我有两个分支,由于某些原因,它们的合并非常繁琐。有时候我想添加一个合并提交来表示我已经从一个分支到另一个分支获取了一些信息,例如我检查了一个文件。
由于使用git merge
会产生很多合并冲突,我唯一感兴趣的是创建一个包含两个父级的提交,编辑是否安全{{1}并提交?我的意思是,如果将来使用MERGE_HEAD
或git rebase
,我是否会面临奇怪的错误?
答案 0 :(得分:3)
我不会使用MERGE_HEAD
这样做,因为没有关于它将来如何继续发挥作用的承诺。
但是,您可以使用git commit-tree
构建任何您想要的任意历史记录,这是一个需要的管道命令:
结果是具有给定父项的提交对象。例如,给定一个部分看起来像树的树
o--o--o <-- br1
/
o--o--o--o <-- br2
\
o--o--o <-- br3
我们可以选择我们喜欢的任何两个,三个,四个或任意数量的提交哈希值,并进行新的合并提交。让我们选择最上面的中间提交和最下面的行最右边的提交。我们将使用br2
小费的树作为实际树:
$ hash=$(git commit-tree -m 'mystery merge' -p br1~1 -p br3 br2)
我们现在在$hash
中拥有此新合并提交的哈希ID。没有分支名称指向它,所以让我们创建一个新名称:
$ git branch br4 $hash
,并提供:
o--o--o <-- br1
/ \
o--o--o--o o <-- br4
\ /
o--o--o <-- br3
(分支br2
仍在那里指向中间的一个节点,我只是没有空间来绘制它。)
由于我们使用br2
作为树(快照)的来源进行保存,如果我们现在运行:
$ git diff br2 br4
我们什么都得不到:两个提交具有相同的树(但是不同的父哈希ID,当然br4
提示的提交消息是&#34;神秘合并&#34;)
这影响未来操作的方式是,当Git去计算新提交的合并基础或新提交的下游任何提交时,Git将遵循我们刚刚作为新提交的一部分做出的父链接。对于大多数的挑选操作而言,这几乎没有什么效果,因为挑选一个提交与其直接父级相反的提交。
请注意,当您进行正常的,普通的,每天合并时,Git正在做的是:
--ours
),另一次是您提到的提交,通常是另一个分支提示, R (偏远或右或--theirs
); git diffs
:git diff B L
,git diff B R
git write-tree
; git commit-tree
一样;最后如果你通过任何方式制作自己的树,Git认为这是合并这两个其他提交的完整而正确的结果。未来git merge
会看到此合并并使用它来通知它下一个合并的合并基础提交 B 应该是。如果我们回到上面的图纸,而不是创建 new 分支名称br4
,而是移动分支名称br3
以适应新的提交,我们得到:< / p>
o--o--o <-- br1
/ \
o--o--o--o \ <-- br2
\ \
o--o--o---o <-- br3
这意味着就Git而言,正确的结果是将左上角中间提交(br1~1
)合并到br3
的上一个提示中(现在{ {1}} - 这有点奇怪;请参阅下面的注释)是位于br3^2
尖端的源树。这意味着如果我们现在运行:
br2
在git merge br1
上时,Git将通过从br3
的提示向后移动来找到合并基础,以找到两个分支上的第一个提交。这是我们的br3
。从那时起有一个提交,即br1~1
的提示,因此我们将br1
与br1~1
区分开来(产生这两个提交之间的任何不同),作为&#34;什么&#39;自从合并基础&#34;以来,在br3中,然后将br3
与br1~1
区分为&#34;自合并基数&#34;以来,br1中的内容是什么?然后Git尝试像往常一样组合这些,然后在br1
上进行新的合并提交。
简而言之,您需要知道自己在做什么:您告诉Git使用您喜欢的任何树作为您构建的合并的正确结果,这会影响将来的合并。
注意:当我们进行合并时,我们选择br3
作为第一个父级和br1~1
(之前的值)作为第二个 。如果我们要合并这样的合并br3
,这是一个不寻常的顺序:它有点倒退。它实际上声明br3
是&#34;主线&#34;有人应该稍后关注。这没有什么根本的错误&#34;向后合并&#34; -the 树是我们选择的任何东西,无论哪个&#34;方向&#34;合并需要 - 但如果您计划稍后使用br1~1
查看此主要工作,则您会看到--first-parent
作为此br1~1
链接。
(--first-parent
命令也进行这些&#34;反转&#34;合并,有些人称之为foxtrot merge。当然它的合并使用的是正常的合并基础和合并过程,而不是一些任意选择的树。但这意味着git pull
所做的合并是#34;向后&#34;当试图跟随git pull
链接时,这是人们可能希望避免--first-parent
的另一个原因。)
答案 1 :(得分:1)
据我了解,你想从另一个分支“挑选”一些信息,是吗?例如:我在功能中更改了文件 foo , bar 和 baz ,并希望“合并” foo 进入主人而不需要 bar 和 baz 。我认为有更好的可能性,然后搞乱MERGE_HEAD
。
git cherry-pick
git cherry-pick --no-commit -x feature
git reset -p # Interactive reset similar to git add -p
Unstage foo? N
Unstage bar? Y
Unstage baz? Y
git commit
你最终会提交一个 foo 的提交,上面写着从...中挑选出来的消息然而,git reset -p
允许取消任何任何一块文件。您也可以从另一个分支中选择一行。
git checkout
git checkout feature -- path/to/foo
git commit
这将检查分支功能中可用版本中的foo。
在这种情况下,您必须编写自己的提交消息。但是您可以通过将以下内容添加到.git/config
文件中来为其创建git别名。
[alias]
pick-file = !git checkout $1 -- $2 && git commit -i --edit -m \"Picked $2 from $1\"
用法:git pick file branch file
git show
例如:
git show feature:path/to/file > file
然后,您可以使用git add
暂存整个文件,或git add -p
来决定您需要哪些行。同样,你必须在那之后提交。您还可以为此任务创建别名。