X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-merge.sh;h=c2092a204035ad0315a3d37ed2f70097e68ed052;hb=511707d42b3b3e57d9623493092590546ffeae80;hp=981d69d35f4e6349d99192996af3b793071a6172;hpb=9a54463a8ab04f19a7f6127df7287320cc731a91;p=git.git diff --git a/git-merge.sh b/git-merge.sh index 981d69d35..c2092a204 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -3,7 +3,7 @@ # Copyright (c) 2005 Junio C Hamano # -USAGE='[-n] [--summary] [--no-commit] [--squash] [-s ] [-m=] +' +USAGE='[-n] [--summary] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s ] [-m=] +' SUBDIRECTORY_OK=Yes . git-sh-setup @@ -19,10 +19,12 @@ LF=' all_strategies='recur recursive octopus resolve stupid ours subtree' default_twohead_strategies='recursive' default_octopus_strategies='octopus' -no_trivial_merge_strategies='ours subtree' +no_fast_forward_strategies='subtree ours' +no_trivial_strategies='recursive recur subtree ours' use_strategies= -index_merge=t +allow_fast_forward=t +allow_trivial_merge=t dropsave() { rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \ @@ -31,7 +33,7 @@ dropsave() { savestate() { # Stash away any local modifications. - git-diff-index -z --name-only $head | + git diff-index -z --name-only $head | cpio -0 -o >"$GIT_DIR/MERGE_SAVE" } @@ -40,7 +42,7 @@ restorestate() { then git reset --hard $head >/dev/null cpio -iuv <"$GIT_DIR/MERGE_SAVE" - git-update-index --refresh >/dev/null + git update-index --refresh >/dev/null fi } @@ -57,7 +59,7 @@ finish_up_to_date () { squash_message () { echo Squashed commit of the following: echo - git-log --no-merges ^"$head" $remote + git log --no-merges ^"$head" $remoteheads } finish () { @@ -79,7 +81,8 @@ finish () { echo "No merge message -- not updating HEAD" ;; *) - git-update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1 + git update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1 + git gc --auto ;; esac ;; @@ -91,21 +94,34 @@ finish () { if test "$show_diffstat" = t then # We want color (if set), but no pager - GIT_PAGER='' git-diff --stat --summary -M "$head" "$1" + GIT_PAGER='' git diff --stat --summary -M "$head" "$1" fi ;; esac + + # Run a post-merge hook + if test -x "$GIT_DIR"/hooks/post-merge + then + case "$squash" in + t) + "$GIT_DIR"/hooks/post-merge 1 + ;; + '') + "$GIT_DIR"/hooks/post-merge 0 + ;; + esac + fi } 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) + 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 + git show-ref -q --verify "refs/heads/$truname" 2>/dev/null then echo "$rh branch '$truname' (early part) of ." elif test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD" @@ -117,11 +133,7 @@ merge_name () { fi } -case "$#" in 0) usage ;; esac - -have_message= -while case "$#" in 0) break ;; esac -do +parse_option () { case "$1" in -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\ --no-summa|--no-summar|--no-summary) @@ -129,9 +141,17 @@ do --summary) show_diffstat=t ;; --sq|--squ|--squa|--squas|--squash) - squash=t no_commit=t ;; + allow_fast_forward=t squash=t no_commit=t ;; + --no-sq|--no-squ|--no-squa|--no-squas|--no-squash) + allow_fast_forward=t squash= no_commit= ;; + --c|--co|--com|--comm|--commi|--commit) + allow_fast_forward=t squash= no_commit= ;; --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit) - no_commit=t ;; + allow_fast_forward=t squash= no_commit=t ;; + --ff) + allow_fast_forward=t squash= no_commit= ;; + --no-ff) + allow_fast_forward=false squash= no_commit= ;; -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ --strateg=*|--strategy=*|\ -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) @@ -164,13 +184,46 @@ do have_message=t ;; -*) usage ;; - *) break ;; + *) return 1 ;; esac shift + args_left=$# +} + +parse_config () { + while test $# -gt 0 + do + parse_option "$@" || usage + while test $args_left -lt $# + do + shift + done + done +} + +test $# != 0 || usage + +have_message= + +if branch=$(git-symbolic-ref -q HEAD) +then + mergeopts=$(git config "branch.${branch#refs/heads/}.mergeoptions") + if test -n "$mergeopts" + then + parse_config $mergeopts + fi +fi + +while parse_option "$@" +do + while test $args_left -lt $# + do + shift + done done if test -z "$show_diffstat"; then - test "$(git-config --bool merge.diffstat)" = false && show_diffstat=false + test "$(git config --bool merge.diffstat)" = false && show_diffstat=false test -z "$show_diffstat" && show_diffstat=t fi @@ -181,15 +234,15 @@ fi # have "-m" so it is an additional safety measure to check for it. if test -z "$have_message" && - second_token=$(git-rev-parse --verify "$2^0" 2>/dev/null) && - head_commit=$(git-rev-parse --verify "HEAD" 2>/dev/null) && + second_token=$(git rev-parse --verify "$2^0" 2>/dev/null) && + head_commit=$(git rev-parse --verify "HEAD" 2>/dev/null) && test "$second_token" = "$head_commit" then merge_msg="$1" shift head_arg="$1" shift -elif ! git-rev-parse --verify HEAD >/dev/null 2>&1 +elif ! git rev-parse --verify HEAD >/dev/null 2>&1 then # If the merged head is a valid one there is no reason to # forbid "git merge" into a branch yet to be born. We do @@ -203,8 +256,8 @@ then rh=$(git rev-parse --verify "$1^0") || die "$1 - not something we can merge" - git-update-ref -m "initial pull" HEAD "$rh" "" && - git-read-tree --reset -u HEAD + git update-ref -m "initial pull" HEAD "$rh" "" && + git read-tree --reset -u HEAD exit else @@ -219,11 +272,11 @@ else merge_name=$(for remote do merge_name "$remote" - done | git-fmt-merge-msg + done | git fmt-merge-msg ) merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name" fi -head=$(git-rev-parse --verify "$head_arg"^0) || usage +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. @@ -232,7 +285,7 @@ set_reflog_action "merge $*" remoteheads= for remote do - remotehead=$(git-rev-parse --verify "$remote"^0 2>/dev/null) || + remotehead=$(git rev-parse --verify "$remote"^0 2>/dev/null) || die "$remote - not something we can merge" remoteheads="${remoteheads}$remotehead " eval GITHEAD_$remotehead='"$remote"' @@ -244,7 +297,7 @@ case "$use_strategies" in '') case "$#" in 1) - var="`git-config --get pull.twohead`" + var="`git config --get pull.twohead`" if test -n "$var" then use_strategies="$var" @@ -252,7 +305,7 @@ case "$use_strategies" in use_strategies="$default_twohead_strategies" fi ;; *) - var="`git-config --get pull.octopus`" + var="`git config --get pull.octopus`" if test -n "$var" then use_strategies="$var" @@ -265,11 +318,20 @@ esac for s in $use_strategies do - for nt in $no_trivial_merge_strategies + for ss in $no_fast_forward_strategies do case " $s " in - *" $nt "*) - index_merge=f + *" $ss "*) + allow_fast_forward=f + break + ;; + esac + done + for ss in $no_trivial_strategies + do + case " $s " in + *" $ss "*) + allow_trivial_merge=f break ;; esac @@ -278,18 +340,15 @@ done case "$#" in 1) - common=$(git-merge-base --all $head "$@") + common=$(git merge-base --all $head "$@") ;; *) - common=$(git-show-branch --merge-base $head "$@") + common=$(git show-branch --merge-base $head "$@") ;; esac echo "$head" >"$GIT_DIR/ORIG_HEAD" -case "$index_merge,$#,$common,$no_commit" in -f,*) - # We've been told not to try anything clever. Skip to real merge. - ;; +case "$allow_fast_forward,$#,$common,$no_commit" in ?,*,'',*) # No common ancestors found. We need a real merge. ;; @@ -299,17 +358,17 @@ f,*) finish_up_to_date "Already up-to-date." exit 0 ;; -?,1,"$head",*) +t,1,"$head",*) # Again the most common case of merging one remote. - echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)" - git-update-index --refresh 2>/dev/null + echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $1)" + git update-index --refresh 2>/dev/null msg="Fast forward" if test -n "$have_message" then msg="$msg (no commit created; -m option ignored)" fi - new_head=$(git-rev-parse --verify "$1^0") && - git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && + new_head=$(git rev-parse --verify "$1^0") && + git read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" && finish "$new_head" "$msg" || exit dropsave exit 0 @@ -321,22 +380,19 @@ f,*) ?,1,*,) # We are not doing octopus, not fast forward, and have only # one common. - git-update-index --refresh 2>/dev/null - case " $use_strategies " in - *' recursive '*|*' recur '*) - : run merge later - ;; - *) + git update-index --refresh 2>/dev/null + case "$allow_trivial_merge" in + t) # 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) + if git read-tree --trivial -m -u -v $common $head "$1" && + result_tree=$(git write-tree) then echo "Wonderful." result_commit=$( printf '%s\n' "$merge_msg" | - git-commit-tree $result_tree -p HEAD -p "$1" + git commit-tree $result_tree -p HEAD -p "$1" ) || exit finish "$result_commit" "In-index merge" dropsave @@ -350,7 +406,7 @@ f,*) up_to_date=t for remote do - common_one=$(git-merge-base --all $head $remote) + common_one=$(git merge-base --all $head $remote) if test "$common_one" != "$remote" then up_to_date=f @@ -419,8 +475,8 @@ do if test "$exit" -eq 1 then cnt=`{ - git-diff-files --name-only - git-ls-files --unmerged + git diff-files --name-only + git ls-files --unmerged } | wc -l` if test $best_cnt -le 0 -o $cnt -le $best_cnt then @@ -432,15 +488,21 @@ do } # Automerge succeeded. - result_tree=$(git-write-tree) && break + result_tree=$(git write-tree) && break done # If we have a resulting tree, that means the strategy module # auto resolved the merge cleanly. if test '' != "$result_tree" then - parents=$(git-show-branch --independent "$head" "$@" | sed -e 's/^/-p /') - result_commit=$(printf '%s\n' "$merge_msg" | git-commit-tree $result_tree $parents) || exit + if test "$allow_fast_forward" = "t" + then + parents=$(git show-branch --independent "$head" "$@") + else + parents=$(git rev-parse "$head" "$@") + fi + parents=$(echo "$parents" | sed -e 's/^/-p /') + result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree $result_tree $parents) || exit finish "$result_commit" "Merge made by $wt_strategy." dropsave exit 0 @@ -496,9 +558,6 @@ Conflicts: sed -e 's/^[^ ]* / /' | uniq } >>"$GIT_DIR/MERGE_MSG" - if test -d "$GIT_DIR/rr-cache" - then - git-rerere - fi + git rerere die "Automatic merge failed; fix conflicts and then commit the result." fi