繁体   English   中英

如何合并 Git 中的子目录?

[英]How do I merge a sub directory in Git?

是否可以仅将子目录的更改从本地 Git 分支合并到远程 Git 分支,还是“全有或全无”?

例如,我有:

branch-a
 - content-1
 - dir-1
   - content-2

branch-b
 - content-1
 - dir-1
   - `content-2

我只想将 branch-a dir-1 的内容与 branch-b dir-1 的内容合并。

作为 SO 问题“ 如何将选择性文件与 git-merge 合并? ”的替代方案,我刚刚发现了这个 GitHub 线程,它更适合基于git read-tree合并整个子目录:

  • 我的存储库 => cookbooks
    我的存储库目标目录 => cookbooks/cassandra
  • 远程存储库 => infochimps
    我想合并到cookbooks/cassandra => infochimps/cookbooks/cassandra远程存储库源

这是我用来合并它们的命令

  • 添加存储库并获取它
git remote add -f infochimps git://github.com/infochimps/cluster_chef.git
  • 执行合并
git merge --allow-unrelated-histories -s ours --no-commit infochimps/master

(这通过使用“ours”策略( -s ours )执行合并,该策略会丢弃源分支中的更改。这记录了infochimps/master已合并的事实,而实际上并未修改目标分支中的任何文件)

  • 仅将infochimps/cookbooks/cassandra合并到cassandra
git read-tree --prefix=cassandra/ -u infochimps/master:cookbooks/cassandra

这将仅读取存储库上游分支上所需的源子目录(即cookbooks/cassandra的树。

请注意,目标子目录名称也应该是cookbooks/cassandra ,否则您会看到:

fatal: Not a valid object name
  • 提交更改
git commit -m 'merging in infochimps cassandra'

附录

这很奇怪, [编辑我] - 但read-tree步骤可能会像这样失败:

error: Entry 'infochimps/cookbooks/cassandra/README' overlaps with 'cookbooks/cassandra/README'. Cannot bind.

...即使两个文件相同 这可能有帮助:

git rm -r cassandra
git read-tree --prefix=cassandra/ -u infochimps/master:cookbooks/cassandra

但是当然,请手动验证这是否符合您的要求。

对于我的示例,假设您有一个分支 'source' 和一个分支 'destination',它们都反映了它们自己的上游版本(或者不是,如果只是本地版本)并且被拉到最新的代码。 假设我想要存储库中名为 newFeature 的子目录,它只存在于“源”分支中。

git checkout destination
git checkout source newFeature/
git commit -am "Merged the new feature from source to destination branch."
git pull --rebase
git push

它比我见过的其他所有东西都少得多复杂,这对我来说非常有用, 可以在这里找到

请注意,这不是“真正的合并”,因此您不会在目标分支中拥有有关 newFeature 的提交信息,只有对该子目录中文件的修改。 但是由于您可能会稍后合并整个分支,或者丢弃它,所以这可能不是问题。

鉴于 OP 的场景,他们有两个分支,但只想将dir-1的历史从branch-a合并到branch-b

# Make sure you are in the branch with the changes you want
git checkout branch-a

# Split the desired folder into its own temporary branch
# This replays all commits, so it could take a while
git subtree split -P dir-1 -b temp-branch

# Enter the branch where you want to merge the desired changes into
git checkout branch-b

# Merge the changes from the temporary branch
git subtree merge -P dir-1 temp-branch

# Handle any conflicts
git mergetool

# Commit
git commit -am "Merged dir-1 changes from branch-a"

# Delete temp-branch
git branch -d temp-branch

我从 Eclipse 的一个论坛帖子中得到了这个,它的作用就像一个魅力:

git checkout source-branch
git checkout target-branch <directories-or-files-you-do-**NOT**-want> 
git commit
git checkout target-branch
git merge source-branch

使用git cherry-pick选择您想要的提交并仅合并这些提交。 这里的关键技巧是以简单的方式获取这些提交(这样您就不必通过手动检查 Git 日志并手动输入来弄清楚它们)。 方法如下:使用git log打印提交的SHA-1 id,如下所示:

git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>

'commit-a' 是要合并的分支起点之前的提交,而 'commit-b' 是要合并的分支上的最后一个提交。 '--reverse' 以相反的顺序打印这些提交,以便稍后挑选。

然后这样做:

git cherry-pick $(git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>)

分两步,简单又稳定!

创建一个包含分支 a 和分支 b 的 Git 存储库:

git checkout branch-a
git diff branch-b dir-1 > a.diff
patch -R -p1 < a.diff

案例 0:我还没有接触文件

git checkout origin/branch-with-the-code-you-want ./path/to/dir1

这会为您提供其他分支上未暂存更改的文件夹。

案例 1:团队有干净的提交

如果您的团队确实提交了干净的提交,那么在提交历史中挖掘可能会很有成效。 在这些情况下使用git cherry-pick COMMIT_HASH 如果需要,您可能想要git rebase -i HEAD~N其中 N 是一些提交以将它们添加为历史中的pick COMMIT_HASH行。

案例 2:干净的提交并不重要,但知道冲突很重要

如果您到处都有所有提交,那么您可能不需要保留历史记录,这是一种适用于这些情况的方法。 请注意,这种方法不会删除文件或为您提供历史记录,但会为您提供每个文件之间的冲突。

# Create an orphan branch with no history but your files
git checkout --orphan temp-branch

# Get the version of the files from the other branch
git checkout origin/branch-with-the-changes ./path/to/the/folder/you/want/to/merge
git commit -m "Commit that has all files like they are on your branch, except that one folder you want to merge"

# Merge the other file tree
git checkout your-branch
git merge temp-branch --allow-unrelated

# Clean up
git branch -D temp-branch

简单的解决方法,合并和重置不需要的更改,保留您想要的

  1. 你有一个目录 structre git/src/agit/src/b的存储库,你只想合并目录b
  2. git merge origin/a-feature-branch
  3. 备份b目录更改,例如mv b b-merged
  4. 通过命令git reset HEAD --hard重置分支
  5. 用 b-merged, mv b b-origin; mv b-merged b; mv b b-origin; mv b-merged b;

这就是我将如何解决它:

首先找到两个分支共有的最后一次提交,这是两个分支开始分歧的地方:

$ git merge-base branchA branchB
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

然后从该提交中签出一个新分支:

git branch branchC 050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

然后签出要从源分支合并到新分支的文件夹:

git checkout branchC
git checkout branchB ./path/to/the/folder/you/want/to/merge
git commit -m "update folder to merge from branchB"

现在 branchC 仅包含您要合并的文件夹中的更改。

最后将这些更改合并到目标分支中:

git checkout branchA
git merge branchC

现在您可以按您认为合适的方式处理任何合并冲突。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM