Add Git Auto-Sync Architecture documentation

This commit is contained in:
IGNY8 VPS (Salman)
2025-11-10 10:58:12 +00:00
parent 7ef2a53e41
commit d283f72fbb

View File

@@ -0,0 +1,225 @@
# Git Auto-Sync Architecture - Complete Picture
## Overview
This document explains how the automatic git synchronization works between Gitea (bare repository) and the VPS working copy.
## Architecture Components
### 1. **Bare Repository (Gitea Server)**
- **Host Path**: `/data/app/gitea/git/repositories/salman/igny8.git`
- **Container Path**: `/data/git/repositories/salman/igny8.git`
- **Type**: Bare repository (no working tree)
- **Purpose**: Stores all commits, branches, and git history
- **Access**: Served by Gitea at `https://git.igny8.com/salman/igny8.git`
### 2. **Working Copy (VPS Deployment)**
- **Host Path**: `/data/app/igny8`
- **Container Path**: `/deploy/igny8` (mounted from host)
- **Type**: Full git repository with working tree
- **Purpose**: Live application code that runs on VPS
- **Remotes**:
- `origin`: `https://git.igny8.com/salman/igny8.git` (HTTPS remote)
- `deploy`: `/data/git/repositories/salman/igny8.git` (local bare repo path)
### 3. **Docker Volume Mount**
```yaml
# From docker-compose.yml
volumes:
- ./gitea:/data # Gitea data directory
- /data/app/igny8:/deploy/igny8:rw # Mount working copy into container
```
This mount makes the VPS working copy accessible inside the Gitea container at `/deploy/igny8`.
### 4. **Post-Receive Hook**
- **Location**: `/data/app/gitea/git/repositories/salman/igny8.git/hooks/post-receive`
- **Trigger**: Automatically runs after every `git push` to Gitea
- **Execution Context**: Runs inside Gitea container, in the bare repository directory
## Complete Flow: Push to Auto-Update
### Step 1: Developer Pushes to Gitea
```bash
git push origin main
# or
git push https://git.igny8.com/salman/igny8.git main
```
### Step 2: Gitea Receives Push
- Push arrives at Gitea server
- Gitea validates and stores commits in bare repository
- Bare repo is updated: `/data/app/gitea/git/repositories/salman/igny8.git`
### Step 3: Post-Receive Hook Executes
The hook runs automatically with this context:
- **Current Directory**: `/data/git/repositories/salman/igny8.git` (bare repo)
- **Environment**: Inside Gitea container
- **Access**: Can access both bare repo and mounted working copy
### Step 4: Hook Logic Breakdown
```bash
# 1. Define paths
DEPLOY_DIR="/deploy/igny8" # Working copy (mounted from host)
SOURCE_REPO="$(pwd)" # Bare repo: /data/git/repositories/salman/igny8.git
# 2. Check if working copy is a git repository
if [ -d "$DEPLOY_DIR/.git" ]; then
# Working copy exists and is a full git repo
# 3. Set up git command with explicit paths
GIT_CMD="git --git-dir=$DEPLOY_DIR/.git --work-tree=$DEPLOY_DIR"
# 4. Add 'deploy' remote if it doesn't exist
# This points to the bare repo (no network needed, direct file access)
if ! $GIT_CMD remote get-url deploy >/dev/null 2>&1; then
$GIT_CMD remote add deploy "$SOURCE_REPO"
fi
# 5. Fetch latest commits from bare repo
# Fetches directly from file system, no HTTPS/SSH needed
$GIT_CMD fetch deploy main
# 6. Reset working tree to latest commit
# This updates all files in /data/app/igny8 to match latest commit
$GIT_CMD reset --hard remotes/deploy/main
# 7. Update origin/main tracking branch
# This is CRITICAL: tells git that local HEAD matches origin/main
# Without this, git status shows "ahead" even though files are synced
$GIT_CMD update-ref refs/remotes/origin/main HEAD
else
# First time setup: working copy doesn't exist yet
# Checkout files from bare repo to create working copy
export GIT_DIR="$SOURCE_REPO"
export GIT_WORK_TREE="$DEPLOY_DIR"
git checkout -f main
fi
```
### Step 5: Result
- **Files Updated**: All files in `/data/app/igny8` now match latest commit
- **Git Status**: Shows "up to date with origin/main" (no phantom commits)
- **Application**: If using volume mounts, containers see changes immediately
## Why This Design?
### Problem We Solved
1. **Phantom Commits**: Previously, hook updated files but not git metadata, causing git to think local was "ahead"
2. **Manual Sync Required**: Had to manually `git pull` after every push
3. **Sync Issues**: Working tree and git metadata were out of sync
### Solution
1. **Direct File System Access**: Hook uses `deploy` remote pointing to bare repo path (no network overhead)
2. **Complete Sync**: Updates both files AND git metadata (tracking branches)
3. **Automatic**: Runs on every push, no manual intervention needed
## Key Git Concepts Used
### 1. Bare Repository
- Repository without working tree
- Only contains `.git` contents (objects, refs, etc.)
- Used by servers to store code without checking out files
### 2. Working Tree
- Directory with actual files you can edit
- Has `.git` directory with repository metadata
- This is what developers work with
### 3. Remote Tracking Branches
- `refs/remotes/origin/main`: Git's record of what `origin/main` was last time we fetched
- When we update this to match HEAD, git knows we're in sync
- Without updating this, git compares HEAD to stale tracking branch → shows "ahead"
### 4. Git Reset --hard
- Moves HEAD to specified commit
- Updates working tree to match that commit
- Discards any local changes (force update)
## File System Layout
```
Host System:
├── /data/app/gitea/
│ └── git/repositories/salman/igny8.git/ (bare repo)
│ ├── objects/ (all commits, trees, blobs)
│ ├── refs/ (branches, tags)
│ └── hooks/
│ └── post-receive (auto-sync hook)
└── /data/app/igny8/ (working copy)
├── .git/ (git metadata)
│ ├── config (has 'origin' and 'deploy' remotes)
│ └── refs/
│ └── remotes/
│ ├── origin/main (tracking branch)
│ └── deploy/main (tracking branch)
├── backend/ (actual application files)
├── frontend/
└── ...
Inside Gitea Container:
├── /data/git/repositories/salman/igny8.git/ (same as host bare repo)
└── /deploy/igny8/ (mounted from /data/app/igny8)
└── (same contents as host /data/app/igny8)
```
## Checking Status
### On Host VPS
```bash
cd /data/app/igny8
git status # Should show "up to date with origin/main"
git log --oneline -5 # See recent commits
git remote -v # See remotes (origin + deploy)
```
### Hook Logs
```bash
docker exec gitea cat /data/gitea/log/hooks.log
```
### Manual Sync (if needed)
```bash
cd /data/app/igny8
git pull origin main # Pull from HTTPS remote
# OR
git fetch deploy main # Fetch from local bare repo
git reset --hard remotes/deploy/main
```
## Troubleshooting
### Issue: "Your branch is ahead of origin/main"
**Cause**: Hook didn't update `refs/remotes/origin/main` tracking branch
**Fix**: Hook should run `git update-ref refs/remotes/origin/main HEAD` (already in hook)
### Issue: Files not updating after push
**Check**:
1. Hook logs: `docker exec gitea cat /data/gitea/log/hooks.log`
2. Hook executable: `ls -la /data/app/gitea/git/repositories/salman/igny8.git/hooks/post-receive`
3. Mount exists: `docker exec gitea ls -la /deploy/igny8`
### Issue: Hook not running
**Check**:
1. Gitea logs: `docker logs gitea --tail 50`
2. Hook file exists and is executable
3. Push actually succeeded (check Gitea web UI)
## Summary
**The Complete Flow:**
1. Developer pushes → Gitea bare repo updated
2. Post-receive hook triggers automatically
3. Hook fetches from bare repo (via `deploy` remote)
4. Hook resets working copy to latest commit
5. Hook updates tracking branch metadata
6. VPS working copy is now in sync
7. Application containers see updated files (via volume mounts)
**Key Innovation:**
- Uses local file system path (`deploy` remote) instead of HTTPS
- Updates both files AND git metadata
- Fully automatic, no manual steps required