Tips & Tricks (Updated: 6/2/2026)

Claude Code Git Workflow: Safe Branches, Small Commits, CI, and Team Handoffs

A practical Claude Code Git workflow for clean branches, commits, rebase, CI gates, rollback, and team handoff.

Claude Code Git Workflow: Safe Branches, Small Commits, CI, and Team Handoffs

The faster Claude Code writes code, the more disciplined your Git workflow has to become. AI can produce a useful diff in minutes, but it can also mix unrelated files, generate oversized commits, resolve conflicts without understanding intent, or push before local checks have run.

This guide gives you a practical Claude Code Git workflow for solo and team development: a clean branch loop, small commits, a review gate, conflict handling, worktree hygiene, safe rollback, CI before push, and daily handoff notes. It also explains beginner Git terms such as staging, commit, and rebase in plain language.

Related ClaudeCodeLab follow-ups: Git conflict resolution with Claude Code, advanced GitHub Actions, and the review workflow checklist. Official references worth keeping open are Claude Code hooks, Claude Code headless mode, Git user manual, Git rebase, GitHub Actions workflow syntax, and pre-commit.

Git terms in plain language

Your working tree is the place where files are currently edited. Claude Code writes into this area. The staging area is the “next commit basket.” Running git add does not permanently save work; it chooses which changes should go into the next commit.

A commit is a named snapshot of the staged changes. A good commit is small enough that a teammate can understand the reason in one sitting. A rebase takes your branch commits and places them on top of the latest base branch. It keeps history readable, but rewriting a branch that other people already use can break their work.

Claude Code should not be treated as only a code generator. In a strong workflow it also reads the diff, proposes what to stage, drafts a commit message, explains conflicts, runs local proof commands, and leaves a handoff that another human can verify.

flowchart LR
  A["Write the goal"] --> B["Update main and create branch"]
  B --> C["Implement a small slice"]
  C --> D["Read diff and choose staging"]
  D --> E["Review gate and local CI"]
  E --> F["Small commit"]
  F --> G["Rebase or open PR"]
  G --> H["Handoff and rollback note"]

Start with a clean branch loop

Before asking Claude Code to edit anything, make the worktree understandable. “Clean” does not always mean zero changes. It means there are no unrelated changes mixed into this task.

git status --short
git fetch origin
git switch main
git pull --ff-only origin main
git switch -c feature/checkout-coupon-validation
git status --short

In PowerShell, a date-stamped branch name is useful when several sessions run in parallel.

$topic = "checkout-coupon-validation"
$date = Get-Date -Format "yyyyMMdd"
git fetch origin
git switch main
git pull --ff-only origin main
git switch -c "feature/$date-$topic"
git status --short

The first Claude Code prompt should define scope before implementation.

Goal: add coupon expiry validation to checkout.
Scope: edit only src/checkout, src/coupons, and matching tests.
Do not stage, commit, push, or edit unrelated files.
Before editing, read package.json and existing checkout tests.
After editing, show git diff --stat and the exact test commands you ran.

This prevents a common failure mode: the implementation is correct, but the diff contains local settings, generated files, or content from a different task. In ClaudeCodeLab publishing work, Masa has seen article edits accidentally pick up product-page drafts and script changes. The fix was not a smarter model; it was a stricter Git loop.

Stage deliberately and commit small

git add -A is convenient, but it is too broad for AI-assisted work. It can stage temporary files, unrelated edits, or half-finished experiments. Prefer reading the diff first and staging exact paths.

git diff --stat
git diff
git add src/checkout/validateCoupon.ts
git add tests/checkout/validateCoupon.test.ts
git diff --staged --stat
git diff --staged

A commit message should explain the change and the user impact. Conventional Commits style is useful because it makes history searchable.

git commit -m "feat(checkout): validate coupon expiry before payment"

For a content or workflow change, add a body.

git commit -m "fix(content): keep Claude Code Git workflow CTA localized" -m "Updates the localized article body, internal links, and review checklist so translated pages follow the same Git workflow."

You can ask Claude Code to draft the message without allowing it to commit.

Read only the staged diff.
Propose one Conventional Commits message.
Do not run git commit.
Mention the user impact in the body if the change affects readers or customers.

Put Git rules in CLAUDE.md

If you repeat the same warning in every session, move it into CLAUDE.md. Think of CLAUDE.md as operating instructions for your AI pair programmer. It is not a user-facing README; it is the local rulebook for how work should happen in the repository.

# Claude Code Git rules

