git stash 并申请

标签 git git-pull git-stash

我是 git 的新手,不太清楚存储的工作原理。

假设我正在处理分支 master 并尝试 git pull 并收到错误,即我的本地更改将被覆盖并且需要 stash 或提交。如果我没有进行任何更改并运行 git stash ,然后执行 git pull 并成功更新,当我 git stash apply 时会发生什么?

一般来说,如果其他人修改文件而我运行 git pull ,当我 run git stash apply 时会发生什么?它是否会覆盖刚刚更新的文件,无论它们在我 stash 它们时是否已上演?它是否覆盖了我刚刚用 git pull 更新的每个文件,以及 stash 的文件?

最佳答案

快速的“TL;DR”外卖版,所以以后可以回来学习更多
git stash 在当前的 HEAD 提交上挂起一个 stash-bag——这是一种特殊形式的 merge 提交,它不在任何分支上。稍后的 git stash apply ,当您进行任何提交时(可能是不同的提交),然后尝试通过查看挂起的 stash-bag 和它挂起的提交来恢复 git 计算的更改。

完成更改后,您应该使用 git stash drop 从它“stash ”的提交中释放 stash 袋。 (而且,git stash pop 只是“应用,然后自动删除”的简写。不过,我建议将这两个步骤分开,以防万一您不喜欢“应用”的结果并且想稍后再试。)

长版
git stash 实际上相当复杂。

据说 "git makes much more sense once you understand X" ,对于许多不同的“X”值,它概括为“一旦你理解了git,git就更有意义”。 :-)

在这种情况下,要真正理解 stash ,您需要了解提交、分支、索引/暂存区、git 的引用 namespace 和 merge 所有工作是如何工作的,因为 git stash 创建了一个非常奇特的 merge 提交,由通常命名空间之外的名称——一种根本不在“分支上”的奇怪 merge ——并且 git stash apply 使用 git 的 merge 机制来尝试“重新应用”在进行特殊 merge 提交时保存的更改,可选保留分阶段和非分阶段更改之间的区别。

幸运的是 ,你实际上不需要了解所有这些来使用 git stash

在这里,您正在某个分支 ( master ) 上工作并且您有一些尚未准备好的更改,因此您不想将它们提交到该分支上。希望它是好的——进入远程存储库上的 origin/master,所以你想选择这些。

假设您和他们都从以 - A - B - C 结尾的提交开始,即 C 是您开始在分支 master 上工作时在存储库中的最终提交。新的“好东西”提交,我们将调用 DE

在您的情况下,您正在运行 git pull 并且它因“工作目录不干净”问题而失败。所以,你运行 git stash 。这会以它特殊的奇怪的 stash-y 方式为你提交你的东西,所以你的工作目录现在是干净的。现在你可以 git pull

在绘制提交方面(就像你用 gitkgit log --graph 得到的图形),你现在有这样的东西。当您运行 i-w 时,存储是小袋子 master 悬卡在您“打开”的提交中,在您的 git stash 分支中。 (名称为 iw 的原因是这些是存储的“i”ndex/staging-area 和“w”ork-tree 部分。)

- A - B - C - D - E      <-- HEAD=master, origin/master
          |\
          i-w            <-- the "stash"

如果您开始在 master 上工作并且从未进行任何提交,则会得到这张图。因此,您最近的提交是 C 。进行存储后, git pull 能够将提交 DE 添加到您的本地分支 master 。 stash 的工作包仍然卡在 C 上。

如果你自己做了几次提交——我们将它们称为 Y ,作为你的提交,而 Z 只是为了有两次提交——“stash then pull”的结果如下所示:
                   .-------- origin/master
- A - B - C - D - E - M  <-- HEAD=master
            \       /
              Y - Z
                  |\
                  i-w    <-- the "stash"

这一次,在 stash 将它的 stash 袋卡在 Z 之后, pull — 只是 fetch 然后是一个真正的 merge ,然后 1343141 到 103145 到 0x223所以它提交 merge ,即 merge 提交。 M 标签仍然指的是提交 origin/master ,而不是 E 。你现在在 M 提交 master ,这是 ME 的 merge 。你“领先” Z

