git-workflow-expert

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Git Workflow Expert

Git工作流专家

Master git operations from daily workflow to disaster recovery. Covers branching strategies, merge vs rebase decisions, conflict resolution, monorepo patterns, and advanced operations that most developers never learn but desperately need.
精通从日常工作流到灾难恢复的Git操作。涵盖分支策略、merge与rebase决策、冲突解决、monorepo模式,以及大多数开发者从未学习但迫切需要的高级操作。

When to Use

适用场景

Use for:
  • Choosing a branching strategy for a project (trunk-based, GitHub Flow, git-flow)
  • Resolving merge conflicts (especially complex multi-file conflicts)
  • Rebase workflows (interactive rebase, rebase onto, autosquash)
  • Cherry-picking across branches
  • Using git bisect to find bug-introducing commits
  • Recovering lost work with reflog
  • Monorepo git patterns (sparse checkout, subtree, submodules)
  • Cleaning up messy git history
  • Setting up git hooks for quality gates
  • Force push safety and shared branch protocols
NOT for:
  • GitHub Actions / CI/CD pipelines (use
    github-actions-pipeline-builder
    )
  • PR review process and checklists (use
    code-review-checklist
    )
  • GitHub API / webhooks / repository management
  • Git LFS setup (mention it, but not the core focus)

适用场景:
  • 为项目选择分支策略(Trunk-Based、GitHub Flow、Git-Flow)
  • 解决合并冲突(尤其是复杂的多文件冲突)
  • Rebase工作流(交互式rebase、rebase onto、autosquash)
  • 跨分支执行cherry-pick
  • 使用git bisect定位引入bug的提交
  • 通过reflog恢复丢失的工作
  • Monorepo Git模式(sparse checkout、subtree、submodules)
  • 清理混乱的Git提交历史
  • 设置Git钩子作为质量门禁
  • 强制推送安全规范与共享分支协议