- Start every coding task with `git status --short` and report unrelated dirty files.
- Do not run `git add -A`, `git commit`, `git push`, `git reset --hard`, or `git clean -fd` unless the user explicitly asks.
- Keep commits small: one behavior change, one test update, or one content slug at a time.
- Before proposing a commit, show `git diff --stat` and `git diff --staged --stat`.
- If a conflict appears, explain both sides before editing the conflicted file.
- Run the closest local checks before push: lint, typecheck, test, build, or article metadata checks.
- Leave a handoff note with changed files, commands run, failing checks, and rollback option.

For team use, add a hook that blocks risky Git commands before they execute. Claude Code hooks are user-defined commands that run at lifecycle events such as tool use.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(git *)",
            "command": "node .claude/hooks/block-dangerous-git.mjs"
          }
        ]
      }
    ]
  }
}
// .claude/hooks/block-dangerous-git.mjs
import process from "node:process";

let raw = "";
for await (const chunk of process.stdin) raw += chunk;

const input = JSON.parse(raw || "{}");
const command = input.tool_input?.command ?? "";

const blocked = [
  /git\s+reset\s+--hard\b/,
  /git\s+clean\s+-[^\s]*f/,
  /git\s+push\s+--force(?!-with-lease)/,
  /git\s+checkout\s+--\s+\./,
  /git\s+restore\s+\.\b/
];

if (blocked.some((pattern) => pattern.test(command))) {
  process.stderr.write(`Blocked risky Git command: ${command}\n`);
  process.exit(2);
}

Hooks are a guardrail, not a complete governance system. Humans can still run commands outside Claude Code, and local machine settings can differ. Use hooks together with CLAUDE.md, review gates, and CI.

Run CI before push

Waiting for remote CI after a push is slower than catching basic failures locally. Give Claude Code a preflight command that runs only the checks available in the project.

