contrib / examples / git-merge.shon commit merge script: --squash, --ff from unborn branch are errors (22e0560)
   1#!/bin/sh
   2#
   3# Copyright (c) 2005 Junio C Hamano
   4#
   5
   6OPTIONS_KEEPDASHDASH=
   7OPTIONS_SPEC="\
   8git merge [options] <remote>...
   9git merge [options] <msg> HEAD <remote>
  10--
  11stat                 show a diffstat at the end of the merge
  12n                    don't show a diffstat at the end of the merge
  13summary              (synonym to --stat)
  14log                  add list of one-line log to merge commit message
  15squash               create a single commit instead of doing a merge
  16commit               perform a commit if the merge succeeds (default)
  17ff                   allow fast-forward (default)
  18s,strategy=          merge strategy to use
  19m,message=           message to be used for the merge commit (if any)
  20"
  21
  22SUBDIRECTORY_OK=Yes
  23. git-sh-setup
  24require_work_tree
  25cd_to_toplevel
  26
  27test -z "$(git ls-files -u)" ||
  28        die "You are in the middle of a conflicted merge."
  29
  30LF='
  31'
  32
  33all_strategies='recur recursive octopus resolve stupid ours subtree'
  34all_strategies="$all_strategies recursive-ours recursive-theirs"
  35default_twohead_strategies='recursive'
  36default_octopus_strategies='octopus'
  37no_fast_forward_strategies='subtree ours'
  38no_trivial_strategies='recursive recur subtree ours recursive-ours recursive-theirs'
  39use_strategies=
  40
  41allow_fast_forward=t
  42allow_trivial_merge=t
  43squash= no_commit= log_arg=
  44
  45dropsave() {
  46        rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
  47                 "$GIT_DIR/MERGE_STASH" || exit 1
  48}
  49
  50savestate() {
  51        # Stash away any local modifications.
  52        git stash create >"$GIT_DIR/MERGE_STASH"
  53}
  54
  55restorestate() {
  56        if test -f "$GIT_DIR/MERGE_STASH"
  57        then
  58                git reset --hard $head >/dev/null
  59                git stash apply $(cat "$GIT_DIR/MERGE_STASH")
  60                git update-index --refresh >/dev/null
  61        fi
  62}
  63
  64finish_up_to_date () {
  65        case "$squash" in
  66        t)
  67                echo "$1 (nothing to squash)" ;;
  68        '')
  69                echo "$1" ;;
  70        esac
  71        dropsave
  72}
  73
  74squash_message () {
  75        echo Squashed commit of the following:
  76        echo
  77        git log --no-merges --pretty=medium ^"$head" $remoteheads
  78}
  79
  80finish () {
  81        if test '' = "$2"
  82        then
  83                rlogm="$GIT_REFLOG_ACTION"
  84        else
  85                echo "$2"
  86                rlogm="$GIT_REFLOG_ACTION: $2"
  87        fi
  88        case "$squash" in
  89        t)
  90                echo "Squash commit -- not updating HEAD"
  91                squash_message >"$GIT_DIR/SQUASH_MSG"
  92                ;;
  93        '')
  94                case "$merge_msg" in
  95                '')
  96                        echo "No merge message -- not updating HEAD"
  97                        ;;
  98                *)
  99                        git update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1
 100                        git gc --auto
 101                        ;;
 102                esac
 103                ;;
 104        esac
 105        case "$1" in
 106        '')
 107                ;;
 108        ?*)
 109                if test "$show_diffstat" = t
 110                then
 111                        # We want color (if set), but no pager
 112                        GIT_PAGER='' git diff --stat --summary -M "$head" "$1"
 113                fi
 114                ;;
 115        esac
 116
 117        # Run a post-merge hook
 118        if test -x "$GIT_DIR"/hooks/post-merge
 119        then
 120            case "$squash" in
 121            t)
 122                "$GIT_DIR"/hooks/post-merge 1
 123                ;;
 124            '')
 125                "$GIT_DIR"/hooks/post-merge 0
 126                ;;
 127            esac
 128        fi
 129}
 130
 131merge_name () {
 132        remote="$1"
 133        rh=$(git rev-parse --verify "$remote^0" 2>/dev/null) || return
 134        bh=$(git show-ref -s --verify "refs/heads/$remote" 2>/dev/null)
 135        if test "$rh" = "$bh"
 136        then
 137                echo "$rh               branch '$remote' of ."
 138        elif truname=$(expr "$remote" : '\(.*\)~[1-9][0-9]*$') &&
 139                git show-ref -q --verify "refs/heads/$truname" 2>/dev/null
 140        then
 141                echo "$rh               branch '$truname' (early part) of ."
 142        elif test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD"
 143        then
 144                sed -e 's/      not-for-merge   /               /' -e 1q \
 145                        "$GIT_DIR/FETCH_HEAD"
 146        else
 147                echo "$rh               commit '$remote'"
 148        fi
 149}
 150
 151parse_config () {
 152        while test $# != 0; do
 153                case "$1" in
 154                -n|--no-stat|--no-summary)
 155                        show_diffstat=false ;;
 156                --stat|--summary)
 157                        show_diffstat=t ;;
 158                --log|--no-log)
 159                        log_arg=$1 ;;
 160                --squash)
 161                        test "$allow_fast_forward" = t ||
 162                                die "You cannot combine --squash with --no-ff."
 163                        squash=t no_commit=t ;;
 164                --no-squash)
 165                        squash= no_commit= ;;
 166                --commit)
 167                        no_commit= ;;
 168                --no-commit)
 169                        no_commit=t ;;
 170                --ff)
 171                        allow_fast_forward=t ;;
 172                --no-ff)
 173                        test "$squash" != t ||
 174                                die "You cannot combine --squash with --no-ff."
 175                        allow_fast_forward=f ;;
 176                -s|--strategy)
 177                        shift
 178                        case " $all_strategies " in
 179                        *" $1 "*)
 180                                use_strategies="$use_strategies$1 " ;;
 181                        *)
 182                                die "available strategies are: $all_strategies" ;;
 183                        esac
 184                        ;;
 185                -m|--message)
 186                        shift
 187                        merge_msg="$1"
 188                        have_message=t
 189                        ;;
 190                --)
 191                        shift
 192                        break ;;
 193                *)      usage ;;
 194                esac
 195                shift
 196        done
 197        args_left=$#
 198}
 199
 200test $# != 0 || usage
 201
 202have_message=
 203
 204if branch=$(git-symbolic-ref -q HEAD)
 205then
 206        mergeopts=$(git config "branch.${branch#refs/heads/}.mergeoptions")
 207        if test -n "$mergeopts"
 208        then
 209                parse_config $mergeopts --
 210        fi
 211fi
 212
 213parse_config "$@"
 214while test $args_left -lt $#; do shift; done
 215
 216if test -z "$show_diffstat"; then
 217    test "$(git config --bool merge.diffstat)" = false && show_diffstat=false
 218    test "$(git config --bool merge.stat)" = false && show_diffstat=false
 219    test -z "$show_diffstat" && show_diffstat=t
 220fi
 221
 222# This could be traditional "merge <msg> HEAD <commit>..."  and the
 223# way we can tell it is to see if the second token is HEAD, but some
 224# people might have misused the interface and used a committish that
 225# is the same as HEAD there instead.  Traditional format never would
 226# have "-m" so it is an additional safety measure to check for it.
 227
 228if test -z "$have_message" &&
 229        second_token=$(git rev-parse --verify "$2^0" 2>/dev/null) &&
 230        head_commit=$(git rev-parse --verify "HEAD" 2>/dev/null) &&
 231        test "$second_token" = "$head_commit"
 232then
 233        merge_msg="$1"
 234        shift
 235        head_arg="$1"
 236        shift
 237elif ! git rev-parse --verify HEAD >/dev/null 2>&1
 238then
 239        # If the merged head is a valid one there is no reason to
 240        # forbid "git merge" into a branch yet to be born.  We do
 241        # the same for "git pull".
 242        if test 1 -ne $#
 243        then
 244                echo >&2 "Can merge only exactly one commit into empty head"
 245                exit 1
 246        fi
 247
 248        test "$squash" != t ||
 249                die "Squash commit into empty head not supported yet"
 250        test "$allow_fast_forward" = t ||
 251                die "Non-fast-forward into an empty head does not make sense"
 252        rh=$(git rev-parse --verify "$1^0") ||
 253                die "$1 - not something we can merge"
 254
 255        git update-ref -m "initial pull" HEAD "$rh" "" &&
 256        git read-tree --reset -u HEAD
 257        exit
 258
 259else
 260        # We are invoked directly as the first-class UI.
 261        head_arg=HEAD
 262
 263        # All the rest are the commits being merged; prepare
 264        # the standard merge summary message to be appended to
 265        # the given message.  If remote is invalid we will die
 266        # later in the common codepath so we discard the error
 267        # in this loop.
 268        merge_name=$(for remote
 269                do
 270                        merge_name "$remote"
 271                done | git fmt-merge-msg $log_arg
 272        )
 273        merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name"
 274fi
 275head=$(git rev-parse --verify "$head_arg"^0) || usage
 276
 277# All the rest are remote heads
 278test "$#" = 0 && usage ;# we need at least one remote head.
 279set_reflog_action "merge $*"
 280
 281remoteheads=
 282for remote
 283do
 284        remotehead=$(git rev-parse --verify "$remote"^0 2>/dev/null) ||
 285            die "$remote - not something we can merge"
 286        remoteheads="${remoteheads}$remotehead "
 287        eval GITHEAD_$remotehead='"$remote"'
 288        export GITHEAD_$remotehead
 289done
 290set x $remoteheads ; shift
 291
 292case "$use_strategies" in
 293'')
 294        case "$#" in
 295        1)
 296                var="`git config --get pull.twohead`"
 297                if test -n "$var"
 298                then
 299                        use_strategies="$var"
 300                else
 301                        use_strategies="$default_twohead_strategies"
 302                fi ;;
 303        *)
 304                var="`git config --get pull.octopus`"
 305                if test -n "$var"
 306                then
 307                        use_strategies="$var"
 308                else
 309                        use_strategies="$default_octopus_strategies"
 310                fi ;;
 311        esac
 312        ;;
 313esac
 314
 315for s in $use_strategies
 316do
 317        for ss in $no_fast_forward_strategies
 318        do
 319                case " $s " in
 320                *" $ss "*)
 321                        allow_fast_forward=f
 322                        break
 323                        ;;
 324                esac
 325        done
 326        for ss in $no_trivial_strategies
 327        do
 328                case " $s " in
 329                *" $ss "*)
 330                        allow_trivial_merge=f
 331                        break
 332                        ;;
 333                esac
 334        done
 335done
 336
 337case "$#" in
 3381)
 339        common=$(git merge-base --all $head "$@")
 340        ;;
 341*)
 342        common=$(git show-branch --merge-base $head "$@")
 343        ;;
 344esac
 345echo "$head" >"$GIT_DIR/ORIG_HEAD"
 346
 347case "$allow_fast_forward,$#,$common,$no_commit" in
 348?,*,'',*)
 349        # No common ancestors found. We need a real merge.
 350        ;;
 351?,1,"$1",*)
 352        # If head can reach all the merge then we are up to date.
 353        # but first the most common case of merging one remote.
 354        finish_up_to_date "Already up-to-date."
 355        exit 0
 356        ;;
 357t,1,"$head",*)
 358        # Again the most common case of merging one remote.
 359        echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $1)"
 360        git update-index --refresh 2>/dev/null
 361        msg="Fast-forward"
 362        if test -n "$have_message"
 363        then
 364                msg="$msg (no commit created; -m option ignored)"
 365        fi
 366        new_head=$(git rev-parse --verify "$1^0") &&
 367        git read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" &&
 368        finish "$new_head" "$msg" || exit
 369        dropsave
 370        exit 0
 371        ;;
 372?,1,?*"$LF"?*,*)
 373        # We are not doing octopus and not fast-forward.  Need a
 374        # real merge.
 375        ;;
 376?,1,*,)
 377        # We are not doing octopus, not fast-forward, and have only
 378        # one common.
 379        git update-index --refresh 2>/dev/null
 380        case "$allow_trivial_merge" in
 381        t)
 382                # See if it is really trivial.
 383                git var GIT_COMMITTER_IDENT >/dev/null || exit
 384                echo "Trying really trivial in-index merge..."
 385                if git read-tree --trivial -m -u -v $common $head "$1" &&
 386                   result_tree=$(git write-tree)
 387                then
 388                        echo "Wonderful."
 389                        result_commit=$(
 390                                printf '%s\n' "$merge_msg" |
 391                                git commit-tree $result_tree -p HEAD -p "$1"
 392                        ) || exit
 393                        finish "$result_commit" "In-index merge"
 394                        dropsave
 395                        exit 0
 396                fi
 397                echo "Nope."
 398        esac
 399        ;;
 400*)
 401        # An octopus.  If we can reach all the remote we are up to date.
 402        up_to_date=t
 403        for remote
 404        do
 405                common_one=$(git merge-base --all $head $remote)
 406                if test "$common_one" != "$remote"
 407                then
 408                        up_to_date=f
 409                        break
 410                fi
 411        done
 412        if test "$up_to_date" = t
 413        then
 414                finish_up_to_date "Already up-to-date. Yeeah!"
 415                exit 0
 416        fi
 417        ;;
 418esac
 419
 420# We are going to make a new commit.
 421git var GIT_COMMITTER_IDENT >/dev/null || exit
 422
 423# At this point, we need a real merge.  No matter what strategy
 424# we use, it would operate on the index, possibly affecting the
 425# working tree, and when resolved cleanly, have the desired tree
 426# in the index -- this means that the index must be in sync with
 427# the $head commit.  The strategies are responsible to ensure this.
 428
 429case "$use_strategies" in
 430?*' '?*)
 431    # Stash away the local changes so that we can try more than one.
 432    savestate
 433    single_strategy=no
 434    ;;
 435*)
 436    rm -f "$GIT_DIR/MERGE_STASH"
 437    single_strategy=yes
 438    ;;
 439esac
 440
 441result_tree= best_cnt=-1 best_strategy= wt_strategy=
 442merge_was_ok=
 443for strategy in $use_strategies
 444do
 445    test "$wt_strategy" = '' || {
 446        echo "Rewinding the tree to pristine..."
 447        restorestate
 448    }
 449    case "$single_strategy" in
 450    no)
 451        echo "Trying merge strategy $strategy..."
 452        ;;
 453    esac
 454
 455    # Remember which strategy left the state in the working tree
 456    wt_strategy=$strategy
 457
 458    git-merge-$strategy $common -- "$head_arg" "$@"
 459    exit=$?
 460    if test "$no_commit" = t && test "$exit" = 0
 461    then
 462        merge_was_ok=t
 463        exit=1 ;# pretend it left conflicts.
 464    fi
 465
 466    test "$exit" = 0 || {
 467
 468        # The backend exits with 1 when conflicts are left to be resolved,
 469        # with 2 when it does not handle the given merge at all.
 470
 471        if test "$exit" -eq 1
 472        then
 473            cnt=`{
 474                git diff-files --name-only
 475                git ls-files --unmerged
 476            } | wc -l`
 477            if test $best_cnt -le 0 -o $cnt -le $best_cnt
 478            then
 479                best_strategy=$strategy
 480                best_cnt=$cnt
 481            fi
 482        fi
 483        continue
 484    }
 485
 486    # Automerge succeeded.
 487    result_tree=$(git write-tree) && break
 488done
 489
 490# If we have a resulting tree, that means the strategy module
 491# auto resolved the merge cleanly.
 492if test '' != "$result_tree"
 493then
 494    if test "$allow_fast_forward" = "t"
 495    then
 496        parents=$(git show-branch --independent "$head" "$@")
 497    else
 498        parents=$(git rev-parse "$head" "$@")
 499    fi
 500    parents=$(echo "$parents" | sed -e 's/^/-p /')
 501    result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree $result_tree $parents) || exit
 502    finish "$result_commit" "Merge made by $wt_strategy."
 503    dropsave
 504    exit 0
 505fi
 506
 507# Pick the result from the best strategy and have the user fix it up.
 508case "$best_strategy" in
 509'')
 510        restorestate
 511        case "$use_strategies" in
 512        ?*' '?*)
 513                echo >&2 "No merge strategy handled the merge."
 514                ;;
 515        *)
 516                echo >&2 "Merge with strategy $use_strategies failed."
 517                ;;
 518        esac
 519        exit 2
 520        ;;
 521"$wt_strategy")
 522        # We already have its result in the working tree.
 523        ;;
 524*)
 525        echo "Rewinding the tree to pristine..."
 526        restorestate
 527        echo "Using the $best_strategy to prepare resolving by hand."
 528        git-merge-$best_strategy $common -- "$head_arg" "$@"
 529        ;;
 530esac
 531
 532if test "$squash" = t
 533then
 534        finish
 535else
 536        for remote
 537        do
 538                echo $remote
 539        done >"$GIT_DIR/MERGE_HEAD"
 540        printf '%s\n' "$merge_msg" >"$GIT_DIR/MERGE_MSG"
 541fi
 542
 543if test "$merge_was_ok" = t
 544then
 545        echo >&2 \
 546        "Automatic merge went well; stopped before committing as requested"
 547        exit 0
 548else
 549        {
 550            echo '
 551Conflicts:
 552'
 553                git ls-files --unmerged |
 554                sed -e 's/^[^   ]*      /       /' |
 555                uniq
 556        } >>"$GIT_DIR/MERGE_MSG"
 557        git rerere
 558        die "Automatic merge failed; fix conflicts and then commit the result."
 559fi