77e972bb6ce6081462004731bf13d1d78afc9539
1# This shell script fragment is sourced by git-rebase to implement
2# its interactive mode. "git rebase --interactive" makes it easy
3# to fix up commits in the middle of a series and rearrange commits.
4#
5# Copyright (c) 2006 Johannes E. Schindelin
6#
7# The original idea comes from Eric W. Biederman, in
8# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/
9#
10# The file containing rebase commands, comments, and empty lines.
11# This file is created by "git rebase -i" then edited by the user. As
12# the lines are processed, they are removed from the front of this
13# file and written to the tail of $done.
14todo="$state_dir"/git-rebase-todo
15
16GIT_CHERRY_PICK_HELP="$resolvemsg"
17export GIT_CHERRY_PICK_HELP
18
19comment_char=$(git config --get core.commentchar 2>/dev/null)
20case "$comment_char" in
21'' | auto)
22 comment_char="#"
23 ;;
24?)
25 ;;
26*)
27 comment_char=$(echo "$comment_char" | cut -c1)
28 ;;
29esac
30
31orig_reflog_action="$GIT_REFLOG_ACTION"
32
33comment_for_reflog () {
34 case "$orig_reflog_action" in
35 ''|rebase*)
36 GIT_REFLOG_ACTION="rebase -i ($1)"
37 export GIT_REFLOG_ACTION
38 ;;
39 esac
40}
41
42die_abort () {
43 apply_autostash
44 rm -rf "$state_dir"
45 die "$1"
46}
47
48has_action () {
49 test -n "$(git stripspace --strip-comments <"$1")"
50}
51
52git_sequence_editor () {
53 if test -z "$GIT_SEQUENCE_EDITOR"
54 then
55 GIT_SEQUENCE_EDITOR="$(git config sequence.editor)"
56 if [ -z "$GIT_SEQUENCE_EDITOR" ]
57 then
58 GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $?
59 fi
60 fi
61
62 eval "$GIT_SEQUENCE_EDITOR" '"$@"'
63}
64
65expand_todo_ids() {
66 git rebase--helper --expand-ids
67}
68
69collapse_todo_ids() {
70 git rebase--helper --shorten-ids
71}
72
73# Switch to the branch in $into and notify it in the reflog
74checkout_onto () {
75 comment_for_reflog start
76 GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
77 output git checkout $onto || die_abort "$(gettext "could not detach HEAD")"
78 git update-ref ORIG_HEAD $orig_head
79}
80
81get_missing_commit_check_level () {
82 check_level=$(git config --get rebase.missingCommitsCheck)
83 check_level=${check_level:-ignore}
84 # Don't be case sensitive
85 printf '%s' "$check_level" | tr 'A-Z' 'a-z'
86}
87
88# Initiate an action. If the cannot be any
89# further action it may exec a command
90# or exit and not return.
91#
92# TODO: Consider a cleaner return model so it
93# never exits and always return 0 if process
94# is complete.
95#
96# Parameter 1 is the action to initiate.
97#
98# Returns 0 if the action was able to complete
99# and if 1 if further processing is required.
100initiate_action () {
101 case "$1" in
102 continue)
103 exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
104 --continue
105 ;;
106 skip)
107 git rerere clear
108 exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
109 --continue
110 ;;
111 edit-todo)
112 exec git rebase--helper --edit-todo
113 ;;
114 show-current-patch)
115 exec git show REBASE_HEAD --
116 ;;
117 *)
118 return 1 # continue
119 ;;
120 esac
121}
122
123init_basic_state () {
124 orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
125 mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
126 rm -f "$(git rev-parse --git-path REBASE_HEAD)"
127
128 : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
129 write_basic_state
130}
131
132init_revisions_and_shortrevisions () {
133 shorthead=$(git rev-parse --short $orig_head)
134 shortonto=$(git rev-parse --short $onto)
135 if test -z "$rebase_root"
136 # this is now equivalent to ! -z "$upstream"
137 then
138 shortupstream=$(git rev-parse --short $upstream)
139 revisions=$upstream...$orig_head
140 shortrevisions=$shortupstream..$shorthead
141 else
142 revisions=$onto...$orig_head
143 shortrevisions=$shorthead
144 test -z "$squash_onto" ||
145 echo "$squash_onto" >"$state_dir"/squash-onto
146 fi
147}
148
149complete_action() {
150 test -s "$todo" || echo noop >> "$todo"
151 test -z "$autosquash" || git rebase--helper --rearrange-squash || exit
152 test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd"
153
154 todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
155 todocount=${todocount##* }
156
157cat >>"$todo" <<EOF
158
159$comment_char $(eval_ngettext \
160 "Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \
161 "Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \
162 "$todocount")
163EOF
164 git rebase--helper --append-todo-help ${keep_empty:+--keep-empty}
165
166 has_action "$todo" ||
167 return 2
168
169 cp "$todo" "$todo".backup
170 collapse_todo_ids
171 git_sequence_editor "$todo" ||
172 die_abort "$(gettext "Could not execute editor")"
173
174 has_action "$todo" ||
175 return 2
176
177 git rebase--helper --check-todo-list || {
178 ret=$?
179 checkout_onto
180 exit $ret
181 }
182
183 expand_todo_ids
184
185 test -n "$force_rebase" ||
186 onto="$(git rebase--helper --skip-unnecessary-picks)" ||
187 die "Could not skip unnecessary pick commands"
188
189 checkout_onto
190 require_clean_work_tree "rebase"
191 exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
192 --continue
193}
194
195git_rebase__interactive () {
196 initiate_action "$action"
197 ret=$?
198 if test $ret = 0; then
199 return 0
200 fi
201
202 git rebase--helper --prepare-branch "$switch_to" ${verbose:+--verbose}
203 init_basic_state
204
205 init_revisions_and_shortrevisions
206
207 git rebase--helper --make-script ${keep_empty:+--keep-empty} \
208 ${rebase_merges:+--rebase-merges} \
209 ${rebase_cousins:+--rebase-cousins} \
210 $revisions ${restrict_revision+^$restrict_revision} >"$todo" ||
211 die "$(gettext "Could not generate todo list")"
212
213 complete_action
214}