git-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Git Best Practices

Git最佳实践

Always Active Principles

始终遵循的原则

When this skill is loaded, follow these directives for all git operations:
  1. Discover before acting — run branch discovery to determine the repo's default and production branches before branching, merging, or opening PRs
  2. Conventional commits — every commit uses
    type(scope): description
    format
  3. Stage explicitly — add files by name so only intended changes are committed
  4. Protect shared history — use
    --force-with-lease
    for force pushes; confirm with the user before any force push
当启用此技能时,所有Git操作需遵循以下准则:
  1. 先探索再操作 — 在进行分支创建、合并或发起PR前,先执行分支探测以确定仓库的默认分支和生产分支
  2. 约定式提交 — 每个提交均使用
    type(scope): description
    格式
  3. 显式暂存 — 通过文件名添加文件,确保仅提交预期的更改
  4. 保护共享历史 — 强制推送时使用
    --force-with-lease
    ;任何强制推送前需与用户确认

Agent Git Workflow

Agent Git工作流

Follow this sequence when performing git operations:
  1. Check state — run
    git status
    and
    git diff HEAD
    ; output: working tree and unstaged/staged delta
  2. Discover branches — identify and store default/current/(optional) production branch names (see Branch Discovery)
  3. Stage by name
    git add path/to/file
    for each file; verify with
    git status
  4. Write a conventional commit
    type(scope): description
    with optional body
  5. Push safely — use regular push by default; use
    git push --force-with-lease origin {branch}
    only for rewritten history and only after user confirmation
执行Git操作时请遵循以下步骤:
  1. 检查状态 — 运行
    git status
    git diff HEAD
    ;输出:工作区状态及未暂存/已暂存的差异
  2. 探测分支 — 识别并存储默认/当前/(可选)生产分支的名称(详见分支探测)
  3. 按名称暂存 — 对每个文件执行
    git add path/to/file
    ;通过
    git status
    验证
  4. 编写约定式提交 — 使用
    type(scope): description
    格式,可选择性添加提交正文
  5. 安全推送 — 默认使用常规推送;仅在重写历史且获得用户确认后,使用
    git push --force-with-lease origin {branch}

Checkpoint Commits

检查点提交

Agents may create WIP checkpoint commits during long-running tasks. These are development artifacts, cleaned up before PR.
  • Prefix with
    wip:
    or use standard conventional commit format
  • Keep changes logically grouped even in WIP state
  • Run
    /rewrite-history
    before opening a PR to craft a clean narrative
在执行长时间任务时,Agent可创建WIP(工作中)检查点提交。这些是开发产物,需在发起PR前清理。
  • 前缀使用
    wip:
    或采用标准约定式提交格式
  • 即使在WIP状态下,也需将更改进行逻辑分组
  • 发起PR前运行
    /rewrite-history
    以生成清晰的提交历史

Commit Discipline

提交规范

  • Stage files explicitly by name:
    git add src/auth.ts src/auth.test.ts
  • Verify staged content with
    git status
    before committing
  • Keep secrets,
    .env
    files, credentials, and large binaries out of commits — warn the user if staged files look sensitive
  • Target one logical change per commit in final PR-ready state
  • 按名称显式暂存文件:
    git add src/auth.ts src/auth.test.ts
  • 提交前通过
    git status
    验证已暂存内容
  • 禁止提交密钥、
    .env
    文件、凭证及大型二进制文件 — 若暂存文件看起来包含敏感信息,需向用户发出警告
  • 在最终可提交PR的状态下,每个提交仅对应一个逻辑更改

Force Push

强制推送

Use
--force-with-lease
exclusively to protect against overwriting upstream changes:
bash
git push --force-with-lease origin feat/my-branch
Always confirm with the user before any force push, regardless of branch.
仅使用
--force-with-lease
以防止覆盖上游更改:
bash
git push --force-with-lease origin feat/my-branch
无论分支类型,任何强制推送前均需与用户确认。

