如何确定git stash的来源

时间:2018-11-07 00:38:05

标签: git

我遇到问题

git stash pop

因为某些dos2unix问题。我想恢复到隐藏状态,而不必合并仅行尾不同的整个文件。 我当时想过要回到藏匿处

git checkout BRANCHNAME

但我不知道如何确定代表此藏匿地来源的BRANCHNAME。 有人有线索吗?

2 个答案:

答案 0 :(得分:5)

TL; DR

使用git stash branch 创建一个新分支并应用存储:

git stash branch newbranch

这始终有效(好,只要您当前的状态是干净的:请参见下面的较长部分),并且等效于创建一个新分支,其父级是您进行隐藏时提交的当前提交,然后运行git apply --index(意味着它分别还原索引和工作树)。

问题的字面答案

您需要做的就是找出是否有任何分支名称标识与该存储的父代相同的提交,因此:

git for-each-ref --format='%(refname:short)' \
    --points-at $(git rev-parse refs/stash~1) refs/heads

将找到可能的分支名称(如果有)。 (这取决于git for-each-ref的相对现代的功能。)

每个存储本身本身就是两次提交,有时甚至是三个提交。 git stash所做的是,它提交了这两个(或三个)提交,但是将它们放在 no 分支上。

Git中的 branch 单词本身有点含糊(请参见What exactly do we mean by "branch"?),但是在这里,我们使用它的含义是分支 name masterdevelop只是指向其分支上的 last 提交:

...--E--F--G   <-- master
         \
          H   <-- develop

当您git checkoutdevelop这样的分支名称时,您正在告诉Git:

  1. 将提交内容提取到 index (您构建下一个提交的位置,也称为暂存区或有时是缓存的位置) em>)
  2. 从索引中取出现在未冻结但仍为Git格式的压缩文件,并将其复制到工作树中,您可以在其中进行处理。
  3. 将名称HEAD附加到分支名称,以便Git知道您现在已签出的提交:

    ...--E--F--G   <-- master
             \
              H   <-- develop (HEAD)
    

    现在,Git知道哈希为H的提交是当前提交或HEAD提交,如名称develop所指向。

如果此时进行普通的新提交(通过将更新的文件或新文件从工作树复制回索引/暂存区,然后运行git commit将其冻结为新的提交), Git使用当前提交作为其父提交写入新提交,然后更新分支名称:

...--E--F--G   <-- master
         \
          H--I   <-- develop (HEAD)

名称HEAD仍附加在分支名称上,但是现在分支名称标识了提交I而不是提交H

git stash的作用是进行两次提交-一个用于索引,一个用于工作树,而没有分支名称。取而代之的是,Git使用名称refs/stash查找w提交(而w查找原始提交和i提交):

...--E--F--G   <-- master
         \
          H   <-- develop (HEAD)
          |\
          i-w   <-- refs/stash

保存iw提交后,git stash运行git reset --hard,将索引和工作树设置回与当前提交匹配的位置(此处为{{ 1}})。

在这种情况下,此时,存储的父提交也由现有分支名称H指向。但是假设您已完成develop,然后继续进行不同的一组更改并进行了新的提交git stash?然后,您将拥有:

I

现在有 no 分支名称指向现有的历史提交...--E--F--G <-- master \ H--I <-- develop (HEAD) |\ i-w <-- refs/stash ,即使可以保证使用H的提交也是如此。

因此,如果您的索引和工作树现在是干净的(即,匹配提交refs/stash并附加了I的内容),并且现在运行HEADgit stash branch recover要做的是附加一个 new 分支名称git stash来提交recover,并检查该提交并将新分支设为当前分支将H附加到它:

HEAD

,并作为...--E--F--G <-- master \ H <-- recover (HEAD) \ I <-- develop 操作的最后一步,应用并删除存储,以使索引恢复为您git stash branch签出并运行{{ 1}},工作树又回到了您H签出并运行git stash时的工作树。现在,您可以完成H的创建和git stash的新提交git add的提交:

git commit

如果J仍指向提交...--E--F--G <-- master \ H--J <-- recover (HEAD) \ I <-- develop ,该怎么办?

如果您没有移动上一个分支,那么现在您仍然有一个新分支。也就是说,现在您将拥有:

develop

(我在这里将新提交保留为H,以便更轻松地与先前的图进行匹配)。此设置没有错。当然,如果您在这里不想要...--E--F--G <-- master \ H <-- develop \ J <-- recover (HEAD) 分支,则不必使用J,但它仍然有效。

那三提交藏匿处呢?

三提交存储是由recovergit stash branch)或git stash save -a--all)制成的。应用(或弹出)这种存储方式要求第三次提交中的文件不与工作树中的文件冲突。通常,这意味着工作树不仅必须按照git stash save -u是“干净的”,而且还必须以运行带有适当选项的--include-untracked提供的意义上是干净的。在这种情况下,甚至git status有时也会失败。如果失败,则不会隐藏存储。

有关更多信息,请参见Why does git stash pop say that it could not restore untracked files from stash entry?

答案 1 :(得分:1)

git stash list可能会给您您想要的东西。

如果您使用git stash savegit stash push保存了存储,则git在存储中添加了一条注释,其中包括分支名称和特定的提交:

$ git stash list
stash@{0}: WIP on master: 039142b Initial commit

即使您为存储库指定了自定义名称,git仍会保存分支名称:

$ git stash save "My stash"
Saved working directory and index state On master: My stash

$ git stash list
stash@{0}: On master: My stash