Techtrekking

Pulling Latest Changes to Production: A Practical Guide

By Pravin

Deploying code to production via git pull is simple — until your prod server has diverged from your repo. This guide covers the safe workflow, how to handle prod-only changes, .env file management, and Docker-specific gotchas.

1. The Basic Workflow

# On prod server cd /path/to/app git status # check for local changes first git fetch origin git log HEAD..origin/main --oneline # preview incoming commits git pull origin main

Never skip git status and the preview step. Blind pulls are how outages happen.

2. When Prod Has Local Changes

This happens more than it should — someone edits a config file directly on the server, or a script writes logs into a tracked directory. Handle it like this:

Step 1: Identify what changed

git status git diff

Step 2: Decide the fate of each change

  • Accidental / junk change (e.g. temp debug logging) → discard it:
    git checkout -- <file>
  • Legitimate prod-only config (should never have been edited directly) → stash it, pull, then reapply or migrate to proper config management:
    git stash git pull origin main git stash pop # resolve conflicts if any
  • Change that should go back into the repo → commit it on a branch and open a PR instead of leaving it as prod drift.

Golden rule

Prod should never be a place where code changes originate. If you find yourself editing files directly on prod regularly, that's a process gap — fix the pipeline, not the symptom.

3. Handling .env Files

.env files are the #1 cause of "why did pulling break prod" incidents. Best practices:

  • Never commit .env to git. Add it to .gitignore from day one.
  • Keep .env out of the pull path entirely. Since it's untracked, git pull won't touch it — but verify with git status that it's not accidentally tracked.
  • Use a template file (.env.example or .env.template) committed to the repo, listing required keys with placeholder/dummy values. When new keys are added, this template changes — that's your signal to update prod's .env manually.
  • Diff-check after every pull:
    diff <(grep -o '^[A-Z_]*' .env.example) <(grep -o '^[A-Z_]*' .env)
    This flags missing keys before the app crashes on startup.
  • Never overwrite prod's .env with one from another environment. Secrets and URLs differ; a copy-paste mistake here is a common cause of data loss or leaked credentials.
  • Consider a secrets manager (Doppler, Vault, AWS Secrets Manager, etc.) for anything beyond a single-server setup — it removes the manual sync problem entirely.

4. Docker + Python Project Considerations

If your app runs in Docker, a git pull alone does nothing to your running containers — you also need to rebuild/restart.

Standard flow

git pull origin main docker compose build # rebuild image with new code docker compose up -d # recreate containers with new image

Key gotchas

  • .env and Docker Compose: Compose auto-loads .env from the project root for variable substitution in docker-compose.yml. If your app also reads .env at runtime (e.g. via python-dotenv), make sure both the host .env and the one mounted/copied into the container are in sync — don't maintain two separate copies.
  • Don't bake .env into the image. Avoid COPY .env .env in your Dockerfile. Instead, pass it via env_file: in docker-compose.yml or --env-file on docker run. This keeps secrets out of image layers and image history.
  • Dependency changes: if requirements.txt / pyproject.toml changed, a plain restart won't pick up new packages — you need docker compose build --no-cache (or at least a normal rebuild) before up -d.
  • Migrations: for Django/Flask/etc. with a database, run migrations after the new image is up but before traffic hits it:
    docker compose exec app python manage.py migrate
  • Zero-downtime concern: docker compose up -d on a single container causes a brief outage. For anything customer-facing, look into rolling restarts, blue-green deploys, or at minimum a health-check-gated restart.
  • Volume-mounted code in dev vs prod: if your dev setup bind-mounts source code for hot-reload, make sure prod's Compose file does not do this — prod should run code baked into the image, not a live mount, to avoid drift between what's deployed and what's actually running.

5. Recommended Deployment Checklist

[ ] git fetch + review incoming diff
[ ] Check for uncommitted local changes on prod
[ ] Resolve/stash any prod-only changes
[ ] git pull
[ ] Diff .env against .env.example for new required keys
[ ] docker compose build (if deps changed)
[ ] Run migrations if needed
[ ] docker compose up -d
[ ] Check logs / health endpoint

TL;DR

  • Treat prod as read-only for code — never edit tracked files there.
  • .env stays untracked, synced manually or via a secrets manager, and never copied blindly between environments.
  • With Docker, git pull is only half the deploy — rebuild, restart, and run migrations as separate explicit steps.
  • Automate this checklist into a deploy script or CI/CD pipeline as soon as you're doing it more than twice.
Comments
No comments yet. Be the first to comment!
Leave a Comment
Your comment will be visible after approval.