Re: [GSoC] [RFC] Proposal: Teach git stash to handle unmerged index entries.
- Date: Wed, 10 Apr 2019 14:09:38 +0900
- From: Junio C Hamano <gitster@xxxxxxxxx>
- Subject: 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 # 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.