threads / discuss / 10087

git-svn merge helper

Subject: git-svn merge helper

## tl;dr

10 messages between Sep 30, 2007 and Oct 3, 2007.

replies: 9people: 4as markdown or json

Björn Steinbrink· Sep 30, 2007, 11:05 UTC · lore
Hi,

I recently discovered git-svn and absolutey love it. One thing that I'm missing though, is an equivalent of "svn merge" for merging between svn remotes, to support the SVN way of using "squashed" merges, where you just note the merge meta-data in the commit message. "git merge" didn't work for me (and probably isn't expected to work) to merge between two svn branches, so I've resorted to cherry-picking the required commits one by one into a temporary branch and then squashing them together by doing a --squash merge with a second temporary branch (as in [1]).

Of course that becomes extremely annoying if there are like 200 commits to merge, so I came up with the following script to help me. It does just what I described above, but automated. Usage is like this:

git-svn-merge trunk 123 543

Which does the same as "svn merge -r123:543 trunk-url", except for being incremental (ie. no huge one-time patch, eventually causing a massive set of conflicts) and often faster.

In case of conflicts, it bails out and let's you fix them. Then you can just re-run it with the same parameters again, as it automatically determines where to start cherry-picking if you're currently on the merge branch.

It's neither complete nor nice to look at, but it more or less gets the job done, so I thought I'll just post it here, maybe someone picks it up and brings it into shape.

Thanks, Björn

[1] http://cheat.errtheblog.com/s/gitsvn/
#!/bin/sh
BRANCH=$(git branch | grep \* | cut -d ' ' -f2)

START=$(git svn find-rev r$2 $1) END=$(git svn find-rev r$3 $1)

if echo $BRANCH | grep -q svnmerge/
then
	START=$(git svn find-rev r$(git svn find-rev HEAD) $1)
else
	git checkout -b svnmerge/$BRANCH
fi
for HASH in $(git log --pretty=format:%H --reverse $START..$END)
do
	git cherry-pick $HASH || exit
done

git checkout $BRANCH git checkout -b svnmerge/$BRANCH-squashed git merge --squash svnmerge/$BRANCH git commit -m "Merged changes from revisions $2-$3 from $1 into $BRANCH."

Benoit SIGOURE· Sep 30, 2007, 14:15 UTC · re: Björn Steinbrink · lore

Re: git-svn merge helper

On Sep 30, 2007, at 1:05 PM, Björn Steinbrink wrote:
Show 13 quoted lines
> Hi,
>
> I recently discovered git-svn and absolutey love it. One thing that  
> I'm
> missing though, is an equivalent of "svn merge" for merging between  
> svn
> remotes, to support the SVN way of using "squashed" merges, where you
> just note the merge meta-data in the commit message. "git merge"  
> didn't
> work for me (and probably isn't expected to work) to merge between two
> svn branches, so I've resorted to cherry-picking the required commits
> one by one into a temporary branch and then squashing them together by
> doing a --squash merge with a second temporary branch (as in [1]).

I fail to see why you'd want to reproduce the broken behavior of svn merge. Anyways, git-svn is a great way to merge SVN branches, unfortunately it can't detect when merges happened on the SVN side. I think you can use it nevertheless by manually adding a graft at the last merge point, which would help you merging the right revisions without having to specify what needs to be merged (unless someone made another merge on the SVN side, in which case you need to update your graft).

Cheers,
-- 
Benoit Sigoure aka Tsuna
EPITA Research and Development Laboratory
Björn Steinbrink· Oct 1, 2007, 02:50 UTC · re: Benoit SIGOURE · lore

Re: git-svn merge helper

On 2007.09.30 16:15:49 +0200, Benoit SIGOURE wrote:
Show 20 quoted lines
> On Sep 30, 2007, at 1:05 PM, Björn Steinbrink wrote:
>
>> Hi,
>>
>> I recently discovered git-svn and absolutey love it. One thing that I'm
>> missing though, is an equivalent of "svn merge" for merging between svn
>> remotes, to support the SVN way of using "squashed" merges, where you
>> just note the merge meta-data in the commit message. "git merge" didn't
>> work for me (and probably isn't expected to work) to merge between two
>> svn branches, so I've resorted to cherry-picking the required commits
>> one by one into a temporary branch and then squashing them together by
>> doing a --squash merge with a second temporary branch (as in [1]).
>
> I fail to see why you'd want to reproduce the broken behavior of svn merge. 
>  Anyways, git-svn is a great way to merge SVN branches, unfortunately it 
> can't detect when merges happened on the SVN side.  I think you can use it 
> nevertheless by manually adding a graft at the last merge point, which 
> would help you merging the right revisions without having to specify what 
> needs to be merged (unless someone made another merge on the SVN side, in 
> which case you need to update your graft).

Then how does that work? The manpage explicitly says that I should not use git-{pull,merge} on branches I want to dcommit from. And a trivial test immediately got the expected effect of git-svn trying to commit to trunk instead of the branch.

Thanks, Björn

Benoit SIGOURE· Oct 1, 2007, 07:56 UTC · re: Björn Steinbrink · lore

Re: git-svn merge helper

On Oct 1, 2007, at 4:50 AM, Björn Steinbrink wrote:
Show 40 quoted lines
> On 2007.09.30 16:15:49 +0200, Benoit SIGOURE wrote:
>> On Sep 30, 2007, at 1:05 PM, Björn Steinbrink wrote:
>>
>>> Hi,
>>>
>>> I recently discovered git-svn and absolutey love it. One thing  
>>> that I'm
>>> missing though, is an equivalent of "svn merge" for merging  
>>> between svn
>>> remotes, to support the SVN way of using "squashed" merges, where  
>>> you
>>> just note the merge meta-data in the commit message. "git merge"  
>>> didn't
>>> work for me (and probably isn't expected to work) to merge  
>>> between two
>>> svn branches, so I've resorted to cherry-picking the required  
>>> commits
>>> one by one into a temporary branch and then squashing them  
>>> together by
>>> doing a --squash merge with a second temporary branch (as in [1]).
>>
>> I fail to see why you'd want to reproduce the broken behavior of  
>> svn merge.
>>  Anyways, git-svn is a great way to merge SVN branches,  
>> unfortunately it
>> can't detect when merges happened on the SVN side.  I think you  
>> can use it
>> nevertheless by manually adding a graft at the last merge point,  
>> which
>> would help you merging the right revisions without having to  
>> specify what
>> needs to be merged (unless someone made another merge on the SVN  
>> side, in
>> which case you need to update your graft).
>
> Then how does that work? The manpage explicitly says that I should not
> use git-{pull,merge} on branches I want to dcommit from. And a trivial
> test immediately got the expected effect of git-svn trying to  
> commit to
> trunk instead of the branch.

Ah, yes, you're right. Well, this will work the day we can pass an option to git-svn dcommit to tell it where the commit must be sent.

-- 
Benoit Sigoure aka Tsuna
EPITA Research and Development Laboratory
Björn Steinbrink· Oct 2, 2007, 21:14 UTC · lore

Re: git-svn merge helper

On 2007.10.01 10:13:45 +0200, Lars Hjemli wrote:
Show 15 quoted lines
> On 10/1/07, Benoit SIGOURE <tsuna@lrde.epita.fr> wrote:
> > On Oct 1, 2007, at 4:50 AM, Björn Steinbrink wrote:
> > > Then how does that work? The manpage explicitly says that I should not
> > > use git-{pull,merge} on branches I want to dcommit from. And a trivial
> > > test immediately got the expected effect of git-svn trying to
> > > commit to
> > > trunk instead of the branch.
> >
> > Ah, yes, you're right.  Well, this will work the day we can pass an
> > option to git-svn dcommit to tell it where the commit must be sent.
> >
> 
> This is fixed in the latest version of git-svn (yet to be released).
> There is no need for an extra option, git-svn dcommit now handles
> merges between subversion branches correctly.
Thanks, but there's still a case that fails.

One common pattern in SVN is to have the feature branch following the trunk. In git terms, that would mean that the feature branch is continually rebased onto the HEAD of the HEAD AFAICT (although SVN of course cannot represent that). The problem with that is, that git doesn't create a merge commit in that case and git-svn gets confused again.

git checkout mybranch git merge master # Creates a merge commit git checkout master git merge mybranch # Does just fast forward

Is there anyway to force a merge commit or some other work around?

Thanks, Björn

Steven Walter· Oct 2, 2007, 22:04 UTC · re: Björn Steinbrink · lore

Re: git-svn merge helper

On Tue, Oct 02, 2007 at 11:14:00PM +0200, Björn Steinbrink wrote:
Show 13 quoted lines
> One common pattern in SVN is to have the feature branch following the
> trunk. In git terms, that would mean that the feature branch is
> continually rebased onto the HEAD of the HEAD AFAICT (although SVN of
> course cannot represent that). The problem with that is, that git
> doesn't create a merge commit in that case and git-svn gets confused
> again.
> 
> git checkout mybranch
> git merge master # Creates a merge commit
> git checkout master
> git merge mybranch # Does just fast forward
> 
> Is there anyway to force a merge commit or some other work around?

When I want to do something like this, I go about it one of two ways. The first option is to simply rebase mybranch onto master. Since my feature branches are not usually published, there is no problem rewinding them. That may not be an option for you, however.

The other option is to have a "build" branch.  By example:

git checkout build git reset --hard master git merge mybranch make

In that way, I have branch with the latest changes from head and the changes from mybranch together. The downside to this method is that you may have to repeated resolve merges. Despite the downsides, I find these two methods to work quite well.

-- 
-Steven Walter <stevenrwalter@gmail.com>
"A human being should be able to change a diaper, plan an invasion,
butcher a hog, conn a ship, design a building, write a sonnet, balance
accounts, build a wall, set a bone, comfort the dying, take orders,
give orders, cooperate, act alone, solve equations, analyze a new
problem, pitch manure, program a computer, cook a tasty meal, fight
efficiently, die gallantly. Specialization is for insects."
   -Robert Heinlein
Björn Steinbrink· Oct 2, 2007, 22:38 UTC · re: Steven Walter · lore

Re: git-svn merge helper

On 2007.10.02 18:04:58 -0400, Steven Walter wrote:
Show 19 quoted lines
> On Tue, Oct 02, 2007 at 11:14:00PM +0200, Björn Steinbrink wrote:
> > One common pattern in SVN is to have the feature branch following the
> > trunk. In git terms, that would mean that the feature branch is
> > continually rebased onto the HEAD of the HEAD AFAICT (although SVN of
> > course cannot represent that). The problem with that is, that git
> > doesn't create a merge commit in that case and git-svn gets confused
> > again.
> > 
> > git checkout mybranch
> > git merge master # Creates a merge commit
> > git checkout master
> > git merge mybranch # Does just fast forward
> > 
> > Is there anyway to force a merge commit or some other work around?
> 
> When I want to do something like this, I go about it one of two ways.
> The first option is to simply rebase mybranch onto master.  Since my
> feature branches are not usually published, there is no problem
> rewinding them.  That may not be an option for you, however.

Unfortunately not, the branch in question is required to be in the SVN repository.

Show 11 quoted lines
> The other option is to have a "build" branch.  By example:
> 
> git checkout build
> git reset --hard master
> git merge mybranch
> make
> 
> In that way, I have branch with the latest changes from head and the
> changes from mybranch together.  The downside to this method is that you
> may have to repeated resolve merges.  Despite the downsides, I find
> these two methods to work quite well.

Thanks, but it makes no difference here, it stil results in a fast forward. This is a small test case which exhibits the behaviour and matches my current workflow with git-svn (except for the dcommits):

git init echo Hi > file1; git add file1; git commit -m file1 git checkout -b branch echo Hi > file2; git add file2; git commit -m file2 git checkout master echo Hi > file3; git add file3; git commit -m file3 git checkout branch git merge master

# Then I'd normally do the following which causes a fast forward #git checkout master #git merge branch

# Now I tried this, which also results in a fast-forward: git checkout -b merge git reset --hard master git merge branch

Anything I'm missing?

Thanks, Björn

Steven Walter· Oct 3, 2007, 00:42 UTC · re: Björn Steinbrink · lore

Re: git-svn merge helper

On Wed, Oct 03, 2007 at 12:38:13AM +0200, Björn Steinbrink wrote:
Show 33 quoted lines
> > The other option is to have a "build" branch.  By example:
> > 
> > git checkout build
> > git reset --hard master
> > git merge mybranch
> > make
> > 
> > In that way, I have branch with the latest changes from head and the
> > changes from mybranch together.  The downside to this method is that you
> > may have to repeated resolve merges.  Despite the downsides, I find
> > these two methods to work quite well.
> 
> Thanks, but it makes no difference here, it stil results in a fast
> forward. This is a small test case which exhibits the behaviour and
> matches my current workflow with git-svn (except for the dcommits):
> 
> git init
> echo Hi > file1; git add file1; git commit -m file1
> git checkout -b branch
> echo Hi > file2; git add file2; git commit -m file2
> git checkout master
> echo Hi > file3; git add file3; git commit -m file3
> git checkout branch
> git merge master
> 
> # Then I'd normally do the following which causes a fast forward
> #git checkout master
> #git merge branch
> 
> # Now I tried this, which also results in a fast-forward:
> git checkout -b merge
> git reset --hard master
> git merge branch

I believe you misunderstood my suggestion. In using a "build" branch, you would not merge master into branch, as you did above. Instead, you would create a third, unpublished branch to hold the merge.

At the same time, I have a slightly better understanding of what it is you're trying to do. If you are trying to keep up an SVN-like workflow (namely pulling changes from trunk into a branch from time to time), then my solution probably isn't suitable for you. However, you might consider why you actually /need/ to do that, outside of SVN convention.

-- 
-Steven Walter <stevenrwalter@gmail.com>
"A human being should be able to change a diaper, plan an invasion,
butcher a hog, conn a ship, design a building, write a sonnet, balance
accounts, build a wall, set a bone, comfort the dying, take orders,
give orders, cooperate, act alone, solve equations, analyze a new
problem, pitch manure, program a computer, cook a tasty meal, fight
efficiently, die gallantly. Specialization is for insects."
   -Robert Heinlein
Björn Steinbrink· Oct 3, 2007, 01:02 UTC · re: Steven Walter · lore

Re: git-svn merge helper

On 2007.10.02 20:42:52 -0400, Steven Walter wrote:
Show 38 quoted lines
> On Wed, Oct 03, 2007 at 12:38:13AM +0200, Björn Steinbrink wrote:
> > > The other option is to have a "build" branch.  By example:
> > > 
> > > git checkout build
> > > git reset --hard master
> > > git merge mybranch
> > > make
> > > 
> > > In that way, I have branch with the latest changes from head and the
> > > changes from mybranch together.  The downside to this method is that you
> > > may have to repeated resolve merges.  Despite the downsides, I find
> > > these two methods to work quite well.
> > 
> > Thanks, but it makes no difference here, it stil results in a fast
> > forward. This is a small test case which exhibits the behaviour and
> > matches my current workflow with git-svn (except for the dcommits):
> > 
> > git init
> > echo Hi > file1; git add file1; git commit -m file1
> > git checkout -b branch
> > echo Hi > file2; git add file2; git commit -m file2
> > git checkout master
> > echo Hi > file3; git add file3; git commit -m file3
> > git checkout branch
> > git merge master
> > 
> > # Then I'd normally do the following which causes a fast forward
> > #git checkout master
> > #git merge branch
> > 
> > # Now I tried this, which also results in a fast-forward:
> > git checkout -b merge
> > git reset --hard master
> > git merge branch
> 
> I believe you misunderstood my suggestion.  In using a "build" branch,
> you would not merge master into branch, as you did above.  Instead, you
> would create a third, unpublished branch to hold the merge.
Almost though so.
Show 5 quoted lines
> At the same time, I have a slightly better understanding of what it is
> you're trying to do.  If you are trying to keep up an SVN-like workflow
> (namely pulling changes from trunk into a branch from time to time),
> then my solution probably isn't suitable for you.  However, you might
> consider why you actually /need/ to do that, outside of SVN convention.

Due to the same reason for which the branch needs to be public at all, there are other people who want to follow it and test it, while there are external dependencies that currently change quite often. So I need to get the relevant changes from trunk into my branch anyway, even with svn conventions put aside (well, unless I force everyone else to merge over and over again). And as sometimes others commit to that branch, too (you just have to love that), keeping a separate branch for the final merge isn't so nice either, as I'd need to constantly cherry-pick those changes then and probably get even more conflicts along the way.

That said, Google finally liked some of the search terms that I threw at it and revealed a thread [1] from march, where Linus was torn on whether or not a --no-fast-forward option should be introduced. That sounds like it would help here, any chance of getting such a thing?

Thanks, Björn

[1] http://lists-archives.org/git/419374-git-merge-and-merge-message.html

Andreas Ericsson· Oct 3, 2007, 11:40 UTC · re: Björn Steinbrink · lore

Re: git-svn merge helper

Björn Steinbrink wrote:
Show 61 quoted lines
> On 2007.10.02 20:42:52 -0400, Steven Walter wrote:
>> On Wed, Oct 03, 2007 at 12:38:13AM +0200, Björn Steinbrink wrote:
>>>> The other option is to have a "build" branch.  By example:
>>>>
>>>> git checkout build
>>>> git reset --hard master
>>>> git merge mybranch
>>>> make
>>>>
>>>> In that way, I have branch with the latest changes from head and the
>>>> changes from mybranch together.  The downside to this method is that you
>>>> may have to repeated resolve merges.  Despite the downsides, I find
>>>> these two methods to work quite well.
>>> Thanks, but it makes no difference here, it stil results in a fast
>>> forward. This is a small test case which exhibits the behaviour and
>>> matches my current workflow with git-svn (except for the dcommits):
>>>
>>> git init
>>> echo Hi > file1; git add file1; git commit -m file1
>>> git checkout -b branch
>>> echo Hi > file2; git add file2; git commit -m file2
>>> git checkout master
>>> echo Hi > file3; git add file3; git commit -m file3
>>> git checkout branch
>>> git merge master
>>>
>>> # Then I'd normally do the following which causes a fast forward
>>> #git checkout master
>>> #git merge branch
>>>
>>> # Now I tried this, which also results in a fast-forward:
>>> git checkout -b merge
>>> git reset --hard master
>>> git merge branch
>> I believe you misunderstood my suggestion.  In using a "build" branch,
>> you would not merge master into branch, as you did above.  Instead, you
>> would create a third, unpublished branch to hold the merge.
> 
> Almost though so.
> 
>> At the same time, I have a slightly better understanding of what it is
>> you're trying to do.  If you are trying to keep up an SVN-like workflow
>> (namely pulling changes from trunk into a branch from time to time),
>> then my solution probably isn't suitable for you.  However, you might
>> consider why you actually /need/ to do that, outside of SVN convention.
> 
> Due to the same reason for which the branch needs to be public at all,
> there are other people who want to follow it and test it, while there
> are external dependencies that currently change quite often. So I need
> to get the relevant changes from trunk into my branch anyway, even with
> svn conventions put aside (well, unless I force everyone else to merge
> over and over again). And as sometimes others commit to that branch, too
> (you just have to love that), keeping a separate branch for the final
> merge isn't so nice either, as I'd need to constantly cherry-pick those
> changes then and probably get even more conflicts along the way.
> 
> That said, Google finally liked some of the search terms that I threw at
> it and revealed a thread [1] from march, where Linus was torn on whether
> or not a --no-fast-forward option should be introduced. That sounds like
> it would help here, any chance of getting such a thing?
> 
Is this what you're looking for? It's in the 'next' branch in git.git.
commit d66424c4ac661c69640765260235452499d80378
Author: Lars Hjemli <hjemli@gmail.com>
Date:   Mon Sep 24 00:51:45 2007 +0200
    git-merge: add --ff and --no-ff options
    
    These new options can be used to control the policy for fast-forward
    merges: --ff allows it (this is the default) while --no-ff will create
    a merge commit.
    
    Signed-off-by: Lars Hjemli <hjemli@gmail.com>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>
-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

← back to recent threads