Reputation: 2839
I'm using git-svn for offline development against my company's Subversion repository, which is the project's repository of record. To enable management visibility I'm required to maintain my feature branches in SVN. Sometimes I need to merge changes from our trunk to a feature branch multiple times over the lifetime of the branch. Since I'm required to keep the branch up-to-date in SVN I have to merge; I can't rebase commits once they're pushed to SVN. Further, git svn dcommit
removes the second parent from merge commits. That means on merges after the first git merge
identifies the branch root as the merge base instead of the most recent merge parent. It therefore tries to re-merge changes that have already been merged, which pretty much guarantees nasty conflicts.
When I merge in SVN I manually specify the base revision:
svn merge -r 49262:49608 $svn/trunk
Is there a way in git to do a merge with a manually specified base revision like that?
Note that I need to specify two revisions, both the base and the parent revision. I have a history like
trunk: A -- B -- C -- D -- H -- I
\ \
feature: E -- F -- G -- J -- K
but git svn dcommit
has removed the parent relationship between G
and D
. I need to run a merge of I
on to K
with a base of D
. Simply running
$ git checkout feature
$ git merge trunk
will try to merge I
on to K
with a base of B
instead of D
, which re-applies C
and D
resulting in extreme merge conflicts. With SVN I would run a command like
$ svn switch $svn/feature
$ svn merge -r D:I $svn/trunk
but git merge
does not have an option to specify the base revision D
. I'm looking for something like
$ git merge --base D trunk
but such an option doesn't appear to exist.
Upvotes: 5
Views: 869
Reputation: 8186
This is what we did. We first found the hash of the merge commit that had lost its 'merge' - MISSING_MERGE, Second we found the commit which that commit had merged in - MERGED_POINT.
Then we went to the receiving branch and created a fake commit
git merge -s ours MERGED_POINT --no-commit
git commit -m "Fake commit because MISSING_MERGE is not marked as a merge commit"
We can then see
git merge-base OURS THEIRS
that we now have the correct base again.
Upvotes: 0
Reputation: 60245
(edit: for a lower-level way of doing this see previous revisions, this way's fastest though)
make a nonce commit with feature
's tree parented on the correct merge base
git checkout `git commit-tree -p $D -m - feature^{tree}`
merge trunk into that as usual
git merge trunk --no-commit
git commit # the two-stepper gets the commit message someplace known
commit the merged tree as the new feature
tip
git commit-tree -p feature -p trunk -F .git/COMMIT_EDITMSG HEAD^{tree} \
| xargs git checkout -B feature
Upvotes: 4
Reputation: 810
You might try git merge <commit hashcode>
where the hashcode of the commit can be found using git log
Update:
Based on your revision, I think what you're looking for is the following. Start by doing git branch D
. You should be able to get the commit hash for D by doing git status
. Then, do git checkout feature
. Then do git merge newBranchFromD
. This will put the state of feature into a merged state, from D, from the trunk.
You could also, in order to keep a cleaner commit history, do a git rebase newBranchFromD
after checking out the feature branch. Be warned, this inserts H into the correct place in the commit history, so that you'd end up with:
trunkAtD: -- H -- I / trunk: A -- B -- C -- D -- H -- I \ \ feature: E -- F -- G -- H -- I -- J -- K
This is a little different than a merge commit, as rebase puts all commits in chronological order in your commit history. Another option you have is to use --squash on your commit, so that the merge doesn't attempt to auto-commit.
Use rebase with caution, as it can cause unexpected outcomes if it's not being used when you know what's going on with it.
Upvotes: 0