Git:还原功能分支中最新提交之前的所有提交

Git: Revert all commits in feature branch prior to latest commit

我有一个分支由于在我们的主分支中强制推送而导致提交历史记录错误。基本上我在这个分支历史中有以下提交:A、B、C、D、E,其中 E 应该保留,但 ABCD 应该被删除。在这些提交被强制从主源删除之前,由于主合并到分支中而添加了它们。我怎样才能做到这一点?

如果 A 是要保留的那个,我可以 git 重置 --hard A 但这是另一个方向....

# make a backup of the current state of your branch
git branch backup your_branch

# reset to the commit prior to A
git reset --hard A^

# then re-apply E
git cherry-pick E

将是一种方法。 Rebase 是另一个(请参阅有关该主题的

您可以使用 git reset --hard A^ 转到最后一个 "good" 提交,然后 git cherry-pick E 应用您要保留的提交。

那你就得强制push到branch去重置东西。一定要让团队中的其他人都知道发生了什么。

带有变基的选项 + drop

正如 Romain 所建议的 "rebase is another",这是一种方法,假设您确实希望 @-A-B-C-D-E 的最终结果是 @-E,正如 Lasse 所问。

我提供这个就像 你的工具包中的另一个工具:它不是解决这个问题的更简单的方法。但是,它确实允许您删除不按顺序的提交(例如,删除 A、C、E 并保留 B、D):

git rebase -i HEAD~6

这将打开您的编辑器(可能 vi),其中的缓冲区如下所示:

pick 4231648cb4 Some previous commit
pick 4bccf2ce81 A some message
pick 7b4cd5ff17 B some message
pick faa44efb7c C some message
pick 0ce0525a79 D some message
pick f104648cc3 E some message

# Rebase 76eb9131b5..ed71142fcb onto 4231648cb4 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

是的,提交的顺序从上到下是反向时间顺序(与 git log 相反),最近的在底部。这就是为什么 "lines are executed from top to bottom" - 从最旧到最近。

按照说明,将要删除的行上的单词 pick 更改为 d(或 drop)。

pick 4231648cb4 Some previous commit
d 4bccf2ce81 A some message
d 7b4cd5ff17 B some message
d faa44efb7c C some message
d 0ce0525a79 D some message
pick f104648cc3 E some message

如果您犯了不可恢复的错误,例如删除一行,请通过不保存退出 (:q!) 中止并重试。

如果一切正常,保存并退出缓冲区 (:wq) 并继续变基,直到你的分支被修复。

如果在那之后发生了一些奇怪的事情(比如你将一个提交散列更改为一个不存在的散列,或者 rebase 停止做某事而你不知道为什么)你可以使用 [=24 完全中止 rebase =] 这将使您回到初始状态。

如果你的分支看起来正确,强制推送。

git push -f

关于力推的重要说明

可能鲜为人知,但是git 2之前的默认推送策略是matching,意思是当你git push时,它会推送all 您的本地分支与匹配的远程分支名称,而不仅仅是您当前的分支。

因此,当您 git push -f 时,它会强制推送 所有 分支(这发生在昨天的一位同事身上)。使用 git config --global push.default 检查。这意味着如果你玩弄其他分支,它也可能会强制推送它。

我会建议 changing the default push strategysimple 如果还没有的话。这是 git 2.

的默认值

分支保护

如果您使用集中托管的 git 解决方案,如 Stash/BitBucket、Gitlab 或 Github,它们都提供所谓的 "branch protection" 规则来防止,除其他事项外,开发人员从强制推送到分支。

添加规则以防止强制推送到 master 和可能的 release 分支。