git-commit-vandalism/builtin
Elijah Newren 9822175d2b Ensure index matches head before invoking merge machinery, round N
This is the bug that just won't die; there always seems to be another
form of it somewhere.  See the commit message of 55f39cf755 ("merge:
fix misleading pre-merge check documentation", 2018-06-30) for a more
detailed explanation), but in short:

<quick summary>

builtin/merge.c contains this important requirement for merge
strategies:

    ...the index must be in sync with the head commit.  The strategies are
    responsible to ensure this.

This condition is important to enforce because there are two likely
failure cases when the index isn't in sync with the head commit:

  * we silently throw away changes the user had staged before the merge

  * we accidentally (and silently) include changes in the merge that
    were not part of either of the branches/trees being merged

Discarding users' work and mis-merging are both bad outcomes, especially
when done silently, so naturally this rule was stated sternly -- but,
unfortunately totally ignored in practice unless and until actual bugs
were found.  But, fear not: the bugs from this were fixed in commit
  ee6566e8d7 ("[PATCH] Rewrite read-tree", 2005-09-05)
through a rewrite of read-tree (again, commit 55f39cf755 has a more
detailed explanation of how this affected merge).  And it was fixed
again in commit
  160252f816 ("git-merge-ours: make sure our index matches HEAD", 2005-11-03)
...and it was fixed again in commit
  3ec62ad9ff ("merge-octopus: abort if index does not match HEAD", 2016-04-09)
...and again in commit
  65170c07d4 ("merge-recursive: avoid incorporating uncommitted changes in a merge", 2017-12-21)
...and again in commit
  eddd1a411d ("merge-recursive: enforce rule that index matches head before merging", 2018-06-30)

...with multiple testcases added to the testsuite that could be
enumerated in even more commits.

Then, finally, in a patch in the same series as the last fix above, the
documentation about this requirement was fixed in commit 55f39cf755
("merge: fix misleading pre-merge check documentation", 2018-06-30), and
we all lived happily ever after...

</quick summary>

Unfortunately, "ever after" apparently denotes a limited time and it
expired today.  The merge-recursive rule to enforce that index matches
head was at the beginning of merge_trees() and would only trigger when
opt->call_depth was 0.  Since merge_recursive() doesn't call
merge_trees() until after returning from recursing, this meant that the
check wasn't triggered by merge_recursive() until it had first finished
all the intermediate merges to create virtual merge bases.  That is a
potentially HUGE amount of computation (and writing of intermediate
merge results into the .git/objects directory) before it errors out and
says, in effect, "Sorry, I can't do any merging because you have some
local changes that would be overwritten."

