t3404: todo list with commented-out commands only aborts
[git] / git-rebase--interactive.sh
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.
14 todo="$state_dir"/git-rebase-todo
15
16 GIT_CHERRY_PICK_HELP="$resolvemsg"
17 export GIT_CHERRY_PICK_HELP
18
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
30
31 die_abort () {
32         apply_autostash
33         rm -rf "$state_dir"
34         die "$1"
35 }
36
37 has_action () {
38         test -n "$(git stripspace --strip-comments <"$1")"
39 }
40
41 git_sequence_editor () {
42         if test -z "$GIT_SEQUENCE_EDITOR"
43         then
44                 GIT_SEQUENCE_EDITOR="$(git config sequence.editor)"
45                 if [ -z "$GIT_SEQUENCE_EDITOR" ]
46                 then
47                         GIT_SEQUENCE_EDITOR="$(git var GIT_EDITOR)" || return $?
48                 fi
49         fi
50
51         eval "$GIT_SEQUENCE_EDITOR" '"$@"'
52 }
53
54 expand_todo_ids() {
55         git rebase--helper --expand-ids
56 }
57
58 collapse_todo_ids() {
59         git rebase--helper --shorten-ids
60 }
61
62 get_missing_commit_check_level () {
63         check_level=$(git config --get rebase.missingCommitsCheck)
64         check_level=${check_level:-ignore}
65         # Don't be case sensitive
66         printf '%s' "$check_level" | tr 'A-Z' 'a-z'
67 }
68
69 # Initiate an action. If the cannot be any
70 # further action it  may exec a command
71 # or exit and not return.
72 #
73 # TODO: Consider a cleaner return model so it
74 # never exits and always return 0 if process
75 # is complete.
76 #
77 # Parameter 1 is the action to initiate.
78 #
79 # Returns 0 if the action was able to complete
80 # and if 1 if further processing is required.
81 initiate_action () {
82         case "$1" in
83         continue)
84                 exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
85                      --continue
86                 ;;
87         skip)
88                 git rerere clear
89                 exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
90                      --continue
91                 ;;
92         edit-todo)
93                 exec git rebase--helper --edit-todo
94                 ;;
95         show-current-patch)
96                 exec git show REBASE_HEAD --
97                 ;;
98         *)
99                 return 1 # continue
100                 ;;
101         esac
102 }
103
104 init_basic_state () {
105         orig_head=$(git rev-parse --verify HEAD) || die "$(gettext "No HEAD?")"
106         mkdir -p "$state_dir" || die "$(eval_gettext "Could not create temporary \$state_dir")"
107         rm -f "$(git rev-parse --git-path REBASE_HEAD)"
108
109         : > "$state_dir"/interactive || die "$(gettext "Could not mark as interactive")"
110         write_basic_state
111 }
112
113 init_revisions_and_shortrevisions () {
114         shorthead=$(git rev-parse --short $orig_head)
115         shortonto=$(git rev-parse --short $onto)
116         if test -z "$rebase_root"
117                 # this is now equivalent to ! -z "$upstream"
118         then
119                 shortupstream=$(git rev-parse --short $upstream)
120                 revisions=$upstream...$orig_head
121                 shortrevisions=$shortupstream..$shorthead
122         else
123                 revisions=$onto...$orig_head
124                 shortrevisions=$shorthead
125                 test -z "$squash_onto" ||
126                 echo "$squash_onto" >"$state_dir"/squash-onto
127         fi
128 }
129
130 complete_action() {
131         test -s "$todo" || echo noop >> "$todo"
132         test -z "$autosquash" || git rebase--helper --rearrange-squash || exit
133         test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd"
134
135         todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
136         todocount=${todocount##* }
137
138 cat >>"$todo" <<EOF
139
140 $comment_char $(eval_ngettext \
141         "Rebase \$shortrevisions onto \$shortonto (\$todocount command)" \
142         "Rebase \$shortrevisions onto \$shortonto (\$todocount commands)" \
143         "$todocount")
144 EOF
145         git rebase--helper --append-todo-help ${keep_empty:+--keep-empty}
146
147         has_action "$todo" ||
148                 return 2
149
150         cp "$todo" "$todo".backup
151         collapse_todo_ids
152         git_sequence_editor "$todo" ||
153                 die_abort "$(gettext "Could not execute editor")"
154
155         has_action "$todo" ||
156                 return 2
157
158         git rebase--helper --check-todo-list || {
159                 ret=$?
160                 git rebase--helper --checkout-onto "$onto_name" "$onto" \
161                     "$orig_head" ${verbose:+--verbose}
162                 exit $ret
163         }
164
165         expand_todo_ids
166
167         test -n "$force_rebase" ||
168         onto="$(git rebase--helper --skip-unnecessary-picks)" ||
169         die "Could not skip unnecessary pick commands"
170
171         git rebase--helper --checkout-onto "$onto_name" "$onto" "$orig_head" \
172             ${verbose:+--verbose}
173         require_clean_work_tree "rebase"
174         exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
175              --continue
176 }
177
178 git_rebase__interactive () {
179         initiate_action "$action"
180         ret=$?
181         if test $ret = 0; then
182                 return 0
183         fi
184
185         git rebase--helper --prepare-branch "$switch_to" ${verbose:+--verbose}
186         init_basic_state
187
188         init_revisions_and_shortrevisions
189
190         git rebase--helper --make-script ${keep_empty:+--keep-empty} \
191                 ${rebase_merges:+--rebase-merges} \
192                 ${rebase_cousins:+--rebase-cousins} \
193                 $revisions ${restrict_revision+^$restrict_revision} >"$todo" ||
194         die "$(gettext "Could not generate todo list")"
195
196         complete_action
197 }