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

Re: Working copy as a pseudo-head

From
Junio C Hamano <junkio@cox.net>
Date
Nov 27, 2006, 09:20 UTC
Message-ID
<7vlklxi6u0.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<456A9F93.1060801@midwinter.com>
Steven Grimm <koreth@midwinter.com> writes:
> Comments? Is this just nuts?

It is not "nuts", but we do not do it currently because it is a bit too combersome to make it recoverable when things go wrong while keeping the cost of making the necessary back-up for recovery low. When switching branches with local changes, "git-checkout -m" needs to deal with a similar issue, but that case only deal with two trees and a working tree. To do this for three-way merge, the conflicts you need to deal with become more complex.

What needs to be done is very simple and straightforward. You first stash away the working tree state in a "virtual" tree, then perform the usual 3-way merge using the common ancestor, your HEAD and the other head, and come up with the merge result without any of your changes. Then you run another three-way merge between the merge result and your previous working tree state using the HEAD before the merge as the common ancestor.

       o---o---X (other head)
      /
  ---o---o---H (your head)
              \  
               W (your working tree)
==>
       o---o---X (other head)
      /         \
  ---o---o---H---M (merge between the base trees)
              \  
               W (your working tree)
==>
       o---o---X (other head)
      /         \
  ---o---o---H---M (merge between the base trees)
              \   \   
               W---W'(your working tree, updated for the merge result)

The design goal here is that you do not want to get any of your local changes (i.e. "diff H W") to be included when you record the result of the base merge 'M', and you would want the diff between H and W to be forward-ported to the diff between M and W'.

The first goal is already quite cumbersome when the merge between X and H involve conflicing merges. We use the working tree to perform the file level merge (i.e. you edit them with your favorite editor, and tell git when you are done), so while that is happening we temporarily need to remove what was between H and W. If the merge is too complex and the user decides to revert the whole thing, we would need to rewind the index and working tree to the state at W (that means we would at least need to stash the diff between H and index, and index and working tree before starting the merge).

After the base merge is done, we would need to update the HEAD to point at M. Then we would perform the second three-way merge between M and W using the original HEAD as their common ancestor to come up with W'. When this conflicts, there is no easy way for the user to recover, other than going back to the original state (that is, HEAD points at H and working tree is W), even after having spent effort to merge between X and H to produce M.

In common usage (call that "best current practice" if you may), you do not have local changes in the working tree that would conflict with the merge, so the current behaviour feels cumbersome only when the safety valve kicks in. After seeing it fail due to the safety valve, you can do the same as what the above pictures depict using existing tools.

 * preserve the local changes (i.e. come up with the virtual
   "W"):
	git commit -a -m WIP
	git tag -f WIP
        git reset --hard HEAD^
 * perform the merge in the now-clean tree:
	git pull ;# again from the same place
	edit edit
        test test
        git commit -a ;# resolve conflicts, test and commit
 * recover what you have preserved, and discard the virtual W:
	git pull --no-commit . WIP ;# merge in
	git reset ;# revert index to HEAD aka base merge result.
	git tag -d WIP
Previous: Steven Grimm
Message 2 of 2 in “Working copy as a pseudo-head”
  1. Steven GrimmNov 27, 2006
  2. Junio C HamanoNov 27, 2006

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.