#!/bin/sh # # Copyright (c) 2005 Linus Torvalds # Copyright (c) 2005 Junio C Hamano # match $0 { with *-revert* test -t 0 && setglobal edit = '-e' setglobal replay = '' setglobal me = 'revert' setglobal USAGE = ''[--edit | --no-edit] [-n] '' with *-cherry-pick* setglobal replay = 't' setglobal edit = '' setglobal me = 'cherry-pick' setglobal USAGE = ''[--edit] [-n] [-r] [-x] '' with * echo >&2 "What are you talking about?> !2 "What are you talking about?" exit 1 } setglobal SUBDIRECTORY_OK = 'Yes' ;# we will cd up source git-sh-setup require_work_tree cd_to_toplevel setglobal no_commit = '' setglobal xopt = '' while case "$#" in 0) break ;; esac { match $1 { with -n|--n|--no|--no-|--no-c|--no-co|--no-com|--no-comm|\ --no-commi|--no-commit setglobal no_commit = 't' with -e|--e|--ed|--edi|--edit setglobal edit = '-e' with --n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit setglobal edit = '' with -r : no-op with -x|--i-really-want-to-expose-my-private-commit-object-name setglobal replay = '' with -X?* setglobal xopt = ""$xopt$[git rev-parse --sq-quote "--$(1#-X)]"" with --strategy-option=* setglobal xopt = ""$xopt$[git rev-parse --sq-quote "--$(1#--strategy-option=)]"" with -X|--strategy-option shift setglobal xopt = ""$xopt$[git rev-parse --sq-quote "--$1]"" with -* usage with * break } shift } set_reflog_action $me test "$me,$replay" = "revert,t" && usage match $no_commit { with t # We do not intend to commit immediately. We just want to # merge the differences in. setglobal head = $[git-write-tree] || die "Your index file is unmerged." with * setglobal head = $[git-rev-parse --verify HEAD] || die "You do not have a valid HEAD" setglobal files = $[git-diff-index --cached --name-only $head] || exit if test $files { die "Dirty index: cannot $me (dirty: $files)" } } setglobal rev = $[git-rev-parse --verify @Argv] && setglobal commit = $[git-rev-parse --verify "$rev^0] || die "Not a single commit $ifsjoin(Argv)" setglobal prev = $[git-rev-parse --verify "$commit^1" !2 >/dev/null] || die "Cannot run $me a root commit" git-rev-parse --verify "$commit^2" >/dev/null !2 > !1 && die "Cannot run $me a multi-parent commit." setglobal encoding = $[git config i18n.commitencoding || echo UTF-8] # "commit" is an existing commit. We would want to apply # the difference it introduces since its first parent "prev" # on top of the current HEAD if we are cherry-pick. Or the # reverse of it if we are revert. match $me { with revert git show -s --pretty=oneline --encoding="$encoding" $commit | sed -e ' s/^[^ ]* /Revert "/ s/$/"/ ' echo echo "This reverts commit $commit." test $rev = $commit || echo "(original 'git revert' arguments: $ifsjoin(Argv))" setglobal base = $commit, next = $prev with cherry-pick setglobal pick_author_script = '' /^author /{ s/'''''/'''''\\''''''''/g h s/^author \([^<]*\) <[^>]*> .*$/\1/ s/'''''/'''''\''''''''/g s/.*/GIT_AUTHOR_NAME='''''&'''''/p g s/^author [^<]* <\([^>]*\)> .*$/\1/ s/'''''/'''''\''''''''/g s/.*/GIT_AUTHOR_EMAIL='''''&'''''/p g s/^author [^<]* <[^>]*> \(.*\)$/\1/ s/'''''/'''''\''''''''/g s/.*/GIT_AUTHOR_DATE='''''&'''''/p q }'' setglobal logmsg = $[git show -s --pretty=raw --encoding="$encoding" $commit] setglobal set_author_env = $[echo $logmsg | env LANG=C LC_ALL=C sed -ne $pick_author_script] eval $set_author_env export GIT_AUTHOR_NAME export GIT_AUTHOR_EMAIL export GIT_AUTHOR_DATE echo $logmsg | sed -e '1,/^$/d' -e 's/^ //' match $replay { with '' echo "(cherry picked from commit $commit)" test $rev = $commit || echo "(original 'git cherry-pick' arguments: $ifsjoin(Argv))" } setglobal base = $prev, next = $commit } >.msg eval GITHEAD_$head=HEAD eval GITHEAD_$next='$(git show -s \ --pretty=oneline --encoding="$encoding" "$commit" | sed -e "s/^[^ ]* //")' export GITHEAD_$head GITHEAD_$next # This three way merge is an interesting one. We are at # $head, and would want to apply the change between $commit # and $prev on top of us (when reverting), or the change between # $prev and $commit on top of us (when cherry-picking or replaying). eval "git merge-recursive $xopt $base -- $head $next" && setglobal result = $[git-write-tree !2 >/dev/null] || do { mv -f .msg "$GIT_DIR/MERGE_MSG" do { echo ' Conflicts: ' git ls-files --unmerged | sed -e 's/^[^ ]* / /' | uniq } >>"$GIT_DIR/MERGE_MSG" echo >&2 "Automatic $me failed. After resolving the conflicts,> !2 "Automatic $me failed. After resolving the conflicts," echo >&2 "mark the corrected paths with 'git-add '> !2 "mark the corrected paths with 'git-add '" echo >&2 "and commit the result.> !2 "and commit the result." match $me { with cherry-pick echo >&2 "You may choose to use the following when making> !2 "You may choose to use the following when making" echo >&2 "the commit:> !2 "the commit:" echo >&2 $set_author_env> !2 "$set_author_env" } exit 1 } # If we are cherry-pick, and if the merge did not result in # hand-editing, we will hit this commit and inherit the original # author date and name. # If we are revert, or if our cherry-pick results in a hand merge, # we had better say that the current user is responsible for that. match $no_commit { with '' git-commit -n -F .msg $edit rm -f .msg }