diff options
-rw-r--r-- | Makefile | 1 | ||||
-rwxr-xr-x | git-rebase-script | 25 | ||||
-rwxr-xr-x | git-revert-script | 187 | ||||
-rwxr-xr-x | git-sh-setup-script | 11 |
4 files changed, 185 insertions, 39 deletions
@@ -215,6 +215,7 @@ check: install: $(PROG) $(SCRIPTS) $(INSTALL) -m755 -d $(DESTDIR)$(bindir) $(INSTALL) $(PROG) $(SCRIPTS) $(DESTDIR)$(bindir) + $(INSTALL) git-revert-script $(DESTDIR)$(bindir)/git-cherry-pick-script $(MAKE) -C templates install $(MAKE) -C tools install diff --git a/git-rebase-script b/git-rebase-script index a335b99178..b0893cc10f 100755 --- a/git-rebase-script +++ b/git-rebase-script @@ -37,25 +37,32 @@ git-rev-parse --verify "$upstream^0" >"$GIT_DIR/HEAD" || exit tmp=.rebase-tmp$$ fail=$tmp-fail -trap "rm -rf $tmp-*" 0 1 2 3 15 +trap "rm -rf $tmp-*" 1 2 3 15 >$fail -git-cherry $upstream $ours | -while read sign commit +git-cherry -v $upstream $ours | +while read sign commit msg do case "$sign" in - -) continue ;; + -) + echo >&2 "* Already applied: $msg" + continue ;; esac + echo >&2 "* Applying: $msg" S=`cat "$GIT_DIR/HEAD"` && - GIT_EXTERNAL_DIFF=git-apply-patch-script git-diff-tree -p $commit && - git-commit-script -C "$commit" || { + git-cherry-pick-script --replay $commit || { + echo >&2 "* Not applying the patch and continuing." echo $commit >>$fail - git-read-tree --reset -u $S + git-reset-script --hard $S } done if test -s $fail then - echo Some commits could not be rebased, check by hand: - cat $fail + echo >&2 Some commits could not be rebased, check by hand: + cat >&2 $fail + echo >&2 "(the same list of commits are found in $tmp)" + exit 1 +else + rm -f $fail fi diff --git a/git-revert-script b/git-revert-script index 22f2082fb1..dd5866ec96 100755 --- a/git-revert-script +++ b/git-revert-script @@ -1,37 +1,164 @@ #!/bin/sh +# +# Copyright (c) 2005 Linus Torvalds +# Copyright (c) 2005 Junio C Hamano +# . git-sh-setup-script || die "Not a git archive" -# We want a clean tree and clean index to be able to revert. -status=$(git status) -case "$status" in -'nothing to commit') ;; +case "$0" in +*-revert-* ) + me=revert ;; +*-cherry-pick-* ) + me=cherry-pick ;; +esac + +usage () { + case "$me" in + cherry-pick) + die "usage git $me [-n] [-r] <commit-ish>" + ;; + revert) + die "usage git $me [-n] <commit-ish>" + ;; + esac +} + +no_commit= replay= +while case "$#" in 0) break ;; esac +do + case "$1" in + -n|--n|--no|--no-|--no-c|--no-co|--no-com|--no-comm|\ + --no-commi|--no-commit) + no_commit=t + ;; + -r|--r|--re|--rep|--repl|--repla|--replay) + replay=t + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +test "$me,$replay" = "revert,t" && usage + +case "$no_commit" in +t) + # We do not intend to commit immediately. We just want to + # merge the differences in. + head=$(git-write-tree) || + die "Your index file is unmerged." + ;; *) - echo "$status" - die "Your working tree is dirty; cannot revert a previous patch." ;; + check_clean_tree || die "Cannot run $me from a dirty tree." + head=$(git-rev-parse --verify HEAD) || + die "You do not have a valid HEAD" + ;; esac rev=$(git-rev-parse --verify "$@") && -commit=$(git-rev-parse --verify "$rev^0") || exit -if git-diff-tree -R -M -p $commit | git-apply --index && - msg=$(git-rev-list --pretty=oneline --max-count=1 $commit) -then - { - echo "$msg" | sed -e ' - s/^[^ ]* /Revert "/ - s/$/"/' - echo - echo "This reverts $commit commit." - test "$rev" = "$commit" || - echo "(original 'git revert' arguments: $@)" - } | git commit -F - -else - # Now why did it fail? - parents=`git-cat-file commit "$commit" 2>/dev/null | - sed -ne '/^$/q;/^parent /p' | - wc -l` - case $parents in - 0) die "Cannot revert the root commit nor non commit-ish." ;; - 1) die "The patch does not apply." ;; - *) die "Cannot revert a merge commit." ;; - esac -fi +commit=$(git-rev-parse --verify "$rev^0") || + die "Not a single commit $@" +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." + +# "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. + +case "$me" in +revert) + git-rev-list --pretty=oneline --max-count=1 $commit | + sed -e ' + s/^[^ ]* /Revert "/ + s/$/"/' + echo + echo "This reverts $commit commit." + test "$rev" = "$commit" || + echo "(original 'git revert' arguments: $@)" + base=$commit next=$prev + ;; + +cherry-pick) + pick_author_script=' + /^author /{ + 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 + }' + set_author_env=`git-cat-file commit "$commit" | + sed -ne "$pick_author_script"` + eval "$set_author_env" + export GIT_AUTHOR_NAME + export GIT_AUTHOR_EMAIL + export GIT_AUTHOR_DATE + + git-cat-file commit $commit | sed -e '1,/^$/d' + case "$replay" in + '') + echo "(cherry picked from $commit commit)" + test "$rev" = "$commit" || + echo "(original 'git cherry-pick' arguments: $@)" + ;; + esac + base=$prev next=$commit + ;; + +esac >.msg + +# 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). + +echo >&2 "First trying simple merge strategy to $me." +git-read-tree -m -u $base $head $next && +result=$(git-write-tree 2>/dev/null) || { + echo >&2 "Simple $me fails; trying Automatic $me." + git-merge-cache -o git-merge-one-file-script -a || { + echo >&2 "Automatic $me failed. After fixing it up," + echo >&2 "you can use \"git commit -F .msg\"" + case "$me" in + cherry-pick) + echo >&2 "You may choose to use the following when making" + echo >&2 "the commit:" + echo >&2 "$set_author_env" + esac + exit 1 + } + result=$(git-write-tree) || exit +} +echo >&2 "Finished one $me." + +# 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. + +case "$no_commit" in +'') + git commit -F .msg + rm -f .msg + ;; +esac diff --git a/git-sh-setup-script b/git-sh-setup-script index 84e15df1bc..9ed5e85152 100755 --- a/git-sh-setup-script +++ b/git-sh-setup-script @@ -11,6 +11,17 @@ die() { exit 1 } +check_clean_tree() { + dirty1_=`git-update-cache -q --refresh` && { + dirty2_=`git-diff-cache --name-only --cached HEAD` + case "$dirty2_" in '') : ;; *) (exit 1) ;; esac + } || { + echo >&2 "$dirty1_" + echo "$dirty2_" | sed >&2 -e 's/^/modified: /' + (exit 1) + } +} + [ -h "$GIT_DIR/HEAD" ] && [ -d "$GIT_DIR/refs" ] && [ -d "$GIT_OBJECT_DIRECTORY/00" ] |