]> granicus.if.org Git - git/commitdiff
subtree: use commits before rejoins for splits
authorStrain, Roger L <roger.strain@swri.org>
Fri, 28 Sep 2018 18:35:39 +0000 (13:35 -0500)
committerJunio C Hamano <gitster@pobox.com>
Sat, 6 Oct 2018 23:09:34 +0000 (08:09 +0900)
Adds recursive evaluation of parent commits which were not part of the
initial commit list when performing a split.

Split expects all relevant commits to be reachable from the target commit
but not reachable from any previous rejoins. However, a branch could be
based on a commit prior to a rejoin, then later merged back into the
current code. In this case, a parent to the commit will not be present in
the initial list of commits, trigging an "incorrect order" warning.

Previous behavior was to consider that commit to have no parent, creating
an original commit containing all subtree content. This commit is not
present in an existing subtree commit graph, changing commit hashes and
making pushing to a subtree repo impossible.

New behavior will recursively check these unexpected parent commits to
track them back to either an earlier rejoin, or a true original commit.
The generated synthetic commits will properly match previously-generated
commits, allowing successful pushing to a prior subtree repo.

Signed-off-by: Strain, Roger L <roger.strain@swri.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
contrib/subtree/git-subtree.sh

index d8861f306593ade478ae4eb76a83d591859d154c..23dd04cbe864432f05f6fb91407dadb529dd075b 100755 (executable)
@@ -231,12 +231,14 @@ cache_miss () {
 }
 
 check_parents () {
-       missed=$(cache_miss "$@")
+       missed=$(cache_miss "$1")
+       local indent=$(($2 + 1))
        for miss in $missed
        do
                if ! test -r "$cachedir/notree/$miss"
                then
                        debug "  incorrect order: $miss"
+                       process_split_commit "$miss" "" "$indent"
                fi
        done
 }
@@ -606,8 +608,20 @@ ensure_valid_ref_format () {
 process_split_commit () {
        local rev="$1"
        local parents="$2"
-       revcount=$(($revcount + 1))
-       progress "$revcount/$revmax ($createcount)"
+       local indent=$3
+
+       if test $indent -eq 0
+       then
+               revcount=$(($revcount + 1))
+       else
+               # processing commit without normal parent information;
+               # fetch from repo
+               parents=$(git show -s --pretty=%P "$rev")
+               extracount=$(($extracount + 1))
+       fi
+
+       progress "$revcount/$revmax ($createcount) [$extracount]"
+
        debug "Processing commit: $rev"
        exists=$(cache_get "$rev")
        if test -n "$exists"
@@ -617,14 +631,13 @@ process_split_commit () {
        fi
        createcount=$(($createcount + 1))
        debug "  parents: $parents"
+       check_parents "$parents" "$indent"
        newparents=$(cache_get $parents)
        debug "  newparents: $newparents"
 
        tree=$(subtree_for_commit "$rev" "$dir")
        debug "  tree is: $tree"
 
-       check_parents $parents
-
        # ugly.  is there no better way to tell if this is a subtree
        # vs. a mainline commit?  Does it matter?
        if test -z "$tree"
@@ -744,10 +757,11 @@ cmd_split () {
        revmax=$(eval "$grl" | wc -l)
        revcount=0
        createcount=0
+       extracount=0
        eval "$grl" |
        while read rev parents
        do
-               process_split_commit "$rev" "$parents"
+               process_split_commit "$rev" "$parents" 0
        done || exit $?
 
        latest_new=$(cache_get latest_new)