Git Intro

Understanding Distributed Version Control & Git's Core Architecture

What is Git?

Git is a modern, high-performance Distributed Version Control System (DVCS) created in 2005 by Linus Torvalds to manage the development of the Linux operating system kernel.

Before Git, version control was dominated by centralized systems like Subversion (SVN), CVS, and Perforce. In centralized systems, every operation (viewing history, diffing changes, committing) required connecting to a central server over a network. If the server crashed or went offline, developers were completely blocked from collaborating or committing code.

Centralized VCS vs. Distributed VCS
In Git, every developer's local machine contains a full-fledged clone of the entire repository—including the complete commit history, all branches, and all tags. Network connectivity is only required when synchronizing (pushing or fetching) with remote servers like ProGit or GitHub.

Snapshots, Not Differences (Deltas)

The fundamental conceptual difference between Git and traditional VCS is how data is stored. Most legacy systems store changes as a base version followed by a sequence of delta differences over time. Git, however, conceives of its data as a stream of complete filesystem snapshots.

Every time you commit in Git, it takes an instantaneous snapshot of what all files in your project look like at that moment and records a reference to that snapshot. To keep storage ultra-efficient, if a file has not changed between commits, Git does not duplicate the file—it simply creates an internal cryptographic pointer to the identical file already saved in the object database.

Commit Object Author & Committer Parent Commit Hash Commit Message → Tree pointer Tree Object (Dir) 100644 main.go (blob) 100644 README.md (blob) 040000 src/ (sub-tree) Blob (main.go) Compressed file bytes Blob (README.md) Compressed markdown bytes

Figure 1.1: Git's Content-Addressable Object Model (Commits → Trees → Blobs).

Content-Addressable Object Database

Everything in Git is addressed by the 40-character SHA-1 (or 64-character SHA-256) hash of its contents and header:

  • Blob (Binary Large Object): Holds pure file content compressed with zlib. Blobs store no file names, folder paths, or timestamps—only raw content.
  • Tree: Represents a directory or folder. Associates file names and file permissions with specific blob or sub-tree hashes.
  • Commit: Represents a point-in-time state. Points to a top-level Tree object, records author and committer names, timestamps, parent commit hash(es), and commit log message.
  • Annotated Tag: A permanent cryptographic reference to a commit, including tagger details, date, and optional GPG signature.

Git Install

Installing Git on macOS, Linux, and Windows Platforms

Installing Git Across Operating Systems

Git is universally supported on macOS, Linux, and Windows. Follow the instructions for your platform:

1. macOS Installation

# Option A: Install via Homebrew (Recommended)
brew install git

# Option B: Install Apple Command Line Developer Tools
xcode-select --install

2. Linux Installation

# Ubuntu / Debian
sudo apt update && sudo apt install -y git

# Red Hat Enterprise Linux / CentOS / Fedora / AlmaLinux
sudo dnf install -y git

# Arch Linux / Manjaro
sudo pacman -S git

# Alpine Linux (Minimal Container Image)
apk add --no-cache git

3. Windows Installation

Download the official installer from git-scm.com/download/win. This provides Git Bash (a complete bash emulation environment) and installs native Git command-line tools into Windows PowerShell.

4. Verifying Your Installation

Confirm Git is installed and check your version in terminal:

git --version
# Expected output: git version 2.44.0 (or newer)

which git
# Expected output: /usr/local/bin/git or /usr/bin/git

Git Config

Configuring Identity, Default Branch, Editors, and Environment Settings

Configuration Scopes in Git

Git utilizes three distinct levels of configuration with ascending precedence:

  • --system: Applied to all users on the operating system (/etc/gitconfig).
  • --global: Applied to your specific OS user account (~/.gitconfig or ~/.config/git/config).
  • --local: Applied only to the current repository directory (.git/config). Overrides global settings.

Setting Up Developer Identity

Every Git commit embeds the author's name and email. Set these globally right after installation:

# Set full legal name and professional email
git config --global user.name "Sanjeev Senapati"
git config --global user.email "sanjeev@prodevans.com"

# Set default primary branch name to 'main'
git config --global init.defaultBranch main

# Set preferred command line text editor (e.g. VS Code, nano, or vim)
git config --global core.editor "vim"

# Configure pull behavior to rebase by default (keeps history linear)
git config --global pull.rebase true

Line Ending Configuration (CRLF vs LF)

Windows uses Carriage Return + Line Feed (\r\n), while macOS and Linux use Line Feed (\n). To prevent dirty diffs across team members:

# On macOS / Linux:
git config --global core.autocrlf input

# On Windows:
git config --global core.autocrlf true

Inspecting Active Configuration

# List all configured keys and which configuration file they originate from
git config --list --show-origin

# Read a specific key value
git config user.email

Git Get Started

Initializing Repositories, Cloning Remotes, and Anatomy of the .git Directory

Initializing a New Repository

To turn any folder into a tracked Git repository, run git init inside that directory:

# Create project directory and enter it
mkdir my-service && cd my-service

# Initialize Git repository
git init
# Initialized empty Git repository in /Users/sanjeev/my-service/.git/

Cloning an Existing Remote Repository

To download a project and its entire history from ProGit or GitHub, use git clone:

# Clone via Smart HTTPS
git clone https://progit.co.in/prodevans/backend.git

# Clone via SSH on custom port 2222
git clone ssh://git@progit.co.in:2222/prodevans/backend.git

# Clone a specific branch directly
git clone -b develop https://progit.co.in/prodevans/backend.git

Anatomy of the Hidden .git Directory

The .git directory contains all internal bookkeeping. Here are its critical contents:

PathRole & Function
HEADFile pointing to the currently checked-out branch ref (e.g., ref: refs/heads/main).
objects/Content-addressable object store holding all compressed blobs, trees, and commits.
refs/heads/Files storing 40-character commit hashes for each local branch.
refs/remotes/Commit hashes for remote tracking branches (e.g. origin/main).
refs/tags/Pointers to specific release tag commit hashes.
indexBinary staging area file caching filenames, file modes, and staged blob SHA-1s.
configRepository-specific configuration file (remotes, branch tracking).
hooks/Client-side hook scripts executed on commit, push, or merge.

Git New Files

File Lifecycles, Tracking Status, and Creating Your First Files

The File Lifecycle in Git

Files in your workspace directory transition through specific lifecycle phases:

StatusDescription
UntrackedFile exists on disk in your folder, but Git has no record of it in the previous commit snapshot or staging index.
Tracked (Unmodified)File content exactly matches the snapshot in the last commit (HEAD).
Tracked (Modified)File has been changed in your workspace since the last commit, but has not yet been staged.
StagedA modified or new file whose exact changes have been marked to go into the next commit snapshot.

Creating New Files and Inspecting Status

# Create new project files
echo "# Payment Microservice" > README.md
echo "package main" > main.go

# Check repository status
git status
# Output:
# On branch main
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#	README.md
#	main.go

Short Status Output

For a compact overview during rapid development, use git status -s:

git status -s
# ?? README.md    (?? = Untracked file)
# ?? main.go      (?? = Untracked file)
#  M config.yaml  ( M = Tracked file modified in working tree, not staged)
# M  api.go       (M  = Tracked file staged in index, ready to commit)

Git Staging

The Staging Area (Index), Selective Staging, and Interactive Hunks

What is the Staging Area (Index)?

The Staging Area (often called the Index) is an intermediate staging buffer where you curate and assemble your next commit snapshot. Unlike other version control systems that force you to commit all modified files simultaneously, Git allows you to craft small, atomic, logical commits by selectively staging specific files—or even specific lines of code.

Basic Staging Commands

# Stage a single specific file
git add README.md

# Stage multiple files
git add main.go internal/api.go

# Stage all modified, created, and deleted files in the entire project
git add -A

# Stage all files in current directory and subdirectories
git add .

Interactive Hunk Staging (git add -p)

When you have made multiple changes in a single file but want to split them into separate commits, use patch staging:

git add -p server.go

Git will display individual change diffs (hunks) and prompt you with options:

  • y: Stage this hunk for the next commit.
  • n: Do not stage this hunk (keep changes in working tree).
  • s: Split this hunk into smaller sub-hunks.
  • e: Manually edit the hunk with your text editor.
  • q: Quit interactive staging.

Un-staging Files (Keeping Worktree Edits)

If you staged a file accidentally, un-stage it without losing your code:

# Modern Git (2.23+):
git restore --staged secret.env

# Traditional Git:
git reset HEAD secret.env

Git Commit

Recording Snapshots, Conventional Commits Standard, and Atomic Best Practices

Creating a Commit

