# 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

