Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
git
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security
Insights
Files
9765b6a
Documentation
block-sha1
builtin
compat
contrib
git-gui
git_remote_helpers
gitk-git
gitweb
perl
ppc
t
templates
vcs-svn
xdiff
.gitattributes
.gitignore
.mailmap
COPYING
GIT-VERSION-GEN
INSTALL
Makefile
README
RelNotes
abspath.c
aclocal.m4
advice.c
advice.h
alias.c
alloc.c
archive-tar.c
archive-zip.c
archive.c
archive.h
attr.c
attr.h
base85.c
bisect.c
bisect.h
blob.c
blob.h
branch.c
branch.h
builtin.h
bundle.c
bundle.h
cache-tree.c
cache-tree.h
cache.h
check-builtins.sh
check-racy.c
check_bindir
color.c
color.h
combine-diff.c
command-list.txt
commit.c
commit.h
config.c
config.mak.in
configure.ac
connect.c
convert.c
copy.c
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
decorate.c
decorate.h
delta.h
diff-delta.c
diff-lib.c
diff-no-index.c
diff.c
diff.h
diffcore-break.c
diffcore-delta.c
diffcore-order.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore.h
dir.c
dir.h
editor.c
entry.c
environment.c
exec_cmd.c
exec_cmd.h
fast-import.c
fetch-pack.h
fixup-builtins
fsck.c
fsck.h
generate-cmdlist.sh
git-add--interactive.perl
git-am.sh
git-archimport.perl
git-bisect.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-difftool--helper.sh
git-difftool.perl
git-filter-branch.sh
git-instaweb.sh
git-lost-found.sh
git-merge-octopus.sh
git-merge-one-file.sh
git-merge-resolve.sh
git-mergetool--lib.sh
git-mergetool.sh
git-parse-remote.sh
git-pull.sh
git-quiltimport.sh
git-rebase--interactive.sh
git-rebase.sh
git-relink.perl
git-remote-testgit.py
git-repack.sh
git-request-pull.sh
git-send-email.perl
git-sh-setup.sh
git-stash.sh
git-submodule.sh
git-svn.perl
git-web--browse.sh
git.c
git.spec.in
graph.c
graph.h
grep.c
grep.h
hash.c
hash.h
help.c
help.h
hex.c
http-backend.c
http-fetch.c
http-push.c
http-walker.c
http.c
http.h
ident.c
imap-send.c
levenshtein.c
levenshtein.h
list-objects.c
list-objects.h
ll-merge.c
ll-merge.h
lockfile.c
log-tree.c
log-tree.h
mailmap.c
mailmap.h
match-trees.c
merge-file.c
merge-recursive.c
merge-recursive.h
name-hash.c
notes-cache.c
notes-cache.h
notes-merge.c
notes-merge.h
notes.c
notes.h
object.c
object.h
pack-check.c
pack-refs.c
pack-refs.h
pack-revindex.c
pack-revindex.h
pack-write.c
pack.h
pager.c
parse-options.c
parse-options.h
patch-delta.c
patch-ids.c
patch-ids.h
path.c
pkt-line.c
pkt-line.h
preload-index.c
pretty.c
progress.c
progress.h
quote.c
quote.h
reachable.c
reachable.h
read-cache.c
reflog-walk.c
reflog-walk.h
refs.c
refs.h
remote-curl.c
remote.c
remote.h
replace_object.c
rerere.c
rerere.h
resolve-undo.c
resolve-undo.h
revision.c
revision.h
run-command.c
run-command.h
send-pack.h
server-info.c
setup.c
sha1-lookup.c
sha1-lookup.h
sha1_file.c
sha1_name.c
shallow.c
shell.c
shortlog.h
show-index.c
sideband.c
sideband.h
sigchain.c
sigchain.h
strbuf.c
strbuf.h
string-list.c
string-list.h
submodule.c
submodule.h
symlinks.c
tag.c
tag.h
tar.h
test-chmtime.c
test-ctype.c
test-date.c
test-delta.c
test-dump-cache-tree.c
test-genrandom.c
test-index-version.c
test-line-buffer.c
test-match-trees.c
test-mktemp.c
test-obj-pool.c
test-parse-options.c
test-path-utils.c
test-run-command.c
test-sha1.c
test-sha1.sh
test-sigchain.c
test-string-pool.c
test-subprocess.c
test-svn-fe.c
test-treap.c
thread-utils.c
thread-utils.h
trace.c
transport-helper.c
transport.c
transport.h
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
tree.h
unimplemented.sh
unpack-trees.c
unpack-trees.h
upload-pack.c
url.c
url.h
usage.c
userdiff.c
userdiff.h
utf8.c
utf8.h
walker.c
walker.h
wrap-for-bin.sh
wrapper.c
write_or_die.c
ws.c
wt-status.c
wt-status.h
xdiff-interface.c
xdiff-interface.h
zlib.c
Breadcrumbs
git
/
git-rebase.sh
Blame
Blame
Latest commit
History
History
executable file
·
599 lines (552 loc) · 13.8 KB
Breadcrumbs
git
/
git-rebase.sh
Top
File metadata and controls
Code
Blame
executable file
·
599 lines (552 loc) · 13.8 KB
Raw
#!/bin/sh # # Copyright (c) 2005 Junio C Hamano. # 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> It then attempts to create a new commit for each commit from the original <branch> that does not exist in the <upstream> branch. It is possible that a merge failure will prevent this process from being completely automatic. You will have to resolve any such merge failure and run git rebase --continue. Another option is to bypass the commit that caused the merge failure with git rebase --skip. To restore the original <branch> and remove the .git/rebase-apply working files, use the command git rebase --abort instead. Note that if <branch> is not specified on the command line, the currently checked out branch is used. Example: git-rebase master~1 topic A---B---C topic A'\''--B'\''--C'\'' topic / --> / D---E---F---G master D---E---F---G master ' SUBDIRECTORY_OK=Yes OPTIONS_SPEC= . git-sh-setup set_reflog_action rebase require_work_tree cd_to_toplevel LF=' ' 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 onto strategy= strategy_opts= do_merge= merge_dir="$GIT_DIR"/rebase-merge apply_dir="$GIT_DIR"/rebase-apply prec=4 verbose= diffstat= test "$(git config --bool rebase.stat)" = true && diffstat=t 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= read_state () { if test "$type" = merge then onto_name=$(cat "$state_dir"/onto_name) && end=$(cat "$state_dir"/end) && msgnum=$(cat "$state_dir"/msgnum) fi && head_name=$(cat "$state_dir"/head-name) && onto=$(cat "$state_dir"/onto) && orig_head=$(cat "$state_dir"/orig-head) && GIT_QUIET=$(cat "$state_dir"/quiet) } continue_merge () { test -d "$merge_dir" || die "$merge_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 "$merge_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)" >> "$merge_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" >"$merge_dir/msgnum" } call_merge () { cmt="$(cat "$merge_dir/cmt.$1")" echo "$cmt" > "$merge_dir/current" hd=$(git rev-parse --verify HEAD) cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD) msgnum=$(cat "$merge_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: $rv $strategy failed, try another" 1>&2 die "$resolvemsg" ;; *) die "Unknown exit code ($rv) from command:" \ "git-merge-$strategy $cmt^ -- HEAD $cmt" ;; esac } move_to_original_branch () { case "$head_name" in refs/*) message="rebase finished: $head_name onto $onto" git update-ref -m "$message" \ $head_name $(git rev-parse HEAD) $orig_head && git symbolic-ref HEAD $head_name || die "Could not move back to $head_name" ;; esac } finish_rb_merge () { move_to_original_branch git notes copy --for-rewrite=rebase < "$merge_dir"/rewritten if test -x "$GIT_DIR"/hooks/post-rewrite && test -s "$merge_dir"/rewritten; then "$GIT_DIR"/hooks/post-rewrite rebase < "$merge_dir"/rewritten fi rm -r "$merge_dir" 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 GIT_EDITOR=: export GIT_EDITOR fi test -n "$interactive_rebase" || test -f "$merge_dir"/interactive } run_pre_rebase_hook () { if test -z "$ok_to_skip_pre_rebase" && test -x "$GIT_DIR/hooks/pre-rebase" then "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || die "The pre-rebase hook refused to rebase." fi } 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 ;; --verify) ok_to_skip_pre_rebase= ;; --continue|--skip|--abort) test $total_argc -eq 1 || usage action=${1##--} ;; --onto) test 2 -le "$#" || usage onto="$2" shift ;; -M|-m|--m|--me|--mer|--merg|--merge) 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")" do_merge=t test -z "$strategy" && strategy=recursive ;; -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) diffstat= ;; --stat) diffstat=t ;; -v|--verbose) verbose=t diffstat=t GIT_QUIET= ;; -q|--quiet) GIT_QUIET=t git_am_opt="$git_am_opt -q" verbose= diffstat= ;; --whitespace=*) git_am_opt="$git_am_opt $1" case "$1" in --whitespace=fix|--whitespace=strip) force_rebase=t ;; esac ;; --ignore-whitespace) git_am_opt="$git_am_opt $1" ;; --committer-date-is-author-date|--ignore-date) git_am_opt="$git_am_opt $1" force_rebase=t ;; -C*) git_am_opt="$git_am_opt $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) force_rebase=t ;; --rerere-autoupdate|--no-rerere-autoupdate) allow_rerere_autoupdate="$1" ;; -*) usage ;; *) break ;; esac shift done test $# -gt 2 && usage test -n "$action" && test -z "$in_progress" && die "No rebase in progress?" case "$action" in continue) 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_state if test -d "$merge_dir" then continue_merge while test "$msgnum" -le "$end" do call_merge "$msgnum" continue_merge done finish_rb_merge exit fi git am --resolved --3way --resolvemsg="$resolvemsg" && move_to_original_branch exit ;; skip) git reset --hard HEAD || exit $? read_state if test -d "$merge_dir" then git rerere clear msgnum=$(($msgnum + 1)) while test "$msgnum" -le "$end" do call_merge "$msgnum" continue_merge done finish_rb_merge exit fi git am -3 --skip --resolvemsg="$resolvemsg" && move_to_original_branch exit ;; abort) git rerere clear read_state case "$head_name" in refs/*) git symbolic-ref HEAD $head_name || die "Could not move back to $head_name" ;; esac git reset --hard $orig_head rm -r "$state_dir" exit ;; esac # Make sure no rebase is in progress if test -n "$in_progress" then 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.' fi test $# -eq 0 && test -z "$rebase_root" && usage require_clean_work_tree "rebase" "Please commit or stash them." if test -z "$rebase_root" then # The upstream head must be given. Make sure it is valid. upstream_name="$1" shift upstream=`git rev-parse --verify "${upstream_name}^0"` || die "invalid upstream $upstream_name" unset root_flag upstream_arg="$upstream_name" else test -z "$onto" && die "--root must be used with --onto" unset upstream_name unset upstream root_flag="--root" upstream_arg="$root_flag" fi # Make sure the branch to rebase onto is valid. onto_name=${onto-"$upstream_name"} case "$onto_name" in *...*) if left=${onto_name%...*} right=${onto_name#*...} && onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD}) then case "$onto" in ?*"$LF"?*) die "$onto_name: there are more than one merge bases" ;; '') die "$onto_name: there is no merge base" ;; esac else die "$onto_name: there is no merge base" fi ;; *) onto=$(git rev-parse --verify "${onto_name}^0") || exit ;; 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 # $head_name -- refs/heads/<that-branch> or "detached HEAD" switch_to= case "$#" in 1) # Is it "rebase other $branchname" or "rebase other $commit"? branch_name="$1" switch_to="$1" if git show-ref --verify --quiet -- "refs/heads/$1" && branch=$(git rev-parse -q --verify "refs/heads/$1") then head_name="refs/heads/$1" elif branch=$(git rev-parse -q --verify "$1") then head_name="detached HEAD" else echo >&2 "fatal: no such branch: $1" usage fi ;; *) # Do not need to switch branches, we are already on it. if branch_name=`git symbolic-ref -q HEAD` then head_name=$branch_name branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'` else head_name="detached HEAD" branch_name=HEAD ;# detached fi branch=$(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 # 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" && # linear history? ! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null then if test -z "$force_rebase" then # Lazily switch to the target branch if needed... test -z "$switch_to" || git checkout "$switch_to" -- say "Current branch $branch_name is up to date." exit 0 else say "Current branch $branch_name is up to date, rebase forced." 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 test -n "$diffstat" then if test -n "$verbose" then echo "Changes from $mb to $onto:" fi # We want color (if set), but no pager GIT_PAGER='' git diff --stat --summary "$mb" "$onto" fi # If the $onto is a proper descendant of the tip of the branch, then # we just fast-forwarded. if test "$mb" = "$branch" then say "Fast-forwarded $branch_name to $onto_name." move_to_original_branch exit 0 fi if test -n "$rebase_root" then revisions="$onto..$orig_head" 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 "$apply_dir" && echo $head_name > "$apply_dir/head-name" && echo $onto > "$apply_dir/onto" && echo $orig_head > "$apply_dir/orig-head" && echo "$GIT_QUIET" > "$apply_dir/quiet" exit $ret fi # start doing a rebase with git-merge # this is rename-aware if the recursive (default) strategy is used mkdir -p "$merge_dir" echo "$onto_name" > "$merge_dir/onto_name" echo "$head_name" > "$merge_dir/head-name" echo "$onto" > "$merge_dir/onto" echo "$orig_head" > "$merge_dir/orig-head" echo "$GIT_QUIET" > "$merge_dir/quiet" msgnum=0 for cmt in `git rev-list --reverse --no-merges "$revisions"` do msgnum=$(($msgnum + 1)) echo "$cmt" > "$merge_dir/cmt.$msgnum" done echo 1 >"$merge_dir/msgnum" echo $msgnum >"$merge_dir/end" end=$msgnum msgnum=1 while test "$msgnum" -le "$end" do call_merge "$msgnum" continue_merge done finish_rb_merge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
You can’t perform that action at this time.