I'm using git on a new project that has two parallel -- but currently experimental -- development branches:
master
: import of existing codebase plus a few mods that I'm generally sure ofexp1
: experimental branch #1exp2
: experimental branch #2
exp1
and exp2
represent two very different architectural approaches. Until I get further along I have no way of knowing which one (if either) will work. As I make progress in one branch I sometimes have edits that would be useful in the other branch and would like to merge just those.
What is the best way to merge selective changes from one development branch to another while leaving behind everything else?
Approaches I've considered:
git merge --no-commit
followed by manual unstaging of a large number of edits that I don't want to make common between the branches.Manual copying of common files into a temp directory followed by
git checkout
to move to the other branch and then more manual copying out of the temp directory into the working tree.A variation on the above. Abandon the
exp
branches for now and use two additional local repositories for experimentation. This makes the manual copying of files much more straightforward.
All three of these approaches seem tedious and error-prone. I'm hoping there is a better approach; something akin to a filter path parameter that would make git-merge
more selective.
Here's how you can get history to follow just a couple files from another branch with a minimum of fuss, even if a more "simple" merge would have brought over a lot more changes that you don't want.
First, you'll take the unusual step of declaring in advance that what you're about to commit is a merge, without git doing anything at all to the files in your working directory:
. . . where "branchname" is whatever you claim to be merging from. If you were to commit right away, it would make no changes but it would still show ancestry from the other branch. You can add more branches/tags/etc. to the command line if you need to, as well. At this point though, there are no changes to commit, so get the files from the other revisions, next.
If you were merging from more than one other branch, repeat as needed.
Now the files from the other branch are in the index, ready to be committed, with history.
and you'll have a lot of explaining to do in that commit message.
Please note though, in case it wasn't clear, that this is messed up thing to do. It is not in the spirit of what a "branch" is for, and cherry-pick is a more honest way to do what you'd be doing, here. If you wanted to do another "merge" for other files on the same branch that you didn't bring over last time, it will stop you with an "already up to date" message. It's a symptom of not branching when we should have, in the "from" branch should be more than one different branch.
It is not exactly what you were looking for, but it was useful to me:
It is a mix of some answers.
I would do a
This way you can limit the range of commits for a filepattern from a branch.
Stolen from: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
A simple approach for selective merging/committing by file:
git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes
You use the cherry-pick command to get individual commits from one branch.
If the change(s) you want are not in individual commits, then use the method shown here to split the commit into individual commits. Roughly speaking, you use
git rebase -i
to get the original commit to edit, thengit reset HEAD^
to selectively revert changes, thengit commit
to commit that bit as a new commit in the history.There is another nice method here in Red Hat Magazine, where they use
git add --patch
or possiblygit add --interactive
which allows you to add just parts of a hunk, if you want to split different changes to an individual file (search in that page for "split").Having split the changes, you can now cherry-pick just the ones you want.
If you only need to merge a particular directory and leave everything else intact and yet preserve history, you could possibly try this... create a new
target-branch
off of themaster
before you experiment.The steps below assume you have two branches
target-branch
andsource-branch
, and the directorydir-to-merge
that you want to merge is in thesource-branch
. Also assume you have other directories likedir-to-retain
in the target that you don't want to change and retain history. Also, assumes there are merge conflicts in thedir-to-merge
.