git-commit-vandalism/builtin
Elijah Newren e98c4269c8 rebase (interactive-backend): fix handling of commits that become empty
As established in the previous commit and commit b00bf1c9a8
(git-rebase: make --allow-empty-message the default, 2018-06-27), the
behavior for rebase with different backends in various edge or corner
cases is often more happenstance than design.  This commit addresses
another such corner case: commits which "become empty".

A careful reader may note that there are two types of commits which would
become empty due to a rebase:

  * [clean cherry-pick] Commits which are clean cherry-picks of upstream
    commits, as determined by `git log --cherry-mark ...`.  Re-applying
    these commits would result in an empty set of changes and a
    duplicative commit message; i.e. these are commits that have
    "already been applied" upstream.

  * [become empty] Commits which are not empty to start, are not clean
    cherry-picks of upstream commits, but which still become empty after
    being rebased.  This happens e.g. when a commit has changes which
    are a strict subset of the changes in an upstream commit, or when
    the changes of a commit can be found spread across or among several
    upstream commits.

Clearly, in both cases the changes in the commit in question are found
upstream already, but the commit message may not be in the latter case.

When cherry-mark can determine a commit is already upstream, then
because of how cherry-mark works this means the upstream commit message
was about the *exact* same set of changes.  Thus, the commit messages
can be assumed to be fully interchangeable (and are in fact likely to be
completely identical).  As such, the clean cherry-pick case represents a
case when there is no information to be gained by keeping the extra
commit around.  All rebase types have always dropped these commits, and
no one to my knowledge has ever requested that we do otherwise.

For many of the become empty cases (and likely even most), we will also
be able to drop the commit without loss of information -- but this isn't
quite always the case.  Since these commits represent cases that were
not clean cherry-picks, there is no upstream commit message explaining
the same set of changes.  Projects with good commit message hygiene will
likely have the explanation from our commit message contained within or
spread among the relevant upstream commits, but not all projects run
that way.  As such, the commit message of the commit being rebased may
have reasoning that suggests additional changes that should be made to
adapt to the new base, or it may have information that someone wants to
add as a note to another commit, or perhaps someone even wants to create
an empty commit with the commit message as-is.