不适用场景:
  • GitHub Actions / CI/CD流水线(请使用
    github-actions-pipeline-builder
  • PR评审流程与检查清单(请使用
    code-review-checklist
  • GitHub API / webhooks / 仓库管理
  • Git LFS配置(可提及但非核心重点)

Core Decision: Branching Strategy

核心决策:分支策略

mermaid
flowchart TD
    Start[New project or rethinking strategy?] --> Team{Team size?}
    Team -->|Solo or 2-3| Trunk[Trunk-Based Development]
    Team -->|4-15| GHFlow[GitHub Flow]
    Team -->|15+ or regulated| Q2{Release cadence?}
    Q2 -->|Continuous deploy| GHFlow
    Q2 -->|Scheduled releases| GitFlow[Git-Flow]
    Q2 -->|Multiple supported versions| GitFlow

    Trunk --> T1[Main branch only]
    T1 --> T2[Short-lived feature branches < 1 day]
    T2 --> T3[Feature flags for incomplete work]

    GHFlow --> G1[main + feature branches]
    G1 --> G2[PR-based review]
    G2 --> G3[Deploy from main after merge]

    GitFlow --> GF1[main + develop + feature + release + hotfix]
    GF1 --> GF2[Formal release branches]
    GF2 --> GF3[Hotfix branches from main]
mermaid
flowchart TD
    Start[New project or rethinking strategy?] --> Team{Team size?}
    Team -->|Solo or 2-3| Trunk[Trunk-Based Development]
    Team -->|4-15| GHFlow[GitHub Flow]
    Team -->|15+ or regulated| Q2{Release cadence?}
    Q2 -->|Continuous deploy| GHFlow
    Q2 -->|Scheduled releases| GitFlow[Git-Flow]
    Q2 -->|Multiple supported versions| GitFlow

    Trunk --> T1[Main branch only]
    T1 --> T2[Short-lived feature branches < 1 day]
    T2 --> T3[Feature flags for incomplete work]

    GHFlow --> G1[main + feature branches]
    G1 --> G2[PR-based review]
    G2 --> G3[Deploy from main after merge]

    GitFlow --> GF1[main + develop + feature + release + hotfix]
    GF1 --> GF2[Formal release branches]
    GF2 --> GF3[Hotfix branches from main]

Strategy Comparison

策略对比

DimensionTrunk-BasedGitHub FlowGit-Flow
Branch lifetimeHoursDaysDays-weeks
Merge frequencyMultiple/dayDailyPer-sprint
CI requirementMandatoryStrongOptional
Rollback mechanismFeature flagsRevert commitRelease branch
Best forHigh-trust teamsMost web projectsVersioned releases
Worst forJunior-heavy teamsMultiple live versionsFast iteration

维度Trunk-BasedGitHub FlowGit-Flow
分支生命周期数小时数天数天至数周
合并频率每日多次每日一次每迭代一次
CI要求强制强烈建议可选
回滚机制功能开关回退提交发布分支
最佳适用场景高信任团队多数Web项目版本化发布
最差适用场景新手占比高的团队多版本并行的项目快速迭代场景

Merge vs Rebase Decision

Merge vs Rebase决策

mermaid
flowchart TD
    Q[Integrating changes?] --> Shared{Is the branch shared?}
    Shared -->|Yes, others push to it| Merge[Use merge]
    Shared -->|No, only me| Q2{Want clean history?}
    Q2 -->|Yes| Rebase[Use rebase]
    Q2 -->|No, preserve context| Merge
    Rebase --> Q3{Long-lived branch?}
    Q3 -->|Yes, many conflicts expected| RebaseOnto[Consider rebase --onto]
    Q3 -->|No| RebaseSimple[Simple rebase]
mermaid
flowchart TD
    Q[Integrating changes?] --> Shared{Is the branch shared?}
    Shared -->|Yes, others push to it| Merge[Use merge]
    Shared -->|No, only me| Q2{Want clean history?}
    Q2 -->|Yes| Rebase[Use rebase]
    Q2 -->|No, preserve context| Merge
    Rebase --> Q3{Long-lived branch?}
    Q3 -->|Yes, many conflicts expected| RebaseOnto[Consider rebase --onto]
    Q3 -->|No| RebaseSimple[Simple rebase]

Anti-Pattern: Rebase Shared Branches

反模式:对共享分支执行Rebase

Novice: "I'll rebase main into the shared feature branch to keep it clean." Expert: Never rebase branches others are pushing to. Rebase rewrites commit SHAs — anyone who already pulled will get duplicate commits and merge hell. Use
merge
for shared branches,
rebase
for personal branches. Detection: Multiple developers report "weird duplicate commits" after a pull.
新手: "我要把main分支rebase到共享功能分支上,保持历史整洁。" 专家: 绝不可以对其他人正在推送的分支执行rebase。Rebase会重写提交SHA——任何已经拉取过该分支的人都会遇到重复提交和合并灾难。共享分支使用
merge
,个人分支使用
rebase
识别迹象: 多名开发者拉取后报告出现“奇怪的重复提交”。

Anti-Pattern: Merge Commit Soup

反模式:合并提交泛滥

Novice: "I'll just merge main into my feature branch every morning to stay current." Expert: Daily merge commits from main create an unreadable history. Instead:
git rebase main
on your personal branch (one clean operation), or if you must merge, at least squash when merging back to main. Timeline: Before 2020, merge was the default. Modern teams prefer rebase for feature branches, merge (or squash-merge) for PRs.

新手: "我每天早上都把main分支merge到我的功能分支上,保持同步。" 专家: 每天从main分支合并会产生难以阅读的提交历史。正确做法:在个人分支上执行
git rebase main
(一次整洁的操作);如果必须合并,至少在合并回main时执行squash。 时间线: 2020年之前,merge是默认操作。现代团队更倾向于对功能分支使用rebase,对PR使用merge(或squash-merge)。

Conflict Resolution

冲突解决

The Calm Approach

冷静处理法

bash
undefined
bash
undefined

1. Before resolving: understand what happened

1. 解决前:了解冲突原因

git log --merge --oneline # Show conflicting commits git diff --name-only --diff-filter=U # List conflicted files
git log --merge --oneline # 显示产生冲突的提交 git diff --name-only --diff-filter=U # 列出冲突文件

2. For each file: understand both sides

2. 针对每个文件:理解双方改动

git diff :2:file :3:file # :2 = ours, :3 = theirs
git diff :2:file :3:file # :2 = 本地版本, :3 = 远程版本

3. Resolve, then verify

3. 解决冲突后验证

git add resolved-file.ts git diff --cached # Review what you're about to commit
git add resolved-file.ts git diff --cached # 检查即将提交的内容

4. After all files resolved

4. 所有文件解决完成后

git merge --continue # or git rebase --continue
undefined
git merge --continue # 或 git rebase --continue
undefined

Anti-Pattern: Accept Ours/Theirs Blindly

反模式:盲目接受本地/远程版本

Novice: "This conflict is too complex, I'll just
git checkout --ours .
and be done." Expert: Blindly accepting one side loses the other person's work. If a conflict is genuinely too complex, use a 3-way merge tool (
git mergetool
) to see base + ours + theirs simultaneously. For large-scale conflicts, consider
rerere
(reuse recorded resolution) to cache conflict solutions. Detection: Features mysteriously disappear after merges.

新手: "这个冲突太复杂了,我直接执行
git checkout --ours .
完事。" 专家: 盲目接受某一方会丢失另一方的工作。如果冲突确实复杂,使用三方合并工具(
git mergetool
)同时查看基础版本+本地版本+远程版本。对于大规模冲突,可考虑使用
rerere
(复用已记录的冲突解决方案)来缓存解决方法。 识别迹象: 合并后功能神秘消失。

