Skip to content

Commit 3a760ca

Browse files
committed
Merge branch 'gr/rebase-i-drop-warn'
Add "drop commit-object-name subject" command as another way to skip replaying of a commit in "rebase -i", and then punish those who do not use it (and instead just remove the lines) by throwing a warning. * gr/rebase-i-drop-warn: git rebase -i: add static check for commands and SHA-1 git rebase -i: warn about removed commits git-rebase -i: add command "drop" to remove a commit
2 parents 720e20e + 804098b commit 3a760ca

File tree

5 files changed

+338
-6
lines changed

5 files changed

+338
-6
lines changed

Documentation/config.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,17 @@ rebase.autoStash::
21802180
successful rebase might result in non-trivial conflicts.
21812181
Defaults to false.
21822182

2183+
rebase.missingCommitsCheck::
2184+
If set to "warn", git rebase -i will print a warning if some
2185+
commits are removed (e.g. a line was deleted), however the
2186+
rebase will still proceed. If set to "error", it will print
2187+
the previous warning and stop the rebase, 'git rebase
2188+
--edit-todo' can then be used to correct the error. If set to
2189+
"ignore", no checking is done.
2190+
To drop a commit without warning or error, use the `drop`
2191+
command in the todo-list.
2192+
Defaults to "ignore".
2193+
21832194
rebase.instructionFormat
21842195
A format string, as specified in linkgit:git-log[1], to be used for
21852196
the instruction list during an interactive rebase. The format will automatically

Documentation/git-rebase.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,12 @@ rebase.autoSquash::
213213
rebase.autoStash::
214214
If set to true enable '--autostash' option by default.
215215

216+
rebase.missingCommitsCheck::
217+
If set to "warn", print warnings about removed commits in
218+
interactive mode. If set to "error", print the warnings and
219+
stop the rebase. If set to "ignore", no checking is
220+
done. "ignore" by default.
221+
216222
rebase.instructionFormat::
217223
Custom commit list format to use during an '--interactive' rebase.
218224

@@ -521,6 +527,9 @@ rebasing.
521527
If you just want to edit the commit message for a commit, replace the
522528
command "pick" with the command "reword".
523529

530+
To drop a commit, replace the command "pick" with "drop", or just
531+
delete the matching line.
532+
524533
If you want to fold two or more commits into one, replace the command
525534
"pick" for the second and subsequent commits with "squash" or "fixup".
526535
If the commits had different authors, the folded commit will be

git-rebase--interactive.sh

Lines changed: 188 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,21 @@ Commands:
152152
s, squash = use commit, but meld into previous commit
153153
f, fixup = like "squash", but discard this commit's log message
154154
x, exec = run command (the rest of the line) using shell
155+
d, drop = remove commit
155156
156157
These lines can be re-ordered; they are executed from top to bottom.
157158
159+
EOF
160+
if test $(get_missing_commit_check_level) = error
161+
then
162+
git stripspace --comment-lines >>"$todo" <<\EOF
163+
Do not remove any line. Use 'drop' explicitly to remove a commit.
164+
EOF
165+
else
166+
git stripspace --comment-lines >>"$todo" <<\EOF
158167
If you remove a line here THAT COMMIT WILL BE LOST.
159168
EOF
169+
fi
160170
}
161171

162172
make_patch () {
@@ -505,7 +515,7 @@ do_next () {
505515
rm -f "$msg" "$author_script" "$amend" "$state_dir"/stopped-sha || exit
506516
read -r command sha1 rest < "$todo"
507517
case "$command" in
508-
"$comment_char"*|''|noop)
518+
"$comment_char"*|''|noop|drop|d)
509519
mark_action_done
510520
;;
511521
pick|p)
@@ -844,6 +854,180 @@ add_exec_commands () {
844854
mv "$1.new" "$1"
845855
}
846856

