git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [RFC/PATCH 05/18] Add testcase for --index-only merges needing the recursive strategy

From
Junio C Hamano <gitster@pobox.com>
Date
Apr 8, 2016, 20:14 UTC
Message-ID
<xmqqtwjbvox1.fsf@gitster.mtv.corp.google.com>
In-Reply-To
<xmqqzit3vqma.fsf@gitster.mtv.corp.google.com>
Junio C Hamano <gitster@pobox.com> writes:
Show 34 quoted lines
> Elijah Newren <newren@gmail.com> writes:
>
>> +test_expect_failure '--index-only with rename/modify works in non-bare-clone' '
>> +	git checkout B^0 &&
>> +
>> +	git merge --index-only -s recursive C^0 &&
>> +
>> +	echo "Making sure the working copy was not updated" &&
>> +	test ! -f b &&
>> +	test -f a &&
>> +	test $(git rev-parse B:a) = $(git hash-object a) &&
>> +
>> +	echo "Making sure the index was updated" &&
>> +	test 1 -eq $(git ls-files -s | wc -l) &&
>> +	test $(git rev-parse B:a) = $(git rev-parse :b)
>
> The most crucial test that is missing (hence prevents reviewers from
> judging if --index-only is a good idea at all) is the test on HEAD.
> Does it record a merge between B and C and move HEAD there, i.e.
>
> 	test $(git rev-parse HEAD^1) = $(git rev-parse B) &&
> 	test $(git rev-parse HEAD^2) = $(git rev-parse C)
>
> or does it make a merge but does not advance HEAD, i.e.
>
> 	test $(git rev-parse HEAD) = $(git rev-parse B)
>
> I fear that it may give a great headache to end users if you move
> HEAD in a repository with a working tree to point at the merge
> result--how do they reconcile the difference between the working
> tree (which was based on B) and the index and HEAD (which is now
> based on the result of the merge)?  The next "git commit -a" would
> appear that it would revert the changes brought in by this merge,
> wouldn't it?

And if the expectation that is not spelled out by this new test is that the merge does not advance HEAD, the command does not make much sense either, because there is no way for you to find out the merge result.

Let's step back a bit. This may or may not be what you are aiming at, but I think I can buy a series whose title is "merge without working tree" if the big-picture objective of the topic were to support this workflow:

    0. I am working on my own branch that is not 'master'.
    1. I see somebody else worked on and finished a good topic
       'en/topic'.  My work is not yet in a good shape, and I do not
       want to switch to 'master' only to merge 'en/topic' to
       'master', but 'en/topic' is so good and my urge to merge it
       to 'master' is strong.
    2. Hence I want a way to merge 'en/topic' to 'master' and
       advance the tip of 'master', without using my working tree
       (or the index or my HEAD for that matter), without disrupting
       my current state.
    3. For simplicity, I can live with it if the early version of
       that "merge en/topic to master" operation is incapable of
       handling conflicts.  Then I'd say "huh, I'd need to manually
       inspect the merge result so I'll do that later" and continue
       what I was doing, or I'd say "OK, let's really have a look",
       save what I was doing in a temporary commit and switch to
       'master' to do the usual "git merge en/topic".
    4. But it would be even better if I could give a temporary
       directory to it as a scratch-pad area, and if I was asked to
       help it resolving conflicts by editing conflicted files in
       the scratch-pad area.

In any case, what is in my current index (or HEAD) is no use for merging en/topic into master, so the command should not care or touch not just what is in my working tree (which gives the operation the same requirement as your series, i.e. "do not touch or require a working tree") but also what is in my index or where my HEAD is.

The low-level ingredients that support "git merge", namely, "git
read-tree -m COMMON OURS THEIRS", actually has a support to make
this kind of "merge without fully populated working tree" possible,
by considering the lack of working tree file an equivalent to having
an unmodified working tree file (I suspect that merge-recursive is
probably broken with this regard, as it was mostly done without
knowing that we anticipated such a need in early life of Git long
before merge-recursive was invented).  We can give an empty
"scratch-pad area" as a temporary working tree, create a temporary
index out of 'master' (in the above example), perform the usual
three-way merge with
    
    GIT_DIR=... point at the real thing ...
    GIT_INDEX_FILE=... point at a temporary file ...
    export GIT_DIR GIT_INDEX_FILE
    rm -fr /var/tmp/scratchpad && mkdir /var/tmp/scratchpad
    cd /var/tmp/scratchpad
    base=$(git merge-base master en/topic)
    git read-tree -m $base master en/topic