Advanced Operations

高级操作

Cherry-Pick Workflow

Cherry-Pick工作流

bash
undefined
bash
undefined

Pick a specific commit from another branch

从其他分支选取特定提交

git cherry-pick abc123
git cherry-pick abc123

Pick a range (exclusive start, inclusive end)

选取一段范围(起始提交不包含,结束提交包含)

git cherry-pick abc123..def456
git cherry-pick abc123..def456

Cherry-pick without committing (stage only)

选取提交但不自动提交(仅暂存)

git cherry-pick --no-commit abc123
git cherry-pick --no-commit abc123

If conflicts: resolve then

如果出现冲突:解决后执行

git cherry-pick --continue

**When to cherry-pick**: Hotfixes that need to go to multiple release branches. Bug fixes from a feature branch that's not ready to merge.

**When NOT to**: If you need many commits, merge or rebase instead. Cherry-pick creates duplicate commits with different SHAs.
git cherry-pick --continue

**适用场景**: 需要推送到多个发布分支的热修复,以及尚未准备好合并的功能分支中的bug修复。

**不适用场景**: 如果需要选取多个提交,使用merge或rebase替代。Cherry-pick会创建具有不同SHA的重复提交。

Git Bisect (Find Bug-Introducing Commit)

Git Bisect(定位引入bug的提交)

bash
undefined
bash
undefined

Start bisect

启动bisect

git bisect start git bisect bad # Current commit is broken git bisect good v1.2.0 # This tag was working
git bisect start git bisect bad # 当前提交存在bug git bisect good v1.2.0 # 该版本是正常的

Git checks out a middle commit. Test it, then:

Git会检出中间提交。测试后执行:

git bisect good # or: git bisect bad
git bisect good # 或: git bisect bad

Repeat until git identifies the first bad commit

重复直到Git定位到第一个有bug的提交

Automated bisect with a test script:

使用测试脚本自动执行bisect:

git bisect start HEAD v1.2.0 git bisect run npm test # Runs test at each step automatically
undefined
git bisect start HEAD v1.2.0 git bisect run npm test # 在每个步骤自动运行测试
undefined

Reflog Recovery (Undo Almost Anything)

Reflog恢复(几乎可以撤销任何操作)

bash
undefined
bash
undefined

See recent HEAD positions

查看最近的HEAD位置

git reflog --oneline -20
git reflog --oneline -20

Recover a dropped stash

恢复已丢弃的stash

