Version control with Claude Code: commits, conflicts, PRs and worktrees
PLClaude Code runs git through its Bash tool, so version control becomes a conversation: it reads a git status snapshot when a session starts, splits changes into commits in the team’s format, explains and resolves conflicts, opens pull requests through the GitHub CLI, and isolates parallel sessions with claude --worktree. Tests and review, not the commit message, prove each change.
This page is for developers who already run Claude Code on a real repository. You have spent two hours on a feature that now spans seven files, and the working tree also holds a bug fix you noticed on the way and a refactor you could not resist. You want three clean commits, a PR a reviewer can approve without reading every line, and a second session shipping a hotfix while the first keeps going. The page assumes you already work in the explore, plan, code and verify loop; this is where that loop’s output turns into history.
What you’ll walk away with from git work in Claude Code
Section titled “What you’ll walk away with from git work in Claude Code”- A
CLAUDE.mdblock and a permission policy that make Claude commit your way and ask before it pushes, even in auto mode. - Four copy-paste prompts: split tangled changes, resolve conflicts, open a verifiable PR, and find a regression with
git bisect. - The
commit-commandsplugin for one-command commits and PRs, and when not to use it. - Parallel sessions in worktrees with
claude --worktree, including.worktreeincludeand cleanup. - Recovery steps for the ways git work with an agent goes wrong, and who signs off before a merge.
What Claude Code knows about your repository
Section titled “What Claude Code knows about your repository”When a local conversation starts, Claude Code gives Claude a git status snapshot: the current branch, git status output, and recent commits. It also loads built-in instructions for writing commits and pull requests. You can start with “commit my changes” instead of pasting a diff.
Two details matter in practice:
- The snapshot is not live. Claude Code takes it at session start and refreshes it after a compaction (v2.1.269 and later), not after every command. After you switch branches or commit in another terminal, Claude works from stale state until it runs
git statusagain. Say “re-read the git state first” after any change you make outside the session. - Commits carry attribution. By default Claude Code adds a
Co-Authored-Bytrailer to commits and a “Generated with Claude Code” line to PR descriptions. Change or hide either with theattributionsetting ("attribution": falseneeds v2.1.281 or later). Older versions ignore a settings file that contains it, so in a shared.claude/settings.jsonuse the object form instead, for example"attribution": { "commit": "", "pr": "", "sessionUrl": false }. SetincludeGitInstructions: falseonly when your own git skill replaces the built-in instructions; it also removes the git status snapshot, so your skill should rungit statusitself.
Set your commit rules and git permissions once
Section titled “Set your commit rules and git permissions once”Put the team’s conventions in CLAUDE.md so every session follows them without being told. See how Claude Code’s memory files load for where this file lives.
## Git rules- Conventional commits: feat, fix, docs, refactor, test, chore, with a scope: feat(auth): add OAuth flow- Subject line under 72 characters; body explains why, not what- One logical change per commit; never mix a refactor with a behaviour change- Run `npm test` before every commit and paste the summary line into the commit body- Never use --no-verify, never amend or force-push a pushed commit, never commit to main- Reference the issue: Closes #123Then decide what Claude may do without asking. This .claude/settings.json lets Claude commit freely, makes every push a prompt, and refuses force pushes:
{ "permissions": { "allow": ["Bash(git add *)", "Bash(git commit *)"], "ask": ["Bash(git push *)"], "deny": ["Bash(git push --force *)", "Bash(git push -f *)"] }}Which of these rules do the work depends on the permission mode. From Claude Code v2.1.283 (both release channels on 2026-10-12), auto mode is the starting mode for interactive terminal sessions on models that support it (see the configuration guide), and in auto mode pushing to any branch of your repository and opening a pull request that matches your request run without a prompt. The ask rule above is what puts a human checkpoint back in front of every push, because auto mode still shows prompts that an ask rule forces. The auto-mode classifier also blocks a force push, git reset --hard, git clean -fd and amending an already-pushed commit by default, and deny rules block in every mode, including bypassPermissions. The configuration guide explains which mode a session starts in.
Git’s own hooks still run when Claude commits. If your repository has a pre-commit hook that lints and runs fast tests, every agent commit passes through it, which is the cheapest verification gate you have.
Split tangled changes into clean commits
Section titled “Split tangled changes into clean commits”Ask for a plan before any commit. The plan is where you catch a bug fix hiding inside a refactor.
Steps 4 and 5 make the history trustworthy. npm test runs against the working tree, so without the stash the unstaged hunks of later groups would still be on disk, and a commit that only works together with them would pass. With everything else stashed, each commit is tested exactly as it will be checked out, and git rebase --exec re-runs the suite on every commit of the finished series, so git bisect and git revert keep working later. You check the result by reading the plan table and the final git log, not the diffs.
Before the first commit of a larger change, run /code-review in the session. It reviews your branch’s commits ahead of upstream plus uncommitted changes for correctness bugs in a background subagent, /code-review --fix applies what it finds, and /code-review high 1234 reviews pull request 1234 instead. It also suggests reuse and simplification cleanups; the effort level you type (high) becomes the default for later /code-review runs until you type another. --fix edits land outside checkpoints, so undo them with git, not /rewind. /security-review checks the branch against origin’s default branch for vulnerabilities.
Use the commit-commands plugin for one-command commits and PRs
Section titled “Use the commit-commands plugin for one-command commits and PRs”Anthropic’s commit-commands plugin packages the common flows as three namespaced commands. Install it once from the shell:
claude plugin install commit-commands@claude-plugins-official| Command | What it does |
|---|---|
/commit-commands:commit | Reads git status, git diff HEAD and recent commits, then writes one commit in the repository’s style |
/commit-commands:commit-push-pr | Creates a branch if you are on main, makes one commit, pushes to origin, and runs gh pr create |
/commit-commands:clean_gone | Deletes local branches whose remote is gone, including their worktrees |
Type plugin commands with the plugin’s namespace, as in the table. The PR command needs the GitHub CLI (gh) signed in.
Two trade-offs to know before you use commit-push-pr. It puts everything into a single commit, so split tangled work first with the prompt above. And its command file pre-approves git push and gh pr create for that turn. Without an ask rule the push runs with no prompt. With the ask rule above you are still asked, because ask rules outrank allow grants. Either way, run your tests before you type the command. Also know that clean_gone force-removes the worktrees (git worktree remove --force) and deletes the branches with git branch -D: commit or push anything you need from those worktrees first.
Resolve merge and rebase conflicts without losing either side
Section titled “Resolve merge and rebase conflicts without losing either side”Conflicts are where an explanation is worth more than a resolution. Ask for both.
A typical answer reads: “Main added rate limiting to the login handler; your branch split the handler into smaller functions. Keep both: move the rate-limit check into your new validateLogin function.” You verify the resolution through the tests main added, which encode what main’s authors meant, and through git range-diff:
# Run straight after `git rebase --continue` finishes: old base..old tip vs new base..new tipgit range-diff "$(git merge-base ORIG_HEAD main)..ORIG_HEAD" main..HEADThe first range is your branch before the rebase (old base to old tip) and the second is the branch after it (new base to new tip), so commits main gained in the meantime do not show up as noise. A commit that changed in unexpected ways during the rebase stands out without you reading the whole diff. Run it before anything else touches ORIG_HEAD; if you ran git reset during conflict resolution, ORIG_HEAD was overwritten, so use your branch’s reflog entry (<branch>@{1}) in its place.
Open a pull request a reviewer can verify
Section titled “Open a pull request a reviewer can verify”“Create a PR” produces a generic description. A reviewer who is not going to read every line needs evidence: what behaviour changed, how it was tested, and what could go wrong.
When Claude creates the PR with gh pr create, Claude Code links the session to that PR. When review comments arrive, reopen the same context:
claude --from-pr 1234--from-pr opens the session picker filtered to sessions linked to that PR, and also takes a PR URL.
gh covers everything on this page. Add the GitHub MCP server when you want Claude to read review threads, Actions logs and issues as structured tool calls instead of parsing gh output.
Who signs off before the merge?
Section titled “Who signs off before the merge?”The human reviewer approves the PR on its Evidence and Risk sections, not on a line-by-line read, and CI is the merge gate. Make that real on the server: require the same test, type-check and lint jobs as status checks on main, so a PR whose Evidence section was written by the agent still cannot merge unless CI reproduces it. The reviewer’s job is to check that the Evidence names the behaviour the issue asked for, that the Risk section names a rollback, and that CI is green. For review that scales past one reviewer, see automated code review with Claude Code. For the case for reading evidence instead of diffs, see reading evidence instead of code.
Run parallel sessions in git worktrees
Section titled “Run parallel sessions in git worktrees”Two sessions editing the same checkout overwrite each other’s files. A worktree gives each session its own directory and branch while sharing one repository history.
-
Start a session in its own worktree. In a terminal at the repository root:
Terminal window claude --worktree notifications # creates .claude/worktrees/notifications/ on branch worktree-notificationsclaude -w # no name: Claude Code generates oneclaude --worktree "#1234" # fetch pull request 1234 into .claude/worktrees/pr-1234 (quote the #)Run the command with a different name in a second terminal for a second isolated session. Run
claudeonce in the repository first to accept the workspace trust dialog; otherwise--worktreeexits with an error. -
Keep the worktrees out of
git status. Add.claude/worktrees/to.gitignore. -
Copy the local files the app needs to boot. A worktree is a fresh checkout, so gitignored files such as
.envare missing. List them in.worktreeincludeat the repository root, in.gitignoresyntax:.env.localconfig/dev-settings.jsonOnly files that match a pattern and are gitignored are copied; tracked files never are. Each copied file lands in every worktree and is readable by every agent there. Keep real credentials in a secret manager, not in a file you fan out.
-
Choose the base branch. New worktrees branch from the remote default branch (
worktree.baseRef: "fresh"). Set"worktree": { "baseRef": "head" }in settings when the worktree should carry your unpushed work. -
Exit and clean up. On exit, Claude Code removes a clean worktree and its branch automatically when the session is unnamed. It asks first when you named the session (
-nor/rename) or the worktree holds changes or new commits; if you keep it, Claude Code prints theclaude --worktree <name> --resumecommand that returns you to it. Claude Code does not clean up worktrees fromclaude -pruns: remove them withgit worktree remove, and rungit worktree unlockfirst if git reports the worktree is locked.
To check out a specific existing branch or place the worktree outside the repository, use git directly: git worktree add ../myapp-hotfix hotfix/auth-timeout, then run claude inside that directory. Running many sessions at once also needs separate ports and a review queue; the parallel agents guide and the worktree isolation checklist cover both.
Resume the right session after switching branches
Section titled “Resume the right session after switching branches”Sessions belong to a directory, not a branch. After git switch, the conversation continues but Claude now reads the other branch’s files, and the git snapshot from session start is stale.
claude -c # most recent conversation in this directoryclaude --resume auth-refactor # a named sessionclaude --continue --fork-session # same history, new session IDResuming the same session in two terminals without --fork-session interleaves both conversations into one transcript. Use --fork-session when you want to try two approaches from the same point, and a worktree when the two approaches must not touch the same files.
Use git history to find when a behaviour changed
Section titled “Use git history to find when a behaviour changed”History is evidence. A bisect driven by a failing test tells you which commit broke something without anyone reading the commits in between.
For lighter questions, ask directly: “When did the session timeout in @src/lib/auth.ts last change? Show the commit and the diff.”
When git workflows in Claude Code go wrong
Section titled “When git workflows in Claude Code go wrong”Claude committed files you did not intend. If the commit is not pushed, run git reset --soft HEAD~1: the commit disappears and the changes stay staged. Then name the scope next time: “commit only the files in src/api/”, or stage with git add yourself and say “commit what is staged, nothing else”.
A rebase or push went wrong. /rewind does not undo git: checkpoints do not track changes made by Bash commands, and a push is outside your machine. Recover with git. git rebase --abort stops a rebase in progress; git reflog lists every position your branch has been at, and git reset --hard <sha> returns to one of them after you check it with git show. Keep the deny rules for force pushes and branch protection on main.
A conflict resolution dropped logic from one side. The tests main added are your check; if they pass and the logic is still gone, main had no test for it. Tell Claude exactly what went missing (“the rate-limit check from main is gone; keep it inside validateLogin”), then ask for a test that covers it so the next rebase cannot lose it again.
A commit skipped the hooks, or the message ignores your format. Claude follows CLAUDE.md, so check that the rule is there and says “never use —no-verify”. For a message on an unpushed commit, ask “rewrite the last commit message as a conventional commit with scope” (it amends; never do this after pushing).
A worktree session fails to start the app. The .env file or a generated file is missing: add it to .worktreeinclude and create a new worktree. If binary assets arrive as small LFS pointer files, Git LFS was set up with git lfs install --local: Claude Code skips repository-level filter drivers when it creates a worktree, so run git lfs pull inside it. If two worktrees fight over port 3000, give each a port through its environment. Run git worktree list to see what exists, and git worktree prune after deleting directories by hand.
claude --from-pr finds nothing. Claude Code links a session to a PR when Claude creates the PR with gh pr create in that session. A PR you opened yourself has no linked session: run claude --resume and press Ctrl+B to filter the picker to sessions on the current branch, or start fresh on the PR’s head commit with claude --worktree "#1234".
Claude pushed when you expected a prompt. The session ran in auto mode and your settings have no ask rule for git push, or the command was spelled differently from the rule (git -C . push). Add the ask rule, check it with /permissions, and rely on branch protection for anything that must never reach main.
Where to go next after version control
Section titled “Where to go next after version control”Using another tool? The same workflows in Codex are in Codex GitHub integration and Codex worktrees; in Cursor, see checkpoints and branching.
Did this guide help you?
One tap, no sign-in.
What will you do with it?
How did it read?
What got in the way? Pick any that apply
Your role?
Thanks. I read every answer. Michał Jaskólski
Did this guide help?
One tap each. Close whenever you like.
no sign-in