Thread (15 messages) 15 messages, 4 authors, 2017-12-08

Re: [SCRIPT/RFC 0/3] git-commit --onto-parent (three-way merge, no working tree file changes)

flat view

From: Igor Djordjevic <hidden>
Date: 2017-11-29 23:10:33

Hi Hannes,

On 29/11/2017 20:11, Johannes Sixt wrote:
Ok, then please explain, how this process should work in my workflow
and with the `commit --onto-parent` feature that you have in mind. I
have an integration branch (which is a throw-away type, so you can
mangle it in any way you want); it is a series of merges:

 ...A    ...C            <- topics A, C
     \       \ E
   ---o---o---o---o I    <- integration
         /       /
     ...B    ...D        <- topics B, D

Now I find a bug in topic B. Assume that the merges of C and D have
textual conflicts with the integration branch (but not with B) and/or
may be evil. What should I do?

With git-post, I make a fixup commit commit on the integration
branch, then `git post B && git merge B`:

 ...A    ...C                  <- topics A, C
     \       \
   ---o---o---o---o---f---F    <- integration
         /       /       /
     ...B    ...D       /      <- topic D
         \             /
          f'----------'        <- topic B

The merge F does not introduce any changes on the integration branch,
so I do not need it, but it helps keep topic B off radar when I ask
`git branch --no-merged` later.
But you`re not committing (posting) on your HEAD`s (direct) parent in 
the first place (topic B), so `commit --onto-parent` isn`t right tool 
for the job... yet :)

To make it easier to explain, I marked your integration branch 
initial head with "I" in the quote above (commit merging-in branch 
D), and marked commit merging-in branch C with "E".

HEAD being currently on commit "I", you can only use `--onto-parent` 
option to commit onto "E" or "D", being parents of "I".

To work with `--onto-parent` and be able to commit on top of any of 
the topic branches, you would need a situation like this instead:

 (1)  ...C      <- topic C
         |
    ...A |      <- topic A
        \|
      ...o I    <- integration
        /|
    ...B |      <- topic B
         |
      ...D      <- topic D

With `commit --onto-parent` you would skip `git post B && git merge 
B` steps, where "fixup commit" would be done with `--onto-parent B`, 
So you end up in situation like this:

 (2)      ...C      <- topic C
             |
        ...A |      <- topic A
            \|
          ...o I'   <- integration
            /|
    ...B---f |      <- topic B
             |
          ...D      <- topic D

State of index and working tree files in your F and my I' commit is 
exactly the same (I' = I + f), where in my case (2) history looks 
like "f" was part of topic B from the start, before integration 
merge happened.

BUT, all this said, I understand that your starting position, where 
not all topic branches are merged at the same time (possibly to keep 
conflict resolution sane), is probably more often to be encountered 
in real-life work... and as existing `--onto-parent` machinery should 
be able to support it already, I`m looking forward to make it happen :)

Once there, starting from your initial position:
   ...A    ...C            <- topics A, C
       \       \ E
     ---o---o---o---o I    <- integration <- HEAD
           /       /
       ...B    ...D        <- topics B, D
... and doing something like `git commit --onto B --merge` would yield:
 
 (3) ...A    ...C            <- topics A, C
         \       \ E
       ---o---o---o---o I'   <- integration
             /       /|
         ...B    ...D |      <- topic D
             \        |
              f-------'      <- topic B

... where (I' = I + f) is still true. If that`s preferred in some 
cases, it could even look like this instead:

 (4) ...A    ...C             <- topics A, C
         \       \ E  I
       ---o---o---o---o---F   <- integration
             /       /   /
         ...B    ...D   /     <- topic D
             \         /
              f-------'       <- topic B

... where F(4) = I'(3), so similar situation, just that we don`t 
discard I but post F on top of it.

Good thing is all necessary logic should already be in place, I just 
need to think a bit about the most sane user interface, and get back 
to you. Thanks for invaluable input so far :)

Of course, do feel free to drop any ideas you come up with as well, 
on how `git commit` user interface/options leading to (3) or (4) 
should look like (they could both be supported).
quoted
Like working on multiple branches at the same time, in the manner
similar to what `git add --patch` allows in regards to working on
multiple commits at the same time. This just takes it on yet another
level... hopefully :)
'kay, I'm not eagerly waiting for this particular next level (I
prefer to keep things plain and simple), but I would never say this
were a broken workflow. ;)
Hehe, thanks, I guess :) Simplicity, but user-oriented, is the major 
point here, where you can work on unrelated patch series at the same 
time (patch queues?), without a need to switch branches, while you 
still make "per series" history as you go, without a need to do it 
after the fact.

It`s a matter of possibilities (where Git usually excels), so one can 
choose for himself, depending on the situation at hand.
quoted
[SCRIPT/RFC 3/3] git-commit--onto-parent.sh[1] (I guess you didn`t
have time to checked that one yet?):
I did have a brief look, but I stopped when I saw

    # Remove entry from HEAD reflog, not to pollute it with
    # uninteresting in-between steps we take, leaking implementation
    # details to end user.

It's a clear sign for me that's something wrong. It is not just
reflogs that can become stale, but all operations that follow the
`git commit` can fail. How do you clean up such a mess?
I would respectfully disagree about it being wrong per se, but that 
said, "cleaning up" reflogs was a last minute design decision so we 
don`t show uninteresting states - from user`s point of view, all that 
happened is commit on top of --onto-parent, and merging that commit 
into where he already was (instead of the commit he was on). 

Implementation details on how we got there should be irrelevant, even 
more if we failed to do so, cluttering reflog with unimportant 
leftovers.

Commands are chained, and in case _anything_ goes wrong, we just bail 
out and restore original index and HEAD position. As working tree is 
not touched at all, no cleanup needed there, so everything is pretty 
simple. Of course, valid tests still should/need to be made, to make 
sure everything is covered, but there really isn`t much to cover in 
the first place.

But this is open for discussion, of course, and code for ref-logging 
all steps is still inside the script, just commented out. Heck, 
there`s even get_checkout_reflog_message() function at the end of the 
script, used to mimic real checkout reflog message, that`s currently 
unused ;)
The "complex situation" I had in mind was not so much about the
user's view, but how the implementation has to work when there are
errors.
Simple - abort. Restore backed up index and HEAD state is all that`s 
to it, and it looks like we never issued the command to begin with.
quoted
From what I understand, your `git-post` makes a commit where you
are _and copies_ it over to destination, so you end up with same
changes in two places (two commits). More, you seem to keep working
on top of your previous commit(s), which seems logical, later
"posting" it where desired - so after the fact. It also means you
do still have all your "fix" commits in HEAD while you work on them
(and until you git-post and abandon them, discarding the
integration branch).
Just to clarify: git-post only copies existing commits, but does not
make the original itself.
Yes, I understand that (hopefully communicated from the second part 
of the quote), but I see my wording of that first sentence was a bit 
unfortunate there (to say the least, lol), thanks for clarifying.
quoted
Could it be that you`re looking at `git commit --onto-parent` from
an unexpected perspective (through your `git-post`, being
conceptually different)...?
That may be the case. I'm very interested in your answer to my
challenge above.
From everything said above, it seems so - at the moment, but I`m 
looking forward making it work for you, too, as it does make sense 
"out in the wild", in real-life scenarios.

Thank you again, for inspiring discussion.

Regards, Buga
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help