Code

Merge branch 'mz/rebase' into pu
authorJunio C Hamano <gitster@pobox.com>
Mon, 31 Jan 2011 03:03:21 +0000 (19:03 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 31 Jan 2011 03:03:21 +0000 (19:03 -0800)
* mz/rebase: (31 commits)
  rebase -i: remove unnecessary state rebase-root
  rebase -i: don't read unused variable preserve_merges
  git-rebase--am: remove unnecessary --3way option
  rebase -m: don't print exit code 2 when merge fails
  rebase -m: remember allow_rerere_autoupdate option
  rebase: remember strategy and strategy options
  rebase: remember verbose option
  rebase: extract code for writing basic state
  rebase: factor out sub command handling
  rebase: make -v a tiny bit more verbose
  rebase -i: align variable names
  rebase: show consistent conflict resolution hint
  rebase: extract am code to new source file
  rebase: extract merge code to new source file
  rebase: remove $branch as synonym for $orig_head
  rebase -i: support --stat
  rebase: factor out call to pre-rebase hook
  rebase: factor out clean work tree check
  rebase: factor out reference parsing
  rebase: reorder validation steps
  ...

Conflicts:
git-rebase--interactive.sh

1  2 
.gitignore
Makefile
git-rebase--interactive.sh
git-rebase.sh

diff --combined .gitignore
index faad9d02b624f9a86603629c2123c7ba82edd26c,ef040585e75ec19c4f0c77f6e34d4ba0e7d2b7cb..9ee7b5a6b4efbd1e0548ad20568f4213194a06a8
  /git-quiltimport
  /git-read-tree
  /git-rebase
+ /git-rebase--am
  /git-rebase--interactive
+ /git-rebase--merge
  /git-receive-pack
  /git-reflog
  /git-relink
  /git-rm
  /git-send-email
  /git-send-pack
 +/git-sh-i18n
  /git-sh-setup
  /git-shell
  /git-shortlog
  /git-show-branch
  /git-show-index
  /git-show-ref
 +/git-skew
  /git-stage
  /git-stash
  /git-status
  /test-sha1
  /test-sigchain
  /test-string-pool
 +/test-subprocess
  /test-svn-fe
  /test-treap
  /common-cmds.h
  *.pdb
  /Debug/
  /Release/
 +/share/
diff --combined Makefile
index 7b024534536cc86350ed811b22e9a5886f3d0ae8,459df3a2a9bdace4c916618e3eebc25c2378f9dd..efd7b3a0c11d44e7992d972e3e147da9f3ec39e8
+++ b/Makefile
@@@ -34,30 -34,6 +34,30 @@@ all:
  # Define NO_EXPAT if you do not have expat installed.  git-http-push is
  # not built, and you cannot push using http:// and https:// transports.
  #
 +# Define NO_GETTEXT if you don't want to build with Git with gettext
 +# support. Building it requires GNU libintl or another gettext
 +# implementation, and additionally libintl-perl at runtime.
 +#
 +# Define NEEDS_LIBINTL if you haven't set NO_GETTEXT and your system
 +# needs to be explicitly linked to -lintl. It's defined automatically
 +# on platforms where we don't expect glibc (Linux, Hurd,
 +# GNU/kFreeBSD), which includes libintl.
 +#
 +# Define HAVE_LIBCHARSET_H if you haven't set NO_GETTEXT and you can't
 +# trust the langinfo.h's nl_langinfo(CODESET) function to return the
 +# current character set. GNU and Solaris have a nl_langinfo(CODESET),
 +# FreeBSD can use either, but MinGW and some others need to use
 +# libcharset.h's locale_charset() instead.
 +#
 +# Define GNU_GETTEXT if you're using the GNU implementation of
 +# libintl. We define this everywhere except on Solaris, which has its
 +# own gettext implementation. If GNU_GETTEXT is set we'll use GNU
 +# extensions like `msgfmt --check'.
 +#
 +# Define GETTEXT_POISON to turn all strings that use gettext into
 +# gibberish. This option should only be used by the Git developers to
 +# check that the Git gettext implementation itself is sane.
 +#
  # Define EXPATDIR=/foo/bar if your expat header and library files are in
  # /foo/bar/include and /foo/bar/lib directories.
  #
@@@ -313,7 -289,6 +313,7 @@@ infodir = share/inf
  gitexecdir = libexec/git-core
  sharedir = $(prefix)/share
  gitwebdir = $(sharedir)/gitweb
 +localedir = $(sharedir)/locale
  template_dir = share/git-core/templates
  htmldir = share/doc/git-doc
  ifeq ($(prefix),/usr)
@@@ -329,7 -304,7 +329,7 @@@ lib = li
  # DESTDIR=
  pathsep = :
  
 -export prefix bindir sharedir sysconfdir gitwebdir
 +export prefix bindir sharedir sysconfdir gitwebdir localedir
  
  CC = gcc
  AR = ar
@@@ -344,8 -319,6 +344,8 @@@ TCLTK_PATH = wis
  PTHREAD_LIBS = -lpthread
  PTHREAD_CFLAGS =
  GCOV = gcov
 +XGETTEXT = xgettext
 +MSGFMT = msgfmt
  
  export TCL_PATH TCLTK_PATH
  
@@@ -396,7 -369,9 +396,9 @@@ SCRIPT_SH += git-merge-resolve.s
  SCRIPT_SH += git-mergetool.sh
  SCRIPT_SH += git-pull.sh
  SCRIPT_SH += git-quiltimport.sh
+ SCRIPT_SH += git-rebase--am.sh
  SCRIPT_SH += git-rebase--interactive.sh
+ SCRIPT_SH += git-rebase--merge.sh
  SCRIPT_SH += git-rebase.sh
  SCRIPT_SH += git-repack.sh
  SCRIPT_SH += git-request-pull.sh
@@@ -407,7 -382,6 +409,7 @@@ SCRIPT_SH += git-web--browse.s
  SCRIPT_LIB += git-mergetool--lib
  SCRIPT_LIB += git-parse-remote
  SCRIPT_LIB += git-sh-setup
 +SCRIPT_LIB += git-sh-i18n
  
  SCRIPT_PERL += git-add--interactive.perl
  SCRIPT_PERL += git-difftool.perl
@@@ -459,11 -433,9 +461,11 @@@ TEST_PROGRAMS_NEED_X += test-run-comman
  TEST_PROGRAMS_NEED_X += test-sha1
  TEST_PROGRAMS_NEED_X += test-sigchain
  TEST_PROGRAMS_NEED_X += test-string-pool
 +TEST_PROGRAMS_NEED_X += test-subprocess
  TEST_PROGRAMS_NEED_X += test-svn-fe
  TEST_PROGRAMS_NEED_X += test-treap
  TEST_PROGRAMS_NEED_X += test-index-version
 +TEST_PROGRAMS_NEED_X += test-mktemp
  
  TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
  
@@@ -588,7 -560,6 +590,7 @@@ LIB_H += userdiff.
  LIB_H += utf8.h
  LIB_H += xdiff-interface.h
  LIB_H += xdiff/xdiff.h
 +LIB_H += gettext.h
  
  LIB_OBJS += abspath.o
  LIB_OBJS += advice.o
@@@ -630,9 -601,6 +632,9 @@@ LIB_OBJS += entry.
  LIB_OBJS += environment.o
  LIB_OBJS += exec_cmd.o
  LIB_OBJS += fsck.o
 +ifndef NO_GETTEXT
 +LIB_OBJS += gettext.o
 +endif
  LIB_OBJS += graph.o
  LIB_OBJS += grep.o
  LIB_OBJS += hash.o
@@@ -787,7 -755,6 +789,7 @@@ BUILTIN_OBJS += builtin/send-pack.
  BUILTIN_OBJS += builtin/shortlog.o
  BUILTIN_OBJS += builtin/show-branch.o
  BUILTIN_OBJS += builtin/show-ref.o
 +BUILTIN_OBJS += builtin/skew.o
  BUILTIN_OBJS += builtin/stripspace.o
  BUILTIN_OBJS += builtin/symbolic-ref.o
  BUILTIN_OBJS += builtin/tag.o
@@@ -810,22 -777,6 +812,22 @@@ EXTLIBS 
  # Platform specific tweaks
  #
  
 +# Platform specific defaults. Where we'd only like some feature on the
 +# minority of systems, e.g. if linking to a library isn't needed
 +# because its features are included in the GNU C library.
 +ifndef NO_GETTEXT
 +      # Systems that use GNU gettext and glibc are the exception
 +      NEEDS_LIBINTL = YesPlease
 +
 +      # Systems that don't use GNU gettext are the exception. Only
 +      # Solaris has a mature non-GNU gettext implementation.
 +      GNU_GETTEXT = YesPlease
 +
 +      # Since we assume a GNU gettext by default we also assume a
 +      # GNU-like langinfo.h by default
 +      HAVE_LIBCHARSET_H =
 +endif
 +
  # We choose to avoid "if .. else if .. else .. endif endif"
  # because maintaining the nesting to match is a pain.  If
  # we had "elif" things would have been much nicer...
@@@ -841,13 -792,11 +843,13 @@@ ifeq ($(uname_S),Linux
        NO_STRLCPY = YesPlease
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
 +      NEEDS_LIBINTL =
  endif
  ifeq ($(uname_S),GNU/kFreeBSD)
        NO_STRLCPY = YesPlease
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
 +      NEEDS_LIBINTL =
  endif
  ifeq ($(uname_S),UnixWare)
        CC = cc
@@@ -914,9 -863,6 +916,9 @@@ ifeq ($(uname_S),SunOS
        NO_MKSTEMPS = YesPlease
        NO_REGEX = YesPlease
        NO_FNMATCH_CASEFOLD = YesPlease
 +ifndef NO_GETTEXT
 +      GNU_GETTEXT =
 +endif
        ifeq ($(uname_R),5.6)
                SOCKLEN_T = int
                NO_HSTRERROR = YesPlease
@@@ -1043,7 -989,6 +1045,7 @@@ ifeq ($(uname_S),GNU
        NO_STRLCPY=YesPlease
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
 +      NEEDS_LIBINTL =
  endif
  ifeq ($(uname_S),IRIX)
        NO_SETENV = YesPlease
@@@ -1242,9 -1187,6 +1244,9 @@@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT)
        EXTLIBS += /mingw/lib/libz.a
        NO_R_TO_GCC_LINKER = YesPlease
        INTERNAL_QSORT = YesPlease
 +ifndef NO_GETTEXT
 +      HAVE_LIBCHARSET_H = YesPlease
 +endif
  else
        NO_CURL = YesPlease
  endif
@@@ -1609,22 -1551,6 +1611,22 @@@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEX
        export GIT_TEST_CMP_USE_COPIED_CONTEXT
  endif
  
 +ifdef NO_GETTEXT
 +      COMPAT_CFLAGS += -DNO_GETTEXT
 +endif
 +
 +ifdef NEEDS_LIBINTL
 +      EXTLIBS += -lintl
 +endif
 +
 +ifdef GNU_GETTEXT
 +      MSGFMT += --check
 +endif
 +
 +ifdef GETTEXT_POISON
 +      COMPAT_CFLAGS += -DGETTEXT_POISON
 +endif
 +
  ifeq ($(TCLTK_PATH),)
  NO_TCLTK=NoThanks
  endif
@@@ -1655,7 -1581,6 +1657,7 @@@ ifndef 
        QUIET_GEN      = @echo '   ' GEN $@;
        QUIET_LNCP     = @echo '   ' LN/CP $@;
        QUIET_GCOV     = @echo '   ' GCOV $@;
 +      QUIET_MSGFMT   = @echo '   ' MSGFMT $@;
        QUIET_SUBDIR0  = +@subdir=
        QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
                         $(MAKE) $(PRINT_DIR) -C $$subdir
@@@ -1685,9 -1610,7 +1687,9 @@@ template_dir_SQ = $(subst ','\'',$(temp
  htmldir_SQ = $(subst ','\'',$(htmldir))
  prefix_SQ = $(subst ','\'',$(prefix))
  gitwebdir_SQ = $(subst ','\'',$(gitwebdir))
 +sharedir_SQ = $(subst ','\'',$(sharedir))
  
 +LOCALEDIR_SQ = $(subst ','\'',$(localedir))
  SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
  PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
  PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
@@@ -1737,7 -1660,7 +1739,7 @@@ ifndef NO_TCLT
        $(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
  endif
  ifndef NO_PERL
 -      $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
 +      $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all
  endif
  ifndef NO_PYTHON
        $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
@@@ -1785,7 -1708,6 +1787,7 @@@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|
      -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
      -e 's|@@DIFF@@|$(DIFF_SQ)|' \
      -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
 +    -e 's|@@LOCALEDIR@@|$(LOCALEDIR_SQ)|g' \
      -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
      -e $(BROKEN_PATH_FIX) \
      $@.sh >$@+
@@@ -2064,10 -1986,6 +2066,10 @@@ attr.s attr.o: EXTRA_CPPFLAGS = -DETC_G
  
  http.s http.o: EXTRA_CPPFLAGS = -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
  
 +ifdef HAVE_LIBCHARSET_H
 +gettext.s gettext.o: EXTRA_CPPFLAGS = -DHAVE_LIBCHARSET_H
 +endif
 +
  ifdef NO_EXPAT
  http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
  endif
@@@ -2141,41 -2059,6 +2143,41 @@@ cscope
        $(RM) cscope*
        $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
  
 +XGETTEXT_OPTIONS = \
 +      --add-comments \
 +      --msgid-bugs-address="Git Mailing List <git@vger.kernel.org>" \
 +      --from-code=UTF-8 \
 +      --output=po/git.pot
 +
 +XGETTEXT_OPTIONS_C = $(XGETTEXT_OPTIONS) --keyword=_ --keyword=N_ --language=C
 +XGETTEXT_OPTIONS_SH = $(XGETTEXT_OPTIONS) --language=Shell
 +XGETTEXT_OPTIONS_PERL = $(XGETTEXT_OPTIONS) --keyword=__ --language=Perl
 +
 +LOCALIZED_C = $(C_OBJ:o=c)
 +LOCALIZED_SH = $(SCRIPT_SH)
 +LOCALIZED_PERL = $(SCRIPT_PERL)
 +
 +ifdef XGETTEXT_INCLUDE_TESTS
 +LOCALIZED_C += t/t0200/test.c
 +LOCALIZED_SH += t/t0200/test.sh
 +LOCALIZED_PERL += t/t0200/test.perl
 +endif
 +
 +pot:
 +      $(XGETTEXT) $(XGETTEXT_OPTIONS_C) $(LOCALIZED_C)
 +      $(XGETTEXT) $(XGETTEXT_OPTIONS_SH) --join-existing $(LOCALIZED_SH)
 +      $(XGETTEXT) $(XGETTEXT_OPTIONS_PERL) --join-existing $(LOCALIZED_PERL)
 +
 +POFILES := $(wildcard po/*.po)
 +MOFILES := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/git.mo,$(POFILES))
 +MODIRS := $(patsubst po/%.po,share/locale/%/LC_MESSAGES/,$(POFILES))
 +ifndef NO_GETTEXT
 +all:: $(MOFILES)
 +endif
 +share/locale/%/LC_MESSAGES/git.mo: po/%.po
 +      @mkdir -p $(dir $@)
 +      $(QUIET_MSGFMT)$(MSGFMT) -o $@ $<
 +
  ### Detect prefix changes
  TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
               $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
@@@ -2205,8 -2088,6 +2207,8 @@@ endi
  ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
        @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@
  endif
 +      @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@
 +      @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@
  
  ### Detect Tck/Tk interpreter path changes
  ifndef NO_TCLTK
@@@ -2304,11 -2185,6 +2306,11 @@@ install: al
        $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
 +ifndef NO_GETTEXT
 +      $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sharedir_SQ)/locale'
 +      (cd share && tar cf - locale) | \
 +              (cd '$(DESTDIR_SQ)$(sharedir_SQ)' && umask 022 && tar xof -)
 +endif
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
  ifndef NO_PERL
        $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
@@@ -2466,10 -2342,6 +2468,10 @@@ ifndef NO_TCLT
        $(MAKE) -C git-gui clean
  endif
        $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
 +ifndef NO_GETTEXT
 +      $(RM) po/git.pot
 +      $(RM) -r share/
 +endif
  
  .PHONY: all install clean strip
  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
index 5873ba4bc3b2a94cd7754ae572072fd745dc059d,a9f44d81f27d63696aa36ea2cd8fdb932cca133d..71b996b5d3e63660e5b5a2c8e9597acc7664383f
  # The original idea comes from Eric W. Biederman, in
  # http://article.gmane.org/gmane.comp.version-control.git/22407
  
- OPTIONS_KEEPDASHDASH=
- OPTIONS_SPEC="\
- git-rebase [-i] [options] [--] <upstream> [<branch>]
- git-rebase [-i] (--continue | --abort | --skip)
- --
-  Available options are
- v,verbose          display a diffstat of what changed upstream
- onto=              rebase onto given branch instead of upstream
- p,preserve-merges  try to recreate merges instead of ignoring them
- s,strategy=        use the given merge strategy
- no-ff              cherry-pick all commits, even if unchanged
- m,merge            always used (no-op)
- i,interactive      always used (no-op)
-  Actions:
- continue           continue rebasing process
- abort              abort rebasing process and restore original branch
- skip               skip current patch and continue rebasing process
- no-verify          override pre-rebase hook from stopping the operation
- verify             allow pre-rebase hook to run
- root               rebase all reachable commmits up to the root(s)
- autosquash         move commits that begin with squash!/fixup! under -i
- "
  . git-sh-setup
- require_work_tree
- DOTEST="$GIT_DIR/rebase-merge"
  
  # The file containing rebase commands, comments, and empty lines.
  # This file is created by "git rebase -i" then edited by the user.  As
  # the lines are processed, they are removed from the front of this
  # file and written to the tail of $DONE.
- TODO="$DOTEST"/git-rebase-todo
+ TODO="$state_dir"/git-rebase-todo
  
  # The rebase command lines that have already been processed.  A line
  # is moved here when it is first handled, before any associated user
  # actions.
- DONE="$DOTEST"/done
+ DONE="$state_dir"/done
  
  # The commit message that is planned to be used for any changes that
  # need to be committed following a user interaction.
- MSG="$DOTEST"/message
+ MSG="$state_dir"/message
  
  # The file into which is accumulated the suggested commit message for
  # squash/fixup commands.  When the first of a series of squash/fixups
  # written to the file so far (including the initial "pick" commit).
  # Each time that a commit message is processed, this line is read and
  # updated.  It is deleted just before the combined commit is made.
- SQUASH_MSG="$DOTEST"/message-squash
+ SQUASH_MSG="$state_dir"/message-squash
  
  # If the current series of squash/fixups has not yet included a squash
  # command, then this file exists and holds the commit message of the
  # original "pick" commit.  (If the series ends without a "squash"
  # command, then this can be used as the commit message of the combined
  # commit without opening the editor.)
- FIXUP_MSG="$DOTEST"/message-fixup
+ FIXUP_MSG="$state_dir"/message-fixup
  
  # $REWRITTEN is the name of a directory containing files for each
  # commit that is reachable by at least one merge base of $HEAD and
- # $UPSTREAM. They are not necessarily rewritten, but their children
+ # $upstream. They are not necessarily rewritten, but their children
  # might be.  This ensures that commits on merged, but otherwise
  # unrelated side branches are left alone. (Think "X" in the man page's
  # example.)
- REWRITTEN="$DOTEST"/rewritten
+ REWRITTEN="$state_dir"/rewritten
  
- DROPPED="$DOTEST"/dropped
+ DROPPED="$state_dir"/dropped
  
  # A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
  # GIT_AUTHOR_DATE that will be used for the commit that is currently
  # being rebased.
- AUTHOR_SCRIPT="$DOTEST"/author-script
+ AUTHOR_SCRIPT="$state_dir"/author-script
  
  # When an "edit" rebase command is being processed, the SHA1 of the
  # commit to be edited is recorded in this file.  When "git rebase
  # will be amended to the HEAD commit, but only provided the HEAD
  # commit is still the commit to be edited.  When any other rebase
  # command is processed, this file is deleted.
- AMEND="$DOTEST"/amend
+ AMEND="$state_dir"/amend
  
  # For the post-rewrite hook, we make a list of rewritten commits and
  # their new sha1s.  The rewritten-pending list keeps the sha1s of
  # commits that have been processed, but not committed yet,
  # e.g. because they are waiting for a 'squash' command.
- REWRITTEN_LIST="$DOTEST"/rewritten-list
- REWRITTEN_PENDING="$DOTEST"/rewritten-pending
- PRESERVE_MERGES=
- STRATEGY=
- ONTO=
- VERBOSE=
- OK_TO_SKIP_PRE_REBASE=
- REBASE_ROOT=
- AUTOSQUASH=
- test "$(git config --bool rebase.autosquash)" = "true" && AUTOSQUASH=t
- NEVER_FF=
- GIT_CHERRY_PICK_HELP="\
- hint: after resolving the conflicts, mark the corrected paths
- hint: with 'git add <paths>' and run 'git rebase --continue'"
+ REWRITTEN_LIST="$state_dir"/rewritten-list
+ REWRITTEN_PENDING="$state_dir"/rewritten-pending
+ GIT_CHERRY_PICK_HELP="$RESOLVEMSG"
  export GIT_CHERRY_PICK_HELP
  
  warn () {
        printf '%s\n' "$*" >&2
  }
  
- output () {
-       case "$VERBOSE" in
-       '')
-               output=$("$@" 2>&1 )
-               status=$?
-               test $status != 0 && printf "%s\n" "$output"
-               return $status
-               ;;
-       *)
-               "$@"
-               ;;
-       esac
- }
  # Output the commit message for the specified commit.
  commit_message () {
        git cat-file commit "$1" | sed "1,/^$/d"
  }
  
- run_pre_rebase_hook () {
-       if test -z "$OK_TO_SKIP_PRE_REBASE" &&
-          test -x "$GIT_DIR/hooks/pre-rebase"
-       then
-               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
-                       echo >&2 "The pre-rebase hook refused to rebase."
-                       exit 1
-               }
-       fi
- }
  ORIG_REFLOG_ACTION="$GIT_REFLOG_ACTION"
  
  comment_for_reflog () {
@@@ -177,7 -113,7 +113,7 @@@ mark_action_done () 
        then
                last_count=$count
                printf "Rebasing (%d/%d)\r" $count $total
-               test -z "$VERBOSE" || echo
+               test -z "$verbose" || echo
        fi
  }
  
@@@ -193,7 -129,7 +129,7 @@@ make_patch () 
        *)
                echo "Root commit"
                ;;
-       esac > "$DOTEST"/patch
+       esac > "$state_dir"/patch
        test -f "$MSG" ||
                commit_message "$1" > "$MSG"
        test -f "$AUTHOR_SCRIPT" ||
  }
  
  die_with_patch () {
-       echo "$1" > "$DOTEST"/stopped-sha
+       echo "$1" > "$state_dir"/stopped-sha
        make_patch "$1"
        git rerere
        die "$2"
  }
  
  die_abort () {
-       rm -rf "$DOTEST"
+       rm -rf "$state_dir"
        die "$1"
  }
  
@@@ -228,15 -164,10 +164,10 @@@ do_with_author () 
  pick_one () {
        ff=--ff
        case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
-       case "$NEVER_FF" in '') ;; ?*) ff= ;; esac
+       case "$force_rebase" in '') ;; ?*) ff= ;; esac
        output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
        test -d "$REWRITTEN" &&
                pick_one_preserving_merges "$@" && return
-       if test -n "$REBASE_ROOT"
-       then
-               output git cherry-pick "$@"
-               return
-       fi
        output git cherry-pick $ff "$@"
  }
  
@@@ -253,20 -184,20 +184,20 @@@ pick_one_preserving_merges () 
        esac
        sha1=$(git rev-parse $sha1)
  
-       if test -f "$DOTEST"/current-commit
+       if test -f "$state_dir"/current-commit
        then
                if test "$fast_forward" = t
                then
                        while read current_commit
                        do
                                git rev-parse HEAD > "$REWRITTEN"/$current_commit
-                       done <"$DOTEST"/current-commit
-                       rm "$DOTEST"/current-commit ||
+                       done <"$state_dir"/current-commit
+                       rm "$state_dir"/current-commit ||
                        die "Cannot write current commit's replacement sha1"
                fi
        fi
  
-       echo $sha1 >> "$DOTEST"/current-commit
+       echo $sha1 >> "$state_dir"/current-commit
  
        # rewrite parents; if none were rewritten, we can fast-forward.
        new_parents=
                        # No point in merging the first parent, that's HEAD
                        new_parents=${new_parents# $first_parent}
                        if ! do_with_author output \
-                               git merge $STRATEGY -m "$msg" $new_parents
+                               git merge ${strategy:+-s $strategy} -m "$msg" \
+                                       $new_parents
                        then
                                printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG
                                die_with_patch $sha1 "Error redoing merge $sha1"
@@@ -472,7 -404,7 +404,7 @@@ do_next () 
                mark_action_done
                pick_one $sha1 ||
                        die_with_patch $sha1 "Could not apply $sha1... $rest"
-               echo "$sha1" > "$DOTEST"/stopped-sha
+               echo "$sha1" > "$state_dir"/stopped-sha
                make_patch $sha1
                git rev-parse --verify HEAD > "$AMEND"
                warn "Stopped at $sha1... $rest"
                printf 'Executing: %s\n' "$rest"
                # "exec" command doesn't take a sha1 in the todo-list.
                # => can't just use $sha1 here.
-               git rev-parse --verify HEAD > "$DOTEST"/stopped-sha
+               git rev-parse --verify HEAD > "$state_dir"/stopped-sha
                ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution
                status=$?
                if test "$status" -ne 0
        test -s "$TODO" && return
  
        comment_for_reflog finish &&
-       HEADNAME=$(cat "$DOTEST"/head-name) &&
-       OLDHEAD=$(cat "$DOTEST"/head) &&
-       SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) &&
+       SHORTONTO=$(git rev-parse --short $onto) &&
        NEWHEAD=$(git rev-parse HEAD) &&
-       case $HEADNAME in
+       case $head_name in
        refs/*)
-               message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO" &&
-               git update-ref -m "$message" $HEADNAME $NEWHEAD $OLDHEAD &&
-               git symbolic-ref HEAD $HEADNAME
+               message="$GIT_REFLOG_ACTION: $head_name onto $SHORTONTO" &&
+               git update-ref -m "$message" $head_name $NEWHEAD $orig_head &&
+               git symbolic-ref HEAD $head_name
                ;;
        esac && {
-               test ! -f "$DOTEST"/verbose ||
-                       git diff-tree --stat $(cat "$DOTEST"/head)..HEAD
+               test ! -f "$state_dir"/verbose ||
+                       git diff-tree --stat $orig_head..HEAD
        } &&
        {
                test -s "$REWRITTEN_LIST" &&
                "$GIT_DIR"/hooks/post-rewrite rebase < "$REWRITTEN_LIST"
                true # we don't care if this hook failed
        fi &&
-       rm -rf "$DOTEST" &&
+       rm -rf "$state_dir" &&
        git gc --auto &&
-       warn "Successfully rebased and updated $HEADNAME."
+       warn "Successfully rebased and updated $head_name."
  
        exit
  }
@@@ -618,11 -548,11 +548,11 @@@ skip_unnecessary_picks () 
                # fd=3 means we skip the command
                case "$fd,$command" in
                3,pick|3,p)
-                       # pick a commit whose parent is current $ONTO -> skip
+                       # pick a commit whose parent is current $onto -> skip
                        sha1=${rest%% *}
                        case "$(git rev-parse --verify --quiet "$sha1"^)" in
-                       "$ONTO"*)
-                               ONTO=$sha1
+                       "$onto"*)
+                               onto=$sha1
                                ;;
                        *)
                                fd=1
        mv -f "$TODO".new "$TODO" &&
        case "$(peek_next_command)" in
        squash|s|fixup|f)
-               record_in_rewritten "$ONTO"
+               record_in_rewritten "$onto"
                ;;
        esac ||
        die "Could not skip unnecessary pick commands"
  }
  
- # check if no other options are set
- is_standalone () {
-       test $# -eq 2 -a "$2" = '--' &&
-       test -z "$ONTO" &&
-       test -z "$PRESERVE_MERGES" &&
-       test -z "$STRATEGY" &&
-       test -z "$VERBOSE"
- }
- get_saved_options () {
-       test -d "$REWRITTEN" && PRESERVE_MERGES=t
-       test -f "$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)"
-       test -f "$DOTEST"/verbose && VERBOSE=t
-       test -f "$DOTEST"/rebase-root && REBASE_ROOT=t
- }
  # Rearrange the todo list that has both "pick sha1 msg" and
  # "pick sha1 fixup!/squash! msg" appears in it so that the latter
  # comes immediately after the former, and change "pick" to
@@@ -724,294 -638,157 +638,157 @@@ rearrange_squash () 
        rm -f "$1.sq" "$1.rearranged"
  }
  
- LF='
- '
- parse_onto () {
-       case "$1" in
-       *...*)
-               if      left=${1%...*} right=${1#*...} &&
-                       onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
-               then
-                       case "$onto" in
-                       ?*"$LF"?* | '')
-                               exit 1 ;;
-                       esac
-                       echo "$onto"
-                       exit 0
-               fi
-       esac
-       git rev-parse --verify "$1^0"
- }
- while test $# != 0
- do
-       case "$1" in
-       --no-verify)
-               OK_TO_SKIP_PRE_REBASE=yes
-               ;;
-       --verify)
-               OK_TO_SKIP_PRE_REBASE=
-               ;;
-       --continue)
-               is_standalone "$@" || usage
-               get_saved_options
-               comment_for_reflog continue
-               test -d "$DOTEST" || die "No interactive rebase running"
-               # Sanity check
-               git rev-parse --verify HEAD >/dev/null ||
-                       die "Cannot read HEAD"
-               git update-index --ignore-submodules --refresh &&
-                       git diff-files --quiet --ignore-submodules ||
-                       die "Working tree is dirty"
-               # do we have anything to commit?
-               if git diff-index --cached --quiet --ignore-submodules HEAD --
+ case "$action" in
+ continue)
+       # do we have anything to commit?
+       if git diff-index --cached --quiet --ignore-submodules HEAD --
+       then
+               : Nothing to commit -- skip this
+       else
+               . "$AUTHOR_SCRIPT" ||
+                       die "Cannot find the author identity"
+               amend=
+               if test -f "$AMEND"
                then
-                       : Nothing to commit -- skip this
-               else
-                       . "$AUTHOR_SCRIPT" ||
-                               die "Cannot find the author identity"
-                       amend=
-                       if test -f "$AMEND"
-                       then
-                               amend=$(git rev-parse --verify HEAD)
-                               test "$amend" = $(cat "$AMEND") ||
-                               die "\
+                       amend=$(git rev-parse --verify HEAD)
+                       test "$amend" = $(cat "$AMEND") ||
+                       die "\
  You have uncommitted changes in your working tree. Please, commit them
  first and then run 'git rebase --continue' again."
-                               git reset --soft HEAD^ ||
-                               die "Cannot rewind the HEAD"
-                       fi
-                       do_with_author git commit --no-verify -F "$MSG" -e || {
-                               test -n "$amend" && git reset --soft $amend
-                               die "Could not commit staged changes."
-                       }
+                       git reset --soft HEAD^ ||
+                       die "Cannot rewind the HEAD"
                fi
+               do_with_author git commit --no-verify -F "$MSG" -e || {
+                       test -n "$amend" && git reset --soft $amend
+                       die "Could not commit staged changes."
+               }
+       fi
  
-               record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
-               require_clean_work_tree "rebase"
-               do_rest
-               ;;
-       --abort)
-               is_standalone "$@" || usage
-               get_saved_options
-               comment_for_reflog abort
-               git rerere clear
-               test -d "$DOTEST" || die "No interactive rebase running"
-               HEADNAME=$(cat "$DOTEST"/head-name)
-               HEAD=$(cat "$DOTEST"/head)
-               case $HEADNAME in
-               refs/*)
-                       git symbolic-ref HEAD $HEADNAME
-                       ;;
-               esac &&
-               output git reset --hard $HEAD &&
-               rm -rf "$DOTEST"
-               exit
-               ;;
-       --skip)
-               is_standalone "$@" || usage
-               get_saved_options
-               comment_for_reflog skip
-               git rerere clear
-               test -d "$DOTEST" || die "No interactive rebase running"
-               output git reset --hard && do_rest
-               ;;
-       -s)
-               case "$#,$1" in
-               *,*=*)
-                       STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
-               1,*)
-                       usage ;;
-               *)
-                       STRATEGY="-s $2"
-                       shift ;;
-               esac
-               ;;
-       -m)
-               # we use merge anyway
-               ;;
-       -v)
-               VERBOSE=t
-               ;;
-       -p)
-               PRESERVE_MERGES=t
-               ;;
-       -i)
-               # yeah, we know
-               ;;
-       --no-ff)
-               NEVER_FF=t
-               ;;
-       --root)
-               REBASE_ROOT=t
-               ;;
-       --autosquash)
-               AUTOSQUASH=t
-               ;;
-       --no-autosquash)
-               AUTOSQUASH=
-               ;;
-       --onto)
-               shift
-               ONTO=$(parse_onto "$1") ||
-                       die "Does not point to a valid commit: $1"
-               ;;
-       --)
-               shift
-               test -z "$REBASE_ROOT" -a $# -ge 1 -a $# -le 2 ||
-               test ! -z "$REBASE_ROOT" -a $# -le 1 || usage
-               test -d "$DOTEST" &&
-                       die "Interactive rebase already started"
-               git var GIT_COMMITTER_IDENT >/dev/null ||
-                       die "You need to set your committer info first"
+       record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
  
-               if test -z "$REBASE_ROOT"
-               then
-                       UPSTREAM_ARG="$1"
-                       UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
-                       test -z "$ONTO" && ONTO=$UPSTREAM
-                       shift
-               else
-                       UPSTREAM=
-                       UPSTREAM_ARG=--root
-                       test -z "$ONTO" &&
-                               die "You must specify --onto when using --root"
-               fi
-               run_pre_rebase_hook "$UPSTREAM_ARG" "$@"
+       require_clean_work_tree "rebase"
+       do_rest
+       ;;
+ skip)
+       git rerere clear
  
-               comment_for_reflog start
+       do_rest
+       ;;
+ esac
  
-               require_clean_work_tree "rebase" "Please commit or stash them."
+ git var GIT_COMMITTER_IDENT >/dev/null ||
+       die "You need to set your committer info first"
  
-               if test ! -z "$1"
-               then
-                       output git checkout "$1" -- ||
-                               die "Could not checkout $1"
-               fi
+ comment_for_reflog start
  
              HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
-               mkdir "$DOTEST" || die "Could not create temporary $DOTEST"
if test ! -z "$switch_to"
+ then
 -      output git checkout "$switch_to" ||
++      output git checkout "$switch_to" -- ||
+               die "Could not checkout $switch_to"
+ fi
  
-               : > "$DOTEST"/interactive || die "Could not mark as interactive"
-               git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
-                       echo "detached HEAD" > "$DOTEST"/head-name
+ orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
+ mkdir "$state_dir" || die "Could not create temporary $state_dir"
  
-               echo $HEAD > "$DOTEST"/head
-               case "$REBASE_ROOT" in
-               '')
-                       rm -f "$DOTEST"/rebase-root ;;
-               *)
-                       : >"$DOTEST"/rebase-root ;;
-               esac
-               echo $ONTO > "$DOTEST"/onto
-               test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy
-               test t = "$VERBOSE" && : > "$DOTEST"/verbose
-               if test t = "$PRESERVE_MERGES"
-               then
-                       if test -z "$REBASE_ROOT"
-                       then
-                               mkdir "$REWRITTEN" &&
-                               for c in $(git merge-base --all $HEAD $UPSTREAM)
-                               do
-                                       echo $ONTO > "$REWRITTEN"/$c ||
-                                               die "Could not init rewritten commits"
-                               done
-                       else
-                               mkdir "$REWRITTEN" &&
-                               echo $ONTO > "$REWRITTEN"/root ||
-                                       die "Could not init rewritten commits"
-                       fi
-                       # No cherry-pick because our first pass is to determine
-                       # parents to rewrite and skipping dropped commits would
-                       # prematurely end our probe
-                       MERGES_OPTION=
-                       first_after_upstream="$(git rev-list --reverse --first-parent $UPSTREAM..$HEAD | head -n 1)"
-               else
-                       MERGES_OPTION="--no-merges --cherry-pick"
-               fi
-               SHORTHEAD=$(git rev-parse --short $HEAD)
-               SHORTONTO=$(git rev-parse --short $ONTO)
-               if test -z "$REBASE_ROOT"
-                       # this is now equivalent to ! -z "$UPSTREAM"
-               then
-                       SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
-                       REVISIONS=$UPSTREAM...$HEAD
-                       SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
-               else
-                       REVISIONS=$ONTO...$HEAD
-                       SHORTREVISIONS=$SHORTHEAD
-               fi
-               git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
-                       --abbrev=7 --reverse --left-right --topo-order \
-                       $REVISIONS | \
-                       sed -n "s/^>//p" |
-               while read -r shortsha1 rest
+ : > "$state_dir"/interactive || die "Could not mark as interactive"
+ write_basic_state
+ if test t = "$preserve_merges"
+ then
+       if test -z "$rebase_root"
+       then
+               mkdir "$REWRITTEN" &&
+               for c in $(git merge-base --all $orig_head $upstream)
                do
-                       if test t != "$PRESERVE_MERGES"
-                       then
-                               printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
-                       else
-                               sha1=$(git rev-parse $shortsha1)
-                               if test -z "$REBASE_ROOT"
-                               then
-                                       preserve=t
-                                       for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
-                                       do
-                                               if test -f "$REWRITTEN"/$p -a \( $p != $ONTO -o $sha1 = $first_after_upstream \)
-                                               then
-                                                       preserve=f
-                                               fi
-                                       done
-                               else
-                                       preserve=f
-                               fi
-                               if test f = "$preserve"
-                               then
-                                       touch "$REWRITTEN"/$sha1
-                                       printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
-                               fi
-                       fi
+                       echo $onto > "$REWRITTEN"/$c ||
+                               die "Could not init rewritten commits"
                done
-               # Watch for commits that been dropped by --cherry-pick
-               if test t = "$PRESERVE_MERGES"
+       else
+               mkdir "$REWRITTEN" &&
+               echo $onto > "$REWRITTEN"/root ||
+                       die "Could not init rewritten commits"
+       fi
+       # No cherry-pick because our first pass is to determine
+       # parents to rewrite and skipping dropped commits would
+       # prematurely end our probe
+       MERGES_OPTION=
+       first_after_upstream="$(git rev-list --reverse --first-parent $upstream..$orig_head | head -n 1)"
+ else
+       MERGES_OPTION="--no-merges --cherry-pick"
+ fi
+ SHORTHEAD=$(git rev-parse --short $orig_head)
+ SHORTONTO=$(git rev-parse --short $onto)
+ if test -z "$rebase_root"
+       # this is now equivalent to ! -z "$upstream"
+ then
+       SHORTUPSTREAM=$(git rev-parse --short $upstream)
+       REVISIONS=$upstream...$orig_head
+       SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
+ else
+       REVISIONS=$onto...$orig_head
+       SHORTREVISIONS=$SHORTHEAD
+ fi
+ git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
+       --abbrev=7 --reverse --left-right --topo-order \
+       $REVISIONS | \
+       sed -n "s/^>//p" |
+ while read -r shortsha1 rest
+ do
+       if test t != "$preserve_merges"
+       then
+               printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
+       else
+               sha1=$(git rev-parse $shortsha1)
+               if test -z "$rebase_root"
                then
-                       mkdir "$DROPPED"
-                       # Save all non-cherry-picked changes
-                       git rev-list $REVISIONS --left-right --cherry-pick | \
-                               sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks
-                       # Now all commits and note which ones are missing in
-                       # not-cherry-picks and hence being dropped
-                       git rev-list $REVISIONS |
-                       while read rev
+                       preserve=t
+                       for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
                        do
-                               if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
+                               if test -f "$REWRITTEN"/$p -a \( $p != $onto -o $sha1 = $first_after_upstream \)
                                then
-                                       # Use -f2 because if rev-list is telling us this commit is
-                                       # not worthwhile, we don't want to track its multiple heads,
-                                       # just the history of its first-parent for others that will
-                                       # be rebasing on top of it
-                                       git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
-                                       short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
-                                       sane_grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
-                                       rm "$REWRITTEN"/$rev
+                                       preserve=f
                                fi
                        done
+               else
+                       preserve=f
+               fi
+               if test f = "$preserve"
+               then
+                       touch "$REWRITTEN"/$sha1
+                       printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
                fi
+       fi
+ done
  
-               test -s "$TODO" || echo noop >> "$TODO"
-               test -n "$AUTOSQUASH" && rearrange_squash "$TODO"
-               cat >> "$TODO" << EOF
+ # Watch for commits that been dropped by --cherry-pick
+ if test t = "$preserve_merges"
+ then
+       mkdir "$DROPPED"
+       # Save all non-cherry-picked changes
+       git rev-list $REVISIONS --left-right --cherry-pick | \
+               sed -n "s/^>//p" > "$state_dir"/not-cherry-picks
+       # Now all commits and note which ones are missing in
+       # not-cherry-picks and hence being dropped
+       git rev-list $REVISIONS |
+       while read rev
+       do
+               if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$state_dir"/not-cherry-picks)" = ""
+               then
+                       # Use -f2 because if rev-list is telling us this commit is
+                       # not worthwhile, we don't want to track its multiple heads,
+                       # just the history of its first-parent for others that will
+                       # be rebasing on top of it
+                       git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
+                       short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
+                       sane_grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
+                       rm "$REWRITTEN"/$rev
+               fi
+       done
+ fi
+ test -s "$TODO" || echo noop >> "$TODO"
+ test -n "$autosquash" && rearrange_squash "$TODO"
+ cat >> "$TODO" << EOF
  
  # Rebase $SHORTREVISIONS onto $SHORTONTO
  #
  #  e, edit = use commit, but stop for amending
  #  s, squash = use commit, but meld into previous commit
  #  f, fixup = like "squash", but discard this commit's log message
 -#  x <cmd>, exec <cmd> = Run a shell command <cmd>, and stop if it fails
 +#  x, exec = run command (the rest of the line) using shell
  #
  # If you remove a line here THAT COMMIT WILL BE LOST.
  # However, if you remove everything, the rebase will be aborted.
  #
  EOF
  
              has_action "$TODO" ||
-                       die_abort "Nothing to do"
+ has_action "$TODO" ||
+       die_abort "Nothing to do"
  
              cp "$TODO" "$TODO".backup
              git_editor "$TODO" ||
-                       die_abort "Could not execute editor"
+ cp "$TODO" "$TODO".backup
+ git_editor "$TODO" ||
+       die_abort "Could not execute editor"
  
              has_action "$TODO" ||
-                       die_abort "Nothing to do"
+ has_action "$TODO" ||
+       die_abort "Nothing to do"
  
              test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks
test -d "$REWRITTEN" || test -n "$force_rebase" || skip_unnecessary_picks
  
-               output git checkout $ONTO || die_abort "could not detach HEAD"
-               git update-ref ORIG_HEAD $HEAD
-               do_rest
-               ;;
-       esac
-       shift
- done
+ output git checkout $onto || die_abort "could not detach HEAD"
+ git update-ref ORIG_HEAD $orig_head
+ do_rest
diff --combined git-rebase.sh
index cbb0ea90ed410d5af68ce814b7fd93a90829f3ee,05b4fe16f750e26dff69fc3ed91db4df8a27631e..5ea7419ab844c7b77ecb3750490c9c9667ddf10e
@@@ -42,12 -42,12 +42,12 @@@ When you have resolved this problem ru
  If you would prefer to skip this patch, instead run \"git rebase --skip\".
  To restore the original branch and stop rebasing run \"git rebase --abort\".
  "
- unset newbase
- strategy=recursive
+ unset onto
+ strategy=
  strategy_opts=
  do_merge=
dotest="$GIT_DIR"/rebase-merge
- prec=4
merge_dir="$GIT_DIR"/rebase-merge
+ apply_dir="$GIT_DIR"/rebase-apply
  verbose=
  diffstat=
  test "$(git config --bool rebase.stat)" = true && diffstat=t
@@@ -55,92 -55,69 +55,69 @@@ git_am_opt
  rebase_root=
  force_rebase=
  allow_rerere_autoupdate=
- continue_merge () {
-       test -n "$prev_head" || die "prev_head must be defined"
-       test -d "$dotest" || die "$dotest directory does not exist"
-       unmerged=$(git ls-files -u)
-       if test -n "$unmerged"
+ # Non-empty if a rebase was in progress when 'git rebase' was invoked
+ in_progress=
+ # One of {am, merge, interactive}
+ type=
+ # One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
+ state_dir=
+ # One of {'', continue, skip, abort}, as parsed from command line
+ action=
+ preserve_merges=
+ autosquash=
+ test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
+ read_basic_state () {
+       head_name=$(cat "$state_dir"/head-name) &&
+       onto=$(cat "$state_dir"/onto) &&
+       if test "$type" = interactive
        then
-               echo "You still have unmerged paths in your index"
-               echo "did you forget to use git add?"
-               die "$RESOLVEMSG"
-       fi
+               orig_head=$(cat "$state_dir"/head)
+       else
+               orig_head=$(cat "$state_dir"/orig-head)
+       fi &&
+       GIT_QUIET=$(cat "$state_dir"/quiet) &&
+       test -f "$state_dir"/verbose && verbose=t
+       test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
+       test -f "$state_dir"/strategy_opts &&
+               strategy_opts="$(cat "$state_dir"/strategy_opts)"
+       test -f "$state_dir"/allow_rerere_autoupdate &&
+               allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
+ }
  
-       cmt=`cat "$dotest/current"`
-       if ! git diff-index --quiet --ignore-submodules HEAD --
+ write_basic_state () {
+       echo "$head_name" > "$state_dir"/head-name &&
+       echo "$onto" > "$state_dir"/onto &&
+       if test "$type" = interactive
        then
-               if ! git commit --no-verify -C "$cmt"
-               then
-                       echo "Commit failed, please do not call \"git commit\""
-                       echo "directly, but instead do one of the following: "
-                       die "$RESOLVEMSG"
-               fi
-               if test -z "$GIT_QUIET"
-               then
-                       printf "Committed: %0${prec}d " $msgnum
-               fi
-               echo "$cmt $(git rev-parse HEAD^0)" >> "$dotest/rewritten"
+               echo "$orig_head" > "$state_dir"/head
        else
-               if test -z "$GIT_QUIET"
-               then
-                       printf "Already applied: %0${prec}d " $msgnum
-               fi
-       fi
-       test -z "$GIT_QUIET" &&
-       GIT_PAGER='' git log --format=%s -1 "$cmt"
-       prev_head=`git rev-parse HEAD^0`
-       # save the resulting commit so we can read-tree on it later
-       echo "$prev_head" > "$dotest/prev_head"
-       # onto the next patch:
-       msgnum=$(($msgnum + 1))
-       echo "$msgnum" >"$dotest/msgnum"
+               echo "$orig_head" > "$state_dir"/orig-head
+       fi &&
+       echo "$GIT_QUIET" > "$state_dir"/quiet &&
+       test t = "$verbose" && : > "$state_dir"/verbose
+       test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy
+       test -n "$strategy_opts" && echo "$strategy_opts" > \
+               "$state_dir"/strategy_opts
+       test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
+               "$state_dir"/allow_rerere_autoupdate
  }
  
- call_merge () {
-       cmt="$(cat "$dotest/cmt.$1")"
-       echo "$cmt" > "$dotest/current"
-       hd=$(git rev-parse --verify HEAD)
-       cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
-       msgnum=$(cat "$dotest/msgnum")
-       end=$(cat "$dotest/end")
-       eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
-       eval GITHEAD_$hd='$(cat "$dotest/onto_name")'
-       export GITHEAD_$cmt GITHEAD_$hd
-       if test -n "$GIT_QUIET"
-       then
-               GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
-       fi
-       eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"'
-       rv=$?
-       case "$rv" in
-       0)
-               unset GITHEAD_$cmt GITHEAD_$hd
-               return
-               ;;
-       1)
-               git rerere $allow_rerere_autoupdate
-               die "$RESOLVEMSG"
-               ;;
-       2)
-               echo "Strategy: $rv $strategy failed, try another" 1>&2
-               die "$RESOLVEMSG"
+ output () {
+       case "$verbose" in
+       '')
+               output=$("$@" 2>&1 )
+               status=$?
+               test $status != 0 && printf "%s\n" "$output"
+               return $status
                ;;
        *)
-               die "Unknown exit code ($rv) from command:" \
-                       "git-merge-$strategy $cmt^ -- HEAD $cmt"
+               "$@"
                ;;
        esac
  }
  
  move_to_original_branch () {
-       test -z "$head_name" &&
-               head_name="$(cat "$dotest"/head-name)" &&
-               onto="$(cat "$dotest"/onto)" &&
-               orig_head="$(cat "$dotest"/orig-head)"
        case "$head_name" in
        refs/*)
                message="rebase finished: $head_name onto $onto"
        esac
  }
  
- finish_rb_merge () {
-       move_to_original_branch
-       git notes copy --for-rewrite=rebase < "$dotest"/rewritten
-       if test -x "$GIT_DIR"/hooks/post-rewrite &&
-               test -s "$dotest"/rewritten; then
-               "$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten
-       fi
-       rm -r "$dotest"
-       say All done.
- }
- is_interactive () {
-       while test $# != 0
-       do
-               case "$1" in
-                       -i|--interactive)
-                               interactive_rebase=explicit
-                               break
-                       ;;
-                       -p|--preserve-merges)
-                               interactive_rebase=implied
-                       ;;
-               esac
-               shift
-       done
+ run_specific_rebase () {
        if [ "$interactive_rebase" = implied ]; then
                GIT_EDITOR=:
                export GIT_EDITOR
        fi
-       test -n "$interactive_rebase" || test -f "$dotest"/interactive
+       export onto autosquash strategy strategy_opts verbose rebase_root \
+       force_rebase action preserve_merges upstream switch_to head_name \
+       state_dir orig_head onto_name GIT_QUIET revisions RESOLVEMSG \
+       allow_rerere_autoupdate git_am_opt type
+       export -f move_to_original_branch output write_basic_state
+       exec git-rebase--$type
  }
  
  run_pre_rebase_hook () {
        fi
  }
  
- test -f "$GIT_DIR"/rebase-apply/applying &&
+ test -f "$apply_dir"/applying &&
        die 'It looks like git-am is in progress. Cannot rebase.'
  
- is_interactive "$@" && exec git-rebase--interactive "$@"
+ if test -d "$apply_dir"
+ then
+       type=am
+       state_dir="$apply_dir"
+ elif test -d "$merge_dir"
+ then
+       if test -f "$merge_dir"/interactive
+       then
+               type=interactive
+               interactive_rebase=explicit
+       else
+               type=merge
+       fi
+       state_dir="$merge_dir"
+ fi
+ test -n "$type" && in_progress=t
  
+ total_argc=$#
  while test $# != 0
  do
        case "$1" in
        --verify)
                OK_TO_SKIP_PRE_REBASE=
                ;;
-       --continue)
-               test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
-                       die "No rebase in progress?"
-               git update-index --ignore-submodules --refresh &&
-               git diff-files --quiet --ignore-submodules || {
-                       echo "You must edit all merge conflicts and then"
-                       echo "mark them as resolved using git add"
-                       exit 1
-               }
-               if test -d "$dotest"
-               then
-                       prev_head=$(cat "$dotest/prev_head")
-                       end=$(cat "$dotest/end")
-                       msgnum=$(cat "$dotest/msgnum")
-                       onto=$(cat "$dotest/onto")
-                       GIT_QUIET=$(cat "$dotest/quiet")
-                       continue_merge
-                       while test "$msgnum" -le "$end"
-                       do
-                               call_merge "$msgnum"
-                               continue_merge
-                       done
-                       finish_rb_merge
-                       exit
-               fi
-               head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
-               onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
-               orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
-               GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
-               git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
-               move_to_original_branch
-               exit
-               ;;
-       --skip)
-               test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
-                       die "No rebase in progress?"
-               git reset --hard HEAD || exit $?
-               if test -d "$dotest"
-               then
-                       git rerere clear
-                       prev_head=$(cat "$dotest/prev_head")
-                       end=$(cat "$dotest/end")
-                       msgnum=$(cat "$dotest/msgnum")
-                       msgnum=$(($msgnum + 1))
-                       onto=$(cat "$dotest/onto")
-                       GIT_QUIET=$(cat "$dotest/quiet")
-                       while test "$msgnum" -le "$end"
-                       do
-                               call_merge "$msgnum"
-                               continue_merge
-                       done
-                       finish_rb_merge
-                       exit
-               fi
-               head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
-               onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
-               orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
-               GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
-               git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
-               move_to_original_branch
-               exit
-               ;;
-       --abort)
-               test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
-                       die "No rebase in progress?"
-               git rerere clear
-               test -d "$dotest" || dotest="$GIT_DIR"/rebase-apply
-               head_name="$(cat "$dotest"/head-name)" &&
-               case "$head_name" in
-               refs/*)
-                       git symbolic-ref HEAD $head_name ||
-                       die "Could not move back to $head_name"
-                       ;;
-               esac
-               git reset --hard $(cat "$dotest/orig-head")
-               rm -r "$dotest"
-               exit
+       --continue|--skip|--abort)
+               test $total_argc -eq 1 || usage
+               action=${1##--}
                ;;
        --onto)
                test 2 -le "$#" || usage
-               newbase="$2"
+               onto="$2"
                shift
                ;;
+       -i|--interactive)
+               interactive_rebase=explicit
+               ;;
+       -p|--preserve-merges)
+               preserve_merges=t
+               test -z "$interactive_rebase" && interactive_rebase=implied
+               ;;
+       --autosquash)
+               autosquash=t
+               ;;
+       --no-autosquash)
+               autosquash=
+               ;;
        -M|-m|--m|--me|--mer|--merg|--merge)
                do_merge=t
                ;;
                esac
                strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")"
                do_merge=t
+               test -z "$strategy" && strategy=recursive
                ;;
        -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
                --strateg=*|--strategy=*|\
  done
  test $# -gt 2 && usage
  
- if test $# -eq 0 && test -z "$rebase_root"
+ if test -n "$action"
  then
-       test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || usage
-       test -d "$dotest" -o -f "$GIT_DIR"/rebase-apply/rebasing &&
-               die 'A rebase is in progress, try --continue, --skip or --abort.'
+       test -z "$in_progress" && die "No rebase in progress?"
+       # Only interactive rebase uses detailed reflog messages
+       if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase
+       then
+               GIT_REFLOG_ACTION="rebase -i ($action)"
+               export GIT_REFLOG_ACTION
+       fi
  fi
  
- # Make sure we do not have $GIT_DIR/rebase-apply
- if test -z "$do_merge"
+ case "$action" in
+ continue)
+       # Sanity check
+       git rev-parse --verify HEAD >/dev/null ||
+               die "Cannot read HEAD"
+       git update-index --ignore-submodules --refresh &&
+       git diff-files --quiet --ignore-submodules || {
+               echo "You must edit all merge conflicts and then"
+               echo "mark them as resolved using git add"
+               exit 1
+       }
+       read_basic_state
+       run_specific_rebase
+       ;;
+ skip)
+       output git reset --hard HEAD || exit $?
+       read_basic_state
+       run_specific_rebase
+       ;;
+ abort)
+       git rerere clear
+       read_basic_state
+       case "$head_name" in
+       refs/*)
+               git symbolic-ref HEAD $head_name ||
+               die "Could not move back to $head_name"
+               ;;
+       esac
+       output git reset --hard $orig_head
+       rm -r "$state_dir"
+       exit
+       ;;
+ esac
+ # Make sure no rebase is in progress
+ if test -n "$in_progress"
  then
-       if mkdir "$GIT_DIR"/rebase-apply 2>/dev/null
-       then
-               rmdir "$GIT_DIR"/rebase-apply
-       else
-               echo >&2 '
- It seems that I cannot create a rebase-apply directory, and
- I wonder if you are in the middle of patch application or another
- rebase.  If that is not the case, please
-       rm -fr '"$GIT_DIR"'/rebase-apply
+       die '
+ It seems that there is already a '"${state_dir##*/}"' directory, and
+ I wonder if you are in the middle of another rebase.  If that is the
+ case, please try
+       git rebase (--continue | --abort | --skip)
+ If that is not the case, please
+       rm -fr '"$state_dir"'
  and run me again.  I am stopping in case you still have something
  valuable there.'
-               exit 1
-       fi
- else
-       if test -d "$dotest"
-       then
-               die "previous rebase directory $dotest still exists." \
-                       'Try git rebase (--continue | --abort | --skip)'
-       fi
  fi
  
- require_clean_work_tree "rebase" "Please commit or stash them."
+ test $# -eq 0 && test -z "$rebase_root" && usage
+ if test -n "$interactive_rebase"
+ then
+       type=interactive
+       state_dir="$merge_dir"
+ elif test -n "$do_merge"
+ then
+       type=merge
+       state_dir="$merge_dir"
+ else
+       type=am
+       state_dir="$apply_dir"
+ fi
  
  if test -z "$rebase_root"
  then
        shift
        upstream=`git rev-parse --verify "${upstream_name}^0"` ||
        die "invalid upstream $upstream_name"
-       unset root_flag
        upstream_arg="$upstream_name"
  else
-       test -z "$newbase" && die "--root must be used with --onto"
+       test -z "$onto" && die "You must specify --onto when using --root"
        unset upstream_name
        unset upstream
-       root_flag="--root"
-       upstream_arg="$root_flag"
+       upstream_arg=--root
  fi
  
  # Make sure the branch to rebase onto is valid.
- onto_name=${newbase-"$upstream_name"}
+ onto_name=${onto-"$upstream_name"}
  case "$onto_name" in
  *...*)
        if      left=${onto_name%...*} right=${onto_name#*...} &&
        fi
        ;;
  *)
-       onto=$(git rev-parse --verify "${onto_name}^0") || exit
+       onto=$(git rev-parse --verify "${onto_name}^0") ||
+       die "Does not point to a valid commit: $1"
        ;;
  esac
  
- # If a hook exists, give it a chance to interrupt
- run_pre_rebase_hook "$upstream_arg" "$@"
  # If the branch to rebase is given, that is the branch we will rebase
  # $branch_name -- branch being rebased, or HEAD (already detached)
  # $orig_head -- commit object name of tip of the branch before rebasing
@@@ -475,14 -419,13 +419,14 @@@ case "$#" i
        switch_to="$1"
  
        if git show-ref --verify --quiet -- "refs/heads/$1" &&
-          branch=$(git rev-parse -q --verify "refs/heads/$1")
+          orig_head=$(git rev-parse -q --verify "refs/heads/$1")
        then
                head_name="refs/heads/$1"
-       elif branch=$(git rev-parse -q --verify "$1")
+       elif orig_head=$(git rev-parse -q --verify "$1")
        then
                head_name="detached HEAD"
        else
 +              echo >&2 "fatal: no such branch: $1"
                usage
        fi
        ;;
                head_name="detached HEAD"
                branch_name=HEAD ;# detached
        fi
-       branch=$(git rev-parse --verify "${branch_name}^0") || exit
+       orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
        ;;
  esac
- orig_head=$branch
  
- # Now we are rebasing commits $upstream..$branch (or with --root,
- # everything leading up to $branch) on top of $onto
+ require_clean_work_tree "rebase" "Please commit or stash them."
+ # Now we are rebasing commits $upstream..$orig_head (or with --root,
+ # everything leading up to $orig_head) on top of $onto
  
  # Check if we are already based on $onto with linear history,
- # but this should be done only when upstream and onto are the same.
- mb=$(git merge-base "$onto" "$branch")
- if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
+ # but this should be done only when upstream and onto are the same
+ # and if this is not an interactive rebase.
+ mb=$(git merge-base "$onto" "$orig_head")
+ if test "$type" != interactive && test "$upstream" = "$onto" &&
+       test "$mb" = "$onto" &&
        # linear history?
-       ! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null
+       ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
  then
        if test -z "$force_rebase"
        then
                # Lazily switch to the target branch if needed...
 -              test -z "$switch_to" || git checkout "$switch_to"
 +              test -z "$switch_to" || git checkout "$switch_to" --
                say "Current branch $branch_name is up to date."
                exit 0
        else
        fi
  fi
  
- # Detach HEAD and reset the tree
- say "First, rewinding head to replay your work on top of it..."
- git checkout -q "$onto^0" || die "could not detach HEAD"
- git update-ref ORIG_HEAD $branch
+ # If a hook exists, give it a chance to interrupt
+ run_pre_rebase_hook "$upstream_arg" "$@"
  
  if test -n "$diffstat"
  then
        GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
  fi
  
+ test "$type" = interactive && run_specific_rebase
+ # Detach HEAD and reset the tree
+ say "First, rewinding head to replay your work on top of it..."
+ git checkout -q "$onto^0" || die "could not detach HEAD"
+ git update-ref ORIG_HEAD $orig_head
  # If the $onto is a proper descendant of the tip of the branch, then
  # we just fast-forwarded.
- if test "$mb" = "$branch"
+ if test "$mb" = "$orig_head"
  then
        say "Fast-forwarded $branch_name to $onto_name."
        move_to_original_branch
@@@ -553,51 -504,4 +505,4 @@@ els
        revisions="$upstream..$orig_head"
  fi
  
- if test -z "$do_merge"
- then
-       git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-               --src-prefix=a/ --dst-prefix=b/ \
-               --no-renames $root_flag "$revisions" |
-       git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
-       move_to_original_branch
-       ret=$?
-       test 0 != $ret -a -d "$GIT_DIR"/rebase-apply &&
-               echo $head_name > "$GIT_DIR"/rebase-apply/head-name &&
-               echo $onto > "$GIT_DIR"/rebase-apply/onto &&
-               echo $orig_head > "$GIT_DIR"/rebase-apply/orig-head &&
-               echo "$GIT_QUIET" > "$GIT_DIR"/rebase-apply/quiet
-       exit $ret
- fi
- # start doing a rebase with git-merge
- # this is rename-aware if the recursive (default) strategy is used
- mkdir -p "$dotest"
- echo "$onto" > "$dotest/onto"
- echo "$onto_name" > "$dotest/onto_name"
- prev_head=$orig_head
- echo "$prev_head" > "$dotest/prev_head"
- echo "$orig_head" > "$dotest/orig-head"
- echo "$head_name" > "$dotest/head-name"
- echo "$GIT_QUIET" > "$dotest/quiet"
- msgnum=0
- for cmt in `git rev-list --reverse --no-merges "$revisions"`
- do
-       msgnum=$(($msgnum + 1))
-       echo "$cmt" > "$dotest/cmt.$msgnum"
- done
- echo 1 >"$dotest/msgnum"
- echo $msgnum >"$dotest/end"
- end=$msgnum
- msgnum=1
- while test "$msgnum" -le "$end"
- do
-       call_merge "$msgnum"
-       continue_merge
- done
- finish_rb_merge
+ run_specific_rebase