Once you have staged your desired files in the index, run git commit to permanently record a snapshot:

git commit -m "feat(auth): implement JWT token validation middleware"

Multi-Line Commit Messages with Context

Production commits should include a short summary title followed by an explanatory body:

git commit -m "fix(payment): prevent duplicate webhook processing" \
-m "Add distributed idempotency lock using Redis key expiration. \
Prevents concurrent charging when Stripe sends duplicate retry events."

The Conventional Commits 1.0.0 Standard

Industry engineering teams follow structured commit messages for automated changelog generation:

PrefixIntent / Semantic Meaning
feat:A new user-facing capability or software feature.
fix:A bug fix patching an issue in production or staging.
docs:Documentation changes only (README, markdown, wikis).
style:Formatting, missing semicolons, white-space changes (no code logic changes).
refactor:Code reorganization that neither fixes a bug nor adds a feature.
perf:A code optimization that improves execution performance or reduces RAM.
test:Adding missing unit tests or correcting existing tests.
ci:Changes to CI/CD pipelines, GitHub Actions workflows, or scripts.
chore:Updating dependencies, build tool settings, package.json / go.mod.
The Atomic Commit Principle
Each commit should represent a single complete, logical unit of work. If a commit breaks unit tests or contains unrelated refactorings alongside a bugfix, split it. Atomic commits make reviewing code, running git bisect, and reverting bugs effortless.

Git Tagging

Lightweight vs Annotated Tags, Release Management, and Cryptographic Verifications

What are Git Tags?

Tags are permanent, human-readable references pointing to specific commits. They are universally used to mark release milestones (e.g. v1.0.0, v2.4.1-rc1).

Lightweight vs. Annotated Tags

  • Lightweight Tag: A simple pointer bookmark to a commit hash. Contains no additional metadata or signature.
  • Annotated Tag (Recommended for Releases): Stored as a full object in the Git object database. Contains tagger name, email, timestamp, release notes, and optional GPG signature.

Creating Tags

# 1. Create an Annotated Tag with release notes (Recommended)
git tag -a v1.2.0 -m "Release v1.2.0: Adds SQLite WAL mode and SSH authentication"

# 2. Create a Lightweight Tag
git tag v1.2.0-beta

# 3. Tag a past commit in history
git tag -a v1.1.0 4a3f12e -m "Release v1.1.0 backport"

Listing and Inspecting Tags

# List all tags
git tag

# Filter tags by semantic version pattern
git tag -l "v1.*"

# Inspect tag author, timestamp, and commit diff
git show v1.2.0

Pushing Tags to Remote Repositories

By default, git push does not transmit tags to remote servers. You must push them explicitly:

# Push a single tag
git push origin v1.2.0

# Push all local tags simultaneously
git push origin --tags

# Delete a tag locally and remotely
git tag -d v1.2.0
git push origin --delete v1.2.0

Git Stash

Temporarily Shelving Uncommitted Work, Inspecting Stashes, and Restoring State

Why Use Git Stash?

Often you are in the middle of writing a feature when an urgent production bug requires your immediate attention. You cannot commit unfinished or broken code, but you cannot switch branches with dirty files. Git Stash takes your dirty working tree and staged index, records them on an internal stack, and restores a clean working directory matching HEAD.

Stashing Work

# Quick stash of all tracked modifications
git stash

# Stash with a descriptive message (Recommended)
git stash push -m "WIP: integrating OAuth2 Google provider"

# Include untracked files in the stash
git stash -u

Viewing and Inspecting Stashes

# List all stashed changes
git stash list
# Output:
# stash@{0}: On main: WIP: integrating OAuth2 Google provider
# stash@{1}: On develop: WIP: navbar redesign

# Inspect diff of the most recent stash
git stash show -p stash@{0}

Restoring Stashed Work

# Pop the latest stash (applies changes and deletes it from stash list)
git stash pop

# Apply a specific stash without deleting it
git stash apply stash@{1}

# Create a new branch directly from a stash and switch to it
git stash branch feature/oauth2 stash@{0}

# Drop a specific stash
git stash drop stash@{0}

# Clear all stashes permanently
git stash clear

Git History

Navigating Commit Logs, Graphical Tree Views, Filtering, and Diff Inspection

Inspecting the Commit History (git log)

Git offers granular inspection of repository history:

# Basic sequential commit log
git log

# Display one commit per line with short hash
git log --oneline

# Graphical ASCII branch tree visualization
git log --graph --oneline --decorate --all

# Limit number of commits displayed
git log -n 5 --oneline

Filtering History by Author, Date, and Message

# Filter commits by author name or email
git log --author="Sanjeev" --oneline

# Filter commits within a specific timeframe
git log --since="2026-10-01" --until="2026-11-01" --oneline

# Search commit messages for keywords (grep)
git log --grep="CVE-" --oneline

# View history of modifications to a single file
git log -p internal/auth/jwt.go

Viewing File Change Statistics (--stat)

To see which files were touched and how many lines were inserted or deleted per commit:

git log --stat -n 3
# Output:
# commit 4a9f21b
# Author: Sanjeev Senapati <sanjeev@prodevans.com>
# Date:   Sat Nov 7 14:22:10 2026 +0530
#
#     feat: optimize sqlite database WAL checkpoints
#
#  internal/database/sqlite.go | 42 ++++++++++++++++++++++------------------
#  internal/database/wal.go    | 18 ++++++++++++++++++
#  2 files changed, 44 insertions(+), 16 deletions(-)

Git Help

Accessing Built-in Manuals, Command Syntax, and Subcommand Discovery

Accessing Built-in Git Help

Git ships with complete documentation embedded directly in the binary. You never need an active internet connection to read full manual pages:

# View comprehensive manual page in terminal pager
git help commit
git commit --help
man git-commit

# View quick flag reference without leaving terminal
git commit -h
git branch -h

Discovering Available Subcommands and Guides

# List all standard Git subcommands
git --help

# List all available subcommands including third-party extensions
git help -a

# Read Git conceptual guides (e.g., gitworkflows, giteveryday, gitglossary)
git help workflows
git help everyday
git help glossary

Git Branch

Branch Mechanics, 41-Byte Pointers, Switching, and Branch Deletion

What is a Branch in Git?

In Git, a branch is not an expensive copy of your project directory. A branch is simply a lightweight, movable pointer to a 40-character commit hash stored in a 41-byte text file inside .git/refs/heads/<branch-name>. Because creating a branch writes only 41 bytes to disk, branch operations in Git are instantaneous regardless of repository size.

C1 C2 C3 main C4 HEAD → feature

Figure 1.2: Branching Mechanics in Git (Pointers to Commits).

Creating and Switching Branches

# Modern Git (Recommended):
# 1. Create a new branch
git branch feature/payment-gateway

# 2. Switch to an existing branch
git switch feature/payment-gateway

# 3. Create AND switch in a single command
git switch -c feature/payment-gateway

# Legacy Git command (still functional):
git checkout -b feature/payment-gateway

Listing Branches

# List local branches (* marks current branch)
git branch

# List both local and remote-tracking branches
git branch -a

# Show commit hash and commit subject for each branch
git branch -v

Deleting and Renaming Branches

# Safe delete local branch (fails if branch has unmerged work)
git branch -d feature/payment-gateway

# Force delete local branch (discards unmerged commits)
git branch -D feature/payment-gateway

# Delete branch on remote repository
git push origin --delete feature/payment-gateway

# Rename current active branch
git branch -m new-branch-name

Git Merge

Fast-Forward vs True Three-Way Merges, Aborting Merges, and Merge Commits

What Happens During a Merge?

Merging integrates changes from another branch into your currently checked-out branch. Git analyzes the commit history graph to find the best common ancestor (merge base) between the two branch tips.

1. Fast-Forward Merge (--ff)

If no new commits were made on the base branch (e.g. main) while your feature branch was developed, Git performs a Fast-Forward merge. It simply moves the main branch pointer forward to point directly at the tip commit of the feature branch. No new merge commit is created.

git switch main
git merge feature/docs

2. True Three-Way Merge (--no-ff)

When both main and the feature branch have diverged (each contains commits the other lacks), Git computes a three-way merge using:

  1. Snapshot of Common Ancestor (Merge Base).
  2. Snapshot of Current Branch (HEAD).
  3. Snapshot of Incoming Branch.

Git applies non-overlapping changes automatically and creates a brand-new Merge Commit with two parent commit hashes.

# Enforce creating a merge commit even if fast-forward is possible
git merge --no-ff feature/billing -m "merge: integrate billing microservice"

3. Squash Merge (--squash)

