CLOUD
development

Deploy Your App to the Server with Git: A Clean, Reversible Workflow

CLOUD|September 13, 2026|9 min read|153 views
Deploy Your App to the Server with Git: A Clean, Reversible Workflow

An engineering guide to Git deployment done right: webhook vs pull, an ordered release pipeline, and rolling back to any previous version in under 5 seconds by switching a symlink.

The Direct Answer: How to Deploy with Git Cleanly and Reversibly

Clean Git deployment rests on one principle: never edit code directly on the server. Instead, have the server check out a specific commit from your repository, build it in a fresh directory, then flip a single symlink so that build becomes the live version. This makes every deploy an atomic operation that either fully succeeds or does nothing, and rolling back to any previous version is just repointing that symlink in under 5 seconds.

You have two ways to trigger a deploy: a webhook that your repository (GitHub or GitLab) fires the moment you push, running the deploy script automatically within a second or two, or a manual pull you run yourself over SSH or on a schedule. The engineering principle is identical either way: the server receives one specific commit by its full identity (a 40-character SHA), builds its dependencies and assets on top, runs migrations, then swaps the live version in a single move.

The golden rule that protects your production: keep at least the last 5 releases in separate directories on disk. A typical application directory weighs 150 to 400 megabytes, so five copies cost you barely 1% of an SSD, in exchange for instant recovery to any of them when the latest deploy breaks. That is the difference between a 30-minute outage while you patch live on the server, and a rollback measured in seconds.

Webhook or Pull: Which to Choose

Both methods solve the same problem in different styles. Choose based on team size and deploy frequency.

Webhook Deployment (Automatic)

On every push to your production branch, GitHub sends a POST request to a receiving endpoint on your server carrying the commit details. The server verifies the signature, then runs the deploy script. This suits teams that ship several times a day, because the trip from push to production drops below 30 seconds with no human step.

  • Upside: zero manual steps, the deploy starts a fraction of a second after the push.
  • Downside: it needs a public, secured endpoint, and any flaw in the script runs automatically without review.

Pull Deployment (Manual or Scheduled)

Here you connect to the server over SSH and run the deploy script yourself, or schedule it as a recurring job. This path is simpler on the security side because it opens no public endpoint, and it gives you a final review moment before pressing the button. Most companies running a custom system who deploy once or twice a week are happy with this path, and it is the most common setup on managed VPS servers.

The practical rule: if you deploy more than 5 times a week, a webhook saves you real time, and if your cadence is calmer, a manual pull is clearer and safer. Many teams start with pull, then move to webhooks once the deploy process matures.

The Full Deploy Pipeline in Order

A good deploy script runs specific steps in strict order, and any failure in any step halts the process before the live version is swapped. The correct order prevents a half-deployed state that serves a broken page to a customer.

The Standard Order

  • 1. Fetch the version: clone or pull the specific commit into a new release directory named by timestamp or SHA, such as releases/20260814-143000.
  • 2. Install dependencies: run the installer in production mode without dev packages, which cuts install size by up to 60% versus a development environment.
  • 3. Build assets: compile the final minified CSS and JavaScript, a step that alone can take 20 to 90 seconds depending on project size.
  • 4. Link shared files: symlink the environment file and directories that must persist across releases, like the uploads and logs folders.
  • 5. Run migrations: apply database migrations, ideally forward-compatible so both the old and new release work against the same schema at the moment of the swap.
  • 6. Warm the cache: prebuild the config, route, and view caches, which trims the first post-deploy request from seconds to a fraction of a second.
  • 7. Atomic swap: repoint the current symlink to the new release directory in one move.
  • 8. Reload processes: reload the PHP runtime and any queue workers so they pick up the new code.

Notice that steps 1 through 6 all happen in a side directory while the customer is still served from the old release, so they feel no interruption. The swap in step 7 is the only sensitive moment, and it is too fast to notice because it is nothing more than rewriting a single symlink.

