~ubuntu-branches/ubuntu/intrepid/git-core/intrepid-updates

« back to all changes in this revision

Viewing changes to git-mergetool.sh

  • Committer: Package Import Robot
  • Author(s): Gerrit Pape
  • Date: 2007-04-22 13:31:05 UTC
  • mfrom: (1.1.14)
  • Revision ID: package-import@ubuntu.com-20070422133105-tkmhz328g2p0epz1
Tags: 1:1.5.1.2-1
* new upstream point release.
* debian/changelog.upstream: upstream changes taken from mailing list
  announcement.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/bin/sh
 
2
#
 
3
# This program resolves merge conflicts in git
 
4
#
 
5
# Copyright (c) 2006 Theodore Y. Ts'o
 
6
#
 
7
# This file is licensed under the GPL v2, or a later version
 
8
# at the discretion of Junio C Hammano.
 
9
#
 
10
 
 
11
USAGE='[--tool=tool] [file to merge] ...'
 
12
SUBDIRECTORY_OK=Yes
 
13
. git-sh-setup
 
14
require_work_tree
 
15
 
 
16
# Returns true if the mode reflects a symlink
 
17
is_symlink () {
 
18
    test "$1" = 120000
 
19
}
 
20
 
 
21
local_present () {
 
22
    test -n "$local_mode"
 
23
}
 
24
 
 
25
remote_present () {
 
26
    test -n "$remote_mode"
 
27
}
 
28
 
 
29
base_present () {
 
30
    test -n "$base_mode"
 
31
}
 
32
 
 
33
cleanup_temp_files () {
 
34
    if test "$1" = --save-backup ; then
 
35
        mv -- "$BACKUP" "$path.orig"
 
36
        rm -f -- "$LOCAL" "$REMOTE" "$BASE"
 
37
    else
 
38
        rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
 
39
    fi
 
40
}
 
41
 
 
42
describe_file () {
 
43
    mode="$1"
 
44
    branch="$2"
 
45
    file="$3"
 
46
 
 
47
    printf "  {%s}: " "$branch"
 
48
    if test -z "$mode"; then
 
49
        echo "deleted"
 
50
    elif is_symlink "$mode" ; then
 
51
        echo "a symbolic link -> '$(cat "$file")'"
 
52
    else
 
53
        if base_present; then
 
54
            echo "modified"
 
55
        else
 
56
            echo "created"
 
57
        fi
 
58
    fi
 
59
}
 
60
 
 
61
 
 
62
resolve_symlink_merge () {
 
63
    while true; do
 
64
        printf "Use (l)ocal or (r)emote, or (a)bort? "
 
65
        read ans
 
66
        case "$ans" in
 
67
            [lL]*)
 
68
                git-checkout-index -f --stage=2 -- "$path"
 
69
                git-add -- "$path"
 
70
                cleanup_temp_files --save-backup
 
71
                return
 
72
                ;;
 
73
            [rR]*)
 
74
                git-checkout-index -f --stage=3 -- "$path"
 
75
                git-add -- "$path"
 
76
                cleanup_temp_files --save-backup
 
77
                return
 
78
                ;;
 
79
            [aA]*)
 
80
                exit 1
 
81
                ;;
 
82
            esac
 
83
        done
 
84
}
 
85
 
 
86
resolve_deleted_merge () {
 
87
    while true; do
 
88
        if base_present; then
 
89
            printf "Use (m)odified or (d)eleted file, or (a)bort? "
 
90
        else
 
91
            printf "Use (c)reated or (d)eleted file, or (a)bort? "
 
92
        fi
 
93
        read ans
 
94
        case "$ans" in
 
95
            [mMcC]*)
 
96
                git-add -- "$path"
 
97
                cleanup_temp_files --save-backup
 
98
                return
 
99
                ;;
 
100
            [dD]*)
 
101
                git-rm -- "$path" > /dev/null
 
102
                cleanup_temp_files
 
103
                return
 
104
                ;;
 
105
            [aA]*)
 
106
                exit 1
 
107
                ;;
 
108
            esac
 
109
        done
 
110
}
 
111
 
 
112
check_unchanged () {
 
113
    if test "$path" -nt "$BACKUP" ; then
 
114
        status=0;
 
115
    else
 
116
        while true; do
 
117
            echo "$path seems unchanged."
 
118
            printf "Was the merge successful? [y/n] "
 
119
            read answer < /dev/tty
 
120
            case "$answer" in
 
121
                y*|Y*) status=0; break ;;
 
122
                n*|N*) status=1; break ;;
 
123
            esac
 
124
        done
 
125
    fi
 
126
}
 
127
 
 
128
save_backup () {
 
129
    if test "$status" -eq 0; then
 
130
        mv -- "$BACKUP" "$path.orig"
 
131
    fi
 
132
}
 