在任何一种情况下,如果您现在运行 origin/master ,存储脚本(它是一个使用大量低级 git“管道”命令的 shell 脚本)有效地执行以下操作:
git diff stash^ stash > /tmp/patch
git apply /tmp/patch

这将 git stash apply 命名为 stash(存储的“工作树”部分)与正确的 3 父级不同。换句话说,它会找出正确的父提交( wC ,视情况而定)和 stash 的工作树之间的“您更改了什么”。然后它将更改应用到当前 checkout 的版本,即 ZE ,同样取决于您从哪里开始。

顺便说一句, M 实际上只是运行相同的 git stash show -p 命令(当然没有 git diff 部分)。如果没有 > /tmp/patch ,它会使用 -p 运行差异。因此,如果您想详细查看 --stat 将 merge 的内容,请使用 git stash apply 。 (不过,这不会向您展示 git stash show -p 可以尝试从存储的索引部分应用什么;这是我对存储脚本的一个小提示。)

在任何情况下,一旦 stash 应用干净,您可以使用 git stash apply 删除对 stash-bag 的引用,以便它可以被垃圾收集。在你放下它之前,它有一个名字( git stash drop ,又名 refs/stash )所以它“永远”坚持下去...... (使其名称变为 stash@{0} )并使新存储使用 stash 名称。大多数 reflog 条目会保留 90 天(您可以将其配置为不同的)然后过期。默认情况下,Stash 不会过期,但是如果您以其他方式配置它,“推送”的 stash 可能会丢失,因此如果您开始根据自己的喜好配置 git,请注意依赖“永远保存”。

请注意, stash@{1} 在这里“pop ”存储堆栈,将 refs/stash 重新编号为 git stash drop 并使 stash@{2} 变为普通 132145使用 stash@{1} 查看存储堆栈。

1无论如何,继续提交它们也不错,然后稍后执行 stash@{1} 以压缩或修复进一步的第二次,第三次,第四次,...,第 n 次提交,和/或重写临时“检查点”提交。但这与此无关。

2它有点复杂,因为您可以使用 stash 来尝试保持暂存更改,但实际上,如果您查看脚本,您将看到实际的命令序列 git stash list 。在这种情况下,它确实只是应用了差异!最终,它直接调用 git rebase -i 以 merge 到工作树中,从而允许从其他地方引入相同的更改。如果你的补丁做了一些“好东西”提交 --indexgit diff ... | git apply --index 的事情,一个普通的 git merge-recursive 会失败。

3这使用 git 的父命名魔法语法,在 git apply 脚本中进行了一些预先规划。因为 stash 是这个时髦的 merge 提交,D 有两个甚至三个父级,但是 stash 脚本设置它以便“第一个父级”是原始提交,Estash,视情况而定, “第二个父级” w 是提交时的索引状态,在小挂起的 stash-bag 中显示为 C,而“第三个父级”(如果存在)是 unstaged-and-maybe-ignored files,来自Zstash^2

请注意,在此答案中,我假设您没有仔细暂存工作树的一部分,并且您没有使用 i 来恢复暂存索引。通过不执行任何这些操作,您将 git stash save -u 提交变得非常多余,因此我们无需在 git stash save -a 步骤中担心它。如果您正在使用 git stash apply --index 或等效项,并且有暂存项目,您可以进入更多的角落情况,其中存储不会干净地应用。

这些相同的警告适用于更多极端情况,适用于使用 iapply 保存的存储,这些存储具有第三次提交。

对于这些特别困难的情况,apply --index 提供了一种将 stash 变成成熟分支的方法——但我会把所有这些留给另一个答案。

关于git stash 并申请,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20409853/

相关文章:

git - 在window服务器上通过ssh执行git pull命令永远挂起

exception - GitHub API : create pull-request that already exists should not throw exception

git - 如何列出 `git stash list` 中存储的父提交

git - `git stash show -p stash@{N}` 和 `git show stash@{N}` 之间的区别?

eclipse - Cherry pick 到 Eclipse git 中的另一个分支

git - Visual Studio 2013 和 BitBucket

git - 在 pull 之前提交所有内容,为什么?

git - 为什么 git stash -p 需要很长时间才能启动?

git - 如何限制用户访问 VSTS 中的特定 Git 存储库?

git - 如何在 Git 中执行不区分大小写的差异