and run "git merge -s resolve" to drive "git merge-one-file". This would populate /var/tmp/scratchpad with files that are involved in the merge, without wasting diskspace for files in 'master' that does not change, and you can edit them, "git add" these paths, and then do a "git write-tree" to create the tree that represents the merge result. You obviously need to avoid touching HEAD when recording that tree as a merge commit and advance the tip of 'master' (as HEAD is still on my own unrelated branch), but that part is trivial (i.e. we have written "git commit" at least twice).

Of course, if you are not going to support merges that need manual conflict resolution, you do not need the scratchpad and the end user experience would be simpler (i.e. you do not have to think about how they resolve, record the resolution, etc.) And your "merge only in index" topic would fit well in that picture.

But then, using the current index and the HEAD as the place to merge into is still wrong. I think this is better done as a separate command, not "git merge" but perhaps something like

    $ git merge-to en/topic master

or something. "git merge --into=master en/topic" is also a possibility.

But as I said in the early part of this message, this may or may not be what you are aiming at. The above is the most sensible tangent that I can think of that may be related to "merge only in index".

Previous: Junio C HamanoNext: Elijah Newren
Message 10 of 30 in “Add --index-only option to git merge”
  1. 00/18 Add --index-only option to git mergeElijah Newren, Apr 8, 2016
  2. 01/18 Remove duplicate codeElijah Newren, Apr 8, 2016
  3. Junio C HamanoApr 8, 2016
  4. 02/18 Avoid checking working copy when creating a virtual merge baseElijah Newren, Apr 8, 2016
  5. 03/18 Document weird bug in octopus merges via testcasesElijah Newren, Apr 8, 2016
  6. 04/18 merge-octopus: Abort if index not cleanElijah Newren, Apr 8, 2016
  7. Junio C HamanoApr 8, 2016
  8. 05/18 Add testcase for --index-only merges needing the recursive strategyElijah Newren, Apr 8, 2016
  9. Junio C HamanoApr 8, 2016
  10. Junio C HamanoApr 8, 2016
  11. 06/18 Add testcase for --index-only merges needing an ff updateElijah Newren, Apr 8, 2016
  12. 07/18 Add testcase for --index-only merges with the resolve strategyElijah Newren, Apr 8, 2016
  13. 08/18 Add testcase for --index-only merges with the octopus strategyElijah Newren, Apr 8, 2016
  14. 09/18 Add testcase for --index-only merges with the ours strategyElijah Newren, Apr 8, 2016
  15. 10/18 Add testcase for --index-only merges with the subtree strategyElijah Newren, Apr 8, 2016
  16. 11/18 merge: Add a new --index-only option, not yet implementedElijah Newren, Apr 8, 2016
  17. Junio C HamanoApr 8, 2016
  18. 12/18 Add --index-only support for recursive mergesElijah Newren, Apr 8, 2016
  19. 13/18 Add --index-only support with read_tree_trivial merges, kind ofElijah Newren, Apr 8, 2016
  20. 14/18 Add --index-only support for ff_only mergesElijah Newren, Apr 8, 2016
  21. 15/18 merge: Pass --index-only along to external merge strategy programsElijah Newren, Apr 8, 2016
  22. 16/18 git-merge-one-file.sh: support --index-only optionElijah Newren, Apr 8, 2016
  23. 17/18 git-merge-resolve.sh: support --index-only optionElijah Newren, Apr 8, 2016
  24. 18/18 git-merge-octopus.sh: support --index-only optionElijah Newren, Apr 8, 2016
  25. Michael J GruberApr 8, 2016
  26. Elijah NewrenApr 9, 2016
  27. Junio C HamanoApr 8, 2016
  28. Elijah NewrenApr 9, 2016
  29. Junio C HamanoApr 9, 2016
  30. Elijah NewrenApr 10, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.