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