Web lists-archives.com

Re: [GSoC] [RFC] Proposal: Teach git stash to handle unmerged index entries.

Junio C Hamano <gitster@xxxxxxxxx> writes:

> As to the design, it does not quite matter if you add four or more
> separate trees to represent stage #[0123] entries in the index to
> the already octopus merge commit that represents a stash entry ...

I forgot that I was planning to expand on this part while writing
the message I am following up.

There are a few things you must take into account while designing a
new format for a stash entry:

 - Your new feature will *NOT* be the last extension to the stash
   subsystem.  Always leave room to other developers to extend it
   further, without breaking backward compatiblity when your new
   feature is int in use.

 - Even though you may have never encountered in your projects,
   higher stage entries can have duplicates.  When merging two
   branches into your current branch, and there are three merge
   bases for such an octopus merge, the system (and the index
   format) is designed to allow a merge backend to store 3 stage #1
   entries (because there are that many common ancestor versions in
   the example), 1 stage #2 entry (because there is only one
   "current brahch" a merge is made into) and 2 stage #3 entries
   (because there are that many other branches you are merging into
   the current branch), all for the same path.

So, a design that says:

   A stash entry in the current system is recorded as a merge
   commit, whose tree represents the state of the tracked working
   tree files, whose first parent records the HEAD commit the stash
   entry was created on, and whose second parent records the tree
   that would have been created if "git write-tree" were done on the
   index when the stash entry was created.  Optionally, it can have
   the third parent whose tree records the state of untracked files.

   Let's add three more parents.  IOW, the fourth parent's tree
   records the result of "git write-tree" of the index after
   removing all the entries other than those at stage #1 and moving
   the remainder from stage #1 down to stage #0, and similarly the
   fifth is for stage #2 and the sixth is for stage #3.

is bad at multiple counts.

 - It does not say what should happen to the third parent when this
   new "record unmerged state" feature is used without using the
   "record untracked paths" feature.

 - It does not allow multiple stage #1 and/or stage #3 entries.

For the first point, I think a trick to record the same commit as
the first parent may be a good hack to say "this is not used"; we
might need to allow commit-tree not to complain about duplicate
parents if we go that route.

FOr the second one, there may be multiple solutions.  A
quick-and-dirty and obvious way may be to add only one new parent to
the merge commit that represents a stash entry (i.e. the fourth
parent).  Make that new parent a merge of three commits, each of
which represents what was in stage #1, stage #2 and stage #3 (we can
reuse the second parent of the stash entry that usually records the
index state to store stage #0 entries).

As we allow multiple stage #1 or stage #3 entries in the index, and
there is no fundamental reason why we should not allow multiple
stage #2 entries, make each of these three commits able to represent
multiple entries at the same stage, perhaps by

 - iterate over the index and count the maximum occurrence of the
   same path at the same stage #$n;
 - make that stage #$n commit a merge of that many parent commits.
   The tree recorded in that stage #$n commit can be an empty tree.

I am not saying this is a good design.  I am merely showing the
expected level of detail when your design gets in a presentable
shape and shared with the list.

Have fun.