git:"fix" 如何在软重置后进行 git 分支

git: how do "fix" a git branch after a soft reset

我总是喜欢在我的可视代码编辑器中查看分支上的更改。因此,我正在我的终端中进行软重置:

kk@macbookpro [10457-fix-encryption]$ git rebase origin/master
kk@macbookpro [10457-fix-encryption]$ git reset --soft origin/master

这真的很有帮助,因为我可以直接在编辑器中看到与母版不同的变化。

现在的问题是,如何撤销软重置?到目前为止我所做的是,在合并分支之前,我必须删除本地分支,然后再次检查远程分支:

kk@macbookpro [10457-fix-encryption]$ git checkout master
kk@macbookpro [master]$ git branch -D 10457-fix-encryption
kk@macbookpro [master]$ git checkout 10457-fix-encryption
kk@macbookpro [10457-fix-encryption]$ git rebase origin/master
kk@macbookpro [10457-fix-encryption]$ git log
// check if everything is ok 
kk@macbookpro [10457-fix-encryption]$ git checkout master
kk@macbookpro [master]$ git merge --no-ff 10457-fix-encryption

但是如您所见,这非常复杂。我敢肯定,这不是“git 方式”。如何使用 less git 命令实现此目的?

请帮忙!

要修复错误或不需要的软重置,只需使用另一个软重置即可。这里的技巧是找到正确的 哈希 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

这需要一些提交集,并且将它们复制到新的和改进的提交中。然后它获取当前分支 name——在本例中,10457-fix-encryption——并使其指向最后一个这样复制的提交。

这里棘手的部分是准确确定哪些提交将被复制。复制的提交是以下所列提交的子集:

git log origin/master..HEAD

你运行 git rebase 命令之前。也就是说,Git 将找到那些 可从 HEAD 到达的提交,但不是 可从 [=31= 到达的提交].

上面的“子集”涵盖了一些特殊情况,其中 git rebase 丢弃不需要复制或出于某些特定原因不应复制的提交。如果我们忽略这些特殊情况——我们可能应该在这里——我们可以画出一个典型的 rebase 情况,如下所示:

          L   <-- origin/master
         /
...--G--H   <-- master
         \
          I--J--K   <-- 10457-fix-encryption (HEAD), origin/10457-fix-encryption

此处,每个提交哈希 ID 已替换为大写字母。 Git 中的提交形成向后看的链:提交 H,是 master 上的最后一次提交,向后指向更早的提交 G,后者进一步向后指向,依此类推在。同时,提交 K10457-fix-encryption 上的最后一次提交:它向后指向提交 J,后者指向提交 I,后者指向提交 H。您已经 运行 一个 git push origin,因此提交 I-J-K 位于另一个 Git 存储库中。他们现在基本上已经准备好合并了,除了一个问题:其他人通过添加一个新的提交(或者可能是几个,但我们只是画画)在 origin 上更新了 master这里的那个)。所以提交 L 他们的 分支的提示。

变基操作将列出提交 IJK 的提交哈希 ID,因为这些是 10457-fix-encryption 上的提交(包含 master plus I-J-K 上的所有提交),minus 上的所有提交 origin/master(包括通过 H 加上 提交 L 的提交数)。这里的集合减法操作恰好留下了 10457-fix-encryption 上的那三个提交。其他集合减法运算也可以,但这个没问题。

接下来,rebase 操作将选择提交 L 作为副本应该去的地方。那是因为 origin/master 选择提交 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 一样,它之前列出的每个提交。如果并且当每个副本都成功时,这将创建一个新的提交,它应用与原始提交相同的 change。我们可以像这样绘制这些副本:

            I'-J'-K'  <-- HEAD
           /
          L   <-- origin/master
         /
...--G--H   <-- master
         \
          I--J--K   <-- 10457-fix-encryption, origin/10457-fix-encryption

请注意,在这个变基的特定阶段结束时,HEAD 现在 select 副本 K',对应于提交 K。变基代码现在通过从提交 K 中提取 name 10457-fix-encryption 并使其指向提交 K':[=86 来完成变基=]

            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_HEAD10457-fix-encryption@{1}HEAD@{1} 都会产生提交的哈希 ID K':

git rev-parse ORIG_HEAD

例如将打印出所需的哈希 ID。

(哈希 ID 的优点是它们永远不会改变。它们的缺点是非常长且难以键入且无法记住,这就是为什么我们主要使用名称而不是哈希 ID 的主要原因。名称具有更进一步的好处是我们可以像 git rebasegit reset 那样 - 移动 它们使它们 select 一些其他的提交。但这当然也是名称的缺点:当我们移动它们时,我们忘记了它们 使用 指定的哈希 ID。这就是 reflogs 的用途,但 reflogs 中的条目看起来都很相似——除了哈希 ID当然——而且使用起来可能很棘手。)

显然,通过让当前分支名称标识提交 L,而 Git 的索引和您的工作树的内容是文件内容,因为它们出现在提交 K',您的编辑器让您将这些视为更改。但是 git diff 会让您将这些视为更改,而不用担心 git reset。只是 运行:

git diff origin/master HEAD

比较这两个提交。 (就个人而言,我喜欢查看 git log -p 输出或 git format-patch 输出,这样我就可以将 each commit 视为与其前身的差异。)或者找到一些方法可以让你的编辑器查看一些特定提交与当前文件相比,而不是使用当前分支名称。 (但也许没有办法做到这一点,具体取决于您的编辑器。)

所以,如果你真的确实需要这样做,你可以不用移动名字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

它关闭了各种安全检查,但让您可以使用三个命令。