如何让git merge处理我工作树中未提交的更改?

56

我和同事目前都在主分支上工作。我的工作树中有一些代码,我不想提交(例如调试语句等)。现在,如果他对这些相同的文件进行更改并提交,我将无法合并它们:

$ git merge origin/master
Updating 1b8c5c6..eb44c23
error: Entry 'blah.java' not uptodate. Cannot merge.

作为一名Subversion背景下的开发者,我习惯于在从代码库拉取更改时,我的工作树会被自动合并,如有冲突则需要手动解决。

我在Git中发现最快捷的方式是:

$ git stash
$ git merge origin/master
$ git stash pop

本质上是移除我的未提交更改,进行合并,然后重新应用更改。 我如何告诉合并命令自动将我的工作树与我正在尝试拉取的更改合并?


3
如果你遇到合并冲突怎么办?如果在被修改过的脏文件中出现合并冲突怎么办?请参考git维护者Junio C Hamano的博客《Fun with keeping local changes around》:http://gitster.livejournal.com/29060.html - Jakub Narębski
谢谢提供链接。虽然大部分情况下,我预计不会有冲突,或者只会有一些非常小的冲突,我也不介意手动修复。如果我提交我的脏文件,我仍然面临冲突的风险,只是之后我必须麻烦地将它们取消提交。 - Jeremy Huiskamp
相关问题:https://dev59.com/JWMl5IYBdhLWcg3wR1WD - leo9r
使用stash的问题在于MERGE_HEAD会被清除,这导致只有最后一次合并被记录。为了让合并修订版保留所有父级,您必须在运行git stash之前设置一个.git/MERGE_HEAD的副本。然后,在最终提交之前,您必须将所有的MERGE_HEAD组合在一起(每行一个SHA)。 - Keith Mason
在“合并”之前,你可能需要添加git fetch origin master - Walter Nissen
4个回答

45

忘掉你所了解的所有关于subversion的东西。

在引入外部更改之前,始终要进行提交。

想象一下,你有一个基本工作正常的代码库——也许不是完美的,但你正在取得一些进展。然后你去执行合并操作,而你要导入的代码会带来大量麻烦(自身存在错误或冲突过多等)。如果你可以撤销这个合并操作,那不是很好吗?

如果你提交了代码,你就可以轻易地撤销它。如果你没有提交,你将遭受苦难。

记住:你提交的内容不必是你推送的内容,但如果你不提交,你就很容易失去它。

安全和简单的方法就是尽早提交,并且经常提交。


2
所以我提交我的调试语句,然后合并。然后我进行一些真正想要推送的实际更改。现在,既然我想提交的内容依赖于那个提交,我该如何将我的调试语句删除? - Jeremy Huiskamp
1
我会考虑这个策略,当我们的代码变得足够复杂,以至于我必须担心撤销它时。然而,目前为止,我相信stash版本仍然是可逆的。我可以重新存储,删除合并提交,并在任何其他提交上再次弹出存储。我不介意忘记我对Subversion所学到的东西,但当它做得比Git好得多时,它就会爆炸,特别是当Git被认为是擅长合并的那一个时。 - Jeremy Huiskamp
5
你可以使用"rebase -i"来重新排序提交记录并将调试语句的添加移动到最后。 - araqnid
1
弹出后可以恢复暂存区。我认为将不完整和未经测试的代码提交到代码库中不是一个好主意。 - Casebash
调试提交应该与删除它们的提交合并。请参考squashed - MSalters
显示剩余2条评论

24
据我所知,你现有的 git stash 是最好的解决方案。我也觉得很奇怪为什么合并只想处理干净的树形结构。

3
我会把这个放在我的 .bashrc 文件中:gm() { git stash; git merge $@; git stash pop }然后等待看看它会以什么方式让我遇到麻烦。 - Jeremy Huiskamp
1
@jeremy:总有一天你会应用一个非常非常旧的存储库 :)。我也遇到过这种情况 :)。 - reto
@reto:这怎么会发生呢? - Casebash
10
Casabash: git stash pop如果无法应用而存在冲突,则不会删除stash。然后,过一段时间当您没有任何本地更改时,再次运行miniscript。Git stash是一个无操作,然后git merge,之后再次弹出旧的stash... - reto
你可以在git stash命令之前加上git stash clear语句,这样可以确保在应用之前stash是干净的。但首先你应该确保stash中没有有价值的东西。 - andyroschy
我的工作目录中没有任何更改。没有修改。我仍然无法合并到我的分支中。我不得不在命令提示符中执行 git stash。尽管它说“没有本地更改 - 没有需要存储的内容”,但出于某种原因,之后我现在能够执行 git merge。毫无意义。 - AlbatrossCafe

8
  • 如果本地工作尚未提交
    • 并且您引入了完全不存在于远程分支中的新文件:
    • 或者,受您本地工作影响的文件与您需要从远程拉取的更改所受影响的文件没有任何重叠:
      • 那么你很幸运:git pull将“正常工作”
    • 否则:
      • 如果您本地的更改与您正在拉取的更改没有重叠:
        • git stash会起作用:
          • git stash save
          • git pull
          • git stash pop
      • 如果您本地的更改与您正在拉取的更改有一些重叠:
        • git stash将需要手动解决冲突:
          • git stash save
          • git pull
          • git stash pop
          • 解决合并冲突
          • git reset
          • git stash drop
  • 如果本地工作已经提交
    • 并且受您本地工作影响的文件与受影响的文件没有任何重叠
      • 那么您很幸运:git pull将“正常工作”
      • 但是:git pull --rebase会“更好地工作”,因为具有更清晰的历史记录
      • 没有合并提交;您的更改将在上游更改之后提交
    • 否则:
      • git pull将需要手动解决冲突:
        • git pull
        • 解决合并冲突
        • 对于每个冲突的文件,git add FILE
        • git commit
      • git pull --rebase仍然可能“更好地工作”,因为具有更清晰的历史记录
        • 然而,解决合并冲突可能会更加困难

详细说明请参见:https://happygitwithr.com/pull-tricky.html


漂亮的结构化回答。 - 1valdis

2
您不能告诉git merge合并那些相对于您的本地存储库有更改的文件。这样可以保护您在合并失败时不会丢失更改。
使用CVS和SVN合并方法,如果您在更新之前没有手动复制文件并且它们在合并时被破坏,您必须手动重新编辑以恢复到良好状态。
如果您在进行合并之前提交更改或将其隐藏起来,那么一切都是可逆的。如果合并不成功,您可以尝试几种方法使其正常工作,并选择最好的一种。
如果您提交了实验性或调试更改,则可以使用git rebase将它们移动到通过git merge获得的提交后面,以便更容易地摆脱它们或避免意外将它们推送到存储库中。
请注意,在已共享的存储库上使用git rebase会给从该存储库拉取的所有人带来困难。
在这些情况下,我更喜欢使用git stash,但仅当合并更改我已经编辑但未提交的文件时才使用它。

你在说什么? SVN在合并之前备份你的文件。Git是版本控制中的C++。它以过度复杂和复杂为荣。 - JohnPristine
我猜我的SVN知识已经过时了。Git也在不断发展,变得越来越有用。昨天我刚看了一个关于Gitless的讲座,它可以操作git仓库,但当你有未提交的更改并想要合并或更改分支时,使用起来要容易得多。 - Jamey Hicks

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