Hi Hannes, On 01/12/2017 18:23, Johannes Sixt wrote: > > > 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 > > This is a very, VERY exotic workflow, I would say. How would you > construct commit I when three or more topics have conflicts? > merge-octopus does not support this use-case. But I`m not interested in constructing commit I in the first place, only help working with it once it`s already there (which shouldn`t be too uncommon in case of unrelated, non-conflicting topics) - but I already agreed my example could have been a bit too esoteric, distracting attention from the important part :) I`ll continue on this further below, where you commented on those more common scenarios. Here, let`s try to look at the whole situation from a "patch queue" perspective instead, starting from something like this: (5) ---O---I <- integration <- HEAD ... and then making progress like this - first, commit A1 onto O, starting "topicA" branch at the same time, even, maybe using syntax like `git commit --onto-parent O -b topicA`: (6) ---O---J <- integration <- HEAD [ J = I + A1 ] \ / A1 <- topicA ..., then commit B1 onto O to start "topicB" branch: (7) B1 <- topicB / \ ---O---K <- integration <- HEAD [ K = J + B1 ] \ / A1 <- topicA ..., then add one more commit (patch) onto B1: (8) B1---B2 <- topicB / \ ---O--------L <- integration <- HEAD [ L = K + B2 ] \ / A1---/ <- topicA ..., and one more, B3: (9) B1---B2---B3 <- topicB / \ ---O-------------M <- integration <- HEAD [ M = L + B3 ] \ / A1--------/ <- topicA We can also start a new topic branch (queue), commit C1: (10) B1---B2---B3 <- topicB / \ ---O-------------N <- integration <- HEAD [ N = M + C1 ] |\ /| | A1--------/ / <- topicA \ / C1---------/ <- topicC And lets make one more "topicA" related commit A2: (11) B1---B2---B3 <- topicB / \ ---O-------------P <- integration <- HEAD [ P = N + A2 ] |\ /| | A1---A2---/ / <- topicA \ / C1---------/ <- topicC Notice how HEAD never leaves "integration" branch, and underlying commit is recreated each time? It`s like a live branch we`re working on, but we`re not actually committing to. No branch switching (and no working tree file changes caused by it), and we`re working on multiple topics/branches simultaneously, being able to instantly test their mutual interaction as we go, but also creating their separate (and "clean") histories at the same time. I guess this would make most sense with simple topics we _could_ practically work on at the same time without making our life too complicated - what stands for "git add --patch", too, when working on multiple commits at the same time. Once satisfied, of course each topic branch would need to be tested separately, and each commit, even - all the same as with "git add --patch" commits. And "git add --patch" can still be used here, too, to distribute partial changes, currently existing together inside the working tree, to different topic branches, at the time of making the commit itself. Does this approach make more sense in regards to "git commit --onto-parent" functionality I`m having in mind? Or I`m dreaming too much here...? :) > > 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. > > I am not used to this picture. I would not think that it is totally > unacceptable, but it still has a hmm-factor. Main idea is not to pile up uninteresting merge commits inside (throwaway) integration branch, needlessly complicating history, but pretend as we just made the integration merge, where fixup commit f was already existing in its topic branch prior the merge. > > 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. > > This is very acceptable. And I can see logic behind this case, too (alongside that other one, where they can both be supported, for different scenarios). > Nevertheless, IMO, it is not the task of git-commit to re-compute a > merge commit. It would be OK that it commits changes on top of a > branch that is not checked out. Perhaps it would even be OK to remove > the change from the current workspace (index and worktree), because > it will return in the form of a merge later, but producing that merge > is certainly not the task of git-commit. Just to make sure we`re on the same page - you mean conceptually, or practically? Or both...? :) Because practically, we don`t do any merge operations/computations (as can be seen inside the script), so we really don`t produce any merges :) Having a merge commit being updated as an outcome is just a consequence of altering our history to pretend fixup commit already existed elsewhere, being brought into our current state from there - and that "current state" is updated accordingly to reflect the change we made in the history that led to it. Let`s look at a different example, no merges involved: (12) ---A---B---C---D <- HEAD Here, we can do `git commit --onto-parent C` to make the history look like this: (13) ---A---B---C---E---D' <- HEAD ..., where we practically inserted commit E between our HEAD and commit C, causing D to be updated to D' accordingly (rebased, practically). Idea is the same with merges involved, updating HEAD commit to reflect altered history. In situation (12), we could also do `git commit --onto-parent C --amend`, ending up with history like this instead: (14) ---A---B---F---D' <- HEAD ..., where F is amended C, E being added to it, instead of being a separate commit. So there are quite some possibilities here. But as said, I can understand a wish to have a commit elsewhere without "merging" it in, too (changes removed from current workspace), or "merging" it inside a separate commit (not updating existing HEAD one). And saying that, making the merge commit at the same time could then be observed as no more than a shortcut, too, like being able to create a new branch on checkout using "-b" option. So even conceptually, it would make sense to wish for something like this: (15) git commit --onto B --merge ..., producing that graph (4) shown in the quote above, I would think? But even in that case, do note no merge is really happening, we just alter history of our current state, where we already are. Splitting changes out of HEAD to a commit directly preceding it, on a different branch, and still keeping those changes in HEAD, naturally causes our current HEAD state to have multiple parents, what is perceived as a merge commit, even without a merge operation leading to it. Thus, `git commit` seems it should be up to the task, whichever approach user opts for :) Regards, Buga