git-mergetool--lib.shon commit t/t7503-pre-commit-hook.sh: Add GIT_PREFIX tests (c35ec8c)
   1#!/bin/sh
   2# git-mergetool--lib is a library for common merge tool functions
   3diff_mode() {
   4        test "$TOOL_MODE" = diff
   5}
   6
   7merge_mode() {
   8        test "$TOOL_MODE" = merge
   9}
  10
  11translate_merge_tool_path () {
  12        case "$1" in
  13        araxis)
  14                echo compare
  15                ;;
  16        bc3)
  17                echo bcompare
  18                ;;
  19        emerge)
  20                echo emacs
  21                ;;
  22        gvimdiff|gvimdiff2)
  23                echo gvim
  24                ;;
  25        vimdiff|vimdiff2)
  26                echo vim
  27                ;;
  28        *)
  29                echo "$1"
  30                ;;
  31        esac
  32}
  33
  34check_unchanged () {
  35        if test "$MERGED" -nt "$BACKUP"; then
  36                status=0
  37        else
  38                while true; do
  39                        echo "$MERGED seems unchanged."
  40                        printf "Was the merge successful? [y/n] "
  41                        read answer
  42                        case "$answer" in
  43                        y*|Y*) status=0; break ;;
  44                        n*|N*) status=1; break ;;
  45                        esac
  46                done
  47        fi
  48}
  49
  50valid_tool () {
  51        case "$1" in
  52        araxis | bc3 | diffuse | ecmerge | emerge | gvimdiff | gvimdiff2 | \
  53        kdiff3 | meld | opendiff | p4merge | tkdiff | vimdiff | vimdiff2 | xxdiff)
  54                ;; # happy
  55        kompare)
  56                if ! diff_mode; then
  57                        return 1
  58                fi
  59                ;;
  60        tortoisemerge)
  61                if ! merge_mode; then
  62                        return 1
  63                fi
  64                ;;
  65        *)
  66                if test -z "$(get_merge_tool_cmd "$1")"; then
  67                        return 1
  68                fi
  69                ;;
  70        esac
  71}
  72
  73get_merge_tool_cmd () {
  74        # Prints the custom command for a merge tool
  75        if test -n "$1"; then
  76                merge_tool="$1"
  77        else
  78                merge_tool="$(get_merge_tool)"
  79        fi
  80        if diff_mode; then
  81                echo "$(git config difftool.$merge_tool.cmd ||
  82                        git config mergetool.$merge_tool.cmd)"
  83        else
  84                echo "$(git config mergetool.$merge_tool.cmd)"
  85        fi
  86}
  87
  88run_merge_tool () {
  89        # If GIT_PREFIX is empty then we cannot use it in tools
  90        # that expect to be able to chdir() to its value.
  91        GIT_PREFIX=${GIT_PREFIX:-.}
  92        export GIT_PREFIX
  93
  94        merge_tool_path="$(get_merge_tool_path "$1")" || exit
  95        base_present="$2"
  96        status=0
  97
  98        case "$1" in
  99        araxis)
 100                if merge_mode; then
 101                        touch "$BACKUP"
 102                        if $base_present; then
 103                                "$merge_tool_path" -wait -merge -3 -a1 \
 104                                        "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
 105                                        >/dev/null 2>&1
 106                        else
 107                                "$merge_tool_path" -wait -2 \
 108                                        "$LOCAL" "$REMOTE" "$MERGED" \
 109                                        >/dev/null 2>&1
 110                        fi
 111                        check_unchanged
 112                else
 113                        "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
 114                                >/dev/null 2>&1
 115                fi
 116                ;;
 117        bc3)
 118                if merge_mode; then
 119                        touch "$BACKUP"
 120                        if $base_present; then
 121                                "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" \
 122                                        -mergeoutput="$MERGED"
 123                        else
 124                                "$merge_tool_path" "$LOCAL" "$REMOTE" \
 125                                        -mergeoutput="$MERGED"
 126                        fi
 127                        check_unchanged
 128                else
 129                        "$merge_tool_path" "$LOCAL" "$REMOTE"
 130                fi
 131                ;;
 132        diffuse)
 133                if merge_mode; then
 134                        touch "$BACKUP"
 135                        if $base_present; then
 136                                "$merge_tool_path" \
 137                                        "$LOCAL" "$MERGED" "$REMOTE" \
 138                                        "$BASE" | cat
 139                        else
 140                                "$merge_tool_path" \
 141                                        "$LOCAL" "$MERGED" "$REMOTE" | cat
 142                        fi
 143                        check_unchanged
 144                else
 145                        "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
 146                fi
 147                ;;
 148        ecmerge)
 149                if merge_mode; then
 150                        touch "$BACKUP"
 151                        if $base_present; then
 152                                "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
 153                                        --default --mode=merge3 --to="$MERGED"
 154                        else
 155                                "$merge_tool_path" "$LOCAL" "$REMOTE" \
 156                                        --default --mode=merge2 --to="$MERGED"
 157                        fi
 158                        check_unchanged
 159                else
 160                        "$merge_tool_path" --default --mode=diff2 \
 161                                "$LOCAL" "$REMOTE"
 162                fi
 163                ;;
 164        emerge)
 165                if merge_mode; then
 166                        if $base_present; then
 167                                "$merge_tool_path" \
 168                                        -f emerge-files-with-ancestor-command \
 169                                        "$LOCAL" "$REMOTE" "$BASE" \
 170                                        "$(basename "$MERGED")"
 171                        else
 172                                "$merge_tool_path" \
 173                                        -f emerge-files-command \
 174                                        "$LOCAL" "$REMOTE" \
 175                                        "$(basename "$MERGED")"
 176                        fi
 177                        status=$?
 178                else
 179                        "$merge_tool_path" -f emerge-files-command \
 180                                "$LOCAL" "$REMOTE"
 181                fi
 182                ;;
 183        gvimdiff|vimdiff)
 184                if merge_mode; then
 185                        touch "$BACKUP"
 186                        if $base_present; then
 187                                "$merge_tool_path" -f -d -c "wincmd J" \
 188                                        "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
 189                        else
 190                                "$merge_tool_path" -f -d -c "wincmd l" \
 191                                        "$LOCAL" "$MERGED" "$REMOTE"
 192                        fi
 193                        check_unchanged
 194                else
 195                        "$merge_tool_path" -R -f -d -c "wincmd l" \
 196                                -c 'cd $GIT_PREFIX' \
 197                                "$LOCAL" "$REMOTE"
 198                fi
 199                ;;
 200        gvimdiff2|vimdiff2)
 201                if merge_mode; then
 202                        touch "$BACKUP"
 203                        "$merge_tool_path" -f -d -c "wincmd l" \
 204                                "$LOCAL" "$MERGED" "$REMOTE"
 205                        check_unchanged
 206                else
 207                        "$merge_tool_path" -R -f -d -c "wincmd l" \
 208                                -c 'cd $GIT_PREFIX' \
 209                                "$LOCAL" "$REMOTE"
 210                fi
 211                ;;
 212        kdiff3)
 213                if merge_mode; then
 214                        if $base_present; then
 215                                ("$merge_tool_path" --auto \
 216                                        --L1 "$MERGED (Base)" \
 217                                        --L2 "$MERGED (Local)" \
 218                                        --L3 "$MERGED (Remote)" \
 219                                        -o "$MERGED" \
 220                                        "$BASE" "$LOCAL" "$REMOTE" \
 221                                > /dev/null 2>&1)
 222                        else
 223                                ("$merge_tool_path" --auto \
 224                                        --L1 "$MERGED (Local)" \
 225                                        --L2 "$MERGED (Remote)" \
 226                                        -o "$MERGED" \
 227                                        "$LOCAL" "$REMOTE" \
 228                                > /dev/null 2>&1)
 229                        fi
 230                        status=$?
 231                else
 232                        ("$merge_tool_path" --auto \
 233                                --L1 "$MERGED (A)" \
 234                                --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
 235                        > /dev/null 2>&1)
 236                fi
 237                ;;
 238        kompare)
 239                "$merge_tool_path" "$LOCAL" "$REMOTE"
 240                ;;
 241        meld)
 242                if merge_mode; then
 243                        touch "$BACKUP"
 244                        "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
 245                        check_unchanged
 246                else
 247                        "$merge_tool_path" "$LOCAL" "$REMOTE"
 248                fi
 249                ;;
 250        opendiff)
 251                if merge_mode; then
 252                        touch "$BACKUP"
 253                        if $base_present; then
 254                                "$merge_tool_path" "$LOCAL" "$REMOTE" \
 255                                        -ancestor "$BASE" \
 256                                        -merge "$MERGED" | cat
 257                        else
 258                                "$merge_tool_path" "$LOCAL" "$REMOTE" \
 259                                        -merge "$MERGED" | cat
 260                        fi
 261                        check_unchanged
 262                else
 263                        "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
 264                fi
 265                ;;
 266        p4merge)
 267                if merge_mode; then
 268                    touch "$BACKUP"
 269                        if $base_present; then
 270                                "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
 271                        else
 272                                "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
 273                        fi
 274                        check_unchanged
 275                else
 276                        "$merge_tool_path" "$LOCAL" "$REMOTE"
 277                fi
 278                ;;
 279        tkdiff)
 280                if merge_mode; then
 281                        if $base_present; then
 282                                "$merge_tool_path" -a "$BASE" \
 283                                        -o "$MERGED" "$LOCAL" "$REMOTE"
 284                        else
 285                                "$merge_tool_path" \
 286                                        -o "$MERGED" "$LOCAL" "$REMOTE"
 287                        fi
 288                        status=$?
 289                else
 290                        "$merge_tool_path" "$LOCAL" "$REMOTE"
 291                fi
 292                ;;
 293        tortoisemerge)
 294                if $base_present; then
 295                        touch "$BACKUP"
 296                        "$merge_tool_path" \
 297                                -base:"$BASE" -mine:"$LOCAL" \
 298                                -theirs:"$REMOTE" -merged:"$MERGED"
 299                        check_unchanged
 300                else
 301                        echo "TortoiseMerge cannot be used without a base" 1>&2
 302                        status=1
 303                fi
 304                ;;
 305        xxdiff)
 306                if merge_mode; then
 307                        touch "$BACKUP"
 308                        if $base_present; then
 309                                "$merge_tool_path" -X --show-merged-pane \
 310                                        -R 'Accel.SaveAsMerged: "Ctrl-S"' \
 311                                        -R 'Accel.Search: "Ctrl+F"' \
 312                                        -R 'Accel.SearchForward: "Ctrl-G"' \
 313                                        --merged-file "$MERGED" \
 314                                        "$LOCAL" "$BASE" "$REMOTE"
 315                        else
 316                                "$merge_tool_path" -X $extra \
 317                                        -R 'Accel.SaveAsMerged: "Ctrl-S"' \
 318                                        -R 'Accel.Search: "Ctrl+F"' \
 319                                        -R 'Accel.SearchForward: "Ctrl-G"' \
 320                                        --merged-file "$MERGED" \
 321                                        "$LOCAL" "$REMOTE"
 322                        fi
 323                        check_unchanged
 324                else
 325                        "$merge_tool_path" \
 326                                -R 'Accel.Search: "Ctrl+F"' \
 327                                -R 'Accel.SearchForward: "Ctrl-G"' \
 328                                "$LOCAL" "$REMOTE"
 329                fi
 330                ;;
 331        *)
 332                merge_tool_cmd="$(get_merge_tool_cmd "$1")"
 333                if test -z "$merge_tool_cmd"; then
 334                        if merge_mode; then
 335                                status=1
 336                        fi
 337                        break
 338                fi
 339                if merge_mode; then
 340                        trust_exit_code="$(git config --bool \
 341                                mergetool."$1".trustExitCode || echo false)"
 342                        if test "$trust_exit_code" = "false"; then
 343                                touch "$BACKUP"
 344                                ( eval $merge_tool_cmd )
 345                                check_unchanged
 346                        else
 347                                ( eval $merge_tool_cmd )
 348                                status=$?
 349                        fi
 350                else
 351                        ( eval $merge_tool_cmd )
 352                fi
 353                ;;
 354        esac
 355        return $status
 356}
 357
 358guess_merge_tool () {
 359        if merge_mode; then
 360                tools="tortoisemerge"
 361        else
 362                tools="kompare"
 363        fi
 364        if test -n "$DISPLAY"; then
 365                if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
 366                        tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
 367                else
 368                        tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
 369                fi
 370                tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3"
 371        fi
 372        case "${VISUAL:-$EDITOR}" in
 373        *vim*)
 374                tools="$tools vimdiff emerge"
 375                ;;
 376        *)
 377                tools="$tools emerge vimdiff"
 378                ;;
 379        esac
 380        echo >&2 "merge tool candidates: $tools"
 381
 382        # Loop over each candidate and stop when a valid merge tool is found.
 383        for i in $tools
 384        do
 385                merge_tool_path="$(translate_merge_tool_path "$i")"
 386                if type "$merge_tool_path" > /dev/null 2>&1; then
 387                        echo "$i"
 388                        return 0
 389                fi
 390        done
 391
 392        echo >&2 "No known merge resolution program available."
 393        return 1
 394}
 395
 396get_configured_merge_tool () {
 397        # Diff mode first tries diff.tool and falls back to merge.tool.
 398        # Merge mode only checks merge.tool
 399        if diff_mode; then
 400                merge_tool=$(git config diff.tool || git config merge.tool)
 401        else
 402                merge_tool=$(git config merge.tool)
 403        fi
 404        if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then
 405                echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
 406                echo >&2 "Resetting to default..."
 407                return 1
 408        fi
 409        echo "$merge_tool"
 410}
 411
 412get_merge_tool_path () {
 413        # A merge tool has been set, so verify that it's valid.
 414        if test -n "$1"; then
 415                merge_tool="$1"
 416        else
 417                merge_tool="$(get_merge_tool)"
 418        fi
 419        if ! valid_tool "$merge_tool"; then
 420                echo >&2 "Unknown merge tool $merge_tool"
 421                exit 1
 422        fi
 423        if diff_mode; then
 424                merge_tool_path=$(git config difftool."$merge_tool".path ||
 425                                  git config mergetool."$merge_tool".path)
 426        else
 427                merge_tool_path=$(git config mergetool."$merge_tool".path)
 428        fi
 429        if test -z "$merge_tool_path"; then
 430                merge_tool_path="$(translate_merge_tool_path "$merge_tool")"
 431        fi
 432        if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
 433        ! type "$merge_tool_path" > /dev/null 2>&1; then
 434                echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
 435                         "'$merge_tool_path'"
 436                exit 1
 437        fi
 438        echo "$merge_tool_path"
 439}
 440
 441get_merge_tool () {
 442        # Check if a merge tool has been configured
 443        merge_tool=$(get_configured_merge_tool)
 444        # Try to guess an appropriate merge tool if no tool has been set.
 445        if test -z "$merge_tool"; then
 446                merge_tool="$(guess_merge_tool)" || exit
 447        fi
 448        echo "$merge_tool"
 449}