在本地更改时,是使用git stash save还是git commit?

27

我更改了代码库中的一些文件,但不想将它们推送到公共仓库或创建任何临时分支来存储它们。我只是想将这些更改保存在某个地方。那么,哪个命令更好:

git stash save "save message" 
或者
git commit -am "save message"
如果我使用git commit,是不是所有的本地提交都会在一个git push命令中公开推送?如果我只想推送其中一个特定的提交,该怎么办?

如果我使用git commit命令,是否所有我的本地提交都会在执行git push命令后公开推送?如果我只想推送其中一个特定的提交,该如何操作?


11
为什么不使用临时分支?如果你使用 commit,你要么会创建一个没有 HEAD 的提交,要么会使用当前的 HEAD 并将其移动。我会使用一个分支,但不公开它。 - Gauthier
1
我不想创建任何分支的原因是,当我最终决定公开这些更改后,所有在这个“实验性”分支中的提交历史都将随之推送,包括我为了保存一些实验性更改而进行的一些零碎提交,但“不确定它们是否正确”。 - Balthier
4个回答

21

当进行推送时,你总是推送一个具体的提交(通常是当前检出分支顶部的提交)。然而,由于提交哈希的一部分是它所基于的提交(父提交),因此你必须推送所有父级提交。通过推送父提交,你还必须推送它们的父级提交等等。因此,你只能推送特定提交的整个历史记录。

如果你创建了一个提交只是为了存储某些内容但不需要推送,你需要确保你永远不会推送该提交或任何基于该提交的提交。要做到这一点,在完成基于临时提交的工作之后,你需要将临时提交压缩到新创建的提交中,以便推送它。

换句话说,是的,可以将提交用于临时私有存储。然而,使用 stash 功能会更容易。事实上,该功能就是为此特定用例而制作的。


我对在这种情况下使用git不是很了解。这是否意味着,如果我为更改的作品做出提交SHA1,然后检出回原始作品,然后执行git pull以从git获取新提交,我的SHA1会进入其他新分支或仅仅消失? - Balthier
在这种情况下,您的历史记录不再是线性的。您有两个基于相同父提交的提交。一个是更改工作的提交,另一个是您获取的提交。您可以将提交合并在一起。您也可以只在更改工作提交上工作,并将结果重新基于获取的内容。这不会引入任何危险,因为您尚未推送更改的工作提交。 - functionpointer
我猜重命名对于本地提交来说还好,因为它不像对于公共提交那样危险 :) - Balthier
@Oznerol256:跟我的工作流程非常相似。如果Git在提交中保留了一个“已发布”标记,这样就像是Mercurial的“状态”,以使变基更安全,那就太好了。这可以通过类似于“注释”的机制来实现。 - torek
@torek,实际上,git可以做到这一点。只需使用origin/<branch>即可。当然,获取将更改远程跟踪分支,但是如果您查看历史记录,可以轻松地找到您最新推送的提交(只需查看获取提交的作者字段)。 - functionpointer
显示剩余2条评论

5

个人而言,我更喜欢直接使用私有(本地)分支,但是stash也很好用。关于stash,有两件事需要注意:

  • 它们是独立的提交。除了标签之外,"stash"提交和与分支或标签标签相关联的提交没有基本区别。(标签标签的格式为refs/tags/tag-foo;分支的格式为refs/heads/branch-foo;单个带标签的stash提交被标记为refs/stash。当然,分支标签也有"添加提交时自动移动"功能,但如果你不再添加更多提交,则它们永远不会移动,因此它们可以像保存单个提交一样正常工作。)
  • 使用reflogs实现了stash "stack"1。默认情况下,引用日志可能会过期(在30或90天后),refs/stash中的引用日志则不会,但你可以通过配置项进行更改,因此堆叠的stash提交也可以"过期"(与reflog条目过期时间相同)。 (更精确地说,它们将"可收集",但如果它们消失了,这种区别就没有什么帮助了 :-)。)

使用stash的意图是保存一些短期的东西。如果你曾经回来看过一个仓库,发现有一堆被命名为"WIP on branch"的stash提交,那就很麻烦了。

其他stash提供的功能/缺陷包括:

  • git stash branch允许你在事后改变主意,并将stash变成分支。 因此,如果"短期"变成了问题(你本来想今天下午修复它,但现在至少推迟了一个月),你可以在所有操作完成之后将stash转换为分支。
  • git stash apply [--index]将尽力在当前分支中"重新创建"已应用的更改。使用--index它将尝试独立恢复已暂存和未暂存的更改。(但是有些情况下这是不可能的。)
  • git stash pop会自动为你放弃stash引用。 不幸的是,即使你打算使用git stash pop --index并忘记了--index部分,它也会这样做。 如果你使用apply,并且稍后在确保一切都按你想要的方式返回后再使用drop,你可以避免这个问题。
请注意,git stash branch命令会自动应用--index选项:新创建的分支将还原已暂存和未暂存的更改,就像你执行git stash时一样。 (该分支也将从你执行git stash时所在的提交分支分离出来。)提交更改(根据需要添加更多内容,或作为两个单独的提交等),然后继续,就像你一开始创建了一个私有分支一样。
1堆栈中可过期的部分包括除stash@{0}之外的所有存储在git stash list输出中的隐藏内容。

所以git stash确实会过期,我担心不能永久保存我的更改。此外,git stash branch <branchname>会创建一个新的私有分支,这是我保存本地工作的最终选择。谢谢。我想我应该修改问题,使用git stash、git commit或git branch。 - Balthier

3
我有点不同的做法。对我来说,stash更适合用于快速保存,而不是日常工作,因为它们不能(轻松)地将实际可存储的内容分解为更小的部分。(例如,如果我有20个已更改的文件,并且我想创建两个包含10个文件的stash,则这并不容易。)
这就是为什么我希望我的日常更改只提交到一个实际的、虽然是临时的分支中,以便我可以随时添加我的工作注释等信息。每日检查、实验等基本上是我不想要推送到最终repo的东西。
当我准备好提交回主repo时,我在最初分支的提交上使用“soft reset”命令。这将把我所有的临时分支提交的更改作为当前更改放回到那个原始提交上,而不保留任何我的日常工作历史记录。
然后我为这些“新”的更改创建一个新分支,我可以一次性提交它们,或者如果有意义的话,我可以将其分成几个提交(例如,一个提交后端内容,另一个提交前端内容,另一个提交资源等)。
完成后,我会得到一个漂亮的、新的、干净的分支,其中的历史记录对其他开发人员有意义,没有我的日常注释,并准备合并和推回到主repo中。然后我可以删除我的临时分支并继续下一个任务。
所以,总结一下...
1.创建一个工作分支
2.根据需要进行多次提交/子分支
3.当你准备好合并回去而不保留历史记录时,git-reset回到你分支的原始提交。现在你所有的更改都是本地更改。
4.根据需要重新提交和合并
另一个好处是我实际上可以将临时分支推送到远程repo,这样我就可以从多个位置工作,而stash无法做到这一点。只需记住完成后,清理服务器上的内容,以保持repo浏览的干净。(有人可能会争辩说,技术上提交仍然存在,只是分离了,这是正确的,但GIT中的分支是轻量级的,在某种程度上,它成为了另一种不失去工作的安全网,因为如果真的有必要,你可以找回一个分离的提交。)

1

我建议你使用存储工具。这就是它存在的原因。您可以将更改存储起来,稍后再将其添加到代码中。您可以使用许多其他功能与git stash一起使用。这里是链接http://git-scm.com/book/en/Git-Tools-Stashing

我建议您阅读git文档here。也要了解该工具。之后,您肯定会成为git大师。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接