git stash list # Empty? Check reflog: git fsck --no-reflogs | grep commit # Find dangling commits git show <sha> # Inspect to find your stash
git stash list # 为空?查看reflog: git fsck --no-reflogs | grep commit # 查找悬空提交 git show <sha> # 检查找到你的stash

Undo a bad rebase

撤销错误的rebase

git reflog
git reflog

Find the SHA before the rebase started

找到rebase开始前的SHA

git reset --hard HEAD@{5} # Reset to that point
git reset --hard HEAD@{5} # 重置到该节点

Recover deleted branch

恢复已删除的分支

git reflog | grep "branch-name" git checkout -b recovered-branch <sha>
undefined
git reflog | grep "branch-name" git checkout -b recovered-branch <sha>
undefined

Interactive Rebase (Clean History)

交互式Rebase(清理提交历史)

bash
undefined
bash
undefined

Rewrite last 5 commits

重写最近5个提交

git rebase -i HEAD~5
git rebase -i HEAD~5

In the editor:

在编辑器中:

pick abc123 Add user model ← keep as-is

pick abc123 Add user model ← 保留原样

squash def456 Fix typo in user model ← squash into previous

squash def456 Fix typo in user model ← 合并到上一个提交

reword ghi789 Add auth ← edit commit message

reword ghi789 Add auth ← 修改提交信息

drop jkl012 WIP debugging ← remove entirely

drop jkl012 WIP debugging ← 完全删除

edit mno345 Add migration ← pause to amend

edit mno345 Add migration ← 暂停以修改提交

Autosquash: commits prefixed with "fixup!" or "squash!" auto-arrange

Autosquash:前缀为"fixup!"或"squash!"的提交会自动合并

git commit --fixup abc123 # Creates "fixup! Add user model" git rebase -i --autosquash HEAD~5 # Automatically squashes it

---
git commit --fixup abc123 # 创建"fixup! Add user model"提交 git rebase -i --autosquash HEAD~5 # 自动合并该提交

---

Monorepo Git Patterns

Monorepo Git模式

Sparse Checkout (Work on Subset)

Sparse Checkout(仅处理子集)

bash
undefined
bash
undefined

Enable sparse checkout

启用sparse checkout

git sparse-checkout init --cone git sparse-checkout set packages/core packages/cli
git sparse-checkout init --cone git sparse-checkout set packages/core packages/cli

Now only packages/core and packages/cli are checked out

现在仅packages/core和packages/cli被检出

Other directories exist in git but aren't on disk

其他目录存在于Git中但不会出现在磁盘上

undefined
undefined

Subtree (Embed Another Repo)

Subtree(嵌入其他仓库)

bash
undefined
bash
undefined

Add a subtree

添加subtree

git subtree add --prefix=libs/shared https://github.com/org/shared.git main --squash
git subtree add --prefix=libs/shared https://github.com/org/shared.git main --squash

Pull updates

拉取更新

git subtree pull --prefix=libs/shared https://github.com/org/shared.git main --squash
git subtree pull --prefix=libs/shared https://github.com/org/shared.git main --squash

Push changes back upstream

将改动推回上游

git subtree push --prefix=libs/shared https://github.com/org/shared.git feature-x
undefined
git subtree push --prefix=libs/shared https://github.com/org/shared.git feature-x
undefined

Submodules vs Subtree

Submodules vs Subtree对比

DimensionSubmodulesSubtree
ModelPointer to external repoCopy of external repo
CloneRequires
--recurse-submodules
Just works
Update
git submodule update
git subtree pull
CI complexityHigher (need init step)Lower
Best forLarge vendored depsSmall shared libs
Footgun riskHigh (detached HEAD trap)Low

维度SubmodulesSubtree
模式指向外部仓库的指针外部仓库的副本
克隆需要
--recurse-submodules
直接可用
更新
git submodule update
git subtree pull
CI复杂度较高(需要初始化步骤)较低
最佳适用场景大型依赖库小型共享库
风险高(分离HEAD陷阱)

Git Hooks for Quality

Git钩子用于质量管控

bash
undefined
bash
undefined