Takes all commits on the feature branch, combines their collective diffs into staged changes in the index, and allows you to make a single clean commit on main:

git switch main
git merge --squash feature/refactor
git commit -m "refactor: simplify database connection pooling"

Aborting a Merge in Progress

If you encounter unexpected merge conflicts and want to reset back to your original clean state:

git merge --abort

Git Workflow

GitFlow vs GitHub Flow vs Trunk-Based Development Comparison

Industry Branching Strategies

Engineering teams choose branching workflows based on team size, release cadence, and deployment automation:

StrategyCore StructureIdeal Use Case
GitHub Flow (Modern Agile) main is always deployable.
Short-lived feature/* branches.
Pull Requests for peer review & CI gates.
Merge to main triggers automated deploy.
Web applications, SaaS products, microservices, continuous deployment environments.
Trunk-Based Development (DevOps / DORA) Developers commit directly to main daily (or via 1-day PRs).
Incomplete features hidden behind Feature Toggles.
Extremely heavy automated testing suite.
High-performing engineering teams (FAANG, DevOps leaders), continuous deployment.
GitFlow (Traditional Enterprise) main (production releases).
develop (integration branch).
feature/*, release/*, hotfix/*.
Mobile apps (App Store review cycles), on-premise boxed software releases.

The Recommended ProGit Flow

# 1. Update your local main branch
git switch main && git pull --rebase

# 2. Branch off main for your task
git switch -c feature/user-settings

# 3. Code, test, and commit atomically
git commit -m "feat(settings): add dark mode preference toggle"

# 4. Push to ProGit and open a Pull Request
git push -u origin feature/user-settings

Git Best Practices

Engineering Standards, Hygiene, Commit Hygiene, and Security Protocols

10 Golden Rules for Git Engineering

  1. Make Commits Atomic: Each commit should solve one problem or implement one isolated feature. Never bundle formatting cleanups into bugfixes.
  2. Write Imperative Commit Messages: Write "fix: prevent SQL injection in login handler", not "fixed bug".
  3. Never Commit Secrets or Credentials: Keep .env, private keys (id_rsa, *.pem), passwords, and API tokens out of Git. Use a strict .gitignore.
  4. Always Pull with Rebase: Configure git config --global pull.rebase true to avoid superfluous merge commit bubbles in your history.
  5. Never Rewrite Shared Remote History: Do not force push (git push -f) to main or shared branches. If you must force-push a private feature branch, always use git push --force-with-lease.
  6. Test Before Committing: Ensure code compiles and all unit tests pass before committing. Use pre-commit hooks to automate linting.
  7. Keep Long-Lived Branches Synced: Frequently rebase your feature branches onto main to resolve conflicts early.
  8. Review Your Own Diff Before Committing: Run git diff --staged to verify exactly what changes you are about to record.
  9. Use Descriptive Branch Names: Use structured prefixes: feat/<name>, fix/<issue-id>, refactor/<scope>.
  10. Sign Release Tags Cryptographically: Always use annotated, GPG/SSH-signed tags (git tag -s v1.0.0) for production releases.

Git Glossary

Complete Terminology Reference Matrix from A to Z

Git Terminology Reference

TermTechnical Definition
BlobBinary Large Object. Compressed file contents stored in .git/objects/. Contains no filename or path metadata.
TreeObject representing a directory. Maps filenames and permissions to Blob or sub-Tree hashes.
CommitObject storing metadata (author, committer, date, message), root Tree pointer, and parent commit pointer(s).
HEADReference pointer indicating your current checked-out branch tip or commit.
Detached HEADState where HEAD points directly to a commit hash rather than a named branch ref.
Working TreeThe visible directory of files on your disk that you can see, edit, and compile.
Index / StagingBinary cache file (.git/index) recording the prepared snapshot for the upcoming commit.
Fast-ForwardMerge where the target branch pointer is simply moved forward to the incoming commit without a new merge commit.
Three-Way MergeMerge combining two divergent branches using their common ancestor (merge base). Creates a merge commit.
RebaseReplaying commits from one branch on top of another base commit to maintain linear history.
ReflogReference Log. Local sequential history of every position HEAD and branch tips have occupied.
OriginThe default shorthand nickname given to the remote repository you cloned from.
UpstreamThe remote tracking branch associated with your current branch, or the original parent repository of a fork.
Bare RepositoryA repository initialized without a working tree (contains only .git contents). Used on servers like ProGit.

Git Revert

Safe Non-Destructive Inversion of Public Commits and Merge Reversals

What is git revert?

git revert is the safest way to undo changes that have already been pushed to a remote repository (such as main on ProGit or GitHub). Unlike git reset, which erases commits from the history graph, git revert records a brand-new commit that applies the exact mathematical inverse diff of the target commit.

Why Revert is Safe for Teams
Because git revert appends a new commit forward in time, it does not rewrite project history. Other team members can pull normally without encountering divergent history or merge conflicts.

Reverting a Single Commit

# Revert the most recent commit on current branch
git revert HEAD

# Revert a specific commit by hash
git revert 4a8f9c2

# Revert without opening text editor (use default generated commit message)
git revert --no-edit 4a8f9c2

Reverting Multiple Commits Without Multiple Commit Messages

# Revert a range of commits and leave changes staged in index (no auto-commit)
git revert -n HEAD~3..HEAD

# Create a single cohesive revert commit
git commit -m "revert: rollback payment v2 integration due to gateway timeout"

Reverting a Merge Commit (The -m Flag)

A merge commit has two parent commits. When you revert a merge commit, Git does not know which branch's changes should be kept. You must specify the mainline parent with -m 1:

# Revert merge commit, preserving parent 1 (mainline)
git revert -m 1 8bf129a -m "revert: rollback merge of feature/crypto-wallet"

Git Reset

Understanding the Three Reset Modes: Soft, Mixed, and Hard

The Three Modes of git reset

git reset moves the current branch pointer (HEAD) backwards in time to a specified commit. How it treats the Staging Area (Index) and your Working Tree depends entirely on which flag you provide:

Command FlagHEAD PointerStaging Area (Index)Working Tree (Files on Disk)
git reset --soft <commit> Moved back to <commit> Untouched! Changes remain staged. Untouched! All your work remains safe.
git reset --mixed <commit>
(Default if no flag given)
Moved back to <commit> Reset to match <commit> (un-stages changes). Untouched! Changes remain in working tree as un-staged edits.
git reset --hard <commit> Moved back to <commit> Reset to match <commit>. DESTRUCTIVE! All modified and un-staged changes are permanently erased to match <commit>.

Scenario 1: Undo Commit, Keep Changes Staged (--soft)

Ideal when you committed too early and want to add another file or change the commit message:

# Undo last commit, keep changes staged in index
git reset --soft HEAD~1

# Add missing file and commit properly
git add forgotten_test.go
git commit -m "feat(api): complete endpoint with unit test coverage"

Scenario 2: Unstage Everything (--mixed)

# Unstage files without losing any code on disk
git reset HEAD~1

Scenario 3: Complete Discard to Match Previous Commit (--hard)

Warning: Destructive Command
git reset --hard permanently destroys uncommitted changes in your working tree. Ensure you have no unsaved work, or run git stash first.
# Discard all changes and restore workspace to exact state of origin/main
git reset --hard origin/main

Git Amend

Modifying the Most Recent Commit, Adding Forgotten Files, and Fixing Messages

What is git commit --amend?

git commit --amend takes whatever is currently staged in your index and combines it with the previous commit, creating a revised commit snapshot that replaces the previous commit entirely.

Use Case 1: Fixing a Typo in the Commit Message

# Open text editor to edit commit message of the last commit
git commit --amend

# Or set new message directly without opening text editor:
git commit --amend -m "fix(auth): correct token expiry calculation in JWT validator"

Use Case 2: Adding a Forgotten File to the Last Commit

# Stage the missed file
git add config/settings.yaml

# Amend commit while preserving the original commit message
git commit --amend --no-edit
The Golden Rule of Amend
Because amending produces a new commit SHA-1 hash, you should never amend a commit that has already been pushed to a shared branch on ProGit or GitHub. Doing so will cause your local branch and the remote branch to diverge.

Git Rebase

Linear Commit Graphs, Rebasing onto Main, and Interactive Rebase (rebase -i)

What is Rebasing?

In Git, there are two primary ways to integrate changes from one branch into another: merging and rebasing.

While a merge creates a new three-way merge commit that ties two divergent histories together, rebasing takes the commits from your feature branch and replays them one-by-one on top of the newest commit of the base branch. The result is a perfectly linear, sequential project history without branching noise.

Rebasing a Feature Branch onto main

# 1. Fetch latest changes from remote
git fetch origin

# 2. Switch to your feature branch
git switch feature/payments

# 3. Rebase your feature commits onto the tip of origin/main
git rebase origin/main

Interactive Rebase (git rebase -i)

Interactive rebase is one of Git's most potent features. It allows you to rewrite, squash, reorder, or drop your local unpushed commits before opening a pull request:

# Interactively inspect and edit the last 4 commits
git rebase -i HEAD~4

Git opens your text editor with a list of commits prefixed by command words:

pick a1b2c3d feat(user): add database migration for users table
pick e4f5g6h fix typo in migration
pick 7i8j9k0 feat(user): add repository query methods
pick 1l2m3n4 wip test debugging

Interactive Rebase Commands

CommandEffect
pick (p)Keep the commit as-is.
reword (r)Keep the commit, but pause to edit the commit message.
edit (e)Pause rebase at this commit to amend code or add files.
squash (s)Melt this commit into the previous commit and concatenate their commit messages.
fixup (f)Melt this commit into the previous commit and discard this commit's message.
drop (d)Delete this commit entirely from history.

Resolving Conflicts During a Rebase

# 1. Edit conflicting files and resolve conflict markers
# 2. Stage resolved files:
git add internal/user/repo.go

# 3. Continue the rebase:
git rebase --continue

# Or abort and restore original state:
git rebase --abort

Git Reflog

The Ultimate Safety Net: Tracking HEAD Movements and Recovering History

What is the Reference Log (reflog)?

Git maintains a local ledger called the Reference Log (reflog) in .git/logs/HEAD. Every single time HEAD or a local branch pointer moves—whether due to a commit, checkout, switch, rebase, merge, reset, or pull—Git appends an immutable entry to the reflog.

Even if you run git reset --hard and believe you erased your work, the commits still exist in the Git object database and are tracked in the reflog for up to 90 days before garbage collection (git gc) runs.

Viewing the Reflog

git reflog
# Output:
# 4a8f9c2 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
# b7e3d11 HEAD@{1}: commit: feat(api): add health check probe
# 9f2a4b8 HEAD@{2}: commit: feat(auth): implement jwt token validator
# 1c3e5d7 HEAD@{3}: checkout: moving from feature/auth to main

Time-Traveling with HEAD@{n}

Each reflog entry has a selector representing steps back in time:

# View commit diff of where HEAD was 2 actions ago
git show HEAD@{2}

# View reflog entries for a specific branch
git reflog show feature/payments

# View where HEAD was 2 hours ago
git reflog show --date=relative

Git Recovery

Disaster Recovery Recipes: Undoing Hard Resets, Restoring Deleted Branches, and Rescuing Work

Emergency Disaster Recovery Recipes

Here are step-by-step solutions to the 4 most common Git emergencies:

Scenario 1: You Ran git reset --hard by Accident

# 1. Run reflog to find the commit hash immediately before your reset
git reflog

# 2. Look for the action before "reset: moving to...":
# b7e3d11 HEAD@{1}: commit: feat(api): add health check probe

# 3. Reset hard to that reflog selector:
git reset --hard HEAD@{1}
# Working directory and all commits are 100% restored!

Scenario 2: You Deleted an Unmerged Branch by Mistake

# You ran: git branch -D feature/payments
# 1. Find the commit hash that was at the tip of the deleted branch:
git reflog
# Look for: 9f2a4b8 HEAD@{4}: commit: feat(pay): integrate stripe api

# 2. Re-create the branch pointing directly at that commit hash:
git branch feature/payments 9f2a4b8
# Branch and all unmerged commits are completely restored!

Scenario 3: You Committed to the Wrong Branch (e.g. main instead of a feature branch)

# 1. Create a new feature branch from your current position (preserves commit):
git branch feature/new-analytics

# 2. Reset main back one commit:
git reset --hard HEAD~1

# 3. Switch to your feature branch:
git switch feature/new-analytics
# main is clean, and your work is safely on the new feature branch!

Scenario 4: Finding Dangling Objects with git fsck

If all else fails and reflog was cleared, scan the raw object database:

git fsck --lost-found
# Shows: dangling commit a1b2c3d...
git show a1b2c3d

Git .gitignore

Ignoring Build Artifacts, OS Junk, Secrets, Glob Patterns, and Cache Removal

What is .gitignore?

A .gitignore text file placed in your project root instructs Git to deliberately ignore untracked files that should never be committed into the repository—such as compiled binaries, dependency folders, logs, OS metadata, and sensitive credentials.

Pattern Matching & Glob Syntax Rules

PatternBehavior / Match Rule
# CommentLines starting with # are comments and ignored.
*.logMatches any file ending in .log anywhere in the project tree.
build/Matches and ignores any directory named build and all its children.
/distLeading slash anchors the match to the project root (ignores root dist/, but not src/dist/).
**/temp** matches directories recursively at any depth.
!important.logExclamation point negates an ignore pattern (forces file to be tracked).
temp?.txt? matches exactly one character (e.g. temp1.txt).

