Merge branch 'mz/rebase'
* mz/rebase: (34 commits)
  rebase: define options in OPTIONS_SPEC
  Makefile: do not install sourced rebase scripts
  rebase: use @{upstream} if no upstream specified
  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
  ...
			
			
				maint
			
			
		
						commit
						78c6e0f3fa
					
				|  | @ -101,7 +101,9 @@ | |||
| /git-quiltimport | ||||
| /git-read-tree | ||||
| /git-rebase | ||||
| /git-rebase--am | ||||
| /git-rebase--interactive | ||||
| /git-rebase--merge | ||||
| /git-receive-pack | ||||
| /git-reflog | ||||
| /git-relink | ||||
|  |  | |||
|  | @ -641,7 +641,7 @@ branch.<name>.remote:: | |||
|  | ||||
| branch.<name>.merge:: | ||||
| 	Defines, together with branch.<name>.remote, the upstream branch | ||||
| 	for the given branch. It tells 'git fetch'/'git pull' which | ||||
| 	for the given branch. It tells 'git fetch'/'git pull'/'git rebase' which | ||||
| 	branch to merge and can also affect 'git push' (see push.default). | ||||
| 	When in branch <name>, it tells 'git fetch' the default | ||||
| 	refspec to be marked for merging in FETCH_HEAD. The value is | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ SYNOPSIS | |||
| -------- | ||||
| [verse] | ||||
| 'git rebase' [-i | --interactive] [options] [--onto <newbase>] | ||||
| 	<upstream> [<branch>] | ||||
| 	[<upstream>] [<branch>] | ||||
| 'git rebase' [-i | --interactive] [options] --onto <newbase> | ||||
| 	--root [<branch>] | ||||
|  | ||||
|  | @ -21,6 +21,12 @@ If <branch> is specified, 'git rebase' will perform an automatic | |||
| `git checkout <branch>` before doing anything else.  Otherwise | ||||
| it remains on the current branch. | ||||
|  | ||||
| If <upstream> is not specified, the upstream configured in | ||||
| branch.<name>.remote and branch.<name>.merge options will be used; see | ||||
| linkgit:git-config[1] for details.  If you are currently not on any | ||||
| branch or if the current branch does not have a configured upstream, | ||||
| the rebase will abort. | ||||
|  | ||||
| All changes made by commits in the current branch but that are not | ||||
| in <upstream> are saved to a temporary area.  This is the same set | ||||
| of commits that would be shown by `git log <upstream>..HEAD` (or | ||||
|  | @ -217,7 +223,8 @@ leave out at most one of A and B, in which case it defaults to HEAD. | |||
|  | ||||
| <upstream>:: | ||||
| 	Upstream branch to compare against.  May be any valid commit, | ||||
| 	not just an existing branch name. | ||||
| 	not just an existing branch name. Defaults to the configured | ||||
| 	upstream for the current branch. | ||||
|  | ||||
| <branch>:: | ||||
| 	Working branch; defaults to HEAD. | ||||
|  |  | |||
							
								
								
									
										4
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										4
									
								
								Makefile
								
								
								
								
							|  | @ -368,7 +368,6 @@ SCRIPT_SH += git-merge-resolve.sh | |||
| SCRIPT_SH += git-mergetool.sh | ||||
| SCRIPT_SH += git-pull.sh | ||||
| SCRIPT_SH += git-quiltimport.sh | ||||
| SCRIPT_SH += git-rebase--interactive.sh | ||||
| SCRIPT_SH += git-rebase.sh | ||||
| SCRIPT_SH += git-repack.sh | ||||
| SCRIPT_SH += git-request-pull.sh | ||||
|  | @ -378,6 +377,9 @@ SCRIPT_SH += git-web--browse.sh | |||
|  | ||||
| SCRIPT_LIB += git-mergetool--lib | ||||
| SCRIPT_LIB += git-parse-remote | ||||
| SCRIPT_LIB += git-rebase--am | ||||
| SCRIPT_LIB += git-rebase--interactive | ||||
| SCRIPT_LIB += git-rebase--merge | ||||
| SCRIPT_LIB += git-sh-setup | ||||
|  | ||||
| SCRIPT_PERL += git-add--interactive.perl | ||||
|  |  | |||
|  | @ -50,3 +50,41 @@ get_remote_merge_branch () { | |||
| 	    esac | ||||
| 	esac | ||||
| } | ||||
|  | ||||
| error_on_missing_default_upstream () { | ||||
| 	cmd="$1" | ||||
| 	op_type="$2" | ||||
| 	op_prep="$3" | ||||
| 	example="$4" | ||||
| 	branch_name=$(git symbolic-ref -q HEAD) | ||||
| 	if test -z "$branch_name" | ||||
| 	then | ||||
| 		echo "You are not currently on a branch, so I cannot use any | ||||
| 'branch.<branchname>.merge' in your configuration file. | ||||
| Please specify which branch you want to $op_type $op_prep on the command | ||||
| line and try again (e.g. '$example'). | ||||
| See git-${cmd}(1) for details." | ||||
| 	else | ||||
| 		echo "You asked me to $cmd without telling me which branch you | ||||
| want to $op_type $op_prep, and 'branch.${branch_name#refs/heads/}.merge' in | ||||
| your configuration file does not tell me, either. Please | ||||
| specify which branch you want to use on the command line and | ||||
| try again (e.g. '$example'). | ||||
| See git-${cmd}(1) for details. | ||||
|  | ||||
| If you often $op_type $op_prep the same branch, you may want to | ||||
| use something like the following in your configuration file: | ||||
|     [branch \"${branch_name#refs/heads/}\"] | ||||
|     remote = <nickname> | ||||
|     merge = <remote-ref>" | ||||
| 		test rebase = "$op_type" && | ||||
| 		echo "    rebase = true" | ||||
| 		echo " | ||||
|     [remote \"<nickname>\"] | ||||
|     url = <url> | ||||
|     fetch = <refspec> | ||||
|  | ||||
| See git-config(1) for details." | ||||
| 	fi | ||||
| 	exit 1 | ||||
| } | ||||
|  |  | |||
							
								
								
									
										32
									
								
								git-pull.sh
								
								
								
								
							
							
						
						
									
										32
									
								
								git-pull.sh
								
								
								
								
							|  | @ -168,34 +168,10 @@ error_on_no_merge_candidates () { | |||
| 		echo "You asked to pull from the remote '$1', but did not specify" | ||||
| 		echo "a branch. Because this is not the default configured remote" | ||||
| 		echo "for your current branch, you must specify a branch on the command line." | ||||
| 	elif [ -z "$curr_branch" ]; then | ||||
| 		echo "You are not currently on a branch, so I cannot use any" | ||||
| 		echo "'branch.<branchname>.merge' in your configuration file." | ||||
| 		echo "Please specify which remote branch you want to use on the command" | ||||
| 		echo "line and try again (e.g. 'git pull <repository> <refspec>')." | ||||
| 		echo "See git-pull(1) for details." | ||||
| 	elif [ -z "$upstream" ]; then | ||||
| 		echo "You asked me to pull without telling me which branch you" | ||||
| 		echo "want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in" | ||||
| 		echo "your configuration file does not tell me, either. Please" | ||||
| 		echo "specify which branch you want to use on the command line and" | ||||
| 		echo "try again (e.g. 'git pull <repository> <refspec>')." | ||||
| 		echo "See git-pull(1) for details." | ||||
| 		echo | ||||
| 		echo "If you often $op_type $op_prep the same branch, you may want to" | ||||
| 		echo "use something like the following in your configuration file:" | ||||
| 		echo | ||||
| 		echo "    [branch \"${curr_branch}\"]" | ||||
| 		echo "    remote = <nickname>" | ||||
| 		echo "    merge = <remote-ref>" | ||||
| 		test rebase = "$op_type" && | ||||
| 			echo "    rebase = true" | ||||
| 		echo | ||||
| 		echo "    [remote \"<nickname>\"]" | ||||
| 		echo "    url = <url>" | ||||
| 		echo "    fetch = <refspec>" | ||||
| 		echo | ||||
| 		echo "See git-config(1) for details." | ||||
| 	elif [ -z "$curr_branch" -o -z "$upstream" ]; then | ||||
| 		. git-parse-remote | ||||
| 		error_on_missing_default_upstream "pull" $op_type $op_prep \ | ||||
| 			"git pull <repository> <refspec>" | ||||
| 	else | ||||
| 		echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'" | ||||
| 		echo "from the remote, but no such ref was fetched." | ||||
|  |  | |||
|  | @ -0,0 +1,30 @@ | |||
| #!/bin/sh | ||||
| # | ||||
| # Copyright (c) 2010 Junio C Hamano. | ||||
| # | ||||
|  | ||||
| . git-sh-setup | ||||
|  | ||||
| case "$action" in | ||||
| continue) | ||||
| 	git am --resolved --resolvemsg="$resolvemsg" && | ||||
| 	move_to_original_branch | ||||
| 	exit | ||||
| 	;; | ||||
| skip) | ||||
| 	git am --skip --resolvemsg="$resolvemsg" && | ||||
| 	move_to_original_branch | ||||
| 	exit | ||||
| 	;; | ||||
| esac | ||||
|  | ||||
| test -n "$rebase_root" && root_flag=--root | ||||
|  | ||||
| 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 "$state_dir" && write_basic_state | ||||
| exit $ret | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,151 @@ | |||
| #!/bin/sh | ||||
| # | ||||
| # Copyright (c) 2010 Junio C Hamano. | ||||
| # | ||||
|  | ||||
| . git-sh-setup | ||||
|  | ||||
| prec=4 | ||||
|  | ||||
| read_state () { | ||||
| 	onto_name=$(cat "$state_dir"/onto_name) && | ||||
| 	end=$(cat "$state_dir"/end) && | ||||
| 	msgnum=$(cat "$state_dir"/msgnum) | ||||
| } | ||||
|  | ||||
| continue_merge () { | ||||
| 	test -d "$state_dir" || die "$state_dir directory does not exist" | ||||
|  | ||||
| 	unmerged=$(git ls-files -u) | ||||
| 	if test -n "$unmerged" | ||||
| 	then | ||||
| 		echo "You still have unmerged paths in your index" | ||||
| 		echo "did you forget to use git add?" | ||||
| 		die "$resolvemsg" | ||||
| 	fi | ||||
|  | ||||
| 	cmt=`cat "$state_dir/current"` | ||||
| 	if ! git diff-index --quiet --ignore-submodules HEAD -- | ||||
| 	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)" >> "$state_dir/rewritten" | ||||
| 	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" | ||||
|  | ||||
| 	# onto the next patch: | ||||
| 	msgnum=$(($msgnum + 1)) | ||||
| 	echo "$msgnum" >"$state_dir/msgnum" | ||||
| } | ||||
|  | ||||
| call_merge () { | ||||
| 	cmt="$(cat "$state_dir/cmt.$1")" | ||||
| 	echo "$cmt" > "$state_dir/current" | ||||
| 	hd=$(git rev-parse --verify HEAD) | ||||
| 	cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) | ||||
| 	msgnum=$(cat "$state_dir/msgnum") | ||||
| 	eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' | ||||
| 	eval GITHEAD_$hd='$onto_name' | ||||
| 	export GITHEAD_$cmt GITHEAD_$hd | ||||
| 	if test -n "$GIT_QUIET" | ||||
| 	then | ||||
| 		GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY | ||||
| 	fi | ||||
| 	test -z "$strategy" && strategy=recursive | ||||
| 	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: $strategy failed, try another" 1>&2 | ||||
| 		die "$resolvemsg" | ||||
| 		;; | ||||
| 	*) | ||||
| 		die "Unknown exit code ($rv) from command:" \ | ||||
| 			"git-merge-$strategy $cmt^ -- HEAD $cmt" | ||||
| 		;; | ||||
| 	esac | ||||
| } | ||||
|  | ||||
| finish_rb_merge () { | ||||
| 	move_to_original_branch | ||||
| 	git notes copy --for-rewrite=rebase < "$state_dir"/rewritten | ||||
| 	if test -x "$GIT_DIR"/hooks/post-rewrite && | ||||
| 		test -s "$state_dir"/rewritten; then | ||||
| 		"$GIT_DIR"/hooks/post-rewrite rebase < "$state_dir"/rewritten | ||||
| 	fi | ||||
| 	rm -r "$state_dir" | ||||
| 	say All done. | ||||
| } | ||||
|  | ||||
| case "$action" in | ||||
| continue) | ||||
| 	read_state | ||||
| 	continue_merge | ||||
| 	while test "$msgnum" -le "$end" | ||||
| 	do | ||||
| 		call_merge "$msgnum" | ||||
| 		continue_merge | ||||
| 	done | ||||
| 	finish_rb_merge | ||||
| 	exit | ||||
| 	;; | ||||
| skip) | ||||
| 	read_state | ||||
| 	git rerere clear | ||||
| 	msgnum=$(($msgnum + 1)) | ||||
| 	while test "$msgnum" -le "$end" | ||||
| 	do | ||||
| 		call_merge "$msgnum" | ||||
| 		continue_merge | ||||
| 	done | ||||
| 	finish_rb_merge | ||||
| 	exit | ||||
| 	;; | ||||
| esac | ||||
|  | ||||
| mkdir -p "$state_dir" | ||||
| echo "$onto_name" > "$state_dir/onto_name" | ||||
| write_basic_state | ||||
|  | ||||
| msgnum=0 | ||||
| for cmt in `git rev-list --reverse --no-merges "$revisions"` | ||||
| do | ||||
| 	msgnum=$(($msgnum + 1)) | ||||
| 	echo "$cmt" > "$state_dir/cmt.$msgnum" | ||||
| done | ||||
|  | ||||
| echo 1 >"$state_dir/msgnum" | ||||
| echo $msgnum >"$state_dir/end" | ||||
|  | ||||
| end=$msgnum | ||||
| msgnum=1 | ||||
|  | ||||
| while test "$msgnum" -le "$end" | ||||
| do | ||||
| 	call_merge "$msgnum" | ||||
| 	continue_merge | ||||
| done | ||||
|  | ||||
| finish_rb_merge | ||||
							
								
								
									
										596
									
								
								git-rebase.sh
								
								
								
								
							
							
						
						
									
										596
									
								
								git-rebase.sh
								
								
								
								
							|  | @ -3,7 +3,7 @@ | |||