.git/hooks/pre-commit (or use husky/lefthook)

.git/hooks/pre-commit(或使用husky/lefthook)

#!/bin/sh
#!/bin/sh

Run linter on staged files only

仅对暂存文件运行检查

npx lint-staged
npx lint-staged

.git/hooks/commit-msg

.git/hooks/commit-msg

#!/bin/sh
#!/bin/sh

Enforce conventional commits

强制遵循规范提交格式

if ! grep -qE "^(feat|fix|docs|style|refactor|test|chore)((.+))?: .+" "$1"; then echo "Commit message must follow Conventional Commits format" exit 1 fi
if ! grep -qE "^(feat|fix|docs|style|refactor|test|chore)((.+))?: .+" "$1"; then echo "提交信息必须遵循Conventional Commits格式" exit 1 fi

.git/hooks/pre-push

.git/hooks/pre-push

#!/bin/sh
#!/bin/sh

Run tests before push

推送前运行测试

npm test || exit 1
undefined
npm test || exit 1
undefined

Anti-Pattern: Skipping Hooks

反模式:跳过钩子

Novice: "The pre-commit hook is slow, I'll just
--no-verify
." Expert: If hooks are too slow, fix the hooks (use lint-staged for incremental linting, parallelize tests).
--no-verify
becomes a habit that defeats the purpose. If you truly need to skip once (emergency hotfix), document why in the commit message.

新手: "pre-commit钩子太慢了,我直接用
--no-verify
跳过。" 专家: 如果钩子太慢,应该优化钩子(使用lint-staged增量检查、并行化测试)。
--no-verify
会变成习惯,失去钩子的意义。如果确实需要跳过一次(紧急热修复),请在提交信息中说明原因。

Branching Strategy Selection Logic

分支策略选择逻辑

When the user asks which branching strategy to use, apply these rules in order:
当用户询问应使用哪种分支策略时,按以下顺序应用规则:

Hard constraints (override everything)

硬性约束(优先级最高)

  1. Multi-version library (
    hasMultipleVersions: true
    AND
    isLibrary: true
    ) → git-flow
    • Reasoning: Maintaining v2.x hotfixes while developing v3.x requires long-lived release branches. Trunk-based cannot serve two audiences.
    • Migration from trunk-based: Create
      release/vN.x
      branches from the last tag on each major. Backport via cherry-pick.
  2. Regulated industry (
    isRegulated: true
    ) → git-flow
    • Reasoning: Auditors expect named release branches with approval gates, a clear trail from commit to production, and the ability to point at a branch and say "this is what shipped." Trunk-based can technically satisfy this with tags, but the audit conversation is easier with git-flow.
    • Note: If CI maturity is high AND the compliance team is open to it, trunk-based with deploy tags + signed commits is superior. But assume the compliance team is not open to it.
  1. 多版本库 (
    hasMultipleVersions: true
    AND
    isLibrary: true
    ) → Git-Flow
    • 理由:维护v2.x热修复的同时开发v3.x需要长期存在的发布分支。Trunk-Based无法同时服务两类用户。
    • 从Trunk-Based迁移:从每个主版本的最后一个标签创建
      release/vN.x
      分支,通过cherry-pick向后移植改动。
  2. 受监管行业 (
    isRegulated: true
    ) → Git-Flow
    • 理由:审计人员需要带有审批门禁的命名发布分支,清晰的从提交到生产的追踪路径,以及能够指向分支说明“这就是上线版本”的能力。Trunk-Based通过标签技术上可以满足,但Git-Flow更便于审计沟通。
    • 注意:如果CI成熟度高且合规团队接受,带有部署标签+签名提交的Trunk-Based更优。但默认假设合规团队不接受。

CI maturity gate

