docs(git): add research reference corpus for git plugin

11 topic files covering the full git surface area needed for skill and
agent authoring: overview, installation, configuration, cli-reference,
commits (Conventional Commits v1.0.0), branching-merging, submodules,
worktrees, gitflow, remotes (push/pull/fetch/force-with-lease), and
history-inspection (bisect, log --format, pickaxe, --diff-filter).
Includes sources.md mapping all 13 source documents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147vXtL5sP6vorDdqXGJJU9
This commit is contained in:
2026-06-28 20:34:42 +00:00
parent 69f395f0f6
commit e1e85284d1
12 changed files with 2043 additions and 0 deletions

View File

@@ -0,0 +1,180 @@
---
topic: branching-merging
source_keys:
- context7-git-htmldocs
---
## Branching Model
Git branches are cheap: each is just a ref file (41 bytes) pointing to a commit. Creating, switching, and deleting branches is a sub-millisecond operation regardless of repo size.
The canonical branching workflow is:
1. Create a branch from a stable point (usually `main` or `develop`).
2. Commit work on the branch.
3. Integrate back via merge or rebase.
4. Delete the branch.
## Creating and Switching Branches
```bash
git switch -c <branch> # create and switch (preferred, Git 2.23+)
git switch -c <branch> <start> # from a specific commit or remote branch
git switch <existing-branch> # switch to existing
git switch - # switch back to previous branch
# Legacy equivalents
git checkout -b <branch>
git checkout <branch>
```
When switching, Git updates `HEAD`, the index, and the working tree. Uncommitted changes that conflict with the target branch will block the switch (Git refuses to overwrite them).
## Merge Strategies
### Fast-forward merge
If the target branch has not diverged from the source, Git simply advances the branch pointer — no merge commit is created. History remains linear.
```bash
git merge <branch> # fast-forward if possible
```
### True merge (--no-ff)
Forces a merge commit even when a fast-forward is possible. Preserves the fact that a group of commits came from a branch. Required by Gitflow on all supporting-branch merges.
```bash
git merge --no-ff <branch>
git merge --no-ff -m "Merge feature/X" <branch>
```
### Squash merge
Collapses all commits from the source branch into a single staged change, which you then commit manually. Keeps the target branch history clean; discards individual commit granularity.
```bash
git merge --squash <branch>
git commit -m "feat: add X" # separate commit step required
```
### Octopus merge
Merging more than two branches simultaneously. Git uses this by default when you pass multiple branch names. Fails on conflicts — use sequential two-way merges when conflicts are expected.
```bash
git merge branch-a branch-b branch-c
```
## Conflict Resolution
When Git cannot auto-merge, it inserts conflict markers into the affected files and stops:
```
<<<<<<< HEAD
current branch content
=======
incoming branch content
>>>>>>> feature/x
```
Resolution workflow:
```bash
# 1. Find conflicted files
git status
# 2. Edit each file to resolve markers, then stage
git add <resolved-file>
# 3. Continue
git merge --continue # or git commit if --continue is unavailable
# Alternatively: abort and reset
git merge --abort
```
Tools:
```bash
git mergetool # open configured merge.tool (meld, vimdiff, etc.)
git diff --diff-filter=U # show only conflicted files
```
## Rebase
Rebase replays a sequence of commits on top of a new base, rewriting SHAs in the process. The result is a linear history with no merge commits.
```bash
git rebase main # rebase current branch onto main
git rebase --onto <newbase> <upstream> <branch> # transplant a range
```
**Interactive rebase** — rewrites local history:
```bash
git rebase -i HEAD~5 # edit last 5 commits
```
Interactive commands:
| Command | Effect |
|---|---|
| `pick` | Keep commit as-is |
| `reword` | Keep commit but edit message |
| `edit` | Pause for amending |
| `squash` | Fold into previous commit (keep message) |
| `fixup` | Fold into previous commit (discard message) |
| `drop` | Remove commit entirely |
| `exec` | Run a shell command |
**Golden rule of rebasing:** Never rebase commits that have been pushed to a shared branch. Rebase rewrites history; force-pushing to shared branches breaks other people's local copies.
## Conflict Resolution During Rebase
```bash
# Resolve each conflicting commit, then:
git add <file>
git rebase --continue
# Skip a problematic commit:
git rebase --skip
# Abort and return to pre-rebase state:
git rebase --abort
```
## Cherry-picking
Applies the diff introduced by a specific commit onto the current branch as a new commit.
```bash
git cherry-pick <sha> # apply one commit
git cherry-pick <sha-a>^..<sha-b> # apply a range (inclusive)
git cherry-pick -n <sha> # stage without committing (for editing)
```
Cherry-picking does not maintain a history link between branches. For sharing code between branches, prefer merge or rebase unless you specifically need to apply an isolated patch.
## Tracking Branches
A tracking relationship lets `git pull` and `git push` know which remote branch to target.
```bash
git push -u origin <branch> # push and set upstream
git branch --set-upstream-to=origin/<branch> # set tracking on existing branch
git branch -vv # show tracking info for all branches
```
`@{upstream}` (or `@{u}`) is shorthand for the tracked remote branch:
```bash
git log @{u}..HEAD # commits not yet pushed
git diff @{u} # diff against upstream
```
## Comparing Branches
```bash
git log main..feature # commits in feature not in main
git log feature..main # commits in main not in feature
git log --left-right main...feature # both diverging sets (symmetric diff)
git diff main...feature # diff from common ancestor to feature tip
git merge-base main feature # print the common ancestor commit
```

View File

