GIT 分支之间的存储和切换问题 - 一个分支的工作出现在另一个分支上而没有合并

GIT stashing and switching between branches issue - work from one branch appeared on the other without merging

我最近同时处理多个分支(确切地说是 3 个分支,我们称它们为 A、B 和 C)。

我在分支 A 然后决定切换到 B,但是我有一些工作,还没有准备好提交。所以我把它藏起来并切换了。

在我审查了 B 上的代码后,我切换到 C 上,以立即进行一些更正。同样,我需要切换到 B,所以我把它们藏起来了。

然后我决定切换到 A 分支,以便从我应用上次存储的最后一个“检查点”开始工作。

然后奇怪的事情开始发生了——我看到了分支 C 的部分变化。

我知道这是一个混乱的工作流程,但今天它发生在我身上......

既然我什么都没有合并,怎么可能发生?

...最糟糕的是我删除了所有隐藏的,除了我应用的一个,认为它是一些旧的、不必要的隐藏。

一切都是为了藏匿……

它们在分支之间共享。如果你把工作藏在一个分支上,它可以很容易地应用到另一个分支上(因此,它在其他分支上是可见的)。

我一定是将存储从分支 C 应用到分支 A。这就是为什么我看到 A 的部分工作的原因 - 因为我只应用了一个存储,而不是整个分支。

如何找回丢失的藏品

存储时,特殊类型的提交是

删除后,在GIT历史记录中仍然可以找到,正如@Code-Apprentice提到的,可以用git reflog查看,这只是[=14=的快捷方式]

git log --reflog --oneline

在我的案例中,丢失的提交显示为:

b10b2fc (refs/stash) WIP on branch: 78beda0 [COMMIT MESSAGE]

所以我可以将此提交合并到我的分支中(这对我来说意味着一些冲突,但总比重做要好):

git merge b10b2fc

Then I decided to switch to A branch, in order to start working from last "checkpoint" I applied last stash.

您在此处应用的“最后存储”是您在分支 C 上所做的存储。这就是为什么您会看到之前在分支 C 上所做的更改。要正确执行此操作,您需要应用从顶部开始的第二个存储:

git checkout A
git stash apply stash@{1}

I know it is messy workflow, but today it happened to me...

这似乎是一个合理的工作流程。作为一名程序员,由于经理的要求,我们经常被拉向多个方向。 git stash 的全部意义在于让我们处理这些类型的中断。你只需要正确使用它。

...the worst part is I deleted all stashed except one I appied, thinking it is some old, unnecessary stash.

这是个问题。这很可能意味着您从分支 A 和 C 上的两个存储中丢失了您的工作。作为最后的手段,您可以通过检查输出 git reflog.

来恢复您的一些工作。

藏起来有害

藏匿处是一种非常奇怪和复杂的野兽,很容易(如您所见)滥用它。

必要时,存储与 HEAD(当前分支)、索引(描述当前分支上的新可能提交)以及创建存储时的工作树密切相关:

index-commit ⬅︎ working-tree-commit
         |         |
          \       /    
          ⬇︎      ⬇︎
         HEAD-commit

该图中的箭头指向出身方向。因此,working-tree-commit 是一种合并(一种非常奇怪的合并,一个合并然后一些)。

实际上,您可以通过调用 git log 查看 复杂的提交:

$ git log stash --graph --oneline
*   778388c (refs/stash) WIP on master: 3429244 z
|\  
| * dcd25d1 index on master: 3429244 z
|/  
* 3429244 (HEAD -> master, branch) z

HEAD 提交不在存储“内部”,但该图中的其他两个提交在。请记住,索引是 HEAD 快照中 all 文件的快照,即提交时 all 您的文件;并且工作树快照是 所有 您可以看到的文件的快照。

因此,如果您将此存储应用于不同的分支,您将向索引和工作树中注入一大堆适用于该分支的内容。你可以很容易地做到这一点,因为正如你所说的那样,你可以拥有多个存储并且它们都是全局可见的。

因此我不太推荐使用stashes。在你描述的特定情况下,我会把这个反应描述为错误的:

but I had some work, not ready for commit. So I stashed it

没有。这是对什么是提交的不灵活态度的标志。您总是“准备好提交”。您应该尽早 并经常 提交。 WIP (work-in-progress) 提交完全没有问题。毕竟,当您修改历史以将其总结为一系列有意义的提交时,您总是可以在以后将 WIP 提交压扁。

因此,在您藏匿的两种情况下,我只会进行 WIP 提交。这更安全,因为它直接绑定到分支 — 事实上,它 分支。只需给它一条 "WIP" 消息,这样当您再次查看它时,您会立即知道您正在做某事。

(所以当时你需要一个藏匿处?在那种你甚至不能做我刚才说的事情的罕见情况下你需要它。索引是部分形成的,可能包含一些不应该包含的东西,因此您正处于索引所说内容和工作树所说内容之间的一些精心设计的重新平衡行为的中间,只是没有时间全部解决并形成真正的提交。这就是为什么存储保留 both 索引 工作树的状态:这是因为它们是 both 处于某种部分 half-baked 状态,你 so 很忙并且 so 很困惑你只需要保留 那个 half-baked 状态 然后离开这里。)