Git:删除分支、合并与撤销错误的 push

August 2, 2026 · 访客

这三件事时不时就会碰上,可命令却总是记不牢,一次和下一次之间怎么也串不起来。所以干脆把它们好好写下来。

删除分支

git branch -d feature-x

这是安全的版本——Git 会先检查,如果 feature-x 里有还没进入你当前分支的提交,就会拒绝删除。如果你确定要删,可以强制执行: (1)

git branch -D feature-x

不过这只是本地删除。如果这个分支在远程(比如 GitHub 上)也存在,你还得单独把它删掉:

git push origin --delete feature-x

有一点值得知道:删除分支其实并不会删除它的提交。它们只是变得无人引用,继续留在仓库里,直到 Git 的垃圾回收机制最终把它们清理掉,而这可能要等上好一阵子。所以 git branch -D 比看上去更宽容——如果你删错了分支,通常还是有办法找回来的(下面 reflog 那一节会详细说)。我不会把这当成一个可靠的计划,但知道它存在还是挺让人安心的。

合并分支

通常的做法是:切换到你想要合并进去的那个分支,然后把另一个分支合进来。

git checkout main
git merge feature-x

接下来会发生什么,取决于自你分支出去之后 main 有没有继续前进。如果没有,Git 只是把 main 的指针直接滑动到 feature-x 的位置——这就是快进(fast-forward),不涉及任何合并提交。如果这期间 main 已经往前走了,Git 就会创建一个真正的合并提交,把两条历史线绑在一起 (2)。

有时候即便快进本来是可行的,你也会想要那个合并提交——它会在历史里留下一个清晰可见的标记,表明曾经存在过一个 feature 分支并被合并了,而不是让改动悄无声息地融进去。为此可以用:

git merge --no-ff feature-x

如果双方改动了同样的行,Git 会停下来,把冲突留给你去处理:

git status

这会列出哪些文件存在冲突。逐个打开,你会在互相竞争的改动周围看到 <<<<<<<=======>>>>>>> 标记——挑出真正应该保留的内容,删掉这些标记,然后:

git add resolved-file.txt
git commit

要是场面乱得不值得再收拾下去,你完全可以直接抽身走人:

git merge --abort

这会把一切恢复到你开始合并之前的样子,分毫不差。

撤销一次错误的 push

这是最让人恐慌的情况,但说实话,这种恐慌通常没什么必要——不过你选择用哪种方式来补救,这里确实很重要。

只要有一丁点可能别人已经 pull 过这个分支,就别去动历史。改为添加一个新的提交,把旧的撤销掉:

git revert <bad-commit-sha>
git push

这是个无聊但永远安全的选项。它不会重写任何东西——只是在上面加一个提交,把错误抵消掉,这样每个人的历史都保持同步,没人需要在自己那边做任何特殊处理 (3)。

如果这个分支确确实实只属于你,还没有人 pull 过,你就可以倒回去重写: (4)

git reset --hard <last-good-commit-sha>
git push --force-with-lease

--force-with-lease,别用纯粹的 --force,哪怕只是出于习惯也该这样。这个区别比看上去重要得多:--force-with-lease 会检查自你上次 fetch 以来有没有人向这个分支 push 过,如果有就拒绝执行。纯粹的 --force 什么都不检查——它会毫不犹豫地覆盖别人的工作,连一句警告都没有 (5)。

如果你盯着终端,努力回想上一个还算正常的提交到底是哪个——git log 在这里帮不上忙,因为它只显示从你当前位置能够到达的提交,而你已经 reset 掉的那些不在其中。你真正需要的是:

git reflog

它会显示你的分支最近指向过的每一个位置,包括那些已经掉出正常历史记录的。往回翻到事情出错之前,然后: (6)

git reset --hard HEAD@{2}

(换成真正符合你情况的位置或 SHA)。reflog 只保存在你自己的机器上,通常会把记录保留大约 90 天,所以与其说它是"应对错误 push 的紧急撤销手段",不如说它是那种"我好像刚把什么搞坏了"时的通用安全网——即便在这个具体场景之外,也值得记住它的存在。

结语

这三件事其实都依赖同一个底层事实:Git 几乎从不立刻丢弃任何东西。被删除的分支、被 reset 掉的提交、分支上的旧位置——它们停留的时间都比看上去要长。这才是真正让 -Dreset --hard 和 force-push 在日常使用中足够安全的原因,前提是你知道万一其中哪一个出了差错,该去哪里找回来。

相关阅读

延伸阅读

  1. git-branch — 分支的创建、列出与删除。
  2. git-merge — 合并策略与冲突解决。
  3. git-revert — 通过创建新提交来撤销旧提交。
  4. git-reset — 移动分支指针,以及 --soft--mixed--hard 之间的区别。
  5. git-push: --force-with-lease — 为什么它比 --force 更安全。
  6. git-reflog — 找回那些在正常历史记录中已经看不到的提交。

评论