@@ -0,0 +1,212 @@
---
topic: cli-reference
source_keys:
- context7-git-htmldocs
- git-scm-docs
---
## Setup and Init
```bash
git init [<directory>] # initialise new repo (or reinit existing)
git init --bare # bare repo (no working tree; used as remote)
git clone <url> [<directory>] # clone a remote repo
git clone --recurse-submodules # clone including all submodules
git clone --depth <n> # shallow clone (only last n commits)
git clone --filter=blob:none # blobless partial clone
```
## Staging and Status
```bash
git status # show working tree and staging area state
git status -s # short format
git add <file> # stage a file
git add -p # interactively stage hunks
git add -A # stage all changes including deletions
git rm <file> # remove file from index and working tree
git rm --cached <file> # unstage (remove from index only)
git mv <old> <new> # rename/move a file
git diff # unstaged changes
git diff --cached # staged changes (what will be committed)
git diff HEAD # all uncommitted changes
git restore <file> # discard working tree changes (Git 2.23+)
git restore --staged <file> # unstage (Git 2.23+)
```
## Committing
```bash
git commit -m "<message>" # commit with inline message
git commit # open editor for message
git commit -a # stage tracked changes and commit in one step
git commit --amend # rewrite the most recent commit (local only)
git commit --amend --no-edit # amend without changing the message
git commit --allow-empty # commit with no changes (useful for triggers)
```
### Key `git commit` Flags
| Flag | Meaning |
|---|---|
| `-m <msg>` | Inline message; multiple `-m` flags become separate paragraphs |
| `-F <file>` | Read message from file; `-` reads from stdin |
| `-a` | Auto-stage modified tracked files |
| `-n` / `--no-verify` | Skip pre-commit and commit-msg hooks |
| `--author "<Name> <email>"` | Override author |
| `--date <date>` | Override author date |
| `--squash=<commit>` | Prefix message with "squash!" for use with `rebase --autosquash` |
| `--fixup=<commit>` | Prefix message with "fixup!" for `rebase --autosquash` |
| `--reset-author` | Reassign authorship to the committer (use with `--amend`) |
| `--trailer <token>:<value>` | Append a footer trailer to the message |
| `--cleanup=<mode>` | Control message whitespace handling: `strip`, `whitespace`, `verbatim`, `scissors` |
## Branching
```bash
git branch # list local branches
git branch -a # list local and remote branches
git branch -vv # show tracking info and last commit
git branch <name> # create branch at current HEAD
git branch <name> <start> # create branch at specific commit
git branch -d <name> # delete (safe — refuses if unmerged)
git branch -D <name> # delete (force)
git branch -m <old> <new> # rename branch
git branch --set-upstream-to=origin/<branch> # set tracking
git switch <branch> # switch to branch (Git 2.23+)
git switch -c <branch> # create and switch (Git 2.23+)
git checkout <branch> # switch (legacy)
git checkout -b <branch> # create and switch (legacy)
```
## Merging
```bash
git merge <branch> # merge branch into current branch
git merge --no-ff <branch> # always create a merge commit
git merge --squash <branch> # squash into a single staged change
git merge --abort # cancel an in-progress merge
git merge --continue # continue after conflict resolution
git merge -m "<msg>" <branch> # custom merge commit message
git merge --into-name <branch> # override branch name in default message
```
## Rebasing
```bash
git rebase <base> # rebase current branch onto base
git rebase -i HEAD~<n> # interactive rebase of last n commits
git rebase -i <commit> # interactive rebase from commit onwards
git rebase --onto <newbase> <upstream> <branch> # transplant branch
git rebase --continue # continue after conflict resolution
git rebase --abort # restore pre-rebase state
git rebase --skip # skip the conflicting commit
git rebase --quit # abort but keep HEAD position
git rebase --autosquash # auto-apply fixup!/squash! commits
```
Interactive rebase `pick` commands: `pick`, `reword`, `edit`, `squash`, `fixup`, `drop`, `exec`, `break`, `label`, `reset`, `merge`.
## Cherry-picking
```bash
git cherry-pick <commit> # apply a commit onto current branch
git cherry-pick <a>..<b> # apply a range (exclusive of a)
git cherry-pick <a>^..<b> # apply a range (inclusive of a)
git cherry-pick -n <commit> # apply without committing (stage only)
git cherry-pick --abort
git cherry-pick --continue
```
## History and Inspection
```bash
git log # full log
git log --oneline # compact one-line per commit
git log --graph --oneline --all # branch graph
git log --stat # show file change counts
git log -p # show patch diff for each commit
git log --author="<name>"
git log --grep="<pattern>"
git log --since="2 weeks ago"
git log <file> # history of a specific file
git log <branch>..<branch> # commits in second not in first
git show <commit> # show commit details and diff
git diff <commit1> <commit2> # diff between two commits
git blame <file> # annotate each line with last commit
git bisect start # start binary search for bug
git bisect good <commit>
git bisect bad <commit>
git bisect reset
```
## Remote Operations
```bash
git remote -v # list remotes
git remote add <name> <url> # add a remote
git remote remove <name>
git remote rename <old> <new>
git fetch <remote> # download objects and refs
git fetch --all # fetch all remotes
git fetch --prune # remove stale remote-tracking refs
git pull # fetch + merge (or rebase if configured)
git push <remote> <branch> # push branch to remote
git push -u origin <branch> # push and set upstream
git push --force-with-lease # safe force push (checks remote tip)
git push --tags # push tags
git push origin :<branch> # delete remote branch
```
## Stashing
```bash
git stash # stash working tree and index
git stash push -m "<msg>" # stash with description
git stash push -u # include untracked files
git stash list # show all stashes
git stash pop # apply most recent and remove from list
git stash apply stash@{n} # apply without removing
git stash drop stash@{n} # delete a stash
git stash clear # delete all stashes
git stash branch <branch> # create branch from stash
```
## Tags
```bash
git tag # list tags
git tag <name> # lightweight tag at HEAD
git tag -a <name> -m "<msg>" # annotated tag
git tag <name> <commit> # tag a specific commit
git tag -d <name> # delete local tag
git push origin <tag> # push tag
git push origin --tags # push all tags
git push origin :refs/tags/<name> # delete remote tag
```
## Undoing
```bash
git reset HEAD~1 # undo last commit, keep changes staged
git reset --soft HEAD~1 # undo last commit, keep changes staged
git reset --mixed HEAD~1 # undo last commit, unstage changes
git reset --hard HEAD~1 # undo last commit, discard changes
git revert <commit> # create new commit that undoes a past commit
git revert -n <commit> # stage the revert without committing
git clean -fd # delete untracked files and directories
git clean -n # dry run (show what would be deleted)
```
## Plumbing (scripting-safe)
```bash
git rev-parse HEAD # print full SHA of HEAD
git rev-parse --short HEAD # print short SHA
git rev-parse --show-toplevel # print repo root path
git symbolic-ref HEAD # print the ref HEAD points to
git cat-file -t <sha> # print object type
git cat-file -p <sha> # print object contents
git update-ref refs/heads/<b> <sha> # set a ref to a commit
git for-each-ref refs/heads/ # list refs with metadata
```

View File