Junio commented on the "become-empty" types of commits as follows[1]:

    WRT a change that ends up being empty (as opposed to a change that
    is empty from the beginning), I'd think that the current behaviour
    is desireable one.  "am" based rebase is solely to transplant an
    existing history and want to stop much less than "interactive" one
    whose purpose is to polish a series before making it publishable,
    and asking for confirmation ("this has become empty--do you want to
    drop it?") is more appropriate from the workflow point of view.

[1] https://lore.kernel.org/git/xmqqfu1fswdh.fsf@gitster-ct.c.googlers.com/

I would simply add that his arguments for "am"-based rebases actually
apply to all non-explicitly-interactive rebases.  Also, since we are
stating that different cases should have different defaults, it may be
worth providing a flag to allow users to select which behavior they want
for these commits.

Introduce a new command line flag for selecting the desired behavior:
    --empty={drop,keep,ask}
with the definitions:
    drop: drop commits which become empty
    keep: keep commits which become empty
    ask:  provide the user a chance to interact and pick what to do with
          commits which become empty on a case-by-case basis

In line with Junio's suggestion, if the --empty flag is not specified,
pick defaults as follows:
    explicitly interactive: ask
    otherwise: drop

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-16 15:40:42 -08:00
..
add.c Merge branch 'js/add-p-in-c' 2019-12-25 11:22:01 -08:00
am.c Merge branch 'en/merge-recursive-cleanup' 2019-10-15 13:47:59 +09:00
annotate.c
apply.c
archive.c pack-protocol.txt: accept error packets in any context 2019-01-02 13:05:30 -08:00
bisect--helper.c Merge branch 'mr/bisect-save-pointer-to-const-string' 2019-12-25 11:22:01 -08:00
blame.c Merge branch 'sg/blame-indent-heuristics-is-now-the-default' 2019-12-01 09:04:30 -08:00
branch.c l10n: minor case fix in 'git branch' '--unset-upstream' description 2019-12-09 12:30:55 -08:00
bundle.c bundle-verify: add --quiet 2019-11-11 11:46:29 +09:00
cat-file.c Merge branch 'cc/multi-promisor' 2019-09-18 11:50:09 -07:00
check-attr.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08:00
check-ignore.c treewide: rename 'exclude' methods to 'pattern' 2019-09-05 14:05:12 -07:00
check-mailmap.c
check-ref-format.c
checkout-index.c Merge branch 'nd/the-index-final' 2019-02-06 22:05:23 -08:00
checkout.c checkout, restore: support the --pathspec-from-file option 2019-12-04 10:10:37 -08:00
clean.c Merge branch 'en/clean-nested-with-ignored' 2019-10-11 14:24:46 +09:00
clone.c Merge branch 'ds/sparse-cone' 2019-12-25 11:21:58 -08:00
column.c builtin: consistently pass cmd_* prefix to parse_options 2019-05-13 14:22:53 +09:00
commit-graph.c test-tool: use 'read-graph' helper 2019-11-13 11:14:16 +09:00
commit-tree.c commit-tree: utilize parse-options api 2019-03-08 10:31:24 +09:00
commit.c Merge branch 'am/pathspec-from-file' 2019-12-25 11:21:57 -08:00
config.c Merge branch 'jk/save-getenv-result' 2019-01-29 12:47:54 -08:00
count-objects.c
credential.c
describe.c Merge branch 'ew/hashmap' 2019-10-15 13:48:02 +09:00
diff-files.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08:00
diff-index.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08:00
diff-tree.c Merge branch 'en/combined-all-paths' 2019-03-07 09:59:54 +09:00
diff.c Merge branch 'nd/diff-parseopt-4' 2019-04-25 16:41:12 +09:00
difftool.c hashmap: remove type arg from hashmap_{get,put,remove}_entry 2019-10-07 10:20:12 +09:00
env--helper.c env--helper: mark a file-local symbol as static 2019-07-11 14:31:04 -07:00
fast-export.c Merge branch 'ew/hashmap' 2019-10-15 13:48:02 +09:00
fetch-pack.c fetch_pack(): drop unused parameters 2019-03-20 18:34:09 +09:00
fetch.c Merge branch 'ds/commit-graph-set-size-mult' 2020-01-06 14:17:51 -08:00
fmt-merge-msg.c Merge branch 'hi/gpg-use-check-signature' 2019-12-10 13:11:45 -08:00
for-each-ref.c parse_opt_ref_sorting: always use with NONEG flag 2019-03-21 12:03:35 +09:00
fsck.c fsck: only provide oid/type in fsck_error callback 2019-10-28 14:05:18 +09:00
gc.c Fix spelling errors in code comments 2019-11-10 16:00:54 +09:00
get-tar-commit-id.c builtin/get-tar-commit-id: make hash size independent 2019-04-01 11:57:39 +09:00
grep.c Merge branch 'cb/pcre2-chartables-leakfix' 2019-10-23 14:43:11 +09:00
hash-object.c builtin: consistently pass cmd_* prefix to parse_options 2019-05-13 14:22:53 +09:00
help.c completion: add more parameter value completion 2019-02-20 12:31:56 -08:00
index-pack.c Merge branch 'bc/object-id-part17' 2019-10-11 14:24:46 +09:00
init-db.c Merge branch 'nd/init-relative-template-fix' into maint 2019-07-25 14:27:06 -07:00
interpret-trailers.c interpret-trailers: load default config 2019-06-19 07:12:49 -07:00
log.c Merge branch 'dl/format-patch-notes-config-fixup' 2019-12-25 11:21:58 -08:00
ls-files.c Merge branch 'ds/include-exclude' 2019-09-30 13:19:32 +09:00
ls-remote.c parse_opt_ref_sorting: always use with NONEG flag 2019-03-21 12:03:35 +09:00
ls-tree.c Merge branch 'nd/attr-pathspec-in-tree-walk' 2019-01-14 15:29:28 -08:00
mailinfo.c
mailsplit.c
merge-base.c
merge-file.c
merge-index.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08:00
merge-ours.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08:00
merge-recursive.c Ensure index matches head before invoking merge machinery, round N 2019-08-19 10:08:03 -07:00
merge-tree.c Merge branch 'jk/tree-walk-overflow' 2019-08-22 12:34:10 -07:00
merge.c Merge branch 'tg/stash-refresh-index' 2019-10-07 11:32:53 +09:00
mktag.c
mktree.c mktree: drop unused length parameter 2019-05-13 14:22:54 +09:00
multi-pack-index.c multi-pack-index: add [--[no-]progress] option. 2019-10-23 12:05:06 +09:00
mv.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08:00
name-rev.c Merge branch 'sg/name-rev-wo-recursion' 2019-12-25 11:21:58 -08:00
notes.c notes: fix minimum number of parameters to "copy" subcommand 2019-10-18 09:43:10 +09:00
pack-objects.c Fix spelling errors in code comments 2019-11-10 16:00:54 +09:00
pack-redundant.c object-store: rename and expand packed_git's sha1 member 2019-04-01 11:57:38 +09:00
pack-refs.c Honor core.precomposeUnicode in more places 2019-04-26 10:54:03 +09:00
patch-id.c patch-id: use oid_to_hex() to print multiple object IDs 2019-12-09 12:26:40 -08:00
prune-packed.c Merge branch 'rj/prune-packed-excess-args' 2019-03-07 09:59:55 +09:00
prune.c object: convert lookup_object() to use object_id 2019-06-20 10:18:09 -07:00
pull.c pull, fetch: add --set-upstream option 2019-08-19 13:05:58 -07:00
push.c push: use skip_prefix() instead of starts_with() 2019-11-27 11:18:39 +09:00
range-diff.c range-diff: clear other_arg at end of function 2019-12-06 12:36:53 -08:00
read-tree.c sparse-checkout: update working directory in-process 2019-11-22 16:11:44 +09:00
rebase.c rebase (interactive-backend): fix handling of commits that become empty 2020-02-16 15:40:42 -08:00
receive-pack.c builtin/receive-pack: replace sha1_to_hex 2019-08-19 15:04:59 -07:00
reflog.c Merge branch 'jk/loose-object-cache-oid' 2019-02-06 22:05:27 -08:00
remote-ext.c
remote-fd.c
remote.c remote: pass NULL to read_ref_full() because object ID is not needed 2019-12-11 13:48:46 -08:00
repack.c Merge branch 'wb/midx-progress' 2019-11-10 18:02:14 +09:00
replace.c Merge branch 'bc/object-id-part17' 2019-10-11 14:24:46 +09:00
rerere.c Merge branch 'nd/the-index' into md/list-objects-filter-by-depth 2019-01-15 15:38:29 -08:00
reset.c Merge branch 'am/pathspec-from-file' 2019-12-10 13:11:41 -08:00
rev-list.c Merge branch 'rs/dedup-includes' 2019-10-11 14:24:48 +09:00
rev-parse.c rev-parse: make --show-toplevel without a worktree an error 2019-11-20 10:19:58 +09:00
revert.c Merge branch 'ra/cherry-pick-revert-skip' 2019-07-19 11:30:21 -07:00
rm.c Merge branch 'jc/denoise-rm-to-resolve' into maint 2019-07-29 12:38:17 -07:00
send-pack.c pack-protocol.txt: accept error packets in any context 2019-01-02 13:05:30 -08:00
shortlog.c Merge branch 'nd/show-gitcomp-compilation-fix' into maint 2018-12-15 12:24:33 +09:00
show-branch.c show-branch: drop unused parameter from show_independent() 2019-05-13 14:22:54 +09:00
show-index.c builtin/show-index: replace sha1_to_hex 2019-08-19 15:04:59 -07:00
show-ref.c Merge branch 'en/unicode-in-refnames' 2019-05-19 16:45:30 +09:00
sparse-checkout.c sparse-checkout: list directories in cone mode 2019-12-30 09:07:18 -08:00
stash.c Merge branch 'tg/stash-refresh-index' 2019-12-01 09:04:37 -08:00
stripspace.c stripspace: allow -s/-c outside git repository 2018-12-26 15:41:47 -08:00
submodule--helper.c Merge branch 'jt/clone-recursesub-ref-advise' 2019-12-10 13:11:43 -08:00
symbolic-ref.c
tag.c tag: add tag.gpgSign config option to force all tags be GPG-signed 2019-06-05 14:39:28 -07:00
unpack-file.c
unpack-objects.c builtin/unpack-objects.c: show throughput progress 2019-11-20 10:30:18 +09:00
update-index.c Merge branch 'js/update-index-ignore-removal-for-skip-worktree' 2019-11-10 18:02:16 +09:00
update-ref.c
update-server-info.c
upload-archive.c
upload-pack.c builtin: consistently pass cmd_* prefix to parse_options 2019-05-13 14:22:53 +09:00
var.c
verify-commit.c Merge branch 'jk/no-system-includes-in-dot-c' 2019-07-31 14:38:56 -07:00
verify-pack.c
verify-tag.c verify-tag: drop signal.h include 2019-06-19 08:19:21 -07:00
worktree.c Merge branch 'pb/no-recursive-reset-hard-in-worktree-add' 2019-12-01 09:04:31 -08:00
write-tree.c cmd_{read,write}_tree: rename "unused" variable that is used 2019-05-13 14:22:53 +09:00