git存储和应用

我是新来的混帐,不太清楚如何存储工作。

比方说,我正在分支大师工作,并试图git pull和接收我的本地更改将被覆盖,需要被隐藏或提交的错误。 如果我没有执行任何更改并运行git stash ,那么请执行git pull并成功更新,当我git stash apply时会发生什么情况?

一般来说,如果别人修改文件,我运行git pull ,当我run git stash apply会发生什么? 它是否覆盖刚更新的文件,而不pipe它们是否在我藏起来的时候被上演? 它覆盖每个文件,我刚刚更新与git pull ,与文件被藏起来?

快速的“TL,DR”外卖版本,所以稍后可以回来学习更多

git stash挂起了一个stash-bag,这是一个合并提交的独特forms,不在任何分支上 – 在当前的HEAD提交中。 后面的git stash apply ,当你在任何提交 – 可能是一个不同的提交 – 然后试图恢复更改 git计算通过查看挂的藏匿袋和提交挂起。

当你完成了这些修改之后,你应该使用git stash drop来释放被“隐藏”的提交的存储包。 (而且, git stash pop只是“应用,然后自动删除”的简写,但是我build议保留这两个步骤,但是如果你不喜欢“apply”的结果并且你想以后再试一下)。

长版

git stash实际上相当复杂。

有人说, “一旦你理解了X , Git就更有意义了” ,对于许多不同的X值来说,一旦你了解Git,Git就会变得更有意义。 🙂

在这种情况下,为了真正了解stash ,您需要了解提交,分支,索引/登台区域,git的引用名称空间以及合并所有工作,因为git stash会创build一个非常特殊的合并提交,通常的名字空间外的一个名字 – 一个奇怪的合并,并不是“在分支上” – 而git stash apply使用git的合并机制来尝试“重新应用”当特殊的合并提交时保存的变化可选地保留分阶段和未分阶段的变化之间的区别。

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

在这里,你正在研究一些分支( master ),并且你还有一些尚未准备好的更改,所以你不想在分支上提交它们。 1与此同时,其他人把一些好东西(或者至less是你希望的东西)放在远程回购的origin/master身上,所以你想挑选那些东西。

假设你和他们都以提交以- A - B - C结束的提交开始,也就是说, C是你在开始分支master工作时在你的回购库中的最终提交。 新的“好东西”提交,我们打电话给DE

在你的情况下,你正在运行的git pull ,它失败了“工作目录不干净”的问题。 所以,你运行git stash 。 这就为你提供了你的东西,以特别的怪异的方式,让你的工作目录变得干净。 现在你可以git pull

在提交的提交(像你得到的gitkgit log --graph )方面,你现在有这样的事情。 当你运行git stash时候,在你的master分支中,存储就是你所“提交”的提交的小包。 (名字iw的原因是这些是藏匿处的“i”ndex / staging-area和“w”ork-tree部分)。

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

如果你开始在master工作,从未做任何提交,这张图就是你所得到的。 你最近的提交是C 藏好之后, git pull能够将提交DE添加到您当地的分支master 。 藏起来的工作包仍然挂着。

如果你做了一些你自己的提交 – 我们将它们叫做Y ,为了你的提交,而Z只是有两个提交 – “存储然后拉”的结果是这样的:

  .-------- origin/master - A - B - C - D - E - M <-- HEAD=master \ / Y - Z |\ iw <-- the "stash" 

这一次, stashZ轴上的藏匿袋之后,只是取而代之的pull合并,而不是“快进”。 所以它使提交M ,合并提交。 origin/master标签仍然指的是提交E ,而不是M 你现在在M master ,这是EZ的合并。 你是origin/master “领先者”之一。

在这两种情况下,如果你现在运行git stash apply ,那么存储脚本(这是一个使用大量低级git“plumbing”命令的shell脚本)可以有效地实现这一点:

 git diff stash^ stash > /tmp/patch git apply /tmp/patch 

