Skip to content

05 · 分支切换与合并

分支是贴在 commit 上的指针。开分支很便宜;真正贵的是合并时的冲突和「合完发现合错了」。

git branch

作用: 列出、创建、重命名、删除本地分支;设置上游。默认不切换过去。

改动范围: 只动分支指针(删除/重命名)。不改工作区,除非你删的是当前分支(Git 会拒绝)。

典型场景: 看自己有哪些分支、开一个功能分支名、删掉已合并的旧分支、看每个分支跟踪谁。

常用写法:

bash
git branch                     # 本地分支
git branch -a                  # 含远程跟踪分支
git branch -vv                 # 跟踪关系、ahead/behind
git branch feature/login       # 基于当前 HEAD 建分支,人还留在原地
git branch feature/login main  # 基于 main 建
git branch -m feature/logn feature/login   # 重命名
git branch -d feature/login    # 安全删除:未合并会拒绝
git branch -D feature/login    # 危险:未合并也删
git branch -u origin/feature/login         # 给当前分支设上游

删除远程分支不是 git branch,是:

bash
git push origin --delete feature/login

不要这样用: branch -D 删还没 merge、也没 push 的分支。指针没了,提交变成 dangling——短期内 reflog 还在,但自己增加了急救步骤。

做错了怎么办: 删错本地分支:

bash
git reflog
git switch -c feature/login a1b2c3d

急救手册 · 删错分支

git switch

作用: 切换当前分支(移动 HEAD 和工作区,使文件变成该分支尖端的样子)。

改动范围: HEAD + 工作区 + 暂存区(会尽量带着你未提交的改动走;带不过去会拒绝切换)。

典型场景: 去做另一个需求;从 main 拉出新分支并立刻开工;参观某次历史(游离)。

常用写法:

bash
git switch main
git switch -c feature/login            # 创建并切过去
git switch -c feature/login main       # 基于 main 创建并切换
git switch -                             # 回到上一个分支
git switch --detach a1b2c3d            # 游离,只看不改

远程已有、本地还没有:

bash
git fetch origin
git switch feature/login               # 现代 Git 会自动跟踪 origin/feature/login

不要这样用: 工作区很脏时强行切到差异很大的分支。Git 会拒绝并提示先 commit / stash。不要为了切过去就 reset --hard

做错了怎么办: 切错分支,git switch - 回去。带着未提交改动切走了:改动还在工作区,再切回来即可。若 Git 拒绝切换,按提示 stash 或 commit,见 08 章

git checkout(旧而全能)

作用: 同时承担「切分支」和「恢复文件」两件事。正因为全能,才容易在恢复文件时写成切分支。

改动范围: 取决于参数。

bash
git checkout main                      # 等同 switch
git checkout -b feature/login          # 等同 switch -c
git checkout -- src/login.ts           # 等同 restore src/login.ts
git checkout a1b2c3d -- src/login.ts   # 取出历史版本的该文件(工作区+暂存区)

新仓库建议用 switch / restore。读老脚本时按上表翻译。

git merge

作用: 把另一个分支的提交合进当前分支。能快进就快进;不能就做一次合并提交(两个父提交)。

改动范围: 本地历史 + 工作区(有冲突时)。不自动推远程。

典型场景:

  • main 合入已审查完的 feature/login
  • 功能分支定期把 main 合进来,减少最后一次冲突。
  • 需要保留「这是一次功能合并」的节点时用 --no-ff

常用写法:

bash
git switch main
git merge feature/login

git merge --no-ff feature/login     # 即使能快进也建合并提交
git merge --squash feature/login    # 把对方所有改动捏成暂存区,自己再 commit(历史变一条)
git merge --abort                   # 冲突或后悔:回到 merge 前

三种结果:

结果含义
Fast-forward当前分支尖端是对方的祖先,指针直接前移,无新提交
Merge commit两边都有独有提交,生成一个双亲提交
Conflict同一处被两边改过,停下来等人解决,见 09 章

不要这样用:

  • 在错误的当前分支上 merge(先 status / branch --show-current)。
  • 冲突解决到一半执行 reset --hard 想「清一下」,把已解决和未解决一起丢掉。应使用 --abort
  • 把已推送的公共历史用 merge 搞乱后,试图 reset + force push 抹掉。

做错了怎么办:

  • 还没 push:git merge --abort(若还在合并中)或 git reset --hard ORIG_HEAD(合并已完成但后悔;先确认工作区没有其它宝贝)。
  • 已经 push:git revert -m 1 <merge_sha> 撤销合并。见 急救手册

git mergetool

作用: 用配置好的外部工具打开冲突文件。

bash
git mergetool

不配工具就不必用,手工编辑冲突标记同样有效,见 09 章

推荐的功能分支节奏

bash
git switch main
git pull --ff-only
git switch -c feature/login

# ... 多次 commit ...

git fetch origin
git merge origin/main            # 或 rebase,见第 06 章
git push -u origin HEAD

# PR 合并后
git switch main
git pull --ff-only
git branch -d feature/login
git push origin --delete feature/login   # 若托管平台没自动删

--ff-onlymain 拒绝意外的本地分叉,避免在默认分支上长出「只有你自己知道的合并提交」。


上一章:04 · 历史 · 下一章:06 · 变基、拣选与改写历史