Sam Hanes
Sam Hanes

Reputation: 2839

git merge against an arbitrary base revision (git-svn)

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?

Update:

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

Answers (3)

Luke Page
Luke Page

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

jthill
jthill

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

Jason Lowenthal
Jason Lowenthal

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

Related Questions