git stash并申请

ner*_*daj 31 git git-stash git-pull

我是git的新手,并不清楚stashing是如何工作的.

假设我正在分支主服务器上工作并尝试git pull接收错误,即我的本地更改将被覆盖并需要被隐藏或提交.如果我没有上演我的任何更改并运行git stash,那么做一个git pull并成功更新,当我发生了什么git stash apply

一般来说,如果其他人修改文件并且我运行git pull,那么当我发生时会发生什么run git stash apply?它是否会覆盖刚刚更新的文件,无论它们是否在我存储时被暂存?它是否会覆盖我刚刚更新过的每个文件,git pull以及被隐藏的文件?

tor*_*rek 67

快速的"TL; DR"外卖版本,所以人们可以稍后回来学习更多

git stash挂起一个存储袋 - 这是一种特殊形式的合并提交,它不在当前HEAD提交的任何分支上.稍后git stash apply,当你在任何提交 - 可能是一个不同的提交 - 然后尝试通过查看挂起的存储袋和它挂起的提交来恢复更改 git计算.

当您完成更改后,您应该使用git stash drop它从"提交"的提交中释放存储袋.(并且,git stash pop只是"应用,然后自动删除"的简写.我建议将两个步骤分开,但是,如果您不喜欢"应用"的结果,并且您想稍后再试.)

长版

git stash 实际上相当复杂.

有人说,"一旦你理解X,git会更有意义",对于许多不同的"X"值,它会推广到"git在你理解git时更有意义".:-)

在这种情况下,要真正理解stash,您需要了解提交,分支,索引/登台区域,git的引用名称空间以及合并所有工作的方式,因为git stash创建了一个非常特殊的合并提交,由外部名称引用通常的名称空间 - 一种奇怪的合并,根本不是"在一个分支上" - 并git stash apply使用git的合并机制来尝试"重新应用"在特殊合并提交时保存的更改,可选择保留区别在分阶段和非分阶段的变化之间.

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

在这里,您正在处理某个branch(master),并且您还有一些尚未准备好的更改,因此您不希望在分支上提交它们.1 与此同时,其他人把一些好东西 - 或者至少,你希望它很好 - 进入origin/master远程仓库,所以你想要选择那些.

假设您和他们都以提交结束开始- A - B - C,即,C当您开始分支时,您在回购中的最终提交master.新的"好东西"承诺,我们会打电话DE.

在你的情况下,你正在运行git pull,它失败了"工作目录不干净"的问题.所以,你跑git stash.这会以特别奇怪的藏匿方式为您提交您的东西,以便您的工作目录现在干净.现在你可以git pull.

就提交的绘制而言(你得到的图表gitk或者git log --graph),你现在有这样的东西.当你跑步的时候i-w,藏匿在你的master分支机构中" 挂"的小东西git stash.(原因的名字iw是,这是"我" ndex /舞台区和"W"藏匿的扫树的部分.)

- A - B - C - D - E      <-- HEAD=master, origin/master
          |\
          i-w            <-- the "stash"
Run Code Online (Sandbox Code Playgroud)

如果你开始工作master并且从未做过任何提交,那么这个图就是你得到的.因此,您最近的承诺就是这样C.在进行存储后,git pull能够添加提交DE到您当地的分支机构master.藏匿的工作袋仍悬挂着C.

如果你做了一些你自己的提交 - 我们会调用它们Y,为了你的提交,Z只是为了进行两次提交 - "stash then pull"的结果如下所示:

                   .-------- origin/master
- A - B - C - D - E - M  <-- HEAD=master
            \       /
              Y - Z
                  |\
                  i-w    <-- the "stash"
Run Code Online (Sandbox Code Playgroud)

这个时候,后stash悬挂其藏匿袋关闭Z时,pull只需首位,而其fetch随后merge-had做一个真正的合并,而不是只是一个"快进".所以它进行提交M,合并提交.该origin/master标签仍然是指犯E,没有M.你现在master在提交M,这是合并EZ.你是"领先"的origin/master.