133
 
 
134
remove_backup () {
 
135
    if test "$status" -eq 0; then
 
136
        rm "$BACKUP"
 
137
    fi
 
138
}
 
139
 
 
140
merge_file () {
 
141
    path="$1"
 
142
 
 
143
    f=`git-ls-files -u -- "$path"`
 
144
    if test -z "$f" ; then
 
145
        if test ! -f "$path" ; then
 
146
            echo "$path: file not found"
 
147
        else
 
148
            echo "$path: file does not need merging"
 
149
        fi
 
150
        exit 1
 
151
    fi
 
152
 
 
153
    BACKUP="$path.BACKUP.$$"
 
154
    LOCAL="$path.LOCAL.$$"
 
155
    REMOTE="$path.REMOTE.$$"
 
156
    BASE="$path.BASE.$$"
 
157
 
 
158
    mv -- "$path" "$BACKUP"
 
159
    cp -- "$BACKUP" "$path"
 
160
 
 
161
    base_mode=`git ls-files -u -- "$path" | awk '{if ($3==1) print $1;}'`
 
162
    local_mode=`git ls-files -u -- "$path" | awk '{if ($3==2) print $1;}'`
 
163
    remote_mode=`git ls-files -u -- "$path" | awk '{if ($3==3) print $1;}'`
 
164
 
 
165
    base_present   && git cat-file blob ":1:$path" > "$BASE" 2>/dev/null
 
166
    local_present  && git cat-file blob ":2:$path" > "$LOCAL" 2>/dev/null
 
167
    remote_present && git cat-file blob ":3:$path" > "$REMOTE" 2>/dev/null
 
168
 
 
169
    if test -z "$local_mode" -o -z "$remote_mode"; then
 
170
        echo "Deleted merge conflict for '$path':"
 
171
        describe_file "$local_mode" "local" "$LOCAL"
 
172
        describe_file "$remote_mode" "remote" "$REMOTE"
 
173
        resolve_deleted_merge
 
174
        return
 
175
    fi
 
176
 
 
177
    if is_symlink "$local_mode" || is_symlink "$remote_mode"; then
 
178
        echo "Symbolic link merge conflict for '$path':"
 
179
        describe_file "$local_mode" "local" "$LOCAL"
 
180
        describe_file "$remote_mode" "remote" "$REMOTE"
 
181
        resolve_symlink_merge
 
182
        return
 
183
    fi
 
184
 
 
185
    echo "Normal merge conflict for '$path':"
 
186
    describe_file "$local_mode" "local" "$LOCAL"
 
187
    describe_file "$remote_mode" "remote" "$REMOTE"
 
188
    printf "Hit return to start merge resolution tool (%s): " "$merge_tool"
 
189
    read ans
 
190
 
 
191
    case "$merge_tool" in
 
192
        kdiff3)
 
193
            if base_present ; then
 
194
                (kdiff3 --auto --L1 "$path (Base)" -L2 "$path (Local)" --L3 "$path (Remote)" \
 
195
                    -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
 
196
            else
 
197
                (kdiff3 --auto -L1 "$path (Local)" --L2 "$path (Remote)" \
 
198
                    -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1)
 
199
            fi
 
200
            status=$?
 
201
            remove_backup
 
202
            ;;
 
203
        tkdiff)
 
204
            if base_present ; then
 
205
                tkdiff -a "$BASE" -o "$path" -- "$LOCAL" "$REMOTE"
 
206
            else
 
207
                tkdiff -o "$path" -- "$LOCAL" "$REMOTE"
 
208
            fi
 
209
            status=$?
 
210
            save_backup
 
211
            ;;
 
212
        meld|vimdiff)
 
213
            touch "$BACKUP"
 
214
            $merge_tool -- "$LOCAL" "$path" "$REMOTE"
 
215
            check_unchanged
 
216
            save_backup
 
217
            ;;
 
218
        xxdiff)
 
219
            touch "$BACKUP"
 
220
            if base_present ; then
 
221
                xxdiff -X --show-merged-pane \
 
222
                    -R 'Accel.SaveAsMerged: "Ctrl-S"' \
 
223
                    -R 'Accel.Search: "Ctrl+F"' \
 
224
                    -R 'Accel.SearchForward: "Ctrl-G"' \
 
225
                    --merged-file "$path" -- "$LOCAL" "$BASE" "$REMOTE"
 
226
            else
 
227
                xxdiff -X --show-merged-pane \
 
228
                    -R 'Accel.SaveAsMerged: "Ctrl-S"' \
 
229
                    -R 'Accel.Search: "Ctrl+F"' \
 
