要修复错误或不需要的软复位,只需使用另一个软复位。这里的诀窍是找到正确的哈希 ID。在这里,reflogs 会有所帮助:被软重置的分支的 reflog 中将包含您想用来恢复它的哈希 ID。在这种特殊情况下,您还可以使用ORIG_HEAD
, 以便在您之后:
git reset --soft origin/master
你可以:
git reset --soft ORIG_HEAD
回到原来的位置。
我怀疑首先没有理由进行软重置。可能有,这取决于这个“可视代码编辑器”的反聪明程度。但这似乎不太可能。
这里要记住的是,分支名称大多只是指定一个特定提交的花哨或方便的方式。还有很多其他方法可以指定某些特定的提交。让我们在这里看看你的终端命令:
kk@macbookpro [10457-fix-encryption]$ git rebase origin/master
这需要一些提交并将它们复制到新的和改进的提交中。然后它获取当前分支名称——在这种情况下,10457-fix-encryption
——并使其指向最后一个这样的复制提交。
这里棘手的部分是准确确定哪些提交将被复制。被复制的提交是那些列出的子集:
git log origin/master..HEAD
在运行git rebase
命令之前。也就是说,Git 会找到那些可以从 到达 HEAD
但不能从 origin/master
到达的提交。
上面的“子集”涵盖了一系列特殊情况,其中git rebase
由于某些特定原因丢弃了不需要复制或不应该复制的提交。如果我们忽略这些特殊情况——我们可能应该在这里——我们可以画出一个典型的变基情况,如下所示:
L <-- origin/master
/
...--G--H <-- master
\
I--J--K <-- 10457-fix-encryption (HEAD), origin/10457-fix-encryption
在这里,每个提交哈希 ID 都被替换为大写字母。Git 中的提交形式是向后看的链: commitH
是最后一次提交 on master
,向后指向更早的 commit G
,后者指向更远的地方,依此类推。同时 commitK
是最后一次提交10457-fix-encryption
:它向后指向 commit J
,指向 commit I
,指向 commit H
。您已经运行了 agit push origin
以便提交I-J-K
位于另一个 Git 存储库中。它们现在大部分都准备好被合并了,除了一个问题:其他人通过添加一个新master
的origin
提交(或者可能是几个,但我们在这里只画一个)更新了。所以commitL
是他们的小费分支。
rebase 操作将列出 commit 、 和 的提交哈希 ID I
,J
因为K
这些是 on 的提交10457-fix-encryption
(由master
plus I-J-K
上的所有提交组成)减去所有的提交origin/master
(由H
plus 上的commit组成L
)。这里的集合减法操作恰好留下了仅on的那三个提交10457-fix-encryption
。其他减法运算也可以,但是这个很好。
接下来,rebase 操作将选择提交L
作为副本应该去的地方。那是因为origin/master
选择 commit L
。Git 将使用其所谓的分离 HEAD 模式来检查提交L
:
L <-- HEAD, origin/master
/
...--G--H <-- master
\
I--J--K <-- 10457-fix-encryption, origin/10457-fix-encryption
rebase 操作现在将继续复制git cherry-pick
它之前列出的每个提交,就像使用 一样。如果并且当每个副本成功时,这将创建一个新的提交,该提交将应用与原始提交相同的更改。我们可以像这样绘制这些副本:
I'-J'-K' <-- HEAD
/
L <-- origin/master
/
...--G--H <-- master
\
I--J--K <-- 10457-fix-encryption, origin/10457-fix-encryption
请注意,在 rebase 的这个特定阶段结束时,HEAD
现在选择 copy K'
,它对应于 commit K
。rebase 代码现在通过从 commit 中提取名称 并使其指向 commit 来完成 rebase :10457-fix-encryption
K
K'
I'-J'-K' <-- 10457-fix-encryption (HEAD)
/
L <-- origin/master
/
...--G--H <-- master
\
I--J--K <-- origin/10457-fix-encryption
kk@macbookpro [10457-fix-encryption]$ git reset --soft origin/master
这样做是移动当前分支名称,而不更改 Git索引中的内容,也不会更改工作树中的内容。所以现在提交图的图片如下所示:
I'-J'-K' ???
/
L <-- 10457-fix-encryption (HEAD), origin/master
/
...--G--H <-- master
\
I--J--K <-- origin/10457-fix-encryption
请注意,不再有提交的分支名称K'
。有几种方法可以找到它:ORIG_HEAD
, 10457-fix-encryption@{1}
, 并且HEAD@{1}
都会产生 commit 的哈希 ID K'
:
git rev-parse ORIG_HEAD
例如将打印出所需的哈希 ID。
(哈希 ID 的优点是它们永远不会改变。它们的缺点是很长,难以输入并且无法记住,这就是我们主要使用名称而不是哈希 ID 的主要原因。名称还有一个优势,我们可以—as git rebase
or git reset
do—<em>移动它们以使它们选择其他提交。但这当然也是名称的一个缺点:当我们移动它们时,我们忘记了它们曾经指定的哈希 ID。这就是 reflogs 的用途,但是 reflogs 中的条目看起来都很相似——当然除了哈希 ID——而且使用起来可能很棘手。)
显然,通过让当前分支名称识别提交L
,而 Git 的索引和您的工作树将文件的内容作为它们的内容,它们出现在 commit 中K'
,您的编辑器可以让您将这些视为更改。但是git diff
会让您将这些视为更改,而无需对git reset
. 赶紧跑:
git diff origin/master HEAD
比较这两个提交。(就个人而言,我喜欢查看git log -p
输出或git format-patch
输出,以便我可以将每个提交视为与其前任的差异。)或者找到一些方法让您的编辑器查看与当前文件相比的某些特定提交,而不是使用当前分支名称。(但也许没有办法做到这一点,这取决于你的编辑器。)
因此,如果您确实需要这样做,您可以在不移动名称10457-fix-encryption
的情况下进行操作。只是做一些其他的临时名称:
git checkout -b tmp
这样你就有了:
I'-J'-K' <-- 10457-fix-encryption, tmp (HEAD)
/
L <-- origin/master
/
...--G--H <-- master
\
I--J--K <-- origin/10457-fix-encryption
您现在git reset --soft origin/master
可以获得:
I'-J'-K' <-- 10457-fix-encryption
/
L <-- origin/master, tmp (HEAD)
/
...--G--H <-- master
\
I--J--K <-- origin/10457-fix-encryption
当你完成比较后,对更新的分支进行另一次重置(软、硬或混合:在这里并不重要,因为你要重置的提交中的内容是 Git 的索引和工作树中的内容)到更新的分支,之后Git会让你删除tmp
,然后签出master
:
git reset 10457-fix-encryption
git checkout 10457-fix-encryption
git branch -d tmp
git checkout master
或者,一旦您对该工作流程更有信心,您可以:
git reset --hard && git checkout master && git branch -D tmp
它关闭了各种安全检查,但让你只需要三个命令。