【问题标题】:git: how do I merge between branches while keeping some changesets exclusive to one branch?git:如何在分支之间合并,同时保留一个分支独有的一些变更集?
【发布时间】:2009-08-17 15:03:39
【问题描述】:

对于那些将绝对路径和数据库凭据硬编码到 Web 应用程序中的多个随机位置的人来说,这里有一个特殊的地方。可悲的是,在他们下地狱之前,他们正在地球上造成严重破坏。我们必须处理他们的代码。

我必须对此类 Web 应用程序之一进行一些小的更改。我创建了一个新分支features,并执行全局查找和替换以将路径和凭据更新到我的本地环境。我承诺。我还将其标记为local

我愉快地跳入了危险的黑客忏悔,经过一百个令人困惑的补丁后,我想将我的features 更改合并到master 分支,但我不希望local 提交被合并。

以后,我将在masterfeatures 之间来回合并,我希望local 留在features 中,并且永远不会出现在master 中。

理想情况下,我希望这一切都能神奇地发生,尽可能少用有趣的参数等等。

有没有我想念的简单明显的方法?

我可以想到几个,但它们都要求我记住我不想要那个提交。这绝对不是我的强项。尤其是对于这样被黑客入侵的程序。

如果做不到这一点,我对更复杂的手动方式来处理这种情况感兴趣。

【问题讨论】:

  • 是的,是的,是的。理想情况下,我应该重构愚蠢的应用程序。只要我得到报酬就去做。 (而且我可以想到其他一些这样的模式有意义的情况,即使在结构良好的应用程序中也是如此)
  • 在我的回答中添加了对您评论的回复。
  • 另一个选项:使用其中一个被子扩展(guilt、stacked git 等)并在队列中重命名一个补丁。我相信这些扩展不会让您将尚未集成回常规提交的补丁合并,因此您不会意外将其合并。仍然不理想,因为您需要记住弹出然后重新应用每次你有新的正常提交时都打补丁,但你解决了忘记你不想要那个提交的问题。

标签: git version-control branch dvcs merge


【解决方案1】:

我对这个问题的解决方案是使用变基而不是合并

从这样的提交树开始:

a-b-c <-- master
 \
  d <-- local
   \
    e-f-g <-- dev

$ git rebase --onto master local dev

       master 
       V 
   a-b-c-e'-f'-g' <-- dev
     \
      d <-- local

$ git checkout master

$ git 合并开发

               master 
               V 
   a-b-c-e'-f'-g' <-- dev
     \
      d <-- local

$ git rebase --onto master master local

               master 
               V 
   a-b-c-e'-f'-g' <-- dev
                \
                 d' <-- local

$ git branch -f dev local

               master 
               V 
   a-b-c-e'-f'-g'
                \
                 d' <-- local
                 ^
                 dev

【讨论】:

  • 好的。现在,一个很好的链接到一个解释所有这些魔法的地方怎么样? :) 我之前已经扫描了 git-scm.com/book,但是我没有理解你刚刚做了什么的基础。
【解决方案2】:

您可以使用 git cherry pick 仅合并您选择的补丁。只需将除本地提交以外的所有提交都挑选到主分支。

【讨论】:

  • 我喜欢这个答案,除了:如果您有 很多 项更改,您将如何做到这一点?是否有单行模式可以从一组中排除一个补丁?
  • 以此类推,Mercurial 移植扩展对此有一个标志:hg transplant -p local。 (您需要许多其他参数才能使其工作,但这是跳过给定变更集的原因。)
  • @quark:交互式变基可以做到这一点。 git checkout -b tmp features &amp;&amp; git rebase -i --onto dev dev tmp 会将您置于一个编辑器中,您可以在其中选择 devfeatures 之间的哪些提交以放置在从 dev 开始的新分支 tmp 上。您也可以将多个提交压缩为一个,如果您喜欢冒险,甚至可以重新排序提交。
【解决方案3】:

