原始内容
name: Git slug: git version: 1.0.12 description: Commits, branches, merges, and rebases Git repositories, resolves conflicts, and recovers lost history. Use when the work touches a repo, commit, branch, merge, rebase, stash, tag, or submodule; when Git refuses a command — index.lock exists, push rejected as non-fast-forward, detached HEAD, dubious ownership, unrelated histories, conflict markers left behind; when something looks lost after a hard reset, a bad rebase, a deleted branch, or a dropped stash; when splitting a mixed change, wording commit messages, cleaning history before review, or force-pushing without wrecking a teammate's work; when a credential or a huge file got committed; when setting up worktrees, hooks, LFS, sparse checkout, signing, or separate work and personal identities. Not for CI pipeline YAML (github-actions, gitlab) or for composing the pull request description itself (pull-request). homepage: https://clawic.com/skills/git changelog: "Display name shown correctly" metadata: clawdbot: emoji: 📚 requires: bins: - git os: - linux - darwin - win32 displayName: Git configPaths: - ~/Clawic/data/git/
User preferences and memory live in ~/Clawic/data/git/ (see setup.md on first use, memory-template.md for the file format). If you have data at an old location (~/git/ or ~/clawic/git/), move it to ~/Clawic/data/git/.
Configuration
User-dependent variables. Defaults apply until the user states a preference; store them in ~/Clawic/data/git/config.yaml.
| Variable | Type | Default | Effect |
|---|---|---|---|
| integration_style | rebase | merge | squash | repo-default | repo-default | How branches get combined and what pull does; repo-default reads the last 20 merges (git log --merges --oneline -20) and follows what the repo already does |
| commit_style | conventional | plain | repo-default | repo-default | Shape of every generated commit subject (Commit Discipline); repo-default copies the style found in git log --oneline -20 |
| branch_naming | text (pattern) | type/topic | Template used when creating branches, lowercase and hierarchical by default |
| protected_branches | list | main, master | Branches never committed to, rewritten, or force-pushed (Core Rule 2, Push gate); a request that targets one becomes "branch first, then propose the merge" |
| force_push_policy | never | own-branches | any | own-branches | Governs the Push gate: never turns every rewrite into a git revert; any still requires --force-with-lease |
| subject_max | number (chars, 50-100) | 72 | Hard stop for every generated commit subject (Core Rule 6) and the length any commit-msg gate enforces |
| message_language | text (language) | repo-default | repo-default | Language of generated commit subjects, bodies, and tag messages; repo-default copies the language already in git log --oneline -20 |
| remote_host | github | gitlab | bitbucket | gitea | other | github | Selects PR-vs-MR wording, blob size limits, and squash-merge semantics quoted in review and release guidance |
| signing | off | ssh | gpg | off | Adds signing flags and commit.gpgsign setup to commit and tag flows |
Preference areas to record as the user reveals them:
- tooling — CLI vs GUI vs IDE Git, hosting CLI in use, pre-commit framework, mergetool of choice
- conventions — subject format, ticket-ID placement, tag scheme, trailers such as
Co-authored-by, monorepo tag prefixes - thresholds — body-length and file-count limits a commit may reach, the large-file guard's size (
--above=), reflog retention (gc.reflogExpireUnreachable), clone depth and filter in CI - restrictions — repos, paths, or file types the agent must leave alone; operations banned outright (no rebase, no
filter-repo); compliance regimes demanding signed or reviewed commits - platform — hosting provider, SSH vs HTTPS, monorepo vs polyrepo, Windows/macOS line-ending and case sensitivity constraints
- safety posture — whether the agent may commit or push unprompted, confirmation before
--hard/clean -f/history rewrites - work order — commit granularity, whether to sync before starting, review gates expected before a push
- cadence — how often to fetch/prune, when to run maintenance on large clones
When To Use
- Any task touching a Git repository: staging, commits, branches, merges, rebases, tags, stashes, submodules.
- Something looks lost — deleted branch, bad rebase, hard reset, vanished stash: recovery is a first-class use (→ Recovery Playbook,
recovery.md). - Git refuses to run and the message is opaque (
index.lock, non-fast-forward, dubious ownership, detached HEAD) →errors.md. - Before any history rewrite or force push: run the Output Gates below first.
- Investigating when a behavior broke, who changed a line, or where code came from →
forensics.md. - Not for CI pipeline configuration — GitHub workflows are
github-actions, GitLab pipelines aregitlab; writing the PR description itself ispull-request.
Quick Reference
| Situation | File |
|---|---|
| Staging surgery, splitting a mixed change, wording a message, stashing | commits.md |
| Creating or switching branches, merge vs rebase, stacked branches | branching.md |
| A merge or rebase stopped on conflicts | conflicts.md |
| Undoing: reset, revert, amend, rewriting a branch before review | history.md |
| Work looks lost: bad reset, dropped stash, deleted branch, detached commits | recovery.md |
| Git printed an error and refuses to proceed | errors.md |
| "When did this break", "who wrote this line", "where did this code go" | forensics.md |
| Push/pull friction, review flow, force-pushing on a shared branch | collaboration.md |
| Forks, upstreams, mirrors, moving or splitting a repository | remotes.md |
| Two checkouts at once: hotfix mid-refactor, parallel agent tasks | worktrees.md |
| Nested repositories: submodules, subtrees, vendored code | submodules.md |
| Slow clone or status, monorepo scale, huge files, LFS | large-repos.md |
| Pre-commit/pre-push automation, lint gates, a hook that never runs | hooks.md |
| A credential or a giant blob reached the history | secrets.md |
| Wrong author identity, auth failures, ignore rules, CRLF churn | config.md |
| Tags, version bumps, backports, release branches, changelogs | releases.md |
| A flag or one-time config that removes a whole trap class | commands.md |
| Git driven from a script, a CI job, or a non-interactive agent | scripting.md |
| User states a workflow preference | setup.md + memory-template.md |
| Anything else | Stay here — Core Rules, Revision Syntax, and the Recovery Playbook cover the default path |
Core Rules
- Rewrite only unpushed history. Check:
git log @{u}..lists exactly the commits safe to amend/rebase/squash. A commit missing from that output is published — fix forward withgit revertinstead. - Force push =
--force-with-lease, own branch only, never a branch inprotected_branches. The lease is void if anything fetched after the remote moved — IDE auto-fetch does this without warning — so add--force-if-includes(git >=2.30) to close that hole. - Destructive command → name the casualties first.
git statusbeforereset --hard,git clean -nbeforegit clean -f,git diff @{u}before force push. If you cannot list what dies, you are not ready to run it. Cheap insurance when you are unsure:git branch backup/$(date +%F-%H%M)costs one ref and zero bytes. git reflogbefore panic. Committed work survives 90 days (reachable) / 30 days (unreachable) — those are reflog-entry lifetimes, and a commit some reflog entry still names does not count as unreachable, sogc's shorter two-week prune window never applies to it (→recovery.md). The only truly unrecoverable losses: never-staged edits killed byreset --hard/restore, and untracked files killed byclean -f.- Conflicts repeat per commit in rebase, once in merge. Same region conflicting across 3+ replayed commits → abort and merge instead (one resolution), or enable
rerereso each resolution is recorded once. - Commit = one reviewable change. Mixed changes →
git add -pto split. Subject: aim ≤50 chars (convention), hard stopsubject_max, default 72 becausegit logindents bodies by four spaces inside an 80-column terminal — hosts truncate around the same width in list views. Body explains why, not what; subject and body both followmessage_language. - A pushed secret is a leaked secret. Rotate the credential first; history rewrite (filter-repo) is cleanup, not containment — forks, clones, and CI caches keep the old objects.
- Escalate undo by blast radius; stop at the first tool that reaches the goal.
git restore(one file, nothing else moves) →git revert(one commit, safe on shared branches) →git reset(moves your branch pointer only) →git rebase(new SHAs, everyone tracking the branch pays) →git filter-repo(every clone in existence is now wrong). Reaching for the right-hand tools when a left-hand one suffices is the single most common self-inflicted Git incident.
Revision Syntax
Most "Git did something I did not ask for" reports are a misread revision expression. Decoder:
| Expression | Means | Trap |
|---|---|---|
HEAD~2 |
Two commits back along first parents | Follows the mainline through merges, skipping the merged branch |
HEAD^2 |
The SECOND PARENT of a merge commit | Not "two back": ^ selects a parent, ~ walks generations |
HEAD@{2} |
Where HEAD pointed two reflog moves ago | Time, not ancestry — and local to this clone only |
@{u} / @{push} |
The tracked upstream / where a push would land | They differ in triangular setups (fork: pull from upstream, push to origin) |
A..B |
Commits reachable from B but not A | In git diff, the same expression means the plain A-to-B diff |
A...B |
log: commits on either side but not both. diff: B against the MERGE-BASE |
The one expression whose meaning changes between log and diff — the source of "my diff shows unrelated files" |
:/fix login |
Most recent commit whose message contains that text | Searches all reachable history, not just this branch |
:1:file :2:file :3:file |
During a conflict: base, ours, theirs | Numbering is fixed; "ours/theirs" inverts under rebase (→ Conflict Basics) |
main@{yesterday} |
Branch tip as of yesterday | Reflog-based: empty in a fresh clone, and gone after reflog expiry |
v1.2^{} |
The commit an annotated tag points at | Without peeling, a tag is its own object — git diff v1.2 compares against the tag object's target, scripts that assume a commit break |
Ambiguity between a branch and a path is resolved with --: git checkout -- config is always the file.
Recovery Playbook
| Symptom | Play |
|---|---|
| Just finished a bad rebase/merge/reset | git reset --hard ORIG_HEAD — Git saved your pre-operation position |
| Commits vanished after a rewrite | git reflog → git reset --hard HEAD@{n} (the entry just before the damage) |
| Deleted a branch | git reflog → git branch restored <sha> |
| Committed on the wrong branch (unpushed) | git switch right-branch && git cherry-pick <sha>, then git switch - && git reset --hard HEAD~1 |
| Committed on detached HEAD, then switched away | Commit stays in git reflog for 30 days → git branch rescue <sha> |
| Need one file as it was N commits ago | git restore --source HEAD~N -- path — nothing else moves |
reset --hard ate staged-but-uncommitted work |
git fsck --lost-found — staged content survives as dangling blobs; never-staged edits are gone |
| Dropped a stash | git fsck --unreachable | grep commit → git stash apply <sha> |
| Bad commit already on a shared branch | git revert <sha> — never rewrite shared history |
| Unsure what happened / anything else | git reflog first; before experimenting, git branch backup — a branch is free insurance |
Deeper chains (deleted file archaeology, corrupted index, post-filter-repo rescue, what expiry actually deletes): recovery.md.
Commit Discipline
- One reviewable change per commit;
git add -psplits mixed work.git commit --fixup <sha>+git rebase -i --autosquashbatches corrections without "fix typo" noise. - Match the repo's existing message style before imposing one — check
git log --oneline -20, or followcommit_styleandmessage_languagewhen the user set them. Conventional commits (type(scope): description) only where the log or release tooling already uses them. git pull --rebase --autostashbefore push: no surprise merge commits, works with a dirty tree.- First push:
git push -u origin HEAD, or setpush.autoSetupRemote(git >=2.37) once and never type-uagain.
Conflict Basics
- Set
merge.conflictStyle zdiff3(git >=2.35) once: markers include the base version, so you see what each side changed instead of guessing intent. - Ours/theirs invert during rebase: "ours" = the branch you are rebasing onto, "theirs" = your own commit being replayed — rebase checks out upstream and applies your commits as patches on top.
- After resolving:
git grep -nE '^(<{7}|={7}|>{7})'must return nothing, then build/tests, then--continue. - Everything else →
conflicts.md.
Output Gates
Before declaring Git work done:
- Rewrite gate: every amended/rebased commit appeared in
git log @{u}..before I touched it - Deletion gate: I listed the casualties (
git status,git clean -n) before any--hard/-f - Push gate: target is not in
protected_branchesand not a shared branch; if forcing at all,--force-with-leaseminimum, and withinforce_push_policy - Conflict gate: marker grep is clean AND the project builds after resolution
- Identity gate:
git config user.emailis the right identity for this repo (work vs personal) - Content gate:
git diff --cached --statreviewed — no credential, no build artifact, no blob the host will reject
Traps
| Trap | Why it fails | Do instead |
|---|---|---|
git stash before a risky operation, expecting untracked files saved |
Plain stash skips untracked files | git stash -u |
Assuming stash pop dropped the stash after a conflict |
Pop only drops on clean apply; on conflict the entry stays | Resolve, then git stash drop |
git clean -fdx to "clean build artifacts" |
-x also deletes ignored files: .env, IDE config, local secrets |
git clean -fd, always preview with -n |
Renaming Foo.js → foo.js works locally, breaks CI |
macOS/Windows filesystems are case-insensitive, Linux is not | git mv Foo.js tmp && git mv tmp foo.js |
git branch -d refuses to delete after squash-merge |
Squashed commits are unreachable from main, so Git thinks the branch is unmerged | Verify the PR merged, then -D |
| Committing a large binary "just this once" | GitHub warns >50 MB, blocks >100 MB — and history keeps the blob forever | Git LFS before first commit; after the fact, git filter-repo (secrets.md) |
"Sharing" hooks via .git/hooks |
.git/hooks is never versioned |
Commit a hooks dir + git config core.hooksPath (hooks.md) |
| Cloned repo has empty submodule directories | Submodules need explicit initialization | git clone --recurse-submodules, or git submodule update --init |
Adding a path to .gitignore to stop tracking it |
Ignore rules never apply to already-tracked files — the file keeps showing up in every diff | git rm --cached <path>, commit the removal, then ignore it |
git reset --hard when the intent was "unstage this" |
--hard also throws away the working tree; unstaging needs no destructive flag |
git restore --staged <path> (index only) |
Marking a config file --assume-unchanged so local edits stop appearing |
Git now lies in status, and any incoming change to that file breaks pull with a confusing error |
Commit a .example template, gitignore the real file (config.md) |
Where Experts Disagree
- Squash-merge vs preserve commits. Squash school treats PR commits as WIP noise (small PRs, GitHub-centric teams); preserve school needs atomic commits for bisect and surgical reverts (long-lived repos, kernel-style review). Follow the repo's existing merge style — mixing styles hurts more than either choice.
- Trunk-based vs long-lived branches. DORA research associates branches merged within about a day with higher delivery performance; git-flow-style release branches pay off only when you maintain multiple released versions in parallel.
- Conventional commits. Pay off when tooling consumes them (changelog generation, semver automation); pure ceremony otherwise. Detect: release automation in the repo → use them.
- Mandatory commit signing. Provenance school signs everything (supply-chain audits, OSS releases, regulated code). Skeptics note that a signature proves a key was present, not that the author was — a compromised laptop signs happily. Boundary: sign what outsiders consume; internal application repos gain little beyond noise.
Related Skills
More Clawic skills, get them at https://clawic.com/skills/git (install if the user confirms):
pull-request— when the branch is ready and the PR itself has to be written and validatedreview-code— when the job is judging someone else's diff, not producing itgithub-actions— when the failure is in workflow YAML rather than in the repositorygitlab— GitLab CI/CD pipelines and merge-request settingscode— planning, implementing, and verifying the change the commits will carry
Feedback
- If useful, star it: https://clawic.com/skills/git
- Latest version: https://clawic.com/skills/git
Part of Clawic, the verified skill library. Get this skill: https://clawic.com/skills/git.