藏匿/分支/工作副本混乱

时间:2014-12-30 00:06:57

标签: git atlassian-sourcetree

我最近开始使用SourceTree和Git,但我仍然对存储/分支和我的工作副本文件感到困惑。我一直在寻找能为我澄清事情的任何事情。

我的困惑在于与分支和存储相关的文件的工作副本。我期待工作的方式是我的文件工作副本也将链接到分支。如果我要切换分支,它会在切换到新分支之前自动存储我的工作副本。如果我要切换回上一个分支,它将再次存储当前工作副本文件并从上一个分支恢复那些文件。

在使用SourceTree和Git一段时间之后,对我来说很明显,这不是它的工作方式,而且你的工作副本文件完全独立于你的分支,就像存放一样。如果您切换到另一个分支,您可以选择手动存储工作副本文件,放弃更改,或将您的工作文件带到新分支。

所以,我想知道的是,这是什么理想的工作流程?假设我在两个不同的分支中同时开发两个功能,并且希望不断地来回跳转。我是否需要记得在每次切换之前存储我的工作副本文件,或者有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

" 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
  • 的提示提交中存在的所有文件的列表
  • 对于第一个列表中不在第二个列表中的文件,从work-dir
  • 中删除这些文件
  • 对于第二个列表中不在第一个列表中的文件,将这些文件添加到work-dir
  • 对于两者中的文件,如果(且仅当)文件不同,则替换work-dir内容

此外,退房工作由"写完"缓存:如果FA中的文件B不同,则B版本的内容首先被复制到索引/缓存中,然后写入工作目录。

如果您已经(使用git add)对文件F进行了一些修改,或者您对工作目录中的F进行了一些未分阶段的修改,则此结帐流程将覆盖那些暂存或未分阶段的更改,因此git checkout会停止并显示错误消息。如果要移除文件F,那么也会覆盖(或者更准确地说,删除)您的更改,因此checkout会再次停止。

另一方面,如果两个提交中的文件F 相同,则checkout可以继续:它只是暂停或未暂停未提交的更改。这就是为什么你有时(但不总是)只需要git checkout你想要工作的分支。


Git" stash" (正如在git stash中),正如您所见,独立于分支。这里的关键概念是每个存储 - 一次可以有多个活动 - 实际上是提交(或者更准确地说,是一组提交:两个或三个,具体取决于你藏)。然而,在你反对在分支上提交提交之前,我们必须做出另外一些区别。具体来说,"分支"是指两个或三个不同的东西,在git中。

提交总是(必然)进入"提交图形",因为图形只是由所有提交及其边缘形成的事物。在某种程度上,"分支"表示"提交图的一部分",这些存储提交在分支上。但是"分支"也指标识分支 tip 提交的名称,这里,这些存储提交不会推进分支提示。 (有关"分支"的多重含义的详细信息,请参阅Jubobs的this post。)

git stash命令查看当前索引/缓存和工作树状态,并从它们进行新的提交 if -this" if"结果非常重要 - 如果他们有未保存的分阶段或非分阶段更改。其中一个新提交(可以从中找到其他提交)保存在特殊引用名称stash下。但是,没有新的提交被添加到当前分支,因此它们不在任何已命名的分支上。从这个意义上说,它们独立于当前分支 - 但由于它们是提交,因此它们具有父提交ID,并且在特定意义上,它们直接附加到{{时}生效的提交中。 {1}}已完成。

对于最终用户而言,这对您来说通常是什么"没有什么":您可能不关心,而且您不必关心。但是,如果您使用save将存储转换为分支,则意味着新分支将从存储附加到的提交中分离出来。 (事实证明,这通常就是你想要的。)


定义git stash branch的别名或宏的一个风险是,第一步git stash save && git checkout ... && git stash pop可能无效。

如果它什么都不做 - 如果它没有在" stash堆栈上推送新的存储" - 然后它仍然成功,你的别名或宏将继续检查其他分支,然后(尝试)从藏匿处堆栈中弹出一个藏匿处。

如果该堆栈上存在另一个(不同的)存储,那么您打算在其他地方使用,那么,您只是尝试将其弹出到您刚刚切换到的分支中。

请注意,这里有两个堆叠的" if" s,必须保留两个条件,以便咬这个特定的bug:

  • 你需要没有任何东西藏匿,
  • 你需要有一些你想要弹出的存在。

解决此问题的一种方法是使用脚本而不仅仅是一个简单的git别名来执行branch-switch-with-stash序列。在脚本中,您像往常一样运行git stash save,但在存储之前和之后,检查git stash引用解析为的SHA-1(如果有)。如果这种情况发生变化,stash会保存一些内容,因此可以弹出一些内容,然后您可以继续执行结帐并弹出序列。如果它没有改变 - 如果之前和之后没有存储,或者堆栈顶部的存储仍然在堆栈的顶部 - 则没有任何东西可以弹出,你应该只是进行结账。 / p>

还有另一个可以咬你的虫子;请参阅this answer一个稍微不同的问题,其中包括表达上述内容的一些shell代码"仅在git stash save实际推送了某些内容时弹出#34;规则。

答案 1 :(得分:1)

  

如果我要切换分支,它会在切换到新分支之前自动存储我的工作副本。

都能跟得上! Git不会自动为您隐藏本地更改。此外,如果您有未提交的更改与您要检出的分支冲突,Git不会让您检查相关分支。您需要丢弃或存储它们并手动"在检查其他分支之前。

  

我觉得很清楚,你的工作副本文件完全独立于你的分支机构,就像存放一样。

是的,这是有充分理由的。特别是,一个用于存储的用例是当你开始进行更改时,错误的"分支签出。然后你可以通过

摆脱困境
  • 存储您当地的更改(从而降落在干净的工作状态),
  • 检查"正确"分支,
  • 弹出存储以恢复您的本地更改。
  

假设我在两个不同的分支中同时开发两个功能,并且希望不断地来回跳转。我是否需要记得在每次切换之前存储我的工作副本文件,或者有更好的方法吗?

是的,在切换到另一个分支之前存储您的更改,然后弹出以前的存储,将是正常的工作流程。如果你经常切换分支,那确实很乏味,但是如果你从命令行使用Git,你可以定义aliases以便抽象出一些复杂性。

我自己从未使用过SourceTree,但我可以想象这种存储/检出/弹出是如何涉及大量繁琐的鼠标点击。不过,显然,SourceTree 引入了一种名为" Custom Actions"允许您定义自己的命令including Git commands。你可能想看一下......