CI成熟度门槛

  1. Low CI maturity (
    ciMaturity: 'low'
    ) → github-flow
    • Reasoning: Trunk-based without comprehensive CI means broken code on main. GitHub Flow (feature branches + PR review + merge) provides a human safety net. Recommend investing in CI, then graduating to trunk-based.
    • Migration to trunk-based later: Shorten branch lifetimes to <1 day, add branch protection requiring green CI, then drop the requirement for PR approval on small changes.
  1. 低CI成熟度 (
    ciMaturity: 'low'
    ) → GitHub Flow
    • 理由:没有完善CI的Trunk-Based会导致main分支出现损坏代码。GitHub Flow(功能分支+PR评审+合并)提供人工安全网。建议先投入CI建设,再升级到Trunk-Based。
    • 后续迁移到Trunk-Based:将分支生命周期缩短至<1天,添加分支保护要求CI通过,然后取消小改动的PR审批要求。

Default (most teams)

默认规则(大多数团队)

  1. Everything elsetrunk-based
    • Reasoning: Smallest feedback loops, least merge pain, forces good CI habits. Feature flags handle incomplete work. Short-lived branches (<1 day) are acceptable as a concession.
    • If team is >15 people: Consider trunk-based with short-lived feature branches (still trunk-based — the branch lives <24h and auto-deletes after merge).
  1. 其他所有情况Trunk-Based
    • 理由:反馈循环最短,合并痛苦最少,强制养成良好的CI习惯。功能开关处理未完成的工作。可接受短生命周期分支(<1天)作为折中方案。
    • 如果团队人数>15人:考虑使用带有短生命周期功能分支的Trunk-Based(仍属于Trunk-Based——分支存在时间<24小时,合并后自动删除)。

Migration paths

迁移路径

FromToSteps
git-flow → trunk-based1. Merge
develop
into
main
. 2. Delete
develop
. 3. Set branch protection on
main
(require CI green). 4. Adopt feature flags for incomplete work. 5. Shorten branch lifetime target to <1 day.
git-flow → github-flow1. Merge
develop
into
main
. 2. Delete
develop
and all
release/*
branches. 3. PR directly to
main
. 4. Tag releases from
main
.
github-flow → trunk-based1. Reduce PR size to <200 lines. 2. Add comprehensive CI. 3. Allow direct push to
main
for trivial changes. 4. Keep PRs for larger changes but merge same-day.

步骤
Git-Flow → Trunk-Based1. 将
develop
合并到
main
。2. 删除
develop
。3. 为
main
设置分支保护(要求CI通过)。4. 采用功能开关处理未完成工作。5. 将分支生命周期目标缩短至<1天。
Git-Flow → GitHub Flow1. 将
develop
合并到
main
。2. 删除
develop
和所有
release/*
分支。3. 直接向
main
提交PR。4. 从
main
打发布标签。
GitHub Flow → Trunk-Based1. 将PR大小缩减至<200行。2. 完善CI体系。3. 允许对微小改动直接推送到
main
。4. 较大改动仍保留PR但当日合并。

Force Push Safety

强制推送安全规范

bash
undefined
bash
undefined

NEVER force push to main/master

绝不要对main/master分支执行强制推送

Use --force-with-lease instead of --force

使用--force-with-lease替代--force

git push --force-with-lease origin feature-branch
git push --force-with-lease origin feature-branch

--force-with-lease checks that remote hasn't been updated

--force-with-lease会检查远程分支自上次拉取后是否有更新

since your last fetch. Prevents overwriting others' work.

防止覆盖他人的工作

Set as default (never use bare --force again):

设置为默认(永远不要使用裸--force):

git config --global alias.pushf "push --force-with-lease"

---
git config --global alias.pushf "push --force-with-lease"

---

References

参考资料

  • references/advanced-rebase-patterns.md
    — Consult for complex rebase scenarios: rebase --onto, interactive rebase strategies, handling rebase conflicts in long-lived branches
  • references/monorepo-git-strategies.md
    — Consult for monorepo-specific patterns: sparse checkout optimization, CODEOWNERS, path-based CI triggers, large repo performance
  • references/advanced-rebase-patterns.md
    — 复杂rebase场景参考:rebase --onto、交互式rebase策略、处理长生命周期分支的rebase冲突
  • references/monorepo-git-strategies.md
    — Monorepo专属模式参考:sparse checkout优化、CODEOWNERS、基于路径的CI触发、大型仓库性能优化