Trying to enforce that all of merge_trees(), merge_recursive(), and
merge_recursive_generic() checked the index == head condition earlier
resulted in a bunch of broken tests.  It turns out that
merge_recursive() has code to drop and reload the cache while recursing
to create intermediate virtual merge bases, but unfortunately that code
runs even when no recursion is necessary.  This unconditional dropping
and reloading of the cache masked a few bugs:

  * builtin/merge-recursive.c: didn't even bother loading the index.

  * builtin/stash.c: feels like a fake 'builtin' because it repeatedly
    invokes git subprocesses all over the place, mixed with other
    operations.  In particular, invoking "git reset" will reset the
    index on disk, but the parent process that invoked it won't
    automatically have its in-memory index updated.

  * t3030-merge-recursive.h: this test has always been broken in that it
    didn't make sure to make index match head before running.  But, it
    didn't care about the index or even the merge result, just the
    verbose output while running.  While commit eddd1a411d
    ("merge-recursive: enforce rule that index matches head before
    merging", 2018-06-30) should have uncovered this broken test, it
    used a test_must_fail wrapper around the merge-recursive call
    because it was known that the merge resulted in a rename/rename
    conflict.  Thus, that fix only made this test fail for a different
    reason, and since the index == head check didn't happen until after
    coming all the way back out of the recursion, the testcase had
    enough information to pass the one check that it did perform.

So, load the index in builtin/merge-recursive.c, reload the in-memory
index in builtin/stash.c, and modify the t3030 testcase to correctly
setup the index and make sure that the test fails in the expected way
(meaning it reports a rename/rename conflict).  This makes sure that
all callers actually make the index match head.  The next commit will
then enforce the condition that index matches head earlier so this
problem doesn't return in the future.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-19 10:08:03 -07:00
..
add.c add: error appropriately on repository with no commits 2019-04-10 12:52:50 +09:00
am.c merge-recursive: introduce an enum for detect_directory_renames values 2019-08-19 10:08:03 -07: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 bisect--helper: verify HEAD could be parsed before continuing 2019-05-28 10:51:01 -07:00
blame.c Merge branch 'br/blame-ignore' 2019-07-19 11:30:20 -07:00
branch.c Merge branch 'po/doc-branch' 2019-07-09 15:25:34 -07:00
bundle.c create_bundle(): drop unused "header" parameter 2019-01-24 12:35:44 -08:00
cat-file.c sha1-file.c: remove the_repo from read_object_with_reference() 2019-06-27 12:45:17 -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 cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08: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: provide better conflict hunk description with detached HEAD 2019-08-16 12:47:20 -07:00
clean.c clean: show an error message when the path is too long 2019-07-19 08:12:44 -07:00
clone.c Merge branch 'mt/dir-iterator-updates' 2019-07-25 13:59:22 -07:00
column.c builtin: consistently pass cmd_* prefix to parse_options 2019-05-13 14:22:53 +09:00
commit-graph.c commit-graph: verify chains with --shallow mode 2019-06-19 20:46:26 -07:00
commit-tree.c commit-tree: utilize parse-options api 2019-03-08 10:31:24 +09:00
commit.c Merge branch 'ra/cherry-pick-revert-skip' 2019-07-19 11:30:21 -07:00
config.c Merge branch 'jk/save-getenv-result' 2019-01-29 12:47:54 -08:00
count-objects.c
credential.c
describe.c hashmap: convert sha1hash() to oidhash() 2019-06-20 10:44:22 -07: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 Merge branch 'js/difftool-no-index' 2019-05-19 16:45:35 +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 object: convert lookup_object() to use object_id 2019-06-20 10:18:09 -07:00
fetch-pack.c fetch_pack(): drop unused parameters 2019-03-20 18:34:09 +09:00
fetch.c l10n: reformat some localized strings for v2.23.0 2019-08-06 12:43:43 -07:00
fmt-merge-msg.c
for-each-ref.c parse_opt_ref_sorting: always use with NONEG flag 2019-03-21 12:03:35 +09:00
fsck.c object: convert lookup_object() to use object_id 2019-06-20 10:18:09 -07:00
gc.c Merge branch 'ds/commit-graph-incremental' 2019-07-19 11:30:20 -07: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 sha1-file.c: remove the_repo from read_object_with_reference() 2019-06-27 12:45:17 -07: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 index-pack: prefetch missing REF_DELTA bases 2019-05-15 11:01:40 +09:00
init-db.c Merge branch 'nd/init-relative-template-fix' 2019-06-13 13:18:46 -07:00
interpret-trailers.c interpret-trailers: load default config 2019-06-19 07:12:49 -07:00
log.c log: really flip the --mailmap default 2019-08-02 09:55:03 -07:00
ls-files.c cleanup: fix possible overflow errors in binary search, part 2 2019-06-13 11:28:53 -07: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 tree-walk.c: remove the_repo from fill_tree_descriptor() 2019-06-27 12:45:17 -07:00
merge.c Merge branch 'ea/merge-code-cleanup' 2019-07-19 11:30:23 -07: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: prepare 'repack' subcommand 2019-06-11 10:34:40 -07:00
mv.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08:00
name-rev.c object: convert lookup_object() to use object_id 2019-06-20 10:18:09 -07:00
notes.c Merge branch 'nd/the-index' into md/list-objects-filter-by-depth 2019-01-15 15:38:29 -08:00
pack-objects.c repack: silence warnings when auto-enabled bitmaps cannot be built 2019-07-31 13:15:51 -07: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 format-patch: make --base patch-id output stable 2019-05-08 19:27:43 +09: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: add --[no-]show-forced-updates passthrough 2019-06-21 09:38:29 -07:00
push.c Merge branch 'nd/style-opening-brace' 2019-01-18 13:49:52 -08:00
range-diff.c builtin: consistently pass cmd_* prefix to parse_options 2019-05-13 14:22:53 +09:00
read-tree.c cmd_{read,write}_tree: rename "unused" variable that is used 2019-05-13 14:22:53 +09:00
rebase.c Merge branch 'js/rebase-cleanup' 2019-07-29 12:39:14 -07:00
receive-pack.c Merge branch 'jk/check-connected-with-alternates' 2019-07-19 11:30:21 -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 remove_all_fetch_refspecs(): drop unused "remote" parameter 2019-05-13 14:22:54 +09:00
repack.c repack: simplify handling of auto-bitmaps and .keep files 2019-07-31 13:26:25 -07:00
replace.c Merge branch 'cc/replace-graft-peel-tags' 2019-05-09 00:37:24 +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 'nd/tree-walk-with-repo' 2019-07-19 11:30:21 -07:00
rev-list.c rev-list: teach --no-object-names to enable piping 2019-06-20 13:13:04 -07:00
rev-parse.c cache.h: flip NO_THE_INDEX_COMPATIBILITY_MACROS switch 2019-01-24 11:55:06 -08: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' 2019-07-25 13:59:24 -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
show-ref.c Merge branch 'en/unicode-in-refnames' 2019-05-19 16:45:30 +09:00
stash.c Ensure index matches head before invoking merge machinery, round N 2019-08-19 10:08:03 -07:00
stripspace.c stripspace: allow -s/-c outside git repository 2018-12-26 15:41:47 -08:00
submodule--helper.c Merge branch 'ms/submodule-foreach-fix' 2019-07-09 15:25:46 -07: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 object: convert lookup_object() to use object_id 2019-06-20 10:18:09 -07:00
update-index.c tree-walk.c: remove the_repo from get_tree_entry() 2019-06-27 12:45:17 -07: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 'nd/worktree-name-sanitization' 2019-06-13 13:19:40 -07:00
write-tree.c cmd_{read,write}_tree: rename "unused" variable that is used 2019-05-13 14:22:53 +09:00