]>
Commit | Line | Data |
---|---|---|
11d62145 JN |
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. | |
1b1dce4b JS |
4 | # |
5 | # Copyright (c) 2006 Johannes E. Schindelin | |
1b1dce4b JS |
6 | # |
7 | # The original idea comes from Eric W. Biederman, in | |
5840eb9d | 8 | # https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/ |
572a7c52 | 9 | # |
80883bb3 MH |
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 | |
6bb4e485 | 13 | # file and written to the tail of $done. |
431b7e78 | 14 | todo="$state_dir"/git-rebase-todo |
80883bb3 | 15 | |
89c7ae9c | 16 | GIT_CHERRY_PICK_HELP="$resolvemsg" |
804c7174 WC |
17 | export GIT_CHERRY_PICK_HELP |
18 | ||
882cd237 JS |
19 | comment_char=$(git config --get core.commentchar 2>/dev/null) |
20 | case "$comment_char" in | |
21 | '' | auto) | |
22 | comment_char="#" | |
23 | ;; | |
24 | ?) | |
25 | ;; | |
26 | *) | |
27 | comment_char=$(echo "$comment_char" | cut -c1) | |
28 | ;; | |
29 | esac | |
180bad3d | 30 | |
6bb4e485 | 31 | orig_reflog_action="$GIT_REFLOG_ACTION" |
1b1dce4b JS |
32 | |
33 | comment_for_reflog () { | |
6bb4e485 | 34 | case "$orig_reflog_action" in |
1b1dce4b JS |
35 | ''|rebase*) |
36 | GIT_REFLOG_ACTION="rebase -i ($1)" | |
37 | export GIT_REFLOG_ACTION | |
376ccb8c | 38 | ;; |
1b1dce4b JS |
39 | esac |
40 | } | |
41 | ||
fcc5ef1c | 42 | append_todo_help () { |
b8fc9e43 | 43 | gettext " |
180bad3d | 44 | Commands: |
f431d73d SB |
45 | p, pick <commit> = use commit |
46 | r, reword <commit> = use commit, but edit the commit message | |
47 | e, edit <commit> = use commit, but stop for amending | |
48 | s, squash <commit> = use commit, but meld into previous commit | |
49 | f, fixup <commit> = like \"squash\", but discard this commit's log message | |
35d515b5 | 50 | x, exec <command> = run command (the rest of the line) using shell |
f431d73d | 51 | d, drop <commit> = remove commit |
9055e401 JS |
52 | l, label <label> = label current HEAD with a name |
53 | t, reset <label> = reset HEAD to a label | |
4c68e7dd JS |
54 | m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] |
55 | . create a merge commit using the original merge commit's | |
56 | . message (or the oneline, if no original merge commit was | |
57 | . specified). Use -c <commit> to reword the commit message. | |
180bad3d JK |
58 | |
59 | These lines can be re-ordered; they are executed from top to bottom. | |
b8fc9e43 | 60 | " | git stripspace --comment-lines >>"$todo" |
180bad3d | 61 | |
37079959 GR |
62 | if test $(get_missing_commit_check_level) = error |
63 | then | |
b8fc9e43 | 64 | gettext " |
37079959 | 65 | Do not remove any line. Use 'drop' explicitly to remove a commit. |
b8fc9e43 | 66 | " | git stripspace --comment-lines >>"$todo" |
37079959 | 67 | else |
b8fc9e43 | 68 | gettext " |
180bad3d | 69 | If you remove a line here THAT COMMIT WILL BE LOST. |
b8fc9e43 | 70 | " | git stripspace --comment-lines >>"$todo" |
37079959 | 71 | fi |
fcc5ef1c AW |
72 | } |
73 | ||
c54b7817 | 74 | die_abort () { |
33ba9c64 | 75 | apply_autostash |
431b7e78 | 76 | rm -rf "$state_dir" |
c54b7817 JS |
77 | die "$1" |
78 | } | |
79 | ||
376ccb8c | 80 | has_action () { |
180bad3d | 81 | test -n "$(git stripspace --strip-comments <"$1")" |
376ccb8c JS |
82 | } |
83 | ||
821881d8 PO |
84 | git_sequence_editor () { |
85 | if test -z "$GIT_SEQUENCE_EDITOR" | |
86 | then | |
87 | GIT_SEQUENCE_EDITOR="$(git config sequence.editor)" | |
88 | if [ -z "$GIT_SEQUENCE_EDITOR" ] | |
89 | then | |
90 | GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $? | |
91 | fi | |
92 | fi | |
93 | ||
94 | eval "$GIT_SEQUENCE_EDITOR" '"$@"' | |
95 | } | |
96 | ||
75c69766 | 97 | expand_todo_ids() { |
3546c8d9 | 98 | git rebase--helper --expand-ids |
75c69766 JH |
99 | } |
100 | ||
101 | collapse_todo_ids() { | |
3546c8d9 | 102 | git rebase--helper --shorten-ids |
f59baa50 NS |
103 | } |
104 | ||
37079959 GR |
105 | # Switch to the branch in $into and notify it in the reflog |
106 | checkout_onto () { | |
107 | GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" | |
9588c52b | 108 | output git checkout $onto || die_abort "$(gettext "could not detach HEAD")" |
37079959 GR |
109 | git update-ref ORIG_HEAD $orig_head |
110 | } | |
111 | ||
112 | get_missing_commit_check_level () { | |
113 | check_level=$(git config --get rebase.missingCommitsCheck) | |
114 | check_level=${check_level:-ignore} | |
115 | # Don't be case sensitive | |
116 | printf '%s' "$check_level" | tr 'A-Z' 'a-z' | |
117 | } | |
118 | ||
27c499bf WS |
119 | # Initiate an action. If the cannot be any |
120 | # further action it may exec a command | |
121 | # or exit and not return. | |
122 | # | |
123 | # TODO: Consider a cleaner return model so it | |
124 | # never exits and always return 0 if process | |
125 | # is complete. | |
126 | # | |
127 | # Parameter 1 is the action to initiate. | |
128 | # | |
129 | # Returns 0 if the action was able to complete | |
130 | # and if 1 if further processing is required. | |
131 | initiate_action () { | |
132 | case "$1" in | |
d48f97aa | 133 | continue) |
9384c0ca AG |
134 | exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ |
135 | --continue | |
d48f97aa WS |
136 | ;; |
137 | skip) | |
138 | git rerere clear | |
9384c0ca AG |
139 | exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ |
140 | --continue | |
d48f97aa WS |
141 | ;; |
142 | edit-todo) | |
143 | git stripspace --strip-comments <"$todo" >"$todo".new | |
144 | mv -f "$todo".new "$todo" | |
145 | collapse_todo_ids | |
146 | append_todo_help | |
147 | gettext " | |
180bad3d JK |
148 | You are editing the todo file of an ongoing interactive rebase. |
149 | To continue rebase after editing, run: | |
150 | git rebase --continue | |
151 | ||
b8fc9e43 | 152 | " | git stripspace --comment-lines >>"$todo" |
eb9a7cb4 | 153 | |
d48f97aa WS |
154 | git_sequence_editor "$todo" || |
155 | die "$(gettext "Could not execute editor")" | |
156 | expand_todo_ids | |
34262322 | 157 | |
d48f97aa WS |
158 | exit |
159 | ;; | |
160 | show-current-patch) | |
161 | exec git show REBASE_HEAD -- | |
162 | ;; | |
27c499bf WS |
163 | *) |
164 | return 1 # continue | |
165 | ;; | |
d48f97aa | 166 | esac |
27c499bf | 167 | } |
26cd160c | 168 | |
27c499bf | 169 | setup_reflog_action () { |
26cd160c | 170 | comment_for_reflog start |
34262322 | 171 | |
d48f97aa | 172 | if test ! -z "$switch_to" |
34262322 | 173 | then |
d48f97aa WS |
174 | GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" |
175 | output git checkout "$switch_to" -- || | |
176 | die "$(eval_gettext "Could not checkout \$switch_to")" | |
177 | ||
178 | comment_for_reflog start | |
34262322 | 179 | fi |
27c499bf | 180 | } |
62db5247 | 181 | |
27c499bf | 182 | init_basic_state () { |
d48f97aa WS |
183 | orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")" |
184 | mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")" | |
185 | rm -f "$(git rev-parse --git-path REBASE_HEAD)" | |
90e1818f | 186 | |
d48f97aa WS |
187 | : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")" |
188 | write_basic_state | |
27c499bf WS |
189 | } |
190 | ||
191 | init_revisions_and_shortrevisions () { | |
192 | shorthead=$(git rev-parse --short $orig_head) | |
193 | shortonto=$(git rev-parse --short $onto) | |
194 | if test -z "$rebase_root" | |
195 | # this is now equivalent to ! -z "$upstream" | |
196 | then | |
197 | shortupstream=$(git rev-parse --short $upstream) | |
198 | revisions=$upstream...$orig_head | |
199 | shortrevisions=$shortupstream..$shorthead | |
200 | else | |
201 | revisions=$onto...$orig_head | |
202 | shortrevisions=$shorthead | |
21d0764c JS |
203 | test -z "$squash_onto" || |
204 | echo "$squash_onto" >"$state_dir"/squash-onto | |
27c499bf WS |
205 | fi |
206 | } | |
207 | ||
208 | complete_action() { | |
209 | test -s "$todo" || echo noop >> "$todo" | |
210 | test -z "$autosquash" || git rebase--helper --rearrange-squash || exit | |
211 | test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd" | |
212 | ||
213 | todocount=$(git stripspace --strip-comments <"$todo" | wc -l) | |
214 | todocount=${todocount##* } | |
215 | ||
216 | cat >>"$todo" <<EOF | |
217 | ||
218 | $comment_char $(eval_ngettext \ | |
219 | "Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \ | |
220 | "Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \ | |
221 | "$todocount") | |
222 | EOF | |
223 | append_todo_help | |
224 | gettext " | |
225 | However, if you remove everything, the rebase will be aborted. | |
226 | ||
227 | " | git stripspace --comment-lines >>"$todo" | |
228 | ||
229 | if test -z "$keep_empty" | |
230 | then | |
231 | printf '%s\n' "$comment_char $(gettext "Note that empty commits are commented out")" >>"$todo" | |
232 | fi | |
233 | ||
234 | ||
235 | has_action "$todo" || | |
236 | return 2 | |
237 | ||
238 | cp "$todo" "$todo".backup | |
239 | collapse_todo_ids | |
240 | git_sequence_editor "$todo" || | |
241 | die_abort "$(gettext "Could not execute editor")" | |
242 | ||
243 | has_action "$todo" || | |
244 | return 2 | |
245 | ||
246 | git rebase--helper --check-todo-list || { | |
247 | ret=$? | |
248 | checkout_onto | |
249 | exit $ret | |
250 | } | |
251 | ||
252 | expand_todo_ids | |
253 | ||
9384c0ca | 254 | test -n "$force_rebase" || |
27c499bf WS |
255 | onto="$(git rebase--helper --skip-unnecessary-picks)" || |
256 | die "Could not skip unnecessary pick commands" | |
257 | ||
258 | checkout_onto | |
9384c0ca AG |
259 | require_clean_work_tree "rebase" |
260 | exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \ | |
261 | --continue | |
27c499bf WS |
262 | } |
263 | ||
264 | git_rebase__interactive () { | |
265 | initiate_action "$action" | |
266 | ret=$? | |
267 | if test $ret = 0; then | |
268 | return 0 | |
269 | fi | |
270 | ||
271 | setup_reflog_action | |
272 | init_basic_state | |
273 | ||
27c499bf WS |
274 | init_revisions_and_shortrevisions |
275 | ||
c04549b2 | 276 | git rebase--helper --make-script ${keep_empty:+--keep-empty} \ |
8f6aed71 | 277 | ${rebase_merges:+--rebase-merges} \ |
7543f6f4 | 278 | ${rebase_cousins:+--rebase-cousins} \ |
c04549b2 WS |
279 | $revisions ${restrict_revision+^$restrict_revision} >"$todo" || |
280 | die "$(gettext "Could not generate todo list")" | |
950b487c WS |
281 | |
282 | complete_action | |
283 | } |