人们在一起编码时出现的一种非常普遍的情况是必须使自己更新(例如,您正在处理的功能分支)。这可能导致同一文件的“冲突”在上游和您的工作树中均已更改。我的问题是,解决与Git冲突的最直接方法是什么。
具体来说,我正在寻找简明扼要的内容,并提供良好的可见性(即知道发生了什么,因为有时冲突超出了自动解决的范围,并且希望在合并之前知道这一点)。比这更好的东西:
# I'm on a branch, have changes in working tree,
# have overlapping change in remote; for simplicity,
# assume no local (unpushed) commits have been made (clean HEAD)
git fetch
git difftool origin/<branchName> HEAD # visually examine incoming changes, to understand them; conclude that the changes are automatically merge-able
#git merge # fails: "Your local changes to the following files would be overwritten by merge:"
#git merge -s resolve # fails: same
#git merge -s recursive # fails: same
#git mergetool # no-op: "No files need merging" ?!
git stash
git pull
git stash pop
git difftool HEAD # visually examine outcome - it worked, but does stashing really need to be involved?
其他答案涉及在获取后提交,这对我来说是一个不对,在此阶段我没有什么可提交的。我想要的是使自己(即我的工作树)与上游保持最新。
答案 0 :(得分:1)
我认为拒绝合并是一个坏主意:
首先,提交内容可以使您轻松恢复工作,如果在某个阶段甚至不对内容进行git add都是不可能的。 如果您需要重新制作补丁,可以对其进行修改,这是一种标准方法。
如果我很了解您,那么您的工作仍在进行中,因此您希望补丁在合并后会得到重新处理,因此,我建议您对补丁进行重新定位,如果它们当时很小:重新定位将指出最终的冲突如果您的补丁很小,则可能很容易修复。
如果您的分支很大,实际上会有很多冲突,那么我建议您在合并之前完成正在处理的补丁程序,以免您的历史记录中出现“草稿”补丁程序我需要将您的内容推送到通用git存储库中。
我个人使用选项1,即使我有很多补丁程序待处理。这使我可以在执行重新设置基准时重新验证每个补丁,还可以防止我不喜欢的“恶意合并”(使git怪罪痛苦,恕我直言)。
总而言之,我认为您应该重新考虑以下事实:您不想提交临时的东西。与隐藏相比,这提供了更多的安全性,并允许您以似乎已经知道的方式使用合并。
答案 1 :(得分:0)
如果您进行更改(即,工作树很脏),您就有东西要提交。最多,您想要临时
提交一些东西。在其他版本控制系统中,您可以通过在分支上提交来实现。在Git中,您也可以这样做:您没有拥有来使用分支,但这也可能是在Git中处理它的最方便的方法。
您提到一个开始的场景,对此我有一个工作模式我觉得有帮助:
人们在一起编码时出现的一个非常普遍的情况是必须使自己(例如,您正在处理的功能分支)保持最新。
假设您正在feature-X
上工作,最终将其放入dev
(开发分支)中。其他开发人员一直在研究功能Y和Z,其中一个功能已经完成,dev
现在已更新,因此您可以运行:
$ git fetch
,发现您的dev
现在位于origin/dev
之后。也就是说,您现在拥有:
...--C--D--H <-- master
\
\ I--J <-- origin/dev
\ /
E--F--G <-- dev, feature-X (HEAD)
在您的存储库中。您的工作树中还有一些内容与提交G
中的文件不同。 (您可能还没有名为feature-X
的分支,而是在HEAD
上附加了dev
。在这种情况下,您现在可以使用git checkout -b feature-X
来简单地创建它,现在您就可以匹配图片了。)
这时要做的是无论如何都要提交您正在处理的东西。这将进行一次新的提交K
:
...--C--D--H <-- master
\
\ I--J <-- origin/dev
\ /
E--F--G <-- dev
\
K feature-X (HEAD)
您现在可以将自己的dev
快进到origin/dev
。基本命令方法是:
$ git checkout dev # safe, since your work is committed
$ git merge --ff-only origin/dev # or `git pull` if you really insist
图形现在看起来像这样:
...--C--D--H <-- master
\
\
\
E--F--G--I--J <-- dev (HEAD), origin/dev
\
K <-- feature-X (HEAD)
大多数人都在这里运行git checkout feature-X; git rebase dev
,这很好,您应该随时使用该方法。 (我经常这样做。考虑这样做,然后再做下面介绍的git reset HEAD^
技巧。)但是我有时所做的只是将重命名 feature-X
改成{{1 }},然后使用feature-X.0
创建一个 new feature-X
:
git checkout -b feature-X
我现在准备再次开始从事...--C--D--H <-- master
\
\
\
E--F--G--I--J <-- dev, origin/dev, feature-X (HEAD)
\
K <-- feature-X.0
的工作,此时,我只是简单地挑选所有feature-X
的提交:
feature-X.0
产生提交$ git cherry-pick dev..feature-X.0
,它是K'
的副本:
K
即使...--C--D--H <-- master
\
\ K' <-- feature-X (HEAD)
\ /
E--F--G--I--J <-- dev, origin/dev
\
K <-- feature-X.0
上有多个提交,此操作也有效:
feature-X.0
如果此新...--C--D--H <-- master
\
\ K'-L' <-- feature-X (HEAD)
\ /
E--F--G--I--J <-- dev, origin/dev
\
K--L <-- feature-X.0
的最后一次提交(在此版本中为feature-X
,而只有一次提交的L'
,则是非常认真尚未准备好提交,此时,我只是使用K'
(如果更容易,可以将其拼写为git reset HEAD^
(在Windows上显然是这样))将分支名称移回一步。这将从当前分支中删除最末端的提交,给出:
HEAD~
并完全按照我开始整个过程之前的方式离开工作树。 (一般来说,部分提交是可以的,因为稍后...--C--D--H <-- master
\
\ K' <-- feature-X (HEAD)
\ /
E--F--G--I--J <-- dev, origin/dev
\
K--L <-- feature-X.0
准备就绪时,我将使用git rebase -i
清理所有内容。)
如果出于任何原因必须重复该过程,则将当前进行中的feature-X
重命名为feature-X
或feature-X.1
或其他名称。我种了一小堆feature-X.2
-es,偶尔去树枝花园修剪最杂草。 最新和最好的名称仍为feature-X
,但是我可以根据需要提供所有以前的工作,直到我将它们淘汰为止。或存储,因为如果代码很复杂并且我错过了某些东西,那么我仍然拥有较旧的版本,其名称可以识别,不仅是引用日志中一些难以理解的哈希ID,而且与其他存储也没有区别其他藏匿处。