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). > > 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. > > [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. > > 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. > > 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