Production Multi-Language .gitignore Template

# Operating System Junk
.DS_Store
Thumbs.db

# Secrets & Environment Variables (NEVER COMMIT)
.env
.env.local
*.pem
*.key

# Go Build Artifacts
/bin/
*.exe
vendor/

# Node.js / Frontend
node_modules/
dist/
.next/
npm-debug.log*

# Python
__pycache__/
*.py[cod]
.venv/
venv/

Debugging Ignore Rules

To determine which exact line in which .gitignore file is causing a file to be ignored:

git check-ignore -v path/to/my-file.log
# Output: .gitignore:4:*.log  path/to/my-file.log

Un-tracking a File That Was Committed Accidentally

If a file was committed before being added to .gitignore, Git continues tracking it. To remove it from Git while keeping the file on your local disk:

# Remove from Git index without deleting the file on disk
git rm --cached .env

# Commit the removal
git commit -m "chore: stop tracking .env secret file"

Git .gitattributes

Line-Ending Normalization, Binary File Flags, Merge Drivers, and Export Controls

What is .gitattributes?

The .gitattributes file defines path-specific settings across your repository. It ensures consistent line endings between developers on Windows and Linux/macOS, specifies which files are binary, customizes merge drivers, and controls what is excluded from release archives.

1. Cross-Platform Line-Ending Normalization

Prevent noisy diffs where every line is marked modified due to Carriage Return differences:

# Set default behavior: auto-normalize text files to LF on commit
* text=auto

# Explicitly declare text files that must ALWAYS have LF line endings
*.go text eol=lf
*.sh text eol=lf
*.js text eol=lf
*.py text eol=lf
*.md text eol=lf

# Windows batch files must retain CRLF
*.bat text eol=crlf
*.cmd text eol=crlf

2. Declaring Binary Files

Ensure Git does not attempt to calculate text diffs or normalize line endings on binaries:

*.png binary
*.jpg binary
*.pdf binary
*.tar.gz binary
*.wasm binary

3. Custom Merge Drivers & Release Archive Exports

# Always keep our version on conflict (e.g. database schema dumps)
db/schema.rb merge=ours

# Exclude test suites and CI workflows when generating git archive release tarballs
/tests export-ignore
/.github export-ignore
/.githooks export-ignore

Git Large File Storage (LFS)

Handling Multi-Megabyte Binaries Without Bloating Repository Objects

Why Git Struggles with Large Binary Files

In standard Git, every modification to a file stores a complete new compressed object in .git/objects/. If a designer commits five 200 MB Photoshop files or machine learning weights, every developer who clones the repository must download all 1 GB of historical binaries—even if they only need the latest code.

