1#!/bin/sh 2# 3# Copyright (c) 2005 Linus Torvalds 4# Copyright (c) 2005 Junio C Hamano 5# 6 7case"$0"in 8*-revert* ) 9test -t0&& edit=-e 10 replay= 11 me=revert 12 USAGE='[--edit | --no-edit] [-n] <commit-ish>';; 13*-cherry-pick* ) 14 replay=t 15 edit= 16 me=cherry-pick 17 USAGE='[--edit] [-n] [-r] [-x] <commit-ish>';; 18* ) 19echo>&2"What are you talking about?" 20exit1;; 21esac 22 23SUBDIRECTORY_OK=Yes ;# we will cd up 24. git-sh-setup 25require_work_tree 26cd_to_toplevel 27 28no_commit= 29xopt= 30while case"$#"in0)break;;esac 31do 32case"$1"in 33-n|--n|--no|--no-|--no-c|--no-co|--no-com|--no-comm|\ 34--no-commi|--no-commit) 35 no_commit=t 36;; 37-e|--e|--ed|--edi|--edit) 38 edit=-e 39;; 40--n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit) 41 edit= 42;; 43-r) 44: no-op;; 45-x|--i-really-want-to-expose-my-private-commit-object-name) 46 replay= 47;; 48-X?*) 49 xopt="$xopt$(git rev-parse --sq-quote "--${1#-X}")" 50;; 51--strategy-option=*) 52 xopt="$xopt$(git rev-parse --sq-quote "--${1#--strategy-option=}")" 53;; 54-X|--strategy-option) 55shift 56 xopt="$xopt$(git rev-parse --sq-quote "--$1")" 57;; 58-*) 59 usage 60;; 61*) 62break 63;; 64esac 65shift 66done 67 68set_reflog_action "$me" 69 70test"$me,$replay"="revert,t"&& usage 71 72case"$no_commit"in 73t) 74# We do not intend to commit immediately. We just want to 75# merge the differences in. 76head=$(git-write-tree)|| 77 die "Your index file is unmerged." 78;; 79*) 80head=$(git-rev-parse --verify HEAD)|| 81 die "You do not have a valid HEAD" 82 files=$(git-diff-index --cached --name-only $head)||exit 83if["$files"];then 84 die "Dirty index: cannot$me(dirty:$files)" 85fi 86;; 87esac 88 89rev=$(git-rev-parse --verify "$@")&& 90commit=$(git-rev-parse --verify "$rev^0")|| 91 die "Not a single commit $@" 92prev=$(git-rev-parse --verify "$commit^1" 2>/dev/null)|| 93 die "Cannot run$mea root commit" 94git-rev-parse --verify"$commit^2">/dev/null 2>&1&& 95 die "Cannot run$mea multi-parent commit." 96 97encoding=$(git config i18n.commitencoding || echo UTF-8) 98 99# "commit" is an existing commit. We would want to apply 100# the difference it introduces since its first parent "prev" 101# on top of the current HEAD if we are cherry-pick. Or the 102# reverse of it if we are revert. 103 104case"$me"in 105revert) 106 git show -s --pretty=oneline --encoding="$encoding"$commit| 107sed-e' 108 s/^[^ ]* /Revert "/ 109 s/$/"/ 110 ' 111echo 112echo"This reverts commit$commit." 113test"$rev"="$commit"|| 114echo"(original 'git revert' arguments: $@)" 115 base=$commit next=$prev 116;; 117 118cherry-pick) 119 pick_author_script=' 120 /^author /{ 121 s/'\''/'\''\\'\'\''/g 122 h 123 s/^author \([^<]*\) <[^>]*> .*$/\1/ 124 s/'\''/'\''\'\'\''/g 125 s/.*/GIT_AUTHOR_NAME='\''&'\''/p 126 127 g 128 s/^author [^<]* <\([^>]*\)> .*$/\1/ 129 s/'\''/'\''\'\'\''/g 130 s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p 131 132 g 133 s/^author [^<]* <[^>]*> \(.*\)$/\1/ 134 s/'\''/'\''\'\'\''/g 135 s/.*/GIT_AUTHOR_DATE='\''&'\''/p 136 137 q 138}' 139 140 logmsg=$(git show -s --pretty=raw --encoding="$encoding" "$commit") 141 set_author_env=$(echo "$logmsg" | 142 LANG=C LC_ALL=C sed -ne "$pick_author_script") 143 eval "$set_author_env" 144 export GIT_AUTHOR_NAME 145 export GIT_AUTHOR_EMAIL 146 export GIT_AUTHOR_DATE 147 148 echo "$logmsg" | 149 sed -e '1,/^$/d' -e 's/^ //' 150 case "$replay" in 151 '') 152 echo "(cherry picked from commit$commit)" 153 test "$rev" = "$commit" || 154 echo "(original 'git cherry-pick' arguments: $@)" 155 ;; 156 esac 157 base=$prevnext=$commit 158 ;; 159 160esac >.msg 161 162eval GITHEAD_$head=HEAD 163eval GITHEAD_$next='$(git show -s \ 164--pretty=oneline --encoding="$encoding""$commit"| 165sed-e"s/^[^ ]* //")' 166export GITHEAD_$headGITHEAD_$next 167 168# This three way merge is an interesting one. We are at 169#$head, and would want to apply the change between$commit 170# and$prevon top of us (when reverting), or the change between 171#$prevand$commiton top of us (when cherry-picking or replaying). 172 173eval "git merge-recursive$xopt$base--$head$next" && 174result=$(git-write-tree 2>/dev/null)|| { 175 mv -f .msg "$GIT_DIR/MERGE_MSG" 176 { 177 echo ' 178Conflicts: 179' 180 git ls-files --unmerged | 181 sed -e 's/^[^ ]* / /' | 182 uniq 183 } >>"$GIT_DIR/MERGE_MSG" 184 echo >&2 "Automatic$mefailed. After resolving the conflicts," 185 echo >&2 "mark the corrected paths with 'git-add<paths>'" 186 echo >&2 "and commit the result." 187 case "$me" in 188 cherry-pick) 189 echo >&2 "You may choose to use the following when making" 190 echo >&2 "the commit:" 191 echo >&2 "$set_author_env" 192 esac 193 exit 1 194} 195 196# If we are cherry-pick, and if the merge did not result in 197# hand-editing, we will hit this commit and inherit the original 198# author date and name. 199# If we are revert, or if our cherry-pick results in a hand merge, 200# we had better say that the current user is responsible for that. 201 202case "$no_commit" in 203'') 204 git-commit -n -F .msg$edit 205 rm -f .msg 206 ;; 207esac