Conventional Commits

约定式提交

Format:
type(scope): description
Subject line rules:
  • Lowercase, imperative mood, no trailing period
  • Under 72 characters
  • Scope is optional but preferred when a clear subsystem exists
Common types:
TypeUse for
feat
New functionality
fix
Bug fix
docs
Documentation only
refactor
Restructuring without behavior change
perf
Performance improvement
chore
Maintenance, dependencies, tooling
test
Adding or updating tests
ci
CI/CD pipeline changes
build
Build system changes
style
Formatting, whitespace (no logic change)
格式:
type(scope): description
主题行规则:
  • 小写、祈使语气、无句末句号
  • 长度不超过72个字符
  • 作用域(scope)为可选,但在存在清晰子系统时建议添加
常见类型:
类型适用场景
feat
新增功能
fix
修复Bug
docs
仅修改文档
refactor
重构(无行为变更)
perf
性能优化
chore
维护、依赖更新、工具配置
test
添加或更新测试
ci
CI/CD流水线变更
build
构建系统变更
style
格式调整、空白字符修改(无逻辑变更)

Commit Bodies

提交正文

Body is optional — only add one when the change is genuinely non-obvious. The subject line carries the "what"; the body explains "why."
Add a body when:
  • The motivation or tradeoff is non-obvious
  • Multi-part changes benefit from a bullet list
  • External context is needed (links, issue references, root cause)
正文为可选内容 — 仅当更改确实不直观时才添加。主题行说明“做了什么”;正文解释“为什么这么做”。
在以下场景添加正文:
  • 动机或权衡方案不直观
  • 多部分变更适合用项目符号列表呈现
  • 需要外部上下文(链接、问题引用、根本原因)

Examples

示例

<examples> <example name="simple-fix"> Single-line fix, no body needed:
fix(shell): restore Alt+F terminal navigation
</example> <example name="scoped-with-body"> Non-obvious fix with body explaining root cause:
fix(shell): use HOMEBREW_PREFIX to avoid path_helper breaking plugins in login shells

macOS path_helper reorders PATH in login shells, putting /usr/local/bin
before /opt/homebrew/bin. This caused `brew --prefix` to resolve the stale
Intel Homebrew, so fzf, zsh-autosuggestions, and zsh-syntax-highlighting
all silently failed to load in Ghostty (which spawns login shells).

Use the HOMEBREW_PREFIX env var (set by brew shellenv in .zshenv) instead
of calling `brew --prefix` — it survives path_helper and is faster.
</example> <example name="multi-part-feature"> Feature with bullet-list body for multi-part changes:
feat(install): add claude bootstrap runtime management

- migrate Claude defaults to declarative files under claude/defaults
- add claude-bootstrap check/fix/uninstall with backup-first migration
- stop stowing full claude/codex runtime trees and tighten drift checks
</example> <example name="ticket-linked"> Monorepo commit with ticket reference in branch and scope:
fix(pool-party): handle stale settlement state on reconnect

PoolSettlement contract stays in pending state when the participant
disconnects mid-settlement. Check settlement timestamp and expire
stale entries on reconnect.

Fixes SEND-718
</example> <example name="submodule-bump"> Submodule update with downstream commit info:
chore(submodule): update claude-code

Bump claude-code to 88d0c75 (feat(skills): add tiltup, specalign, and e2e skills).
For trivial bumps,
bump
or
bump claude-code submodule
is acceptable. </example>
<example name="breaking-change"> Breaking change using `!` suffix:
refactor(api)!: change auth endpoint response format

The /auth/token endpoint now returns { access_token, expires_in }
instead of { token, expiry }. All clients must update their parsers.
</example> </examples>
<examples> <example name="simple-fix"> 单行修复,无需正文:
fix(shell): restore Alt+F terminal navigation
</example> <example name="scoped-with-body"> 不直观的修复,正文解释根本原因:
fix(shell): use HOMEBREW_PREFIX to avoid path_helper breaking plugins in login shells

