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