diff options
Diffstat (limited to 'git-mergetool--lib.sh')
-rw-r--r-- | git-mergetool--lib.sh | 420 |
1 files changed, 133 insertions, 287 deletions
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index bfb01f7842..f013a03506 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -1,3 +1,4 @@ +#!/bin/sh # git-mergetool--lib is a library for common merge tool functions diff_mode() { test "$TOOL_MODE" = diff @@ -8,33 +9,19 @@ merge_mode() { } translate_merge_tool_path () { - case "$1" in - vimdiff) - echo vim - ;; - gvimdiff) - echo gvim - ;; - emerge) - echo emacs - ;; - araxis) - echo compare - ;; - *) - echo "$1" - ;; - esac + echo "$1" } check_unchanged () { - if test "$MERGED" -nt "$BACKUP"; then + if test "$MERGED" -nt "$BACKUP" + then status=0 else - while true; do + while true + do echo "$MERGED seems unchanged." printf "Was the merge successful? [y/n] " - read answer < /dev/tty + read answer || return 1 case "$answer" in y*|Y*) status=0; break ;; n*|N*) status=1; break ;; @@ -43,304 +30,160 @@ check_unchanged () { fi } +valid_tool_config () { + if test -n "$(get_merge_tool_cmd "$1")" + then + return 0 + else + return 1 + fi +} + valid_tool () { + setup_tool "$1" || valid_tool_config "$1" +} + +setup_tool () { case "$1" in - kdiff3 | tkdiff | xxdiff | meld | opendiff | \ - emerge | vimdiff | gvimdiff | ecmerge | diffuse | araxis) - ;; # happy - tortoisemerge) - if ! merge_mode; then - return 1 - fi - ;; - kompare) - if ! diff_mode; then - return 1 - fi + vim*|gvim*) + tool=vim ;; *) - if test -z "$(get_merge_tool_cmd "$1")"; then - return 1 - fi + tool="$1" ;; esac + mergetools="$(git --exec-path)/mergetools" + + # Load the default definitions + . "$mergetools/defaults" + if ! test -f "$mergetools/$tool" + then + return 1 + fi + + # Load the redefined functions + . "$mergetools/$tool" + + if merge_mode && ! can_merge + then + echo "error: '$tool' can not be used to resolve merges" >&2 + exit 1 + elif diff_mode && ! can_diff + then + echo "error: '$tool' can only be used to resolve merges" >&2 + exit 1 + fi + return 0 } get_merge_tool_cmd () { # Prints the custom command for a merge tool - if test -n "$1"; then - merge_tool="$1" - else - merge_tool="$(get_merge_tool)" - fi - if diff_mode; then + merge_tool="$1" + if diff_mode + then echo "$(git config difftool.$merge_tool.cmd || - git config mergetool.$merge_tool.cmd)" + git config mergetool.$merge_tool.cmd)" else echo "$(git config mergetool.$merge_tool.cmd)" fi } +# Entry point for running tools run_merge_tool () { + # If GIT_PREFIX is empty then we cannot use it in tools + # that expect to be able to chdir() to its value. + GIT_PREFIX=${GIT_PREFIX:-.} + export GIT_PREFIX + merge_tool_path="$(get_merge_tool_path "$1")" || exit base_present="$2" status=0 - case "$1" in - kdiff3) - if merge_mode; then - if $base_present; then - ("$merge_tool_path" --auto \ - --L1 "$MERGED (Base)" \ - --L2 "$MERGED (Local)" \ - --L3 "$MERGED (Remote)" \ - -o "$MERGED" \ - "$BASE" "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) - else - ("$merge_tool_path" --auto \ - --L1 "$MERGED (Local)" \ - --L2 "$MERGED (Remote)" \ - -o "$MERGED" \ - "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) - fi - status=$? - else - ("$merge_tool_path" --auto \ - --L1 "$MERGED (A)" \ - --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \ - > /dev/null 2>&1) - fi - ;; - kompare) - "$merge_tool_path" "$LOCAL" "$REMOTE" - ;; - tkdiff) - if merge_mode; then - if $base_present; then - "$merge_tool_path" -a "$BASE" \ - -o "$MERGED" "$LOCAL" "$REMOTE" - else - "$merge_tool_path" \ - -o "$MERGED" "$LOCAL" "$REMOTE" - fi - status=$? - else - "$merge_tool_path" "$LOCAL" "$REMOTE" - fi - ;; - meld) - if merge_mode; then - touch "$BACKUP" - "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - else - "$merge_tool_path" "$LOCAL" "$REMOTE" - fi - ;; - diffuse) - if merge_mode; then - touch "$BACKUP" - if $base_present; then - "$merge_tool_path" \ - "$LOCAL" "$MERGED" "$REMOTE" \ - "$BASE" | cat - else - "$merge_tool_path" \ - "$LOCAL" "$MERGED" "$REMOTE" | cat - fi - check_unchanged - else - "$merge_tool_path" "$LOCAL" "$REMOTE" | cat - fi - ;; - vimdiff) - if merge_mode; then - touch "$BACKUP" - "$merge_tool_path" -d -c "wincmd l" \ - "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - else - "$merge_tool_path" -d -c "wincmd l" \ - "$LOCAL" "$REMOTE" - fi - ;; - gvimdiff) - if merge_mode; then - touch "$BACKUP" - "$merge_tool_path" -d -c "wincmd l" -f \ - "$LOCAL" "$MERGED" "$REMOTE" - check_unchanged - else - "$merge_tool_path" -d -c "wincmd l" -f \ - "$LOCAL" "$REMOTE" - fi - ;; - xxdiff) - if merge_mode; then - touch "$BACKUP" - if $base_present; then - "$merge_tool_path" -X --show-merged-pane \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" \ - "$LOCAL" "$BASE" "$REMOTE" - else - "$merge_tool_path" -X $extra \ - -R 'Accel.SaveAsMerged: "Ctrl-S"' \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - --merged-file "$MERGED" \ - "$LOCAL" "$REMOTE" - fi - check_unchanged - else - "$merge_tool_path" \ - -R 'Accel.Search: "Ctrl+F"' \ - -R 'Accel.SearchForward: "Ctrl-G"' \ - "$LOCAL" "$REMOTE" - fi - ;; - opendiff) - if merge_mode; then - touch "$BACKUP" - if $base_present; then - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - -ancestor "$BASE" \ - -merge "$MERGED" | cat - else - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - -merge "$MERGED" | cat - fi - check_unchanged - else - "$merge_tool_path" "$LOCAL" "$REMOTE" | cat - fi - ;; - ecmerge) - if merge_mode; then + # Bring tool-specific functions into scope + setup_tool "$1" + + if merge_mode + then + run_merge_cmd "$1" + else + run_diff_cmd "$1" + fi + return $status +} + +# Run a either a configured or built-in diff tool +run_diff_cmd () { + merge_tool_cmd="$(get_merge_tool_cmd "$1")" + if test -n "$merge_tool_cmd" + then + ( eval $merge_tool_cmd ) + status=$? + return $status + else + diff_cmd "$1" + fi +} + +# Run a either a configured or built-in merge tool +run_merge_cmd () { + merge_tool_cmd="$(get_merge_tool_cmd "$1")" + if test -n "$merge_tool_cmd" + then + trust_exit_code="$(git config --bool \ + mergetool."$1".trustExitCode || echo false)" + if test "$trust_exit_code" = "false" + then touch "$BACKUP" - if $base_present; then - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \ - --default --mode=merge3 --to="$MERGED" - else - "$merge_tool_path" "$LOCAL" "$REMOTE" \ - --default --mode=merge2 --to="$MERGED" - fi - check_unchanged - else - "$merge_tool_path" --default --mode=diff2 \ - "$LOCAL" "$REMOTE" - fi - ;; - emerge) - if merge_mode; then - if $base_present; then - "$merge_tool_path" \ - -f emerge-files-with-ancestor-command \ - "$LOCAL" "$REMOTE" "$BASE" \ - "$(basename "$MERGED")" - else - "$merge_tool_path" \ - -f emerge-files-command \ - "$LOCAL" "$REMOTE" \ - "$(basename "$MERGED")" - fi + ( eval $merge_tool_cmd ) status=$? - else - "$merge_tool_path" -f emerge-files-command \ - "$LOCAL" "$REMOTE" - fi - ;; - tortoisemerge) - if $base_present; then - touch "$BACKUP" - "$merge_tool_path" \ - -base:"$BASE" -mine:"$LOCAL" \ - -theirs:"$REMOTE" -merged:"$MERGED" check_unchanged else - echo "TortoiseMerge cannot be used without a base" 1>&2 - status=1 - fi - ;; - araxis) - if merge_mode; then - touch "$BACKUP" - if $base_present; then - "$merge_tool_path" -wait -merge -3 -a1 \ - "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \ - >/dev/null 2>&1 - else - "$merge_tool_path" -wait -2 \ - "$LOCAL" "$REMOTE" "$MERGED" \ - >/dev/null 2>&1 - fi - check_unchanged - else - "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \ - >/dev/null 2>&1 - fi - ;; - *) - merge_tool_cmd="$(get_merge_tool_cmd "$1")" - if test -z "$merge_tool_cmd"; then - if merge_mode; then - status=1 - fi - break - fi - if merge_mode; then - trust_exit_code="$(git config --bool \ - mergetool."$1".trustExitCode || echo false)" - if test "$trust_exit_code" = "false"; then - touch "$BACKUP" - ( eval $merge_tool_cmd ) - check_unchanged - else - ( eval $merge_tool_cmd ) - status=$? - fi - else ( eval $merge_tool_cmd ) + status=$? fi - ;; - esac - return $status + return $status + else + merge_cmd "$1" + fi } -guess_merge_tool () { - if merge_mode; then +list_merge_tool_candidates () { + if merge_mode + then tools="tortoisemerge" else tools="kompare" fi - if test -n "$DISPLAY"; then - if test -n "$GNOME_DESKTOP_SESSION_ID" ; then + if test -n "$DISPLAY" + then + if test -n "$GNOME_DESKTOP_SESSION_ID" + then tools="meld opendiff kdiff3 tkdiff xxdiff $tools" else tools="opendiff kdiff3 tkdiff xxdiff meld $tools" fi - tools="$tools gvimdiff diffuse ecmerge araxis" + tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare" fi - if echo "${VISUAL:-$EDITOR}" | grep emacs > /dev/null 2>&1; then - # $EDITOR is emacs so add emerge as a candidate - tools="$tools emerge vimdiff" - elif echo "${VISUAL:-$EDITOR}" | grep vim > /dev/null 2>&1; then - # $EDITOR is vim so add vimdiff as a candidate + case "${VISUAL:-$EDITOR}" in + *vim*) tools="$tools vimdiff emerge" - else + ;; + *) tools="$tools emerge vimdiff" - fi + ;; + esac +} + +guess_merge_tool () { + list_merge_tool_candidates echo >&2 "merge tool candidates: $tools" # Loop over each candidate and stop when a valid merge tool is found. for i in $tools do merge_tool_path="$(translate_merge_tool_path "$i")" - if type "$merge_tool_path" > /dev/null 2>&1; then + if type "$merge_tool_path" >/dev/null 2>&1 + then echo "$i" return 0 fi @@ -353,12 +196,14 @@ guess_merge_tool () { get_configured_merge_tool () { # Diff mode first tries diff.tool and falls back to merge.tool. # Merge mode only checks merge.tool - if diff_mode; then + if diff_mode + then merge_tool=$(git config diff.tool || git config merge.tool) else merge_tool=$(git config merge.tool) fi - if test -n "$merge_tool" && ! valid_tool "$merge_tool"; then + if test -n "$merge_tool" && ! valid_tool "$merge_tool" + then echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool" echo >&2 "Resetting to default..." return 1 @@ -368,28 +213,28 @@ get_configured_merge_tool () { get_merge_tool_path () { # A merge tool has been set, so verify that it's valid. - if test -n "$1"; then - merge_tool="$1" - else - merge_tool="$(get_merge_tool)" - fi - if ! valid_tool "$merge_tool"; then + merge_tool="$1" + if ! valid_tool "$merge_tool" + then echo >&2 "Unknown merge tool $merge_tool" exit 1 fi - if diff_mode; then + if diff_mode + then merge_tool_path=$(git config difftool."$merge_tool".path || - git config mergetool."$merge_tool".path) + git config mergetool."$merge_tool".path) else merge_tool_path=$(git config mergetool."$merge_tool".path) fi - if test -z "$merge_tool_path"; then + if test -z "$merge_tool_path" + then merge_tool_path="$(translate_merge_tool_path "$merge_tool")" fi if test -z "$(get_merge_tool_cmd "$merge_tool")" && - ! type "$merge_tool_path" > /dev/null 2>&1; then + ! type "$merge_tool_path" >/dev/null 2>&1 + then echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\ - "'$merge_tool_path'" + "'$merge_tool_path'" exit 1 fi echo "$merge_tool_path" @@ -397,9 +242,10 @@ get_merge_tool_path () { get_merge_tool () { # Check if a merge tool has been configured - merge_tool=$(get_configured_merge_tool) + merge_tool="$(get_configured_merge_tool)" # Try to guess an appropriate merge tool if no tool has been set. - if test -z "$merge_tool"; then + if test -z "$merge_tool" + then merge_tool="$(guess_merge_tool)" || exit fi echo "$merge_tool" |