“TL; DR”部分:提防只是盲目做git stash save && git checkout ... && git stash pop
。
实际上有几件你可以取笑,特别是在使用git的命令行界面时。
特别是,“当前分支”(如果有的话)只是记录在文件中的项目(该文件包含HEAD
参考,.git/HEAD
)。查看该文件的原始内容,您通常会看到ref: refs/heads/master
等。 (在“分离HEAD”模式下,您将看到一个原始SHA-1。)有一些低级别的git命令会更新HEAD
而不做任何其他操作。
但是,大多数人主要使用git checkout
来切换分支,除了正确的方法:-)来做到这一点 - 内置了一些保护。主要是,如果您有工作树,它将拒绝切换分支或“索引”(AKA缓存)修改将被这样的交换机丢失。假设您在分支A
上,并且您要求切换到分支B
。结帐过程必须:
- 得到存在于尖端的所有文件的清单提交分行
A
- 的获取存在于尖端的所有文件的列表选项
B
- 的承诺在文件第一个不在第二个的列表中,从第二个列表中不在第一个文件的工作目录
- 中删除这些文件,将这些文件添加到工作目录中
- 中的文件如果(且仅当)文件不同,则替换工作目录内容[R
此外,退房时被做缓存“通过书写”:如果文件F
为A
和B
不同,的B
版本的内容将首先被复制到索引/缓存,然后写入工作目录。
如果你已经上演(与git add
)一些修改文件F
,或者你有一些未上演修改F
在你的工作目录,该结账过程将覆盖这些阶段性或非阶段性变化,因此git checkout
停止带有错误信息。如果文件F
将被删除,那么也会覆盖(或者更准确地说,删除)您的更改,因此checkout
也会停止。
在另一方面,如果文件F
是两个犯了同一,在checkout
可以继续:它只是离开未提交的更改上演或不分级。这就是为什么你有时可以,但不总是,只需git checkout
你想要工作的分支。
Git的 “藏匿”(如git stash
),正如你所看到的,独立的分支。这里的关键概念是每个存储 - 你可以有多个活动 - 实际上是一个提交(或更确切地说,一组提交:两个或三个,这取决于你存储的内容)。但是,在您反对在分支机构上进行提交之前,我们必须再做一些区分。具体来说,“分支”一词指的是两三个不同的东西,在git中。
提交总是(必然)进入“提交图”,因为图仅仅是由所有提交和它们的边形成的东西。如果“分支”一词意味着“提交图的一部分”,这些存储提交在分支上。但“分支”这个词也指的是标识分支的名称提示提交,并且在这里,这些提交提交不会推进分支提示。 (见this post,也Jubobs,对的“分支”的多重含义的更多细节。)
的git stash
命令查看当前索引/缓存和工作树的状态,并从他们身上,使新的提交如果 - 这个“如果”事实证明是非常重要的 - 如果他们有未保存的分阶段或未分阶段的变化。其中一个新提交(可从其中找到其他提交)保存在特殊参考名称stash
下。尽管没有任何新的提交被添加到当前分支,所以它们不在任何命名的分支上。从这个意义上说,它们独立于当前分支 - 但是因为它们是提交,所以它们具有父提交ID,并且从特定意义上讲,它们直接附加到完成时提交的提交。
这对于最终用户来说意味着什么往往是“没有”:你可能不在乎,也不必关心。但是,如果您曾使用git stash branch
将存储转换为分支,则意味着新分支将从存储所附的提交中分离出来。 (这一点,因为它的出现,通常是你想要什么。)与定义,做git stash save && git checkout ... && git stash pop
别名或宏
一个风险是第一步,git stash save
,可以什么都不做。如果它什么都不做 - 如果它不在“存储堆栈”上推送新的存储 - 然后它成功了,并且你的别名或宏将继续检出其他分支,然后(尝试)从藏匿处堆积出来。
如果在该堆栈上还有另一个(不同的)存储器,那么你打算在其他地方使用,那么你只是试图将它弹出到你刚切换到的分支中。
注意,有两个堆叠的“如果”在这儿,必须持有,这个特定的错误两个条件咬:
- 你需要什么都没有藏匿,并
- 你需要有一些现存的你不要想要弹出。
解决此问题的一种方法是使用脚本,而不仅仅是一个简单的git别名来执行分支交换存储序列。在脚本中,像往常一样运行git stash
,但在存储之前和之后,检查stash
参考所解析的SHA-1(如果有)。如果这个变化,git stash save
保存了一些东西,所以有一些东西可以弹出,你可以继续做结账和流行的顺序。如果它没有改变 - 如果前后没有隐藏,或者如果堆栈顶部的存储仍然在堆栈的顶部,那么没有任何可以弹出的东西,你应该只是做一个结帐。
还有另一个bug可以咬你这里;看到this answer到一个有点不同的问题,其中包括一些shell代码表示上述“只有当save
实际推动某些东西”的规则弹出。
*如果我要切换分支,它会在切换到新分支之前自动保存我的工作副本。如果您有未提交的更改与您正在检查的分支发生冲突,那么Git不会让您这样做。你需要“手动”存储它们; Git不会自动为你做。 – Jubobs
好吧,知道我不只是错过了一些东西。我猜想SourceTree中的弹出窗口询问你是否想要放弃本地更改也应该提醒您在切换之前隐藏它们。 – Mathieson
如果你从命令行使用Git,我相信你会有更好的体验,但这只是我的看法。特别是,我不确定SourceTree是否允许您定义别名/宏。 – Jubobs