subtree: improve decision on merges kept in split

When multiple identical parents are detected for a commit being considered for copying, explicitly check whether one is the common merge base between the commits. If so, the other commit can be used as the identical parent; if not, a merge must be performed to maintain history. In some situations two parents of a merge commit may appear to both have identical subtree content with each other and the current commit. However, those parents can potentially come from different commit graphs. Previous behavior would simply select one of the identical parents to serve as the replacement for this commit, based on the order in which they were processed. New behavior compares the merge base between the commits to determine if a new merge commit is necessary to maintain history despite the identical content. Signed-off-by: Strain, Roger L <roger.strain@swri.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Strain, Roger L committed Sep 28, 2018 at 13:35 UTC 68f8ff81513fb3599ef3dfc3dd11da36d868e91b
1 file changed +19 -2
contrib/subtree/git-subtree.sh
+19 -2
@@ -541,6 +541,7 @@ copy_or_skip () {
541 nonidentical=
542 p=
543 gotparents=
544 + copycommit=
545 for parent in $newparents
546 do
547 ptree=$(toptree_for_commit $parent) || exit $?
@@ -548,7 +549,24 @@ copy_or_skip () {
549 if test "$ptree" = "$tree"
550 then
551 # an identical parent could be used in place of this rev.
551 - identical="$parent"
552 + if test -n "$identical"
553 + then
554 + # if a previous identical parent was found, check whether
555 + # one is already an ancestor of the other
556 + mergebase=$(git merge-base $identical $parent)
557 + if test "$identical" = "$mergebase"
558 + then
559 + # current identical commit is an ancestor of parent
560 + identical="$parent"
561 + elif test "$parent" != "$mergebase"
562 + then
563 + # no common history; commit must be copied
564 + copycommit=1
565 + fi
566 + else
567 + # first identical parent detected
568 + identical="$parent"
569 + fi
570 else
571 nonidentical="$parent"
572 fi
@@ -571,7 +589,6 @@ copy_or_skip () {
589 fi
590 done
591
574 - copycommit=
592 if test -n "$identical" && test -n "$nonidentical"
593 then
594 extras=$(git rev-list --count $identical..$nonidentical)