857+
# Check if the SHA-1 passed as an argument is a
858+
# correct one, if not then print $2 in "$todo".badsha
859+
# $1: the SHA-1 to test
860+
# $2: the line to display if incorrect SHA-1
861+
check_commit_sha () {
862+
badsha=0
863+
if test -z $1
864+
then
865+
badsha=1
866+
else
867+
sha1_verif="$(git rev-parse --verify --quiet $1^{commit})"
868+
if test -z $sha1_verif
869+
then
870+
badsha=1
871+
fi
872+
fi
873+
874+
if test $badsha -ne 0
875+
then
876+
warn "Warning: the SHA-1 is missing or isn't" \
877+
"a commit in the following line:"
878+
warn " - $2"
879+
warn
880+
fi
881+
882+
return $badsha
883+
}
884+
885+
# prints the bad commits and bad commands
886+
# from the todolist in stdin
887+
check_bad_cmd_and_sha () {
888+
retval=0
889+
git stripspace --strip-comments |
890+
(
891+
while read -r line
892+
do
893+
IFS=' '
894+
set -- $line
895+
command=$1
896+
sha1=$2
897+
898+
case $command in
899+
''|noop|x|"exec")
900+
# Doesn't expect a SHA-1
901+
;;
902+
pick|p|drop|d|reword|r|edit|e|squash|s|fixup|f)
903+
if ! check_commit_sha $sha1 "$line"
904+
then
905+
retval=1
906+
fi
907+
;;
908+
*)
909+
warn "Warning: the command isn't recognized" \
910+
"in the following line:"
911+
warn " - $line"
912+
warn
913+
retval=1
914+
;;
915+
esac
916+
done
917+
918+
return $retval
919+
)
920+
}
921+
922+
# Print the list of the SHA-1 of the commits
923+
# from stdin to stdout
924+
todo_list_to_sha_list () {
925+
git stripspace --strip-comments |
926+
while read -r command sha1 rest
927+
do
928+
case $command in
929+
"$comment_char"*|''|noop|x|"exec")
930+
;;
931+
*)
932+
long_sha=$(git rev-list --no-walk "$sha1" 2>/dev/null)
933+
printf "%s\n" "$long_sha"
934+
;;
935+
esac
936+
done
937+
}
938+
939+
# Use warn for each line in stdin
940+
warn_lines () {
941+
while read -r line
942+
do
943+
warn " - $line"
944+
done
945+
}
946+
947+
# Switch to the branch in $into and notify it in the reflog
948+
checkout_onto () {
949+
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
950+
output git checkout $onto || die_abort "could not detach HEAD"
951+
git update-ref ORIG_HEAD $orig_head
952+
}
953+
954+
get_missing_commit_check_level () {
955+
check_level=$(git config --get rebase.missingCommitsCheck)
956+
check_level=${check_level:-ignore}
957+
# Don't be case sensitive
958+
printf '%s' "$check_level" | tr 'A-Z' 'a-z'
959+
}
960+
961+
# Check if the user dropped some commits by mistake
962+
# Behaviour determined by rebase.missingCommitsCheck.
963+
# Check if there is an unrecognized command or a
964+
# bad SHA-1 in a command.
965+
check_todo_list () {
966+
raise_error=f
967+
968+
check_level=$(get_missing_commit_check_level)
969+
970+
case "$check_level" in
971+
warn|error)
972+
# Get the SHA-1 of the commits
973+
todo_list_to_sha_list <"$todo".backup >"$todo".oldsha1
974+
todo_list_to_sha_list <"$todo" >"$todo".newsha1
975+
976+
# Sort the SHA-1 and compare them
977+
sort -u "$todo".oldsha1 >"$todo".oldsha1+
978+
mv "$todo".oldsha1+ "$todo".oldsha1
979+
sort -u "$todo".newsha1 >"$todo".newsha1+
980+
mv "$todo".newsha1+ "$todo".newsha1
981+
comm -2 -3 "$todo".oldsha1 "$todo".newsha1 >"$todo".miss
982+
983+
# Warn about missing commits
984+
if test -s "$todo".miss
985+
then
986+
test "$check_level" = error && raise_error=t
987+
988+
warn "Warning: some commits may have been dropped" \
989+
"accidentally."
990+
warn "Dropped commits (newer to older):"
991+
992+
# Make the list user-friendly and display
993+
opt="--no-walk=sorted --format=oneline --abbrev-commit --stdin"
994+
git rev-list $opt <"$todo".miss | warn_lines
995+
996+
warn "To avoid this message, use \"drop\" to" \
997+
"explicitly remove a commit."
998+
warn
999+
warn "Use 'git config rebase.missingCommitsCheck' to change" \
1000+
"the level of warnings."
1001+
warn "The possible behaviours are: ignore, warn, error."
1002+
warn
1003+
fi
1004+
;;
1005+
ignore)
1006+
;;
1007+
*)
1008+
warn "Unrecognized setting $check_level for option" \
1009+
"rebase.missingCommitsCheck. Ignoring."
1010+
;;
1011+
esac
1012+
1013+
if ! check_bad_cmd_and_sha <"$todo"
1014+
then
1015+
raise_error=t
1016+
fi
1017+
1018+
if test $raise_error = t
1019+
then
1020+
# Checkout before the first commit of the
1021+
# rebase: this way git rebase --continue
1022+
# will work correctly as it expects HEAD to be
1023+
# placed before the commit of the next action
1024+
checkout_onto
1025+
1026+
warn "You can fix this with 'git rebase --edit-todo'."
1027+
die "Or you can abort the rebase with 'git rebase --abort'."
1028+
fi
1029+
}
1030+
8471031
# The whole contents of this file is run by dot-sourcing it from
8481032
# inside a shell function. It used to be that "return"s we see
8491033
# below were not inside any function, and expected to return
@@ -1094,13 +1278,13 @@ git_sequence_editor "$todo" ||
10941278
has_action "$todo" ||
10951279
return 2
10961280

1281+
check_todo_list
1282+
10971283
expand_todo_ids
10981284

10991285
test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
11001286

1101-
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
1102-
output git checkout $onto || die_abort "could not detach HEAD"
1103-
git update-ref ORIG_HEAD $orig_head
1287+
checkout_onto
11041288
do_rest
11051289

11061290
}

t/lib-rebase.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# specified line.
1515
#
1616
# "<cmd> <lineno>" -- add a line with the specified command
17-
# ("squash", "fixup", "edit", or "reword") and the SHA1 taken
17+
# ("squash", "fixup", "edit", "reword" or "drop") and the SHA1 taken
1818
# from the specified line.
1919
#
2020
# "exec_cmd_with_args" -- add an "exec cmd with args" line.
@@ -46,14 +46,19 @@ set_fake_editor () {
4646
action=pick
4747
for line in $FAKE_LINES; do
4848
case $line in
49-
squash|fixup|edit|reword)
49+
squash|fixup|edit|reword|drop)
5050
action="$line";;
5151
exec*)
5252
echo "$line" | sed 's/_/ /g' >> "$1";;
5353
"#")
5454
echo '# comment' >> "$1";;
5555
">")
5656
echo >> "$1";;
57+
bad)
58+
action="badcmd";;
59+
fakesha)
60+
echo "$action XXXXXXX False commit" >> "$1"
61+
action=pick;;
5762
*)
5863
sed -n "${line}s/^pick/$action/p" < "$1".tmp >> "$1"
5964
action=pick;;

0 commit comments

Comments
 (0)