]>
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 | ## |
215a7ad1 | 13 | . git-sh-setup || die "Not a git archive." |
4426ac70 | 14 | |
ad4e9ce4 JB |
15 | final=.dotest/final-commit |
16 | ## | |
17 | ## If this file exists, we ask before applying | |
18 | ## | |
19 | query_apply=.dotest/.query_apply | |
4426ac70 JH |
20 | |
21 | ## We do not munge the first line of the commit message too much | |
22 | ## if this file exists. | |
6bff6a60 | 23 | keep_subject=.dotest/.keep_subject |
4426ac70 | 24 | |
47f0b6d5 JH |
25 | ## We do not attempt the 3-way merge fallback unless this file exists. |
26 | fall_back_3way=.dotest/.3way | |
4426ac70 | 27 | |
853916ff LT |
28 | MSGFILE=$1 |
29 | PATCHFILE=$2 | |
a196d8d4 | 30 | INFO=$3 |
4426ac70 JH |
31 | SIGNOFF=$4 |
32 | EDIT=${VISUAL:-${EDITOR:-vi}} | |
ad4e9ce4 | 33 | |
a567d315 JH |
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")" | |
853916ff | 38 | |
4426ac70 JH |
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 | ` | |
a567d315 JH |
59 | test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { |
60 | test '' = "$LAST_SIGNED_OFF_BY" && echo | |
61 | echo "$SIGNOFF" | |
62 | } >>"$MSGFILE" | |
4426ac70 | 63 | fi |
ad4e9ce4 | 64 | fi |
4426ac70 | 65 | |
6bff6a60 JH |
66 | patch_header= |
67 | test -f "$keep_subject" || patch_header='[PATCH] ' | |
ad4e9ce4 | 68 | |
4426ac70 JH |
69 | { |
70 | echo "$patch_header$SUBJECT" | |
71 | if test -s "$MSGFILE" | |
72 | then | |
73 | echo | |
74 | cat "$MSGFILE" | |
75 | fi | |
76 | } >"$final" | |
ad4e9ce4 | 77 | |
4426ac70 JH |
78 | interactive=yes |
79 | test -f "$query_apply" || interactive=no | |
ad4e9ce4 | 80 | |
4426ac70 | 81 | while [ "$interactive" = yes ]; do |
ad4e9ce4 JB |
82 | echo "Commit Body is:" |
83 | echo "--------------------------" | |
4426ac70 | 84 | cat "$final" |
ad4e9ce4 JB |
85 | echo "--------------------------" |
86 | echo -n "Apply? [y]es/[n]o/[e]dit/[a]ccept all " | |
87 | read reply | |
4426ac70 JH |
88 | case "$reply" in |
89 | y|Y) interactive=no;; | |
ad4e9ce4 | 90 | n|N) exit 2;; # special value to tell dotest to keep going |
4426ac70 JH |
91 | e|E) "$EDIT" "$final";; |
92 | a|A) rm -f "$query_apply" | |
93 | interactive=no ;; | |
ad4e9ce4 JB |
94 | esac |
95 | done | |
96 | ||
4426ac70 JH |
97 | if test -x "$GIT_DIR"/hooks/applypatch-msg |
98 | then | |
99 | "$GIT_DIR"/hooks/applypatch-msg "$final" || exit | |
100 | fi | |
101 | ||
853916ff | 102 | echo |
61096819 | 103 | echo Applying "'$SUBJECT'" |
853916ff LT |
104 | echo |
105 | ||
a567d315 | 106 | git-apply --index "$PATCHFILE" || { |
47f0b6d5 JH |
107 | |
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 | |
113 | ||
114 | test -f "$fall_back_3way" || exit 1 | |
115 | ||
a567d315 JH |
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. | |
47f0b6d5 JH |
119 | |
120 | O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` | |
121 | rm -fr .patch-merge-* | |
122 | ||
123 | ( | |
124 | N=10 | |
125 | ||
126 | # if the patch records the base tree... | |
127 | sed -ne ' | |
128 | /^diff /q | |
129 | /^applies-to: \([0-9a-f]*\)$/{ | |
130 | s//\1/p | |
131 | q | |
132 | } | |
133 | ' "$PATCHFILE" | |
134 | ||
135 | # or hoping the patch is against our recent commits... | |
136 | git-rev-list --max-count=$N HEAD | |
137 | ||
138 | # or hoping the patch is against known tags... | |
139 | git-ls-remote --tags . | |
140 | ) | | |
141 | while read base junk | |
142 | do | |
143 | # Try it if we have it as a tree. | |
144 | git-cat-file tree "$base" >/dev/null 2>&1 || continue | |
145 | ||
146 | rm -fr .patch-merge-tmp-* && | |
147 | mkdir .patch-merge-tmp-dir || break | |
148 | ( | |
149 | cd .patch-merge-tmp-dir && | |
150 | GIT_INDEX_FILE=../.patch-merge-tmp-index && | |
151 | GIT_OBJECT_DIRECTORY="$O_OBJECT" && | |
152 | export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY && | |
153 | git-read-tree "$base" && | |
154 | git-apply --index && | |
155 | mv ../.patch-merge-tmp-index ../.patch-merge-index && | |
156 | echo "$base" >../.patch-merge-base | |
157 | ) <"$PATCHFILE" 2>/dev/null && break | |
158 | done | |
159 | ||
160 | test -f .patch-merge-index && | |
161 | his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) && | |
162 | orig_tree=$(cat .patch-merge-base) && | |
163 | rm -fr .patch-merge-* || exit 1 | |
164 | ||
165 | echo Falling back to patching base and 3-way merge using $orig_tree... | |
166 | ||
167 | # This is not so wrong. Depending on which base we picked, | |
168 | # orig_tree may be wildly different from ours, but his_tree | |
169 | # has the same set of wildly different changes in parts the | |
170 | # patch did not touch, so resolve ends up cancelling them, | |
171 | # saying that we reverted all those changes. | |
172 | ||
173 | if git-merge-resolve $orig_tree -- HEAD $his_tree | |
174 | then | |
175 | echo Done. | |
176 | else | |
177 | echo Failed to merge in the changes. | |
178 | exit 1 | |
179 | fi | |
a567d315 | 180 | } |
4426ac70 JH |
181 | |
182 | if test -x "$GIT_DIR"/hooks/pre-applypatch | |
183 | then | |
184 | "$GIT_DIR"/hooks/pre-applypatch || exit | |
185 | fi | |
186 | ||
50eb31d1 | 187 | tree=$(git-write-tree) || exit 1 |
853916ff | 188 | echo Wrote tree $tree |
bf7960eb JH |
189 | parent=$(git-rev-parse --verify HEAD) && |
190 | commit=$(git-commit-tree $tree -p $parent <"$final") || exit 1 | |
853916ff | 191 | echo Committed: $commit |
bf7960eb | 192 | git-update-ref HEAD $commit $parent || exit |
4426ac70 JH |
193 | |
194 | if test -x "$GIT_DIR"/hooks/post-applypatch | |
195 | then | |
196 | "$GIT_DIR"/hooks/post-applypatch | |
197 | fi |