[英]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
git checkout origin/branch-with-the-code-you-want ./path/to/dir1
这会为您提供其他分支上未暂存更改的文件夹。
如果您的团队确实提交了干净的提交,那么在提交历史中挖掘可能会很有成效。 在这些情况下使用git cherry-pick COMMIT_HASH
。 如果需要,您可能想要git rebase -i HEAD~N
其中 N 是一些提交以将它们添加为历史中的pick COMMIT_HASH
行。
如果您到处都有所有提交,那么您可能不需要保留历史记录,这是一种适用于这些情况的方法。 请注意,这种方法不会删除文件或为您提供历史记录,但会为您提供每个文件之间的冲突。
# 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
简单的解决方法,合并和重置不需要的更改,保留您想要的
git/src/a
, git/src/b
的存储库,你只想合并目录b
git merge origin/a-feature-branch
b
目录更改,例如mv b b-merged
git reset HEAD --hard
重置分支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.