"Once you are comfortable with these tools, you will be able to ‘rewrite the past’ and ‘select precisely which changes to keep.’"
1. Rebasing: git rebase#
At its core, rebase means changing the base of a branch.
Comparing the philosophies: Merge vs. Rebase
graph TD
subgraph Merge_Flow
A1((A)) --> B1((B))
B1 --> C1((C))
B1 --> D1((D))
C1 --> M1((Merge Commit))
D1 --> M1
end
subgraph Rebase_Flow
A2((A)) --> B2((B))
B2 --> C2((C))
C2 --> D2((D prime))
endExplanation:
- Merge: Preserves the ancestry of the branches and produces a new merge point,
M1. The history reflects what actually happened, but with many branches, the graph can become a tangled web. - Rebase: Takes the
featurebranch's commitDand “reapplies” it using the latest commit onmaster,C, as its new base. The resultingD'replays the same patch, though conflict resolution and the new base may change the final contents; its hash also changes because its parent pointer has changed. The history becomes a straight line.
Scenario: keeping a feature branch up to date
You are working on the feature branch, while master has moved ahead.
- The Merge approach: Preserves the divergence between branches and may create a merge commit.
- The Rebase approach:
git switch feature/example git rebase master
The golden rule: do not rebase public branches!
The technical reason: hash fission
- Changing the parent: When you
rebase, you create new commits with different parent relationships. The original commit objects are not modified in place.- The chain reaction: A hash is generated from the contents, including the parent hash. When the parent hash changes, the commit's hash changes completely as well, becoming
D'.- Breaking history: If you push
D'to a shared remote branch, other collaborators still have the oldDhistory locally, and you need to coordinate a common base.- The resulting mess: When a colleague runs
git pull, Git seesDlocally andD'remotely. Because their hashes differ, Git treats them as two distinct histories. If your colleague tries to merge them, this can produce many duplicate commits and messy conflicts.In short: rebase only branches that are “your own.” On shared branches, stick to Merge.
2. Cherry-picking: git cherry-pick#
Scenario: You have written 10 commits on the dev branch, but an urgent release needs just one specific feature, such as Commit X, on master.
# 1. 切换到目标分支
git switch master
# 2. 将特定的提交“拣选”过来
git cherry-pick <commit-hash>Git normally applies the changes introduced by that commit to the current branch and creates a new commit; conflicts are possible. To cherry-pick a merge commit, specify the mainline parent with -m.
3. Interactive rebasing: git rebase -i#
This is “surgery” for rewriting history. It lets you combine, rename, or even remove past commits.
# 修改最近 3 个提交
git rebase -i HEAD~3Common commands in the editor:
pick: Keep the commit.reword: Keep the commit, but change its commit message.edit: Stop to let you modify the code.squash: Combine commits. Fold this commit into the previous one, often to clean up a messy series of WIP commits.drop: Skip the commit in the new history. Whether the old object remains available depends on references, reflogs, and GC.
4. Reference logs: git reflog (the ultimate rescue tool)#
Scenario: You accidentally ran git reset --hard or lost code during a rebase.
The local reflog records reference updates, and the HEAD reflog can also record checkouts. Entries expire and are not automatically transferred to a remote by normal fetch/push operations. It cannot guarantee recovery of uncommitted content.
# 1. 查看所有历史轨迹 (即使是被 reset 掉的)
git reflog
# 2. 找到你想找回的那个时刻的哈希值
# 3. 先建立恢复分支保住该提交,不覆盖当前工作区
git branch recovery/saved-tip <reflog-hash>
git show --stat <reflog-hash>5. Finding bugs: git bisect (binary search)#
Scenario: Your project suddenly has an error, and you do not know which day or commit introduced it.
git bisect start # 开始查找
git bisect bad # 标记当前版本是坏的
git bisect good <hash> # 标记很久以前的一个已知好版本
# Git 会自动切换到中间的 commit,请你测试:
git bisect good # 如果这个版本是好的
# ... 循环往复,直到 Git 锁定那个引起 Bug 的 commit
git bisect reset # 结束查找,回到原点Interrupting operations and verifying the result#
If a rebase or cherry-pick encounters conflicts, check status, edit and stage the conflicted files, then use git rebase --continue or git cherry-pick --continue, respectively. To abandon the operation, use its corresponding --abort option. rebase -i HEAD~3 requires that ancestor to exist; use --root for a range including the initial commit.
bisect requires a reproducible good/bad test. Use git bisect skip for commits that cannot be tested in your environment; skipping multiple commits may leave more than one possible culprit. When finished, run git bisect reset to return to your position before the search.
References & further reading
Adapted from technical notes. Examples use generic names.
Continue along a reading path
Git: from snapshots to collaboration and recovery
- 01Git's underlying model: objects, snapshots, and references
- 02From the first add to undoing a change.
- 03Git branches: merging, conflicts, and saving work in progress
- 04Remote collaboration with Git: fetching, tracking, and two remotes
- 05Advanced Git: rebasing, cherry-picking, and bisecting
- 06A Git scenario handbook: correcting, undoing, and recovering