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