Subject: Re: Regression: git-svn clone failure

From: Sam Vilain <[email-masked]>
Date: Wed, 23 Dec 2009 13:09:05 +1300

Andrew Myrick wrote:
> This makes perfect sense now.  Thank you for clarifying.  Unfortunately, I don't think the patch you provided will help my particular problem.  Allow me to elaborate.
>
> As I mentioned before, my project's integration model is to create a separate branch for every change.  Specifically, we create a branch from a recent internal tag.  So, the model for a simple bug fix looks something like this:
>
>             F---G  branch1
>           /           \
>         D  tag1  \    E  tag2
>        /                 \  /
> A---B                 C  trunk
>
> Revision B on trunk was tagged with tag1.  A bug was found in that version, so a branch was created from tag1, a fix was committed to the branch, and then the branch was merged back to trunk.  Finally, trunk is tagged with tag2.
>
> The "missing commit" messages show up when git svn fetch is fetching revision C.  It warns the there is a cherry-pick from branch1, and states that commits D and F are missing.  These commits are just copies, however; there is no code change.  The svn:mergeinfo property on trunk also only points at commit G.  Should git-svn be ignoring commits D and F, which are copy operations, not code changes?
>
> Also of note is that we very, very rarely cherry-pick commits, and never directly from a branch to trunk.  Branches are always integrated back to trunk in their entirety.
>   

Ok. Yes, I can see that. I guess what the code needs to do then is
figure out if the missing changes didn't touch the tree, and exclude
them if that happens.

in the check_cherry_pick function, try putting at the end something like;

for my $commit (keys %commits) {
if (has_no_changes($commit)) {
delete $commits{$commit};
}
}

Before the return. has_no_changes should be:

sub has_no_changes {
my $commit = shift;
# merges should always have no changes, but more
# importantly $commit~1 won't be defined for them, so
# don't proceed if that is the case.
my $num_parents = split / /, command_oneline(
qw(rev-list --parents -1 -m), $commit,
);
return 0 if $num_parents > 1;
return (command_oneline("rev-parse", "$commit^{tree}")
eq command_oneline("rev-parse", "$commit~1^{tree}"));
}

has_no_changes should also be memoized. Cherry picking a single commit
from a large unrelated branch will be slow (using cat-file --batch could
help here, but that's not something I can hack out off the cuff like
this), the first time, then it will remember whether particular commits
have changes or not.

Good luck,
Sam