]>
Commit | Line | Data |
---|---|---|
853916ff LT |
1 | #!/bin/sh |
2 | ## | |
3 | ## applypatch takes four file arguments, and uses those to | |
4 | ## apply the unpacked patch (surprise surprise) that they | |
5 | ## represent to the current tree. | |
6 | ## | |
7 | ## The arguments are: | |
8 | ## $1 - file with commit message | |
9 | ## $2 - file with the actual patch | |
a196d8d4 LT |
10 | ## $3 - "info" file with Author, email and subject |
11 | ## $4 - optional file containing signoff to add | |
853916ff | 12 | ## |
6cf6193b FK |
13 | |
14 | USAGE='<msg> <patch> <info> [<signoff>]' | |
ae2b0f15 | 15 | . git-sh-setup |
4426ac70 | 16 | |
c6f60f99 | 17 | case "$#" in 3|4) ;; *) usage ;; esac |
6cf6193b | 18 | |
ad4e9ce4 JB |
19 | final=.dotest/final-commit |
20 | ## | |
21 | ## If this file exists, we ask before applying | |
22 | ## | |
23 | query_apply=.dotest/.query_apply | |
4426ac70 JH |
24 | |
25 | ## We do not munge the first line of the commit message too much | |
26 | ## if this file exists. | |
6bff6a60 | 27 | keep_subject=.dotest/.keep_subject |
4426ac70 | 28 | |
47f0b6d5 JH |
29 | ## We do not attempt the 3-way merge fallback unless this file exists. |
30 | fall_back_3way=.dotest/.3way | |
4426ac70 | 31 | |
853916ff LT |
32 | MSGFILE=$1 |
33 | PATCHFILE=$2 | |
a196d8d4 | 34 | INFO=$3 |
4426ac70 JH |
35 | SIGNOFF=$4 |
36 | EDIT=${VISUAL:-${EDITOR:-vi}} | |
ad4e9ce4 | 37 | |
a567d315 JH |
38 | export GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$INFO")" |
39 | export GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$INFO")" | |
40 | export GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$INFO")" | |
41 | export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$INFO")" | |
853916ff | 42 | |
4426ac70 JH |
43 | if test '' != "$SIGNOFF" |
44 | then | |
45 | if test -f "$SIGNOFF" | |
46 | then | |
47 | SIGNOFF=`cat "$SIGNOFF"` || exit | |
48 | elif case "$SIGNOFF" in yes | true | me | please) : ;; *) false ;; esac | |
49 | then | |
50 | SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e ' | |
51 | s/>.*/>/ | |
52 | s/^/Signed-off-by: /' | |
53 | ` | |
54 | else | |
55 | SIGNOFF= | |
56 | fi | |
57 | if test '' != "$SIGNOFF" | |
58 | then | |
59 | LAST_SIGNED_OFF_BY=` | |
60 | sed -ne '/^Signed-off-by: /p' "$MSGFILE" | | |
61 | tail -n 1 | |
62 | ` | |
a567d315 JH |
63 | test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { |
64 | test '' = "$LAST_SIGNED_OFF_BY" && echo | |
65 | echo "$SIGNOFF" | |
66 | } >>"$MSGFILE" | |
4426ac70 | 67 | fi |
ad4e9ce4 | 68 | fi |
4426ac70 | 69 | |
6bff6a60 JH |
70 | patch_header= |
71 | test -f "$keep_subject" || patch_header='[PATCH] ' | |
ad4e9ce4 | 72 | |
4426ac70 JH |
73 | { |
74 | echo "$patch_header$SUBJECT" | |
75 | if test -s "$MSGFILE" | |
76 | then | |
77 | echo | |
78 | cat "$MSGFILE" | |
79 | fi | |
80 | } >"$final" | |
ad4e9ce4 | 81 | |
4426ac70 JH |
82 | interactive=yes |
83 | test -f "$query_apply" || interactive=no | |
ad4e9ce4 | 84 | |
4426ac70 | 85 | while [ "$interactive" = yes ]; do |
ad4e9ce4 JB |
86 | echo "Commit Body is:" |
87 | echo "--------------------------" | |
4426ac70 | 88 | cat "$final" |
ad4e9ce4 | 89 | echo "--------------------------" |
9754563c | 90 | printf "Apply? [y]es/[n]o/[e]dit/[a]ccept all " |
ad4e9ce4 | 91 | read reply |
4426ac70 JH |
92 | case "$reply" in |
93 | y|Y) interactive=no;; | |
ad4e9ce4 | 94 | n|N) exit 2;; # special value to tell dotest to keep going |
4426ac70 JH |
95 | e|E) "$EDIT" "$final";; |
96 | a|A) rm -f "$query_apply" | |
97 | interactive=no ;; | |
ad4e9ce4 JB |
98 | esac |
99 | done | |
100 | ||
4426ac70 JH |
101 | if test -x "$GIT_DIR"/hooks/applypatch-msg |
102 | then | |
103 | "$GIT_DIR"/hooks/applypatch-msg "$final" || exit | |
104 | fi | |
105 | ||
853916ff | 106 | echo |
61096819 | 107 | echo Applying "'$SUBJECT'" |
853916ff LT |
108 | echo |
109 | ||
a567d315 | 110 | git-apply --index "$PATCHFILE" || { |
47f0b6d5 JH |
111 | |
112 | # git-apply exits with status 1 when the patch does not apply, | |
113 | # but it die()s with other failures, most notably upon corrupt | |
114 | # patch. In the latter case, there is no point to try applying | |
115 | # it to another tree and do 3-way merge. | |
116 | test $? = 1 || exit 1 | |
117 | ||
118 | test -f "$fall_back_3way" || exit 1 | |
119 | ||
a567d315 JH |
120 | # Here if we know which revision the patch applies to, |
121 | # we create a temporary working tree and index, apply the | |
122 | # patch, and attempt 3-way merge with the resulting tree. | |
47f0b6d5 JH |
123 | |
124 | O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` | |
125 | rm -fr .patch-merge-* | |
126 | ||
bf3e2748 JH |
127 | if git-apply -z --index-info "$PATCHFILE" \ |
128 | >.patch-merge-index-info 2>/dev/null && | |
129 | GIT_INDEX_FILE=.patch-merge-tmp-index \ | |
130 | git-update-index -z --index-info <.patch-merge-index-info && | |
131 | GIT_INDEX_FILE=.patch-merge-tmp-index \ | |
132 | git-write-tree >.patch-merge-tmp-base && | |
133 | ( | |
134 | mkdir .patch-merge-tmp-dir && | |
135 | cd .patch-merge-tmp-dir && | |
136 | GIT_INDEX_FILE="../.patch-merge-tmp-index" \ | |
137 | GIT_OBJECT_DIRECTORY="$O_OBJECT" \ | |
138 | git-apply $binary --index | |
139 | ) <"$PATCHFILE" | |
140 | then | |
141 | echo Using index info to reconstruct a base tree... | |
142 | mv .patch-merge-tmp-base .patch-merge-base | |
143 | mv .patch-merge-tmp-index .patch-merge-index | |
144 | else | |
47f0b6d5 JH |
145 | ( |
146 | N=10 | |
147 | ||
bf3e2748 JH |
148 | # Otherwise, try nearby trees that can be used to apply the |
149 | # patch. | |
47f0b6d5 JH |
150 | git-rev-list --max-count=$N HEAD |
151 | ||
152 | # or hoping the patch is against known tags... | |
153 | git-ls-remote --tags . | |
154 | ) | | |
bf3e2748 JH |
155 | while read base junk |
156 | do | |
47f0b6d5 JH |
157 | # Try it if we have it as a tree. |
158 | git-cat-file tree "$base" >/dev/null 2>&1 || continue | |
159 | ||
160 | rm -fr .patch-merge-tmp-* && | |
161 | mkdir .patch-merge-tmp-dir || break | |
162 | ( | |
163 | cd .patch-merge-tmp-dir && | |
164 | GIT_INDEX_FILE=../.patch-merge-tmp-index && | |
165 | GIT_OBJECT_DIRECTORY="$O_OBJECT" && | |
166 | export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY && | |
167 | git-read-tree "$base" && | |
168 | git-apply --index && | |
169 | mv ../.patch-merge-tmp-index ../.patch-merge-index && | |
170 | echo "$base" >../.patch-merge-base | |
171 | ) <"$PATCHFILE" 2>/dev/null && break | |
bf3e2748 JH |
172 | done |
173 | fi | |
47f0b6d5 JH |
174 | |
175 | test -f .patch-merge-index && | |
176 | his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) && | |
177 | orig_tree=$(cat .patch-merge-base) && | |
178 | rm -fr .patch-merge-* || exit 1 | |
179 | ||
180 | echo Falling back to patching base and 3-way merge using $orig_tree... | |
181 | ||
182 | # This is not so wrong. Depending on which base we picked, | |
183 | # orig_tree may be wildly different from ours, but his_tree | |
184 | # has the same set of wildly different changes in parts the | |
185 | # patch did not touch, so resolve ends up cancelling them, | |
186 | # saying that we reverted all those changes. | |
187 | ||
188 | if git-merge-resolve $orig_tree -- HEAD $his_tree | |
189 | then | |
190 | echo Done. | |
191 | else | |
192 | echo Failed to merge in the changes. | |
193 | exit 1 | |
194 | fi | |
a567d315 | 195 | } |
4426ac70 JH |
196 | |
197 | if test -x "$GIT_DIR"/hooks/pre-applypatch | |
198 | then | |
199 | "$GIT_DIR"/hooks/pre-applypatch || exit | |
200 | fi | |
201 | ||
50eb31d1 | 202 | tree=$(git-write-tree) || exit 1 |
853916ff | 203 | echo Wrote tree $tree |
bf7960eb JH |
204 | parent=$(git-rev-parse --verify HEAD) && |
205 | commit=$(git-commit-tree $tree -p $parent <"$final") || exit 1 | |
853916ff | 206 | echo Committed: $commit |
bf7960eb | 207 | git-update-ref HEAD $commit $parent || exit |
4426ac70 JH |
208 | |
209 | if test -x "$GIT_DIR"/hooks/post-applypatch | |
210 | then | |
211 | "$GIT_DIR"/hooks/post-applypatch | |
212 | fi |