macOS path_helper reorders PATH in login shells, putting /usr/local/bin
before /opt/homebrew/bin. This caused `brew --prefix` to resolve the stale
Intel Homebrew, so fzf, zsh-autosuggestions, and zsh-syntax-highlighting
all silently failed to load in Ghostty (which spawns login shells).

Use the HOMEBREW_PREFIX env var (set by brew shellenv in .zshenv) instead
of calling `brew --prefix` — it survives path_helper and is faster.
</example> <example name="multi-part-feature"> 多部分功能变更,正文使用项目符号列表:
feat(install): add claude bootstrap runtime management

- migrate Claude defaults to declarative files under claude/defaults
- add claude-bootstrap check/fix/uninstall with backup-first migration
- stop stowing full claude/codex runtime trees and tighten drift checks
</example> <example name="ticket-linked"> 包含工单引用的单体仓库提交(分支和作用域中均有体现):
fix(pool-party): handle stale settlement state on reconnect

PoolSettlement contract stays in pending state when the participant
disconnects mid-settlement. Check settlement timestamp and expire
stale entries on reconnect.

Fixes SEND-718
</example> <example name="submodule-bump"> 包含下游提交信息的子模块更新:
chore(submodule): update claude-code

Bump claude-code to 88d0c75 (feat(skills): add tiltup, specalign, and e2e skills).
对于简单的版本升级,使用
bump
bump claude-code submodule
格式即可接受。 </example>
<example name="breaking-change"> 使用`!`后缀标记破坏性变更:
refactor(api)!: change auth endpoint response format

The /auth/token endpoint now returns { access_token, expires_in }
instead of { token, expiry }. All clients must update their parsers.
</example> </examples>

Branch Discovery

分支探测

Before branching or opening a PR, discover the repo's branch topology. Run these commands and store the results:
bash
undefined
在创建分支或发起PR前,需探测仓库的分支拓扑。运行以下命令并存储结果:
bash
undefined

Default branch (PR target for most repos)

默认分支(大多数仓库的PR目标分支)

gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'
gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name'

Current branch

当前分支

git branch --show-current
git branch --show-current

Production branch (if different from default)

生产分支(若与默认分支不同)

git branch -r --list 'origin/main' 'origin/master' 'origin/production'

**Fallback when `gh` is unavailable or the repo has no remote:**

```bash
git branch -r --list 'origin/main' 'origin/master' 'origin/production'

**当`gh`不可用或仓库无远程仓库时的 fallback 方案:**

```bash

Infer default branch from local refs

从本地引用推断默认分支

git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@'
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@'

Last resort: check local branches and fail loudly if unknown

最后手段:检查本地分支,若未知则报错

if git rev-parse --verify main >/dev/null 2>&1; then echo main elif git rev-parse --verify master >/dev/null 2>&1; then echo master else echo "ERROR: unable to determine default branch (main/master not found)." >&2 exit 1 fi

Store the discovered branch name and reference it throughout. Use the actual branch name in all subsequent commands.
if git rev-parse --verify main >/dev/null 2>&1; then echo main elif git rev-parse --verify master >/dev/null 2>&1; then echo master else echo "ERROR: unable to determine default branch (main/master not found)." >&2 exit 1 fi

存储探测到的分支名称,并在后续操作中引用。在所有后续命令中使用实际分支名称。

Branch Naming

分支命名

Use repository branch naming conventions first. If no convention is documented, use:
Format:
type/description-TICKET-ID
Examples:
  • feat/add-login-SEND-77
  • fix/pool-party-stall-SEN-68
  • chore/update-deps
  • hotfix/auth-bypass
Include the ticket ID when an issue exists. Omit when there is no ticket.
优先使用仓库的分支命名规范。若无文档记录的规范,使用以下格式:
格式:
type/description-TICKET-ID
示例:
  • feat/add-login-SEND-77
  • fix/pool-party-stall-SEN-68
  • chore/update-deps
  • hotfix/auth-bypass