Git Large File Storage (Git LFS) solves this by replacing large files inside your Git repository with tiny pointer text files (around 130 bytes). The actual binary payloads are stored on dedicated LFS storage servers (such as ProGit's built-in LFS or S3 buckets).

Anatomy of an LFS Pointer File

version https://git-lfs.github.com/spec/v1
oid sha256:4d7a2846a4d773f3e389f4b00f4f71ec16d87fa923c52c2c00882d16177aa3e0
size 124589201

Installing and Using Git LFS

# 1. Install Git LFS hooks on your machine (one-time setup)
git lfs install

# 2. Tell LFS which file extensions to track
git lfs track "*.psd"
git lfs track "*.bin"
git lfs track "models/*.onnx"

# 3. Commit the generated .gitattributes file
git add .gitattributes
git commit -m "chore: track binary models with Git LFS"

# 4. Add, commit, and push normally
git add models/weights.onnx
git commit -m "feat(ai): add initial quantized transformer weights"
git push origin main

Managing Local LFS Disk Cache

# Fetch LFS objects for current checkout only
git lfs pull

# Delete old cached LFS files from local machine to free up disk space
git lfs prune

Git Signing Commits/Tags

Cryptographic Proof of Identity Using GPG and Modern SSH Signatures

Why Cryptographically Sign Commits?

In Git, the author and committer names and emails are arbitrary strings defined in git config. Anyone can easily spoof commits claiming to be Linus Torvalds or your enterprise CEO.

Cryptographic Signing generates a mathematical signature embedded into each commit or tag using your private key. Remote platforms like ProGit and GitHub verify this against your registered public key and display a green "Verified" badge.

Option A: Modern SSH Signature Signing (Git 2.34+ - Recommended)

Starting with Git 2.34, you no longer need complex GPG tools; you can sign commits directly with your existing Ed25519 SSH key:

# 1. Tell Git to use SSH for signing
git config --global gpg.format ssh

# 2. Specify your SSH public key path
git config --global user.signingkey ~/.ssh/id_ed25519.pub

# 3. Enable automatic commit signing for all commits
git config --global commit.gpgsign true

# 4. Enable automatic tag signing
git config --global tag.gpgsign true

Option B: Traditional GPG Signing

# 1. Generate GPG Key Pair
gpg --full-generate-key
# Choose RSA (4096-bit) or Ed25519, enter name and email

# 2. Get your GPG Key ID
gpg --list-secret-keys --keyid-format=long
# Example output: sec   rsa4096/3AA5C34371567BD2 ...

# 3. Configure Git with your key ID
git config --global user.signingkey 3AA5C34371567BD2
git config --global commit.gpgsign true

Verifying Signed Commits in Terminal

git log --show-signature -n 1
# Output:
# commit 9e2b10a (HEAD -> main)
# gpg: Signature made Sun Nov  8 11:15:20 2026 IST
# gpg: using ED25519 key 4A8F9C2...
# gpg: Good signature from "Sanjeev Senapati <sanjeev@prodevans.com>" [ultimate]

Git Cherrypick & Patch

Porting Specific Commits Across Branches, Generating Email Patches, and Applying Diffs

What is git cherry-pick?

git cherry-pick allows you to select a specific commit from any branch and apply its exact changes onto your currently checked-out branch as a brand-new commit.

This is invaluable when a critical bugfix was made on a develop branch and needs to be backported immediately to a production main or release/v1.0 branch without merging unrelated unfinished work.

Basic Cherry-Picking

# 1. Switch to target branch where you want the fix
git switch main

# 2. Apply a specific commit from develop branch
git cherry-pick 7a4e1b9

# 3. Cherry-pick without auto-committing (leaves changes staged)
git cherry-pick -n 7a4e1b9

Cherry-Picking a Range of Commits

# Cherry-pick all commits from A up to B (inclusive)
git cherry-pick A^..B

Generating and Applying Patches

Before modern pull requests, developers collaborated by exchanging email patches:

# Generate a formatted Unix mailbox patch for the latest commit
git format-patch -1 HEAD
# Creates 0001-feat-add-sqlite-wal.patch

# Inspect what the patch will change
git apply --stat 0001-feat-add-sqlite-wal.patch

# Check if patch applies cleanly without errors
git apply --check 0001-feat-add-sqlite-wal.patch

# Apply patch and record commit with original author, timestamp, and message
git am 0001-feat-add-sqlite-wal.patch

Git Merge Conflicts

Conflict Marker Anatomy, Three-Way Resolution Walkthrough, and Verification

Why Do Merge Conflicts Occur?

A merge conflict occurs when two different branches have modified the exact same lines of a file since their common ancestor, or when one branch modified a file while the other branch deleted it. Git refuses to guess which version is correct and pauses the merge so a human engineer can review.

Anatomy of Conflict Markers

Git edits the conflicting file directly and inserts visual delimiter markers:

<<<<<<< HEAD
// Changes on your current branch (e.g. main)
const databaseURL = "sqlite://data/progit.db?cache=shared&mode=wal";
=======
// Incoming changes from the branch being merged (e.g. feature/db)
const databaseURL = process.env.DATABASE_URL || "postgres://localhost:5432/progit";
>>>>>>> feature/postgres-support

Step-by-Step Resolution Process

  1. Locate Conflicted Files:
    git status
    # Conflicted files show as "both modified: database/connection.js"
  2. Open and Edit Files: Open the file in your editor, decide which logic to preserve (or combine them), and delete all marker lines (<<<<<<<, =======, >>>>>>>).
  3. Stage Resolved Files:
    git add database/connection.js
  4. Finalize the Merge:
    git commit -m "merge: resolve database connection string conflict"
Safety Exit: Aborting Conflicted Merges
If you make a mistake or want to abort the merge entirely and return to your pre-merge state, simply run: git merge --abort (or git rebase --abort).

Git CI/CD

How Git Events Drive Automated Testing, Webhook Triggers, and Status Gating

The Convergence of Git and CI/CD

Modern Continuous Integration and Continuous Deployment (CI/CD) is entirely driven by Git repository events. Rather than manual deployments by system administrators, Git acts as the single source of truth (GitOps).

Developer git push origin ProGit Server HTTP POST Webhook CI Runner Lint, Test, Build Deploy Production

Figure 3.1: Git Event-Driven CI/CD Architecture.

Key Git Triggers for Automation

  • Push to Feature Branch: Triggers automated unit testing, static code analysis (SonarQube/golangci-lint), and builds preview containers.
  • Pull Request Created / Synchronized: Executes end-to-end integration tests and reports pass/fail status back to the PR merge button.
  • Merge to main: Automatically compiles release binaries, builds Docker container images, pushes to registry, and rolls out to staging/production.
  • Tag Created (v*): Triggers release pipelines, generates GitHub/ProGit release notes, and deploys release packages.

Git Hooks

Automating Checks with Pre-Commit, Commit-Msg, Pre-Push, and Server Hooks

What are Git Hooks?

Git hooks are custom executable scripts that Git fires automatically before or after key actions (like committing, pushing, or receiving code). They live inside .git/hooks/ as sample scripts ending in .sample.

Client-Side vs. Server-Side Hooks

Hook NameScopeWhen It Executes & Use Case
pre-commitClientRuns before commit message is written. Validates code formatting, runs linters, scans for leaked API keys. Exit code ≠ 0 cancels commit.
commit-msgClientValidates the commit message text (enforces Conventional Commits formatting).
pre-pushClientRuns right before git push transmits objects. Runs fast unit tests.
pre-receiveServerRuns on Git server (ProGit). Enforces branch protection, verifies signed commits, prevents pushes with files > 50 MB.
post-receiveServerRuns on Git server after push is accepted. Triggers webhooks and sends notifications.

Writing a Custom pre-commit Hook

Create an executable script at .git/hooks/pre-commit:

#!/bin/bash
# .git/hooks/pre-commit

echo "==> Running automated pre-commit quality checks..."

# Check 1: Scan for accidental AWS / Private key commits
if git diff --staged | grep -E "AKIA[0-9A-Z]{16}|BEGIN PRIVATE KEY"; then
  echo "ERROR: Leaked credentials or private keys detected in staged files!"
  exit 1
fi

# Check 2: Run Go unit tests
go test -v ./...
if [ $? -ne 0 ]; then
  echo "ERROR: Go unit tests failed! Fix tests before committing."
  exit 1
fi

echo "All pre-commit checks passed cleanly."
exit 0

Make the script executable:

chmod +x .git/hooks/pre-commit

# Version controlling hooks across your entire team:
git config core.hooksPath .githooks

Git Submodules

Embedding External Repositories, Recursive Cloning, and Submodule Synchronization

What is a Git Submodule?

A submodule allows you to keep an external Git repository as a subdirectory of another Git repository. The parent repository does not track the external repository's files directly; instead, it records a specific commit SHA-1 pointer in the parent tree and maintains remote repository metadata in a file named .gitmodules.

Adding a Submodule to Your Project

# Add external library repository into libs/proto
git submodule add https://progit.co.in/prodevans/proto.git libs/proto

# Commit the new submodule and .gitmodules file
git add .gitmodules libs/proto
git commit -m "chore: embed proto contract submodule"

Cloning a Repository That Contains Submodules

When you run normal git clone, submodule directories will be empty! To download everything automatically:

# Clone repo AND all embedded submodules recursively
git clone --recurse-submodules https://progit.co.in/prodevans/app.git

# If you already cloned normally, initialize and fetch submodules:
git submodule update --init --recursive

Updating Submodule Commit Pointers

# Pull latest upstream commits inside the submodule
cd libs/proto
git switch main && git pull origin main

# Switch back to parent repo and record the new submodule pointer
cd ../..
git add libs/proto
git commit -m "chore: bump proto submodule to latest commit"

Git Remote Advanced

Multiple Remotes, Refspecs, Remote Pruning, and Safe Force-Pushing

Managing Multiple Remotes

In open-source and enterprise workflows, you often track both your own fork (origin) and the shared company upstream repository (upstream):

# View current remotes and URLs
git remote -v

# Add upstream remote pointing to central organization repo
git remote add upstream https://progit.co.in/prodevans/core-service.git

# Sync your local main with upstream main
git fetch upstream
git switch main
git merge upstream/main

Pruning Deleted Remote Tracking Branches

When a colleague deletes a merged branch on the remote server, your local Git still keeps obsolete origin/feature-xyz references. Clean them up with pruning:

# Fetch and prune deleted branches in one command
git fetch --prune

# Or prune a specific remote
git remote prune origin

Understanding Refspecs

Inside .git/config, Git defines how remote branches map to local tracking branches via refspecs:

[remote "origin"]
    url = https://progit.co.in/prodevans/app.git
    fetch = +refs/heads/*:refs/remotes/origin/*

The leading + indicates that Git will update the remote-tracking ref even if the update is not a fast-forward.

Safe Force-Pushing (--force-with-lease)

Never Use git push -f
Blind force pushing (-f) overwrites whatever is on the remote server, potentially destroying a colleague's commits pushed since your last fetch.

Always use --force-with-lease:

# Only force push if the remote branch has NOT received any new commits since your last fetch
git push --force-with-lease origin feature/my-branch

ProGit Architecture & Zero CGO

Pure Go Engine, Sub-50ms Cold Boots, < 40 MB RAM Footprint, and High-Concurrency SQLite WAL

What is ProGit?

ProGit is an ultra-fast, high-concurrency self-hosted Git collaboration platform engineered entirely in pure Go with zero external database dependencies and an embedded modern React 19 single-page application.

ProGit provides development teams and enterprises with a sovereign, sovereign-controlled alternative to public cloud services like GitHub and GitLab, as well as an upgraded modern successor to legacy platforms like Gogs and Gitea.

Zero CGO & Pure Go Compilation
Unlike traditional Git platforms that link against native C libraries (libgit2, SQLite via GCC), ProGit compiles with CGO_ENABLED=0. It produces a completely static binary that runs on Linux, macOS, and minimal Alpine containers without external shared library dependencies.

Architectural Highlights

  • Memory Footprint: Consumes under 40 MB of RAM under typical production workloads (compared to GitLab's 4 GB to 8 GB minimum).
  • Sub-50ms Cold Starts: Boots from disk and starts serving HTTP and SSH Git traffic in under 50 milliseconds.
  • High-Concurrency SQLite WAL: Uses modernc.org/sqlite with Write-Ahead Logging (WAL) and automated checkpoints for outstanding concurrent read/write throughput without needing PostgreSQL or MySQL.
  • Built-in SSH Server (Port 2222): Pure-Go SSH implementation isolated from host system accounts.
  • Embedded React 19 UI: Single binary embeds all compiled web assets, templates, and localization files.

ProGit Container Quickstart

Launching ProGit with Podman or Docker in Under 5 Minutes

5-Minute Container Deployment

ProGit distributes official, hardened multi-architecture container images on GitHub Container Registry (GHCR) supporting both Intel/AMD (x86_64) and ARM64 (Apple Silicon / AWS Graviton).

Option A: Rootless Podman Deployment (Recommended)

# Create persistent data volume on host
mkdir -p ~/progit/data

# Run ProGit container rootless
podman run -d --name progit \
  -p 3000:3000 \
  -p 2222:2222 \
  -v ~/progit/data:/data:Z \
  ghcr.io/sanjeevsenapati/progit:latest

Option B: Docker Compose Deployment

Create a docker-compose.yml file:

version: '3.8'

services:
  progit:
    image: ghcr.io/sanjeevsenapati/progit:latest
    container_name: progit
    restart: always
    ports:
      - "3000:3000"   # HTTP Web UI & Smart Git HTTPS
      - "2222:2222"   # Built-in SSH Git Server
    volumes:
      - ./progit-data:/data
    environment:
      - PROGIT_RUN_MODE=prod
      - PROGIT_DOMAIN=progit.co.in
# Start container in background
docker compose up -d

# Verify container is running and healthy
curl -I http://localhost:3000/
# Output: HTTP/1.1 200 OK

Web Installation & Security Hardening

Initial Configuration Wizard, Super Administrator Setup, and Disabling the Install URL

Initial Setup via Web Installation Wizard

When you access ProGit for the very first time at http://localhost:3000/install, you are presented with the graphical setup wizard:

  1. Database Settings: Select SQLite3 (path defaults to /data/progit.db).
  2. Application Name: Set your organization or company title (e.g. ProGit Enterprise).
  3. Domain & Port Settings: Domain progit.co.in, HTTP Port 3000, SSH Port 2222.
  4. Administrator Account: Create the initial Super Administrator username, password, and email.
  5. Click Install ProGit to initialize the database schema.

Hardening Security: Disabling the /install Path

Preventing Unauthorized Re-Installation
Once the installation wizard finishes and the initial admin user is created, ProGit automatically sets INSTALL_LOCK = true in app.ini. This permanently disables the /install endpoint in the browser to prevent malicious attackers from reconfiguring the database.

Creating Subsequent Administrators via CLI

For ongoing operations, the ops team can create additional admin accounts directly via the CLI without exposing any browser install endpoints:

# Create new admin user directly via CLI binary
progit admin user create --name alice --password "SuperSecretPass123!" --email alice@prodevans.com --admin=true

SSH Keys & Personal Access Tokens

Setting Up Ed25519 Keys on Port 2222, Generating PATs, and Enterprise SSO

Authentication in ProGit

ProGit supports high-security cryptographic authentication across both Git CLI and Web UI access:

1. Setting Up Ed25519 SSH Keys (Port 2222)

ProGit embeds its own pure-Go SSH server listening by default on port 2222:

# 1. Generate an Ed25519 cryptographic key pair
ssh-keygen -t ed25519 -C "sanjeev@prodevans.com"

# 2. View your public key
cat ~/.ssh/id_ed25519.pub
# Copy output: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... sanjeev@prodevans.com

3. Open ProGit Web UI → Click your avatar → Settings → SSH Keys → Click Add Key → Paste your public key.

2. Generating Personal Access Tokens (PAT)

For automated CI/CD pipelines, curl scripts, or HTTPS Git operations, generate a scoped Personal Access Token:

  1. Navigate to Settings → Access Tokens.
  2. Enter a description (e.g. macbook-terminal) and select scopes (repo, user).
  3. Copy the token (e.g. pgt_84bf7291a...). Use this token as your password when cloning or pushing over HTTPS.
# Clone via HTTPS using Personal Access Token
git clone https://sanjeev:pgt_84bf7291a...@progit.co.in/prodevans/backend.git

Repository Creation & Branch Protection

Creating Repositories, Pushing Existing Projects, and Enforcing Branch Protection Rules

Repository Lifecycle on ProGit

Repositories on ProGit can be created via the web interface or pushed directly from an existing local project:

Pushing an Existing Local Codebase to ProGit

# 1. In terminal, navigate to your local codebase
cd /path/to/my-project

# 2. Add your ProGit repository as the 'origin' remote
git remote add origin https://progit.co.in/prodevans/my-project.git

# 3. Push all commits and set upstream branch tracking
git push -u origin main

Branch Protection Rules

To protect critical branches (e.g., main, release/*) from regressions or accidental force-pushes, ProGit allows repository administrators to configure branch protection:

  • Require Pull Request Before Merging: Direct pushes to the protected branch are blocked. All code must pass peer review.
  • Require Status Checks to Pass: Automated CI/CD pipelines (unit tests, security scanners) must report success before the merge button unlocks.
  • Restrict Who Can Merge: Limit merge approval authority to designated tech leads or repo owners.
  • Prevent Force Pushes & Deletion: Disallows git push --force and branch deletion.

Online Web IDE & 8 Syntax Themes

In-Browser Code Editing, Folder Uploads, Prettier Formatting, and Syntax Highlighters

The ProGit Built-In Web IDE

ProGit features an integrated, full-featured in-browser code editor that allows developers to review code, create files, edit multi-line source code, and format on the fly without launching a local IDE.

Key Web IDE Capabilities

  • Online File Creation & Editing: Add new files, modify source code, and commit directly from your web browser with custom commit messages.
  • Recursive Folder Uploads: Drag-and-drop entire directory trees into the browser to upload assets and source bundles.
  • Prettier Integration: One-click automated code formatting for JavaScript, TypeScript, JSON, Markdown, and YAML.

8 Curated Syntax Highlighter Themes

Developers can customize their editing workspace with 8 beautiful built-in color schemes:

Theme NameAesthetic Profile
DraculaRich dark purple with vibrant pink and cyan accents.
NordArctic, north-bluish clean minimalist palette.
MonokaiClassic hacker dark theme with bright yellow and magenta highlights.
GitHub DarkThe familiar, elegant dark theme from GitHub.
Synthwave '84Neon retro 80s aesthetic with glowing purples and magentas.
Solarized DarkScientifically calibrated contrast palette reducing eye fatigue.
One DarkAtom / VS Code standard dark slate aesthetic.
Material OceanDeep oceanic blue tones inspired by Google Material Design.

Pull Requests & Merge Strategies

Public Visibility, Member-Only Merge Controls, and Three Native Merge Strategies

Pull Requests in ProGit

ProGit implements full GitHub-class Pull Request workflows for collaborative code review and quality gating:

1. Public Visibility for Open-Source Collaboration

In public repositories, any user—even unauthenticated visitors—can explore code diffs, review discussions, and inspect commits. This enables seamless community open-source participation.

2. Restricted Member-Only Merge Controls

Security Scoped Merge Permissions
While anyone can read public pull requests, the Merge Pull Request action is strictly restricted to authenticated users who possess write permissions on the target repository or the original repository owner.

3. Three Native Merge Strategies

When merging a pull request, ProGit offers three configurable merge strategies:

  • Create a Merge Commit (--no-ff): Preserves all historical commits from the branch and adds a merge commit.
  • Squash and Merge: Combines all commits from the PR into a single clean commit on the target branch. Keeps history compact.
  • Rebase and Merge: Replays commits linearly on top of the base branch without creating a merge commit.

Git-Backed Wiki Engine

Dual-Interface Documentation via Web Markdown Editor and Offline Bare Git Clone

The Git-Backed Wiki Engine

Documentation is a first-class citizen in ProGit. Every repository has an optional built-in Wiki powered by a dedicated Git repository under the hood.

Dual-Interface Documentation Management

  • Web UI Markdown Editor: Create, edit, and organize documentation pages directly in the browser with live Markdown preview. If no wiki exists, users see a GitHub-style "Create your first Wiki page" prompt.
  • Offline Git Bare Clone: Every wiki is stored as a Git repository named <repo-name>.wiki.git. You can clone it locally, edit markdown in your favorite editor, and push changes:
# Clone repository wiki locally to your workstation
git clone https://progit.co.in/prodevans/backend.wiki.git

# Enter wiki folder and edit markdown pages
cd backend.wiki
echo "# Architecture Overview" > Architecture.md

# Commit and push documentation updates
git add Architecture.md
git commit -m "docs: add system architecture diagram"
git push origin main

Repository Wiki Settings

Repository administrators can enable or disable the Wiki module at any time via Repository Settings → Collaboration Features → Enable Wiki.

ProGit Pages Static Hosting

Zero-Configuration Web Hosting from Git Branches and Custom Domains

What is ProGit Pages?

ProGit Pages is a built-in static site hosting service directly integrated into ProGit. It allows engineering teams to host documentation portals, project showcases, and single-page apps directly from their repository branches with zero external web servers.

Supported Branch Sources

You can configure ProGit Pages to publish from:

  • The docs branch (serving from root).
  • The gh-pages branch (standard GitHub Pages convention).
  • The main branch (serving from the /docs directory).

Custom Domain (CNAME) Support

To bind a custom domain (such as progit.co.in), simply commit a CNAME text file to the publishing branch root:

# CNAME file content:
progit.co.in

ProGit Pages automatically configures HTTP routing and serves assets with optimal caching headers.

Developer Direct Messaging

User Search, Connection Request Acceptance Protocols, and Server Enable Flags

Developer Direct Messaging

ProGit provides a secure internal direct messaging feature allowing developers to communicate directly inside the platform without needing third-party chat tools.

Privacy-Preserving User Discovery

  • No Public User Scraping: To protect developers from spam, username harvesting, and misuse, ProGit does not display an unrestricted public directory of all registered users.
  • Search by Username or Email: Users must actively search for a teammate's username or email ID to initiate contact.
  • Connection Acceptance Protocol: When a user sends a message to a new contact, the recipient receives a connection prompt. Messages must be accepted before a conversation begins. If the recipient rejects the request, the sender is respectfully notified.

Server-Wide Configuration Flag

System administrators can enable or disable the direct messaging capability across the entire server via app.ini:

[feature]
ENABLE_MESSAGES = true  # Set to false to disable messaging platform-wide

Agile Kanban Project Boards

Visual Sprint Columns, Issue Tracking, Milestones, and Story Assignment

Kanban Project Boards in ProGit

Every repository and organization on ProGit features visual Kanban boards for agile sprint planning and issue tracking:

  • Custom Sprint Columns: Organize tasks into Backlog, In Progress, Code Review, and Done.
  • Drag-and-Drop Workflow: Move cards between columns with automated status synchronization.
  • Issue & PR Integration: Link issues directly to Pull Requests; merging a PR automatically moves associated cards to Done.
  • Team Assignment & Milestones: Assign assignees, label priorities (e.g. bug, p0-blocker), and group tasks into release Milestones with burndown tracking.

Webhooks & CI/CD Integration

Configuring Outgoing HTTP POST Webhooks, HMAC Secret Verification, and Event Delivery

ProGit Webhooks

Webhooks allow external services (like CI/CD runners, Jenkins, Slack, or Discord) to be notified whenever specific events happen in your repository.

Configuring a Webhook

  1. In your repository, navigate to Settings → Webhooks → Add Webhook.
  2. Set Payload URL: https://ci.mycompany.com/webhook.
  3. Set Content Type: application/json.
  4. Enter a shared Secret for HMAC-SHA256 signature verification.
  5. Choose trigger events: Push Events, Pull Requests, Issues, or All Events.

Verifying Webhook Signatures in Backend Services

ProGit sends the HMAC hex digest in the X-ProGit-Signature header:

// Example Go verification middleware
mac := hmac.New(sha256.New(), []byte(webhookSecret))
mac.Write(requestBody)
expectedSignature := hex.EncodeToString(mac.Sum(nil))

if !hmac.Equal([]byte(headerSignature), []byte(expectedSignature)) {
    http.Error(w, "Invalid signature", http.StatusUnauthorized)
    return
}

Danger Zone & Administration

Repository Renaming, Ownership Transfer, Archiving, and Deletion Security

Repository Danger Zone Operations

Located at the bottom of Repository Settings → Danger Zone, these actions permanently alter or remove repository resources and require explicit confirmation:

1. Transferring Repository Ownership

Transfer a repository to another user or an organization (e.g. from sanjeev/backend to prodevans/backend). ProGit automatically updates internal Git paths and sets up HTTP redirect stubs so existing Git remotes continue working.

2. Archiving a Repository (Read-Only Mode)

Places the repository in immutable read-only mode. All commits, issues, and wikis remain readable, but all pushes, pull request creations, and edits are blocked.

3. Deleting a Repository

Irreversible Deletion Protection
Deleting a repository purges all Git objects, wiki pages, issues, and pull request histories from disk. ProGit requires the user to manually type the full repository name (e.g. prodevans/core-api) and verify their password before proceeding.

CI/CD Fundamentals (CI vs CD vs CD)

Continuous Integration, Delivery, and Deployment Explained

Understanding CI, CD, and CD

In modern DevOps, the acronym CI/CD covers three distinct levels of pipeline automation:

PhaseWhat It DoesOutcome / Artifact
Continuous Integration (CI) Automates the building, compilation, linting, and unit/integration testing of code upon every commit and pull request. Validated commit status report (green checkmark or red failure). Catches bugs before code reaches main.
Continuous Delivery (CD) Automatically packages passing code into production-ready deployment artifacts (Docker container images, compiled binaries, Helm charts) and deploys to a staging environment. Artifact stored in registry (e.g. GHCR, Docker Hub), ready for manual one-click promotion to production.
Continuous Deployment (CD) Takes Continuous Delivery one step further by automatically releasing passing changes directly to production with zero human intervention. Live production code updated automatically whenever a PR merges into main.

GitHub Actions Architecture & YAML

Event Triggers, Runner Environments, Job Dependencies, and Step Anatomy

GitHub Actions Operational Architecture

GitHub Actions uses declarative YAML files placed in the .github/workflows/*.yml directory of your repository. Here is the structural hierarchy:

1. Event Trigger push: [main] pull_request schedule / cron 2. Runner & Jobs runs-on: ubuntu-latest Parallel jobs or sequential needs: [build-job] 3. Steps & Actions - uses: actions/checkout - uses: actions/setup-go - run: go test ./...

Figure 5.1: GitHub Actions Execution Flow.

Anatomy of a Workflow File

name: CI Pipeline

on: # 1. Triggers
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs: # 2. Jobs
  test:
    runs-on: ubuntu-latest # Runner environment
    steps: # 3. Sequential steps
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Setup Go Runtime
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'

      - name: Run Test Suite
        run: go test -v -race ./...

Pipeline 1: Automated Test & Lint

Complete Production CI Matrix Across Go Versions with Linting and Race Detection

Production CI Matrix Pipeline

Save this file as .github/workflows/ci.yml. It triggers on every push and pull request, executing linters and unit tests across a version matrix:

name: Continuous Integration

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  lint:
    name: Code Quality & Linting
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.23'
          cache: true

      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@v6
        with:
          version: v1.60

  test:
    name: Unit & Integration Tests
    needs: [ lint ]
    runs-on: ubuntu-latest
    strategy:
      matrix:
        go-version: [ '1.22', '1.23' ]
        os: [ ubuntu-latest ]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Go ${{ matrix.go-version }}
        uses: actions/setup-go@v5
        with:
          go-version: ${{ matrix.go-version }}
          cache: true

      - name: Run Tests with Race Detector
        run: go test -v -race -coverprofile=coverage.out ./...

      - name: Upload Test Coverage Artifact
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report-go-${{ matrix.go-version }}
          path: coverage.out

Pipeline 2: Docker Build & GHCR

Multi-Architecture Container Images (amd64, arm64) with Layer Caching

Production Multi-Architecture Container Build

Save this as .github/workflows/docker-publish.yml. It builds production images for both Intel/AMD (x86_64) and ARM64 (Apple Silicon / AWS Graviton) using Docker Buildx and pushes to GitHub Container Registry (GHCR):

name: Build and Publish Container Image

on:
  push:
    branches: [ main ]
    tags: [ 'v*.*.*' ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-push:
    name: Build Multi-Arch Docker Image
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up QEMU (for multi-architecture emulation)
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Docker metadata (Tags & Labels)
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha,format=short

      - name: Build and Push Multi-Arch Image
        uses: docker/build-push-action@v5
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Pipeline 3: Deploy via SSH

Zero-Downtime Remote Production Deployment via SSH and Docker Compose

Production SSH Deployment Pipeline

Save this as .github/workflows/deploy.yml. It securely connects to your production Linux server over SSH, pulls the newest container image, and performs a zero-downtime rolling reload:

name: Deploy to Production Server

on:
  workflow_run:
    workflows: [ "Build and Publish Container Image" ]
    types: [ completed ]
    branches: [ main ]

jobs:
  deploy:
    name: Remote SSH Deployment
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    steps:
      - name: Execute Remote Deployment Script via SSH
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.PROD_SERVER_HOST }}
          username: ${{ secrets.PROD_SERVER_USER }}
          key: ${{ secrets.PROD_SSH_PRIVATE_KEY }}
          port: 22
          script: |
            echo "==> Deploying newest ProGit release..."
            cd /opt/progit
            
            # Pull latest container image
            podman pull ghcr.io/prodevans/progit:main
            
            # Restart service container with zero downtime
            podman-compose down && podman-compose up -d
            
            # Health check probe
            sleep 3
            curl -f http://127.0.0.1:3000/api/v1/version || exit 1
            echo "==> Deployment successfully verified!"

Pipeline 4: Static Site Deployment

Automated Documentation Build and Publishing to ProGit Pages / GitHub Pages

Automated Documentation Publishing Pipeline

Save this as .github/workflows/pages.yml. It publishes documentation and static sites to the docs or gh-pages branch whenever changes occur:

name: Deploy Documentation Portal

on:
  push:
    branches: [ main ]
    paths:
      - 'index.html'
      - 'tutorial.html'
      - 'docs/**'

permissions:
  contents: write

jobs:
  deploy-pages:
    name: Sync Documentation to Pages
    runs-on: ubuntu-latest
    steps:
      - name: Checkout main branch
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Sync and Push to docs branch
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          
          # Checkout docs publishing branch
          git checkout docs || git checkout -b docs
          
          # Pull latest docs from main
          git checkout main -- index.html tutorial.html docs/ sitemap.xml robots.txt
          
          # Commit and push
          git add -A
          git diff --quiet && git diff --staged --quiet || git commit -m "docs: auto-deploy updated documentation [skip ci]"
          git push origin docs

CI/CD Secrets & Production Security

Least Privilege Scopes, Secret Masking, SHA Pinning, and OIDC Federation

Hardening CI/CD Pipelines

CI/CD runners have access to production credentials, making them prime targets for supply-chain attacks. Follow these mandatory security protocols:

1. Enforce Least Privilege Token Permissions

Always declare the permissions: block in your workflow files to strip unnecessary default permissions from GITHUB_TOKEN:

permissions:
  contents: read      # Read-only repo access
  packages: write     # Allowed to push container packages
  pull-requests: write # Allowed to post PR comments

2. Pin GitHub Actions by Full Commit SHA

Tags (like @v4) can be mutated if a maintainer account is compromised. In enterprise environments, pin third-party actions to immutable commit SHAs:

# Instead of: uses: actions/checkout@v4
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

3. Masking Secrets and Log Protection

Never echo environment secrets to the console. GitHub Actions masks known repository secrets, but nested variables or curl payloads can be accidentally leaked. Use ::add-mask:: if your script dynamically fetches sensitive values:

echo "::add-mask::$DYNAMIC_API_KEY"

Git Command Cheat Sheet

Complete CLI Matrix of Everyday and Emergency Commands

Essential Git CLI Matrix

Action / OperationCommand Syntax
Initialize repositorygit init [directory]
Clone repositorygit clone <url>
Check statusgit status -s
Stage changesgit add <file> / git add -A
Interactive staginggit add -p
Create commitgit commit -m "feat: message"
Amend last commitgit commit --amend --no-edit
Create branchgit switch -c <branch-name>
Switch branchgit switch <branch-name>
List branchesgit branch -a
Delete branchgit branch -d <name> / git push origin -d <name>
Merge branchgit merge --no-ff <branch>
Squash mergegit merge --squash <branch>
Rebase onto maingit rebase main
Interactive rebasegit rebase -i HEAD~N
Stash changesgit stash push -m "wip"
Restore stashgit stash pop
View commit graphgit log --graph --oneline --decorate --all
Inspect commit diffgit show <hash>
Safe undo commitgit revert <hash>
Soft reset (keep staged)git reset --soft HEAD~1
Mixed reset (unstage)git reset HEAD~1
Destructive resetgit reset --hard <commit>
View reflog ledgergit reflog
Push with trackinggit push -u origin <branch>
Safe force pushgit push --force-with-lease origin <branch>
Prune deleted remotesgit fetch --prune
Create annotated taggit tag -a v1.0.0 -m "Release v1.0.0"
Push all tagsgit push origin --tags

GitHub Actions Syntax Sheet

Workflow Anatomy, Contexts, Expressions, and Built-in Variables

GitHub Actions Syntax Reference

YAML ElementDescription / Example
on: pushTriggers workflow on code push to specified branches or tags.
on: pull_requestTriggers when a PR is opened, synchronized, or reopened.
on: workflow_dispatchEnables manual execution button in the web UI with custom input parameters.
on: scheduleRuns workflow on a cron schedule: - cron: '0 0 * * *' (every midnight).
runs-on:Specifies the runner OS: ubuntu-latest, windows-latest, macos-latest, or self-hosted.
needs: [jobA]Forces the job to run only after jobA completes successfully.
matrix:Runs the job across multiple OS/language versions in parallel.
uses: actions/...Executes a reusable pre-built action from GitHub Marketplace.
with:Supplies input parameters to an action.
env:Defines environment variables accessible to steps.
${{ secrets.VAR }}Securely injects an encrypted repository secret.
${{ github.sha }}The full 40-character commit SHA that triggered the workflow.
${{ github.ref }}The branch or tag ref that triggered the workflow (e.g. refs/heads/main).
if: failure()Condition step to run only if a previous step failed.
if: always()Forces step to run even if previous steps failed or were cancelled.