@@ -0,0 +1,169 @@
---
topic: commits
source_keys:
- conventional-commits-spec
- commitlint-config-conventional
---
## Conventional Commits Specification (v1.0.0)
Conventional Commits is a lightweight convention on top of commit messages that provides a set of rules for creating an explicit commit history. It enables automated tooling (CHANGELOG generation, semantic version bumping) and structured filtering.
## Message Format
```
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
Each section is separated by a blank line. The header is the only required part.
## Rules
| Element | Rule |
|---|---|
| `type` | Required. Lowercase noun. |
| `scope` | Optional. Noun in parentheses directly after type: `feat(api):`. |
| `description` | Required. Immediately follows `type/scope: `. Imperative mood, no trailing period. |
| `body` | Optional. Begins one blank line after description. Free-form prose, multiple paragraphs allowed. |
| `footer(s)` | Optional. Begins one blank line after body (or description). `<token>: <value>` format. |
| `BREAKING CHANGE` | Must be uppercase. Either a footer token or signalled by `!` before the colon. |
## Standard Types
The spec mandates only `feat` and `fix`. The following 11 types are the de-facto standard from `@commitlint/config-conventional` (Angular commit message guidelines):
| Type | Meaning | SemVer impact | Appears in CHANGELOG |
|---|---|---|---|
| `feat` | New user-visible feature | MINOR | Yes |
| `fix` | Bug fix | PATCH | Yes |
| `perf` | Performance improvement, no API change | PATCH | Yes |
| `revert` | Reverts a previous commit | PATCH | Yes |
| `docs` | Documentation only | none | No |
| `style` | Formatting, whitespace — no logic change | none | No |
| `refactor` | Code restructuring — no feature or fix | none | No |
| `test` | Adding or fixing tests | none | No |
| `build` | Build system or external dependency changes | none | No |
| `ci` | CI configuration and scripts | none | No |
| `chore` | Anything not fitting above | none | No |
A `BREAKING CHANGE` footer or `!` on **any** type always triggers a MAJOR bump.
## Breaking Changes
Two equivalent notations:
**`!` in header** (preferred — visible in `git log --oneline`):
```
feat!: drop support for Node 6
feat(api)!: remove deprecated endpoint
```
**`BREAKING CHANGE` footer** (machine-readable body):
```
feat: allow config to extend other configs
BREAKING CHANGE: `extends` key now used for extending config files
```
**Both together** (most explicit):
```
feat!: drop support for Node 6
BREAKING CHANGE: use JavaScript features not available in Node 6.
```
Rules:
- `BREAKING CHANGE` must be all caps.
- `BREAKING-CHANGE` (hyphenated) is an accepted synonym.
- Any type can carry a breaking change, not just `feat`.
- The footer value must describe what broke.
## Footer Token Rules
```
<token>: <value>
<token> #<value> # for issue references
```
- Tokens use hyphens for word separation: `Reviewed-by`, `Co-authored-by`, `Refs`.
- Exception: `BREAKING CHANGE` (space allowed, uppercase).
- Multiple footers allowed, one per line.
- Blank line required before the footer block.
Valid footer examples:
```
Reviewed-by: Z
Refs: #123
Co-authored-by: Alice <alice@example.com>
BREAKING CHANGE: the `--format` flag now requires a value
```
## Examples
Minimal — no body, no footer:
```
docs: correct spelling of CHANGELOG
```
With scope:
```
feat(lang): add Polish language
```
Breaking change via `!`:
```
feat!: send an email to the customer when a product is shipped
```
Breaking change via footer:
```
feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
```
Multi-paragraph body with multiple footers:
```
fix: prevent racing of requests
Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.
Remove timeouts which were used to mitigate the racing issue but are
obsolete now.
Reviewed-by: Z
Refs: #123
```
Revert:
```
revert: let us never again speak of the noodle incident
Refs: 676104e, a215868
```
## commitlint Constraints (`config-conventional`)
| Constraint | Value |
|---|---|
| Header max length | 100 characters |
| Subject must not end with `.` | enforced |
| Subject must be lowercase | enforced (not sentence-case or UPPER-CASE) |
| Body / footer line max length | 100 characters |
| Type must be one of the 11 standard types | error if not |
| Blank line before body | warning |
| Blank line before footer | warning |
## SemVer Mapping Summary
| Condition | SemVer bump |
|---|---|
| `fix`, `perf`, `revert` | PATCH |
| `feat` | MINOR |
| Any type with `BREAKING CHANGE` or `!` | MAJOR |
| All other types (`docs`, `style`, `refactor`, `test`, `build`, `ci`, `chore`) | none |

View File

@@ -0,0 +1,147 @@
---
topic: configuration
source_keys:
- git-scm-docs
---
## Config Scopes
Git reads configuration from three scopes in order: system → global → local. The last value wins. A fourth `worktree` scope exists when `extensions.worktreeConfig` is enabled.
| Scope | Flag | File (Linux/macOS) | File (Windows) |
|---|---|---|---|
| system | `--system` | `$(prefix)/etc/gitconfig` | `$(prefix)\etc\gitconfig` |
| global | `--global` | `~/.gitconfig` or `$XDG_CONFIG_HOME/git/config` | `%USERPROFILE%\.gitconfig` |
| local | `--local` (default) | `.git/config` | `.git/config` |
| worktree | `--worktree` | `.git/config.worktree` | `.git/config.worktree` |
Writes default to local scope. Pass `--global` to write user-wide settings.
## Inspecting Config
```bash
git config --list # merged view of all scopes
git config --global --list # global scope only
git config --global --edit # open in $EDITOR
git config --get user.email # read a single key
git config --unset core.editor # remove a key
```
## Essential Variables
### Identity (required — no defaults)
```bash
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
```
These are stamped on every commit. There is no system default — omitting them causes `git commit` to fail.
### Editor
```bash
git config --global core.editor "code --wait" # VS Code
git config --global core.editor "vim"
git config --global core.editor "nano"
```
Used for commit messages, rebase TODO lists, `git notes edit`, etc. Falls back to `$VISUAL` / `$EDITOR` env vars if unset.
### Default Branch Name
```bash
git config --global init.defaultBranch main
```
Controls the name of the initial branch created by `git init`. Defaults to `master` on most installations; set to `main` to match current convention.
### Pull Behaviour
```bash
git config --global pull.rebase true # rebase instead of merge on pull
```
| Value | Behaviour |
|---|---|
| `false` | Merge (creates a merge commit) |
| `true` | Rebase (rewrites local commits on top of fetched) |
| `merges` | Rebase, preserving merge commits |
| `interactive` | Interactive rebase on pull |
Leaving this unset causes a warning on every `git pull` in Git ≥ 2.27. Setting `pull.rebase true` is the cleaner-history choice for most workflows.
### Push Behaviour
```bash
git config --global push.default simple
```
| Value | Behaviour |
|---|---|
| `simple` (default) | Push current branch to its upstream; refuse if names differ |
| `current` | Push current branch to same-named remote branch |
| `upstream` | Push to the branch's configured upstream, regardless of name |
| `matching` | Push all matching local/remote branch pairs |
| `nothing` | Refuse all pushes unless an explicit refspec is given |
### Line Endings
```bash
# Windows
git config --global core.autocrlf true
# Linux / macOS
git config --global core.autocrlf input
```
`true` converts CRLF→LF on check-in and LF→CRLF on check-out (Windows). `input` converts CRLF→LF on check-in only.
### Credential Storage
```bash
git config --global credential.helper cache # in-memory, expires
git config --global credential.helper osxkeychain # macOS Keychain
git config --global credential.helper manager-core # Windows Credential Manager
```
### Global Ignore File
```bash
git config --global core.excludesFile ~/.gitignore_global
```
Patterns in this file are ignored across all repos without touching `.gitignore`.
### Merge and Diff Tools
```bash
git config --global merge.tool meld # or vimdiff, kdiff3, etc.
git config --global diff.tool vimdiff
```
### Aliases
Defined under `[alias]` in the config file:
```ini
[alias]
st = status
co = checkout
br = branch -vv
last = log -1 HEAD
lg = log --graph --oneline --decorate --all
undo = reset --soft HEAD~1
```
## Minimal First-Time Setup
```bash
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global core.editor "vim"
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global push.default simple
git config --global credential.helper cache
git config --global core.excludesFile ~/.gitignore_global
```

View File

@@ -0,0 +1,158 @@
---
topic: gitflow
source_keys:
- nvie-gitflow-post
- atlassian-gitflow-tutorial
- gitflow-cheatsheet
---
## Core Philosophy
Gitflow is a branching model that treats branching and merging as routine operations, not exceptional ones. It defines a strict structure where every branch has a fixed purpose, a fixed origin point, and a fixed merge target. This predictability enables automated tooling and makes the history of any project self-documenting.
The central invariant: `main` always reflects production-ready code; `develop` always reflects the latest integrated development state. All other branches are temporary scaffolding.
The model was designed for software with **explicit versioned releases**. Vincent Driessen (the original author) noted in 2020 that teams doing continuous delivery should prefer GitHub Flow instead.
## The Five Branch Types
### 1. `main` (permanent)
HEAD always reflects a production-ready, releasable state. Every commit is tagged with a version. Automated deployment pipelines trigger off this branch.
**Receives merges from:** `release/*` and `hotfix/*` only. Never committed to directly.
### 2. `develop` (permanent)
Integration branch for all completed features. HEAD reflects the latest delivered development changes for the next release. When `develop` is feature-complete for a release, a release branch forks from it.
**Receives merges from:** `feature/*`, `release/*`, `hotfix/*`.
### 3. Feature branches (short-lived)
| Property | Value |
|---|---|
| Branch from | `develop` |
| Merge back to | `develop` |
| Naming | `feature/<name>` or `feature/TICKET-123-description` |
Isolate development of a single feature. Live primarily in developer local repos; pushed to `origin` only when collaboration is needed. No direct relationship with `main`.
Lifecycle:
1. Branch from `develop`.
2. Develop in isolation.
3. Merge back to `develop` with `--no-ff`.
4. Delete the branch.
### 4. Release branches (short-lived)
| Property | Value |
|---|---|
| Branch from | `develop` |
| Merge back to | both `main` AND `develop` |
| Naming | `release/<version>` (e.g. `release/1.2.0`) |
Purpose: prepare a production release. Once branched, no new features — only bug fixes, version bumping, and release metadata. This frees `develop` to receive features for the *next* release immediately.
Lifecycle:
1. Branch from `develop` when it has reached the desired state.
2. Bump the version number as the first commit.
3. Fix last-minute bugs directly on the release branch.
4. Merge into `main` with `--no-ff`; tag the merge commit with the version.
5. Merge back into `develop` with `--no-ff` (to carry bug fixes forward).
6. Delete the branch.
### 5. Hotfix branches (short-lived)
| Property | Value |
|---|---|
| Branch from | `main` (from the tagged production commit) |
| Merge back to | both `main` AND `develop` (or active release branch) |
| Naming | `hotfix/<version>` (e.g. `hotfix/1.2.1`) |
Purpose: emergency patches for production bugs. Allows fixing critical issues without interrupting feature development on `develop`.
Lifecycle:
1. Branch from `main`.
2. Bump the patch version.
3. Fix the bug.
4. Merge into `main` with `--no-ff`; tag with new version.
5. Merge into `develop` with `--no-ff` — or into the active release branch if one is open (it will carry the fix into `develop` at close).
6. Delete the branch.
## Naming Conventions
| Branch type | Convention | Examples |
|---|---|---|
| Permanent | exact name | `main`, `develop` |
| Feature | `feature/<name>` | `feature/login-oauth`, `feature/JIRA-42-cart` |
| Release | `release/<version>` | `release/2.1.0` |
| Hotfix | `hotfix/<version>` | `hotfix/2.1.1` |
Versions follow semantic versioning: `MAJOR.MINOR.PATCH`.
## The `--no-ff` Rule
All merges of supporting branches (feature, release, hotfix) into permanent branches use `--no-ff`:
```bash
git merge --no-ff <branch>
```
This forces a merge commit even when a fast-forward is possible, preserving the branch history in the DAG. Without it, the commit group collapses into a linear history and you lose the ability to identify which commits belonged to a given feature or to revert a feature atomically by reverting the merge commit.
## Hard Invariants
1. `main` only receives merges from `release/*` and `hotfix/*`.
2. `develop` only receives merges from `feature/*`, `release/*`, and `hotfix/*`.
3. All merges into permanent branches use `--no-ff`.
4. Release branches are created from `develop`; hotfix branches are created from `main`.
5. Both release and hotfix branches merge into **both** `main` and `develop` at close.
6. Version tags are applied to the merge commit on `main`.
## git-flow CLI
The `git-flow` CLI wraps the manual operations. The `git-flow-avh` fork is the most maintained.
**Setup:**
```bash
git flow init # interactive prompt for branch naming
git flow init -d # use defaults without prompting
```
**Feature branches:**
```bash
git flow feature start <name> # branch feature/<name> from develop
git flow feature finish <name> # merge into develop (--no-ff), delete
git flow feature publish <name> # push to origin
git flow feature track <name> # track a remote feature branch
```
**Release branches:**
```bash
git flow release start <version> # branch release/<version> from develop
git flow release publish <version> # push for collaboration
git flow release finish <version> # merge into main (tagged) + develop, delete
```
**Hotfix branches:**
```bash
git flow hotfix start <version> # branch hotfix/<version> from main
git flow hotfix finish <version> # merge into main (tagged) + develop, delete
```
## When to Use Gitflow
**Good fit:**
- Software with explicit versioned releases: libraries, desktop apps, mobile apps, versioned APIs.
- Projects that must maintain and patch multiple concurrent production versions.
- Larger teams with parallel feature development and release preparation happening simultaneously.
- Workflows where release preparation (docs, QA, sign-off) takes meaningful calendar time.
**Poor fit / when not to use:**
- Continuously deployed web applications (SaaS, internal tools, websites) — release branches add ceremony with no benefit when deploys happen multiple times per day.
- Teams practising trunk-based development where the trunk is always deployable — GitHub Flow (short-lived feature branches off `main`, fast merges, immediate deploy) is simpler and better matched.
- Small teams or solo projects where branching overhead exceeds the benefit.
- Projects without versioned releases.
Driessen's own 2020 note: "If your team is doing continuous delivery of software, I would suggest to adopt a much simpler workflow (like GitHub Flow) instead of trying to shoehorn git-flow into your team."

View File

@@ -0,0 +1,359 @@
---
topic: history-inspection
source_keys:
- git-scm-bisect-docs
- git-scm-log-docs
- git-scm-diff-docs
- context7-git-htmldocs
---
## git bisect
Binary search through commit history to find the commit that introduced a bug or behaviour change. Requires O(log2 N) test steps.
### Core Workflow
```bash
git bisect start
git bisect bad # current HEAD is broken
git bisect good <commit> # known-good baseline
# Git checks out midpoint. Test, then:
git bisect good # test passed
git bisect bad # test failed
# Repeat until Git prints "X is the first bad commit"
git bisect reset # return to original HEAD
git bisect reset <commit> # return to a specific commit
git bisect reset bisect/bad # check out the bad commit itself
```
Compact start form:
```bash
git bisect start HEAD v1.2 -- # HEAD=bad, v1.2=good; -- separates paths
git bisect start HEAD v1.2 -- src/ # limit bisection to src/ directory
```
### bisect run — Automated Mode
```bash
git bisect run <cmd> [<arg>...]
```
Runs `<cmd>` on each candidate commit. Git interprets the exit code:
| Exit code | Meaning |
|---|---|
| `0` | Good (test passed) |
| `1–124` | Bad (test failed) |
| `125` | Skip this commit (cannot test — e.g. build broken) |
| `126–127` | POSIX shell errors — treated as bad |
| `128+` | Aborts the bisect session |
The 125 build-failure skip pattern:
```bash
#!/bin/sh
make || exit 125 # skip if build is broken
./check_test_case.sh # 0=good, nonzero=bad
```
Keep test scripts outside the repository so checkout does not clobber them.
### bisect skip
```bash
git bisect skip # skip current commit
git bisect skip v2.5..v2.6 # skip a range (v2.5 exclusive, v2.6 inclusive)
git bisect skip v2.5 v2.5..v2.6 # skip point commit + range
```
If the first bad commit is adjacent to a skipped commit, bisect reports it cannot pinpoint the exact culprit but prints the likely candidates.
### bisect log / bisect replay
```bash
git bisect log # print session history (good/bad/skip decisions)
git bisect log > bisect.log # save to file
# edit bisect.log to remove a wrong decision
git bisect reset && git bisect replay bisect.log # replay from edited log
```
Use `log` + `replay` to undo mistakes without restarting from scratch.
### bisect visualize / view
```bash
git bisect visualize # open remaining suspects in gitk
git bisect view # alias for visualize
git bisect visualize --stat # show stat instead of full diff
git bisect visualize -p # show patches
```
Falls back to `git log` when no graphical display is detected (checks `DISPLAY`, `SESSIONNAME`, `MSYSTEM`, `SECURITYSESSIONID`).
### Non-Bug Hunts: new / old / custom terms
Use `new`/`old` when searching for a property change rather than a regression:
```bash
git bisect start
git bisect new HEAD # has the property
git bisect old HEAD~10 # does not have the property
```
Custom terms:
```bash
git bisect start --term-new slow --term-old fast
git bisect slow # equivalent to: git bisect bad
git bisect fast # equivalent to: git bisect good
git bisect terms # show active term names
```
### Advanced Start Flags
| Flag | Effect |
|---|---|
| `--no-checkout` | Updates `BISECT_HEAD` ref instead of checking out; useful for tests that don't need a working tree; automatic in bare repos |
| `--first-parent` | Follow only first parents at merges; finds the integration commit that introduced a regression; ignores broken side branches |
| `-- <path>...` | Limit bisection to specific paths; reduces number of trials |
---
## git log — Format and Filtering
### Named Format Presets (`--format` / `--pretty`)
| Name | Output |
|---|---|
| `oneline` | `<hash> <title>` |
| `short` | hash, author, title |
| `medium` | hash, author, date, full message (default) |
| `full` | adds committer |
| `fuller` | separate author/committer dates |
| `reference` | `<abbrev> (<title>, <date>)` — for use in commit messages |
| `email` | RFC 2822 email format |
| `raw` | full object as stored in the object database |
| `format:<str>` | custom template with placeholders |
### Custom Format Placeholders
**Commit identity:**
| Placeholder | Meaning |
|---|---|
| `%H` | full commit hash |
| `%h` | abbreviated commit hash |
| `%T` | tree hash |
| `%t` | abbreviated tree hash |
| `%P` | full parent hashes |
| `%p` | abbreviated parent hashes |
**Author:**
| Placeholder | Meaning |
|---|---|
| `%an` | author name |
| `%aN` | author name (mailmap-resolved) |
| `%ae` | author email |
| `%aE` | author email (mailmap-resolved) |
| `%ad` | author date (respects `--date=`) |
| `%ar` | author date, relative |
| `%at` | author date, UNIX timestamp |
| `%ai` | author date, ISO 8601-like |
| `%aI` | author date, strict ISO 8601 |
| `%as` | author date, short (YYYY-MM-DD) |
**Committer:**
| Placeholder | Meaning |
|---|---|
| `%cn` | committer name |
| `%ce` | committer email |
| `%cd` | committer date (respects `--date=`) |
| `%cr` | committer date, relative |
| `%ct` | committer date, UNIX timestamp |
| `%ci` | committer date, ISO 8601-like |
| `%cs` | committer date, short |
**Message:**
| Placeholder | Meaning |
|---|---|
| `%s` | subject (first line) |
| `%f` | sanitized subject (filename-safe) |
| `%b` | body (everything after blank line following subject) |
| `%B` | raw body (subject + body) |
| `%N` | commit notes |
**Refs and decorations:**
| Placeholder | Meaning |
|---|---|
| `%d` | ref names (like `--decorate`) |
| `%D` | ref names without surrounding parentheses |
| `%S` | ref name by which commit was reached (requires `--source`) |
| `%(decorate[:opts])` | custom decorated refs; options: `prefix=`, `suffix=`, `separator=`, `pointer=`, `tag=` |
| `%(describe[:opts])` | like `git describe`; options: `tags=`, `abbrev=`, `match=`, `exclude=` |
**GPG signature:**
| Placeholder | Meaning |
|---|---|
| `%G?` | status: `G`=good, `B`=bad, `U`=unknown, `X`=expired, `R`=revoked, `N`=no signature |
| `%GS` | signer name |
| `%GK` | signing key ID |
**Trailers:**
```
%(trailers[:key=<k>][,only][,separator=<s>][,unfold][,keyonly][,valueonly])
```
**Formatting / color:**
| Placeholder | Meaning |
|---|---|
| `%n` | newline |
| `%%` | literal `%` |
| `%Cred` / `%Cgreen` / `%Cblue` / `%Creset` | terminal colors |
| `%C(<spec>)` | color per git-config spec |
| `%<(<n>[,trunc])` | right-pad field to width n |
| `%>(<n>)` | left-pad to width |
**Reflog** (requires `-g` / `--walk-reflogs`):
| Placeholder | Meaning |
|---|---|
| `%gD` | reflog selector (e.g. `refs/stash@{1}`) |
| `%gd` | shortened reflog selector |
| `%gs` | reflog subject |
### Pickaxe Search: -S and -G
**`-S<string>`** — finds commits where the **count** of `<string>` changed (i.e. the string was added or removed net). Does not match commits where the string merely appears in a diff hunk without a count change.
```bash
git log -S"my_function"
git log -S"my_function" --pickaxe-regex # treat as POSIX ERE
git log -S"my_function" --pickaxe-all # show all files in matching changesets
```
**`-G<regex>`** — finds commits where any added or removed **line** in the patch matches `<regex>`. Broader than `-S`: matches whenever the pattern appears in diff text regardless of count.
```bash
git log -G"frotz\(nitfol"
```
**Critical distinction:** given a diff that removes one occurrence of `foo` and adds one occurrence of `foo` (net change = 0):
- `-S"foo"` — does **not** match (count unchanged)
- `-G"foo"` — **matches** (pattern appears in patch text)
Binary files are searched by `-S`; ignored by `-G` unless `--text` is supplied.
**`--pickaxe-all`** — when a match is found, show all changed files in that changeset, not just the matching ones.
### --follow
```bash
git log --follow -- <file>
```
Continues file history across renames. Without `--follow`, log stops at the rename boundary. Only valid for a single file path.
### --diff-filter
Selects commits (in `git log`) or files (in `git diff`) by change type:
| Letter | Meaning |
|---|---|
| `A` | Added |
| `C` | Copied |
| `D` | Deleted |
| `M` | Modified |
| `R` | Renamed |
| `T` | Type changed (regular file ↔ symlink ↔ submodule) |
| `U` | Unmerged (conflict) |
| `X` | Unknown (indicates a git bug) |
| `B` | Pairing broken |
Lowercase letters **exclude** that type:
```bash
git log --diff-filter=ad # exclude added and deleted files
git log --diff-filter=M # only show commits with modified files
```
`C` and `R` only appear when copy/rename detection is enabled (`-C`, `-M` flags or `diff.renames` config).
### -L — Line Range History
Traces the evolution of a specific range of lines or a named function through commits. Implies `--patch`.
```bash
git log -L 10,20:file.txt
git log -L /start_pattern/,/end_pattern/:file.txt
git log -L :myfunction:src/app.c
git log -L /init/,+15:config.py # 15 lines after first match of /init/
```
Range formats:
| Format | Meaning |
|---|---|
| `<n>` | Absolute line number (1-based) |
| `/<regex>/` | First line matching regex from previous range end |
| `^/<regex>/` | First line matching regex from file start |
| `+<n>` / `-<n>` | Offset relative to `<start>` (end position only) |
Limitations: incompatible with `--raw`, `--numstat`, `--shortstat`, `--name-only`, `--name-status`, `--check`. Cannot use pathspec limiters alongside `-L`.
### Graph and Ancestry Filters
```bash
git log --first-parent # at merges, follow only first parent (mainline evolution)
git log --merges # only merge commits (≥2 parents); equivalent to --min-parents=2
git log --no-merges # only non-merge commits; equivalent to --max-parents=1
git log --ancestry-path D..M # only commits actually on the path from D to M
git log --min-parents=<n> # include only commits with ≥ n parents
git log --max-parents=<n> # include only commits with ≤ n parents
```
`--ancestry-path` is significant: without it, `D..M` includes all commits reachable from M but not D — including side branches that merged into the path. With it, only commits directly between D and M are shown.
---
## git diff — Output Control
### --stat
```bash
git diff --stat # diffstat: file names + ± bar
git diff --stat=<width>,<name-width>,<count>
git diff --compact-summary # alongside --stat: shows new/gone, +x/-x (executable), +l (symlink)
git diff --numstat # machine-readable: <added>\t<deleted>\t<path>; - for binary
```
### --name-only / --name-status
```bash
git diff --name-only # only filenames, one per line
git diff --name-status # status letter + filename per line
```
`--name-status` uses the same status letters as `--diff-filter`.
### --word-diff
```bash
git diff --word-diff # inline word-level diff with [-removed-] {+added+} markers
git diff --word-diff=color # color only, no markers
git diff --word-diff=porcelain # machine-readable: +/- prefixed lines, ~ for newlines
git diff --word-diff-regex=<re> # define what counts as a "word"
```
### Whitespace Flags
| Flag | Effect |
|---|---|
| `-b` / `--ignore-space-change` | Treat any run of whitespace as equivalent; ignore trailing whitespace |
| `-w` / `--ignore-all-space` | Ignore all whitespace completely |
| `--ignore-space-at-eol` | Ignore whitespace at end-of-line only |
| `--ignore-blank-lines` | Ignore changes consisting entirely of blank lines |
| `-I<regex>` / `--ignore-matching-lines=<re>` | Ignore changes where all changed lines match regex |

View File

@@ -0,0 +1,53 @@
---
topic: installation
source_keys:
- git-scm-docs
---
## Linux
Debian / Ubuntu:
```bash
sudo apt install git-all
```
Fedora / RHEL / CentOS:
```bash
sudo dnf install git-all
```
Other distributions use their native package manager. The `git-all` meta-package pulls in optional tools (GUI clients, credential helpers); install `git` alone for the minimal CLI.
## macOS
The fastest path — run any git command and macOS prompts you to install the Xcode Command Line Tools:
```bash
git --version
```
This installs Apple's bundled git. For a more recent version, use the binary installer from git-scm.com or install via Homebrew:
```bash
brew install git
```
## Windows
**Option 1 — Git for Windows** (recommended): download the installer from git-scm.com/download/win. It includes Git Bash (a POSIX shell), Git GUI, and optionally integrates with the Windows credential manager.
**Option 2 — Chocolatey**:
```bash
choco install git
```
**Option 3 — winget**:
```bash
winget install --id Git.Git
```
## Post-install Verification
```bash
git --version
```
Minimum recommended versions for modern features: 2.23+ (for `git switch` / `git restore`), 2.38+ (for `git worktree` improvements).

View File

@@ -0,0 +1,76 @@
---
topic: overview
source_keys:
- context7-git-htmldocs
---
## What Git Is
Git is a distributed version control system designed to track changes in source code across the full lifetime of a project. Unlike centralised VCS tools, every developer holds a complete copy of the repository — full history, all branches, all objects. This means most operations (log, diff, branch, commit) are local and fast, and the repository survives any single node failing.
## Core Mental Model
Git models a project's history as a directed acyclic graph (DAG) of commit objects. Each commit is identified by a SHA-1 hash derived from its content and parent references, making history immutable by design. You cannot change a past commit — you can only create new commits that supersede it.
Three areas govern where changes live at any moment:
- **Working tree** — the files on disk you edit directly.
- **Index (staging area)** — a snapshot assembled for the next commit. Changes must be explicitly staged with `git add` before they become part of a commit.
- **Repository (`.git/`)** — the permanent object store. Once committed, content is addressable by hash.
## Key Concepts
**Repository** — a `.git/` directory containing all objects (blobs, trees, commits, tags) and refs. Bare repositories (no working tree) are used as shared remotes.
**Commit** — a snapshot of the entire repository tree at a point in time, plus a pointer to its parent(s), author metadata, and a message. A merge commit has two parents.
**Branch** — a movable pointer to a commit. Creating a branch is cheap: it is just a 41-byte ref file. Switching branches (`git checkout` / `git switch`) updates HEAD and the working tree.
**HEAD** — a symbolic ref pointing to the currently checked-out branch (or directly to a commit in detached HEAD state). The next commit advances whatever HEAD points to.
**Remote** — a named reference to another repository. `origin` is the conventional name for the repository a local repo was cloned from. Remotes are fetched into remote-tracking branches (e.g. `origin/main`) which are local, read-only mirrors.
**Tag** — a permanent, human-readable name for a specific commit. Annotated tags carry a message and are signed; lightweight tags are just a ref alias.
**Ref** — any named pointer to a commit: branches live under `refs/heads/`, tags under `refs/tags/`, remotes under `refs/remotes/`.
## Repository Structure
```
.git/
├── HEAD # points to current branch or commit
├── config # local repo config
├── index # staging area (binary)
├── objects/ # content-addressable object store
│ ├── pack/ # packed objects for efficiency
│ └── info/
├── refs/
│ ├── heads/ # local branch tips
│ ├── remotes/ # remote-tracking branches
│ └── tags/ # tags
├── hooks/ # optional shell scripts on git events
├── modules/ # submodule git dirs (when present)
└── worktrees/ # linked worktree metadata (when present)
```
## Fundamental Workflow
```bash
git init # create a new repository
git add <file> # stage changes
git diff --cached # review what is staged
git commit -m "message" # snapshot staged changes
git log --oneline --graph # visualise history
git push origin main # send commits to remote
git pull # fetch + merge (or rebase) from remote
```
## Architecture Properties
**Distributed** — every clone is a full backup. There is no single point of failure at the protocol level.
**Content-addressed** — objects are stored by their SHA-1 hash. Identical content is stored once regardless of how many branches or commits reference it.
**Immutable history** — commit hashes change if content changes. Rewriting history (rebase, amend) creates new commits; old ones remain until garbage-collected.
**Porcelain vs plumbing** — Git exposes high-level commands for humans (porcelain: `commit`, `merge`, `log`) and low-level commands for scripting (plumbing: `cat-file`, `update-ref`, `rev-parse`). Scripts should prefer plumbing for stability.

View File

@@ -0,0 +1,192 @@
---
topic: remotes
source_keys:
- git-scm-push-docs
- git-scm-fetch-docs
- git-scm-pull-docs
- git-scm-remote-docs
- context7-git-htmldocs
---
## Remote Management (`git remote`)
### Add
```bash
git remote add <name> <url>
git remote add -f <name> <url> # fetch immediately after adding
git remote add -t <branch> <name> <url> # track only one branch (repeatable)
git remote add --no-tags <name> <url> # suppress automatic tag import
git remote add --mirror=fetch <name> <url> # mirror all refs locally (bare repos only)
git remote add --mirror=push <name> <url> # every push behaves like --mirror
```
### Remove / Rename / URLs
```bash
git remote remove <name> # delete remote + all tracking refs + config
git remote rename <old> <new>
git remote set-url <name> <newurl> # replace first fetch URL
git remote set-url <name> <newurl> <oldurl-regex> # replace specific URL by regex
git remote set-url --push <name> <url> # change push URL only (must point same repo)
git remote set-url --add <name> <url> # add extra push URL (push to multiple remotes)
git remote set-url --delete <name> <regex> # remove matching URLs
git remote get-url <name> # show effective URL after insteadOf rewrites
git remote get-url --push --all <name> # show all push URLs
```
`--push` on `set-url` changes only where pushes go — fetch and push URLs must still reference the same repository. For genuine fetch-from-A push-to-B workflows, use two separate named remotes.
### Inspect and Housekeeping
```bash
git remote -v # list remotes with URLs
git remote show <name> # live query: tracked branches, ahead/behind status
git remote show -n <name> # same, using cached data (no network)
git remote prune <name> # delete stale tracking refs (no fetch)
git remote prune --dry-run <name> # preview what would be pruned
git remote set-head <name> -a # auto-detect remote's default branch (fetch first)
git remote set-head <name> <branch> # set remote HEAD explicitly
git remote set-head <name> -d # delete refs/remotes/<name>/HEAD
```
`git remote show` requires `-v` before `show`, not after. `set-head -a` silently does nothing if the tracking branch doesn't exist locally — always fetch first.
## Fetching (`git fetch`)
```bash
git fetch <remote> # fetch all branches from remote
git fetch <remote> <branch> # fetch one branch (stores in FETCH_HEAD)
git fetch --all # fetch from all configured remotes
git fetch --all --prune # fetch all + prune stale tracking refs
git fetch --prune # delete remote-tracking refs no longer on remote
git fetch --prune-tags # also prune local tags not on remote
git fetch --depth=<n> # deepen / create shallow clone
git fetch --unshallow # convert shallow clone to full history
git fetch --update-shallow # allow fetch to update shallow boundaries
git fetch --refmap='' <remote> <branch> # fetch without storing (FETCH_HEAD only)
```
**`--prune` does not prune tags by default.** Add `--prune-tags` explicitly, or configure permanently:
```bash
git config remote.origin.prune true # auto-prune on every fetch
git config fetch.pruneTags true # prune tags when --prune is active
```
**Remote-tracking branch mechanics.** The default fetch refspec is `+refs/heads/*:refs/remotes/origin/*`. The `+` forces updates — remote-tracking branches mirror the remote exactly and do not protect local history. Fetch never touches local branches.
## Pushing (`git push`)
```bash
git push <remote> <branch> # push branch
git push -u origin <branch> # push and set upstream (branch.<name>.remote/merge)
git push --all # push all local branches
git push --tags # push all tags
git push origin <tag> # push a specific tag
git push origin --delete <branch> # delete remote branch
git push origin :<branch> # delete remote branch (refspec form)
git push --prune origin 'refs/heads/*:refs/heads/*' # delete remote branches with no local counterpart
```
### Force Push Safety
**`--force` (`-f`)** — unconditionally overwrites the remote ref. Applies to all refs in the push. To force only one ref, use `+` in the refspec:
```bash
git push origin +main develop # forces main, safe-pushes develop
```
**`--force-with-lease`** — rejects the push if the remote ref has moved since your last fetch. Three forms:
| Form | What it protects |
|---|---|
| `--force-with-lease` (bare) | All refs being pushed, vs. remote-tracking branch |
| `--force-with-lease=<refname>` | Named ref only |
| `--force-with-lease=<refname>:<sha>` | Named ref must be at exact SHA — stable, not experimental |
**Critical caveat with the bare form:** any background process that runs `git fetch` (IDE plugin, cron, editor) updates your remote-tracking branch, making the lease check pass even if someone else has pushed. The protection is silently defeated.
Two mitigations:
```bash
# Option 1: dedicated push remote (background tools only fetch origin)
git remote add origin-push $(git config remote.origin.url)
git push --force-with-lease origin-push
# Option 2: explicit SHA via tag (unaffected by tracking branch state)
git fetch
git tag base master
git rebase -i master
git push --force-with-lease=master:base master:master
```
**`--force-if-includes`** — adds a second check on top of bare `--force-with-lease`: verifies the remote-tracking tip appears in your local branch's reflog, meaning you actually integrated it. No-op without `--force-with-lease`. Has no effect when `--force-with-lease=<ref>:<sha>` is used.
Safest force-push combination:
```bash
git push --force-with-lease --force-if-includes origin
```
### Refspec Syntax
```
[+]<src>[:<dst>]
```
| Pattern | Meaning |
|---|---|
| `<branch>` | Push to same-named remote branch |
| `<src>:<dst>` | Push `<src>` local ref to `<dst>` remote ref |
| `+<src>:<dst>` | Force this refspec (non-fast-forward allowed) |
| `:<branch>` | Delete remote `<branch>` |
| `refs/heads/*:refs/heads/*` | Glob: push all matching branches |
| `^refs/heads/dev-*` | Negative: exclude matching refs |
| `tag <name>` | Sugar for `refs/tags/<name>:refs/tags/<name>` |
Remote-side policies (`receive.denyDeletes`, `receive.denyDeleteCurrent`, `receive.denyNonFastForwards`) are enforced server-side regardless of local flags.
## Pulling (`git pull`)
`git pull` is `git fetch` followed by a merge or rebase. Always fetch first if you want control; `git pull` is convenient but less explicit.
### Diverged Branch Resolution Strategies
**`--ff-only`** (recommended default for disciplined teams)
- Succeeds only when local is a strict ancestor of remote — no divergence.
- Fails explicitly when diverged, forcing a conscious choice.
- Config: `git config pull.ff only`
**`--rebase`** / `--rebase=true`
- Replays local unpublished commits on top of fetched tip. Linear history.
- Rewrites SHAs — unsafe for commits already pushed to a shared branch.
- Config: `git config pull.rebase true`
**`--rebase=merges`**
- Preserves intentional local merge commits during replay.
- Config: `git config pull.rebase merges`
**`--no-rebase`** / merge (default when `pull.rebase=false`)
- Three-way merge commit. Non-linear history. Original commits unchanged.
- Config: `git config pull.rebase false`
**`--squash`**
- Collapses all incoming commits into staged changes. Does not commit. You write the commit message.
### Config Precedence for Pull Behaviour
Precedence (highest wins):
1. Command-line flag
2. `pull.rebase` global/local config
3. `branch.<name>.rebase` (branch-specific override)
4. `branch.autoSetupRebase` (set on tracking branch creation)
Per-branch override example:
```bash
git config --global pull.rebase true
git config branch.develop.rebase false # develop always merges
```
### Pull Gotchas
- Rebase rewrites SHAs. Only rebase unpublished local work — rebasing already-pushed commits causes conflicts for everyone downstream.
- `--recurse-submodules` only fetches already-checked-out submodules; newly added submodules are not initialized automatically.
- Default merge strategy changed to `ort` in Git 2.34. `recursive` is now an alias. Strategy options (`-X ours`, `-X theirs`, `-X ignore-space-change`) still pass through.
- `pull.rebase` default became `--ff-only` in recent Git versions. Teams migrating from older Git should set this explicitly to avoid surprises.

View File

@@ -0,0 +1,113 @@
# Sources
## context7-git-htmldocs
- **URL:** context7:/git/htmldocs
- **Description:** Official Git HTML documentation from the git/htmldocs repository — covers all commands, concepts, and internals (19,370 code snippets, High reputation).
- **Contributing files:** overview.md, cli-reference.md, branching-merging.md
- **Status:** `extracted`
## git-scm-docs
- **URL:** https://git-scm.com/docs/git-config
- **Description:** Official git-scm.com reference pages — git-config manual covering all config variables, scopes, and the installation guide.
- **Contributing files:** installation.md, configuration.md, cli-reference.md
- **Status:** `extracted`
## git-scm-submodule-docs
- **URL:** https://git-scm.com/docs/git-submodule
- **Description:** Official git-scm.com reference for git-submodule — all subcommands, flags, configuration keys, and behaviour details.
- **Contributing files:** submodules.md
- **Status:** `extracted`
## git-scm-worktree-docs
- **URL:** https://git-scm.com/docs/git-worktree
- **Description:** Official git-scm.com reference for git-worktree — all subcommands, flags, ref-sharing rules, and gotchas.
- **Contributing files:** worktrees.md
- **Status:** `extracted`
## nvie-gitflow-post
- **URL:** https://nvie.com/posts/a-successful-git-branching-model/
- **Description:** Original 2010 post by Vincent Driessen introducing the Gitflow branching model, including a 2020 reflection note recommending GitHub Flow for continuous delivery teams.
- **Contributing files:** gitflow.md
- **Status:** `extracted`
## atlassian-gitflow-tutorial
- **URL:** https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow
- **Description:** Atlassian's comprehensive Gitflow tutorial covering all five branch types, lifecycle steps, and CLI usage.
- **Contributing files:** gitflow.md
- **Status:** `extracted`
## gitflow-cheatsheet
- **URL:** https://danielkummer.github.io/git-flow-cheatsheet/
- **Description:** Visual cheatsheet for the git-flow CLI commands (git-flow-avh fork), covering all subcommands for feature, release, and hotfix branches.
- **Contributing files:** gitflow.md
- **Status:** `extracted`
## conventional-commits-spec
- **URL:** https://www.conventionalcommits.org/en/v1.0.0/
- **Description:** The Conventional Commits v1.0.0 specification — full format rules, breaking change conventions, footer token format, examples, and SemVer mapping rationale.
- **Contributing files:** commits.md
- **Status:** `extracted`
## commitlint-config-conventional
- **URL:** https://github.com/conventional-changelog/commitlint
- **Description:** The commitlint `@commitlint/config-conventional` package — defines the 11 standard commit types, header length limits, and validation constraints.
- **Contributing files:** commits.md
- **Status:** `extracted`
## git-scm-push-docs
- **URL:** https://git-scm.com/docs/git-push
- **Description:** Official git-scm.com reference for git-push — refspec syntax, --force-with-lease semantics (including background-fetch caveat and mitigations), --force-if-includes, --delete, --prune, --set-upstream.
- **Contributing files:** remotes.md
- **Status:** `extracted`
## git-scm-fetch-docs
- **URL:** https://git-scm.com/docs/git-fetch
- **Description:** Official git-scm.com reference for git-fetch — --prune, --prune-tags, --all, --depth, --unshallow, --update-shallow, remote-tracking branch mechanics and refmap.
- **Contributing files:** remotes.md
- **Status:** `extracted`
## git-scm-pull-docs
- **URL:** https://git-scm.com/docs/git-pull
- **Description:** Official git-scm.com reference for git-pull — diverged branch resolution strategies (--ff-only, --rebase variants, merge), pull.rebase config precedence, and gotchas.
- **Contributing files:** remotes.md
- **Status:** `extracted`
## git-scm-remote-docs
- **URL:** https://git-scm.com/docs/git-remote
- **Description:** Official git-scm.com reference for git-remote — add, remove, rename, set-url (fetch/push split), prune, set-head, show, get-url with insteadOf resolution.
- **Contributing files:** remotes.md
- **Status:** `extracted`
## git-scm-bisect-docs
- **URL:** https://git-scm.com/docs/git-bisect
- **Description:** Official git-scm.com reference for git-bisect — full workflow, bisect run exit code semantics, bisect skip, log/replay, visualize, new/old/custom terms, --no-checkout, --first-parent.
- **Contributing files:** history-inspection.md
- **Status:** `extracted`
## git-scm-log-docs
- **URL:** https://git-scm.com/docs/git-log
- **Description:** Official git-scm.com reference for git-log — full --format placeholder table, -S/-G pickaxe search, --follow, --diff-filter, -L line range history, --ancestry-path, --first-parent, --merges.
- **Contributing files:** history-inspection.md
- **Status:** `extracted`
## git-scm-diff-docs
- **URL:** https://git-scm.com/docs/git-diff
- **Description:** Official git-scm.com reference for git-diff — --diff-filter letter table, --stat variants, --name-only/--name-status, --word-diff modes, whitespace flags.
- **Contributing files:** history-inspection.md
- **Status:** `extracted`

View File

@@ -0,0 +1,203 @@
---
topic: submodules
source_keys:
- git-scm-submodule-docs
---
## Concept Overview
A submodule is a full Git repository embedded as a subdirectory inside a parent repository (the superproject). The superproject does not store the submodule's files — it stores a pointer to a specific commit SHA in the submodule's history. Submodules maintain completely independent commit histories.
Two files govern submodules:
- `.gitmodules` — version-controlled; defines each submodule's name, path, and URL. Shared with collaborators.
- `.git/config` — local only; populated on `git submodule init`. Override URLs here before fetching.
The submodule's git directory lives at `.git/modules/<name>/`, linked to the working tree via a `.git` pointer file. The working directory normally ends up in **detached HEAD state** after `git submodule update`.
## Key Commands
### Add a submodule
```bash
git submodule add <url> <path>
git submodule add -b <branch> <url> <path> # track a specific branch
git submodule add --depth 1 <url> <path> # shallow clone
git submodule add -f <url> <path> # force-add (gitignored path or name conflict)
git submodule add --name <name> <url> <path> # logical name differs from path
```
After `add`, two items are staged: a new `.gitmodules` entry and a gitlink at the path. A `git commit` is still required.
### Initialize
```bash
git submodule init [<path>...]
```
Copies submodule URLs from `.gitmodules` to `.git/config`. This is where you can edit local URL overrides before fetching. Does not clone.
### Update (clone + checkout)
```bash
git submodule update --init --recursive # most common: init + update, all levels
git submodule update --remote --merge # update to remote branch tip
git submodule update --remote --rebase # same, via rebase
git submodule update --jobs <n> # parallel updates
git submodule update -f # force (discard local changes)
```
| Flag | Meaning |
|---|---|
| `--init` | Run init first (avoids a separate step) |
| `--remote` | Use the submodule's remote branch tip instead of the superproject's recorded commit |
| `--checkout` | Detached HEAD at recorded commit (default) |
| `--rebase` | Rebase current branch onto recorded commit |
| `--merge` | Merge recorded commit into current branch |
| `--recursive` | Operate on nested submodules |
| `--jobs <n>` | Parallel clone (defaults to `submodule.fetchJobs`) |
| `-N` / `--no-fetch` | Skip remote fetch |
| `--depth <n>` | Shallow clone |
| `--filter <spec>` | Partial clone filter |
### Status
```bash
git submodule status [--recursive] [<path>...]
git submodule status --cached # show SHA in superproject index
```
Prefix meanings:
- `-` — not initialized
- `+` — checked-out commit differs from superproject's recorded commit
- `U` — merge conflict inside the submodule
- (blank) — clean
### Deinit (unregister)
```bash
git submodule deinit <path>
git submodule deinit --all # all submodules
git submodule deinit -f <path> # force (local modifications present)
```
Removes the submodule section from `.git/config` and empties the working tree. Does **not** remove the entry from `.gitmodules` or the gitlink from the index — use `git rm` for that.
### Remove completely
```bash
git submodule deinit path/to/sub
git rm path/to/sub
rm -rf .git/modules/<name> # stale git dir not auto-cleaned
git commit -m "Remove submodule"
```
### Sync URLs
```bash
git submodule sync [--recursive]
```
Propagates URL changes from `.gitmodules` into `.git/config`. Use after a submodule's remote URL has been renamed upstream.
### Run a command in every submodule
```bash
git submodule foreach <command>
git submodule foreach --recursive <command>
git submodule foreach 'git pull origin main || :' # || : continues on failure
```
Available shell variables inside `<command>`: `$name`, `$sm_path`, `$displaypath`, `$sha1`, `$toplevel`.
### Other subcommands
```bash
git submodule summary [<path>...] # show commits between recorded and current
git submodule set-branch -b <branch> <path> # set tracking branch for --remote
git submodule set-url <path> <url> # update URL in .gitmodules + sync
git submodule absorbgitdirs [<path>...] # move embedded .git/ into .git/modules/
```
## Workflow Patterns
### Clone a repo with submodules
```bash
# One step (Git 2.13+)
git clone --recurse-submodules <url>
# Two steps
git clone <url>
git submodule update --init --recursive
```
### Add a dependency as a submodule
```bash
git submodule add https://github.com/org/lib.git libs/lib
git commit -m "chore: add lib as submodule"
```
### Keep submodules pinned to superproject's recorded commit
```bash
git submodule update --recursive # after every git pull
```
Configure Git to do this automatically on pull:
```bash
git config submodule.recurse true
```
### Update submodules to latest on their remote branch
```bash
git submodule update --remote --merge --recursive
git commit -am "chore: update submodules to latest"
```
### Override a submodule URL locally (private mirror)
```bash
git submodule init
# Edit .git/config to change the URL
git submodule update
```
## Common Gotchas
**Detached HEAD by default.** `git submodule update` checks out a specific commit, not a branch. Commits made inside the submodule are invisible to the superproject until you update the pointer. Always check your branch before committing inside a submodule.
**Two pushes required.** Commit and push inside the submodule first, then update the pointer in the superproject and push that. Forgetting to push the submodule leaves others unable to fetch the recorded commit.
**`--recursive` is not the default.** Most commands operate one level deep. Pass `--recursive` explicitly for nested submodules.
**Relative URLs are relative to the remote, not the filesystem.** `../foo.git` is relative to the superproject's default remote URL.
**Custom update commands are security-gated.** A `.gitmodules` entry of `update = !some-command` is not copied to `.git/config` by `git submodule init`, so cloning cannot execute arbitrary code automatically.
**`deinit` is not removal.** Use `git rm` after `deinit` to actually remove from the repo. Also delete `.git/modules/<name>/` manually.
**`.git/modules/` persists after `git rm`.** Re-adding the same path will fail until you delete it.
## Configuration
In `.gitmodules` (version-controlled):
| Key | Purpose |
|---|---|
| `submodule.<name>.path` | Working tree path |
| `submodule.<name>.url` | Remote URL |
| `submodule.<name>.branch` | Branch for `update --remote` |
| `submodule.<name>.update` | Default update procedure |
| `submodule.<name>.shallow` | Recommend shallow clone |
In `.git/config` (local, after `init`):
| Key | Purpose |
|---|---|
| `submodule.<name>.url` | Local URL override |
| `submodule.<name>.update` | Local procedure override |
| `submodule.fetchJobs` | Default parallelism for `update --jobs` |
| `submodule.recurse` | Auto-recurse on `pull`, `push`, etc. |

View File

@@ -0,0 +1,181 @@
---
topic: worktrees
source_keys:
- git-scm-worktree-docs
---
## Concept Overview
A worktree lets you check out multiple branches simultaneously from one repository, each in its own directory on disk. All worktrees share the same objects, configuration, and most refs — but each has its own `HEAD`, index, and per-worktree metadata.
**Main worktree** — the original working tree from `git init` or `git clone`. Exactly one per repo. Cannot be removed or moved via git commands (use `repair` if moved manually).
**Linked worktree** — any additional worktree created with `git worktree add`. Multiple can coexist. Each gets a private directory at `$GIT_DIR/worktrees/<name>/` holding its `HEAD`, `index`, `gitdir` pointer, and optionally a `locked` file.
**Shared across worktrees:** everything under `refs/` (branches, tags, remotes), objects, config.
**Per-worktree (not shared):** `HEAD`, `ORIG_HEAD`, `MERGE_HEAD`, refs under `refs/bisect/`, `refs/worktree/`, `refs/rewritten/`.
## Key Commands
### Add a worktree
```bash
git worktree add <path> # create worktree, derive branch from path basename
git worktree add <path> <branch> # check out existing branch
git worktree add -b <new-branch> <path> # create and check out new branch
git worktree add -B <branch> <path> # create or reset branch to HEAD
git worktree add -d <path> # detached HEAD
git worktree add --orphan -b <branch> <path> # new unborn branch
```
| Flag | Meaning |
|---|---|
| `-b <branch>` | Create and check out a new branch; fails if it exists |
| `-B <branch>` | Like `-b` but resets the branch if it already exists |
| `-d` / `--detach` | Detach HEAD; useful for throwaway experiments |
| `--orphan` | Create empty unborn branch |
| `--no-checkout` | Suppress initial checkout (for sparse-checkout setup) |
| `--guess-remote` | Look for a matching remote-tracking branch by path basename |
| `--lock [--reason <str>]` | Lock immediately on creation (atomic; avoids race vs. add-then-lock) |
| `-f` / `--force` | Allow when branch is already checked out elsewhere |
| `--relative-paths` | Link via relative paths (portable across moves) |
Using "`-`" as `<commit-ish>` is shorthand for `@{-1}` (previous branch).
### List worktrees
```bash
git worktree list # show all worktrees
git worktree list -v # show lock/prune reasons
git worktree list --porcelain # machine-readable output
git worktree list --porcelain -z # NUL-terminated (for paths with spaces)
```
Output shows path, HEAD commit, branch name, and `locked` or `prunable` status.
### Lock / Unlock
```bash
git worktree lock <worktree> --reason "on external SSD"
git worktree unlock <worktree>
```
Prevents the worktree from being pruned, moved, or deleted. Use for worktrees on removable drives or network mounts.
### Move a worktree
```bash
git worktree move <worktree> <new-path>
git worktree move -f <worktree> <new-path> # override standard safeguards
git worktree move -ff <worktree> <new-path> # override locked state too
```
Cannot move the main worktree. Cannot move a worktree that contains submodules.
### Remove a worktree
```bash
git worktree remove <worktree> # only clean worktrees (no untracked/modified files)
git worktree remove -f <worktree> # force-remove unclean
git worktree remove -ff <worktree> # force-remove even if locked
```
Deletes the worktree directory and its `$GIT_DIR/worktrees/<name>/` metadata. Main worktree cannot be removed.
### Prune stale metadata
```bash
git worktree prune # clean up orphaned metadata
git worktree prune --dry-run # preview what would be removed
git worktree prune --expire <time> # override expiry threshold
```
Cleans up `$GIT_DIR/worktrees/` entries for directories that no longer exist. Also triggered by `git gc`. Controlled by `gc.worktreePruneExpire` config.
### Repair broken connections
```bash
git worktree repair # fix all broken connections from main worktree
git worktree repair <path> # reconnect a specific linked worktree
```
Reestablishes bidirectional pointers after a manual move. Run from the main worktree after it was moved, or from a linked worktree after it was moved.
## Workflow Patterns
### Emergency fix without disrupting current work
```bash
git worktree add -b emergency-fix ../temp main
cd ../temp
# fix, commit
git commit -a -m "fix: critical production bug"
cd -
git worktree remove ../temp
```
No stashing required. Your ongoing work in the main worktree is untouched.
### Review a PR branch alongside your current work
```bash
git worktree add ../review-pr-123 origin/feature-xyz
# open ../review-pr-123 in a second editor window or terminal
```
### Throwaway experiment in detached HEAD
```bash
git worktree add -d ../experiment
# experiment freely
git worktree remove ../experiment
```
### Sparse-checkout worktree
```bash
git worktree add --no-checkout ../sparse main
cd ../sparse
git sparse-checkout init --cone
git sparse-checkout set src/
git checkout main
```
### Worktree on removable media
```bash
git worktree add /mnt/usb/project feature-branch
git worktree lock /mnt/usb/project --reason "external SSD"
# when device reconnected:
git worktree unlock /mnt/usb/project
```
## Common Gotchas
**A branch can only be checked out in one worktree at a time.** Attempting to add a worktree for an already-checked-out branch fails without `--force`.
**Submodules are unsupported.** The docs explicitly warn: "Multiple checkout in general is still experimental, and the support for submodules is incomplete. It is NOT recommended to make multiple checkouts of a superproject." Worktrees with submodules cannot be moved and require `--force` to remove.
**Never `rm -rf` a worktree directory manually.** It leaves stale metadata in `$GIT_DIR/worktrees/`. Use `git worktree remove` instead. If you already deleted manually, run `git worktree prune` or wait for `git gc`.
**Moving worktrees manually breaks bidirectional pointers.** Fix with `git worktree repair`.
**`--lock` on `add` is not the same as create-then-lock.** There is a race window between two separate calls. Use `--lock` directly on `add` when the guarantee matters.
**`extensions.worktreeConfig = true` is a one-way door for older Git.** It enables per-worktree config (`git config --worktree ...`) but makes the repo refuse to open in older Git versions. Also: `core.bare` and `core.worktree` must then live in `config.worktree`, not `config`.
**Force-flag escalation.** Some operations require `-f` twice (`-ff`) — specifically, removing or moving a locked worktree.
**Worktree identification.** Worktrees can be referenced by full path, unique basename, or unique partial path. Ambiguous partial paths error.
**`checkout.defaultRemote`** — if a branch name matches multiple remotes during `worktree add`, Git refuses unless this is configured to disambiguate.
## Configuration
| Key | Effect |
|---|---|
| `worktree.guessRemote` | Default for `--guess-remote` flag on `worktree add` |
| `worktree.useRelativePaths` | Default for `--relative-paths` on `worktree add` |
| `gc.worktreePruneExpire` | How long before stale worktree metadata is pruned by `git gc` |
| `extensions.worktreeConfig` | Enable per-worktree config scope (`config.worktree` file) |