cherry-pick: Suggest a better method to retain authorship
[gitweb.git] / git-merge.sh
index 75af10d3e431edf6f7447ab4a3dfcf84e994a2ef..4afcd95316c01e5d1811184c615c4da574ab0717 100755 (executable)
@@ -3,9 +3,15 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [--reflog-action=<action>] [-m=<merge-message>] <commit>+'
+USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commit>+'
 
+SUBDIRECTORY_OK=Yes
 . git-sh-setup
+require_work_tree
+cd_to_toplevel
+
+test -z "$(git ls-files -u)" ||
+       die "You are in the middle of a conflicted merge."
 
 LF='
 '
@@ -32,7 +38,7 @@ savestate() {
 restorestate() {
         if test -f "$GIT_DIR/MERGE_SAVE"
        then
-               git reset --hard $head
+               git reset --hard $head >/dev/null
                cpio -iuv <"$GIT_DIR/MERGE_SAVE"
                git-update-index --refresh >/dev/null
        fi
@@ -57,10 +63,10 @@ squash_message () {
 finish () {
        if test '' = "$2"
        then
-               rlogm="$rloga"
+               rlogm="$GIT_REFLOG_ACTION"
        else
                echo "$2"
-               rlogm="$rloga: $2"
+               rlogm="$GIT_REFLOG_ACTION: $2"
        fi
        case "$squash" in
        t)
@@ -91,9 +97,25 @@ finish () {
        esac
 }
 
+merge_name () {
+       remote="$1"
+       rh=$(git-rev-parse --verify "$remote^0" 2>/dev/null) || return
+       bh=$(git-show-ref -s --verify "refs/heads/$remote" 2>/dev/null)
+       if test "$rh" = "$bh"
+       then
+               echo "$rh               branch '$remote' of ."
+       elif truname=$(expr "$remote" : '\(.*\)~[1-9][0-9]*$') &&
+               git-show-ref -q --verify "refs/heads/$truname" 2>/dev/null
+       then
+               echo "$rh               branch '$truname' (early part) of ."
+       else
+               echo "$rh               commit '$remote'"
+       fi
+}
+
 case "$#" in 0) usage ;; esac
 
-rloga= have_message=
+have_message=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -123,9 +145,6 @@ do
                        die "available strategies are: $all_strategies" ;;
                esac
                ;;
-       --reflog-action=*)
-               rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-               ;;
        -m=*|--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
                merge_msg=`expr "z$1" : 'z-[^=]*=\(.*\)'`
                have_message=t
@@ -188,14 +207,7 @@ else
        # in this loop.
        merge_name=$(for remote
                do
-                       rh=$(git-rev-parse --verify "$remote"^0 2>/dev/null) &&
-                       if git show-ref -q --verify "refs/heads/$remote"
-                       then
-                               what=branch
-                       else
-                               what=commit
-                       fi &&
-                       echo "$rh               $what '$remote'"
+                       merge_name "$remote"
                done | git-fmt-merge-msg
        )
        merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name"
@@ -204,7 +216,7 @@ head=$(git-rev-parse --verify "$head_arg"^0) || usage
 
 # All the rest are remote heads
 test "$#" = 0 && usage ;# we need at least one remote head.
-test "$rloga" = '' && rloga="merge: $@"
+set_reflog_action "merge $*"
 
 remoteheads=
 for remote
@@ -212,6 +224,8 @@ do
        remotehead=$(git-rev-parse --verify "$remote"^0 2>/dev/null) ||
            die "$remote - not something we can merge"
        remoteheads="${remoteheads}$remotehead "
+       eval GITHEAD_$remotehead='"$remote"'
+       export GITHEAD_$remotehead
 done
 set x $remoteheads ; shift
 
@@ -219,21 +233,36 @@ case "$use_strategies" in
 '')
        case "$#" in
        1)
-               use_strategies="$default_twohead_strategies" ;;
+               var="`git-config --get pull.twohead`"
+               if test -n "$var"
+               then
+                       use_strategies="$var"
+               else
+                       use_strategies="$default_twohead_strategies"
+               fi ;;
        *)
-               use_strategies="$default_octopus_strategies" ;;
+               var="`git-config --get pull.octopus`"
+               if test -n "$var"
+               then
+                       use_strategies="$var"
+               else
+                       use_strategies="$default_octopus_strategies"
+               fi ;;
        esac
        ;;
 esac
 
 for s in $use_strategies
 do
-       case " $s " in
-       *" $no_trivial_merge_strategies "*)
-               index_merge=f
-               break
-               ;;
-       esac
+       for nt in $no_trivial_merge_strategies
+       do
+               case " $s " in
+               *" $nt "*)
+                       index_merge=f
+                       break
+                       ;;
+               esac
+       done
 done
 
 case "$#" in
@@ -264,8 +293,8 @@ f,*)
        echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)"
        git-update-index --refresh 2>/dev/null
        new_head=$(git-rev-parse --verify "$1^0") &&
-       git-read-tree -u -v -m $head "$new_head" &&
-       finish "$new_head" "Fast forward"
+       git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" &&
+       finish "$new_head" "Fast forward" || exit
        dropsave
        exit 0
        ;;
@@ -275,24 +304,30 @@ f,*)
        ;;
 ?,1,*,)
        # We are not doing octopus, not fast forward, and have only
-       # one common.  See if it is really trivial.
-       git var GIT_COMMITTER_IDENT >/dev/null || exit
-
-       echo "Trying really trivial in-index merge..."
+       # one common.
        git-update-index --refresh 2>/dev/null
-       if git-read-tree --trivial -m -u -v $common $head "$1" &&
-          result_tree=$(git-write-tree)
-       then
-           echo "Wonderful."
-           result_commit=$(
-               echo "$merge_msg" |
-               git-commit-tree $result_tree -p HEAD -p "$1"
-           ) || exit
-           finish "$result_commit" "In-index merge"
-           dropsave
-           exit 0
-       fi
-       echo "Nope."
+       case " $use_strategies " in
+       *' recursive '*|*' recur '*)
+               : run merge later
+               ;;
+       *)
+               # See if it is really trivial.
+               git var GIT_COMMITTER_IDENT >/dev/null || exit
+               echo "Trying really trivial in-index merge..."
+               if git-read-tree --trivial -m -u -v $common $head "$1" &&
+                  result_tree=$(git-write-tree)
+               then
+                       echo "Wonderful."
+                       result_commit=$(
+                               echo "$merge_msg" |
+                               git-commit-tree $result_tree -p HEAD -p "$1"
+                       ) || exit
+                       finish "$result_commit" "In-index merge"
+                       dropsave
+                       exit 0
+               fi
+               echo "Nope."
+       esac
        ;;
 *)
        # An octopus.  If we can reach all the remote we are up to date.
@@ -399,7 +434,14 @@ fi
 case "$best_strategy" in
 '')
        restorestate
-       echo >&2 "No merge strategy handled the merge."
+       case "$use_strategies" in
+       ?*' '?*)
+               echo >&2 "No merge strategy handled the merge."
+               ;;
+       *)
+               echo >&2 "Merge with strategy $use_strategies failed."
+               ;;
+       esac
        exit 2
        ;;
 "$wt_strategy")