The technical heart of all of the above is the directory layout. Instead of your app living in one fixed folder, you organize it like this: a releases folder holding each version in its own subdirectory, a shared folder for files that cross releases, and a symlink named current that always points at the live version. The web server is aimed at current, not at a specific folder.

On deploy, the new version is built fully inside releases, and when every step succeeds, current is repointed to it in one uninterruptible operation. This is the idea that made tools like Capistrano, Deployer, and Envoyer the standard in deployment for more than 10 years. The measured benefit: the actual swap time is under 50 milliseconds, shorter than the response time of any real request.

Shared files matter here because they prevent data loss. The environment file holding your secrets, the user uploads directory, and the log files all live in shared and are symlinked into each release, so they are neither cloned nor wiped when an old release is deleted.

Rolling Back to a Previous Version in Seconds

This is where the layout proves its real value. When a deploy reveals a production defect, you do not open an editor on the server or rush a fix commit. You repoint current to the previous release directory, which still exists exactly as it was, and your site is healthy again within seconds.

Levels of Rollback

  • Instant rollback: switch current to the previous release. No build, no pull, just a repointed link, completing in under 5 seconds. This is your first line of defense.
  • Code rollback: if the defect is in the code itself and you want it recorded in repository history, run git revert on the bad commit to create an inverse commit, then deploy normally. This keeps history clean without rewriting it.
  • Tag rollback: if you tag every production release with a tag like v1.4.2, you deploy the previous tag directly with one command, which is clearer for teams tracking numbered releases.

The only trap in rollback is the database. Repointing the symlink reverts the code instantly, but it does not undo a migration that dropped a column or changed a data type. Hence the golden rule: make your migrations forward and backward compatible, and never drop a column in the same deploy that stops using it. Remove the usage in one deploy, then drop the column in a later deploy days afterward. This makes any code rollback safe without touching data.

Securing the Webhook and Access

If you choose the webhook path, you are opening a door onto your server, and that door must be tight. More than 80% of automated deployment breaches come from an endpoint with no signature verification.

  • Verify the signature: GitHub sends a signature header computed with a shared secret, and your server must compute the same signature for the payload and reject any request that does not match, so no one but you can trigger a deploy.
  • Deploy keys: use a read-only deploy key to pull the repository, so even if the key leaks from the server, no one can push to your repo.
  • Branch filtering: make the script ignore any push to a branch other than production, so a push to a test branch never touches the live site.
  • Isolate secrets: the environment file stays entirely outside the repository and outside any web-readable path, linked only from shared.

On Cloud's Saudi servers, the endpoint, the repository mirror, and the database all sit inside the Kingdom, so the webhook trip from GitHub to your server in Riyadh completes with a response time near 8 milliseconds for local requests, versus 100 to 120 milliseconds if your server were abroad. Proximity also means your deploy data and secrets never leave the borders, a baseline requirement for systems tied to National Access or government integration.

Common Mistakes to Avoid

Most deploy disasters repeat in known patterns, and avoiding them pushes your successful-deploy rate above 99%.

  • Editing directly on the server: any manual change to the live version is lost on the next deploy and breaks parity with the repository. The rule: the server reads from Git only, never written by hand.
  • Deploying without prior testing: run tests in a CI environment before the deploy, not after. Catching a defect in a test is 100 times cheaper than catching it in production.
  • Destructive migrations in one deploy: separating a column drop from removing its usage, as explained, protects your ability to roll back.
  • Deleting all old releases immediately: keep at least 5 releases, because without a previous copy on disk your rollback turns from seconds into a full rebuild.
  • Skipping cache warming: a deploy without a prebuilt cache means the first dozens of users pay the slowness tax.

Clean deployment is not a single tool, it is discipline in directory layout, step order, and rollback policy. When you assemble these three on a Saudi cloud server close to your users and aligned with digital sovereignty requirements, every deploy becomes a quiet event rather than a gamble, and rollback becomes a one-click option rather than a midnight nightmare.

Share