技术 (Git) 解决方案是使用 git attributes,使用属性合并。

merge

merge 属性会影响在git merge 期间需要文件级合并时如何合并文件的三个版本。

您将在 SO 问题“How do I tell git to always select my local version for conflicted merges on a specific file?”中找到使用此类属性的示例,以在合并到给定分支时强制保留某些文件的本地版本。

设置合并属性的问题是包含路径的文件可能包含我想要合并的其他更改代码

不要忘记,您可以通过git attributes 关联任何类型的脚本来管理这些合并。这包括一个脚本,能够将您想要的更改保留在本地,同时合并其余部分。编写这样一个“合并管理器”比较复杂,但它是一种实现临时自动化解决方案的方法。


技术含量较低的解决方案是将配置值配置文件分开:

  • 配置文件只包含要替换的名称
  • 配置值是几个文件(每个环境一个),每个文件都有实际值。

脚本用于将实际配置文件中的名称替换为给定环境所需的配置值文件之一的值。

【讨论】:

  • 设置合并属性的问题是包含路径的文件可能包含我想要合并的其他更改代码。所以更多的是关于那个变更集而不是整个文件。
  • 有趣的回应,但是,是的,看起来很麻烦。
【解决方案4】:

好的。这不能保证每次都能正常工作,但这样的事情可以工作(在这种情况下,你无论如何都会有一个必须解决的冲突更改):

  • 做你当地的分支机构
  • 仅进行本地更改
  • 继续开发

合并到主节点时:

  • rebase -i master 从您的分支中移动,并将仅限本地的更改移动到补丁链的 END
  • 解决进程中的任何冲突。如果仅本地更改位于配置文件中,并且您在常规开发中没有触及它们,那么您将没有问题。如果,否则,您确实有冲突,那么这是您在同一区域实际发生变化的情况,无论如何都需要您注意解决。
  • 签出大师
  • 合并你的本地分支 -1:

    git 合并本地^

这将使您在本地拥有除最后一项之外的所有更改。

如果您有多个 local=only 更改,我建议您在 rebase 期间将它们压缩在一起。

