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