DevOpsUpdated Feb 2026

    Git Deployment for Hosting: Push Code Directly to Your Server

    Stop uploading files via FTP. Modern deployment means running git push production main and watching your code go live in seconds—with version history, instant rollbacks, and zero downtime. Here's how to set it up.

    Mallory Keegan
    Mallory Keegan

    Web hosting enthusiast who tests providers and breaks down features, pricing, and real world speed

    Git deployment workflow showing code flowing from local computer through git repository to production server with CI/CD pipeline

    Git-based deployment workflows for modern web hosting

    ⚡ Quick Reference: Choose Your Method

    Platform deploy (Vercel, Netlify)🟢 Easiest
    GitHub Actions + rsync/SCP🟡 Medium
    Git push to VPS (bare repo)🟡 Medium
    GitLab CI/CD or Coolify🔴 Advanced

    What Is Git Deployment?

    Git deployment means using Git—the version control system—as the mechanism to push your code from your local machine (or CI server) to your production hosting. Instead of manually uploading files via FTP or a file manager, you run git push and your server automatically receives the new code, runs any build steps, and updates the live site.

    🔄 Deployment Flow

    1Write code locally

    Develop features, fix bugs, update content on your local machine. Test locally with a dev server.

    2Commit changes

    git add . && git commit -m 'Add new feature'. Each commit is a snapshot of your entire codebase with a message explaining what changed.

    3Push to remote

    git push production main. This sends your commits to the server (or platform). The push triggers the deployment process.

    4Server receives code

    A post-receive hook, CI pipeline, or platform webhook detects the push and begins the deployment process.

    5Build & deploy

    Run build steps (npm run build, composer install, etc.), run database migrations, restart services, clear caches. Site goes live.

    Why Deploy with Git

    Full Version History

    Every deployment is a Git commit. See exactly what changed, when, and who made the change. Compare any two deployments with git diff. Your codebase has a complete audit trail.

    Instant Rollbacks

    Broken deployment? Run git revert or git reset and push. Your site reverts to the last working state in seconds—not minutes of frantic FTP uploads.

    One-Command Deploy

    git push production main. That's it. No file manager, no FTP client, no dragging folders. Deployments become routine, not events.

    Encrypted Transfers

    Git uses SSH or HTTPS for all transfers. No more FTP sending your credentials and code in plain text over the network.

    Team Collaboration

    Multiple developers work on branches, review code in pull requests, and merge to deploy. No more 'who uploaded what?' confusion.

    Preview Deployments

    Push to a staging branch to preview changes before they go live. Platforms like Vercel create unique preview URLs for every pull request.

    Git Deployment Methods Compared

    MethodSetup TimeCI/CDRollbackZero DowntimeBest For
    git push to bare repo20 min❌ Manual✅ git reset❌ Brief downtimeVPS, full control
    GitHub Actions → rsync30 min✅ Full pipeline✅ Re-run workflow✅ With symlinksVPS + CI/CD
    Vercel/Netlify5 min✅ Automatic✅ One click✅ Atomic deploysStatic/JAMstack
    Cloudflare Pages5 min✅ Automatic✅ One click✅ Edge deployStatic + Workers
    GitLab CI/CD1-2 hrs✅ Built-in✅ Pipeline replay✅ ConfigurableSelf-hosted, enterprise
    Coolify / CapRover1-2 hrs✅ Built-in✅ Docker rollback✅ Container swapSelf-hosted PaaS
    DeployHQ / Buddy15 min✅ Visual pipeline✅ One click❌ VariesTeams, GUI preference

    Git Push to VPS (Step-by-Step)

    This is the most flexible approach: set up a bare Git repository on your VPS that automatically deploys when you push. Works with any hosting provider that gives you SSH access.

    Step 1: Set Up SSH Keys

    Local machine (run once)
    # Generate SSH key (if you don't have one)
    ssh-keygen -t ed25519 -C "your@email.com"
    
    # Copy your public key to the server
    ssh-copy-id user@your-server-ip
    
    # Test connection (should log in without password)
    ssh user@your-server-ip

    Step 2: Create Bare Repository on Server

    On your server (via SSH)
    # Create the bare repository
    mkdir -p /home/deploy/repos/mysite.git
    cd /home/deploy/repos/mysite.git
    git init --bare
    
    # Create the web root (where your site lives)
    mkdir -p /var/www/mysite

    Step 3: Create Post-Receive Hook

    /home/deploy/repos/mysite.git/hooks/post-receive
    #!/bin/bash
    set -e
    
    TARGET="/var/www/mysite"
    GIT_DIR="/home/deploy/repos/mysite.git"
    BRANCH="main"
    
    while read oldrev newrev ref
    do
        if [ "$ref" = "refs/heads/$BRANCH" ]; then
            echo "🚀 Deploying $BRANCH to $TARGET..."
    
            # Checkout the latest code
            git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
    
            # Navigate to project directory
            cd $TARGET
    
            # Install dependencies (Node.js example)
            npm ci --production
    
            # Build the project
            npm run build
    
            # Restart the application (PM2 example)
            pm2 restart mysite --update-env
    
            echo "✅ Deployment complete!"
        fi
    done
    Make the hook executable
    chmod +x /home/deploy/repos/mysite.git/hooks/post-receive

    Step 4: Add Remote & Deploy

    Local machine
    # Add the production remote
    git remote add production user@your-server-ip:/home/deploy/repos/mysite.git
    
    # Deploy!
    git push production main
    
    # You'll see the hook output in your terminal:
    # 🚀 Deploying main to /var/www/mysite...
    # ✅ Deployment complete!

    GitHub Actions CI/CD

    GitHub Actions provides free CI/CD (2,000 minutes/month on free plan). This workflow runs tests, builds your project, and deploys to your VPS via rsync—only if tests pass.

    .github/workflows/deploy.yml
    name: Deploy to Production
    
    on:
      push:
        branches: [main]
    
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-node@v4
            with:
              node-version: 20
              cache: 'npm'
          - run: npm ci
          - run: npm run lint
          - run: npm test
    
      deploy:
        needs: test  # Only deploy if tests pass
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-node@v4
            with:
              node-version: 20
              cache: 'npm'
          - run: npm ci
          - run: npm run build
    
          - name: Deploy via rsync
            uses: burnett01/rsync-deployments@6.0.0
            with:
              switches: -avzr --delete
              path: dist/
              remote_path: /var/www/mysite/
              remote_host: ${{ secrets.SERVER_IP }}
              remote_user: deploy
              remote_key: ${{ secrets.SSH_PRIVATE_KEY }}

    🔑 Setting Up Secrets

    In your GitHub repo: Settings → Secrets and variables → Actions → New repository secret. Add SERVER_IP (your server's IP) and SSH_PRIVATE_KEY (your private key contents). Never commit SSH keys to your repo.

    Platform Git Deploy (Vercel, Netlify, Cloudflare Pages)

    The simplest approach: connect your GitHub/GitLab repo to a platform and every push triggers an automatic deployment. Zero server management.

    Vercel

    100GB bandwidth, 6,000 build mins/mo

    Setup: Import repo → auto-detect framework → deploy. That's it.

    Preview deploys for every PR, serverless functions, edge functions, analytics, instant rollback, custom domains + SSL. Best for Next.js (built by same team).

    Netlify

    100GB bandwidth, 300 build mins/mo

    Setup: New site from Git → pick repo → set build command → deploy.

    Preview deploys, serverless functions, forms, identity (auth), split testing, custom domains + SSL, edge functions.

    Cloudflare Pages

    Unlimited bandwidth, 500 builds/mo

    Setup: Connect GitHub → select repo → configure build → deploy.

    Unlimited bandwidth (free), Workers integration, global edge network, preview deploys, custom domains + SSL. Fastest edge delivery.

    Railway

    $5 free credit/mo, then pay-as-you-go

    Setup: New project from GitHub → auto-detect → deploy. Supports backends.

    Full-stack support (databases, queues, cron), Docker support, private networking, logs, metrics. Not just static sites.

    Hosting Providers with Git Deploy

    ProviderGit SupportSSH AccessCI/CDPrice
    Vercel✅ NativeN/A✅ Built-inFree-$20/mo
    Netlify✅ NativeN/A✅ Built-inFree-$19/mo
    Cloudflare Pages✅ NativeN/A✅ Built-inFree
    DigitalOcean App Platform✅ Native✅ (Droplets)✅ Built-in$5+/mo
    Railway✅ Native✅ Built-in$5 credit free
    SiteGround✅ Pre-installed❌ Manual hooks$2.99+/mo
    Cloudways✅ Via SSH❌ Manual hooks$14+/mo
    DigitalOcean Droplet✅ Install yourself✅ Full root❌ GitHub Actions$6+/mo
    Hetzner VPS✅ Install yourself✅ Full root❌ GitHub Actions€3.79+/mo
    Hostinger (shared)❌ No SSH (basic)❌ (premium only)$2.99+/mo

    Branching Strategies for Deployment

    Simple (main only)

    main → production

    All development happens on main. Every push to main deploys to production. No branches, no PRs. Best for solo developers on small projects. Risk: broken code goes live immediately.

    Best for: Solo devs, personal sites, prototypes

    main + staging

    main → staging → production

    Develop on main, push to staging branch to preview, merge to production branch to deploy. Two environments: staging.yoursite.com and yoursite.com.

    Best for: Small teams, client sites

    GitHub Flow

    feature-branch → PR → main (deploy)

    Create feature branches from main. Open PR for code review. Merge to main triggers deploy. Simple, effective, widely used. Preview deploys for each PR (Vercel/Netlify).

    Best for: Most teams, SaaS products

    Git Flow

    feature → develop → release → main

    main (production), develop (integration), feature branches, release branches, hotfix branches. More structure, more overhead. Useful for software with versioned releases.

    Best for: Large teams, versioned software

    Trunk-Based Development

    short-lived branches → main (deploy continuously)

    Everyone commits to main (trunk) daily. Feature flags hide unfinished work. Continuous deployment on every merge. Requires strong test suite and feature flag system.

    Best for: High-performing teams, continuous deployment

    Rollbacks & Recovery

    The ability to quickly rollback a broken deployment is one of Git deployment's greatest strengths. Here are multiple rollback methods:

    git revert (safest)
    git revert HEAD && git push production main

    Creates a new commit that undoes the last commit. Preserves full history. Use this in shared repos where others may have pulled the bad commit.

    git reset (force)
    git reset --hard HEAD~1 && git push -f production main

    Rewrites history by removing the last commit entirely. Faster but destructive—only use on branches where you're the sole contributor. The -f (force push) is required.

    Deploy specific commit
    git push production abc123:main

    Push a specific known-good commit to the production branch. Useful when you need to skip multiple bad commits and go back to a specific version.

    Platform rollback
    Vercel/Netlify: Dashboard → Deployments → click 'Redeploy' on any previous deployment

    One-click rollback to any previous deployment. The platform keeps all build artifacts, so rollback is instant (no rebuild required).

    Symlink rollback
    ln -sfn /var/www/releases/20260224 /var/www/current

    For zero-downtime deployments using the release directory pattern (Capistrano-style). Each deploy creates a new directory. The 'current' symlink points to the active release.

    Security Best Practices

    Never commit secrets

    Use .gitignore to exclude .env files, private keys, API tokens, and database credentials. Use environment variables on the server. If you accidentally commit a secret, rotate it immediately—deleting the commit isn't enough (it's in Git history forever).

    Use SSH keys, not passwords

    SSH key authentication is stronger than passwords and can't be brute-forced. Use Ed25519 keys (ssh-keygen -t ed25519). Disable password authentication in sshd_config. Use a dedicated deploy user with limited permissions.

    Create a dedicated deploy user

    Don't deploy as root. Create a 'deploy' user that owns only the web root directory. Restrict SSH access to key-based auth only. Use sudo only for specific commands (service restart).

    Protect the main branch

    On GitHub/GitLab: require PR reviews before merging to main, require passing CI checks, prevent force pushes, require signed commits. This prevents accidental or malicious deployments.

    Audit deployment logs

    Log every deployment: who pushed, what commit, when, and whether it succeeded. GitHub Actions provides this automatically. For VPS deploys, add logging to your post-receive hook.

    Keep .git out of the web root

    If your .git directory is accessible via HTTP (yoursite.com/.git/), attackers can download your entire source code, including any secrets that were ever committed. Ensure your web server blocks access to .git.

    Common Mistakes

    Committing node_modules or vendor directories

    → Add node_modules/ and vendor/ to .gitignore. Run npm ci or composer install in your deployment hook/CI pipeline. Committing dependencies bloats your repo (100MB+) and causes merge conflicts.

    Not testing before deploying

    → Add a CI step (GitHub Actions, GitLab CI) that runs your test suite before deployment. Even a basic linting check catches obvious errors. The 'needs: test' dependency in GitHub Actions ensures deploy only runs if tests pass.

    Deploying without a build step

    → Modern frameworks (React, Next.js, Vue, Astro) require a build step. Your deployment script must run npm run build (or equivalent) and serve the output directory—not the source files.

    No .gitignore from the start

    → Create .gitignore before your first commit. Include: .env, node_modules/, dist/, .DS_Store, *.log, IDE config files. Use gitignore.io to generate templates for your stack.

    Force-pushing to shared branches

    → git push -f rewrites history and breaks other contributors' local repos. Only force-push to branches you own. Protect main branch from force pushes in repo settings.

    Not backing up the database before deploying

    → If your deployment includes database migrations, dump the database first. Add mysqldump or pg_dump to the start of your deploy script. Migrations can fail mid-way, leaving your schema in an inconsistent state.

    Frequently Asked Questions

    Is FTP dead? Should I switch to Git deployment?
    FTP isn't technically dead, but it should be for any serious project. FTP has critical problems: (1) No version history—if you overwrite a file, it's gone. (2) No rollback—if a deployment breaks the site, you're manually fixing files. (3) Insecure—FTP sends credentials in plain text (use SFTP at minimum). (4) Error-prone—manually uploading files means you'll forget one eventually. (5) No collaboration—multiple people editing via FTP is a recipe for conflicts. Git deployment solves all of these: full version history, one-command rollbacks, encrypted transfers, automated deployments, and proper collaboration. The switch takes 1-2 hours: initialize a git repo, push your code, set up a deployment hook. Even for a simple WordPress site, using Git (via services like SpinupWP, Trellis, or WP Pusher) is dramatically better than FTP.
    Can I use Git deployment with shared hosting?
    It depends on the host. Most budget shared hosts (Hostinger, Bluehost, GoDaddy basic plans) don't support Git natively—you don't have SSH access or the ability to install Git on the server. However, some shared hosts do support it: (1) SiteGround: Git is pre-installed on all plans. You can SSH in and set up a bare repo with post-receive hooks. (2) A2 Hosting: SSH access with Git available on Turbo plans. (3) DreamHost: Full SSH access with Git. For hosts without Git support, alternatives include: (a) GitHub Actions + SFTP: Push to GitHub, the Action deploys via SFTP automatically. (b) DeployHQ or Buddy: Third-party services that connect your Git repo to your host via FTP/SFTP. (c) WP Pusher: For WordPress sites, deploys themes/plugins from GitHub/Bitbucket. If Git deployment is important to you (it should be), choose a VPS ($6/mo on DigitalOcean) or a platform with native Git support (Vercel, Netlify, Railway).
    How do I handle database migrations with Git deployment?
    Database changes are the trickiest part of Git deployment because you can't version-control a live database the same way you version-control code. Best practices: (1) Use migration files: Frameworks like Laravel (php artisan migrate), Django (python manage.py migrate), Rails (rails db:migrate), and Prisma (prisma migrate deploy) generate versioned migration files that live in your Git repo. Your deployment script runs pending migrations after pulling code. (2) Never put database credentials in Git: Use environment variables (.env files excluded via .gitignore). (3) Always back up before deploying: Your deploy script should dump the database before running migrations. (4) Make migrations reversible: Write 'down' migrations so you can rollback both code AND database changes. (5) Separate code deploy from schema changes: Deploy the new code first (make it backward-compatible with the old schema), then run migrations, then deploy any code that requires the new schema. This prevents downtime during migrations.
    What's the difference between CI/CD and Git deployment?
    Git deployment is one piece of the CI/CD puzzle. CI (Continuous Integration) automatically runs tests, linting, and builds whenever you push code. CD (Continuous Deployment/Delivery) automatically deploys code that passes CI to production. A simple 'git push to server' is deployment without CI—you're deploying whatever you push, tested or not. A full CI/CD pipeline (GitHub Actions, GitLab CI, CircleCI) does: push code → run tests → build → deploy (only if tests pass) → notify. For solo developers or small projects, a simple git push with a post-receive hook is fine. For teams or production applications, you want CI/CD: it catches bugs before they reach production, ensures consistent builds, and creates an audit trail of every deployment. Start simple (git push), add CI when you have tests (GitHub Actions free tier: 2,000 minutes/month), and add CD when you trust your test suite.
    How do I deploy a static site (React, Next.js, Astro) with Git?
    Static sites are the easiest to deploy with Git because there's no server-side runtime to manage. Three approaches ranked by simplicity: (1) Platform deploy (easiest): Connect your GitHub repo to Vercel, Netlify, or Cloudflare Pages. Push to main → platform auto-builds and deploys. Zero configuration for most frameworks. Free tier handles most sites. This is the recommended approach. (2) GitHub Actions + hosting: Push to GitHub → Action runs 'npm run build' → uploads the dist/ folder to your server via rsync/SCP or to S3/R2. More control, more setup. (3) Git push to VPS: Set up a bare repo on your server with a post-receive hook that runs the build and copies files to your web root. Most manual but full control. For Next.js specifically: Vercel (built by the Next.js team) provides the best experience—automatic ISR, edge functions, and preview deployments. For Astro: Netlify, Vercel, or Cloudflare Pages all work excellently with zero config.

    Find Hosting with Git Deploy Support

    Whether you need a VPS with SSH access or a platform with automatic Git deployment, find the right host for your workflow.

    Find Developer-Friendly Hosting