【讨论】:

    【解决方案5】:

    我会对 master 做一个交互式 rebase 并将你的 path-name-fixup-commit 移到最后。然后,您可以合并到该点。继续将您的特殊承诺移到最后。

    您可能还会发现存储库很有用。您可以将它们隐藏起来,而不是实际提交路径名修复。如果尝试这种方法,您可能需要查看How to reverse apply a stash 上的问题。

    【讨论】:

    • 是的,但这无助于我来回合并。我尝试使用 stash 一段时间,但它很快就变得无聊了。最好 rebase -i 提交。
    【解决方案6】:

    好吧,因为到目前为止还没有答案提供直接的解决方案,所以我假设我想做的事情是不可能的,并添加到一堆偶尔有用的解决方案中:

    如果你总是在features 分支上开发,那么你可以将features 合并到master,然后在master 中合并git revert local。 (其中local 是引用您为本地环境自定义路径等的提交的标签。)

    现在你绝不能将master 合并到features,因为这也会合并反向的local 提交。

    在这种情况下,master 变成了一个部署分支,只接收来自其他分支的合并。 (理想情况下,仅来自features 分支。)

    这很容易走下坡路,只需将另一个开发人员添加到工作流程中,事情就会变得非常混乱。仍然可以通过使用显式合并策略来解决,但这通常很痛苦。

    【讨论】:

    • 听起来真正的答案是修复代码。将硬编码路径提取到一个配置文件中,该文件可以被本地配置文件覆盖。跟踪默认配置文件,但不跟踪本地配置文件或类似的东西。
    • 是的,这通常是个好建议,但请在我的问题下查看我自己的评论。
    【解决方案7】:

    我不知道这是否可行,但是:

    1. 创建一个提交,给定配置文件的“主”版本,将它们转换为您在本地需要的版本。注意 SHA-1。我们称之为MAKE_LOCAL
    2. 根据您的本地配置文件版本,创建一个提交,将它们转换为适合 master 的版本。注意 SHA-1。我们称之为MAKE_REMOTE
    3. 使用 git 挂钩,当您提交时:
      1. git cherry-pick MAKE_REMOTE(或使用git diffpatch
      2. 允许开始提交
      3. git cherry-pick MAKE_LOCAL(或使用git diffpatch

    我认为以这种方式转换文件有更好的方法,但我不记得了(如果你能从 RubyConf 找到 shacon 的 git 演示文稿,并且可以浏览 800 张幻灯片,里面有一些很好的例子) .

    【讨论】:

      【解决方案8】:

      就个人而言,如果我不得不做这样的事情并且由于某种原因而无法在我进行时重构凭据,我会再添加两个分支,最终得到类似于以下的安排:

      master:你继承的原始代码

      localcred:从 master 分支,并添加一个补丁,将所有凭据更改为您在本地所需的内容。以后将此分支视为只读(并可能添加一个挂钩以防止意外提交)。

      feature: master 的分支,所有的修复都在这里(并且可能添加一个钩子以防止与 localcred 中的补丁合并)

      local:一个分支(不是标签!),它将作为localcred 的一个分支开始,然后在您需要运行单元测试时合并功能。所有测试都从这里进行,但这里没有开发。另外,这个分支是一次性的,因为你可能想在feature内部进行rebase,处理结果的最快方法是删除分支local,从localcred再次分支并合并feature在运行测试之前。这可能是我的工作流程中足够常见的操作,我会构建一个别名,只需几次击键就可以重复执行此操作,但我完全利用 Git 分支的可处置性,这让一些人感到害怕看着我,所以 YMMV。

      当您认为您的修复已准备好发布时,您对 feature 执行最终变基以清理历史记录,转储并重新创建 local 以进行最终测试,将 feature 合并到 master,然后一次这已被上游接受,将 master 合并到 localcred 并将您的凭据补丁重新设置到顶部,然后转储并重新创建 localfeature 并重新开始游戏。

      如果您想快速测试大量微小的代码变体,而无需每次都提交和合并,请查看 local,进行更改直到您满意为止,提交并立即从 @987654339 中挑选@ 到 feature,然后删除并重新创建本地。

      这能满足您的需求吗?

      【讨论】:

        【解决方案9】:

        这个问题是一个老问题,但我仍然没有找到一个好的答案。目前我面临同样的问题,下面是我的解决方法:

        我的本​​地仓库中有两个分支:masterlocal_settings。 从master 切断local_settings 分支后,我在那里提交了所有本地路径,没有标记也没有试图记住它们。 在本地开发期间,我切换到local_settings 分支,因此我可以使用本地路径运行应用程序。但是到了提交的时候,我会存储一个当前状态并切换到master 分支。然后我弹出隐藏的变更集并将其提交到master。最后一步是切换回local_settings,从master合并并继续开发。 回顾一下:我只提交到local_settings 分支的更改将保留在本地并且永远不会进入master;并且没有从 local_settings 合并到 master

        现在假设我需要向之前添加了本地路径的文件添加“良好”修改,但在 master 分支中需要“良好”修改。 当工作副本是local_settings 的负责人时,我会进行更改,将其隐藏并查看master。尽管我已经在master 上,但存储库保留了一个相对于local_settings 的变更集。 git stash pop 将隐藏的变更集应用于工作副本并最终具有相对于 master 的差异,但仅限于最近的修改,不包括先前添加的本地路径,并且不是最近隐藏的变更集的一部分。因此,它可以在master 分支中提交而不会弄乱路径。然后再次从master 合并到local_settings

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-22
          • 2022-01-05
          • 1970-01-01
          • 2022-08-17
          • 2023-02-11
          • 2010-12-15
          相关资源
          最近更新 更多