squirrelworks

DevOps > Deployment Pipelines

Automating Production Deployments via Bare Git Repositories & Hooks

After establishing secure Ed25519 SSH transport to our remote host, we eliminated manual FTP syncs by implementing an automated server-side Git deployment pipeline. Here is how we configured a bare repository on KnownHost, scripted a post-receive hook to handle live web-root checkouts, managed file permissions, and validated zero-downtime updates.

Bare Git Repo Setup Post-Receive Hook Automation Web Root Sync Verification
bash — sandbox-repo
$ git add .
$ git commit -m "Deploy update"
$ git push sandbox-remote main
Everything up-to-date

1. Bare Repository Provisioning & Remote Mapping

Pushing directly to a standard working directory risks version conflicts and index corruption. Instead, we initialized a dedicated bare repository outside the public HTTP path to act as the central receive target for local code pushes.

Pipeline Layer Target Path / Endpoint Operational Purpose
Bare Storage Target ~/repo/site.git Holds object databases and revision histories cleanly separated from served web files.
Live Production Root ~/public_html Target directory where active site assets are checked out for Apache to serve.
Local Remote Alias sandbox-remote Encapsulates SSH user, Ed25519 key, and server target path into a single push alias.
Tech Fact Icon
Architecture Note

Maintaining site.git outside public_html keeps internal repository metadata, commit histories, and server-side hook scripts completely inaccessible from the public internet.

2. Authoring & Deploying the Post-Receive Hook

Git hooks trigger custom shell scripts upon specific repo lifecycle events. To achieve zero-latency code updates, we created an executable post-receive script inside the bare repository's hooks/ directory.

1. Post-Receive Shell Script Implementation

When a local developer executes a push, Git executes this script on the server. The script forces a checkout of the repository directly into the target sandbox directory:

#!/bin/bash
git --work-tree=/home/squirrel/public_html/sandbox-repo --git-dir=/home/squirrel/repo/sandbox-repo.git checkout -f
2. Applying Execution Privileges

By default, newly created files lack execution flags. We updated file permissions via SSH to allow the Git process to run the hook upon receiving objects:

# Grant execution permissions to post-receive hook
chmod +x ~/repo/sandbox-repo.git/hooks/post-receive

3. Deployment Execution Timeline & Error Diagnostics

Moving from manual file transfers to automated hook deployments required validating server paths, fixing SSH shell permission quirks, and verifying real-time terminal output during push operations.

Hook Provisioning & Test Execution Log Status: Operational
Phase 1
Bare Repository Initialization

Logged into KnownHost host via Ed25519 SSH tunnel. Navigated outside the public directory tree and initialized the storage repo using git init --bare ~/repo/site.git.

Phase 2
Hook Scripting & Permission Trap

Authored the post-receive script using nano. Initial test push succeeded at the Git protocol layer but failed to unpack files into public_html because the hook file lacked execute bit flags (permission denied).

Phase 3
Permission Remediation & Path Verification

Executed chmod +x post-receive to grant execution rights. Explicitly passed --work-tree and --git-dir arguments in the checkout statement to prevent relative path misinterpretations during headless execution.

Phase 4
Push Verification & Live Checkout Validation

Triggered local test push via git push sandbox-remote main. Terminal streaming returned the hook's custom log confirmation messages, verifying zero-latency checkout into live production.

Force Checkout (-f) Safeguard

Using checkout -f ensures that tracked production files are immediately overwritten with incoming commit states, preventing local working tree drift from blocking automated deployments.

Remote Stream Logging

Standard output (echo) generated inside post-receive scripts streams directly back to the developer's local terminal window during git push operations for immediate feedback.

4. End-to-End Deployment Sequence & Transport Architecture

The execution flow spans the local environment, encrypted SSH transport, server-side bare repository processing, and public web-root checkouts. The sequence diagram below maps the interaction lifecycle during a push operation:

sequenceDiagram
    autonumber
    actor Dev as Developer (VS Code)
    participant LocalRepo as Local .git Repo
    participant SSH as SSH Tunnel (Ed25519)
    participant BareRepo as Bare Repo (~/repo/sandbox-repo.git)
    participant Hook as post-receive Hook
    participant WebRoot as Live Web Root (~/public_html/sandbox-repo)

    Dev->>LocalRepo: 1. git add . & git commit
    Note over LocalRepo: Writes Tree & Blob objects
to local .git directory Dev->>SSH: 2. git push sandbox-remote main SSH->>BareRepo: 3. Invokes git-receive-pack Note over BareRepo: Stores compressed commit
objects on KnownHost BareRepo->>Hook: 4. Triggers execution post-transfer Hook->>WebRoot: 5. git --work-tree=... checkout -f Note over WebRoot: Overwrites/deletes files
to match latest commit tree BareRepo-->>Dev: 6. Returns push success status
Tech Fact Icon
Pipeline Mechanics Summary
  • Transport Layer: Local Git relies on SSH for transport, running git-receive-pack remotely without exposing public upload endpoints.
  • Atomic State Updates: Passing checkout -f evaluates the commit tree delta, handling file modifications, additions, and deletions in a single pass.
Establishing Continuous Deployment Reliability

By combining post-quantum Ed25519 SSH transport, a isolated bare repository architecture, and an automated post-receive hook, our delivery pipeline is fully modern. Site updates no longer depend on manual file transfer utility apps or risky live editing, ensuring that every code change is versioned, validated, and published in milliseconds.

Deployment Summary
Local Env: VS Code / Git Bash
Transport: SSH (Ed25519)
Remote Host: KnownHost
Hook Event: post-receive