From e1e85284d14ca1e5f920ae0ece56c212480d0820 Mon Sep 17 00:00:00 2001 From: Defame1297 Date: Sun, 28 Jun 2026 20:34:42 +0000 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_0147vXtL5sP6vorDdqXGJJU9 --- .../research/docs/git/branching-merging.md | 180 +++++++++ .../docs/research/docs/git/cli-reference.md | 212 +++++++++++ plugins/git/docs/research/docs/git/commits.md | 169 +++++++++ .../docs/research/docs/git/configuration.md | 147 +++++++ plugins/git/docs/research/docs/git/gitflow.md | 158 ++++++++ .../research/docs/git/history-inspection.md | 359 ++++++++++++++++++ .../docs/research/docs/git/installation.md | 53 +++ .../git/docs/research/docs/git/overview.md | 76 ++++ plugins/git/docs/research/docs/git/remotes.md | 192 ++++++++++ plugins/git/docs/research/docs/git/sources.md | 113 ++++++ .../git/docs/research/docs/git/submodules.md | 203 ++++++++++ .../git/docs/research/docs/git/worktrees.md | 181 +++++++++ 12 files changed, 2043 insertions(+) create mode 100644 plugins/git/docs/research/docs/git/branching-merging.md create mode 100644 plugins/git/docs/research/docs/git/cli-reference.md create mode 100644 plugins/git/docs/research/docs/git/commits.md create mode 100644 plugins/git/docs/research/docs/git/configuration.md create mode 100644 plugins/git/docs/research/docs/git/gitflow.md create mode 100644 plugins/git/docs/research/docs/git/history-inspection.md create mode 100644 plugins/git/docs/research/docs/git/installation.md create mode 100644 plugins/git/docs/research/docs/git/overview.md create mode 100644 plugins/git/docs/research/docs/git/remotes.md create mode 100644 plugins/git/docs/research/docs/git/sources.md create mode 100644 plugins/git/docs/research/docs/git/submodules.md create mode 100644 plugins/git/docs/research/docs/git/worktrees.md diff --git a/plugins/git/docs/research/docs/git/branching-merging.md b/plugins/git/docs/research/docs/git/branching-merging.md new file mode 100644 index 0000000..e36262b --- /dev/null +++ b/plugins/git/docs/research/docs/git/branching-merging.md @@ -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 # create and switch (preferred, Git 2.23+) +git switch -c # from a specific commit or remote branch +git switch # switch to existing +git switch - # switch back to previous branch + +# Legacy equivalents +git checkout -b +git checkout +``` + +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 # 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 +git merge --no-ff -m "Merge feature/X" +``` + +### 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 +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 + +# 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 # 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 +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 # apply one commit +git cherry-pick ^.. # apply a range (inclusive) +git cherry-pick -n # 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 # push and set upstream +git branch --set-upstream-to=origin/ # 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 +``` diff --git a/plugins/git/docs/research/docs/git/cli-reference.md b/plugins/git/docs/research/docs/git/cli-reference.md new file mode 100644 index 0000000..71c5c88 --- /dev/null +++ b/plugins/git/docs/research/docs/git/cli-reference.md @@ -0,0 +1,212 @@ +--- +topic: cli-reference +source_keys: + - context7-git-htmldocs + - git-scm-docs +--- + +## Setup and Init + +```bash +git init [] # initialise new repo (or reinit existing) +git init --bare # bare repo (no working tree; used as remote) +git clone [] # clone a remote repo +git clone --recurse-submodules # clone including all submodules +git clone --depth # 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 # stage a file +git add -p # interactively stage hunks +git add -A # stage all changes including deletions +git rm # remove file from index and working tree +git rm --cached # unstage (remove from index only) +git mv # 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 # discard working tree changes (Git 2.23+) +git restore --staged # unstage (Git 2.23+) +``` + +## Committing + +```bash +git commit -m "" # 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 ` | Inline message; multiple `-m` flags become separate paragraphs | +| `-F ` | Read message from file; `-` reads from stdin | +| `-a` | Auto-stage modified tracked files | +| `-n` / `--no-verify` | Skip pre-commit and commit-msg hooks | +| `--author " "` | Override author | +| `--date ` | Override author date | +| `--squash=` | Prefix message with "squash!" for use with `rebase --autosquash` | +| `--fixup=` | Prefix message with "fixup!" for `rebase --autosquash` | +| `--reset-author` | Reassign authorship to the committer (use with `--amend`) | +| `--trailer :` | Append a footer trailer to the message | +| `--cleanup=` | 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 # create branch at current HEAD +git branch # create branch at specific commit +git branch -d # delete (safe — refuses if unmerged) +git branch -D # delete (force) +git branch -m # rename branch +git branch --set-upstream-to=origin/ # set tracking +git switch # switch to branch (Git 2.23+) +git switch -c # create and switch (Git 2.23+) +git checkout # switch (legacy) +git checkout -b # create and switch (legacy) +``` + +## Merging + +```bash +git merge # merge branch into current branch +git merge --no-ff # always create a merge commit +git merge --squash # squash into a single staged change +git merge --abort # cancel an in-progress merge +git merge --continue # continue after conflict resolution +git merge -m "" # custom merge commit message +git merge --into-name # override branch name in default message +``` + +## Rebasing + +```bash +git rebase # rebase current branch onto base +git rebase -i HEAD~ # interactive rebase of last n commits +git rebase -i # interactive rebase from commit onwards +git rebase --onto # 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 # apply a commit onto current branch +git cherry-pick .. # apply a range (exclusive of a) +git cherry-pick ^.. # apply a range (inclusive of a) +git cherry-pick -n # 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="" +git log --grep="" +git log --since="2 weeks ago" +git log # history of a specific file +git log .. # commits in second not in first +git show # show commit details and diff +git diff # diff between two commits +git blame # annotate each line with last commit +git bisect start # start binary search for bug +git bisect good +git bisect bad +git bisect reset +``` + +## Remote Operations + +```bash +git remote -v # list remotes +git remote add # add a remote +git remote remove +git remote rename +git fetch # 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 # push branch to remote +git push -u origin # push and set upstream +git push --force-with-lease # safe force push (checks remote tip) +git push --tags # push tags +git push origin : # delete remote branch +``` + +## Stashing + +```bash +git stash # stash working tree and index +git stash push -m "" # 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 # create branch from stash +``` + +## Tags + +```bash +git tag # list tags +git tag # lightweight tag at HEAD +git tag -a -m "" # annotated tag +git tag # tag a specific commit +git tag -d # delete local tag +git push origin # push tag +git push origin --tags # push all tags +git push origin :refs/tags/ # 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 # create new commit that undoes a past commit +git revert -n # 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 # print object type +git cat-file -p # print object contents +git update-ref refs/heads/ # set a ref to a commit +git for-each-ref refs/heads/ # list refs with metadata +``` diff --git a/plugins/git/docs/research/docs/git/commits.md b/plugins/git/docs/research/docs/git/commits.md new file mode 100644 index 0000000..e1131a2 --- /dev/null +++ b/plugins/git/docs/research/docs/git/commits.md @@ -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 + +``` +[optional scope]: + +[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). `: ` 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 + +``` +: + # # 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 +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 | diff --git a/plugins/git/docs/research/docs/git/configuration.md b/plugins/git/docs/research/docs/git/configuration.md new file mode 100644 index 0000000..fab91cc --- /dev/null +++ b/plugins/git/docs/research/docs/git/configuration.md @@ -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 +``` diff --git a/plugins/git/docs/research/docs/git/gitflow.md b/plugins/git/docs/research/docs/git/gitflow.md new file mode 100644 index 0000000..ed3ac3e --- /dev/null +++ b/plugins/git/docs/research/docs/git/gitflow.md @@ -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/` 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/` (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/` (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/` | `feature/login-oauth`, `feature/JIRA-42-cart` | +| Release | `release/` | `release/2.1.0` | +| Hotfix | `hotfix/` | `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 +``` + +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 # branch feature/ from develop +git flow feature finish # merge into develop (--no-ff), delete +git flow feature publish # push to origin +git flow feature track # track a remote feature branch +``` + +**Release branches:** +```bash +git flow release start # branch release/ from develop +git flow release publish # push for collaboration +git flow release finish # merge into main (tagged) + develop, delete +``` + +**Hotfix branches:** +```bash +git flow hotfix start # branch hotfix/ from main +git flow hotfix finish # 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." diff --git a/plugins/git/docs/research/docs/git/history-inspection.md b/plugins/git/docs/research/docs/git/history-inspection.md new file mode 100644 index 0000000..3d56279 --- /dev/null +++ b/plugins/git/docs/research/docs/git/history-inspection.md @@ -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 # 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 # 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 [...] +``` + +Runs `` 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 | +| `-- ...` | Limit bisection to specific paths; reduces number of trials | + +--- + +## git log — Format and Filtering + +### Named Format Presets (`--format` / `--pretty`) + +| Name | Output | +|---|---| +| `oneline` | ` ` | +| `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 | diff --git a/plugins/git/docs/research/docs/git/installation.md b/plugins/git/docs/research/docs/git/installation.md new file mode 100644 index 0000000..730ff48 --- /dev/null +++ b/plugins/git/docs/research/docs/git/installation.md @@ -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). diff --git a/plugins/git/docs/research/docs/git/overview.md b/plugins/git/docs/research/docs/git/overview.md new file mode 100644 index 0000000..928cc15 --- /dev/null +++ b/plugins/git/docs/research/docs/git/overview.md @@ -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. diff --git a/plugins/git/docs/research/docs/git/remotes.md b/plugins/git/docs/research/docs/git/remotes.md new file mode 100644 index 0000000..16e657f --- /dev/null +++ b/plugins/git/docs/research/docs/git/remotes.md @@ -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. diff --git a/plugins/git/docs/research/docs/git/sources.md b/plugins/git/docs/research/docs/git/sources.md new file mode 100644 index 0000000..3308009 --- /dev/null +++ b/plugins/git/docs/research/docs/git/sources.md @@ -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` diff --git a/plugins/git/docs/research/docs/git/submodules.md b/plugins/git/docs/research/docs/git/submodules.md new file mode 100644 index 0000000..9882eb5 --- /dev/null +++ b/plugins/git/docs/research/docs/git/submodules.md @@ -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. | diff --git a/plugins/git/docs/research/docs/git/worktrees.md b/plugins/git/docs/research/docs/git/worktrees.md new file mode 100644 index 0000000..eb36ab9 --- /dev/null +++ b/plugins/git/docs/research/docs/git/worktrees.md @@ -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) |