是否可以仅将子目录的更改从本地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的内容合并。
Answers:
就像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我们的--no-commit infochimps / master
(这通过使用“我们的”策略(-s ours)执行合并,该策略将丢弃源分支中的更改。这将记录infochimps/master已合并的事实,而无需实际修改目标分支中的任何文件)
- 仅合并
infochimps/cookbooks/cassandra到cassandra
git read-tree --prefix = cassandra / -u infochimps / master:菜谱/ cassandra
这仅读取所需的源子目录的树,即cookbooks/cassandra在源存储库的上游分支上。
请注意,目标子目录名称也应为cookbooks/cassandra,否则您将看到:
fatal: Not a valid object name
- 提交更改
git commit -m'合并到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
但是当然,请手动验证这是否符合您的要求。
<rev>:<path>,比如HEAD:README,:README,master:./README
git read-tree步骤对我而言失败:error: Entry 'foo/bar/baz.php' overlaps with 'bar/baz.php'. Cannot bind.
overlaps with错误也会在相同文件上弹出。那有多奇怪?
infochimps/master已合并的事实,但没有实际修改目标分支中的任何文件。因为下一步git read-tree --prefix=cassandra将做修改。最后的提交将记录实际的“合并”内容。
在我的示例中,假设您有一个分支“源”和一个分支“目的地”,它们既反映了自己的上游版本(或者不反映,如果仅是本地的),并被拉到最新的代码。假设我想要存储库中名为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的提交信息,而仅是对该子目录中文件的修改。但是,由于您可能稍后将合并整个分支,或者将其丢弃,因此这可能不是问题。
我是从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
checkout使文件夹相同=>区别只是取消checkout文件夹=>merge区别。这是一个有效的策略。
给定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
使用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>)
这是两个步骤,简单而稳定!
Two steps, simple and stable!一点都不简单:)
git,它具有可怕的界面和可怕的心理模型,里面充斥着各种谜团,随意的名称和含义。