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-quiltimport | ||||||
| /git-read-tree | /git-read-tree | ||||||
| /git-rebase | /git-rebase | ||||||
|  | /git-rebase--am | ||||||
| /git-rebase--interactive | /git-rebase--interactive | ||||||
|  | /git-rebase--merge | ||||||
| /git-receive-pack | /git-receive-pack | ||||||
| /git-reflog | /git-reflog | ||||||
| /git-relink | /git-relink | ||||||
|  |  | ||||||
|  | @ -641,7 +641,7 @@ branch.<name>.remote:: | ||||||
|  |  | ||||||
| branch.<name>.merge:: | branch.<name>.merge:: | ||||||
| 	Defines, together with branch.<name>.remote, the upstream branch | 	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). | 	branch to merge and can also affect 'git push' (see push.default). | ||||||
| 	When in branch <name>, it tells 'git fetch' the default | 	When in branch <name>, it tells 'git fetch' the default | ||||||
| 	refspec to be marked for merging in FETCH_HEAD. The value is | 	refspec to be marked for merging in FETCH_HEAD. The value is | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ SYNOPSIS | ||||||
| -------- | -------- | ||||||
| [verse] | [verse] | ||||||
| 'git rebase' [-i | --interactive] [options] [--onto <newbase>] | 'git rebase' [-i | --interactive] [options] [--onto <newbase>] | ||||||
| 	<upstream> [<branch>] | 	[<upstream>] [<branch>] | ||||||
| 'git rebase' [-i | --interactive] [options] --onto <newbase> | 'git rebase' [-i | --interactive] [options] --onto <newbase> | ||||||
| 	--root [<branch>] | 	--root [<branch>] | ||||||
|  |  | ||||||
|  | @ -21,6 +21,12 @@ If <branch> is specified, 'git rebase' will perform an automatic | ||||||
| `git checkout <branch>` before doing anything else.  Otherwise | `git checkout <branch>` before doing anything else.  Otherwise | ||||||
| it remains on the current branch. | 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 | 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 | 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 | 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>:: | ||||||
| 	Upstream branch to compare against.  May be any valid commit, | 	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>:: | <branch>:: | ||||||
| 	Working branch; defaults to HEAD. | 	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-mergetool.sh | ||||||
| SCRIPT_SH += git-pull.sh | SCRIPT_SH += git-pull.sh | ||||||
| SCRIPT_SH += git-quiltimport.sh | SCRIPT_SH += git-quiltimport.sh | ||||||
| SCRIPT_SH += git-rebase--interactive.sh |  | ||||||
| SCRIPT_SH += git-rebase.sh | SCRIPT_SH += git-rebase.sh | ||||||
| SCRIPT_SH += git-repack.sh | SCRIPT_SH += git-repack.sh | ||||||
| SCRIPT_SH += git-request-pull.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-mergetool--lib | ||||||
| SCRIPT_LIB += git-parse-remote | 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_LIB += git-sh-setup | ||||||
|  |  | ||||||
| SCRIPT_PERL += git-add--interactive.perl | SCRIPT_PERL += git-add--interactive.perl | ||||||
|  |  | ||||||
|  | @ -50,3 +50,41 @@ get_remote_merge_branch () { | ||||||
| 	    esac | 	    esac | ||||||
| 	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 "You asked to pull from the remote '$1', but did not specify" | ||||||
| 		echo "a branch. Because this is not the default configured remote" | 		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." | 		echo "for your current branch, you must specify a branch on the command line." | ||||||
| 	elif [ -z "$curr_branch" ]; then | 	elif [ -z "$curr_branch" -o -z "$upstream" ]; then | ||||||
| 		echo "You are not currently on a branch, so I cannot use any" | 		. git-parse-remote | ||||||
| 		echo "'branch.<branchname>.merge' in your configuration file." | 		error_on_missing_default_upstream "pull" $op_type $op_prep \ | ||||||
| 		echo "Please specify which remote branch you want to use on the command" | 			"git pull <repository> <refspec>" | ||||||
| 		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." |  | ||||||
| 	else | 	else | ||||||
| 		echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'" | 		echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'" | ||||||
| 		echo "from the remote, but no such ref was fetched." | 		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 | ||||||
							
								
								
									
										598
									
								
								git-rebase.sh
								
								
								
								
							
							
						
						
									
										598
									
								
								git-rebase.sh
								
								
								
								
							|  | @ -3,7 +3,7 @@ | ||||||
| # Copyright (c) 2005 Junio C Hamano. | # 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 | LONG_USAGE='git-rebase replaces <branch> with a new branch of the | ||||||
| same name.  When the --onto option is provided the new branch starts | 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> | 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 | 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 | . git-sh-setup | ||||||
| set_reflog_action rebase | set_reflog_action rebase | ||||||
| require_work_tree | require_work_tree | ||||||
|  | @ -36,18 +68,18 @@ cd_to_toplevel | ||||||
|  |  | ||||||
| LF=' | LF=' | ||||||
| ' | ' | ||||||
| OK_TO_SKIP_PRE_REBASE= | ok_to_skip_pre_rebase= | ||||||
| RESOLVEMSG=" | resolvemsg=" | ||||||
| When you have resolved this problem run \"git rebase --continue\". | When you have resolved this problem run \"git rebase --continue\". | ||||||
| If you would prefer to skip this patch, instead run \"git rebase --skip\". | 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\". | To restore the original branch and stop rebasing run \"git rebase --abort\". | ||||||
| " | " | ||||||
| unset newbase | unset onto | ||||||
| strategy=recursive | strategy= | ||||||
| strategy_opts= | strategy_opts= | ||||||
| do_merge= | do_merge= | ||||||
| dotest="$GIT_DIR"/rebase-merge | merge_dir="$GIT_DIR"/rebase-merge | ||||||
| prec=4 | apply_dir="$GIT_DIR"/rebase-apply | ||||||
| verbose= | verbose= | ||||||
| diffstat= | diffstat= | ||||||
| test "$(git config --bool rebase.stat)" = true && diffstat=t | test "$(git config --bool rebase.stat)" = true && diffstat=t | ||||||
|  | @ -55,92 +87,67 @@ git_am_opt= | ||||||
| rebase_root= | rebase_root= | ||||||
| force_rebase= | force_rebase= | ||||||
| allow_rerere_autoupdate= | 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 () { | read_basic_state () { | ||||||
| 	test -n "$prev_head" || die "prev_head must be defined" | 	head_name=$(cat "$state_dir"/head-name) && | ||||||
| 	test -d "$dotest" || die "$dotest directory does not exist" | 	onto=$(cat "$state_dir"/onto) && | ||||||
|  | 	# We always write to orig-head, but interactive rebase used to write to | ||||||
| 	unmerged=$(git ls-files -u) | 	# head. Fall back to reading from head to cover for the case that the | ||||||
| 	if test -n "$unmerged" | 	# user upgraded git with an ongoing interactive rebase. | ||||||
|  | 	if test -f "$state_dir"/orig-head | ||||||
| 	then | 	then | ||||||
| 		echo "You still have unmerged paths in your index" | 		orig_head=$(cat "$state_dir"/orig-head) | ||||||
| 		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" |  | ||||||
| 	else | 	else | ||||||
| 		if test -z "$GIT_QUIET" | 		orig_head=$(cat "$state_dir"/head) | ||||||
| 		then | 	fi && | ||||||
| 			printf "Already applied: %0${prec}d " $msgnum | 	GIT_QUIET=$(cat "$state_dir"/quiet) && | ||||||
| 		fi | 	test -f "$state_dir"/verbose && verbose=t | ||||||
| 	fi | 	test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)" | ||||||
| 	test -z "$GIT_QUIET" && | 	test -f "$state_dir"/strategy_opts && | ||||||
| 	GIT_PAGER='' git log --format=%s -1 "$cmt" | 		strategy_opts="$(cat "$state_dir"/strategy_opts)" | ||||||
|  | 	test -f "$state_dir"/allow_rerere_autoupdate && | ||||||
| 	prev_head=`git rev-parse HEAD^0` | 		allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)" | ||||||
| 	# 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" |  | ||||||
| } | } | ||||||
|  |  | ||||||
| call_merge () { | write_basic_state () { | ||||||
| 	cmt="$(cat "$dotest/cmt.$1")" | 	echo "$head_name" > "$state_dir"/head-name && | ||||||
| 	echo "$cmt" > "$dotest/current" | 	echo "$onto" > "$state_dir"/onto && | ||||||
| 	hd=$(git rev-parse --verify HEAD) | 	echo "$orig_head" > "$state_dir"/orig-head && | ||||||
| 	cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) | 	echo "$GIT_QUIET" > "$state_dir"/quiet && | ||||||
| 	msgnum=$(cat "$dotest/msgnum") | 	test t = "$verbose" && : > "$state_dir"/verbose | ||||||
| 	end=$(cat "$dotest/end") | 	test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy | ||||||
| 	eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"' | 	test -n "$strategy_opts" && echo "$strategy_opts" > \ | ||||||
| 	eval GITHEAD_$hd='$(cat "$dotest/onto_name")' | 		"$state_dir"/strategy_opts | ||||||
| 	export GITHEAD_$cmt GITHEAD_$hd | 	test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \ | ||||||
| 	if test -n "$GIT_QUIET" | 		"$state_dir"/allow_rerere_autoupdate | ||||||
| 	then | } | ||||||
| 		GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY |  | ||||||
| 	fi | output () { | ||||||
| 	eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"' | 	case "$verbose" in | ||||||
| 	rv=$? | 	'') | ||||||
| 	case "$rv" in | 		output=$("$@" 2>&1 ) | ||||||
| 	0) | 		status=$? | ||||||
| 		unset GITHEAD_$cmt GITHEAD_$hd | 		test $status != 0 && printf "%s\n" "$output" | ||||||
| 		return | 		return $status | ||||||
| 		;; |  | ||||||
| 	1) |  | ||||||
| 		git rerere $allow_rerere_autoupdate |  | ||||||
| 		die "$RESOLVEMSG" |  | ||||||
| 		;; |  | ||||||
| 	2) |  | ||||||
| 		echo "Strategy: $rv $strategy failed, try another" 1>&2 |  | ||||||
| 		die "$RESOLVEMSG" |  | ||||||
| 		;; | 		;; | ||||||
| 	*) | 	*) | ||||||
| 		die "Unknown exit code ($rv) from command:" \ | 		"$@" | ||||||
| 			"git-merge-$strategy $cmt^ -- HEAD $cmt" |  | ||||||
| 		;; | 		;; | ||||||
| 	esac | 	esac | ||||||
| } | } | ||||||
|  |  | ||||||
| move_to_original_branch () { | 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 | 	case "$head_name" in | ||||||
| 	refs/*) | 	refs/*) | ||||||
| 		message="rebase finished: $head_name onto $onto" | 		message="rebase finished: $head_name onto $onto" | ||||||
|  | @ -152,42 +159,16 @@ move_to_original_branch () { | ||||||
| 	esac | 	esac | ||||||
| } | } | ||||||
|  |  | ||||||
| finish_rb_merge () { | run_specific_rebase () { | ||||||
| 	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 |  | ||||||
|  |  | ||||||
| 	if [ "$interactive_rebase" = implied ]; then | 	if [ "$interactive_rebase" = implied ]; then | ||||||
| 		GIT_EDITOR=: | 		GIT_EDITOR=: | ||||||
| 		export GIT_EDITOR | 		export GIT_EDITOR | ||||||
| 	fi | 	fi | ||||||
|  | 	. git-rebase--$type | ||||||
| 	test -n "$interactive_rebase" || test -f "$dotest"/interactive |  | ||||||
| } | } | ||||||
|  |  | ||||||
| run_pre_rebase_hook () { | 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" | 	   test -x "$GIT_DIR/hooks/pre-rebase" | ||||||
| 	then | 	then | ||||||
| 		"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || | 		"$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || | ||||||
|  | @ -195,163 +176,94 @@ run_pre_rebase_hook () { | ||||||
| 	fi | 	fi | ||||||
| } | } | ||||||
|  |  | ||||||
| test -f "$GIT_DIR"/rebase-apply/applying && | test -f "$apply_dir"/applying && | ||||||
| 	die 'It looks like git-am is in progress. Cannot rebase.' | 	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 | while test $# != 0 | ||||||
| do | do | ||||||
| 	case "$1" in | 	case "$1" in | ||||||
| 	--no-verify) | 	--no-verify) | ||||||
| 		OK_TO_SKIP_PRE_REBASE=yes | 		ok_to_skip_pre_rebase=yes | ||||||
| 		;; | 		;; | ||||||
| 	--verify) | 	--verify) | ||||||
| 		OK_TO_SKIP_PRE_REBASE= | 		ok_to_skip_pre_rebase= | ||||||
| 		;; | 		;; | ||||||
| 	--continue) | 	--continue|--skip|--abort) | ||||||
| 		test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || | 		test $total_argc -eq 2 || usage | ||||||
| 			die "No rebase in progress?" | 		action=${1##--} | ||||||
|  |  | ||||||
| 		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 |  | ||||||
| 		;; | 		;; | ||||||
| 	--onto) | 	--onto) | ||||||
| 		test 2 -le "$#" || usage | 		test 2 -le "$#" || usage | ||||||
| 		newbase="$2" | 		onto="$2" | ||||||
| 		shift | 		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 | 		do_merge=t | ||||||
| 		;; | 		;; | ||||||
| 	-X*|--strategy-option*) | 	-X) | ||||||
| 		case "$#,$1" in | 		shift | ||||||
| 		1,-X|1,--strategy-option) | 		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$1")" | ||||||
| 			usage ;; | 		do_merge=t | ||||||
| 		*,-X|*,--strategy-option) | 		test -z "$strategy" && strategy=recursive | ||||||
| 			newopt="$2" | 		;; | ||||||
| 			shift ;; | 	-s) | ||||||
| 		*,--strategy-option=*) | 		shift | ||||||
| 			newopt="$(expr " $1" : ' --strategy-option=\(.*\)')" ;; | 		strategy="$1" | ||||||
| 		*,-X*) |  | ||||||
| 			newopt="$(expr " $1" : ' -X\(.*\)')" ;; |  | ||||||
| 		1,*) |  | ||||||
| 			usage ;; |  | ||||||
| 		esac |  | ||||||
| 		strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")" |  | ||||||
| 		do_merge=t | 		do_merge=t | ||||||
| 		;; | 		;; | ||||||
| 	-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\ | 	-n) | ||||||
| 		--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) |  | ||||||
| 		diffstat= | 		diffstat= | ||||||
| 		;; | 		;; | ||||||
| 	--stat) | 	--stat) | ||||||
| 		diffstat=t | 		diffstat=t | ||||||
| 		;; | 		;; | ||||||
| 	-v|--verbose) | 	-v) | ||||||
| 		verbose=t | 		verbose=t | ||||||
| 		diffstat=t | 		diffstat=t | ||||||
| 		GIT_QUIET= | 		GIT_QUIET= | ||||||
| 		;; | 		;; | ||||||
| 	-q|--quiet) | 	-q) | ||||||
| 		GIT_QUIET=t | 		GIT_QUIET=t | ||||||
| 		git_am_opt="$git_am_opt -q" | 		git_am_opt="$git_am_opt -q" | ||||||
| 		verbose= | 		verbose= | ||||||
| 		diffstat= | 		diffstat= | ||||||
| 		;; | 		;; | ||||||
| 	--whitespace=*) | 	--whitespace) | ||||||
| 		git_am_opt="$git_am_opt $1" | 		shift | ||||||
|  | 		git_am_opt="$git_am_opt --whitespace=$1" | ||||||
| 		case "$1" in | 		case "$1" in | ||||||
| 		--whitespace=fix|--whitespace=strip) | 		fix|strip) | ||||||
| 			force_rebase=t | 			force_rebase=t | ||||||
| 			;; | 			;; | ||||||
| 		esac | 		esac | ||||||
|  | @ -363,22 +275,21 @@ do | ||||||
| 		git_am_opt="$git_am_opt $1" | 		git_am_opt="$git_am_opt $1" | ||||||
| 		force_rebase=t | 		force_rebase=t | ||||||
| 		;; | 		;; | ||||||
| 	-C*) | 	-C) | ||||||
| 		git_am_opt="$git_am_opt $1" | 		shift | ||||||
|  | 		git_am_opt="$git_am_opt -C$1" | ||||||
| 		;; | 		;; | ||||||
| 	--root) | 	--root) | ||||||
| 		rebase_root=t | 		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 | 		force_rebase=t | ||||||
| 		;; | 		;; | ||||||
| 	--rerere-autoupdate|--no-rerere-autoupdate) | 	--rerere-autoupdate|--no-rerere-autoupdate) | ||||||
| 		allow_rerere_autoupdate="$1" | 		allow_rerere_autoupdate="$1" | ||||||
| 		;; | 		;; | ||||||
| 	-*) | 	--) | ||||||
| 		usage | 		shift | ||||||
| 		;; |  | ||||||
| 	*) |  | ||||||
| 		break | 		break | ||||||
| 		;; | 		;; | ||||||
| 	esac | 	esac | ||||||
|  | @ -386,58 +297,106 @@ do | ||||||
| done | done | ||||||
| test $# -gt 2 && usage | test $# -gt 2 && usage | ||||||
|  |  | ||||||
| if test $# -eq 0 && test -z "$rebase_root" | if test -n "$action" | ||||||
| then | then | ||||||
| 	test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || usage | 	test -z "$in_progress" && die "No rebase in progress?" | ||||||
| 	test -d "$dotest" -o -f "$GIT_DIR"/rebase-apply/rebasing && | 	# Only interactive rebase uses detailed reflog messages | ||||||
| 		die 'A rebase is in progress, try --continue, --skip or --abort.' | 	if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase | ||||||
|  | 	then | ||||||
|  | 		GIT_REFLOG_ACTION="rebase -i ($action)" | ||||||
|  | 		export GIT_REFLOG_ACTION | ||||||
|  | 	fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # Make sure we do not have $GIT_DIR/rebase-apply | case "$action" in | ||||||
| if test -z "$do_merge" | 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 | then | ||||||
| 	if mkdir "$GIT_DIR"/rebase-apply 2>/dev/null | 	die ' | ||||||
| 	then | It seems that there is already a '"${state_dir##*/}"' directory, and | ||||||
| 		rmdir "$GIT_DIR"/rebase-apply | I wonder if you are in the middle of another rebase.  If that is the | ||||||
| 	else | case, please try | ||||||
| 		echo >&2 ' | 	git rebase (--continue | --abort | --skip) | ||||||
| It seems that I cannot create a rebase-apply directory, and | If that is not the case, please | ||||||
| I wonder if you are in the middle of patch application or another | 	rm -fr '"$state_dir"' | ||||||
| rebase.  If that is not the case, please |  | ||||||
| 	rm -fr '"$GIT_DIR"'/rebase-apply |  | ||||||
| and run me again.  I am stopping in case you still have something | and run me again.  I am stopping in case you still have something | ||||||
| valuable there.' | 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 | 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" | if test -z "$rebase_root" | ||||||
| then | then | ||||||
| 	# The upstream head must be given.  Make sure it is valid. | 	case "$#" in | ||||||
| 	upstream_name="$1" | 	0) | ||||||
| 	shift | 		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"` || | 	upstream=`git rev-parse --verify "${upstream_name}^0"` || | ||||||
| 	die "invalid upstream $upstream_name" | 	die "invalid upstream $upstream_name" | ||||||
| 	unset root_flag |  | ||||||
| 	upstream_arg="$upstream_name" | 	upstream_arg="$upstream_name" | ||||||
| else | 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_name | ||||||
| 	unset upstream | 	unset upstream | ||||||
| 	root_flag="--root" | 	upstream_arg=--root | ||||||
| 	upstream_arg="$root_flag" |  | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # Make sure the branch to rebase onto is valid. | # Make sure the branch to rebase onto is valid. | ||||||
| onto_name=${newbase-"$upstream_name"} | onto_name=${onto-"$upstream_name"} | ||||||
| case "$onto_name" in | case "$onto_name" in | ||||||
| *...*) | *...*) | ||||||
| 	if	left=${onto_name%...*} right=${onto_name#*...} && | 	if	left=${onto_name%...*} right=${onto_name#*...} && | ||||||
|  | @ -456,13 +415,11 @@ case "$onto_name" in | ||||||
| 	fi | 	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 | 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 | # If the branch to rebase is given, that is the branch we will rebase | ||||||
| # $branch_name -- branch being rebased, or HEAD (already detached) | # $branch_name -- branch being rebased, or HEAD (already detached) | ||||||
| # $orig_head -- commit object name of tip of the branch before rebasing | # $orig_head -- commit object name of tip of the branch before rebasing | ||||||
|  | @ -475,10 +432,10 @@ case "$#" in | ||||||
| 	switch_to="$1" | 	switch_to="$1" | ||||||
|  |  | ||||||
| 	if git show-ref --verify --quiet -- "refs/heads/$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 | 	then | ||||||
| 		head_name="refs/heads/$1" | 		head_name="refs/heads/$1" | ||||||
| 	elif branch=$(git rev-parse -q --verify "$1") | 	elif orig_head=$(git rev-parse -q --verify "$1") | ||||||
| 	then | 	then | ||||||
| 		head_name="detached HEAD" | 		head_name="detached HEAD" | ||||||
| 	else | 	else | ||||||
|  | @ -496,20 +453,23 @@ case "$#" in | ||||||
| 		head_name="detached HEAD" | 		head_name="detached HEAD" | ||||||
| 		branch_name=HEAD ;# detached | 		branch_name=HEAD ;# detached | ||||||
| 	fi | 	fi | ||||||
| 	branch=$(git rev-parse --verify "${branch_name}^0") || exit | 	orig_head=$(git rev-parse --verify "${branch_name}^0") || exit | ||||||
| 	;; | 	;; | ||||||
| esac | esac | ||||||
| orig_head=$branch |  | ||||||
|  |  | ||||||
| # Now we are rebasing commits $upstream..$branch (or with --root, | require_clean_work_tree "rebase" "Please commit or stash them." | ||||||
| # everything leading up to $branch) on top of $onto |  | ||||||
|  | # 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, | # Check if we are already based on $onto with linear history, | ||||||
| # but this should be done only when upstream and onto are the same. | # but this should be done only when upstream and onto are the same | ||||||
| mb=$(git merge-base "$onto" "$branch") | # and if this is not an interactive rebase. | ||||||
| if test "$upstream" = "$onto" && test "$mb" = "$onto" && | mb=$(git merge-base "$onto" "$orig_head") | ||||||
|  | if test "$type" != interactive && test "$upstream" = "$onto" && | ||||||
|  | 	test "$mb" = "$onto" && | ||||||
| 	# linear history? | 	# linear history? | ||||||
| 	! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null | 	! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null | ||||||
| then | then | ||||||
| 	if test -z "$force_rebase" | 	if test -z "$force_rebase" | ||||||
| 	then | 	then | ||||||
|  | @ -522,10 +482,8 @@ then | ||||||
| 	fi | 	fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
| # Detach HEAD and reset the tree | # If a hook exists, give it a chance to interrupt | ||||||
| say "First, rewinding head to replay your work on top of it..." | run_pre_rebase_hook "$upstream_arg" "$@" | ||||||
| git checkout -q "$onto^0" || die "could not detach HEAD" |  | ||||||
| git update-ref ORIG_HEAD $branch |  | ||||||
|  |  | ||||||
| if test -n "$diffstat" | if test -n "$diffstat" | ||||||
| then | then | ||||||
|  | @ -537,9 +495,16 @@ then | ||||||
| 	GIT_PAGER='' git diff --stat --summary "$mb" "$onto" | 	GIT_PAGER='' git diff --stat --summary "$mb" "$onto" | ||||||
| fi | 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 | # If the $onto is a proper descendant of the tip of the branch, then | ||||||
| # we just fast-forwarded. | # we just fast-forwarded. | ||||||
| if test "$mb" = "$branch" | if test "$mb" = "$orig_head" | ||||||
| then | then | ||||||
| 	say "Fast-forwarded $branch_name to $onto_name." | 	say "Fast-forwarded $branch_name to $onto_name." | ||||||
| 	move_to_original_branch | 	move_to_original_branch | ||||||
|  | @ -553,51 +518,4 @@ else | ||||||
| 	revisions="$upstream..$orig_head" | 	revisions="$upstream..$orig_head" | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if test -z "$do_merge" | run_specific_rebase | ||||||
| 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 |  | ||||||
|  |  | ||||||
|  | @ -158,15 +158,24 @@ test_expect_success 'Show verbose error when HEAD could not be detached' ' | ||||||
| ' | ' | ||||||
| rm -f B | rm -f B | ||||||
|  |  | ||||||
| test_expect_success 'dump usage when upstream arg is missing' ' | test_expect_success 'fail when upstream arg is missing and not on branch' ' | ||||||
| 	git checkout -b usage topic && | 	git checkout topic && | ||||||
| 	test_must_fail git rebase 2>error1 && | 	test_must_fail git rebase >output.out && | ||||||
| 	grep "[Uu]sage" error1 && | 	grep "You are not currently on a branch" output.out | ||||||
| 	test_must_fail git rebase --abort 2>error2 && | ' | ||||||
| 	grep "No rebase in progress" error2 && |  | ||||||
| 	test_must_fail git rebase --onto master 2>error3 && | test_expect_success 'fail when upstream arg is missing and not configured' ' | ||||||
| 	grep "[Uu]sage" error3 && | 	git checkout -b no-config topic && | ||||||
| 	! grep "can.t shift" error3 | 	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' ' | 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_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' ' | test_expect_success 'rebase --skip with am -3' ' | ||||||
| 	git rebase --skip | 	git rebase --skip | ||||||
| 	' | 	' | ||||||
|  |  | ||||||
|  | @ -84,6 +84,16 @@ testrebase() { | ||||||
| 		test_cmp reflog_before reflog_after && | 		test_cmp reflog_before reflog_after && | ||||||
| 		rm 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 | testrebase "" .git/rebase-apply | ||||||
|  |  | ||||||
|  | @ -40,4 +40,59 @@ test_expect_success 'non-interactive rebase --continue works with touched file' | ||||||
| 	git rebase --continue | 	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 | test_done | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano