author | Junio C Hamano <gitster@pobox.com> | |
Mon, 31 Jan 2011 03:03:21 +0000 (19:03 -0800) | ||
committer | Junio 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
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 | patch | | diff1 | | diff2 | | blob | history |
Makefile | patch | | diff1 | | diff2 | | blob | history |
git-rebase--interactive.sh | patch | | diff1 | | diff2 | | blob | history |
git-rebase.sh | patch | | diff1 | | diff2 | | blob | history |
diff --combined .gitignore
index faad9d02b624f9a86603629c2123c7ba82edd26c,ef040585e75ec19c4f0c77f6e34d4ba0e7d2b7cb..9ee7b5a6b4efbd1e0548ad20568f4213194a06a8
--- 1/.gitignore
--- 2/.gitignore
+++ b/.gitignore
/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
# 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.
#
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)
# DESTDIR=
pathsep = :
-export prefix bindir sharedir sysconfdir gitwebdir
+export prefix bindir sharedir sysconfdir gitwebdir localedir
CC = gcc
AR = ar
PTHREAD_LIBS = -lpthread
PTHREAD_CFLAGS =
GCOV = gcov
+XGETTEXT = xgettext
+MSGFMT = msgfmt
export TCL_PATH TCLTK_PATH
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
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
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))
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
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
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
# 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...
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
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
NO_STRLCPY=YesPlease
NO_MKSTEMPS = YesPlease
HAVE_PATHS_H = YesPlease
+ NEEDS_LIBINTL =
endif
ifeq ($(uname_S),IRIX)
NO_SETENV = YesPlease
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
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
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
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))
$(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
-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 >$@+
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
$(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)
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
$(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
$(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
diff --combined git-rebase--interactive.sh
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 () {
then
last_count=$count
printf "Rebasing (%d/%d)\r" $count $total
- test -z "$VERBOSE" || echo
+ test -z "$verbose" || echo
fi
}
*)
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"
}
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 "$@"
}
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"
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
}
# 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
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
--- 1/git-rebase.sh
--- 2/git-rebase.sh
+++ b/git-rebase.sh
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
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
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
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