在任何一种情况下,如果您现在运行git stash apply,存储脚本(它是一个使用大量低级git"plumbing"命令的shell脚本)有效2执行此操作:

git diff stash^ stash > /tmp/patch
git apply /tmp/patch
Run Code Online (Sandbox Code Playgroud)

这种差异stash,其名称w- 存储的"工作树"部分 - 与正确的3父母相对.换句话说,它会在正确的父提交(CZ适当的)和隐藏的工作树之间找出"你改变了什么" .然后,将更改应用到当前签出的版本,这是无论是EM,同样取决于你开始的地方.

顺便说一句,git stash show -p实际上只是运行相同的git diff命令(> /tmp/patch当然没有任何部分).没有-p,它运行差异--stat.因此,如果您想详细了解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天(您可以将其配置为不同)然后过期.默认情况下,stashes不会过期,但如果你另外配置,那么"推送"的存储可能会丢失,所以如果你开始根据自己的喜好配置git,请注意依赖"永远保存".

请注意,git stash drop"啪啪"在这里藏匿栈,重编stash@{2},以stash@{1}和制作stash@{1}变得平淡stash.使用git stash list看藏匿堆栈.


1无论如何都要继续提交它们,然后再git rebase -i进行压缩或修复进一步的第二,第三,第四,......,第n次提交,和/或重写临时"检查点"提交.但这与此无关.

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

3这使用了git的父命名魔术语法,并在stash脚本中进行了一些提前规划.因为存储是这个时髦的合并提交,w有两个甚至三个父,但是存储脚本设置它,以便"第一个父"是原始提交,C或者Z,视情况而定."第二个父级" stash^2是提交时的索引状态,如i小悬挂式存储袋所示,"第三个父级"(如果存在)是来自git stash save -u或的未分级和可能被忽略的文件git stash save -a.

请注意,在此答案中,我假设您没有仔细地分阶段部分工作树,并且您没有使用它git stash apply --index来恢复分阶段索引.通过不执行任何操作,您提交的i提交几乎是多余的,因此我们在apply步骤中不必担心它.如果您正在使用apply --index或等效,并且分阶段的项目,您可以进入更多的角落案例,其中存储将不会干净地应用.

这些相同的警告适用于更多的角落情况,与第三次提交保存的-u或者保存的情况-a.

对于这些特别困难的案例,git stash提供了一种将存储转变为成熟分支的方法 - 但我会将所有这些留给另一个答案.

  • @AmadeusDrZaius:“应用”步骤(事实上,git 中的所有这些东西)都使用我所说的“合并机制”。只有某些命令公开选项(“--strategy”和“-X”),其他命令使用默认设置;默认停止并出现冲突错误。当然,git 只能告诉您*它*看到的冲突,因此一般来说,即使 git 对结果感到满意,您也始终必须检查结果。 (2认同)

Seb*_*ien 6

stash git 命令会记住 stash 的来源:

   git stash list
Run Code Online (Sandbox Code Playgroud)

输出

   stash@{0}: WIP on master.color-rules.0: 35669fb [NEW] another step toward initial cube
Run Code Online (Sandbox Code Playgroud)

您可以在哪里看到它是在哪个 SHA1 上制作的。因此,如果您 git stash、git pull、git stash apply 并且遇到冲突,则不会删除 stash(仅当您删除或应用成功时才会删除)。所以你总是可以从 git stash 列表中获取 SHA1 和

   git checkout 35669fb
   git stash apply
Run Code Online (Sandbox Code Playgroud)

它保证工作。我建议使用 -b 选项并为该恢复提供一个分支名称。

话虽如此,我最喜欢的工作流程是始终以新的“个人”名称结帐以避免此类问题

  • `git stash branch &lt;newbranch&gt;` 结合了所有三个步骤(检查 stash 适用的版本,创建新分支,并使用 `--index` 应用 stash,然后在成功应用后删除 stash)。 (3认同)