【问题标题】:.gitattributes & individual merge strategy for a file.gitattributes 和文件的个人合并策略
【发布时间】:2018-01-30 00:08:45
【问题描述】:

我的(网络)应用程序有一个主分支和一个测试分支。这些项目几乎相同,除了一个设置应用程序的文件,比如“setup”。

每当我将一个分支合并到另一个分支时,我希望该分支保留其设置版本。也就是说,git 不应该尝试合并对该文件的更改。

我按照guidance from the Pro Git book 创建了一个 .gitattributes 文件,其中包含“setup merge=ours”行。但是,这不起作用 - 如果我引入冲突,也不会使用快进合并。

(准确地说:

$: mkdir gitest
$: cd gittest
$: git init
$: echo "setup merge=ours" >> .gitattributes 
$: echo "master" >> setup
$: git add setup .gitattributes
$: git commit -a -m ...
$: git branch test
$: git checkout test
$: echo "test" >> setup
$: git commit -a -m ...
$: git checkout master
$: git merge test

预期结果:setup 包含单词“master”,而 git 执行 ff 合并并且 setup 是“test”。)

【问题讨论】:

  • 我查看了 git 源代码,但看不到 merge=ours 是如何工作的。我想有人没有尝试就写了。另一个答案提供了一个更复杂的解决方案,但它实际上似乎有效。
  • 这似乎确实有效!谢谢 Karl。作为对那个答案的轻微修改:简单地将“exit 0”作为合并驱动程序比专门的 bash 脚本更容易做到这一点。

标签: git


【解决方案1】:

我遇到了同样的错误,只需在 .git/config 中定义一个“我们的”合并驱动程序即可解决:

[merge "ours"]
    name = "Keep ours merge"
    driver = true

因为 true 总是返回 0,所以保存当前状态的临时文件不会改变,并且会保持为最终版本。

您可以在此处阅读有关合并驱动程序的更多信息:http://www.kernel.org/pub/software/scm/git/docs/gitattributes.html#_defining_a_custom_merge_driver

附录:

这在实际调用驱动程序的任何时候都有效,并且这似乎仅在提交更改相同文件时才会发生(git 合并属性)。如果单个分支发生更改,则不会调用驱动程序。

【讨论】:

  • @VitalyB 我尝试了几种方法,但只有在两个分支都发生变化时才有效。至少有一次冲突,然后调用合并策略。从那时起,对于所有冲突和更改(包括 ff-able 的),将调用合并策略并且预期的文件不受影响。请参阅下面凯文的回答
  • 至少发生一次冲突并不能保证将来总是会调用合并策略。可悲的是,我的经验告诉我并非如此。
  • 您的附录是正确的。合并“我们的”不会保护文件免受更改。然而,它确实保护了更改免受更改。考虑到 A->B->B',合并 B'->A 只会使 A==B' 即使合并“我们的”已经到位,因为 A 没有变化,而 B' 有变化,而 A 是直接祖先B',它被认为是“我们的”。但是,如果也是 A->A',则合并 B'->A' 将不适用于任何受合并“我们的”保护且在 A' 中更改的文件。
【解决方案2】:

我发现如果我修改了两个分支上的文件并将修改提交到每个分支,然后尝试合并,它将调用合并驱动程序并监听我的.gitattributes,它指定了merge=ours。在此之后,两个文件在两个分支上总是不同的,所以合并驱动程序总是会被调用,所以我不需要一个自定义的合并驱动程序来接触文件。最初只需要对两者进行修改。

【讨论】:

  • 您在过去一年中遇到过这种技术的任何问题吗?我还发现没有必要按照 Jorge 的建议对“我们的”策略进行自定义重新定义。但我想知道当你不看的时候,是否有什么东西会回来咬你。
  • 我没有注意到任何问题,然后我再次将它用于非常简单的目的,即在版本控制中保留一些单独的文件(如 Gemfile.lock 和 .bundle/config)但不同在不同开发者的分支上。不知道它有多洁净,但我发现它很方便。
  • Kevin,我的用例类似。我所有的 Android 调试代码都依赖于 public static boolean DEBUG_ON。能够在我的生产分支中将其保留为false,在我的开发分支中保留为true,这让生活(和GIT 日志)变得更加简单。所以感谢你指出我正确的方向。出于兴趣,这是我发表的帖子,其中引用了您的答案:git smudge/clean filter between branches
  • 一天后,我的文件不再单独保存。 Git 决定现在跨分支合并更改。尽管 2 个文件在分支中有所不同,但似乎不再调用合并驱动程序。可惜……
  • 我认为这是因为 git 处理的是对文件的更改,而不是文件本身。举个例子:假设你有一个分支。现在您创建一个“测试”分支,并在每个指定您的“config.php merge=ours”的文件中添加 .gitattributes 文件(当然要确保设置了git config merge.ours.driver=true)。现在让我们说在创建新分支之后,您对 config.php 进行了一些更改“test”,然后签出“master”并将“test”合并回它。会发生的是,“test”对 config.php 进行了更改,但 master 没有,因此没有“我们的”,因为“我们”没有任何更改!
【解决方案3】:

仅在非平凡的情况下调用合并驱动程序,即如果 master 和 test 都已触及 setup(并且您需要先定义合并驱动程序 ours):

git init
git config merge.ours.name '"always keep ours" merge driver'
git config merge.ours.driver 'touch %A'
echo "setup merge=ours" >> .gitattributes 
echo "master" >> setup
git add setup .gitattributes
git commit -a -m ...
git branch test
git checkout test
echo "test" >> setup
git commit -a -m ...
git checkout master
echo "more content" >> setup
git commit -a -m ...
git merge test

话虽如此,我想知道在存储库中进行设置是否明智。如果你真的希望它受到版本控制,你可以使用子模块或子树合并策略来保持公共文件同步。

【讨论】:

    【解决方案4】:

    有一个涂抹干净的脚本,而不是单独的分支。根据您使用的机器,脚本可能会有所不同。

    【讨论】:

    • 虽然您确实可以使用 smudge 和 clean git 关键字扩展过滤器,因为它们是由每个分支的 .gitattributes 文件定义的,如果您正在跟踪您的 .gitattributes 文件,那么您需要在 .gitattributes 上使用 merge=ours 来定义在每个分支上使用哪些不同的过滤器。您所描述的听起来像是单分支设置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 2012-07-05
    • 2010-12-04
    • 2022-07-13
    • 2015-03-24
    相关资源
    最近更新 更多