# Git Multibranch

> Guidance for setting up Git-based multi-branch deployment systems with web servers. This skill applies when configuring Git repositories with post-receive hooks that deploy different branches to different directories, typically served by Nginx or Apache. Use for tasks involving SSH-accessible Git servers, branch-specific deployments, and web server configuration.

- Skill: `tools-only/git-multibranch` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds add tools-only/git-multibranch`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/git-multibranch/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/tools-only/git-multibranch

---


# Git Multi-Branch Deployment

## Overview

This skill provides guidance for configuring Git repositories that automatically deploy content from different branches to different web-accessible directories. The typical setup involves a bare Git repository with post-receive hooks that check out branch contents to specific deployment directories served by a web server.

## Core Components

A multi-branch deployment system requires four interconnected components:

1. **SSH Server** - Enables remote Git operations
2. **Bare Git Repository** - Receives pushes and triggers deployment hooks
3. **Post-Receive Hook** - Deploys branch contents to appropriate directories
4. **Web Server** - Serves deployed content from branch-specific directories

## Approach Strategy

### Phase 1: SSH Configuration

Before configuring Git, ensure SSH access is properly configured:

- Verify SSH service is running and accessible
- Check authentication settings: `PasswordAuthentication`, `PermitRootLogin`, and also `UsePAM`, `KbdInteractiveAuthentication`
- Create the Git user account with appropriate shell access
- Test SSH connectivity before proceeding to Git setup

**Critical Check**: After any SSH configuration changes, restart the SSH service and verify connectivity with a test login.

### Phase 2: Git Repository Setup

Create a bare repository that will receive pushes:

```bash
# Create as the git user or with proper ownership
git init --bare /path/to/repo.git
```

Key considerations:
- The repository must be owned by the Git user
- The repository starts empty - handle first-push scenarios in the hook
- Set appropriate permissions on the repository directory

### Phase 3: Deployment Directory Setup

Create and configure deployment directories before writing the hook:

```bash
mkdir -p /var/www/main /var/www/dev
chown git:git /var/www/main /var/www/dev
```

**Permission Verification**: The post-receive hook runs as the Git user. Verify the Git user has write permissions to all deployment directories before testing.

### Phase 4: Post-Receive Hook Implementation

The post-receive hook deploys branch contents on each push. See `references/post_receive_hook.md` for implementation details and edge case handling.

Key hook requirements:
- Parse branch name from stdin (format: `oldrev newrev refname`)
- Handle initial push when branches don't exist yet
- Deploy to correct directory based on branch name
- Handle the `refs/heads/` prefix in refnames

### Phase 5: Web Server Configuration

Configure the web server to serve content from deployment directories. Each branch maps to a specific location path or virtual host.

## Verification Strategy

### Test from Clean State

**Critical**: Always test from the exact state that evaluation will use:

1. Start with a fresh clone of an empty repository
2. Make initial commits locally
3. Push to the server
4. Verify deployment directories contain expected content

### Verification Commands

After each deployment phase, verify:

```bash
# Check SSH connectivity
ssh git@localhost 'echo connected'

# Verify repository permissions
ls -la /path/to/repo.git

# Check hook is executable
ls -la /path/to/repo.git/hooks/post-receive

# Verify deployment directory permissions
ls -la /var/www/

# Test web server response
curl -s http://localhost/main/
curl -s http://localhost/dev/
```

### Clean State Testing Protocol

After initial setup testing, reset to clean state before final verification:

1. Remove all content from deployment directories
2. Delete any test branches in the repository
3. Perform a fresh clone and push sequence
4. This ensures the setup handles first-push scenarios correctly

## Common Pitfalls

### SSH Configuration Incomplete

**Problem**: Changing `PasswordAuthentication` alone may not enable password auth.

**Solution**: Check all related settings: `UsePAM`, `KbdInteractiveAuthentication`, `ChallengeResponseAuthentication`. Restart SSH service after changes.

### Post-Receive Hook Edge Cases

**Problem**: Hook fails on first push when target branch doesn't exist.

**Solution**: The hook must handle both:
- First push to a new branch (branch doesn't exist yet)
- Subsequent pushes to existing branches

See `references/post_receive_hook.md` for handling strategies.

### Testing Pollutes Repository State

**Problem**: Test commits and pushes leave the repository in a non-empty state, making subsequent tests unrepresentative.

**Solution**:
- Test from a clean state matching evaluation conditions
- Avoid force-pushing as a workaround - this masks first-push issues
- Reset deployment directories and repository state between test iterations

### Git User Permission Issues

**Problem**: Post-receive hook runs as Git user but cannot write to deployment directories.

**Solution**:
- Verify ownership: `chown git:git /var/www/main /var/www/dev`
- Check parent directory permissions
- Test hook execution manually as the Git user

### Host Key Verification Overhead

**Problem**: Using both manual host key addition and `StrictHostKeyChecking=no` is redundant.

**Solution**: Choose one approach:
- Add host key to known_hosts once, then rely on it
- OR use `StrictHostKeyChecking=no` consistently (less secure but simpler for local testing)

### Deployment Methods

**Problem**: Unclear which method to use for deploying branch content.

**Options**:
- `git checkout -f` - Simple, overwrites working tree
- `git archive | tar` - Creates clean export, no .git files
- `git worktree` - Maintains multiple checkouts

Choose based on requirements. Document the rationale for the chosen approach.

## Edge Cases to Handle

1. **First push scenario**: When pushing to a branch that doesn't exist on the server yet
2. **Empty repository**: The very first push when no branches exist at all
3. **Branch deletion**: Decide whether to clean up deployment directories when branches are deleted
4. **Non-existent deployment directories**: Handle gracefully if directories don't exist during hook execution
5. **Concurrent pushes**: Consider race conditions if multiple pushes happen simultaneously

## Resources

### references/

- `post_receive_hook.md` - Detailed post-receive hook implementation with edge case handling

