【问题标题】:How to merge specific files from Git branches如何从 Git 分支合并特定文件
【发布时间】:2023-04-10 09:45:02
【问题描述】:

我有 2 个 git 分支 branch1 和 branch2,我想将 branch2 中的 file.py 合并到 branch1 中的 file.py 中,并且只有那个文件。

本质上,我只想处理 branch1 中的 file.py,但想利用合并命令。最好的方法是什么?

【问题讨论】:

标签: git git-merge


【解决方案1】:

在他们自己的提交中对branch2 中的file.py 的所有修改是否与对其他文件的修改分开?如果是这样,您可以简单地cherry-pick 更改:

git checkout branch1
git cherry-pick <commit-with-changes-to-file.py>

否则,merge 不会对单个路径进行操作...您不妨创建一个 git diff 补丁,将 file.pybranch2git apply 更改为 branch1

git checkout branch2
git diff <base-commit-before-changes-to-file.py> -- file.py > my.patch
git checkout branch1
git apply my.patch

【讨论】:

    【解决方案2】:

    虽然本身不​​是合并,但有时需要另一个分支上另一个文件的全部内容。 Jason Rudolph 的blog post 提供了一种将文件从一个分支复制到另一个分支的简单方法。应用如下技术:

    $ git checkout branch1 # ensure in branch1 is checked out and active
    $ git checkout branch2 file.py
    

    现在file.py 现在在branch1

    【讨论】:

    • 简单,但这实际上不是 merge。它只是用分支 2 中的任何内容覆盖 file.py
    • 如果将文件从branch1 合并回branch2 会怎样?你会发生冲突!
    • 这会保留提交历史吗?
    【解决方案3】:

    要仅合并来自 branch2 的 file.py 的更改,请取消其他更改。

    git checkout -B wip branch2
    git read-tree branch1
    git checkout branch2 file.py
    git commit -m'merging only file.py history from branch2 into branch1'
    git checkout branch1
    git merge wip
    

    Merge 甚至不会查看任何其他文件。如果树足够不同,您可能需要“-f”结帐。

    请注意,这将使分支 1 看起来好像分支 2 的历史记录中的所有内容都已合并,这可能不是您想要的。上面第一次结帐的更好版本可能是

    git checkout -B wip `git merge-base branch1 branch2`
    

    在这种情况下,提交消息可能也应该是

    git commit -m"merging only $(git rev-parse branch2):file.py into branch1"
    

    【讨论】:

      【解决方案4】:

      branch2file.py 中的内容不再适用于 branch1 时,需要选择一些更改并保留其他更改。要完全控制,请使用--patch 开关进行交互式合并:

      $ git checkout --patch branch2 file.py
      

      git-add(1) 手册页中的交互模式部分解释了要使用的键:

      y - stage this hunk
      n - do not stage this hunk
      q - quit; do not stage this hunk nor any of the remaining ones
      a - stage this hunk and all later hunks in the file
      d - do not stage this hunk nor any of the later hunks in the file
      g - select a hunk to go to
      / - search for a hunk matching the given regex
      j - leave this hunk undecided, see next undecided hunk
      J - leave this hunk undecided, see next hunk
      k - leave this hunk undecided, see previous undecided hunk
      K - leave this hunk undecided, see previous hunk
      s - split the current hunk into smaller hunks
      e - manually edit the current hunk
      ? - print help
      

      split 命令特别有用。

      【讨论】:

      • 如何在使用补丁的同时使用合并工具?而不是关键的东西
      • @Gabriel 我什至使用了 Git 补丁文件和 tarball,因为它很容易创建一个 repo (git init &lt;dir&gt;) 最后扔掉它 (rm -r &lt;dir&gt;)。
      • 在应用补丁时如何工作的链接也很有用,讨论+- 起始行,以及您应该如何执行更改选择。
      • 有没有办法以非交互方式做到这一点?
      【解决方案5】:

      其他当前答案都不会真正“合并”文件,就像您使用合并命令一样。 (充其量他们会要求你手动选择差异。)如果你真的想利用来自共同祖先的信息进行合并,你可以按照 git 参考手册的"Advanced Merging" section 中的一个程序进行操作.

      对于此协议,我假设您希望将文件 'path/to/file.txt' 从 origin/master 合并到 HEAD - 进行适当的修改。 (您不必位于存储库的顶级目录中,但这会有所帮助。)

      # Find the merge base SHA1 (the common ancestor) for the two commits:
      git merge-base HEAD origin/master
      
      # Get the contents of the files at each stage
      git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
      git show HEAD:path/to/file.txt > ./file.ours.txt
      git show origin/master:path/to/file.txt > ./file.theirs.txt
      
      # You can pre-edit any of the files (e.g. run a formatter on it), if you want.
      
      # Merge the files
      git merge-file -p ./file.ours.txt ./file.common.txt ./file.theirs.txt > ./file.merged.txt
      
      # Resolve merge conflicts in ./file.merged.txt
      # Copy the merged version to the destination
      # Clean up the intermediate files
      

      git merge-file 应该使用所有默认的合并设置进行格式化等。

      还要注意,如果你的“我们的”是工作副本版本,又不想过于谨慎,可以直接对文件进行操作:

      git merge-base HEAD origin/master
      git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
      git show origin/master:path/to/file.txt > ./file.theirs.txt
      git merge-file path/to/file.txt ./file.common.txt ./file.theirs.txt
      

      【讨论】:

      • 这确实是实际上合并更改的唯一选项。我在 bash 循环中使用它对几个文件执行此操作:for file in {file1,file2,etc}; do git show $(git merge-base HEAD dev-mysql-to-pdo):$file &gt; common.tmp; git show HEAD:$file &gt; current.tmp; git show dev-mysql-to-pdo:$file &gt; other.tmp; git merge-file -p current.tmp common.tmp other.tmp &gt; $file; rm current.tmp other.tmp common.tmp; done
      【解决方案6】:

      你可以stashstash pop文件:

      git checkout branch1
      git checkout branch2 file.py
      git stash
      git checkout branch1
      git stash pop
      

      【讨论】:

      • 这会用 branch2/file.py 的内容覆盖 branch1/file.py,而不是应该引发合并冲突来解决的合并。
      • 不“合并”文件,只是替换它...最后三个语句几乎没有改变结果...
      【解决方案7】:

      我处于同样的情况,我想从一个分支合并一个文件,该分支在 2 个分支上有很多提交。我尝试了上面的很多方法以及我在互联网上找到的其他方法,但都失败了(因为提交历史很复杂)所以我决定按照我的方式(疯狂的方式)。

      git merge <other-branch>
      cp file-to-merge file-to-merge.example
      git reset --hard HEAD (or HEAD^1 if no conflicts happen)
      cp file-to-merge.example file-to-merge
      

      【讨论】:

        【解决方案8】:

        我所做的有点手动,但我:

        1. 正常合并分支;恢复了与revert 的合并;
        2. 将我所有的文件检出到HEAD~1,即它们在 合并提交;
        3. 重新调整我的提交以隐藏这个骇客 提交历史记录。

        丑吗?是的。容易记住?也可以。

        【讨论】:

          【解决方案9】:

          如果您只关心冲突解决而不关心保留提交历史,则以下方法应该有效。假设您要将a.py b.pyBRANCHA 合并到BRANCHB。首先,确保BRANCHB 中的任何更改都已提交或隐藏,并且没有未跟踪的文件。那么:

          git checkout BRANCHB
          git merge BRANCHA
          # 'Accept' all changes
          git add .
          # Clear staging area
          git reset HEAD -- .
          # Stash only the files you want to keep
          git stash push a.py b.py
          # Remove all other changes
          git add .
          git reset --hard
          # Now, pull the changes
          git stash pop
          

          git 不会识别a.py b.py 中存在冲突,但如果确实存在冲突,则存在合并冲突标记。使用第三方合并工具,例如 VSCode,将能够更轻松地解决冲突。

          【讨论】:

            【解决方案10】:

            我发现的最让我头疼的解决方案:

            git checkout <b1>
            git checkout -b dummy
            git merge <b2>
            git checkout <b1>
            git checkout dummy <path to file>
            

            这样做之后,b2 中的path to file 中的文件就是与b1 完全合并后的样子。

            【讨论】:

              【解决方案11】:

              最简单的解决方案是:

              git checkout 源分支的名称和我们要添加到当前分支的特定文件的路径

              git checkout sourceBranchName pathToFile
              

              【讨论】:

                【解决方案12】:

                Matthew Turner 的解决方案是最简单的,但如果 branch1 和文件具有相同的名称,则会出错。在这种情况下,将第二行替换为

                git checkout branch2 -- file.py

                【讨论】:

                  猜你喜欢
                  • 2020-11-13
                  • 2012-11-22
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-03-28
                  • 1970-01-01
                  • 2010-12-13
                  • 1970-01-01
                  相关资源
                  最近更新 更多