// scripts/claude-git-preflight.mjs
import { execSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";

const run = (command) => {
  console.log(`\n$ ${command}`);
  execSync(command, { stdio: "inherit", shell: true });
};

run("git diff --check");
run("git diff --cached --check");
run("git status --short");

const pkg = existsSync("package.json")
  ? JSON.parse(readFileSync("package.json", "utf8"))
  : { scripts: {} };

for (const script of ["lint", "typecheck", "test", "build"]) {
  if (pkg.scripts?.[script]) run(`npm run ${script}`);
}

Run it before push:

node scripts/claude-git-preflight.mjs

For Python or Go repositories, use the same idea with ruff check, pytest, or go test ./.... The key is not the tool name. The key is that Claude Code must report what actually ran.

After implementation, run the local preflight.
If a command fails, stop and explain the first failing command, likely cause, and smallest next fix.
Do not push until the preflight is green.

Add pre-commit and GitHub Actions gates

pre-commit runs checks before a commit is created. It gives humans and Claude Code the same local gate.

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: git-diff-check
        name: git diff whitespace check
        entry: git diff --check
        language: system
        pass_filenames: false
      - id: npm-test
        name: npm test when available
        entry: node scripts/claude-git-preflight.mjs
        language: system
        pass_filenames: false
python -m pip install pre-commit
pre-commit install
pre-commit run --all-files

Then repeat the important checks in GitHub Actions so every pull request is verified on a clean runner.

# .github/workflows/claude-code-pr-gate.yml
name: Claude Code PR Gate

on:
  pull_request:
    branches: [main]

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - run: npm ci
      - run: git diff --check origin/main...HEAD
      - run: npm run lint --if-present
      - run: npm run typecheck --if-present
      - run: npm test --if-present
      - run: npm run build --if-present

When CI fails, do not paste an entire log into Claude Code first. Provide the first failing command, the error block, and the files involved. That keeps the repair loop short.

Handle conflicts and rebase with intent

A conflict means Git cannot automatically choose between two edits to the same area. Do not ask Claude Code to “just keep both” unless that is truly the desired behavior. Ask it to explain the intent on both sides first.

git fetch origin
git rebase origin/main
git status --short
git diff --name-only --diff-filter=U

Prompt Claude Code like this:

We are in a rebase conflict.
For each conflicted file, explain what our branch changed and what origin/main changed.
Resolve only after explaining the business intent.
After editing, run the narrowest relevant test.
Do not continue the rebase until I approve the resolved diff.

After the fix:

git add src/checkout/validateCoupon.ts
npm test -- --runInBand validateCoupon
git rebase --continue

If the resolution looks wrong, abort:

git rebase --abort

If a branch has already been pushed and you rewrite it, use --force-with-lease only under your team rules. The beginner mistake to avoid is force-pushing over work that somebody else added.

Roll back safely

Rollback should leave evidence. For shared commits, prefer git revert because it creates a new commit that undoes the earlier one.

git log --oneline -5
git revert --no-edit HEAD
git status --short

For uncommitted work, target exact paths.

git restore --staged src/checkout/validateCoupon.ts
git restore src/checkout/validateCoupon.ts

Before a larger rollback, create a backup branch.

$sha = git rev-parse --short HEAD
git switch -c "backup/before-rollback-$sha"
git switch -
git revert --no-edit HEAD

Use this prompt before letting Claude Code plan a rollback:

Suggest a rollback plan.
Prefer git revert for shared commits.
Do not use reset --hard or clean -fd.
List exactly which files or commits would be affected.

Concrete use cases

Use case 1: solo feature work. Create a feature/yyyyMMdd-topic branch, give Claude Code exact files and tests, keep the commit to one behavior change, and run local preflight before push. If the result is wrong, the rollback path is simple.

Use case 2: team pull requests. Split roles. The implementation session edits but does not commit. The review session reads only the staged diff. A human checks PR title, CI, risk, and rollback before push. This prevents AI momentum from turning into unreviewed main-branch risk.

Use case 3: content and product updates. On ClaudeCodeLab, articles, Gumroad links, training CTAs, and internal links affect revenue. A content branch should be scoped by slug and locale. Check description length, hero image, CTA links, mojibake, and localized body, not only build success.

Use case 4: long refactors. Do not ask Claude Code to rewrite the whole system in one commit. Add tests first, change internals second, remove old code last. Tell Claude Code when public APIs must stay stable until a later commit.

Failure modes to watch

FailureWhy it happensPrevention
git add -A stages unrelated filesAI work creates or touches more than the task needsStage exact paths after git diff --stat
Giant commitImplementation, tests, copy, and config happen togetherKeep one purpose per commit
Vague conflict resolutionThe model merges text without preserving intentRequire an ours/theirs explanation first
Bad rebase pushLocal history no longer matches remoteUse team-approved --force-with-lease only
Red PR after pushLocal checks never ranRun scripts/claude-git-preflight.mjs
Destructive rollbackreset --hard removes evidencePrefer git revert for shared commits
Hook overconfidenceHooks do not cover every human actionCombine hooks with review and CI

Masa’s practical lesson from ClaudeCodeLab publishing work was simple: the most expensive mistakes were not syntax errors. They were unexplained diffs. A file changed for a reason nobody could reconstruct is a workflow failure even when the build passes.

Leave a daily handoff

A handoff should be short, factual, and restartable. It is not a diary. It is the evidence another person needs to continue safely.

## Handoff: 2026-06-02

Branch: feature/20260602-checkout-coupon-validation
Goal: validate coupon expiry before payment authorization

Changed:
- src/checkout/validateCoupon.ts
- tests/checkout/validateCoupon.test.ts

Checks:
- npm run lint: passed
- npm test -- --runInBand validateCoupon: passed
- npm run build: not run, no UI/build config touched

Risk:
- Coupon timezone boundary still needs one integration test.

Rollback:
- Revert commit `abc1234` if production checkout rejects valid coupons.

Prompt:

Write a daily handoff.
Include branch, goal, changed files, checks run, checks not run, risk, and rollback.
Do not claim a command passed unless it was actually run in this session.

Turn the workflow into a real operating system

A Git workflow article is weak if it ends as a command list. Readers need a repeatable operating model for their repository. Solo builders can start with the free Claude Code cheatsheet and keep the daily commands nearby. If you want reusable prompts, CLAUDE.md rules, and review templates, compare the ClaudeCodeLab products.

For teams, the real work is deciding branch naming, commit size, CI gates, permissions, review ownership, rollback behavior, and handoff format against the actual repository. That is where Claude Code training and consultation is useful: the output is not a generic prompt, but a workflow your team can use repeatedly.

What happened when we tried it

Using this Git loop on ClaudeCodeLab content updates changed the review from “reread everything” to “inspect the slug, locales, metadata, CTA, and diff scope.” The biggest wins were git diff --staged --stat and the handoff note. They make it obvious what was verified and what remains risky. Claude Code is most valuable when it writes quickly and leaves proof that the next person can trust.

#claude-code #git #workflow #ci #code-review #team-development
Free

Free PDF: Claude Code Cheatsheet

Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.

We handle your data with care and never send spam.

Level up your Claude Code workflow

Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.

Masa

About the Author

Masa

Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.