Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 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 |
Linus Torvalds | a196d8d | 2005-06-23 09:40:23 -0700 | [diff] [blame] | 10 | ## $3 - "info" file with Author, email and subject |
| 11 | ## $4 - optional file containing signoff to add |
Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 12 | ## |
freku045@student.liu.se | 6cf6193 | 2005-12-13 23:30:31 +0100 | [diff] [blame] | 13 | |
| 14 | USAGE='<msg> <patch> <info> [<signoff>]' |
Junio C Hamano | ae2b0f1 | 2005-11-24 00:12:11 -0800 | [diff] [blame] | 15 | . git-sh-setup |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 16 | |
Junio C Hamano | c6f60f9 | 2005-12-15 13:02:25 -0800 | [diff] [blame] | 17 | case "$#" in 3|4) ;; *) usage ;; esac |
freku045@student.liu.se | 6cf6193 | 2005-12-13 23:30:31 +0100 | [diff] [blame] | 18 | |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 19 | final=.dotest/final-commit |
| 20 | ## |
| 21 | ## If this file exists, we ask before applying |
| 22 | ## |
| 23 | query_apply=.dotest/.query_apply |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 24 | |
| 25 | ## We do not munge the first line of the commit message too much |
| 26 | ## if this file exists. |
Junio C Hamano | 6bff6a6 | 2005-08-16 22:18:27 -0700 | [diff] [blame] | 27 | keep_subject=.dotest/.keep_subject |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 28 | |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 29 | ## We do not attempt the 3-way merge fallback unless this file exists. |
| 30 | fall_back_3way=.dotest/.3way |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 31 | |
Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 32 | MSGFILE=$1 |
| 33 | PATCHFILE=$2 |
Linus Torvalds | a196d8d | 2005-06-23 09:40:23 -0700 | [diff] [blame] | 34 | INFO=$3 |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 35 | SIGNOFF=$4 |
| 36 | EDIT=${VISUAL:-${EDITOR:-vi}} |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 37 | |
Junio C Hamano | a567d31 | 2005-10-04 01:11:27 -0700 | [diff] [blame] | 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")" |
Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 42 | |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 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 | ` |
Junio C Hamano | a567d31 | 2005-10-04 01:11:27 -0700 | [diff] [blame] | 63 | test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || { |
| 64 | test '' = "$LAST_SIGNED_OFF_BY" && echo |
| 65 | echo "$SIGNOFF" |
| 66 | } >>"$MSGFILE" |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 67 | fi |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 68 | fi |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 69 | |
Junio C Hamano | 6bff6a6 | 2005-08-16 22:18:27 -0700 | [diff] [blame] | 70 | patch_header= |
| 71 | test -f "$keep_subject" || patch_header='[PATCH] ' |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 72 | |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 73 | { |
| 74 | echo "$patch_header$SUBJECT" |
| 75 | if test -s "$MSGFILE" |
| 76 | then |
| 77 | echo |
| 78 | cat "$MSGFILE" |
| 79 | fi |
| 80 | } >"$final" |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 81 | |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 82 | interactive=yes |
| 83 | test -f "$query_apply" || interactive=no |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 84 | |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 85 | while [ "$interactive" = yes ]; do |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 86 | echo "Commit Body is:" |
| 87 | echo "--------------------------" |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 88 | cat "$final" |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 89 | echo "--------------------------" |
Jason Riedy | 9754563 | 2005-12-06 14:21:52 -0800 | [diff] [blame] | 90 | printf "Apply? [y]es/[n]o/[e]dit/[a]ccept all " |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 91 | read reply |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 92 | case "$reply" in |
| 93 | y|Y) interactive=no;; |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 94 | n|N) exit 2;; # special value to tell dotest to keep going |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 95 | e|E) "$EDIT" "$final";; |
| 96 | a|A) rm -f "$query_apply" |
| 97 | interactive=no ;; |
James Bottomley | ad4e9ce | 2005-04-20 08:23:00 -0700 | [diff] [blame] | 98 | esac |
| 99 | done |
| 100 | |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 101 | if test -x "$GIT_DIR"/hooks/applypatch-msg |
| 102 | then |
| 103 | "$GIT_DIR"/hooks/applypatch-msg "$final" || exit |
| 104 | fi |
| 105 | |
Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 106 | echo |
Linus Torvalds | 6109681 | 2005-04-18 17:40:32 -0700 | [diff] [blame] | 107 | echo Applying "'$SUBJECT'" |
Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 108 | echo |
| 109 | |
Junio C Hamano | a567d31 | 2005-10-04 01:11:27 -0700 | [diff] [blame] | 110 | git-apply --index "$PATCHFILE" || { |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 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 | |
Junio C Hamano | a567d31 | 2005-10-04 01:11:27 -0700 | [diff] [blame] | 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. |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 123 | |
| 124 | O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd` |
| 125 | rm -fr .patch-merge-* |
| 126 | |
Junio C Hamano | bf3e274 | 2005-11-29 13:53:30 -0800 | [diff] [blame] | 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 |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 145 | ( |
| 146 | N=10 |
| 147 | |
Junio C Hamano | bf3e274 | 2005-11-29 13:53:30 -0800 | [diff] [blame] | 148 | # Otherwise, try nearby trees that can be used to apply the |
| 149 | # patch. |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 150 | git-rev-list --max-count=$N HEAD |
| 151 | |
| 152 | # or hoping the patch is against known tags... |
| 153 | git-ls-remote --tags . |
| 154 | ) | |
Junio C Hamano | bf3e274 | 2005-11-29 13:53:30 -0800 | [diff] [blame] | 155 | while read base junk |
| 156 | do |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 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 |
Junio C Hamano | bf3e274 | 2005-11-29 13:53:30 -0800 | [diff] [blame] | 172 | done |
| 173 | fi |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 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 |
Pavel Roskin | 82e5a82 | 2006-07-10 01:50:18 -0400 | [diff] [blame] | 185 | # patch did not touch, so resolve ends up canceling them, |
Junio C Hamano | 47f0b6d | 2005-10-06 14:25:52 -0700 | [diff] [blame] | 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 |
Junio C Hamano | a567d31 | 2005-10-04 01:11:27 -0700 | [diff] [blame] | 195 | } |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 196 | |
| 197 | if test -x "$GIT_DIR"/hooks/pre-applypatch |
| 198 | then |
| 199 | "$GIT_DIR"/hooks/pre-applypatch || exit |
| 200 | fi |
| 201 | |
Linus Torvalds | 50eb31d | 2005-04-29 14:56:18 -0700 | [diff] [blame] | 202 | tree=$(git-write-tree) || exit 1 |
Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 203 | echo Wrote tree $tree |
Junio C Hamano | bf7960e | 2005-09-27 18:14:27 -0700 | [diff] [blame] | 204 | parent=$(git-rev-parse --verify HEAD) && |
| 205 | commit=$(git-commit-tree $tree -p $parent <"$final") || exit 1 |
Linus Torvalds | 853916f | 2005-04-12 01:40:20 -0700 | [diff] [blame] | 206 | echo Committed: $commit |
Shawn Pearce | 67644a4 | 2006-05-19 05:16:18 -0400 | [diff] [blame] | 207 | git-update-ref -m "applypatch: $SUBJECT" HEAD $commit $parent || exit |
Junio C Hamano | 4426ac7 | 2005-08-19 13:53:13 -0700 | [diff] [blame] | 208 | |
| 209 | if test -x "$GIT_DIR"/hooks/post-applypatch |
| 210 | then |
| 211 | "$GIT_DIR"/hooks/post-applypatch |
| 212 | fi |