230
                    -R 'Accel.SearchForward: "Ctrl-G"' \
 
231
                    --merged-file "$path" -- "$LOCAL" "$REMOTE"
 
232
            fi
 
233
            check_unchanged
 
234
            save_backup
 
235
            ;;
 
236
        opendiff)
 
237
            touch "$BACKUP"
 
238
            if base_present; then
 
239
                opendiff "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$path" | cat
 
240
            else
 
241
                opendiff "$LOCAL" "$REMOTE" -merge "$path" | cat
 
242
            fi
 
243
            check_unchanged
 
244
            save_backup
 
245
            ;;
 
246
        emerge)
 
247
            if base_present ; then
 
248
                emacs -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$path"
 
249
            else
 
250
                emacs -f emerge-files-command "$LOCAL" "$REMOTE" "$path"
 
251
            fi
 
252
            status=$?
 
253
            save_backup
 
254
            ;;
 
255
    esac
 
256
    if test "$status" -ne 0; then
 
257
        echo "merge of $path failed" 1>&2
 
258
        mv -- "$BACKUP" "$path"
 
259
        exit 1
 
260
    fi
 
261
    git add -- "$path"
 
262
    cleanup_temp_files
 
263
}
 
264
 
 
265
while case $# in 0) break ;; esac
 
266
do
 
267
    case "$1" in
 
268
        -t|--tool*)
 
269
            case "$#,$1" in
 
270
                *,*=*)
 
271
                    merge_tool=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 
272
                    ;;
 
273
                1,*)
 
274
                    usage ;;
 
275
                *)
 
276
                    merge_tool="$2"
 
277
                    shift ;;
 
278
            esac
 
279
            ;;
 
280
        --)
 
281
            break
 
282
            ;;
 
283
        -*)
 
284
            usage
 
285
            ;;
 
286
        *)
 
287
            break
 
288
            ;;
 
289
    esac
 
290
    shift
 
291
done
 
292
 
 
293
if test -z "$merge_tool"; then
 
294
    merge_tool=`git-config merge.tool`
 
295
    case "$merge_tool" in
 
296
        kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | "")
 
297
            ;; # happy
 
298
        *)
 
299
            echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
 
300
            echo >&2 "Resetting to default..."
 
301
            unset merge_tool
 
302
            ;;
 
303
    esac
 
304
fi
 
305
 
 
306
if test -z "$merge_tool" ; then
 
307
    if type kdiff3 >/dev/null 2>&1 && test -n "$DISPLAY"; then
 
308
        merge_tool="kdiff3";
 
309
    elif type tkdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
 
310
        merge_tool=tkdiff
 
311
    elif type xxdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
 
312
        merge_tool=xxdiff
 
313
    elif type meld >/dev/null 2>&1 && test -n "$DISPLAY"; then
 
314
        merge_tool=meld
 
315
    elif type opendiff >/dev/null 2>&1; then
 
316
        merge_tool=opendiff
 
317
    elif type emacs >/dev/null 2>&1; then
 
318
        merge_tool=emerge
 
319
    elif type vimdiff >/dev/null 2>&1; then
 
320
        merge_tool=vimdiff
 
321
    else
 
322
        echo "No available merge resolution programs available."
 
323
        exit 1
 
324
    fi
 
325
fi
 
326
 
 
327
case "$merge_tool" in
 
328
    kdiff3|tkdiff|meld|xxdiff|vimdiff|opendiff)
 
329
        if ! type "$merge_tool" > /dev/null 2>&1; then
 
330
            echo "The merge tool $merge_tool is not available"
 
331
            exit 1
 
332
        fi
 
333
        ;;
 
334
    emerge)
 
335
        if ! type "emacs" > /dev/null 2>&1; then
 
336
            echo "Emacs is not available"
 
337
            exit 1
 
338
        fi
 
339
        ;;
 
340
    *)
 
341
        echo "Unknown merge tool: $merge_tool"
 
342
        exit 1
 
343
        ;;
 
344
esac
 
345
 
 
346
if test $# -eq 0 ; then
 
347
        files=`git ls-files -u | sed -e 's/^[^  ]*      //' | sort -u`
 
348
        if test -z "$files" ; then
 
349
                echo "No files need merging"
 
350
                exit 0
 
351
        fi
 
352
        echo Merging the files: $files
 
353
        git ls-files -u | sed -e 's/^[^ ]*      //' | sort -u | while read i
 
354
        do
 
355
                printf "\n"
 
356
                merge_file "$i" < /dev/tty > /dev/tty
 
357
        done
 
358
else
 
359
        while test $# -gt 0; do
 
360
                printf "\n"
 
361
                merge_file "$1"
 
362
                shift
 
363
        done
 
364
fi
 
365
exit 0