我不小心在本地主分支上运行了gitmergesome_other_branch。我还没有将更改推送给origin master。如何撤消合并?


合并后,git状态显示:

# On branch master
# Your branch is ahead of 'origin/master' by 5 commits.

我如何撤销所有这些提交?


当前回答

如果您注意到需要在合并后立即恢复,并且在合并尝试后还没有做任何其他操作,则只需发出以下命令:git reset--hard HEAD@{1}。

本质上,如果在合并之后没有提交任何其他内容,那么合并sha将指向HEAD@{0},因此HEAD@{1}将是合并之前的前一点。

其他回答

使用git reflog检查合并之前的提交(git refog将是比git log更好的选项)。然后,您可以使用以下方法重置它:

git reset --hard commit_sha

还有另一种方法:

git reset --hard HEAD~1

它会让你回到我的承诺。

请注意,任何已修改和未提交/未提交的文件都将重置为其未修改的状态。要保留它们,要么隐藏更改,要么查看下面的--merge选项。


正如@Velmont在下面的回答中所建议的,在这个直接案例中,使用:

git reset --hard ORIG_HEAD

可能会产生更好的结果,因为它应该保留您的更改。ORIG_HEAD将在合并发生之前直接指向提交,因此您不必自己寻找它。


另一个技巧是使用--merge开关而不是--hard,因为它不会不必要地重置文件:

git reset --merge ORIG_HEAD

--合并重置索引并更新<commit>和HEAD之间不同的工作树中的文件,但保留索引和工作树之间不同的文件(即具有尚未添加的更改)。

我认为您可以执行gitrebase-I[hash][branch_name],其中[hash]是标识哈希值,表示您希望倒回的位置加上一个(或您希望返回的提交次数),然后在编辑器中删除您不再需要的提交行。保存文件。出口祈祷它应该重新缠绕。您可能需要进行一次git重置——很难,但此时应该很好。如果您不想将特定的提交保存在历史记录中,也可以使用此选项将其从堆栈中拉出,但这可能会使存储库处于您可能不希望的状态。

策略:在一切都很好的地方创建一个新的分支。

理由:恢复合并很难。有太多的解决方案,这取决于许多因素,例如您是否提交或推动了合并,或者自合并以来是否有新的提交。此外,您还需要对git有相对深入的了解,以使这些解决方案适应您的情况。如果你盲目地遵循一些指令,你可能会得到一个“空合并”,没有任何东西会被合并,进一步的合并尝试会让Git告诉你“已经是最新的”。

解决方案:

假设您想将dev合并到feature-1中。

查找要接收合并的修订:git log--单行功能-1a1b2c3d4将分支“dev”合并到“feature-1”<--要撤消的合并e5f6g7h8修复零点模块中的NPE<--合并前的NPE,您可能需要这个查看(及时返回):数字结账e5f6g7h8从那里创建一个新分支并签出:git签出-b功能-1

现在您可以重新启动合并:

合并:gitmerge-dev修复合并冲突。提交:gitcommit当您对结果满意时,删除旧分支:gitbranch--delete feature-1

您可以使用git reflog查找上一次结账。有时候,这是一个你想回到的好状态。

具体而言,

$ git reflog
$ git reset --hard HEAD@{0}

你必须改变你的头,当然不是你的,而是你的头。。。。

所以在回答之前,让我们添加一些背景,解释一下这个HEAD是什么。

首先,什么是头部?

HEAD只是对当前分支上当前提交(最新)的引用。在任何给定时间只能有一个HEAD。(不包括git工作树)

HEAD的内容存储在.git/HEAD中,它包含当前提交的40字节SHA-1。


分离式封头

如果您不在最近一次提交中,这意味着HEAD指向历史上的先前提交,它称为分离的HEAD。

在命令行上,它看起来像-SHA-1而不是分支名称,因为HEAD没有指向当前分支的末端

关于如何从分离的HEAD恢复的几个选项:


git校验

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

这将签出指向所需提交的新分支。此命令将签出到给定的提交。此时,您可以创建一个分支并从此开始工作。

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

数字刷新

您也可以始终使用reflog。git reflog将显示更新HEAD的任何更改,检查所需的reflog条目将将HEAD设置回该提交。

每次修改HEAD时,reflog中都会有一个新条目

git reflog
git checkout HEAD@{...}

这会让你回到你想要的承诺


git reset--hard<commit_id>

将你的头“移”回所需的位置。

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.

注:(自Git 2.7以来)您也可以使用git rebase--也可以不使用autostash。


git还原<sha-1>

“撤消”给定的提交或提交范围。重置命令将“撤消”给定提交中所做的任何更改。将提交带有撤销补丁的新提交,而原始提交也将保留在历史记录中。

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

此模式说明了哪个命令执行什么操作。正如您可以看到的那样,重置和签出修改HEAD。