【问题标题】:How to merge submodules and always keep "ours"?如何合并子模块并始终保留“我们的”?
【发布时间】:2019-09-19 08:18:08
【问题描述】:

我有一个带有第二个 repo 作为子模块的 git repo。两个 repos 都有针对通常直接对应的各种功能的相应分支,例如如果父 repo 在分支 A,子模块也将在分支 A。

在父模块和子模块 repos 中,随着时间的推移会添加更多分支,有时我会将旧分支合并到以后的分支中,例如在两个 repos 中定期将分支 A 合并到分支 B,而分支 B 也会获得不在 A 中的新提交。

当我在 A 子模块更新后将分支 A 合并到 B 的父仓库时,问题就出现了。我想忽略这些更新(即,我总是想在合并期间丢弃子模块更新,否则父分支 B 可能最终得到子模块分支 A,这是错误的)。

我找到了一些instructions 来了解如何在合并文件 时始终使用“我们的”,但它似乎对子模块无效。以下是使用子模块重现问题的方法:

# first command will update your ~/.gitconfig, you may want to undo it later
git config --global merge.ours.driver true

mkdir -p tmp/sub
cd tmp
git init
git commit --allow-empty -m "chore: Initial commit"
echo 'sub merge=ours' >> .gitattributes
git add .gitattributes
git commit -m 'chore: Preserve sub during merges'

mkdir sub
pushd sub
git init
git commit --allow-empty -m "sub: init"
popd
git submodule add ./sub
git commit -m 'add submodule'

git checkout -b demo-prod
pushd sub
echo prod > readme
git add readme
git commit -m 'add prod readme'
popd
git commit sub -m 'sub: add prod readme'

git checkout -
git submodule update
pushd sub
echo master > log
git add log
git commit -m 'add master log'
popd
git commit sub -m 'sub: add master log'

git checkout demo-prod
git merge -

预期结果是自动合并,但实际结果是合并冲突,因为“sub”在父 repo 的两个分支中都有新的提交。

在这种情况下如何实现轻松合并?

【问题讨论】:

    标签: git merge git-submodules


    【解决方案1】:

    t7405-submodule-merge.sh 中测试了与子模块的合并,它始终包含一个merge -s ours,它应该可以满足您的需求。
    (测试添加于commit f37ae35,2009 年 4 月,Git v1.6.2.4)

    子模块 was discussed in Nov. 2017 的实际合并,用于 this patch,在 commit 6c8647d,2018 年 1 月,v2.17.0-rc0,但你不应该在这里需要它。

    使用merge strategy "-s ours" 可能太多了(因为它会忽略来自另一个分支的所有 提交),但合并递归策略选项可能会有所帮助:git merge -X ours

    【讨论】:

    • merge -s ours 避免了冲突,但正如您所说,它太多了,因为它实际上并没有合并任何其他更改。我只想要子模块的“我们的”。我按照您的建议尝试了git merge -X ours,但这似乎没有效果(即它会产生与常规合并相同的冲突)。我不确定您对 -X ours 的期望究竟是什么,但它似乎并没有改变任何东西。
    • 任何想法如何让-X ours 为子模块工作?令人惊讶的是,这只适用于文件,而不适用于子模块......我什至可以使用-s theirs,但这不存在,只有-s ours,这不是我想要的。而且我不能只 reset 到另一个分支,因为我缺乏强制推送权限来摆弄历史。
    • @SvenS 不确定。我怀疑这种合并需要在子模块本身内应用。
    • 感谢您抽出宝贵时间回复;)不知道该怎么做,也许将子模块指针设置为“他们的”中的那个,并在合并之前提交它,以便在那里不会有任何冲突。只需要找出要设置的哈希值,这不是一个通用的解决方案。同时我有一个解决方法:切换到master,使用-X ours与我的分支合并,然后切换回我的分支并快速合并到master。之后将 master 重置为之前的 HEAD。很好地复制了 -X theirs 行为,尽管可能合并消息是错误的......
    • @SvenS 该解决方法可能会被编写脚本以在最后设置正确的合并消息。我会监控你的赏金(stackoverflow.com/q/30994172/6309),看看是否有人提出了实际的解决方案。
    【解决方案2】:

    当我在 A 子模块更新后将分支 A 合并到 B 的父仓库时,问题就出现了。我想忽略 [任何分支-A 子模块] 更新(即,我总是想在合并期间丢弃子模块更新,否则父分支 B 可能以错误的子模块分支 A 结束)。

    当您合并时,如果在另一个分支中更改了路径并且在本地分支中根本没有触及,Git 认为没有冲突的机会,因此它“微不足道”地采用另一个分支版本。到目前为止,Git 甚至没有将其视为自动合并,它根本没有为它运行任何合并驱动程序,据我所知,没有什么可以关闭,你无法停止它,...

    ……这可能看起来像是一个“无法完成”的平面,但这是 Git。 Git 自动执行的任何操作,如果您愿意,您可以在之后轻松修复。在提交之前运行合并--no-commitgit checkout @ path/to/submodule,或者如果你忘记了执行git checkout @~ path/to/submodulegit commit --amend。许多自定义工作流程可以通过配置设置或挂钩实现自动化,但我认为这个很奇怪,如果你想要自动化,你将不得不编写脚本。

    【讨论】:

    • 我不担心“无冲突”的情况,因为总是有冲突。发生这种情况是因为 B 的子模块以永远不会在 A 中更新的方式进行更新,因此无论 A 中发生的任何更新都将始终与 B 中的现有更新冲突。Git 确实每次都检测到冲突,我只需要知道如何告诉它在检测到它们时该怎么做。
    • 好吧,同样的事情,那么,只是在提交之前git checkout @ path/to/submodule,冲突的效果实际上与--no-commit相同。
    猜你喜欢
    • 1970-01-01
    • 2012-06-07
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多