查看图片。我有一个master
分支。在提交A
时,我从中分支dev
分支。在B
点,我与dev
同步了master
,创建了M1
。在C
点,我们的团队从中分支release
分支。将来,我需要将dev
合并回release
。
不幸的是,我意外地将D
的提交master
合并到我的dev
分支,创建了M2
。现在我无法将dev
合并到release
,因为它包含属于C..D
的提交master
,不应转到release
。
我的开发还没有结束,我现在不打算将dev
合并到release
。但是,我希望保持同步并将release
合并到我的dev
分支。在完成开发并将dev
合并到release
之前,我希望此类合并将在未来多次发生。
因此,在某些时候我需要从M2
恢复dev
。我希望尽早完成,因为release
的提交可能会与M2
中的更改冲突。请记住,release
中不存在其中一些更改。
由于我想尽早恢复M2
,我希望在从release
合并到dev
之前执行此操作。这就是问题实际开始的地方。感谢您阅读这一点:)
我可以在M2
中恢复dev
,这不是问题。但是,在此之后,当我将release
合并到dev
时,git将合并库计算为C
。虽然我希望合并基数为B
,但假装合并M2
根本就没有发生过。由于这个不正确的基础,合并实际上会自动丢弃更改B..C
。 Git认为,我手动删除了它们,因为这是他在恢复提交M2
时看到的内容!
让我澄清一下。想象一下有人在foo.txt
中创建了文件C
。此文件将dev
添加到M2
。在我恢复dev
后,它将从M2
移除。当我将release
合并到dev
时,git会在foo.txt
中看到release
,它会在基本提交foo.txt
中看到C
,但它看不到foo.txt
中的dev
。因此git认为我删除了foo.txt
。但我没有这样做。
如果我将B
指定为合并库,则没有问题。有没有办法在git中做到这一点?
由于我发现无法覆盖合并库,我做了一点点黑客攻击。我在这里发布是因为我有另一个相关的问题。
见第二张图片。我从tmp
开始了新的本地分支E
,在M2
之前提交。除了dev
之外,我对M2
的所有更改都选择了这个分支。我将release
合并到tmp
,并将结果M3
仅与tmp
中的一位父项合并(请注意图片上的虚线)。
我在M2
中还原dev
,提交G
。我创建了从release
到dev
的“假”合并。此提交不包含任何更改,但有两个父级:来自dev
和release
。然后,我将M3
挑选到dev
并用空虚假合并压扁它。因此,我创建了M4
,正确的更改和正确的父母。
问题是:我真的需要这种“假”合并吗?也许有办法挑选M3
到dev
并让它有两个父母?
我将在这里总结一些问题:
如果您能够阅读本文,请感谢您!
我在讨论后意识到,我的解决方案(或所述问题的任何其他解决方案)都存在严重缺陷。正如我所说,在某些时候我会将dev
合并到release
。正如我没有说过的那样,在此之后的某个时刻我们会将release
合并到master
。在这一点上,我们将面临完全相同的问题。此合并的基础将解析为D
,而不是C
。这将导致类似的问题,但规模要大得多。
因此,此问题的最佳解决方案是继续tmp
中的开发,并将其设为新dev
,从历史记录中有效排除错误合并M2
。
答案 0 :(得分:1)
我很确定你的底线问题的简短答案是否定的:
git reset
这是可能的,尽管这是一种解决方法。你git reset <wanted base>
。您当前提交和新基础之间的所有更改都在工作区中未提交,因此您可以进行所需的新提交(尽管您丢失了一些您可能想要的树信息)。在任何情况下,您都可以围绕M1进行dev
分支以摆脱它:
git checkout dev
git rebase -i <commit prior to M1 or even to A>
-i
将允许删除合并提交。
修改强>
你的变通方法在dev
中的最终提交可能看起来像你想要的,但你必须记住在git中,如果下面有一行连接到你,那么这些提交也是你的一部分。您所做的是精心重新定义以删除M2
,因此在任何父级中都不会考虑提交C..D。
如果你可以告诉git只是将基于B的dev
合并到release
,那么以下我认为可以很好地估计会发生什么:
如果层次结构中存在M2,则无法绕过C..D。但是,你可以通过还原或重新定位来跳过它,或者做那个疯狂的分支绕过你做的。
答案 1 :(得分:1)
简短的回答是“不,你不能选择自己的合并基础”,你的临时分支方法是正确的。现在让我们来看第二个问题:
有没有办法为提交手动指定父项?
这里的答案是响亮的是,但你必须使用Git的“管道工具”来完成它,特别是git commit-tree
。
当git commit
创建新提交时,它会执行以下操作(当然,在收集提交消息之后等等):
git write-tree
。这将打印出新树的哈希ID。git commit-tree args
(见下文)。这会打印出新提交的哈希ID。git update-ref -m "commit: subject" HEAD commit-hash
。步骤2是我们可以选择父母进行提交的地方。 commit-tree命令接受一个必需参数,即树ID(由步骤1生成),以及每个父ID设置一个-p
参数。每个-p
都采用提交父指定符。这可以是原始哈希,也可以是gitrevisions
可接受的任何内容。实际上,树ID也可以这种方式编写,如果您只想使用相同的源树创建一个 new 提交,这很方便。
因此,假设您在分支X
下有一个当前源树,指向提交 CX 。您现在希望将X合并到分支dest
中,但是您希望合并的行为就像 CX 的父提交是提交 P 一样,以便git将使用git merge-base --all P dest
找到合并基础。 (如果您已经知道所需的合并基础 B ,则只需选择 P = B 。)
我们需要的是一个提交,其树与 CX 相同,但其(单个)父级是 P 。这个提交甚至根本不必在任何分支上,它只需要存在于存储库中。如果您希望它在分支上,请使用配方中的git branch
:
X=dev # name of desired branch
P=<hash ID for commit P>
git show $P # just to check
cat > /tmp/msg << END
temp commit of $X's tree from $(git rev-parse $X)
This is a special commit made with parent $P
just for doing a merge.
END
newcommit=$(git commit-tree -p $P $X^{tree}) < /tmp/msg
# git branch tmp $newcommit # save newcommit as new branch
git checkout dest
git merge $newcommit # or git merge tmp
(以上都是未经测试的)。
在这里使用$X^{tree}
,不需要做很多复杂的挑选。当然,如果你需要省略特定的提交来构建一个新的(不同的)树,你真的需要一个临时分支并做一些挑选。
答案 2 :(得分:0)
我认为您可以在分支dev
中执行D
并从中移除M2
和$ git checkout dev
$ git rebase -i <commit-sha-of-E>
。
D
将出现一个新窗口。现在只需删除M2
和$ git rebase --continue # finish your rebase.
的提交行,然后保存并退出。
var xdoc = XDocument.Load(theXmlURLpath);
var testElements = xdoc.Root.Element("tests").Elements("test");
foreach (var testElement in testElements)
{
var lang = testElement.Attribute("language").Value; // en / it / hu / es
var text = testElement.Value; // hello or ciao ...
switch (lang)
{
case "nl":
// do something
break;
case "d":
// do something
break;
case "gb":
// do something
break;
case "fr":
// do something
break;
case "esp":
// do something
break;
case "it":
// do something
break;
}
}