Git:在最新提交之前恢复功能分支中的所有提交

Git:在最新提交之前恢复功能分支中的所有提交,git,git-reset,git-revert,Git,Git Reset,Git Revert,我有一个分支由于我们的主分支中的强制推送而获得错误的提交历史记录。基本上,我在此分支历史记录中有以下提交:A、B、C、D、E,其中E应该保留,但ABCD应该删除。它们之所以被添加,是因为在强制从主源中删除这些提交之前,主合并到分支中。我怎样才能做到这一点 如果A是要保留的,我可以重新设置git——A很难,但它是另一个方向 # make a backup of the current state of your branch git branch backup your_branch # res

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

如果A是要保留的,我可以重新设置git——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
应用您想要保留的提交

然后,您必须强制将其推到分支以重置内容。一定要让团队中的其他人知道发生了什么

带有rebase+
drop的选项
正如Romain所建议的“再基础是另一种”,这里有一种方法可以做到这一点,假设您确实希望
@-A-B-C-D-E
的最终结果是
@-E
,正如Lasse所问的那样

我将此作为工具带中的另一个工具提供:它不是这个问题的简单解决方案。但是,它允许您删除不按顺序的提交(例如,删除A、C、E和保留B、D):

这将打开您的编辑器(可能是
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
如果您犯了不可恢复的错误,例如删除一行,请通过退出而不保存(
:q!
)中止,然后重试

如果一切正常,请保存并退出缓冲区(
:wq
),然后继续重新定基,直到分支修复完毕

如果在此之后发生了一些不稳定的情况(例如,您将提交哈希更改为不存在的哈希,或者rebase停止执行某些操作,但您不知道原因),您可以使用
git rebase--abort
完全中止rebase,这将使您回到初始状态

如果您的分支看起来正确,请用力推

git push -f
关于力推的一个重要注记 可能鲜为人知,但git 2之前的默认推送策略是
匹配
,这意味着当您
git推送
时,它将用匹配的远程分支名称推送所有本地分支,而不仅仅是当前分支

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

如果还不是这样的话,我建议您使用
simple
。这是Git2的默认设置

分支保护 如果您使用的是集中托管的git解决方案,如Stash/BitBucket、Gitlab或Github,它们都提供所谓的“分支保护”规则,以防止开发人员强制执行分支


添加一个规则,以防止强制推送到
主分支
和可能的
释放分支。

您能告诉我们有关要删除的提交的更多信息吗?是
A
D
提交非合并提交,还是合并提交?ABCD从主机合并(不再在远程主机中),因此应删除。E是我最新的承诺,现在我的头在哪里。我只是想让E出现在分支历史中我只是想澄清一下,您是想恢复这些提交中引入的更改(这会将提交保留在您的存储库中),还是希望完全消除这些提交,就像它们从未发生过一样?如果安全的话,请消除它们:)@LasseVågsætherkarlsen换句话说,你希望
-A-B-C-D-E
的最终结果是
-E
还是
-A-B-C-D-E-F-G
,其中
G
是“A-B-C-D
的相反变化”?@TimBiegeleisen是的,他不能这样做,因为他会失去E。Cherry把它捡回来似乎是实现这一点的好方法。否?您的答案是重写远程历史记录,通常情况下,这不是要执行的写入操作。ABCD是从主控中合并的(不再在远程主控中),因此应该删除。E是我最新的承诺,现在我的头在哪里。我只想在分支机构工作history@joelgullander这就是我所理解的,这就是我在回答中提到的需要。谢谢,这很有效。我总是害怕做强迫性的事情,所以我很高兴我在这里得到了一些帮助。非常感谢我没有勇气(以及部分,知识)自己写作的部分@我很乐意帮忙!我实际上正在准备(给)一个git培训课程,这类事情可以帮助我解决这些问题。我在即将进行的演讲中的主要目标是“别担心——在git中有5种不同的方法可以做几乎任何事情,你可以自信地做其中的大多数事情,你可以撤销大多数错误”@Romanvaleri同样,面对这个问题,我自己也会做我上面写的事情,甚至不考虑你更直接的解决方案。谢谢你!
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
git push -f