How do I merge a sub directory in git?

2019-01-06 09:33发布

问题:

Is it possible to merge only the changes for a sub-directory from a local git branch to a remote git branch or is it "all or nothing"?

For example, I have:

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

and

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

I only want to merge the contents of branch-a dir-1 with the contents of branch-b dir-1.

回答1:

Just as an alternative to the SO question "How do you merge selective files with git-merge?", I just found this GitHub thread which could be more adapted for merging a whole subdirectory, based on git read-tree:

  • My repository => cookbooks
    My repository target directory => cookbooks/cassandra

  • Remote repository => infochimps
    Remote repository source I want merged into cookbooks/cassandra => infochimps/cookbooks/cassandra

Here are the commands I used to merge them

  • Add the repository and fetch it
git remote add -f infochimps git://github.com/infochimps/cluster_chef.git
  • Perform the merge
git merge -s ours --no-commit infochimps/master
  • Merge only infochimps/cookbooks/cassandra into cassandra
git read-tree --prefix=cassandra/ -u infochimps/master:cookbooks/cassandra
  • Commit the change
 git commit -m 'merging in infochimps cassandra'

Addendum

It's bizarre,[edit me] — but the read-tree step can possibly fail like this:

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

... even when both files are identical. This might help:

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

But off course, verify manually that this does what you want.



回答2:

For my example, assume you have a branch 'source' and a branch 'destination' which both reflect upstream versions of themselves (or not, if local only) and are pulled to the latest code. Let's say I want the subdirectory in the repo called newFeature which only exists in the 'source' branch.

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

Significantly less convoluted than everything else I've seen and this worked perfectly for me, found here.

Note that this isn't a 'real merge' so you won't have the commit information about newFeature in the destination branch, just the modifications to the files in that subdirectory. But since you're presumably going to merge the entire branch back over later, or discard it, that might not be an issue.



回答3:

I got this from a forum thread at Eclipse and it worked like a charm:

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


回答4:

Use git cherry-pick to select the commits you want and merge only these commits. The key trick here is to get these commits in an easy way(so that you don't have to figure out them by manually checking the git log and entering them by hand). Here's how: use git log to print the commit's sha1 id, like this:

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

commit-a is the commit immediately before the start point of the branch to merge, commit-b is the last commit on the branch to merge. --reverse prints these commit in reverse order for cherry pick later.

Then do it like:

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

Two steps, simple and stable!



回答5:

create git repo contains both branch-a and branch-b

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


标签: git