若存在对应工单,需包含工单ID。无工单时可省略。

Branch Flow

分支流

Use repository branch flow policy first. If policy is undocumented, a common baseline is:
{production-branch} (production deploys)
 └── {default-branch} (staging/testnet deploys, PR target)
      ├── feat/add-feature-TICKET
      ├── fix/bug-description-TICKET
      └── hotfix/* (branches off production branch for hotfixes)
  • Feature and fix branches start from the default branch
  • Hotfix branches start from the production branch
  • PRs target the default branch unless the repo uses a single-branch flow
  • When default branch and production branch are the same, all PRs target that branch directly
优先使用仓库的分支流策略。若无文档记录的策略,以下为通用基线:
{production-branch}(生产环境部署分支)
 └── {default-branch}(预发布/测试网部署分支,PR目标分支)
      ├── feat/add-feature-TICKET
      ├── fix/bug-description-TICKET
      └── hotfix/*(从生产分支创建的热修复分支)
  • 功能分支和修复分支从默认分支创建
  • 热修复分支从生产分支创建
  • PR默认目标为默认分支,除非仓库使用单分支流
  • 若默认分支与生产分支为同一分支,所有PR直接目标该分支

Merge Strategy

合并策略

Use repository merge policy first (required in many organizations).
If no policy exists, these defaults are reasonable:
PR targetStrategyRationale
Feature → default branchSquash mergeClean history, one commit per feature
Default → productionMerge commitPreserves the release boundary; visible deploy points
Hotfix → productionSquash mergeSingle atomic fix on production
优先使用仓库的合并策略(许多组织强制要求)。
若无相关策略,以下默认方案较为合理:
PR目标分支策略理由
功能分支 → 默认分支Squash Merge(压缩合并)历史清晰,每个功能对应一个提交
默认分支 → 生产分支Merge Commit(合并提交)保留发布边界;部署节点可见
热修复分支 → 生产分支Squash Merge(压缩合并)生产环境上的单个原子性修复

PR Workflow

PR工作流

Sizing

大小评估

Pragmatic sizing over arbitrary limits. Each commit tells a clear story regardless of PR size. A PR should be reviewable as a coherent unit — if a reviewer cannot hold the full change in their head, consider splitting.
注重实际可评审性而非任意限制。无论PR大小,每个提交都应讲述清晰的故事。PR应作为一个连贯的单元可被评审 — 若评审者无法完全理解所有更改,考虑拆分PR。

PR Creation

PR创建

Use repo-native PR tooling (
gh pr create
, GitLab CLI, or web UI) with:
  • Short title under 70 characters
  • Summary section with 1-3 bullet points
  • Test plan as a bulleted checklist
使用仓库原生的PR工具(
gh pr create
、GitLab CLI或网页端),并包含:
  • 不超过70个字符的简短标题
  • 包含1-3个项目符号的摘要部分
  • 以项目符号清单形式呈现的测试计划

History Rewriting Before PR

PR前的历史重写

For branches with messy WIP history, use
/rewrite-history
to:
  1. Backup the branch
  2. Reset to the base branch tip
  3. Recommit changes as a clean narrative sequence
  4. Verify byte-for-byte match with backup
  5. Confirm with the user before force-pushing rewritten history
  6. Open PR with link to backup branch
Each rewritten commit introduces one coherent idea, building on the previous — like a tutorial teaching the reader how the feature was built.
对于包含混乱WIP历史的分支,使用
/rewrite-history
命令:
  1. 备份分支
  2. 重置到基准分支的最新提交
  3. 以清晰的叙事顺序重新提交更改
  4. 验证与备份分支的字节级一致性
  5. 重写历史后强制推送前需与用户确认
  6. 发起PR时附上备份分支链接
每个重写后的提交都应引入一个连贯的想法,基于前一个提交构建 — 就像教程向读者展示功能是如何逐步构建的。