How do I merge a sub directory in Git?

前端 未结 6 859
太阳男子
太阳男子 2020-11-27 11:08

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:<

相关标签:
6条回答
  • 2020-11-27 11:44

    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
    
    0 讨论(0)
  • 2020-11-27 11:47

    Given the OP's scenario where they have two branches, but want to merge only the history of dir-1 from branch-a into 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
    
    0 讨论(0)
  • 2020-11-27 11:53

    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 --allow-unrelated-histories -s ours --no-commit infochimps/master
    

    (this performs a merge by using the 'ours' strategy (-s ours), which discards changes from the source branch. This records the fact that infochimps/master has been merged, without actually modifying any file in the target branch)

    • Merge only infochimps/cookbooks/cassandra into cassandra
    git read-tree --prefix=cassandra/ -u infochimps/master:cookbooks/cassandra
    

    This reads the tree for only the required source subdirectory i.e. cookbooks/cassandra, on the upstream branch of the source repository.

    Note that the target subdirectory name should also be cookbooks/cassandra, or you would see:

    fatal: Not a valid object name
    
    • 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.

    0 讨论(0)
  • 2020-11-27 12:06

    Create a Git repository to contain both branch-a and branch-b:

    git checkout branch-a
    git diff branch-b dir-1 > a.diff
    patch -R -p1 < a.diff
    
    0 讨论(0)
  • 2020-11-27 12:08

    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 repository 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
    

    It is 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.

    0 讨论(0)
  • 2020-11-27 12:10

    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 them out by manually checking the Git log and entering them by hand). Here's how: use git log to print the commit's SHA-1 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, and 'commit-b' is the last commit on the branch to merge. '--reverse' prints these commits in reverse order for cherry-picking later.

    Then do it like:

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

    It is two steps, simple and stable!

    0 讨论(0)
提交回复
热议问题