我正在尝试将使用git或TortoiseGit在我的存储库的主分支中进行的更改合并到开发分支中。我知道我可以使用git pull或merge,但这会在开发分支中同时合并太多更改,并且使解决冲突变得更加困难。
如果我使用的是SVN或TortoiseSVN,我可以一次一点地合并来自主干的更改,而不是一次性合并,使用一系列修订进行合并。我可以用git或TortoiseGit做类似的事情吗?也就是说,我可以将一系列修订合并到我的开发分支中,而不是立即合并所有更改吗?
答案 0 :(得分:6)
从命令行使用Git,您可以将feature
重新定位到master
:
git rebase master feature
# Now force push the changes to your remote
git push <remote> feature --force
警告: 如果您与其他人共享这些提交/分支,请不要随意强制推送(重写)提交/分支 ,因为你会因为旧版本的提交/分支所做的任何更改而导致冲突。可以在(非常)小团队中以这种方式工作,但需要良好的协调。
您还可以使用--onto
标记指定范围,其中<start commit>
是范围的独占开头:
git rebase --onto master <start commit> feature
最后,cherry-pick
实际上可以接受一系列参数。已签出master
分支:
# Cherry-pick all commits from `<start commit>`
# exclusive, not included) to feature:
git cherry-pick <start commit>..feature
我的最初目标是能够将feature
分支与master
中所做的更改同步,但我不想仅仅master
合并,因为它导致了太多必须立即解决的冲突。我只是希望能够逐步合并这些变化,因此我可以用更小,更易于管理的部分解决冲突。
git rebase
实现这一目标的最佳方式实际上是git rebase
。实际上,它是完美的。它会做的是以相同的顺序对我在feature
和 制作这些提交的 所做的所有提交,除了它 在目标分支的最新版本 之上重新发布它们,在我的情况下,它是master
。
这有两个重要原因:
这相当于将master
合并到feature
。为什么?因为feature
基本上是在master
的最新版本之上重新创建的...所有master
的提交现在都存在于feature
的历史记录中,包括master
中的提交{1}} feature
还没有。
Git按顺序重新提交 一次提交 ,所以如果有任何冲突,它们会被引入几个较小的进程中,更易于管理的作品,一次一个,这正是我希望做的!
这就是它在视觉上的样子(例子改编自official Linux Kernel Git documentation):
A---B---C feature
/
D---E---F---G master
在上面的示例中,提交F
和G
在master
上进行的操作,因为我将feature
分开。我想要做的是将这些更改同步到feature
:
git rebase master feature
现在我的分支看起来像这样:
A'--B'--C' feature
/
D---E---F---G master
\
A---B---C (no branch)
A
到C
之前的A'
已在C'
的最新版本之上通过master
重新创建{{1}}。旧的提交仍然存在于Git仓库中,但由于没有引用它们的分支指针,它们最终将被Git垃圾收集。
答案 1 :(得分:4)
是的,你可以这样做。假设您的存储库看起来像这样:
master
A---[B]
\
\ feature
(c1)---(c2)---(...)---(c100)
您想将feature
分支合并到master
,但那里有很多提交。相反,让我们创建一个新的分支tmp
,指向feature
之前的提交:
git branch tmp c2
A---[B]
\
\ tmp feature
(c1)---[(c2)]---(...)---(c100)
现在tmp
指向c2
。现在,我们只需将提交c1...c2
合并到master中,而不考虑c3...c100
:
git checkout master
git merge tmp
现在,将tmp
移至下一批提交(我们需要-f
到force
,因为tmp
已经存在)。例如,如果我们现在要转移到c6
,请使用:
git branch -f tmp c6
重复此操作,直到您想要合并的所有提交都在。
答案 2 :(得分:2)
注意:John的回答是正确的;这只是基于评论中后续问题的进一步解释 - 我只需要更多空间:)
我喜欢不必创建临时分支以在提交中合并的想法,但使用
git merge <commit-hash>
的问题是它只合并在一个修订版中,而不是它们的范围(正确吗?)。如果我有100个版本要合并,我不是必须100次使用该命令吗?
不,在Git中,历史始终是连通的。因此,如果将提交合并到master中,并且在master
的共同祖先和该提交之间进行更多提交,则会完全保留这些提交。与SVN不同,Git保留对先前提交的完全引用(具有无限数量的指针,因此您可以一次合并多个分支)。因此,最后,您将始终看到分支的起始位置,发生了什么,合并之间以及合并回主分支的位置 - 只有名称(或者更确切地说是标签 )不保留分支(除了在自动合并文本中,如果计算^^)。
所以你的历史就像这样:
* -- A -- * ---------- * ----- * -- * -- M [master]
\
\
B1 -- B2 -- B3 -- B4 -- B5 -- B6 -- B7 -- B8 -- B9 [br]
假设您要将B9
(分支br
上的HEAD提交)合并回M
master
分支指向的地方#
。通过直接合并,您将获得此(* -- A -- * ---------- * ----- * -- * -- M ---------------- # [master]
\ /
\ /
B1 -- B2 -- B3 -- B4 -- B5 -- B6 -- B7 -- B8 -- B9 [br]
是合并提交):
br
因此,即使删除了分支指针* -- A -- * -- * -- * -- * -- M -- #---------- # --------------- # --- # [master]
\ / / / /
\ / / / /
B1 -- B2 ------------ - B3 -- B4 -- B5 -- B6 -- B7 -- B8 -- B9 [br]
,您仍然可以看到在该单独分支上发生的所有提交。
或者,如果您想要在多个步骤中合并,您可以轻松地合并它:
{{1}}
同样,您可以随时回顾整个树,以及在分支上进行的所有单独提交 - 即使您删除了分支(再次删除指针)。
所以也许这个解释也会告诉你,你不一定需要在这么小的步骤中进行合并。在合并期间,您永远不会丢失信息,因为您始终可以回顾所有提交。