| # Copyright (c) 2005 Junio C Hamano. | ||||
| # | ||||
|  | ||||
| USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] (<upstream>|--root) [<branch>] [--quiet | -q]' | ||||
| USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]' | ||||
| LONG_USAGE='git-rebase replaces <branch> with a new branch of the | ||||
| same name.  When the --onto option is provided the new branch starts | ||||
| out with a HEAD equal to <newbase>, otherwise it is equal to <upstream> | ||||
|  | @ -28,7 +28,39 @@ Example:       git-rebase master~1 topic | |||
| ' | ||||
|  | ||||
| SUBDIRECTORY_OK=Yes | ||||
| OPTIONS_SPEC= | ||||
| OPTIONS_KEEPDASHDASH= | ||||
| OPTIONS_SPEC="\ | ||||
| git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>] | ||||
| git rebase [-i] [options] --onto <newbase> --root [<branch>] | ||||
| git-rebase [-i] --continue | --abort | --skip | ||||
| -- | ||||
|  Available options are | ||||
| v,verbose!         display a diffstat of what changed upstream | ||||
| q,quiet!           be quiet. implies --no-stat | ||||
| 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!           use merging strategies to rebase | ||||
| i,interactive!     let the user edit the list of commits to rebase | ||||
| f,force-rebase!    force rebase even if branch is up to date | ||||
| X,strategy-option=! pass the argument through to the merge strategy | ||||
| stat!              display a diffstat of what changed upstream | ||||
| n,no-stat!         do not show diffstat of what changed upstream | ||||
| verify             allow pre-rebase hook to run | ||||
| rerere-autoupdate  allow rerere to update index with resolved conflicts | ||||
| root!              rebase all reachable commits up to the root(s) | ||||
| autosquash         move commits that begin with squash!/fixup! under -i | ||||
| committer-date-is-author-date! passed to 'git am' | ||||
| ignore-date!       passed to 'git am' | ||||
| whitespace=!       passed to 'git apply' | ||||
| ignore-whitespace! passed to 'git apply' | ||||
| C=!                passed to 'git apply' | ||||
|  Actions: | ||||
| continue!          continue rebasing process | ||||
| abort!             abort rebasing process and restore original branch | ||||
| skip!              skip current patch and continue rebasing process | ||||
| " | ||||
| . git-sh-setup | ||||
| set_reflog_action rebase | ||||
| require_work_tree | ||||
|  | @ -36,18 +68,18 @@ cd_to_toplevel | |||
|  | ||||
| LF=' | ||||
| ' | ||||
| OK_TO_SKIP_PRE_REBASE= | ||||
| RESOLVEMSG=" | ||||
| ok_to_skip_pre_rebase= | ||||
| resolvemsg=" | ||||
| When you have resolved this problem run \"git rebase --continue\". | ||||
| 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 +87,67 @@ git_am_opt= | |||
| rebase_root= | ||||
| force_rebase= | ||||
| allow_rerere_autoupdate= | ||||
| # 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 | ||||
|  | ||||
| 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" | ||||
| read_basic_state () { | ||||
| 	head_name=$(cat "$state_dir"/head-name) && | ||||
| 	onto=$(cat "$state_dir"/onto) && | ||||
| 	# We always write to orig-head, but interactive rebase used to write to | ||||
| 	# head. Fall back to reading from head to cover for the case that the | ||||
| 	# user upgraded git with an ongoing interactive rebase. | ||||
| 	if test -f "$state_dir"/orig-head | ||||
| 	then | ||||
| 		echo "You still have unmerged paths in your index" | ||||
| 		echo "did you forget to use git add?" | ||||
| 		die "$RESOLVEMSG" | ||||
| 	fi | ||||
|  | ||||
| 	cmt=`cat "$dotest/current"` | ||||
| 	if ! git diff-index --quiet --ignore-submodules HEAD -- | ||||
| 	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" | ||||
| 		orig_head=$(cat "$state_dir"/orig-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" | ||||
| 		orig_head=$(cat "$state_dir"/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)" | ||||
| } | ||||
|  | ||||
| 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" | ||||
| write_basic_state () { | ||||
| 	echo "$head_name" > "$state_dir"/head-name && | ||||
| 	echo "$onto" > "$state_dir"/onto && | ||||
| 	echo "$orig_head" > "$state_dir"/orig-head && | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| 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" | ||||
|  | @ -152,42 +159,16 @@ move_to_original_branch () { | |||
| 	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 | ||||
| 	. git-rebase--$type | ||||
| } | ||||
|  | ||||
| run_pre_rebase_hook () { | ||||
| 	if test -z "$OK_TO_SKIP_PRE_REBASE" && | ||||
| 	if test -z "$ok_to_skip_pre_rebase" && | ||||
| 	   test -x "$GIT_DIR/hooks/pre-rebase" | ||||
| 	then | ||||
| 		"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || | ||||
|  | @ -195,163 +176,94 @@ 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 | ||||
| 	--no-verify) | ||||
| 		OK_TO_SKIP_PRE_REBASE=yes | ||||
| 		ok_to_skip_pre_rebase=yes | ||||
| 		;; | ||||
| 	--verify) | ||||
| 		OK_TO_SKIP_PRE_REBASE= | ||||
| 		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 2 || usage | ||||
| 		action=${1##--} | ||||
| 		;; | ||||
| 	--onto) | ||||
| 		test 2 -le "$#" || usage | ||||
| 		newbase="$2" | ||||
| 		onto="$2" | ||||
| 		shift | ||||
| 		;; | ||||
| 	-M|-m|--m|--me|--mer|--merg|--merge) | ||||
| 	-i) | ||||
| 		interactive_rebase=explicit | ||||
| 		;; | ||||
| 	-p) | ||||
| 		preserve_merges=t | ||||
| 		test -z "$interactive_rebase" && interactive_rebase=implied | ||||
| 		;; | ||||
| 	--autosquash) | ||||
| 		autosquash=t | ||||
| 		;; | ||||
| 	--no-autosquash) | ||||
| 		autosquash= | ||||
| 		;; | ||||
| 	-M|-m) | ||||
| 		do_merge=t | ||||
| 		;; | ||||
| 	-X*|--strategy-option*) | ||||
| 		case "$#,$1" in | ||||
| 		1,-X|1,--strategy-option) | ||||
| 			usage ;; | ||||
| 		*,-X|*,--strategy-option) | ||||
| 			newopt="$2" | ||||
| 			shift ;; | ||||
| 		*,--strategy-option=*) | ||||
| 			newopt="$(expr " $1" : ' --strategy-option=\(.*\)')" ;; | ||||
| 		*,-X*) | ||||
| 			newopt="$(expr " $1" : ' -X\(.*\)')" ;; | ||||
| 		1,*) | ||||
| 			usage ;; | ||||
| 		esac | ||||
| 		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")" | ||||
| 	-X) | ||||
| 		shift | ||||
| 		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$1")" | ||||
| 		do_merge=t | ||||
| 		test -z "$strategy" && strategy=recursive | ||||
| 		;; | ||||
| 	-s) | ||||
| 		shift | ||||
| 		strategy="$1" | ||||
| 		do_merge=t | ||||
| 		;; | ||||
| 	-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ | ||||
| 		--strateg=*|--strategy=*|\ | ||||
| 	-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy) | ||||
| 		case "$#,$1" in | ||||
| 		*,*=*) | ||||
| 			strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;; | ||||
| 		1,*) | ||||
| 			usage ;; | ||||
| 		*) | ||||
| 			strategy="$2" | ||||
| 			shift ;; | ||||
| 		esac | ||||
| 		do_merge=t | ||||
| 		;; | ||||
| 	-n|--no-stat) | ||||
| 	-n) | ||||
| 		diffstat= | ||||
| 		;; | ||||
| 	--stat) | ||||
| 		diffstat=t | ||||
| 		;; | ||||
| 	-v|--verbose) | ||||
| 	-v) | ||||
| 		verbose=t | ||||
| 		diffstat=t | ||||
| 		GIT_QUIET= | ||||
| 		;; | ||||
| 	-q|--quiet) | ||||
| 	-q) | ||||
| 		GIT_QUIET=t | ||||
| 		git_am_opt="$git_am_opt -q" | ||||
| 		verbose= | ||||
| 		diffstat= | ||||
| 		;; | ||||
| 	--whitespace=*) | ||||
| 		git_am_opt="$git_am_opt $1" | ||||
| 	--whitespace) | ||||
| 		shift | ||||
| 		git_am_opt="$git_am_opt --whitespace=$1" | ||||
| 		case "$1" in | ||||
| 		--whitespace=fix|--whitespace=strip) | ||||
| 		fix|strip) | ||||
| 			force_rebase=t | ||||
| 			;; | ||||
| 		esac | ||||
|  | @ -363,22 +275,21 @@ do | |||
| 		git_am_opt="$git_am_opt $1" | ||||
| 		force_rebase=t | ||||
| 		;; | ||||
| 	-C*) | ||||
| 		git_am_opt="$git_am_opt $1" | ||||
| 	-C) | ||||
| 		shift | ||||
| 		git_am_opt="$git_am_opt -C$1" | ||||
| 		;; | ||||
| 	--root) | ||||
| 		rebase_root=t | ||||
| 		;; | ||||
| 	-f|--f|--fo|--for|--forc|--force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase|--no-ff) | ||||
| 	-f|--no-ff) | ||||
| 		force_rebase=t | ||||
| 		;; | ||||
| 	--rerere-autoupdate|--no-rerere-autoupdate) | ||||
| 		allow_rerere_autoupdate="$1" | ||||
| 		;; | ||||
| 	-*) | ||||
| 		usage | ||||
| 		;; | ||||
| 	*) | ||||
| 	--) | ||||
| 		shift | ||||
| 		break | ||||
| 		;; | ||||
| 	esac | ||||
|  | @ -386,58 +297,106 @@ do | |||
| 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." | ||||
| 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 | ||||
| 	# The upstream head must be given.  Make sure it is valid. | ||||
| 	upstream_name="$1" | ||||
| 	case "$#" in | ||||
| 	0) | ||||
| 		if ! upstream_name=$(git rev-parse --symbolic-full-name \ | ||||
| 			--verify -q @{upstream} 2>/dev/null) | ||||
| 		then | ||||
| 			. git-parse-remote | ||||
| 			error_on_missing_default_upstream "rebase" "rebase" \ | ||||
| 				"against" "git rebase <upstream branch>" | ||||
| 		fi | ||||
| 		;; | ||||
| 	*)	upstream_name="$1" | ||||
| 		shift | ||||
| 		;; | ||||
| 	esac | ||||
| 	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#*...} && | ||||
|  | @ -456,13 +415,11 @@ case "$onto_name" in | |||
| 	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,10 +432,10 @@ case "$#" in | |||
| 	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 | ||||
|  | @ -496,20 +453,23 @@ case "$#" in | |||
| 		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 | ||||
|  | @ -522,10 +482,8 @@ then | |||
| 	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 | ||||
|  | @ -537,9 +495,16 @@ 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 +518,4 @@ else | |||
| 	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 | ||||
|  |  | |||
|  | @ -158,15 +158,24 @@ test_expect_success 'Show verbose error when HEAD could not be detached' ' | |||
| ' | ||||
| rm -f B | ||||
|  | ||||
| test_expect_success 'dump usage when upstream arg is missing' ' | ||||
| 	git checkout -b usage topic && | ||||
| 	test_must_fail git rebase 2>error1 && | ||||
| 	grep "[Uu]sage" error1 && | ||||
| 	test_must_fail git rebase --abort 2>error2 && | ||||
| 	grep "No rebase in progress" error2 && | ||||
| 	test_must_fail git rebase --onto master 2>error3 && | ||||
| 	grep "[Uu]sage" error3 && | ||||
| 	! grep "can.t shift" error3 | ||||
| test_expect_success 'fail when upstream arg is missing and not on branch' ' | ||||
| 	git checkout topic && | ||||
| 	test_must_fail git rebase >output.out && | ||||
| 	grep "You are not currently on a branch" output.out | ||||
| ' | ||||
|  | ||||
| test_expect_success 'fail when upstream arg is missing and not configured' ' | ||||
| 	git checkout -b no-config topic && | ||||
| 	test_must_fail git rebase >output.out && | ||||
| 	grep "branch.no-config.merge" output.out | ||||
| ' | ||||
|  | ||||
| test_expect_success 'default to @{upstream} when upstream arg is missing' ' | ||||
| 	git checkout -b default topic && | ||||
| 	git config branch.default.remote . | ||||
| 	git config branch.default.merge refs/heads/master | ||||
| 	git rebase && | ||||
| 	test "$(git rev-parse default~1)" = "$(git rev-parse master)" | ||||
| ' | ||||
|  | ||||
| test_expect_success 'rebase -q is quiet' ' | ||||
|  |  | |||
|  | @ -35,6 +35,11 @@ test_expect_success 'rebase with git am -3 (default)' ' | |||
| 	test_must_fail git rebase master | ||||
| ' | ||||
|  | ||||
| test_expect_success 'rebase --skip can not be used with other options' ' | ||||
| 	test_must_fail git rebase -v --skip && | ||||
| 	test_must_fail git rebase --skip -v | ||||
| ' | ||||
|  | ||||
| test_expect_success 'rebase --skip with am -3' ' | ||||
| 	git rebase --skip | ||||
| 	' | ||||
|  |  | |||
|  | @ -84,6 +84,16 @@ testrebase() { | |||
| 		test_cmp reflog_before reflog_after && | ||||
| 		rm reflog_before reflog_after | ||||
| 	' | ||||
|  | ||||
| 	test_expect_success 'rebase --abort can not be used with other options' ' | ||||
| 		cd "$work_dir" && | ||||
| 		# Clean up the state from the previous one | ||||
| 		git reset --hard pre-rebase && | ||||
| 		test_must_fail git rebase$type master && | ||||
| 		test_must_fail git rebase -v --abort && | ||||
| 		test_must_fail git rebase --abort -v && | ||||
| 		git rebase --abort | ||||
| 	' | ||||
| } | ||||
|  | ||||
| testrebase "" .git/rebase-apply | ||||
|  |  | |||
|  | @ -40,4 +40,59 @@ test_expect_success 'non-interactive rebase --continue works with touched file' | |||
| 	git rebase --continue | ||||
| ' | ||||
|  | ||||
| test_expect_success 'rebase --continue can not be used with other options' ' | ||||
| 	test_must_fail git rebase -v --continue && | ||||
| 	test_must_fail git rebase --continue -v | ||||
| ' | ||||
|  | ||||
| test_expect_success 'rebase --continue remembers merge strategy and options' ' | ||||
| 	rm -fr .git/rebase-* && | ||||
| 	git reset --hard commit-new-file-F2-on-topic-branch && | ||||
| 	test_commit "commit-new-file-F3-on-topic-branch" F3 32 && | ||||
| 	test_when_finished "rm -fr test-bin funny.was.run" && | ||||
| 	mkdir test-bin && | ||||
| 	cat >test-bin/git-merge-funny <<-EOF | ||||
| 	#!$SHELL_PATH | ||||
| 	case "\$1" in --opt) ;; *) exit 2 ;; esac | ||||
| 	shift && | ||||
| 	>funny.was.run && | ||||
| 	exec git merge-recursive "\$@" | ||||
| 	EOF | ||||
| 	chmod +x test-bin/git-merge-funny && | ||||
| 	( | ||||
| 		PATH=./test-bin:$PATH | ||||
| 		test_must_fail git rebase -s funny -Xopt master topic | ||||
| 	) && | ||||
| 	test -f funny.was.run && | ||||
| 	rm funny.was.run && | ||||
| 	echo "Resolved" >F2 && | ||||
| 	git add F2 && | ||||
| 	( | ||||
| 		PATH=./test-bin:$PATH | ||||
| 		git rebase --continue | ||||
| 	) && | ||||
| 	test -f funny.was.run | ||||
| ' | ||||
|  | ||||
| test_expect_success 'rebase --continue remembers --rerere-autoupdate' ' | ||||
| 	rm -fr .git/rebase-* && | ||||
| 	git reset --hard commit-new-file-F3-on-topic-branch && | ||||
| 	git checkout master | ||||
| 	test_commit "commit-new-file-F3" F3 3 && | ||||
| 	git config rerere.enabled true && | ||||
| 	test_must_fail git rebase -m master topic && | ||||
| 	echo "Resolved" >F2 && | ||||
| 	git add F2 && | ||||
| 	test_must_fail git rebase --continue && | ||||
| 	echo "Resolved" >F3 && | ||||
| 	git add F3 && | ||||
| 	git rebase --continue && | ||||
| 	git reset --hard topic@{1} && | ||||
| 	test_must_fail git rebase -m --rerere-autoupdate master && | ||||
| 	test "$(cat F2)" = "Resolved" && | ||||
| 	test_must_fail git rebase --continue && | ||||
| 	test "$(cat F3)" = "Resolved" && | ||||
| 	git rebase --continue | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano