summaryrefslogtreecommitdiff
path: root/git-apply-patch-script
blob: 13ec1c4490612f524f9b1070a57229cdc2c50aed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/bin/sh
# Copyright (C) 2005 Junio C Hamano
#
# Applying diff between two trees to the work tree can be
# done with the following single command:
#
# GIT_EXTERNAL_DIFF=git-apply-patch-script git-diff-tree -p $tree1 $tree2
#

case "$#" in
2)
    echo >&2 "cannot handle unmerged diff on path $1."
    exit 1 ;;
esac
name="$1" tmp1="$2" hex1="$3" mode1="$4" tmp2="$5" hex2="$6" mode2="$7"

type1=f
case "$mode1" in
*120???) type1=l  ;;
*1007??) mode1=+x ;;
*1006??) mode1=-x ;;
.)       type1=-  ;; 
esac

type2=f
case "$mode2" in
*120???) type2=l  ;;
*1007??) mode2=+x ;;
*1006??) mode2=-x ;;
.)       type2=-  ;; 
esac

case "$type1,$type2" in

-,?)
    dir=$(dirname "$name")
    case "$dir" in '' | .) ;; *) mkdir -p "$dir" ;; esac || {
	echo >&2 "cannot create leading path for $name."
	exit 1
    }
    if test -e "$name"
    then
	echo >&2 "path $name to be created already exists."
	exit 1
    fi
    case "$type2" in
    f)
        # creating a regular file
	cat "$tmp2" >"$name" || {
	    echo >&2 "cannot create a regular file $name."
	    exit 1
	} 
	case "$mode2" in
	+x)
	    echo >&2 "created a regular file $name with mode +x."
	    chmod "$mode2" "$name"
	    ;;
	-x)
	    echo >&2 "created a regular file $name."
            ;;
        esac
	;;
    l)
        # creating a symlink
        ln -s "$(cat "$tmp2")" "$name" || {
	    echo >&2 "cannot create a symbolic link $name."
	    exit 1
	}
	echo >&2 "created a symbolic link $name."
        ;;
    *)
        echo >&2 "do not know how to create $name of type $type2."
	exit 1
    esac
    git-update-cache --add -- "$name" ;;

?,-)
    rm -f "$name" || {
	echo >&2 "cannot remove $name"
	exit 1
    }
    echo >&2 "deleted $name."
    git-update-cache --remove -- "$name" ;;

l,f|f,l)
    echo >&2 "cannot change a regular file $name and a symbolic link $name."
    exit 1 ;;

l,l)
    # symlink to symlink
    current=$(readlink "$name") || {
	echo >&2 "cannot read the target of the symbolic link $name."
	exit 1
    }
    original=$(cat "$tmp1")
    next=$(cat "$tmp2")
    test "$original" != "$current" || {
	echo >&2 "cannot apply symbolic link target change ($original->$next) to $name which points to $current."
	exit 1
    }
    if test "$next" != "$current"
    then
	rm -f "$name" && ln -s "$next" "$name" || {
	    echo >&2 "cannot create symbolic link $name."
	    exit 1
	}
	echo >&2 "changed symbolic target of $name."
        git-update-cache -- "$name"
    fi ;;

f,f)
    # changed
    test -e "$name" || {
	echo >&2 "regular file $name to be patched does not exist."
	exit 1
    }
    dir=$(dirname "$name")
    case "$dir" in '' | .) ;; *) mkdir -p "$dir";; esac || {
	echo >&2 "cannot create leading path for $name."
	exit 1
    }
    tmp=.git-apply-patch-$$
    trap "rm -f $tmp-*" 0 1 2 3 15

    # Be careful, in case "$tmp2" is borrowed path from the work tree
    # we are looking at...
    diff -u -L "a/$name" -L "b/$name" "$tmp1" "$tmp2" >$tmp-patch

    # This will say "patching ..." so we do not say anything outselves.
    patch -p1 <$tmp-patch || exit
    rm -f $tmp-patch
    case "$mode1,$mode2" in
    "$mode2,$mode1") ;;
    *)
	chmod "$mode2" "$name"
	echo >&2 "changed mode from $mode1 to $mode2."
	;;
    esac
    git-update-cache -- "$name"

esac