这个不同之stash在于,它将stash的“工作树”部分命名为正确的父项。 换句话说,它找出了正确的父提交( CZ ,如适用)和隐藏的工作树之间的“你改变了什么”。 然后,根据您开始的位置,将更改应用到当前检出的版本( EM

顺便提一下, git stash show -p真的只是运行相同的git diff命令(当然没有> /tmp/patch部分)。 没有-p ,它用--stat运行diff。 所以,如果你想详细看看什么git stash apply将合并,使用git stash show -p 。 (这不会告诉你什么git stash apply可以尝试从存储的索引部分申请,虽然;这是一个轻微的抱怨,我已经与存储脚本。


在任何情况下,一旦隐藏应用程序,您可以使用git stash drop删除对隐藏包的引用,以便它可以被垃圾收集。 直到你放弃它,它有一个名字( refs/stash ,又名stash@{0} ),所以它坚持“永远”…除了一个事实,如果你做了一个新的藏匿, stash脚本“推”当前存储到存储reflog(以便其名称变成stash@{1} ),并使新的存储使用refs/stash名称。 大多数reflog条目会保留90天(可以将其configuration为不同),然后过期。 默认情况下,Stash不会过期,但是如果你configuration了这个,否则一个“推”藏匿可能会丢失,所以如果你开始configurationgit的话,要注意依赖于“save forever”。

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


1不pipe怎么样,先进行提交,然后再做一次git rebase -i压缩或修正第二,第三,第四,…,第n个提交,并/或重写临时的“检查点”提交。 但是,这是独立的。

2这是一个更复杂的,因为你可以使用 – --index来保持阶段性的变化,但事实上,如果你看脚本,你会看到实际的命令序列git diff ... | git apply --index git diff ... | git apply --index 。 在这种情况下,它确实只是应用差异! 最后,它直接调用git merge-recursive来合并工作树,允许从别处引入相同的更改。 一个普通的git apply将失败,如果你的补丁做了“好东西”提交DE也。

3这使用了git的父命名魔法语法,在stash脚本里面有一点提前计划。 由于存储是这个时髦的合并提交, w有两个甚至三个父母,但存储脚本设置它,以便“第一个父母”是原始提交, CZ ,适当的。 “第二个父母” stash^2是提交时的索引状态,在小吊袋中显示为i ,“第三父母”(如果存在)是未分离和可能被忽略的文件,从git stash save -ugit stash save -a

请注意,在这个答案中,我假定你没有仔细地上演你的工作树的一部分,并且你没有使用git stash apply --index来恢复staged索引。 通过不做任何这一点,你使i承诺非常多余,所以我们不必担心在apply步骤。 如果你正在使用apply --index或者等价物,并且已经上演了物品,那么你可以进入更多的angular落里,那里的藏品不会很干净。

这些相同的注意事项适用于更多的angular落案例,使用-u-a保存的存储具有第三次提交。

对于这些特别困难的情况, git stash提供了一种方法将一个存储转化为一个完整的分支,但是我将把所有这些都留给另一个答案。

一般来说,未提交的更改总是不好的。 要么你的改变是好的,然后提交他们,否则他们是不好的,而不是放弃他们。 做任何git操作,而没有提交更改往往会造成麻烦,git将无法帮助你,因为git不知道你没有提交的任何东西。

说了这些,回到你的问题。 ;)

Git通常很聪明。 当您应用存储时,它会尝试将您的更改与其他更改合并。 大多数时候这只是工作。

如果变化真的发生冲突,因为你以不同的方式改变了相同的行,git会告诉你,你将不得不自己解决冲突。 – 即使在这种情况下,git将通过git mergetool来帮助你,它会启动一个合适的命令来显示你的冲突,并允许你逐一解决它们。

存储git命令会记住藏匿处的来源:

  git stash list 

输出

  stash@{0}: WIP on master.color-rules.0: 35669fb [NEW] another step toward initial cube 

在哪里可以看到在哪个SHA1上制作的。 所以,如果你藏起来,git pull,git stash apply并且你有冲突,那么这个存储就不会被丢弃(只有当你放弃或者申请成功的时候)。 所以你总是可以从git存储列表中获取SHA1

  git checkout 35669fb git stash apply 

这是工作的保证。 我build议使用-b选项并为该恢复提供分支名称。

这就是说,我最喜欢的工作stream程是总是以新的“个人”名义结账,以避免这种问题