mergetool: Add a test for running mergetool in a sub-directory
[gitweb.git] / git-mergetool.sh
index 507028f8597ef7a288ab7dd5c4d5a5163585380a..a4855d9444bfe5e1f5b7f4bcba402d3855c052e5 100755 (executable)
@@ -70,16 +70,16 @@ resolve_symlink_merge () {
                git checkout-index -f --stage=2 -- "$MERGED"
                git add -- "$MERGED"
                cleanup_temp_files --save-backup
-               return
+               return 0
                ;;
            [rR]*)
                git checkout-index -f --stage=3 -- "$MERGED"
                git add -- "$MERGED"
                cleanup_temp_files --save-backup
-               return
+               return 0
                ;;
            [aA]*)
-               exit 1
+               return 1
                ;;
            esac
        done
@@ -97,15 +97,15 @@ resolve_deleted_merge () {
            [mMcC]*)
                git add -- "$MERGED"
                cleanup_temp_files --save-backup
-               return
+               return 0
                ;;
            [dD]*)
                git rm -- "$MERGED" > /dev/null
                cleanup_temp_files
-               return
+               return 0
                ;;
            [aA]*)
-               exit 1
+               return 1
                ;;
            esac
        done
@@ -127,6 +127,14 @@ check_unchanged () {
     fi
 }
 
+checkout_staged_file () {
+    tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^    ]*\)    ')
+
+    if test $? -eq 0 -a -n "$tmpfile" ; then
+       mv -- "$tmpfile" "$3"
+    fi
+}
+
 merge_file () {
     MERGED="$1"
 
@@ -137,7 +145,7 @@ merge_file () {
        else
            echo "$MERGED: file does not need merging"
        fi
-       exit 1
+       return 1
     fi
 
     ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
@@ -153,9 +161,9 @@ merge_file () {
     local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'`
     remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'`
 
-    base_present   && git cat-file blob ":1:$prefix$MERGED" >"$BASE" 2>/dev/null
-    local_present  && git cat-file blob ":2:$prefix$MERGED" >"$LOCAL" 2>/dev/null
-    remote_present && git cat-file blob ":3:$prefix$MERGED" >"$REMOTE" 2>/dev/null
+    base_present   && checkout_staged_file 1 "$prefix$MERGED" "$BASE"
+    local_present  && checkout_staged_file 2 "$prefix$MERGED" "$LOCAL"
+    remote_present && checkout_staged_file 3 "$prefix$MERGED" "$REMOTE"
 
     if test -z "$local_mode" -o -z "$remote_mode"; then
        echo "Deleted merge conflict for '$MERGED':"
@@ -200,14 +208,19 @@ merge_file () {
            fi
            status=$?
            ;;
-       meld|vimdiff)
+       meld)
            touch "$BACKUP"
            "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
            check_unchanged
            ;;
+       vimdiff)
+           touch "$BACKUP"
+           "$merge_tool_path" -c "wincmd l" "$LOCAL" "$MERGED" "$REMOTE"
+           check_unchanged
+           ;;
        gvimdiff)
            touch "$BACKUP"
-           "$merge_tool_path" -f "$LOCAL" "$MERGED" "$REMOTE"
+           "$merge_tool_path" -c "wincmd l" -f "$LOCAL" "$MERGED" "$REMOTE"
            check_unchanged
            ;;
        xxdiff)
@@ -269,7 +282,12 @@ merge_file () {
     if test "$status" -ne 0; then
        echo "merge of $MERGED failed" 1>&2
        mv -- "$BACKUP" "$MERGED"
-       exit 1
+
+       if test "$merge_keep_temporaries" = "false"; then
+           cleanup_temp_files
+       fi
+
+       return 1
     fi
 
     if test "$merge_keep_backup" = "true"; then
@@ -280,6 +298,7 @@ merge_file () {
 
     git add -- "$MERGED"
     cleanup_temp_files
+    return 0
 }
 
 prompt=$(git config --bool mergetool.prompt || echo true)
@@ -306,6 +325,7 @@ do
            prompt=true
            ;;
        --)
+           shift
            break
            ;;
        -*)
@@ -350,6 +370,22 @@ init_merge_tool_path() {
        fi
 }
 
+prompt_after_failed_merge() {
+    while true; do
+       printf "Continue merging other unresolved paths (y/n) ? "
+       read ans
+       case "$ans" in
+
+           [yY]*)
+               return 0
+               ;;
+
+           [nN]*)
+               return 1
+               ;;
+       esac
+    done
+}
 
 if test -z "$merge_tool"; then
     merge_tool=`git config merge.tool`
@@ -398,6 +434,7 @@ else
     init_merge_tool_path "$merge_tool"
 
     merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
+    merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
 
     if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
         echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
@@ -409,6 +446,8 @@ else
     fi
 fi
 
+last_status=0
+rollup_status=0
 
 if test $# -eq 0 ; then
     files=`git ls-files -u | sed -e 's/^[^     ]*      //' | sort -u`
@@ -422,14 +461,29 @@ if test $# -eq 0 ; then
     sort -u |
     while IFS= read i
     do
+       if test $last_status -ne 0; then
+           prompt_after_failed_merge < /dev/tty || exit 1
+       fi
        printf "\n"
        merge_file "$i" < /dev/tty > /dev/tty
+       last_status=$?
+       if test $last_status -ne 0; then
+           rollup_status=1
+       fi
     done
 else
     while test $# -gt 0; do
+       if test $last_status -ne 0; then
+           prompt_after_failed_merge || exit 1
+       fi
        printf "\n"
        merge_file "$1"
+       last_status=$?
+       if test $last_status -ne 0; then
+           rollup_status=1
+       fi
        shift
     done
 fi
-exit 0
+
+exit $rollup_status