Simplify merges even more aggressively.
[gitweb.git] / git-subtree.sh
index aeafadac95d4bb25e38d90ee58d0d9ba4f85d59f..e2e47f82ac9c86035d9ed9ab84a24e8bc7c7626e 100755 (executable)
@@ -17,6 +17,7 @@ h,help        show the help
 q             quiet
 prefix=       the name of the subdir to split out
  options for 'split'
+annotate=     add a prefix to commit message of new commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
 ignore-joins  ignore prior --rejoin commits
@@ -30,6 +31,7 @@ command=
 onto=
 rejoin=
 ignore_joins=
+annotate=
 
 debug()
 {
@@ -55,6 +57,8 @@ while [ $# -gt 0 ]; do
        shift
        case "$opt" in
                -q) quiet=1 ;;
+               --annotate) annotate="$1"; shift ;;
+               --no-annotate) annotate= ;;
                --prefix) prefix="$1"; shift ;;
                --no-prefix) prefix= ;;
                --onto) onto="$1"; shift ;;
@@ -141,7 +145,7 @@ find_existing_splits()
        dir="$1"
        revs="$2"
        git log --grep="^git-subtree-dir: $dir\$" \
-               --pretty=format:'%s%n%n%b%nEND' "$revs" |
+               --pretty=format:'%s%n%n%b%nEND' $revs |
        while read a b junk; do
                case "$a" in
                        git-subtree-mainline:) main="$b" ;;
@@ -164,6 +168,7 @@ copy_commit()
 {
        # We're doing to set some environment vars here, so
        # do it in a subshell to get rid of them safely later
+       debug copy_commit "{$1}" "{$2}" "{$3}"
        git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b' "$1" |
        (
                read GIT_AUTHOR_NAME
@@ -178,7 +183,7 @@ copy_commit()
                        GIT_COMMITTER_NAME \
                        GIT_COMMITTER_EMAIL \
                        GIT_COMMITTER_DATE
-               (echo -n '*'; cat ) |  # FIXME
+               (echo -n "$annotate"; cat ) |
                git commit-tree "$2" $3  # reads the rest of stdin
        ) || die "Can't copy commit $1"
 }
@@ -253,20 +258,35 @@ copy_or_skip()
        assert [ -n "$tree" ]
 
        identical=
+       nonidentical=
        p=
+       gotparents=
        for parent in $newparents; do
                ptree=$(toptree_for_commit $parent) || exit $?
+               [ -z "$ptree" ] && continue
                if [ "$ptree" = "$tree" ]; then
                        # an identical parent could be used in place of this rev.
                        identical="$parent"
+               else
+                       nonidentical="$parent"
                fi
-               if [ -n "$ptree" ]; then
-                       parentmatch="$parentmatch$parent"
+               
+               # sometimes both old parents map to the same newparent;
+               # eliminate duplicates
+               is_new=1
+               for gp in $gotparents; do
+                       if [ "$gp" = "$parent" ]; then
+                               is_new=
+                               break
+                       fi
+               done
+               if [ -n "$is_new" ]; then
+                       gotparents="$gotparents $parent"
                        p="$p -p $parent"
                fi
        done
        
-       if [ -n "$identical" -a "$parentmatch" = "$identical" ]; then
+       if [ -n "$identical" ]; then
                echo $identical
        else
                copy_commit $rev $tree "$p" || exit $?
@@ -334,9 +354,9 @@ cmd_split()
                unrevs="$(find_existing_splits "$dir" "$revs")"
        fi
        
-       # We can't restrict rev-list to only "$dir" here, because that leaves out
-       # critical information about commit parents.
-       debug "git rev-list --reverse --parents $revs $unrevs"
+       # We can't restrict rev-list to only $dir here, because some of our
+       # parents have the $dir contents the root, and those won't match.
+       # (and rev-list --follow doesn't seem to solve this)
        git rev-list --reverse --parents $revs $unrevs |
        while read rev parents; do
                debug