Re: [PATCH] cherry-pick: do not error on non-merge commits when '-m 1' is specified
Junio C Hamano writes: > Sergey Organov writes: > >> When cherry-picking multiple commits, it's impossible to have both >> merge- and non-merge commits on the same command-line. Not specifying >> '-m 1' results in cherry-pick refusing to handle merge commits, while >> specifying '-m 1' fails on non-merge commits. > > Allowing "-m1" even when picking a single parent commit, because > the 1-st parent is defined for such a commit, makes sense, espeially > when running a cherry-pick on a range, exactly for the above reason. > It is slightly less so when cherry-picking a single commit, but not > by a large margin. [...] >> +} else if (1 < opts->mainline) >> +/* Non-first parent explicitly specified as mainline for >> + * non-merge commit */ > > Style. > > /* >* Our multi-line comments are to be >* formatted like this. >*/ Ah, sorry for that. Will you fix it for me? Thanks! -- Sergey
[PATCH] cherry-pick: do not error on non-merge commits when '-m 1' is specified
When cherry-picking multiple commits, it's impossible to have both merge- and non-merge commits on the same command-line. Not specifying '-m 1' results in cherry-pick refusing to handle merge commits, while specifying '-m 1' fails on non-merge commits. This patch allows '-m 1' for non-merge commits. Besides, as mainline is always the only parent for a non-merge commit, it made little sense to disable it in the first place. Signed-off-by: Sergey Organov --- sequencer.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index 1ce6326..2393bdf 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1543,9 +1543,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, return error(_("commit %s does not have parent %d"), oid_to_hex(>object.oid), opts->mainline); parent = p->item; - } else if (0 < opts->mainline) - return error(_("mainline was specified but commit %s is not a merge."), - oid_to_hex(>object.oid)); + } else if (1 < opts->mainline) + /* Non-first parent explicitly specified as mainline for +* non-merge commit */ + return error(_("commit %s does not have parent %d"), +oid_to_hex(>object.oid), opts->mainline); else parent = commit->parents->item; -- 2.10.0.1.g57b01a3
Re: [PATCH v9 00/17] rebase -i: offer to recreate commit topology by rebasing merges
This has been sent by mistake, I'm sorry, please disregard. Sergey Organov <sorga...@gmail.com> writes: > Johannes Schindelin <johannes.schinde...@gmx.de> writes: > >> Junio, I think this is now ready for `next`. Thank you for your patience >> and help with this. [...]
Re: [PATCH v9 00/17] rebase -i: offer to recreate commit topology by rebasing merges
Johannes Schindelinwrites: > Junio, I think this is now ready for `next`. Thank you for your patience > and help with this. > > Once upon a time, I dreamed of an interactive rebase that would not > linearize all patches and drop all merge commits, but instead recreate > the commit topology faithfully. > > My original attempt was --preserve-merges, but that design was so > limited that I did not even enable it in interactive mode. > > Subsequently, it *was* enabled in interactive mode, with the predictable > consequences: as the --preserve-merges design does not allow for > specifying the parents of merge commits explicitly, all the new commits' > parents are defined *implicitly* by the previous commit history, and > hence it is *not possible to even reorder commits*. > > This design flaw cannot be fixed. Not without a complete re-design, at > least. This patch series offers such a re-design. > > Think of --rebase-merges as "--preserve-merges done right". It > introduces new verbs for the todo list, `label`, `reset` and `merge`. > For a commit topology like this: > > A - B - C > \ / > D > > the generated todo list would look like this: > > # branch D > pick 0123 A > label branch-point > pick 1234 D > label D > > reset branch-point > pick 2345 B > merge -C 3456 D # C > > There are more patches in the pipeline, based on this patch series, but > left for later in the interest of reviewable patch series: one mini > series to use the sequencer even for `git rebase -i --root`, and another > one to add support for octopus merges to --rebase-merges. And then one > to allow for rebasing merge commits in a smarter way (this one will need > a bit more work, though, as it can result in very complicated, nested > merge conflicts *very* easily). > > Changes since v8: > > - Disentangled the patch introducing `label`/`reset` from the one > introducing `merge` again (this was one stupid, tired `git commit > --amend` too many). > > - Augmented the commit message of "introduce the `merge` command" to > describe what the `label onto` is all about. > > - Fixed the error message when `reset` would overwrite untracked files to > actually say that a "reset" failed (not a "merge"). > > - Clarified the rationale for `label onto` in the commit message of > "rebase-helper --make-script: introduce a flag to rebase merges". > > - Edited the description of `--rebase-merges` heavily, for clarity, in > "rebase: introduce the --rebase-merges option". > > - Edited the commit message of (and the documentation introduced by) " rebase > -i: introduce --rebase-merges=[no-]rebase-cousins" for clarity (also > mentioning the `--ancestry-path` option). > > - When run_git_commit() fails after a successful merge, we now take pains > not to reschedule the `merge` command. > > - Rebased the patch series on top of current `master`, i.e. both > `pw/rebase-keep-empty-fixes` and `pw/rebase-signoff`, to resolve merge > conflicts myself. > > > Johannes Schindelin (15): > sequencer: avoid using errno clobbered by rollback_lock_file() > sequencer: make rearrange_squash() a bit more obvious > sequencer: refactor how original todo list lines are accessed > sequencer: offer helpful advice when a command was rescheduled > sequencer: introduce new commands to reset the revision > sequencer: introduce the `merge` command > sequencer: fast-forward `merge` commands, if possible > rebase-helper --make-script: introduce a flag to rebase merges > rebase: introduce the --rebase-merges option > sequencer: make refs generated by the `label` command worktree-local > sequencer: handle post-rewrite for merge commands > rebase --rebase-merges: avoid "empty merges" > pull: accept --rebase=merges to recreate the branch topology > rebase -i: introduce --rebase-merges=[no-]rebase-cousins > rebase -i --rebase-merges: add a section to the man page > > Phillip Wood (1): > rebase --rebase-merges: add test for --keep-empty > > Stefan Beller (1): > git-rebase--interactive: clarify arguments > > Documentation/config.txt | 8 + > Documentation/git-pull.txt | 6 +- > Documentation/git-rebase.txt | 163 - > builtin/pull.c | 14 +- > builtin/rebase--helper.c | 13 +- > builtin/remote.c | 18 +- > contrib/completion/git-completion.bash | 4 +- > git-rebase--interactive.sh | 22 +- > git-rebase.sh | 16 + > refs.c | 3 +- > sequencer.c| 892 - > sequencer.h| 7 + > t/t3421-rebase-topology-linear.sh | 1 + > t/t3430-rebase-merges.sh | 244 +++ > 14 files changed, 1352 insertions(+), 59
[PATCH] cherry-pick: do not error on non-merge commits when '-m 1' is specified
When cherry-picking multiple commits, it's impossible to have both merge- and non-merge commits on the same command-line. Not specifying '-m 1' results in cherry-pick refusing to handle merge commits, while specifying '-m 1' fails on non-merge commits. This patch allows '-m 1' for non-merge commits. Besides, as mainline is always the only parent for a non-merge commit, it made little sense to disable it in the first place. Signed-off-by: Sergey Organov <sorga...@gmail.com> --- sequencer.c | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index 1ce6326..2393bdf 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1543,9 +1543,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit, return error(_("commit %s does not have parent %d"), oid_to_hex(>object.oid), opts->mainline); parent = p->item; - } else if (0 < opts->mainline) - return error(_("mainline was specified but commit %s is not a merge."), - oid_to_hex(>object.oid)); + } else if (1 < opts->mainline) + /* Non-first parent explicitly specified as mainline for +* non-merge commit */ + return error(_("commit %s does not have parent %d"), +oid_to_hex(>object.oid), opts->mainline); else parent = commit->parents->item; -- 2.10.0.1.g57b01a3
Re: What's cooking in git.git (Apr 2018, #02; Tue, 17)
Junio C Hamanowrites: [...] > > * js/rebase-recreate-merge (2018-04-11) 15 commits [...] > "git rebase" learned "--rebase-merges" to transplant the whole > topology of commit graph elsewhere. > > This looked more or less ready for 'next'. Please stop me if there > are remaining issues I forgot about. It seems this is currently in inconsistent state. Despite the new name of the option, it still doesn't rebase merges. It rather recreates them from scratch, and Johannes is hopefully still working on implementation of proper rebasing. In addition, for what it's worth, I'm cooking a review of the problems of the suggested UI. I believe the UI of this new feature is seriously mis- and/or under- developed and is not suitable as is for the core Git. -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Hi Jacob, Jacob Keller <jacob.kel...@gmail.com> writes: > On Wed, Apr 18, 2018 at 9:24 PM, Sergey Organov <sorga...@gmail.com> wrote: >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >>> Hi Phillip, >>> >>> On Fri, 13 Apr 2018, Phillip Wood wrote: >>> >>>> On 12/04/18 23:02, Johannes Schindelin wrote: >>>> > >>>> > [...] >>>> > >>>> > So: the order of the 3-way merges does matter. >>>> > >>>> > [...] >>>> >>>> Those conflicts certainly look intimidating (and the ones in your later >>>> reply with the N way merge example still look quite complicated). One >>>> option would be just to stop and have the user resolve the conflicts >>>> after each conflicting 3-way merge rather than at the end of all the >>>> merges. There are some downsides: there would need to be a way to >>>> explain to the user that this is an intermediate step (and what that >>>> step was); the code would have to do some book keeping to know where it >>>> had got to; and it would stop and prompt the user to resolve conflicts >>>> more often which could be annoying but hopefully they'd be clearer to >>>> resolve because they weren't nested. >>> >>> I thought about that. But as I pointed out: the order of the merges *does* >>> matter. Otherwise we force the user to resolve conflicts that they >>> *already* resolved during this rebase... >> >> How it's relevant to what Phillip suggested? How the order of taking 2 >> steps, A and B, affects an ability to stop after the first step? It's >> still either "A,stop,B" or "B,stop,A", depending on the chosen order. >> >> What's the _actual_ problem here, if any? >> >> -- Sergey > > I believe the order of the merges changes which ones cause conflicts, > but it's possible to generate pre-images (i.e. a set of parents to > merge) which cause conflicts regardless of which ordering we pick, so > I'm not sure there is a "best ordering". I totally agree, but this still does not address the problem of recursive conflicts, and it's this particular problem that Phillip's suggestion addresses. Just stop after _every_ conflict and let user resolve it, whatever the order is. Recursive conflicts are simply showstoppers. Whatever cleverness is invented to represent them, it will still outsmart most of the users. As for your statement, it should be clear the absolute "best ordering" simply can't exist, as merges are inherently symmetric in the DAG. One can try all orders in turn and select one that brings less conflicts though. Comparing conflicts is a problem by itself here. Recursive vs non-recursive and conflict vs no-conflict are obvious and could be the only checks adopted, all other cases being considered equal. If we do select fixed order method, or can't find the best order, the default order should simply match the natural one, first parent first. Besides, it's the change to the mainline that is most important for an actual Git merge, so letting it come first sounds most reasonable. -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Johannes Schindelinwrites: > Hi Phillip, > > On Fri, 13 Apr 2018, Phillip Wood wrote: > >> On 12/04/18 23:02, Johannes Schindelin wrote: >> > >> > [...] >> > >> > So: the order of the 3-way merges does matter. >> > >> > [...] >> >> Those conflicts certainly look intimidating (and the ones in your later >> reply with the N way merge example still look quite complicated). One >> option would be just to stop and have the user resolve the conflicts >> after each conflicting 3-way merge rather than at the end of all the >> merges. There are some downsides: there would need to be a way to >> explain to the user that this is an intermediate step (and what that >> step was); the code would have to do some book keeping to know where it >> had got to; and it would stop and prompt the user to resolve conflicts >> more often which could be annoying but hopefully they'd be clearer to >> resolve because they weren't nested. > > I thought about that. But as I pointed out: the order of the merges *does* > matter. Otherwise we force the user to resolve conflicts that they > *already* resolved during this rebase... How it's relevant to what Phillip suggested? How the order of taking 2 steps, A and B, affects an ability to stop after the first step? It's still either "A,stop,B" or "B,stop,A", depending on the chosen order. What's the _actual_ problem here, if any? -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Hi Jacob, Jacob Keller <jacob.kel...@gmail.com> writes: > On Wed, Apr 11, 2018 at 10:42 PM, Sergey Organov <sorga...@gmail.com> wrote: >> Hi Jacob, >> >> Jacob Keller <jacob.kel...@gmail.com> writes: >>> On Wed, Apr 11, 2018 at 6:13 AM, Sergey Organov <sorga...@gmail.com> wrote: >>>> It was rather --recreate-merges just a few weeks ago, and I've seen >>>> nobody actually commented either in favor or against the >>>> --rebase-merges. >>>> >>>> git rebase --rebase-merges >>>> >>> >>> I'm going to jump in here and say that *I* prefer --rebase-merges, as >>> it clearly mentions merge commits (which is the thing that changes). >> >> OK, thanks, it's fair and the first argument in favor of --rebase-merges >> I see. >> > > I'd be ok with "--keep-merges" also. I don't like the idea of > "flatten" as it, to me, means that anyone who wants to understand the > option without prior knowledge must immediately read the man page or > they will be confused. Something like "--rebase-merges" at least my > coworkers got it instantly. The same could be said for "--keep-merges" > too, but so far no one I asked said the immediately understood > "--no-flatten". If they got --rebase-merges instantly, they should already have known what "rebase" and "merge" mean. If so, they are likely Git users that are already familiar with "git rebase" and thus at least heard about a buddy called --preserve-merges. If it's the case indeed, the outcome you've got was rather predictable, me thinks. Now, what are the consequences? When pleasing maximum number of users of --preserve-merges (and probably --recreate-merges) is number one target of design, while the rest of issues are secondary, being in favor of --rebase-merges, --keep-merges, or ---merges is only natural indeed. However, I don't believe meeting user expectations should be the number one criteria of a good design. Sound technical design should come first, and meeting user expectations, provided they don't contradict the design, only second. That's how Git was born, that's how it should continue to evolve. Going in reverse direction, from user expectations to design, will give us Bzr, not Git. In discussing of these patch series though I rather see care for user expectations or preferences being used as an excuse for questionable design all the time. That's what actually bothers me much more than choosing particular names for particular options. Narrowing back to the topic, don't you see, honestly, that there is something wrong with: git rebase --rebase-merges that is supposedly easy to understand even without referring to the manual, yet when you do happen to refer to the manual, you suddenly realize it's not that easy to understand: --rebase-merges[=(rebase-cousins|no-rebase-cousins)] Rebase merge commits instead of flattening the history by replaying merges. Merge conflict resolutions or manual amendments to merge commits are not rebased automatically, but have to be applied manually. ??? Please read the description. Actually read as if you never knew what's all this about. Why does it use "flattening the history" that is supposedly hard to understand to explain "--rebase-merges" that is supposedly easy to understand? How comes? And if it's actually a good explanation, why didn't author just call the option --no-flatten-history, to match its description? Next, what is "replaying merges", exactly? That's explaining one term with another that has not being explained and sounds being even more vague. Further, "Merge conflict resolutions or manual amendments to merge commits are not rebased automatically, but have to be applied manually." is mutually exclusive with "Rebase merge commits", making all this even more messy. A merge commit is just content with multiple parents, and `git rebase`, by definition, reapplies the changes the content introduces. Any "amendments" or "resolutions" that could have been happening (or not) when that commit was being created are entirely irrelevant. Further yet it goes with: "By default, or when `no-rebase-cousins` was specified, commits which do not have `` as direct ancestor will keep their original branch point." Really? What does it actually mean? What is "commit branch point", exactly? What "direct ancestor" means in this context, exactly? Provided even when I do know what the option actually does, the description looks wrong, how it could explain anything? Having all this right here in the patch series, you guys try to convince me that it should not be fixed? That it meets user expectations? You know what? I, a
Re: Draft of Git Rev News edition 38
Kaartic Sivaraam <kaartic.sivar...@gmail.com> writes: > Hi, > > On Monday 16 April 2018 08:33 PM, Sergey Organov wrote: >> Christian Couder <christian.cou...@gmail.com> writes: >>> Here "the above article" means the Jake's "branch -l: print useful >>> info whilst rebasing a non-local branch" article above the current >>> article. > > Just a little correction. I suppose Chris actually meant the "rebase -i: > offer to recreate merge commits" article written by Jake and not the > "branch -l: print useful info whilst rebasing a non-local branch" article. > > That said, I read the draft and found it good except for two minor issues, > > 1. I see the following sentence in the "Rebasing merges: a jorney to the > ultimate solution (Road Clear) (written by Jacob Keller)" article > > "A few examples were tried, but it was proven that the original > concept did not work, as dropped commits could end up being > replaid into the merge commits, turning them into "evil" > merges." > > I'm not sure if 'replaid' is proper English assuming the past tense of > replay was intended there (which I think is 'replayed'). It could have meant, say, "reapplied", -- we need to ask the author. While we are at it, please also consider to replace "original concept" by "original algorithm", as it didn't work due to a mistake in the algorithm as opposed to failure of the concept itself. -- Sergey
Re: Draft of Git Rev News edition 38
Christian Couderwrites: > Hi Sergey, > [...] > Jake wrote the article below the above line. His article summarizes > the discussions that happened following your email that is linked to > in the above line. The above line is actually the title of Jake's > second article. > [...] > Here "the above article" means the Jake's "branch -l: print useful > info whilst rebasing a non-local branch" article above the current > article. > [...] > You call it a reference but it is actually the title of the article > that Jake wrote. Yes, it contains a link to your email, but that is > just because we want to make it easy and straightforward for people > who are interested in all the discussions to find them. Yeah, I see now, it was confusion on my side. Thanks for clarification! The rest is also fine with me, and thanks for editorial changes! -- Sergey
Re: Draft of Git Rev News edition 38
Hi Christian, Christian Couder <christian.cou...@gmail.com> writes: > On Mon, Apr 16, 2018 at 12:11 AM, Christian Couder > <christian.cou...@gmail.com> wrote: >> >> A draft of a new Git Rev News edition is available here: >> >> >> https://github.com/git/git.github.io/blob/master/rev_news/drafts/edition-38.md > > The draft has just been updated with 2 articles contributed by Jake > about rebasing merges, so I am cc'ing more people involved in those > discussions. I find this section of the draft pretty close to my own vision of what and how has been discussed, except for a few issues. [all quotations below are taken from the draft] > Some discussion about --preserve-merges and compatibility with scripts > (i.e. should we change or fix it? or should we deprecate it?) > followed. > >Rebasing merges: a jorney to the ultimate solution (Road Clear) >(written by Jacob Keller) What article by Jacob is actually meant here I have no idea, please check, as this one, and the RFC this refers to, was written by me, not by Jacob, and it is the outline of potential method of actually rebasing merges that is discussed in the next paragraph, so it likely belongs right after the next paragraph: > After the discussions in the above article Sergey posted an outline of a > potential method for actually rebasing a merge (as opposed to recreating > it from scratch) which used a process of git cherry-pick -mN of the > merge onto each topic branch being merged, and then merging the result. The reference to: Rebasing merges: a jorney to the ultimate solution (Road Clear) (written by Sergey Organov) belongs here, if at all. In addition, I'd like to see a minor edition to the following: > Sergey replied that he thinks the solution produces the same result as > his updated strategy. This has been said in the context that assumed lack of conflicts during application of both strategies. Something like this, maybe: "Sergey replied that he thinks the solution produces the same result as his updated strategy, at least when none of the strategies produce any conflicts." Next, this is very close, but not exactly right: > Further suggestions to the strategy were proposed and tested, ultimately > resulting in Sergey proposing the addition of using the original merge > commit as a merge base during the final step. This was not an addition, this was a fix of particular mistake in the original RFC that has been revealed during testing. I didn't get it right at first that it's original merge commit that must be used as merge base, so my original proposal ended up implicitly using wrong merge base, that is the one computed by "git merge-base U1' U2'". Something along these lines may fit better: "Further suggestions to the strategy were proposed and tested, ultimately resulting in Sergey proposing the fix to his method, specifically using the original merge commit as a merge base during the final step." I'd also like a reference to the final fixed [RFC v2] be added right here. The reference is: https://public-inbox.org/git/87r2oxe3o1@javad.com/ Thanks a lot! -- Sergey
[PATCH] glossary: substitute "ancestor" for "direct ancestor" in 'push' description.
Even though "direct ancestor" is not defined in the glossary, the common meaning of the term is simply "parent", parents being the only direct ancestors, and the rest of ancestors being indirect ancestors. As "parent" is obviously wrong in this place in the description, we should simply say "ancestor", as everywhere else. Signed-off-by: Sergey Organov <sorga...@gmail.com> --- Documentation/glossary-content.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 6bd..6c2d23d 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -463,7 +463,7 @@ exclude;; [[def_push]]push:: Pushing a <<def_branch,branch>> means to get the branch's <<def_head_ref,head ref>> from a remote <<def_repository,repository>>, - find out if it is a direct ancestor to the branch's local + find out if it is an ancestor to the branch's local head ref, and in that case, putting all objects, which are <<def_reachable,reachable>> from the local head ref, and which are missing from the remote -- 2.10.0.1.g57b01a3
Re: [PATCH v6 15/15] rebase -i --rebase-merges: add a section to the man page
Johannes Schindelinwrites: > + > +* Merge branch 'report-a-bug' > +|\ > +| * Add the feedback button > +* | Merge branch 'refactor-button' > +|\ \ > +| |/ > +| * Use the Button class for all buttons > +| * Extract a generic Button class from the DownloadButton one > + Consider to put SHA1s into the diagram, as they are then used in explanaitions. Hopefully I got them right here: * 6f5e4d Merge branch 'report-a-bug' |\ | * abcdef Add the feedback button * | a1b2c3 Merge branch 'refactor-button' |\ \ | |/ | * 654321 Use the Button class for all buttons | * 123456 Extract a generic Button class from the DownloadButton one Original explanation, just for reference, unchanged: > + > +label onto > + > +# Branch: refactor-button > +reset onto > +pick 123456 Extract a generic Button class from the DownloadButton one > +pick 654321 Use the Button class for all buttons > +label refactor-button > + > +# Branch: report-a-bug > +reset refactor-button # Use the Button class for all buttons > +pick abcdef Add the feedback button > +label report-a-bug > + > +reset onto > +merge -C a1b2c3 refactor-button # Merge 'refactor-button' > +merge -C 6f5e4d report-a-bug # Merge 'report-a-bug' > + -- Sergey
Re: [PATCH v6 14/15] rebase -i: introduce --rebase-merges=[no-]rebase-cousins
Johannes Schindelinwrites: [...] > ++ > +By default, or when `no-rebase-cousins` was specified, commits which do not > +have `` as direct ancestor will keep their original branch point. sans quotes, <...> are used without them throughout the manual page. > +If the `rebase-cousins` mode is turned on, such commits are rebased onto > +`` (or ``, if specified). (or , if --onto is specified). sans quotes, and there is no defined. -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Wed, 11 Apr 2018, Sergey Organov wrote: > >> The RFC v2 and Phillip's strategy are essentially the same, as has been >> already shown multiple times, both theoretically and by testing. > > No, they are not. It's off-topic here. If you _really_ want to discuss it further, you are still welcome to come back to where you ran away from and continue: https://public-inbox.org/git/87po3oddl1@javad.com/ Abrupt change of the topic of discussion indicates your intention to take attention off the apparent ugliness of git rebase --rebase-merges I also get it as an indication that there are no more arguments in favor of --rebase-merges on your side, at least for now. -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Hi Jacob, Jacob Keller <jacob.kel...@gmail.com> writes: > On Wed, Apr 11, 2018 at 6:13 AM, Sergey Organov <sorga...@gmail.com> wrote: >> It was rather --recreate-merges just a few weeks ago, and I've seen >> nobody actually commented either in favor or against the >> --rebase-merges. >> >> git rebase --rebase-merges >> > > I'm going to jump in here and say that *I* prefer --rebase-merges, as > it clearly mentions merge commits (which is the thing that changes). OK, thanks, it's fair and the first argument in favor of --rebase-merges I see. I don't get why this detail matters so much it should be reflected in the option name, and if it is what matters most, why the patch series are not headed: rebase -i: offer to rebase merge commits. Once upon a time, I dreamt of an interactive rebase that would not drop merge commits, but instead rebase them. > I hadn't mentioned this before, because it was a suggestion that > someone else made and it seemed that Johannes liked it, so I didn't > think further discussion was worthwhile. So you guys seem to be winning 2:1, or even 3:1, counting the guy who made the suggestion. Except it was Buga's suggestion [1], and I believe I was able to convince him that something like --no-flatten would be better [2]: > I hope he'd be pleased to be able to say --no-flatten=remerge and get > back his current mode of operation, that he obviously has a good use > for. Makes sense, I like it, thanks for elaborating. [ Especially that you used "(no) flatten" phrasing, where original `--preserve-merges` documentation says it`s used "not to flatten the history", nice touch ;) ] So I assume it's 2:2 by now, with the author of original suggestion on my side. I still find git rebase --rebase-merges both being ugly and missing the point. When I look at it with a fresh eye, the questions that immediately rise are: "What the hell else could 'git _rebase_' do with (merge) commits but _rebase_ them? Why do I even need to specify this option? Should I also specify --rebase-non-merges to rebase the rest of commits?" Well, if it was called something like --[no-]keep-merges, it'd make more sense as it'd be obvious that alternative is to drop merges (notice how the old --preserve-merges does match this criteria). However, it'd still miss to reflect the generic intent of the patch series, -- to preserve history shape as much as possible, -- now citing author's head message non-twisted: rebase -i: offer to recreate commit topology Once upon a time, I dreamt of an interactive rebase that would not flatten branch structure, but instead recreate the commit topology faithfully. -- Sergey [1] https://public-inbox.org/git/bc9f82fb-fd18-ee45-36a4-921a1381b...@gmail.com/ [2] https://public-inbox.org/git/a3d40dca-f508-5853-89bc-1f9ab3934...@gmail.com/
Re: [PATCH v6 04/15] sequencer: introduce new commands to reset the revision
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Wed, 11 Apr 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> [...] >> >> > We disallow '#' as label because that character will be used as >> > separator in the upcoming `merge` command. >> >> Please consider to use # not only in `merge` and `reset`, but in the >> rest of the commands as well, to unify this new syntax. I.e., right now >> it seems to be: >> >> pick abcd A commit message >> merge beaf # B commit message >> >> I suggest to turn it to: >> >> pick abcd # A commit message >> merge beaf # B commit message > > First of all, that alignment of pick's and merge's first arguments? As if it has anything to do with the topic of the issue! Just a nice look. Let it be: pick abcd # A commit message merge beaf # B commit message if it's that essential indeed. > That does not exist. If you want aligned arguments, you have to use the > rebase.abbreviateCommands feature. It's changing the subject. > Second: this change would break backwards-compatibility. For almost eleven > years, we generated `pick abcdef0123 A commit message`. I thought we already agreed that you have no backward compatibility issues with this new feature, as it's a new feature, complete re-design, as you put it yourself: "This design flaw cannot be fixed. Not without a complete re-design, at least. This patch series offers such a re-design." At least could you please answer plain yes/no to this simple question: is this feature a complete re-design or not? yes/no, please! > Even if there are no scripts that rely on this form, power users have > gotten used to it, and I can tell you from experience how unsettling > even minor visual changes are in everyday operations. > In short: no, we cannot do that. You can do that, provided it's complete re-design indeed. You don't wish to, but you can. Nothing will break and things will be at least a little bit cleaner. Each directive having its own dedicated syntax... gosh! No luck getting syntax description, I'm afraid. > Just like your proposal to conflate the `merge` and `pick` commands There was never such proposal. The proposal was not to introduce new `merge` command when there is already `pick` that could simply be extended to pick any commit, whatever number of parents it happens to have. But provided you decline to even put a # before the commit message... that proposal is simply a pie in the sky. > for some perception of consistency: The user experience is more > important than individual persons' sense of elegance (that might not > even be shared with the majority). It's about consistency indeed. Consistent handling of commits is essential. Consistency is one of the things that bring positive user experience. You disagree? Besides, it was bad user experience that forced you to re-design, isn't it? I'm afraid you miss good opportunity to fix some of your former mistakes and you make some new. As the discussion goes, it seems you'd never admit it, the design is set in stone, and my attempts are in fact pointless. Overall, I hereby withdraw all my pending suggestions to improve this patch series. -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Wed, 11 Apr 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > On Tue, 10 Apr 2018, Sergey Organov wrote: >> > >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> >> >> > Once upon a time, I dreamt of an interactive rebase that would not >> >> > flatten branch structure, but instead recreate the commit topology >> >> > faithfully. >> >> >> >> [...] >> >> >> >> > Think of --rebase-merges as "--preserve-merges done right". >> >> >> >> Both option names seem to miss the primary point of the mode of >> >> operation that you've formulated in the first sentence. I suggest to >> >> rather call the new option in accordance to your description, say, >> >> --no-flatten, --keep-topology, or --preserve-shape. >> > >> > A very quick A/B test shows that neither --no-flatten nor --keep-topology >> > and certainly not --preserve-shape conveys to Git users what those options >> > are supposed to do. >> >> In fact, my preference would be --[no-]flatten, exactly because the >> default mode of rebase operation flattens the history, and thus what I'm >> talking about is: >> >> git rebase --no-flatten > > And this is the option out of the four that fared *worst* in the A/B > testing. Not even experts in Git internals were able to figure out what > the heck you are talking about. It was you who introduced the "flatten" term, not me. I took it from your descriptions. So they are able to make sense of your own: >>> Once upon a time, I dreamt of an interactive rebase that would not >>> flatten branch structure, but instead recreate the commit topology >>> faithfully. Yet they can't get: --no-flatten:: Instead of flattening branch structure, recreate the commit topology faithfully Are you kidding? Well, suppose for a moment that nobody could even guess what "flatten" means indeed. Then are you willing to remove the "flatten" from both the description of our patch series and from the proposed patch to the Git manual: -r:: --rebase-merges[=(rebase-cousins|no-rebase-cousins)]:: Rebase merge commits instead of _flattening_ the history by replaying merges. ??? > > Now, you can beat that dead horse until it is pulp. Your choice. I'd > rather go on to more interesting things, because as far as I am concerned, > the naming issue has been settled, with you being the only person in > disfavor of --rebase-merges. It was rather --recreate-merges just a few weeks ago, and I've seen nobody actually commented either in favor or against the --rebase-merges. git rebase --rebase-merges _is_ plain simple ugly. > > What you *could* do is finally take your RFC to the test. Run it with the > concrete example I showed you in > https://public-inbox.org/git/nycvar.qro.7.76.6.1803261405170...@zvavag-6oxh6da.rhebcr.pbec.zvpebfbsg.pbz/ > > It is high time that you demonstrated on this concrete case study how your > proposed solution performs. And then tally that up with Phillip's > strategy. What you could do is to stop shifting the subject of discussion. The RFC v2 and Phillip's strategy are essentially the same, as has been already shown multiple times, both theoretically and by testing. Ask Bugga for details. One way or another, this doesn't make git rebase --rebase-merges even a bit less ugly. -- Sergey
Re: [PATCH v6 04/15] sequencer: introduce new commands to reset the revision
Hi Johannes, Johannes Schindelinwrites: [...] > We disallow '#' as label because that character will be used as separator > in the upcoming `merge` command. Please consider to use # not only in `merge` and `reset`, but in the rest of the commands as well, to unify this new syntax. I.e., right now it seems to be: pick abcd A commit message merge beaf # B commit message I suggest to turn it to: pick abcd # A commit message merge beaf # B commit message So that the # is finally universally the start of comment. While we are at this, I couldn't find any even semi-formal syntax description of the entire todo list. Is there one already? Are you going to provide one? -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Tue, 10 Apr 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > Once upon a time, I dreamt of an interactive rebase that would not >> > flatten branch structure, but instead recreate the commit topology >> > faithfully. >> >> [...] >> >> > Think of --rebase-merges as "--preserve-merges done right". >> >> Both option names seem to miss the primary point of the mode of >> operation that you've formulated in the first sentence. I suggest to >> rather call the new option in accordance to your description, say, >> --no-flatten, --keep-topology, or --preserve-shape. > > A very quick A/B test shows that neither --no-flatten nor --keep-topology > and certainly not --preserve-shape conveys to Git users what those options > are supposed to do. In fact, my preference would be --[no-]flatten, exactly because the default mode of rebase operation flattens the history, and thus what I'm talking about is: git rebase --no-flatten vs git rebase --rebase-merges I honestly fail to see how the latter conveys the purpose of the option better than the former, sorry. To tell the truth, the latter also looks plain ugly to me. > But --rebase-merges did convey the purpose of my patch series. So > there. - Except that your primary description of the series (that I find pretty solid) doesn't mention _merges_ at all and still conveys the purpose? - Except that this patch series _don't_ actually _rebase_ merges? Yeah, I remember a follow-up is to be expected, but anyway. I'm still unconvinced. -- Sergey
Re: [PATCH v6 00/15] rebase -i: offer to recreate commit topology
Hi Johannes, Johannes Schindelinwrites: > Once upon a time, I dreamt of an interactive rebase that would not > flatten branch structure, but instead recreate the commit topology > faithfully. [...] > Think of --rebase-merges as "--preserve-merges done right". Both option names seem to miss the primary point of the mode of operation that you've formulated in the first sentence. I suggest to rather call the new option in accordance to your description, say, --no-flatten, --keep-topology, or --preserve-shape. Besides, this way the option name will only specify one thing: _what_ it is about, leaving out the _how_ part, that could vary and could then be specified as option value or as another companion option(s), that is usually considered to be an indication of a good design. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelinwrites: > Hi Sergey, > [...] > In the parlance of your RFC v2, where you start with this history (which I > translated into the left-to-right notation that is used in pretty much all > of Git's own documentation about interactive rebases, which you apparently > either did not read, or chose *not* to imitate, creating yet another > unnecessary diversion): > > > - B1 > \ > - B2 - M First, it should rather be: - B1 \ M / - B2 as RFC presents essentially symmetric approach and I'd like it to be explicit. Representation in RFC simply saves some vertical space: M / \ B1 B2 Another reason to use it is that I liked to somehow indicate that this is about abstract DAG representation of Git history, not to be confused with some actual practical Git history. So that, for example, the reader can't be tempted to even try to assume that M has been necessarily created by "git merge" operation in the first place. That said, I'm sorry if it upsets you. I'll stick to your preferred notation below. > > You now insert U1 and U2 with trees identical to M: > > - B1 - U1 > \ > - B2 - U2 - M - B1 - U1 \ UM / - B2 - U2 _YES_. You've slightly screwed RFC as UM is not M anymore, having different parents, but otherwise it's still right. > So U1 is essentially B2 cherry-picked on top of B1, and U2 is essentially > B1 cherry-picked on top of B2. _NO_. No any cherry-picking has been involved, and I see absolutely no reason to pretend there has, except to intentionally make otherwise simple thing look tricky. U1 tree is still M tree, and U2 tree is still M tree, and UM tree is still M tree. That's what actually matters from RFC POV. > These U1/U2 commits are now to be cherry-picked on top of the rebased B1' > and B2'. I spare you more diagrams, you get the idea. _YES_. Exactly 2 cherry-picks. > Now, the changes in U1/U2 *are* the changes of the merge parents, that's > how they were constructed. Either _YES_, or _NO_, depending on the exact meaning of the term "the changes of the merge parents" you've used, but I suspect it's _NO_, taking into account your further inferences. The U1/U2 are constructed by simply duplicating the tree of the original merge commit M and thus they represent the changes _to_ the merge parents B1/B2 introduced by M, and not the changes "_of_ the merge parents" B1/B2, provided the latter meant to have some relation to the changes introduced by the merge parents B1/B2 themselves. > > Since they repeat what B1 and B2 are about, _NO_, they do not repeat what B1 and B2 are about at all. They rather represent what M is about. In other words, whatever B1 and B2 are about, the RFC method doesn't care. And as this is fundamental misinterpretation of the RFC on your side, it starts to be big _NO_ from now on... > and since B1'/B2' means they are rebased, and since U1'/U2' are *also* > rebased, but independently... > > ... you essentially have to rebase *every parent's changes > twice*. _NO_. U1' is rebase of U1 (on top of B1'), and U2' is rebase of U2 (on top of B2'). Each of U1/U2 is rebased only once. > The answer "No" to this is... astonishing. It's still _NO_, sorry. In fact, I could have said _NO_ the first time you started to assign some arbitrary "meaning" to the commits, as RFC is about somewhat formal proof of the method, using already well-known operations on the DAG, and to criticize the RFC, you need to either find and show a _formal_ mistake somewhere in the proof logic, or to show a use-case where it fails, as you did for RFC v1. Assigning arbitrary "meaning" to the DAG nodes and operations on them won't do the trick, sorry. I'd like to reach some agreement on formal correctness of the RFC first, and then discuss the meanings, the implementations, and other consequences based on well-established formal base. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Wed, 28 Mar 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > I use rebase every day. I use the Git garden shears every week. If you >> > do not trust my experience with these things, nothing will convince >> > you. >> >> Unfortunately you have exactly zero experience with rebasing merges as >> you've never actually rebased them till now, and it's rebasing merges >> that matters in this particular discussion. > > Who says that I have 0 experience with that? Oh yes, you do. Like, as if > you know. I just didn't see even single symptom of it in the discussion, still I said nothing about it until you started to use your presumed experience in place of true arguments. > Guess what I do with those Git garden shears' merges? Can you guess? Of > course you can. But you'll never know until I tell you. It is a little > silly to try to tell me that I do not have any experience with rebasing > merges when you have no idea what strategies I tried in the past. Please notice that I never even started to discuss your 'merge' directive, exactly because I believe you have huge experience both implementing and using it that could be relied upon. Just don't mix-in rebasing merge commits into it, as that is fundamentally different operation. And the other unspoken strategies you tried are irrelevant here, as you declined the whole idea of replaying merge-the-commit instead of replaying merge-the-operation until recently, and it seems you still do, at least to some level, by attempting to use 'merge' operation to replay "the (merge) _commit_". I'm afraid that whatever you've tried in the past likely suffered from the same conceptual confusion, and thus did not work indeed. That said, negative experience is still an experience, often helpful, but what is relevant here is that it likely was not about rebasing merge commits at all, so trying to use this irrelevant experience in the discussion to support your arguments, or rather lack of them, seems even more unfair to me then using relevant experience for that purpose. > Now, Phillip's strategy is clearly the best strategy I ever heard > about, For 'pick' vs 'merge', it's not about strategy, it's about concept. It looks like you still believe that you somehow "merge" a merge commit when you actually rebase it (with Phillip's strategy if you wish). You don't merge it anywhere, period. > and I am in the process of doing Actual Work to Put It To The Test. That's the best outcome of the discussion I ever hoped for, seriously, and I'll be all ears to listen to the outcomes of the experience you will gain with it. BTW, when you have it working, use the strategy you've implemented for non-merge commits as well, as a good one should still work fine. Moreover, it should better bring exactly the same results as the default existing strategy being used for non-merge commits, even in conflicting situations. Hopefully /that/ experience will finally push you strong enough to get the concept right, and you will finally understand that what you've implemented is nothing else but a _cherry-pick_ of a _merge commit_, that reads simply _pick_, for brevity. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Fri, 30 Mar 2018, Sergey Organov wrote: > >> Could we please agree to stop using backward compatibility as an >> objection in the discussion of the --recreate-merges feature? > > No. > > The expectation of users as to what a `pick` is has not changed just > because you wish it would. As if I ever suggested to change user expectations. Could you please stop putting words into my mouth? I _am_ a user, and I expect 'pick' to pick commits, no matter how many parents they might have. And no, --preserve-merges did not ever pick commits with number of parents more than one, it rather threw them away and re-merged the heads. Calling it 'pick' was a huge mistake indeed! Fixing that mistake is what I expect, as a user. Just teach the 'pick' to correctly pick any commit, please! > > That is a matter of backwards-compatibility. OK, fine, at least its only about user expectations and not about some scripting incompatibility. > You see, if you are driving a car for a hundred years already, and then > switch to a different car, and it has a lever in the same place as your > previous car's windshield wiper, but in the new car it has a button that > activates the emergency driver seat ejection OMG *it has a seat ejection > like in the James Bond movies! Where can I get that car?* Sorry for > disgressing. Except it's irrelevant as the 'pick' will still pick commits. > I am really concerned about that willingness to put an innocuous button, > so to speak, onto something users got really used to, over the course of a > decade or so, when that button should really be made red and blinking and > OMG where can I get that car? It's irrelevant as the 'pick' will still pick commits. > So to reiterate, I am really interested in a practical solution that won't > cause nasty surprises. I rather don't see how it possibly could cause any surprises, especially compared to using 'merge' to pick commits. > Meaning: `pick` != merge. Exactly! Use 'merge' when you merge, as you are already doing. Use 'pick' when you are picking. You don't merge "merge commit" when you are picking it! > That was a mistake in preserve-merges, as I have only mentioned like a > hundred times, and we won't repeat it. The mistake was that it used 'pick' to denote re-merge. You already fixed that mistake by introducing 'merge' to re-merge, thanks God. Please don't commit yet another mistake by now using 'merge' to pick! -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi, > > On Thu, 29 Mar 2018, Sergey Organov wrote: > >> Jacob Keller <jacob.kel...@gmail.com> writes: >> >> > I care about the general compatibility of the rebase todo list >> > regardless of which options you enabled on the command line to >> > generate it. >> >> It's a good thing in general, yes. However, I recall I was told by the >> author that --recreate-merges was introduced exactly to break backward >> compatibility of the todo list. If so, could we please agree to stop >> using backward compatibility as an objection in the discussion of this >> particular feature? > > That is a serious misrepresentation of what I said. > > If I had changed --preserve-merges to the new format, *that* would have > broken backwards-compatibility. > > So the entire reason of introducing --recreate-merges was to *not have to > break backwards-compatibility*. > > I definitely did not say the *exact opposite*. I'm sorry I committed ambiguity in my wording that allowed it to be misinterpreted. I actually intended to say roughly the same thing you are saying, as what matters for the discussion is that new todo list format does not need to be (backward-)compatible to that of --preserve-merges. > Hopefully this clarifies your confusion, There was actually no confusion on my side, and I like your wording better. Except that you've managed to clarify your intentions without actually addressing the primary concern: Could we please agree to stop using backward compatibility as an objection in the discussion of the --recreate-merges feature? Could we? I understand you are still resistant to change 'pick' syntax, but it's not because of backward-compatibility, right? -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Jacob Keller <jacob.kel...@gmail.com> writes: > On Wed, Mar 28, 2018 at 4:29 AM, Sergey Organov <sorga...@gmail.com> wrote: > >> Jacob Keller <jacob.kel...@gmail.com> writes: >> >> > On Tue, Mar 27, 2018 at 10:57 PM, Sergey Organov <sorga...@gmail.com> >> wrote: >> >> >> >> Hi Johannes, >> >> >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > Hi Sergey, >> >> > >> >> >> >> [...] >> >> >> >> >> >> Reusing existing concepts where possible doesn`t have this >> problem. >> >> >> > >> >> >> > Existing concepts are great. As long as they fit the requirements >> of >> >> >> > the new scenarios. In this case, `pick` does *not* fit the >> > requirement >> >> >> > of "rebase a merge commit". >> >> >> >> >> >> It does, provided you use suitable syntax. >> >> > >> >> > You know what `pick` would also do, provided you use suitable syntax? >> > Pick >> >> > your nose. >> >> > >> >> > Don't blame me for this ridiculous turn the discussion took. >> >> > >> >> > Of course, using the suitable syntax you can do anything. Unless there >> > is >> >> > *already* a syntax and you cannot break it for backwards-compatibility >> >> > reasons, as is the case here. >> >> >> >> Backward compatibility to what? To a broken '--preserve-merges'? I had a >> >> feel you've invented '--recreate-merges' exactly to break that >> >> compatibility. No? >> >> >> >> Or is it "Backwards compatibility of a feature that existed only as a >> >> topic branch in `next` before being worked on more?", as you say >> >> yourself below? >> >> >> > >> > I'm pretty sure he meant that changing the meaning and behavior of "pick" >> > is incompatible, as people use scripts which check the edit lists, and >> > these scripts would expect pick to behave in a certain way. >> >> Are we still speaking about that new --recreate-merges feature? You >> already care for compatibility for it? You expect there are already >> scripts that use it? >> >> Once again, it seems like you care and don't care about backward >> compatibility at the same time, here is your phrase below: >> >> "He absolutely cares about compatibility, but in this case, the feature >> has not yet been merged into an official release." >> >> Are we still speaking about that new --recreate-merges feature? >> >> Do you guys care for compatibility for this particular --recreate-merges >> feature or not? I'm lost. "Yes" or "No" answer, if you please! >> >> -- Sergey >> > > I care about the general compatibility of the rebase todo list regardless > of which options you enabled on the command line to generate it. It's a good thing in general, yes. However, I recall I was told by the author that --recreate-merges was introduced exactly to break backward compatibility of the todo list. If so, could we please agree to stop using backward compatibility as an objection in the discussion of this particular feature? > Yes this has a bit of problem because *any* new todo command will > break the todo list, but it's better to only add new commands rather > than change semantics of existing ones. I'm not against new commands in general. I'm against inventing new entities without necessity, so, provided we did agree not to care about compatibility, there should be some other necessity to invent yet another command. I don't see such a necessity. Do you? The main principle I stand for in this discussion though is that all the commits should be treated equally as much as possible, new command or no new command. Doing otherwise will lead to all kinds of troubles and confusion, both in implementation and in user experience. Overall, what I think is needed is extending the syntax of existing todo commands to handle merge commits. This will give a provision to get it right this time. Otherwise it will likely end up being yet another subject of deprecation in the future. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Jacob Keller <jacob.kel...@gmail.com> writes: > On Tue, Mar 27, 2018 at 10:57 PM, Sergey Organov <sorga...@gmail.com> wrote: >> >> Hi Johannes, >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: [...] > I'm pretty sure the fact has already been accepted, as he did indeed > implement and develop a strategy for rebasing the merges (Phillip's > strategy). He hasn't chosen to re-write all the code such that it was > "always" this method, but rather kept it as an incremental patch on top as > it makes it easier to review the changes since we've already spent time > looking at and reviewing the --recreate-merges patches. That's perfectly OK with me, except that he apparently still can't accept the fact that rebasing a non-merge is not fundamentally different from rebasing a merge. "Rebase non-merge" is just a special case of generic "rebase commit", provided we do have generic method that is capable to rebase any commit, and we do have it, Phillip's or not. > Having watched from the sidelines, I've been unable to completely > understand and parse the strategies completely, but I've also found > Phillip's method to be easier to understand. It doesn't matter at all for this particular discussion. Let's call the method "rebase a commit", a black-box, that is capable to rebase any commit. I don't care what implementation is inside. Rebasing a commit is still rebasing a commit, and it should not be called "merge" in the todo list. > As someone who's read the discussion on the sidelines, it certainly > does feel like there is some misunderstanding on both sides. Neither > of you have been able to get the other to see what you clearly both > believe strongly. Calling "rebase" operation "merge" is wrong no matter what method is used to rebase a commit. Isn't it obvious? It's currently called "pick" in the todo and it seems natural to continue to use that name for picking a commit, whatever number of parents it happens to have. > Unfortunately I do not have any suggestion as to how to resolve the > misunderstanding. This sub-thread is not about method at all, so no resolution on that matter is required here. This sub-thread is about todo format only. > Sergey's method appears to me to be more complex, and I agree that the > extra steps could cause more merge conflicts, at least in how it was > originally conceptualized and implemented. It is possible that we are > mis-understanding the terminology for U1 and U2? It sure seems like it > introduces more changes for merge conflicts than the strategy proposed by > Phillip. However, the latest editions also sound a lot closer to Phillip's > strategy in general, so maybe I have mis-understood how it works and what > is fundamentally different about the two strategies. There is nothing fundamentally different between them and thus I don't care in this discussion what exact method is being used. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Jacob Keller <jacob.kel...@gmail.com> writes: > On Tue, Mar 27, 2018 at 10:57 PM, Sergey Organov <sorga...@gmail.com> wrote: >> >> Hi Johannes, >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> > Hi Sergey, >> > >> >> [...] >> >> >> >> Reusing existing concepts where possible doesn`t have this problem. >> >> > >> >> > Existing concepts are great. As long as they fit the requirements of >> >> > the new scenarios. In this case, `pick` does *not* fit the > requirement >> >> > of "rebase a merge commit". >> >> >> >> It does, provided you use suitable syntax. >> > >> > You know what `pick` would also do, provided you use suitable syntax? > Pick >> > your nose. >> > >> > Don't blame me for this ridiculous turn the discussion took. >> > >> > Of course, using the suitable syntax you can do anything. Unless there > is >> > *already* a syntax and you cannot break it for backwards-compatibility >> > reasons, as is the case here. >> >> Backward compatibility to what? To a broken '--preserve-merges'? I had a >> feel you've invented '--recreate-merges' exactly to break that >> compatibility. No? >> >> Or is it "Backwards compatibility of a feature that existed only as a >> topic branch in `next` before being worked on more?", as you say >> yourself below? >> > > I'm pretty sure he meant that changing the meaning and behavior of "pick" > is incompatible, as people use scripts which check the edit lists, and > these scripts would expect pick to behave in a certain way. Are we still speaking about that new --recreate-merges feature? You already care for compatibility for it? You expect there are already scripts that use it? Once again, it seems like you care and don't care about backward compatibility at the same time, here is your phrase below: "He absolutely cares about compatibility, but in this case, the feature has not yet been merged into an official release." Are we still speaking about that new --recreate-merges feature? Do you guys care for compatibility for this particular --recreate-merges feature or not? I'm lost. "Yes" or "No" answer, if you please! -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelinwrites: > Hi Sergey, > [...] >> >> Reusing existing concepts where possible doesn`t have this problem. >> > >> > Existing concepts are great. As long as they fit the requirements of >> > the new scenarios. In this case, `pick` does *not* fit the requirement >> > of "rebase a merge commit". >> >> It does, provided you use suitable syntax. > > You know what `pick` would also do, provided you use suitable syntax? Pick > your nose. > > Don't blame me for this ridiculous turn the discussion took. > > Of course, using the suitable syntax you can do anything. Unless there is > *already* a syntax and you cannot break it for backwards-compatibility > reasons, as is the case here. Backward compatibility to what? To a broken '--preserve-merges'? I had a feel you've invented '--recreate-merges' exactly to break that compatibility. No? Or is it "Backwards compatibility of a feature that existed only as a topic branch in `next` before being worked on more?", as you say yourself below? [...] >> > The implementation detail is, of course, that I will introduce this with >> > the technically-simpler strategy: always recreating merge commits with the >> > recursive strategy. A follow-up patch series will add support for rebasing >> > merge commits, and then use it by default. >> >> Switching to use it by default would be backward incompatible again? Yet >> another option to obsolete? Sigh. > > Oh wow. > > Backwards compatibility of a feature that existed only as a topic branch > in `next` before being worked on more? Any other splendid ideas? Either you care about compatibility or not. You can't have it both ways, sorry. And "technically-simpler strategy: always recreating merge commits with the recursive strategy" vs. "rebasing merge commits" is not just a minor strategy change, it's entire paradigm shift in handling merge commits while rebasing. I'm afraid you will still come up with a wrong design unless you finally accept this fact. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelinwrites: > Hi Sergey, [...] > But I'll stop here. Even my account how there are conceptual differences > between the changes in merge vs non-merge commits (the non-merge commit > *introduces* changes, the merge commit *reconciles existing* changes) > seems to fly by without convincing you. Good for you, but Git should keep caring about content, it should care not about meaning. Please leave it to the user to assign meaning to their content. If you rather want a SCM that focuses on meaning, I'd suggest to look at Bzr and see how it goes. > I use rebase every day. I use the Git garden shears every week. If you do > not trust my experience with these things, nothing will convince you. Unfortunately you have exactly zero experience with rebasing merges as you've never actually rebased them till now, and it's rebasing merges that matters in this particular discussion. > You are just stuck with your pre-existing opinion. I'm afraid that it's rather your huge experience with re-creating merges that makes you stuck to your pre-existing opinion and carefully shields you from experiencing actual paradigm shift. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Tue, 27 Mar 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > On Mon, 12 Mar 2018, Sergey Organov wrote: >> > >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > >> >> > On Wed, 7 Mar 2018, Sergey Organov wrote: >> >> > >> >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> >> >> >> >> > How can your approach -- which relies *very much* on having the >> >> >> > original parent commits -- not *require* that consistency check? >> >> >> >> >> >> I don't understand what you mean, sorry. Could you please point me >> >> >> to the *require* you talk about in the original proposal? >> >> > >> >> > Imagine a todo list that contains this line >> >> > >> >> > merge -C abcdef 123456 >> >> > >> >> > and now the user edits it (this is an interactive rebase, after >> >> > all), adding another merge head: >> >> > >> >> > merge -C abcdef 987654 123456 >> >> > >> >> > Now your strategy would have a serious problem: to find the >> >> > original version of 987654. If there was one. >> >> >> >> We are talking about different checks then. My method has a built-in >> >> check that Pillip's one doesn't. >> > >> > Since you did not bother to elaborate, I have to assume that your >> > "built-in check" is that thing where intermediate merges can give you >> > conflicts? >> > >> > If so, there is a possibility in Phillip's method for such conflicts, >> > too: we have to perform as many 3-way merges as there are parent >> > commits. >> > >> > It does make me uncomfortable to have to speculate what you meant, >> > though. >> >> It doesn't matter anymore as this check could easily be added to >> Phillip's algorithm as well, see [1]. >> >> [1] https://public-inbox.org/git/87efkn6s1h@javad.com > > Ah, and there I was, thinking that finally you would answer my questions > directly, instead you keep directing me elsewhere ("read that! Somewhere > in there you will find the answer you are looking for"). Except I've copy-pasted it for /you/ from that reference in another answer to /you/, and /you/ denied it there as being unexplained. As it actually happens to be discussed and explained in the referenced material, should I rather copy-paste the entire reference to fulfill your requirements? Here I repeat, directly again, that essential quote from that reference, in case you forgot it: git-rebase-first-parent --onto A' M tree_U1'=$(git write-tree) git merge-recursive B -- $tree_U1' B' tree=$(git write-tree) M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB') [ $conflicted_last_merge = "yes" ] || trees-match $tree_U1' $tree || stop-for-user-amendment where 'git-rebase-first-parent' denotes whatever machinery is currently being used to rebase simple non-merge commit. > My time is a bit too valuable, and I will not continue a discussion where > my questions are constantly deflected that way. No deflection on my side was ever intended. The referenced discussion actually has explanations. Maybe one whole page of reading, and it is to be read in context, and then a few follow-ups in that discussion could also be of interest, provided you are interested. I'm sorry should you have no time for that. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelinwrites: > Hi Buga, > > On Tue, 13 Mar 2018, Igor Djordjevic wrote: > >> On 12/03/2018 11:46, Johannes Schindelin wrote: >> > >> > > Sometimes one just needs to read the manual, and I don`t really >> > > think this is a ton complicated, but just something we didn`t really >> > > have before (real merge rebasing), so it requires a moment to grasp >> > > the concept. >> > >> > If that were the case, we would not keep getting bug reports about >> > --preserve-merges failing to reorder patches. >> >> Not sure where that is heading to, but what I`m arguing about is that >> introducing new commands and concepts (`merge`, and with `-R`) just >> makes the situation even worse (more stuff to grasp). > > The problem with re-using `pick` is that its concept does not apply to > merges. The cherry-pick of a non-merge commit is well-defined: the current > HEAD is implicitly chosen as the cherry-picked commit's (single) parent > commit. There is no ambiguity here. > > But for merge commits, we need to specify the parent commits (apart from > the first one) *explicitly*. There was no need for that in the `pick` > command, nor in the concept of a cherry-pick. > >> Reusing existing concepts where possible doesn`t have this problem. > > Existing concepts are great. As long as they fit the requirements of the > new scenarios. In this case, `pick` does *not* fit the requirement of > "rebase a merge commit". It does, provided you use suitable syntax. > If you really want to force the `pick` concept onto the use case where > you need to "reapply" merges, then the closest you get really is > Sergey's idea, which I came to reject when considering its practical > implications. Which one, and what are the implications that are bad, I wonder? > Even so, you would have to make the `pick` command more complicated to > support merge commits. And whatever you would do to extend the `pick` > command would *not make any sense* to the current use case of the `pick` > command. It would rather make a lot of sense. Please don't use 'merge' to pick commits, merge ones or not! > The real problem, of course, is that a non-merge commit, when viewed from > the perspective of the changes it introduced, is a very different beast > than a merge commit: it does not need to reconcile changes, ever, because > there is really only one "patch" to one revision. That is very different > from a merge commit, whose changes can even disagree with one another (and > in fact be resolved with changes disagreeing *yet again*)! You'd still 'pick' it though, not 'merge'. You don't merge "merge commit", it makes no sense. It only makes perfect sense when you get rid of original "merge commit" and re-merge from scratch, as you were doing till now. >> > > Saying in favor of `--rebase-merges`, you mean as a separate option, >> > > alongside `--recreate-merges` (once that series lands)? >> > >> > No. I am against yet another option. The only reason I pollute the >> > option name space further with --recreate-merges is that it would be >> > confusing to users if the new mode was called --preserve-merges=v2 >> > (but work *totally differently*). >> >> I see. So I take you`re thinking about renaming `--recreate-merges` to >> `--rebase-merges` instead? > > Thinking about it. Nothing will happen before v2.17.0 on that front, > though, because -- unlike you gentle people -- I have to focus on > stabilizing Git's code base now. > >> That would seem sensible, too, I think, being the default usage mode in >> the first place. Being able to actually (re)create merges, too, once >> user goes interactive, would be "just" an additional (nice and powerful) >> feature on top of it. > > The implementation detail is, of course, that I will introduce this with > the technically-simpler strategy: always recreating merge commits with the > recursive strategy. A follow-up patch series will add support for rebasing > merge commits, and then use it by default. Switching to use it by default would be backward incompatible again? Yet another option to obsolete? Sigh. -- Sergey
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Mon, 12 Mar 2018, Sergey Organov wrote: > >> [...] >> >> Yet another consequence is that my approach will likely result in better >> code reuse. > > This is a purely academic speculation. At least until somebody implements > Phillip's method. Oh wait, I already started to implement it, and it was > not exactly hard to implement: > > https://github.com/dscho/git/commit/26d2858800a4e0d3cc6313ddb54dd4d2ce516f31 Nice! Please see [1] for some recent relevant discussion. [1] https://public-inbox.org/git/87efkn6s1h@javad.com/ -- Sergey
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Dear Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Mon, 12 Mar 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > [...] >> > >> > Where "easy" meant that I had to spend 1h still to figure out why >> > using the unrebased merge parents as merge bases. >> >> That's because you try to figure out something that is not there in the >> [RFC v2]. I suggest to forget everything you've already imagined and >> just read the [RFC v2] proposal afresh. It should take about 10 minutes >> or less to get it. Really. >> >> > The same amount of time did not allow me to wrap my head around >> > Sergey's verbose explanations. >> >> Honestly, I don't believe it, sorry, but I'm willing to explain anything >> you wish to be explained in _[RFC v2]_. > > No, really. If you cannot bring yourself to believe my words, then I hate > to break it to you: I am not lying. > > As to "I'm willing to explain anything you wish to be explained in RFC > v2": I was asking, and asking, and asking again, for a simple summary of > the idea behind your proposal. Nothing. That was the answer. No. The answer rather was this simple explanation that I gave you multiple times already "rebase each side of the merge, then merge the results back using original merge commit as the merge base". Yet you say there was none. I'm confused. Well, as it seems you grok Phillip's notation just fine, here is RFC algorithm in this notation [1]: git checkout --detach A' git merge-recursive A -- A' M tree_U1'=$(git write-tree) git checkout --detach B' git merge-recursive B -- B' M tree_U2'=$(git write-tree) git merge-recursive M -- $tree_U1' $tree_U2' tree=$(git write-tree) M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB') > I had to figure it out myself: the idea is to *create* fake commits, > non-merge ones, for every single merge commit parent. Those fake commits > combine the changes of *all* merge commit parents *but one*. And then > those commits are rebased, individually, with tons of opportunities for > merge conflicts. Repeated ones. And then that result is merged. Wrong. See above. Anyway, it doesn't matter anymore, see [1]. References: [1] https://public-inbox.org/git/87efkn6s1h@javad.com -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Mon, 12 Mar 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> > >> > On Wed, 7 Mar 2018, Sergey Organov wrote: >> > >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> >> >> > How can your approach -- which relies *very much* on having the >> >> > original parent commits -- not *require* that consistency check? >> >> >> >> I don't understand what you mean, sorry. Could you please point me to >> >> the *require* you talk about in the original proposal? >> > >> > Imagine a todo list that contains this line >> > >> >merge -C abcdef 123456 >> > >> > and now the user edits it (this is an interactive rebase, after all), >> > adding another merge head: >> > >> >merge -C abcdef 987654 123456 >> > >> > Now your strategy would have a serious problem: to find the original >> > version of 987654. If there was one. >> >> We are talking about different checks then. My method has a built-in >> check that Pillip's one doesn't. > > Since you did not bother to elaborate, I have to assume that your > "built-in check" is that thing where intermediate merges can give you > conflicts? > > If so, there is a possibility in Phillip's method for such conflicts, too: > we have to perform as many 3-way merges as there are parent commits. > > It does make me uncomfortable to have to speculate what you meant, > though. It doesn't matter anymore as this check could easily be added to Phillip's algorithm as well, see [1]. [1] https://public-inbox.org/git/87efkn6s1h@javad.com
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Buga, > > On Tue, 13 Mar 2018, Igor Djordjevic wrote: > >> On 12/03/2018 13:56, Sergey Organov wrote: >> > >> > > > I agree with both of you that `pick ` is inflexible >> > > > (not to say just plain wrong), but I never thought about it like >> > > > that. >> > > > >> > > > If we are to extract further mentioned explicit old:new merge >> > > > parameter mapping to a separate discussion point, what we`re >> > > > eventually left with is just replacing this: >> > > > >> > > >merge -R -C >> > > > >> > > > ... with this: >> > > > >> > > >pick >> > > >> > > I see where you are coming from. >> > > >> > > I also see where users will be coming from. Reading a todo list in >> > > the editor is as much documentation as it is a "program to execute". >> > > And I am afraid that reading a command without even mentioning the >> > > term "merge" once is pretty misleading in this setting. >> > > >> > > And even from the theoretical point of view: cherry-picking >> > > non-merge commits is *so much different* from "rebasing merge >> > > commits" as discussed here, so much so that using the same command >> > > would be even more misleading. >> > >> > This last statement is plain wrong when applied to the method in the >> > [RFC] you are replying to. > > That is only because the RFC seems to go out of its way to break down a > single merge commit into as many commits as there are merge commit > parents. Complex entity is being split for ease of reasoning. People tend to use this often. > This is a pretty convoluted way to think about it: if you have three > parent commits, for example, that way of thinking would introduce three > intermediate commits, one with the changes of parent 2 & 3 combined, one > with the changes of parent 1 & 3 combined, and one with the changes of > parent 1 & 2 combined. No. > To rebase those commits, you essentially have to rebase *every parent's > changes twice*. No. > It gets worse with merge commits that have 4 parents. In that case, you > have to rebase every parent's changes *three times*. Sorry, the [RFC] has nothing of the above. Once again, it's still just as simple is: rebase every side of the merge then merge the results using the original merge commit as a merge base. And if you can't or don't want to grok the explanation in the RFC, just forget the explanation, no problem. > And so on. > >> > Using the method in [RFC], "cherry-pick non-merge" is nothing more or >> > less than reduced version of generic "cherry-pick merge", exactly as >> > it should be. > > I really get the impression that you reject Phillip's proposal on the > ground of not being yours. In other words, the purpose of this here > argument is to praise one proposal because of its heritage, rather than > trying to come up with the best solution. No. As the discussion evolved, I inclined to conclusion that modified Phillip's algorithm is actually better suited for the implementation [1]. > On that basis, I will go with the proposal that is clearly the simplest > and does the job and gets away with avoiding unnecessary work. These algorithms are actually the same one, as has already been shown elsewhere in the discussion. Asymmetric incremental nature of the Phillip's one is apparently better suited for naturally asymmetrical way Git already handles merging. FYI, here is the latest proposal that came out of discussion [1]: git-rebase-first-parent --onto A' M tree_U1'=$(git write-tree) git merge-recursive B -- $tree_U1' B' tree=$(git write-tree) M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB') [ $conflicted_last_merge = "yes" ] || trees-match $tree_U1' $tree || stop-for-user-amendment where 'git-rebase-first-parent' denotes whatever machinery is currently being used to rebase simple non-merge commit. > >> > Or, in other words, "cherry-pick merge" is generalization of >> > "cherry-pick non-merge" to multiple parents. >> >> I think Sergey does have a point here, his approach showing it. > > His approach is showing that he wants to shoehorn the "rebase a merge > commit" idea into a form where you can cherry-pick *something*. > > It does not have to make sense. And to me, it really does not. Except that Phillip's one does exactly this as well, only in increment
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Igor Djordjevic <igor.d.djordje...@gmail.com> writes: > Hi Sergey, > > On 19/03/2018 06:44, Sergey Organov wrote: >> >> > > > > > Second side note: if we can fast-forward, currently we prefer >> > > > > > that, and I think we should keep that behavior with -R, too. >> > > > > >> > > > > I agree. >> > > > >> > > > I'm admittedly somewhat lost in the discussion, but are you >> > > > talking fast-forward on _rebasing_ existing merge? Where would it >> > > > go in any of the suggested algorithms of rebasing and why? >> > > > >> > > > I readily see how it can break merges. E.g., any "git merge >> > > > --ff-only --no-ff" merge will magically disappear. So, even if >> > > > somehow supported, fast-forward should not be performed by default >> > > > during _rebasing_ of a merge. >> > > >> > > Hmm, now that you brought this up, I can only agree, of course. >> > > >> > > What I had in my mind was more similar to "no-rebase-cousins", like >> > > if we can get away without actually rebasing the merge but still >> > > using the original one, do it. But I guess that`s not what Johannes >> > > originally asked about. >> > > >> > > This is another definitive difference between rebasing (`pick`?) and >> > > recreating (`merge`) a merge commit - in the case where we`re rebasing, >> > > of course it doesn`t make sense to drop commit this time (due to >> > > fast-forward). This does make sense in recreating the merge (only). >> > >> > Eh, I might take this back. I think my original interpretation (and >> > agreement) to fast-forwarding is correct. >> > >> > But the confusion here comes from `--no-ff` as used for merging, as >> > opposed to `--no-ff` as used for rebasing. I _think_ Johannes meant >> > the latter one. >> > >> > In rebasing, `--no-ff` means that even if a commit inside todo list >> > isn`t to be changed, do not reuse it but create a new one. Here`s >> > excerpt from the docs[1]: >> > >> > --no-ff >> > With --interactive, cherry-pick all rebased commits instead of >> > fast-forwarding over the unchanged ones. This ensures that the >> > entire history of the rebased branch is composed of new commits. >> > >> > Without --interactive, this is a synonym for --force-rebase. >> > >> > >> > So fast-forwarding in case of rebasing (merge commits as well) is >> > something you would want by default, as it wouldn`t drop/lose >> > anything, but merely reuse existing commit (if unchanged), instead of >> > cherry-picking (rebasing) it into a new (merge) commit anyway. >> >> This sounds like breakage. E.g., it seems to be breaking every "-x ours" >> merge out there. > > Either you are not understanding how rebase fast-forward works, or > I`m missing what you are pointing to... Mind explaining how can > something that`s left unchanged suddenly become a breakage? It was misunderstanding on my side indeed, sorry. > >> Fast-forwarding existing merge, one way or another, still seems to be >> wrong idea to me, as merge commit is not only about content change, but >> also about joint point at particular place in the DAG. > > Not sure what this has to do with rebase fast-forwarding, either - > nothing changes for fast-forwarded (merge or non-merge) commit in > question, both content, joint point and everything else stays exactly > the same. If anything changed, then it can`t/won`t be fast-forwarded, > being unchanged is a prerequisite. > > Let me elaborate a bit. Here`s a starting diagram: [... detailed explanation skipped for brevity ...] > Does this settle your concerns, or I`m missing something? Yes, it does, thank you! Leaving as many leading commits as possible unchanged during rebase is what fast-forward mean in this case then, and it's pretty OK with me. >> As for fast-forwarding re-merge, explicitly requested, I'm not sure. On >> one hand, it's inline with the default "git merge" behavior, on the >> other hand, it still feels wrong, somehow. > > Regarding fast-forwarding in context of merging, in case where we are > recreating merges (not rebasing them), following existing `git merge` > logic might make sense, where I would expect rebasing todo list `merge` > command to pick-up tricks from `git merge` as needed, like learning > to accept
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Buga, Igor Djordjevic <igor.d.djordje...@gmail.com> writes: > Hi Sergey, > > On 16/03/2018 08:31, Sergey Organov wrote: >> >> > > As I said, putting myself on the user side, I'd prefer entirely >> > > separate first step of the algorithm, exactly as written, with >> > > its own conflict resolution, all running entirely the same way as >> > > it does with non-merge commits. I'm used to it and don't want to >> > > learn something new without necessity. I.e., I'd prefer to >> > > actually see it in two separate stages, like this: >> > > >> > > Rebasing mainline of the merge... >> > > [.. possible conflicts resolution ..] >> > > Merging in changes to side branch(es)... >> > > [.. possible conflicts resolution ..] >> > > >> > > And if the second stage gives non-trivial conflicts, I'd like to >> > > have a simple way to just do "merge -s ours " on top of >> > > already rebased mainline of the merge and go with it. Note that >> > > the latter is significantly different than re-merging everything >> > > from scratch, that would be the only choice with "all-in-one" >> > > approach, and it essentially gives me back those simple "rebase >> > > first parent and just record other parents" semantics when >> > > needed. >> > >> > [...] >> > >> > Also note that, for example, in case side branch(es) dropped some >> > commits (interactively or otherwise), first step alone would still >> > reintroduce those dropped changes, thus later possible `merge -s ours >> > ` would be a pretty bad "evil merge" case and a wrong thing to >> > do in general. >> >> Except that my presumption is that the second step has been run already >> and has stopped due to conflicts, so I see the conflicting result of >> dropping those commits on side branch(es), check the previous state of >> the right side of the conflicting merge, and decide those state, being >> the result of the fist step after possibly demanding conflicts >> resolution, is fine after all. Thus I just re-merge -x ours the >> branch(es), instead of re-merging everythig from scratch only to finally >> get back to the same result, be it evil or not, the hard way. > > Might be my comment missed the point here, it should have been more > about what you said regarding "first step having its own conflict > resolution" - in case of dropped commits on side branch(es), you would > be trying to resolve conflicts using one tree that doesn`t/shouldn`t > even exist anymore (rebased merge commit first parent changes), which > might be pretty confusing, only to find the "second stage" later > removing changes that you might have actually picked as "first stage" > conflict resolution, making it all even worse. > > Only once "huge merge" is done completely (meaning all steps involved > in merge commit rebasing), user can have a more realistic overview of > (possibly nested, even) conflicts to resolve (and knowing his resolution > will actually stick). > > Regarding `merge -s ours ` you mention, as you say it would > happen only after "huge merge" is complete (with possible conflicts), > I guess it`s unrelated to having "merge commit rebasing" happen in > one go ("huge merge"), or iteratively, in stages (from user`s > perspective, unrelated to underlying implementation)...? > > Thus I`m questioning use-case for step-by-step merge commit rebasing > where each stage has its own conflict resolution, in the face of it > possibly being more confusing than helpful. > > Otherwise, I see the point in what you would like to accomplish with > that `merge -s ours ` (not from scratch), but I`m not sure > what would be the most sane way to allow it, and if it would be worth > it in the first place, seeming to be a pretty exotic use case. I find your arguments sound, except that I somehow feel that "exotic use case" will solve 90% of conflicting merge rebases, as merges are about the mainline in the first place. It's likely nothing more than personal feeling though, so I'd simply agree to disagree at this point, at least until some actual experience is gained. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Igor Djordjevicwrites: > On 15/03/2018 00:11, Igor Djordjevic wrote: >> >> > > > Second side note: if we can fast-forward, currently we prefer >> > > > that, and I think we should keep that behavior with -R, too. >> > > >> > > I agree. >> > >> > I'm admittedly somewhat lost in the discussion, but are you >> > talking fast-forward on _rebasing_ existing merge? Where would it >> > go in any of the suggested algorithms of rebasing and why? >> > >> > I readily see how it can break merges. E.g., any "git merge >> > --ff-only --no-ff" merge will magically disappear. So, even if >> > somehow supported, fast-forward should not be performed by default >> > during _rebasing_ of a merge. >> >> Hmm, now that you brought this up, I can only agree, of course. >> >> What I had in my mind was more similar to "no-rebase-cousins", like >> if we can get away without actually rebasing the merge but still >> using the original one, do it. But I guess that`s not what Johannes >> originally asked about. >> >> This is another definitive difference between rebasing (`pick`?) and >> recreating (`merge`) a merge commit - in the case where we`re rebasing, >> of course it doesn`t make sense to drop commit this time (due to >> fast-forward). This does make sense in recreating the merge (only). > > Eh, I might take this back. I think my original interpretation (and > agreement) to fast-forwarding is correct. > > But the confusion here comes from `--no-ff` as used for merging, as > opposed to `--no-ff` as used for rebasing. I _think_ Johannes meant > the latter one. > > In rebasing, `--no-ff` means that even if a commit inside todo list > isn`t to be changed, do not reuse it but create a new one. Here`s > excerpt from the docs[1]: > > --no-ff > With --interactive, cherry-pick all rebased commits instead of > fast-forwarding over the unchanged ones. This ensures that the > entire history of the rebased branch is composed of new commits. > > Without --interactive, this is a synonym for --force-rebase. > > > So fast-forwarding in case of rebasing (merge commits as well) is > something you would want by default, as it wouldn`t drop/lose > anything, but merely reuse existing commit (if unchanged), instead of > cherry-picking (rebasing) it into a new (merge) commit anyway. This sounds like breakage. E.g., it seems to be breaking every "-x ours" merge out there. Fast-forwarding existing merge, one way or another, still seems to be wrong idea to me, as merge commit is not only about content change, but also about joint point at particular place in the DAG. As for fast-forwarding re-merge, explicitly requested, I'm not sure. On one hand, it's inline with the default "git merge" behavior, on the other hand, it still feels wrong, somehow. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Buga, Igor Djordjevicwrites: > Hi Sergey, [...] >> As I said, putting myself on the user side, I'd prefer entirely separate >> first step of the algorithm, exactly as written, with its own conflict >> resolution, all running entirely the same way as it does with non-merge >> commits. I'm used to it and don't want to learn something new without >> necessity. I.e., I'd prefer to actually see it in two separate stages, >> like this: >> >> Rebasing mainline of the merge... >> [.. possible conflicts resolution ..] >> Merging in changes to side branch(es)... >> [.. possible conflicts resolution ..] >> >> And if the second stage gives non-trivial conflicts, I'd like to have a >> simple way to just do "merge -s ours " on top of already rebased >> mainline of the merge and go with it. Note that the latter is >> significantly different than re-merging everything from scratch, that >> would be the only choice with "all-in-one" approach, and it essentially >> gives me back those simple "rebase first parent and just record other >> parents" semantics when needed. > > I`m undecided here, and while I do see a point in what you`re saying, > this being new to general public I dont`t think you being accustomed > to it is a very strong argument :) Sure. It's mostly that having already familiar step separate seems to be a good idea, as well as resulting isolation of the new stuff, where I readily agree not to granulate it further. As if the latter actually makes any difference... Octopus merges? I mean, really? > Yes, having more steps would mean more power/options to the user, but > more complexity to explain to and guide him through as well, not really > sure where the line should be drawn - for the first time, at least. A good thing is that while it runs smoothly it still runs smoothly both ways. > Also note that, for example, in case side branch(es) dropped some > commits (interactively or otherwise), first step alone would still > reintroduce those dropped changes, thus later possible `merge -s ours > ` would be a pretty bad "evil merge" case and a wrong thing to > do in general. Except that my presumption is that the second step has been run already and has stopped due to conflicts, so I see the conflicting result of dropping those commits on side branch(es), check the previous state of the right side of the conflicting merge, and decide those state, being the result of the fist step after possibly demanding conflicts resolution, is fine after all. Thus I just re-merge -x ours the branch(es), instead of re-merging everythig from scratch only to finally get back to the same result, be it evil or not, the hard way. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Buga, Igor Djordjevic <igor.d.djordje...@gmail.com> writes: > Hi Sergey, > > On 14/03/2018 08:21, Sergey Organov wrote: >> >> There are still 2 issues about the implementation that need to be >> discussed though: >> >> 1. Still inverted order of the second merge compared to RFC. >> >> It'd be simple to "fix" again, except I'm not sure it'd be better, and >> as there is no existing experiences with this step to follow, it >> probably should be left as in the original, where it means "merge the >> changes made in B' (w.r.t B) into our intermediate version of the >> resulting merge". >> >> The original Phillip's version seems to better fit the asymmetry between >> mainline and side-branch handling. >> >> The actual difference will be only in the order of ours vs theirs in >> conflicts though, and thus it's not that critical. > > Shouldn`t this be easy to solve just by changing the order of > and , on passing to `git merge-recursive`, if needed? (or > that`s what you meant by "simple to fix"?) Yes, that's exactly what I meant, except it looks cleaner as is, so I don't think the exchange is called for. >> 2. The U1' == U2' consistency check in RFC that I still think is worth >> to be implemented. > > At the moment, I think we`d appreciate test cases where it actually > proves useful, as the general consensus seems to be leaning towards > it possibly being annoying (over-paranoid). As we now have a simple way to actually check it even in this algorithm, I'd suggest command-line option to either relax or enforce the check, whatever the default is. For the default, I'd still opt for safety, as without it we will gather little experience with this new matter. Honestly, without this check available, I'd likely vote for at least an option for stopping on every rebased merge, on the ground that if rebasing a non-merge could be a trouble, rebasing a merge is at least double-trouble, and it's not that frequent anyway. So the check we discuss is actually a way to make all the process much less paranoid, not more. By the way, nobody yet commented about "rerere" behavior that basically stops rebasing every time it fires. Do you consider it over-paranoid? As for test cases, I have none myself, but "-s ours" merge may be an example of an actual trouble. If we don't treat it specially, then changes to side branch will be silently propagated over the merge, that's obviously not what is needed, provided user keeps his intention to leave the merge "-s ours". If we do treat it specially, it could be the case that the merge in question only looks like "-s ours" by pure accident, and thus changes to the side branch should be propagated. I don't see how we can safely proceed without stop for user assistance. Had we already achieved some consensus on this issue? > >> In application to the method being discussed, we only need the check if >> the final merge went without conflicts, so the user was not already >> involved, and the check itself is then pretty simple: >> >> "proceed without stop only if $tree = $tree_U1'" >> >> Its equivalence to the U1' == U2' test in the RFC follows from the fact >> that if M' is non-conflicting merge of U1' and U2', then M' == U1' if >> and only if U2' == U1'. > > Nicely spot! I`m glad there`s still (kind of) former U1' == U2' check > in this approach, too, in case it proves useful :) > >> Finally, here is a sketch of the implementation that I'd suggest to >> use: >> >> git-rebase-first-parent --onto A' M >> tree_U1'=$(git write-tree) >> git merge-recursive B -- $tree_U1' B' >> tree=$(git write-tree) >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB') >> [ $conflicted_last_merge = "yes" ] || >> trees-match $tree_U1' $tree || >> stop-for-user-amendment > > Yes, in case where we would want the "no-op merge" check (equivalent > to U1' == U2' with original approach), this aligns with something I > would expect. > > Note that all the "rebase merge commit" steps leading to the check > will/should probably be observed as a single one from user`s perspective > (in worst case ending with nested conflicts we discussed), thus > `$conflicted_last_merge` is not related to `merge-recursive` step(s) > only, but `rebase-first-parent`, too (just in case this isn`t implied). > > Might be easier to reason about simply as `[ $conflicts = "yes" ] || ` No. For this check it's essential to ensure that no tweaking of the content has been performed under the hood after the user has resolved conflicts, i.e., after he has been involved last
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Buga, Igor Djordjevic <igor.d.djordje...@gmail.com> writes: > On 14/03/2018 15:24, Sergey Organov wrote: [...] >> Thinking about it I've got an idea that what we actually need is >> --no-flatten flag that, when used alone, will just tell "git rebase" to >> stop flattening history, and which will be implicitly imposed by >> --recreate-merges (and --preserve-merges). >> >> Then the only thing the --recreate-merges will tune is to put 'merge' >> directives into the todo list for merge commits, exactly according to >> what its name suggests, while the default behavior will be to put 'pick' >> with suitable syntax into the todo. And arguments to the >> --recreate-merge will specify additional options for the 'merge' >> directive, obviously. > > This seem to basically boil down to what I mentioned previously[2] > through use of new `--rebase-merges` alongside `--recreate-merges`, just > that you named it `--no-flatten` here, but the point is the same - and > not something Johannes liked, "polluting" rebase option space further. Not quite so. The problem with --XXX-merges flags is that they do two things at once: they say _what_ to do and _how_ to do it. Clean UI designs usually have these things separate, and that's what I propose. The --[no-]flatten says _what_ (not) to do, and --recreate-merges says _how_ exactly it will be performed. In this model --no-flatten could have been called, say --preserve-shape, but not --rebase-merges. To minimize pollution, the _how_ part could rather be made option value: --no-flatten[=] where is 'rebase', 'remerge', etc. In this case we will need separate option to specify strategy options, if required, that will lead us to something similar to the set of merge strategies options. > I would agree with him, and settling onto `--rebase-merges` _instead_ of > `--recreate-merges` seems as a more appropriate name, indeed, now that > default behavior is actually merge commit rebasing and not recreating > (recreating still being possible through user editing the todo list). I hope he'd be pleased to be able to say --no-flatten=remerge and get back his current mode of operation, that he obviously has a good use for. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Igor Djordjevicwrites: > Hi Dscho, > > On 07/03/2018 08:26, Johannes Schindelin wrote: [...] >> Second side note: if we can fast-forward, currently we prefer that, and I >> think we should keep that behavior with -R, too. > > I agree. I'm admittedly somewhat lost in the discussion, but are you talking fast-forward on _rebasing_ existing merge? Where would it go in any of the suggested algorithms of rebasing and why? I readily see how it can break merges. E.g., any "git merge --ff-only --no-ff" merge will magically disappear. So, even if somehow supported, fast-forward should not be performed by default during _rebasing_ of a merge. >> If the user wants to force a new merge, they simply remove that -R >> flag. Alternatively, they'd replace 'pick' with 'merge', as they already do for other actions. "A plurality is not to be posited without necessity". Please, _please_, don't use 'merge' command to 'pick' merge commits! It's utterly confusing! Thinking about it I've got an idea that what we actually need is --no-flatten flag that, when used alone, will just tell "git rebase" to stop flattening history, and which will be implicitly imposed by --recreate-merges (and --preserve-merges). Then the only thing the --recreate-merges will tune is to put 'merge' directives into the todo list for merge commits, exactly according to what its name suggests, while the default behavior will be to put 'pick' with suitable syntax into the todo. And arguments to the --recreate-merge will specify additional options for the 'merge' directive, obviously. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Buga, Igor Djordjevic <igor.d.djordje...@gmail.com> writes: > Hi Sergey, > > On 13/03/2018 17:10, Sergey Organov wrote: >> >> > Hi Sergey, I've been following this discussion from the sidelines, >> > though I haven't had time to study all the posts in this thread in >> > detail. I wonder if it would be helpful to think of rebasing a merge as >> > merging the changes in the parents due to the rebase back into the >> > original merge. So for a merge M with parents A B C that are rebased to >> > A' B' C' the rebased merge M' would be constructed by (ignoring shell >> > quoting issues) >> > >> > git checkout --detach M >> > git merge-recursive A -- M A' >> > tree=$(git write-tree) >> > git merge-recursive B -- $tree B' >> > tree=$(git write-tree) >> > git merge-recursive C -- $tree C' >> > tree=$(git write-tree) >> > M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC') >> >> I wonder if it's OK to exchange the order of heads in the first merge >> (also dropped C for brevity): > > It should be, being "left" or "right" hand side ("theirs" or "ours") > of the three-way merge shouldn`t matter, they`re still both equally > compared to the merge-base. > >> git checkout --detach A' >> git merge-recursive A -- A' M >> tree=$(git write-tree) >> git merge-recursive B -- $tree B' >> tree=$(git write-tree) >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB') >> >> If so, don't the first 2 lines now read: "rebase (first parent of) M on >> top of A'"? > > Hmm, lol, yes...? :) So basically, this: > > (1) git checkout --detach M > git merge-recursive A -- M A' > tree=$(git write-tree) > ... > > ... is equivalent to this: > > (2) git checkout --detach A' > git merge-recursive A -- A' M > tree=$(git write-tree) > ... > > ..., being equivalent to this: > > (3) git checkout --detach A' > git cherry-pick -m 1 M > tree=$(git write-tree) > ... > > ..., where in all three cases that `$tree` is equivalent to U1' we > discussed about so much already :) Exactly, and thanks for noticing that it's actually U1', that happens to soon become rather handy, see below. > I tested it like this as well, slightly modifying previously sent out > script (like this one[1]), and it still seems to be working ;) Nice! Very nice of you, thanks! Yet another outcome of this transformation is that the fist step is now free to (and probably should) utilize all the options (-s, -X, etc.) that usual rebase has: git-rebase-first-parent --onto A' M tree=$(git write-tree) where 'git-rebase-first-parent' is whatever machinery is currently being used to rebase simple non-merge commit. [ Moreover, Phillip's method could further be transformed to what is in RFC, not that I think it should, see below. Just for the sake of completeness though, here is the essential missing transformation that makes Phillip's method symmetric, after which it becomes true special case of the RFC with particular rebase-first-parent implementation: git checkout --detach A' git merge-recursive A -- A' M tree_U1'=$(git write-tree) git checkout --detach B' git merge-recursive B -- B' M tree_U2'=$(git write-tree) git merge-recursive M -- $tree_U1' $tree_U2' tree=$(git write-tree) M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB') ] > >> If so, then it could be implemented so that it reduces back to regular >> rebase of non-merges when applied to a single-parent commit, similar to >> the method in the RFC, striking out one of advantages of the RFC. > > I guess so, but I think it now boils down only to what one finds > easier to reason about even more. I actually think there is more to it. It's incremental asymmetric nature of the Phillip's approach that I now find rather appealing and worth to be used in practice. While the RFC approach, being entirely symmetric, is nice from the POV of theory and reasoning, yet simple to implement, the actual user interface of Git is inherently asymmetric with respect to merges (one merges side-branch(es) to mainline), so asymmetric approach of the Phillip's method should give smoother user experience, even if only because of 1 less merge. There are still 2 issues about the implementation that need to be discussed though: 1. Still inverted order of the second merge compared to RFC. It'd be simple to "fix" again, except I'm not sure it'd be better, and as there is no existing experiences with this step to follow, it probably should be left as in the original, where it means "merge the changes made in B' (w.r.t B) into our i
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Phillip, Phillip Woodwrites: [...] > Hi Sergey, I've been following this discussion from the sidelines, > though I haven't had time to study all the posts in this thread in > detail. I wonder if it would be helpful to think of rebasing a merge as > merging the changes in the parents due to the rebase back into the > original merge. So for a merge M with parents A B C that are rebased to > A' B' C' the rebased merge M' would be constructed by (ignoring shell > quoting issues) > > git checkout --detach M > git merge-recursive A -- M A' > tree=$(git write-tree) > git merge-recursive B -- $tree B' > tree=$(git write-tree) > git merge-recursive C -- $tree C' > tree=$(git write-tree) > M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC') I wonder if it's OK to exchange the order of heads in the first merge (also dropped C for brevity): git checkout --detach A' git merge-recursive A -- A' M tree=$(git write-tree) git merge-recursive B -- $tree B' tree=$(git write-tree) M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB') If so, don't the first 2 lines now read: "rebase (first parent of) M on top of A'"? If so, then it could be implemented so that it reduces back to regular rebase of non-merges when applied to a single-parent commit, similar to the method in the RFC, striking out one of advantages of the RFC. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Buga, Igor Djordjevicwrites: [...] > I don`t know, I`m thinking if we are looking at todo list from > different perspectives - to you, it seems to be a sequence of > commands to create something new (yes, from something that already > exists, but that`s implementation detail). In that context, using > `merge` might have sense (even if still being a very special merge). > > But to me, as we already have `pick` and not `commit` to rebase > commits, it means we are not creating but rather reusing what we have > (being an important concept to reason about), thus `pick` would still > fit in for picking a merge commit just nicely, and more naturally, > too. Exactly. Fundamentally, a good editing tool should first be able to just safely reproduce back what it got, only then everything else goes. >From this follows that git history-editing tool should start from sound history representation, i.e., some text representation of the DAG that allows to re-create the DAG back. The simplest way is to just list all the nodes in some topological order, along with references to the parents. Then, to simplify the list, first parent, unless explicitly specified, could be assumed to be the preceding item in the list. Next, we actually need _to do_ something with this, so we convert this to a _todo_ list by prepending action to each element of the list (isn't it Lisp once again?). Let the action be called 'pick'. Then, e.g., the piece of history: B1---B2 / \ S--M0---M1 M2 M3 -- M4 from M0 to M4 will be represented like this: skip S # Just to have a handy reference pick M0 # Implicit first parent (S) pick M1 # Implicit first parent (M0) pick M2 # Implicit first parent (M1) pick B1 M1 # Explicit first parent pick B2 # Implicit first parent (B1) pick M3 M2 B2 # Explicit first and second parents pick M4 Which basically gets us back to what you are advocating. Here is another variant, using command options to specify parents (I also exchanged order of branch and mainline): skip S # To have the base reference handy pick M0 # Implicit first parent (S) pick B1 # Implicit first parent (M0) pick B2 # Implicit first parent (B1) pick M1 -1 M0 # Explicit first parent M0 pick M2 # Implicit first parent (M1) pick M3 -2 B2 # Implicit first parent (M2) and # explicit second parent B2 pick M4 # Implicit first parent (M3) I like this one even better. IMHO, this is indeed a good starting point. No special treatment for merges is needed so far. -- Sergey
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelinwrites: [...] > The biggest difference is that it is easy for me to see the motivation > behind Phillip's strategy, whereas I am still puzzled why one would come > up with a complicated strategy that splits merge commits and re-merges > them later, and why it should work in general (I still suspect that this > is not the case). Because I believe that rebasing simple commit (1 parent) should be nothing else but reduced version of rebasing any commit (N parents) at N=1. The [RFC v2] being discussed provides exactly such a method. OTOH, check what Phillip's version does at N=1. Is it the same as "rebase simple commit" strategy you already happily use? If not, please explain why it must be different. > Where "easy" meant that I had to spend 1h still to figure out why using > the unrebased merge parents as merge bases. That's because you try to figure out something that is not there in the [RFC v2]. I suggest to forget everything you've already imagined and just read the [RFC v2] proposal afresh. It should take about 10 minutes or less to get it. Really. > The same amount of time did not allow me to wrap my head around > Sergey's verbose explanations. Honestly, I don't believe it, sorry, but I'm willing to explain anything you wish to be explained in _[RFC v2]_. > But I'll take your word for it that the strategies are equivalent, and go > with the one that has both a simpler explanation (in my mind, at least), > and an more robust implementation. It's up to you, and it'd still be much better than what we have now, but you will need to face the (I think unfortunate) consequences I just summarized elsewhere in the thread. -- Sergey
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Buga, Igor Djordjevicwrites: > Hi Dscho, [...] > I think the root of misunderstanding might be coming from the fact > that Sergey was mainly describing a general concept (without a > strictly defined implementation strategy, not being restricted to a > specific one), where Phillip came up with a solution that eventually > seems to use the same concept (as those transformations above should > show), but simplifying it further inside a concrete implementation. As a side-note, starting from sound general concept leaves a hope to end-up with something like Git, while starting from an implementation, however nice it is, gives a danger of ending-up with something like Bzr. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Johannes, Johannes Schindelinwrites: > Hi Buga, > > On Sun, 11 Mar 2018, Igor Djordjevic wrote: > >> I agree with both of you that `pick ` is inflexible >> (not to say just plain wrong), but I never thought about it like that. >> >> If we are to extract further mentioned explicit old:new merge >> parameter mapping to a separate discussion point, what we`re >> eventually left with is just replacing this: >> >> merge -R -C >> >> ... with this: >> >> pick > > I see where you are coming from. > > I also see where users will be coming from. Reading a todo list in the > editor is as much documentation as it is a "program to execute". And I am > afraid that reading a command without even mentioning the term "merge" > once is pretty misleading in this setting. > > And even from the theoretical point of view: cherry-picking non-merge > commits is *so much different* from "rebasing merge commits" as discussed > here, so much so that using the same command would be even more > misleading. This last statement is plain wrong when applied to the method in the [RFC] you are replying to. Using the method in [RFC], "cherry-pick non-merge" is nothing more or less than reduced version of generic "cherry-pick merge", exactly as it should be. Or, in other words, "cherry-pick merge" is generalization of "cherry-pick non-merge" to multiple parents. -- Sergey
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelinwrites: > Hi Sergey, [...] > That is misrepresenting what happened. No, it's you who are spreading misinformation, probably unintentional, but still. > First, you came up with a strategy. I pointed out shortcomings that > implied that we cannot use it unchanged. Then, Buga fixed your strategy by > using additional steps (making the process more complicated than before, > still without a simple-enough explanation for my liking, fixing the > shortcomings). Then, Phillip presented a super-simple strategy and Buga > confirmed that it also fixes the shortcomings I pointed out. Except that you've missed very essential thing: even before Phillip presented his method, the original has been fixed and simultaneously became even simpler. It's now entirely described in [RFC v2] that you apparently still refuse to read. > I am very excited that we finally found something that works *and* is easy > to reason about. You have chances to be even more exited as we in fact have 2 of them that both work and are both easy to reason about. > Let's focus on that strategy rather than going back to the strategy which > has known flaws and only an unsatisfyingly complex explanation. Not that fast, as it now has no known flaws and still has surprisingly simple explanation. It also has its own niceties that are currently being discussed elsewhere in the thread. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Wed, 7 Mar 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > How can your approach -- which relies *very much* on having the >> > original parent commits -- not *require* that consistency check? >> >> I don't understand what you mean, sorry. Could you please point me to >> the *require* you talk about in the original proposal? > > Imagine a todo list that contains this line > > merge -C abcdef 123456 > > and now the user edits it (this is an interactive rebase, after all), > adding another merge head: > > merge -C abcdef 987654 123456 > > Now your strategy would have a serious problem: to find the original > version of 987654. If there was one. We are talking about different checks then. My method has a built-in check that Pillip's one doesn't. All the external checks, if any, will have to be the same. > >> > What would your approach (that still has no satisfyingly trivial >> > explanation, in my mind) >> >> Here is one-liner: rebase sides of the merge commit and then 3-way >> merge them, using original merge commit as merge base. > > But I already pointed out how that would undo a commit having been > dropped. No. Not for this version. You did it for originally flawed version of the method, that has been already fixed by addition of "using original merge commit as merge base" in the above sentence, and that was the exact reason for [RFC v2], that in turn is explicitly stated at the beginning of [RFC v2]. > >> > do if somebody edited a `merge` command and let it merge a completely >> > unrelated commit? >> >> Don't see a problem, sorry. The method should still work, provided you have >> original merge commit and two new parents for the new merge. > > That is assuming a lot. That is exactly what this consistency check is > for, that I mentioned earlier, and which you listed as a downside of > Phillip's strategy (forgetting that your strategy has the same downside, > so...). Again, we are talking about different checks. My method has a built-in check that Pillip's doesn't. All the external checks, if any, will have to be the same. > But I guess that you are still talking about the non-interactive version > of the rebase, and missed that our conversation proceeded to the point > where we want that same strategy to work *also* in the interactive version > (and not have a completely different functionality depending whether you > use --interactive or not)? For me, non-interactive is an interactive one with unmodified todo list. -- Sergey
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Buga, Igor Djordjevicwrites: [...] > That said, *if* we decide we like temporary commit U1' == U2' consistency > check (especially for non-interactive rebase, maybe), we can produce > these after the fact for the sake of the check only. I don't believe interactive vs. non-interactive split is actually helpful. I'd consider non-interactive just a special case of interactive when user didn't edit the todo list, nothing more. No special treatment should be required. For one, consistency checks in both modes has similar importance, even if only because there could be parts of history being interactively rebased which the user didn't intend to edit, nor actually edited during given session. Now let me get back to pros and cons of the two approaches to rebasing merges we have. Below I still advocate my approach by further discussing the differences, but simultaneously I'd like to emphasize that whatever particular way of rebasing merges will finally be used, it will be a huge step forward and I'm glad I've raised the issue in the first place. First, please consider the fact that my "rebase sides" method has yet another nice property: it reduces back to original "rebase the commit" operation when you apply it to a non-merge commit. In other words, it's true generalization on top of rebasing of simple commit. OTOH, Phillip's approach, when reduced to non-merge commit, still does a version of rebase, but very specific one, and in inverse manner. I.e., rather than merging changes of the commit to be rebased into the new base, it merges changes introduced by the new base into the commit being rebased. One consequence is that when conflict occurs, Phillip's approach will give surprising order of ours vs theirs changes, inverted with respect to those of the usual rebase of non-merge commit, while my approach will give exact non-merge commit semantics. It could likely be fixed by slightly modifying Phillip's approach, but it will make its implementation more complex. Another consequence is that, provided my version is used, all options that tune "simple commit rebase" behavior will automagically work for rebasing merge commits, in exactly the same manner. OTOH, Phillip's approach, without special attention in implementation, will do the same thing no matter what -m -s, or -X options say. Yet another consequence is that my approach will likely result in better code reuse. Even though mine seems to be harder to implement stand-alone than Phillip's one, it should be actually easier to implement inside the "git rebase", as it will use exactly the same machinery that "git rebase" already uses to rebase simple commits, adding only final "git merge-recursive" (or "git merge-resolve", or "git merge-octopus", -- any of them will do the job), which current implementation already performs as well, for re-creating merges from scratch. Second thought, unrelated to the above. To me it seems that my "rebasing sides" approach, being entirely symmetric, is cleaner than incremental merging suggested by Phillip, as with my approach one will still deal with branches independently, in the same way as for simple commits, until the single final merge operation. This comes with drawback of 1 additional step in my approach when compared to the Phillip's one though, but then mine has definitely no issues with the exact order of merges. Overall, to me it seems that unmodified Phillip's approach will bring unnecessarily wide set of new user experiences, and fixing it will require some tricks in implementation, for no apparent reason. -- Sergey
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Wed, 7 Mar 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > On Tue, 6 Mar 2018, Sergey Organov wrote: >> > >> >> This is v2 of my "Rebasing merges" proposal. >> > >> > Didn't we settle on Phillip's "perform successive three-way merges >> > between the original merge commit and the new tips with the old tips >> > as base" strategy? >> >> It seems you did, dunno exactly why. > > That is not true. You make it sound like I was the only one who liked > this, and not Phillip and Buga, too. > > Are you interested in the best solution, or in your solution :-) I'm interested in any that works, and only you say that those suggested by Phillip is somehow superior. I still believe it's mine that superior, even if slightly. > >> The main problem with this decision is that we still don't see how and >> when to stop for user amendment using this method. OTOH, the original >> has this issue carefully discussed. > > Why would we want to stop, unless there are merge conflicts? There is somewhat lengthy discussion about it that you probably missed. Not to repeat it, just see how 'rerere' works when it fires during rebase, even with no conflicts. > >> > It has the following advantages: >> > >> > - it is *very simple* to describe >> >> The original is as simple if not simpler: >> >> "rebase sides of the merge commit and then three-way merge them back >> using original merge commit as base" > > And that is also wrong, as I had proved already! Only Buga's addition made > it robust against dropping/modifying commits, and that addition also makes > it more complicated. No. Get your facts straight. The [RFC v2] already fixed that original mistake. Could you please finally read it? > And it still has no satisfactory simple explanation why it works. It has. It's there in the [RFC v2]. You seem to be the only one who doesn't get it. I suppose you just didn't bother to read. >> No problems with octopuses, and no virtual merge bases of recursive >> merges to reason about. > > But those are no problems for Phillip's strategy, either! I thought it was you who started to discuss virtual merge bases and related problems, as well as how it's difficult to support octopus merges, but it's fine with me if there are none of these problems. > > So your point is...? Still the same -- use what's better, the [RFC v2]. > >> > - it is *very easy* to reason about, once it is pointed out that >> > rebases and merges result in the same trees. >> >> The original is as easy to reason about, if not easier, especially as >> recursive merge strategy is not being used there in new ways. > > So do it. I still have to hear a single-sentence, clear and obvious > explanation why it works. > > And please do not describe why your original version works, because it > does not work. Original [RFC] didn't work because of rather simple mistake that I've already admitted and fixed. [RFC v2] has got the fix. Read [RFC v2] and get your facts straight. > Describe why the one amended with Buga's hack works. It doesn't matter as these hacks are not needed anymore. > >> I honestly don't see any advantages of Phillip's method over the >> original, except personal preferences. At the same time, I have no >> objection of using it either, provided consistency check problem is >> solved there as well. > > Okay, let me reiterate then, because I do not want this point to be > missed: > > Phillip's method is essentially merging the new tips into the original > merge, pretending that the new tips were not rebased but merged into > upstream. > > So it exploits the duality of the rebase and merge operation, which both > result in identical trees (potentially after resolving merge > conflicts). > > I cannot think of any such interpretation for your proposal augmented by > Buga's fix-ups. And I haven't heard any such interpretation from your > side, either. No fix-ups or augmentations are needed. It was a mistake that has been fixed in [RFC v2]. You've missed essential part of the discussion. Read the [RFC v2], please: Significant changes are: 1. Fixed mistake in the final merge step in the original proposal: wrong merge base was used. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Wed, 7 Mar 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > On Tue, 6 Mar 2018, Phillip Wood wrote: >> > >> >> On 03/03/18 00:29, Igor Djordjevic wrote: >> >> > >> >> > On 02/03/2018 12:31, Phillip Wood wrote: >> >> >> >> >> >>> Thinking about it overnight, I now suspect that original proposal >> >> >>> had a mistake in the final merge step. I think that what you did is >> >> >>> a way to fix it, and I want to try to figure what exactly was wrong >> >> >>> in the original proposal and to find simpler way of doing it right. >> >> >>> >> >> >>> The likely solution is to use original UM as a merge-base for final >> >> >>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty >> >> >>> natural though, as that's exactly UM from which both U1' and U2' >> >> >>> have diverged due to rebasing and other history editing. >> >> >> >> >> >> Hi Sergey, I've been following this discussion from the sidelines, >> >> >> though I haven't had time to study all the posts in this thread in >> >> >> detail. I wonder if it would be helpful to think of rebasing a merge >> >> >> as merging the changes in the parents due to the rebase back into the >> >> >> original merge. So for a merge M with parents A B C that are rebased >> >> >> to A' B' C' the rebased merge M' would be constructed by (ignoring >> >> >> shell quoting issues) >> >> >> >> >> >> git checkout --detach M >> >> >> git merge-recursive A -- M A' >> >> >> tree=$(git write-tree) >> >> >> git merge-recursive B -- $tree B' >> >> >> tree=$(git write-tree) >> >> >> git merge-recursive C -- $tree C' >> >> >> tree=$(git write-tree) >> >> >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC') >> >> >> >> >> >> This should pull in all the changes from the parents while preserving >> >> >> any evil conflict resolution in the original merge. It superficially >> >> >> reminds me of incremental merging [1] but it's so long since I looked >> >> >> at >> >> >> that I'm not sure if there are any significant similarities. >> >> >> >> >> >> [1] https://github.com/mhagger/git-imerge >> >> > >> >> > Interesting, from quick test[3], this seems to produce the same >> >> > result as that other test I previously provided[2], where temporary >> >> > commits U1' and U2' are finally merged with original M as a base :) >> >> > >> >> > Just that this looks like even more straight-forward approach...? >> >> > >> >> > The only thing I wonder of here is how would we check if the >> >> > "rebased" merge M' was "clean", or should we stop for user amendment? >> >> > With that other approach Sergey described, we have U1'==U2' to test >> >> > with. >> >> >> >> I think (though I haven't rigorously proved to myself) that in the >> >> absence of conflicts this scheme has well defined semantics (the merges >> >> can be commuted), so the result should be predicable from the users >> >> point of view so maybe it could just offer an option to stop. >> > >> > I am not so sure that the result is independent of the order of the >> > merges. In other words, I am not necessarily certain that it is impossible >> > to concoct A,A',B,B' commits where merging B'/B before A'/A has a >> > different result than merging A'/A before B'/B. >> > >> > Remember, when constructing counter-examples to hypotheses, those >> > counter-examples do not really *have* to make sense on their own. For >> > example, A' could introduce *completely different* changes from A, and the >> > same is true for B' and B. >> > >> > I could imagine, for example, that using a ton of consecutive empty lines, >> > and using patches that insert something into these empty lines (and are >> > thusly inherently ambiguous when said set of empty lines has changed), >> > could even intro
Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Tue, 6 Mar 2018, Sergey Organov wrote: > >> This is v2 of my "Rebasing merges" proposal. > > Didn't we settle on Phillip's "perform successive three-way merges between > the original merge commit and the new tips with the old tips as base" > strategy? It seems you did, dunno exactly why. The main problem with this decision is that we still don't see how and when to stop for user amendment using this method. OTOH, the original has this issue carefully discussed. > It has the following advantages: > > - it is *very simple* to describe The original is as simple if not simpler: "rebase sides of the merge commit and then three-way merge them back using original merge commit as base" No problems with octopuses, and no virtual merge bases of recursive merges to reason about. > - it is *very easy* to reason about, once it is pointed out that rebases > and merges result in the same trees. The original is as easy to reason about, if not easier, especially as recursive merge strategy is not being used there in new ways. I honestly don't see any advantages of Phillip's method over the original, except personal preferences. At the same time, I have no objection of using it either, provided consistency check problem is solved there as well. > > ... and BTW... > >> 3. I now use "True Merge" name instead of former "Trivial Merge", to >>avoid confusion with what Git documentation calls "trivial merge", >>thanks to Junio C Hamano <gits...@pobox.com> for pointing this out. > > "True Merge" is probably also a candidate for improvement. If what you > refer to is a "true" merge, that means all others are "untrue" > merges??? [d]evil merges, obviously. Seriously, it's pure history joint. Just "joint' will do. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelinwrites: > Hi Phillip, > > On Tue, 6 Mar 2018, Phillip Wood wrote: > >> On 03/03/18 00:29, Igor Djordjevic wrote: >> > >> > On 02/03/2018 12:31, Phillip Wood wrote: >> >> >> >>> Thinking about it overnight, I now suspect that original proposal >> >>> had a mistake in the final merge step. I think that what you did is >> >>> a way to fix it, and I want to try to figure what exactly was wrong >> >>> in the original proposal and to find simpler way of doing it right. >> >>> >> >>> The likely solution is to use original UM as a merge-base for final >> >>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty >> >>> natural though, as that's exactly UM from which both U1' and U2' >> >>> have diverged due to rebasing and other history editing. >> >> >> >> Hi Sergey, I've been following this discussion from the sidelines, >> >> though I haven't had time to study all the posts in this thread in >> >> detail. I wonder if it would be helpful to think of rebasing a merge >> >> as merging the changes in the parents due to the rebase back into the >> >> original merge. So for a merge M with parents A B C that are rebased >> >> to A' B' C' the rebased merge M' would be constructed by (ignoring >> >> shell quoting issues) >> >> >> >> git checkout --detach M >> >> git merge-recursive A -- M A' >> >> tree=$(git write-tree) >> >> git merge-recursive B -- $tree B' >> >> tree=$(git write-tree) >> >> git merge-recursive C -- $tree C' >> >> tree=$(git write-tree) >> >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC') >> >> >> >> This should pull in all the changes from the parents while preserving >> >> any evil conflict resolution in the original merge. It superficially >> >> reminds me of incremental merging [1] but it's so long since I looked at >> >> that I'm not sure if there are any significant similarities. >> >> >> >> [1] https://github.com/mhagger/git-imerge >> > >> > Interesting, from quick test[3], this seems to produce the same >> > result as that other test I previously provided[2], where temporary >> > commits U1' and U2' are finally merged with original M as a base :) >> > >> > Just that this looks like even more straight-forward approach...? >> > >> > The only thing I wonder of here is how would we check if the >> > "rebased" merge M' was "clean", or should we stop for user amendment? >> > With that other approach Sergey described, we have U1'==U2' to test with. >> >> I think (though I haven't rigorously proved to myself) that in the >> absence of conflicts this scheme has well defined semantics (the merges >> can be commuted), so the result should be predicable from the users >> point of view so maybe it could just offer an option to stop. > > I am not so sure that the result is independent of the order of the > merges. In other words, I am not necessarily certain that it is impossible > to concoct A,A',B,B' commits where merging B'/B before A'/A has a > different result than merging A'/A before B'/B. > > Remember, when constructing counter-examples to hypotheses, those > counter-examples do not really *have* to make sense on their own. For > example, A' could introduce *completely different* changes from A, and the > same is true for B' and B. > > I could imagine, for example, that using a ton of consecutive empty lines, > and using patches that insert something into these empty lines (and are > thusly inherently ambiguous when said set of empty lines has changed), > could even introduce a merge conflict in one order, but no conflict in the > other. > > Even so, I think that merging in the order of the parents makes the most > sense, and that using that strategy makes sense, too, because you really > have to try hard to make it fail. Alternatively, consider to adopt the original approach that has none of these issues as it uses exactly the same method for rebasing merge commits that you are already using for rebasing simple commits, not to mention the advantage of the built-in consistency check. -- Sergey
[RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi, This is v2 of my "Rebasing merges" proposal. Significant changes are: 1. Fixed mistake in the final merge step in the original proposal: wrong merge base was used. Thanks everybody who provided test-cases, and special thanks to Igor Djordjevicfor implementing and testing a few variants of the method. 2. Added discussion of the exact place where handling of special frequent cases such as "git merge -ours", if any, should go. 3. I now use "True Merge" name instead of former "Trivial Merge", to avoid confusion with what Git documentation calls "trivial merge", thanks to Junio C Hamano for pointing this out. During discussion of the original proposal, yet another way of implementing a true rebase of a merge commit has been suggested by Phillip Wood [1]. His method also gathers the changes on both sides of the merge and then merges them back to the original merge, so both methods have similar concept and differ in implementation. It looks like both implementations bring the same result, at least it was so in the limited testing that Igor performed. [1] https://public-inbox.org/git/6c8749ca-ec5d-b4b7-f1a0-50d9ad294...@talktalk.net/ ---8<-8<-- By accepting the challenges raised in recent discussion of advanced support for history rebasing and editing in Git, I hopefully figured out a clean and elegant method of rebasing merges that I think is "The Right Way (TM)" to perform this so far troublesome operation. ["(TM)" here has second meaning: "True Merge" (TM), see below.] Let me begin with quick outline of the method, to illustrate the simplicity of the approach, and special thanks here must go to "Johannes Sixt" for his original bright idea to use "cherry-pick -m1" to rebase merge commits. Given 2 original branches, b1 and b2, and a merge commit M that joins them, suppose we've already rebased b1 to b1', and b2 to b2'. Suppose also that B1' and B2' happen to be the tip commits on b1' and b2', respectively. To produce merge commit M' that joins b1' and b2', the following operations will suffice: 1. Checkout b2' and cherry-pick -m2 M, to produce U2' (and new b2'). 2. Checkout b1' and cherry-pick -m1 M, to produce U1' (and new b1'). 3. Perform 3-way merge of U1' and U2' using original M as merge base, to get UM'. 4. Get rid of U1' and U2' by re-writing parent references of UM' from U1' and U2' to B1' and B2', respectively, to produce M'. 5. Mission complete. Let's now turn to the method itself and see why and how it actually works. First off, let me introduce you to my new friend, the True Merge, or (TM) for short. By definition, (TM) is a merge that brings absolutely no differences to the sides of the merge. (I also like to call him "Angel Merge" (AM), both as being the most beautiful of all merges, and as direct antithesis to "[d]evil merge"; or even "Perfect Merge" (PM), but the latter goes after lunch time.) Being trivial history joint and nothing else, (TM)/(AM)/(PM) is safe and easy to be rebased (see below). However, since most of us have never met (TM) in practice, you probably wonder how (TM) can actually help us handle general case of rebasing of some random merge. Let's start with this history: M / \ B1 B2 where B1 and B2 are tip commits of 2 branches, and M is the merge commit that joins them. Let's transform this history to the following one, contextually equivalent to the original, by introducing 2 non-merge utility commits U1 and U2, and a new utility merge commit UM: UM / \ U1 U2 || B1 B2 were contents of all the created commits match, and are exact copies of the original content of M. I.e., provided [A] denotes "content of commit A", we have: [UM] = [U1] = [U2] = [M] Stress again how these changes to the history preserve the exact content of the original merge ([UM] = [M]), how U1 an U2 represent content changes due to the merge on either side[*], and how content of neither preceding nor subsequent commits is affected by the change of representation. Now observe that as [U1] = [UM], and [U2] = [UM], the UM happens to be exactly our new friend -- the "True Merge (TM)" his true self, introducing exactly zero changes to content. Pure history joint. Next, we separately rebase both branches of our new representation of the history to whatever new base we need, and we get: U1' U2' || B1' B2' where U1' and U2' are rebased versions of U1 and U2, obtained by usual rebasing methods for non-merge commits. Finally, let's merge back our branches. To perform the right kind of merge, notice that U1' and U2' have diverged from U1 and U2, respectively. Further, provided [U1] = [U2] = [UM] = [M], they have both diverged from the original merge commit M. Therefore, to merge U1' and U2' into UM', it suffices to use 3-way merge using original M as the merge base: UM' / \ U1' U2' \ /
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Phillip, Phillip Woodwrites: > On 03/03/18 00:29, Igor Djordjevic wrote: >> Hi Phillip, [...] >> >> The only thing I wonder of here is how would we check if the >> "rebased" merge M' was "clean", or should we stop for user amendment? >> With that other approach Sergey described, we have U1'==U2' to test with. > > I think (though I haven't rigorously proved to myself) that in the > absence of conflicts this scheme has well defined semantics (the merges > can be commuted), so the result should be predicable from the users > point of view so maybe it could just offer an option to stop. Yes, hopefully it's predictable, but is it the intended one? We don't know, so there is still some level of uncertainty. When in doubt, I try to find similar cases. There are two I'm aware of: 1. "git merge" just commits the result when there are no conflicts. However, it supposedly has been run by the user just now, and thus user can amend what he gets. That's effectively a stop for amendment from our POV. 2. When rebasing, "rerere", when fires, stages the changes, and rebasing stops for amendment. For me "rerere" behavior is rather annoying (I've never in fact amended what it prepared), but I always assumed there are good reasons it behaves this way. Overall, to be consistent, it seems we do need to stop at U1' != U2', at least by default. Additional options could be supported then to specify user intentions, both on the command level and in the todo list, provided it proves to be useful. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)
Hi Igor, Igor Djordjevicwrites: [...] > Now, not to get misinterpreted to pick sides in "(re)create" vs > "rebase" merge commit discussion, I just think these two (should) have > a different purpose, and actually having both inside interactive rebase > is what we should be aiming for. Yes, if the user has an existing merge that he intends to throw away by re-merging from scratch, he should be given a way to do it during history editing session, no argues. What I argue against is that this mode of operation is the default one, let alone the only one. > And that`s what I think is important to understand before any further > discussion - _(re)creating_ existing merge commits is not the same as > _rebasing_ them, even though the former can sometimes be used to > achieve the latter. Yes, indeed. Sometimes creating new merge instead of original does the job of rebasing the original, only it does it by pure accident. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Plillip and Igor, Igor Djordjevicwrites: > Hi Phillip, > > On 02/03/2018 12:31, Phillip Wood wrote: >> >> > Thinking about it overnight, I now suspect that original proposal had a >> > mistake in the final merge step. I think that what you did is a way to >> > fix it, and I want to try to figure what exactly was wrong in the >> > original proposal and to find simpler way of doing it right. >> > >> > The likely solution is to use original UM as a merge-base for final >> > 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural >> > though, as that's exactly UM from which both U1' and U2' have diverged >> > due to rebasing and other history editing. >> >> Hi Sergey, I've been following this discussion from the sidelines, >> though I haven't had time to study all the posts in this thread in >> detail. I wonder if it would be helpful to think of rebasing a merge as >> merging the changes in the parents due to the rebase back into the >> original merge. So for a merge M with parents A B C that are rebased to >> A' B' C' the rebased merge M' would be constructed by (ignoring shell >> quoting issues) >> >> git checkout --detach M >> git merge-recursive A -- M A' >> tree=$(git write-tree) >> git merge-recursive B -- $tree B' >> tree=$(git write-tree) >> git merge-recursive C -- $tree C' >> tree=$(git write-tree) >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC') >> >> This should pull in all the changes from the parents while preserving >> any evil conflict resolution in the original merge. It superficially >> reminds me of incremental merging [1] but it's so long since I looked at >> that I'm not sure if there are any significant similarities. >> >> [1] https://github.com/mhagger/git-imerge > > Interesting, from quick test[3], this seems to produce the same > result as that other test I previously provided[2], where temporary > commits U1' and U2' are finally merged with original M as a base :) Looks like sound approach and it's interesting if these 2 methods do in fact always bring the same result. Because if we look at the (now fixed) original approach closely, it also just gathers the changes in merge parents into U1' and U2', then merges the changes back into the original M (=U1=U2=UM). Overall, this one looks like another implementation of essentially the same method and confirms that we all have the right thought direction here. > > Just that this looks like even more straight-forward approach...? > > The only thing I wonder of here is how would we check if the > "rebased" merge M' was "clean", or should we stop for user amendment? > With that other approach Sergey described, we have U1'==U2' to test > with. That's an advantage of the original, yes. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Igor, Igor Djordjevic <igor.d.djordje...@gmail.com> writes: > Hi Sergey, > > On 01/03/2018 06:39, Sergey Organov wrote: [...] >> >> Yeah, I now see it myself. I'm sorry for being lazy and not inspecting >> this more carefully in the first place. > > No problem, that`s why we`re discussing it, and I`m glad we`re > aligned now, so we can move forward :) > >> > So while your original proposal currently seems like it could be >> > working nicely for non-interactive rebase (and might be some simpler >> > interactive ones), now hitting/acknowledging its first real use >> > limit, my additional quick attempt[1] just tries to aid pretty >> > interesting case of complicated interactive rebase, too, where we >> > might be able to do better as well, still using you original proposal >> > as a base idea :) >> >> Yes, thank you for pushing me back to reality! :-) The work and thoughts >> you are putting into solving the puzzle are greatly appreciated! > > You`re welcome, and I am enjoying it :) > >> Thinking about it overnight, I now suspect that original proposal had a >> mistake in the final merge step. I think that what you did is a way to >> fix it, and I want to try to figure what exactly was wrong in the >> original proposal and to find simpler way of doing it right. >> >> The likely solution is to use original UM as a merge-base for final >> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural >> though, as that's exactly UM from which both U1' and U2' have diverged >> due to rebasing and other history editing. > > Yes, this might be it...! ;) > > To prove myself it works, I`ve assembled a pretty crazy `-s ours` > merge interactive rebase scenario, and it seems this passes the test, > ticking all the check boxes (I could think of) :P I must admit it's quite a relief to hear this. What we now have is so simple and obvious that it'd be a huge disappointment if didn't work! > Here, merge commit M is done with `-s ours` (obsoleting branch "B"), > plus amended to make it an "evil merge", where a commit B2 from > obsoleted branch "B" is cherry picked to "master". [...] > There, I hope I didn`t miss any expectation. And, it _seems_ to work > exactly as expected :D That's very nice, to the level of being even suspect! :-) To avoid falling into euphoria though, we need to keep in mind that "expectations" is rather vague concept, and we likely still need to stop for user amendment unless we absolutely sure nothing surprising happens. I.e., we better require U1'==U2' test to succeed to proceed non-stop automatically. Besides, it will be somewhat inline with what 'rerere' does. > In real life, except for usual possibility for conflicts during > commit rebasing, we might experience _three_ possible conflict > situations once "rebased" merge itself is to be created - two when > rebasing each of temporary merge helper commits, and one on the > "rebased" merge itself. This is something where we might think about > user experience, not introducing (too much) confusion... Yeah, this is terribly important issue to take care of! Relative simplicity of the concept itself raises the chances of finding a suitable solution, I hope. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Igor, Igor Djordjevic <igor.d.djordje...@gmail.com> writes: > Hi Sergey, > > On 28/02/2018 06:19, Sergey Organov wrote: >> >> > > (3) ---X1---o---o---o---o---o---X2 >> > >|\ |\ >> > >| A1---A2---A3---U1 | A1'--A2'--A3'--U1' >> > >| \ | >> > >| M | >> > >| / | >> > >\-B1---B2---B3---U2 \-B1'--B2'--B3'--U2' >> > > >> > >> > Meh, I hope I`m rushing it now, but for example, if we had decided to >> > drop commit A2 during an interactive rebase (so losing A2' from >> > diagram above), wouldn`t U2' still introduce those changes back, once >> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/ >> >> I think the method will handle this nicely. > > That`s what I thought as well. And then I made a test. And then the > test broke... Now, might be the test was flawed in the first place, > but thinking about it a bit more, it does seem to make sense not to > handle this case nicely :/ Yeah, I now see it myself. I'm sorry for being lazy and not inspecting this more carefully in the first place. [...] > So while your original proposal currently seems like it could be > working nicely for non-interactive rebase (and might be some simpler > interactive ones), now hitting/acknowledging its first real use > limit, my additional quick attempt[1] just tries to aid pretty > interesting case of complicated interactive rebase, too, where we > might be able to do better as well, still using you original proposal > as a base idea :) Yes, thank you for pushing me back to reality! :-) The work and thoughts you are putting into solving the puzzle are greatly appreciated! Thinking about it overnight, I now suspect that original proposal had a mistake in the final merge step. I think that what you did is a way to fix it, and I want to try to figure what exactly was wrong in the original proposal and to find simpler way of doing it right. The likely solution is to use original UM as a merge-base for final 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural though, as that's exactly UM from which both U1' and U2' have diverged due to rebasing and other history editing. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Igor Djordjevicwrites: [...] >> > Hmm, still rushing it, but what about adding an additional step, >> > something like this: >> >> I think it's unneeded, as it should work fine without it, see another >> reply. > > Unfortunately, I have a broken test case saying different - it could > very well be a flawed test, too, but let`s elaborate in that > other sub-thread[1], indeed. Yeah, I was too fast to reply and I was wrong, sorry about it. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Igor, Igor Djordjevicwrites: > On 28/02/2018 21:25, Igor Djordjevic wrote: >> >> But U1' and U2' are really to be expected to stay the same in >> non-interactive rebase case only... > > Just to rephrase to "could be expected" here, meaning still not > necessarily in this case, either - I`ve just witnessed > non-interactive rebase Johannes previously described[1], merge with > `-s ours` (dropping B* patches), plus B1 cherry-picked between > X1..X2, eventually coming up with different U1' and U2', too (which > would produce a wrong end result, if continued). Even non-interactive rebase may bring arbitrary asymmetric changes on both sides of the merge, especially likely when resolving conflicts needs to take place. OTOH, interactive history editing session could have merges that we don't intend to edit at all. Overall, neither non-interactive case is in fact much simpler, nor interactive case is so much different. > But I guess this should go to the "complex history" pile, good thing > still being that diff safety check between U1' and U2' works as > expected, thus automatic merge rebase can be aborted and command > given back to the user for closer inspection. Exactly. This fact hopefully won't stop us from looking for more suitable automated handling of the general case though. It should still be our goal to reduce the number of such aborts and to suggest better merge result for amendment when we are still aborting. Your proposal hopefully is such a valuable improvement. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Igor Djordjevicwrites: > On 28/02/2018 03:12, Igor Djordjevic wrote: >> >> Would additional step as suggested in [1] (using R1 and R2 to "catch" >> interactive rebase additions/amendments/drops, on top of U1' and >> U2'), make more sense (or provide an additional clue, at least)? >> >> [1] >> https://public-inbox.org/git/8829c395-fb84-2db0-9288-f7b28fa0d...@gmail.com/ > > Heh, no sleeping tonight :P > > Anyway, from (yet another) ad hoc test, additional step mentioned in > [1] above seems to handle this case, too (merge with `-s ours` > dropping B* patches, plus B1 cherry-picked between X1..X2): > > On 28/02/2018 00:27, Johannes Schindelin wrote: >> >> - One of the promises was that the new way would also handle merge >> strategies other than recursive. What would happen, for example, if M >> was generated using `-s ours` (read: dropping the B* patches' changes) >> and if B1 had been cherry-picked into the history between X1..X2? >> >> Reverting R would obviously revert those B1 changes, even if B1' would >> obviously not even be part of the rebased history! >> >> Yes, I agree that this `-s ours` example is quite concocted, but the point >> of this example is not how plausible it is, but how easy it is to come up >> with a scenario where this design to "rebase merge commits" results in >> very, very unwanted behavior. > > And not just that - it worked with additional interactive rebase > adding, amending and removing commits, on top of all this still > preserving original `-s ours` merge commit evil-merge amendment, too, > all as expected (or so it seems) :P Great! I do believe that once we start from some sensible approach, many kinds of improvements are possible. I'll definitely need to take close look at what you came up with, thanks! I'd like to say though that nobody should expect miracles from automated rebasing of merges when we get to complex history editing. It will need to retreat to manual merge, sooner or later. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Jacob Keller <jacob.kel...@gmail.com> writes: > On Tue, Feb 27, 2018 at 10:14 AM, Junio C Hamano <gits...@pobox.com> wrote: >> Sergey Organov <sorga...@gmail.com> writes: >> >>> You've already bit this poor thingy to death. Please rather try your >>> teeth on the proposed Trivial Merge (TM) method. >> >> Whatever you do, do *NOT* call any part of your proposal "trivial >> merge", unless you are actually using the term to mean what Git >> calls "trivial merge". The phrase has an established meaning in Git >> and your attempt to abuse it to mean something entirely different is >> adding unnecessary hindrance for other people to understand what you >> want to perform. > > Agreed, I think we need better terminology here, the current words for > (TM) are definitely *not* trivial merges. Same for "angel merge", I > don't think that term really works well either. Agreed. How do we call a merge that introduces no differences on either side of the merge then? Is there some English for even more trivial than what Git calls "trivial merge"? -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelinwrites: > Hi Buga, > > thank you for making this a lot more understandable to this thick > developer. > > On Tue, 27 Feb 2018, Igor Djordjevic wrote: > >> On 27/02/2018 19:55, Igor Djordjevic wrote: >> > >> > It would be more along the lines of "(1) rebase old merge commit parents, >> > (2) generate separate diff between old merge commit and each of its >> > parents, (3) apply each diff to their corresponding newly rebased >> > parent respectively (as a temporary commit, one per rebased parent), >> > (4) merge these temporary commits to generate 'rebased' merge commit, >> > (5) drop temporary commits, recording their parents as parents of >> > 'rebased' merge commit (instead of dropped temporary commits)". >> > >> > Implementation wise, steps (2) and (3) could also be done by simply >> > copying old merge commit _snapshot_ on top of each of its parents as >> > a temporary, non-merge commit, then rebasing (cherry-picking) these >> > temporary commits on top of their rebased parent commits to produce >> > rebased temporary commits (to be merged for generating 'rebased' >> > merge commit in step (4)). >> >> For those still tagging along (and still confused), here are some >> diagrams (following what Sergey originally described). Note that >> actual implementation might be even simpler, but I believe it`s a bit >> easier to understand like this, using some "temporary" commits approach. >> >> Here`s our starting position: >> >> (0) ---X1---o---o---o---o---o---X2 (master) >>|\ >>| A1---A2---A3 >>| \ >>| M (topic) >>| / >>\-B1---B2---B3 >> >> >> Now, we want to rebase merge commit M from X1 onto X2. First, rebase >> merge commit parents as usual: >> >> (1) ---X1---o---o---o---o---o---X2 >>|\ |\ >>| A1---A2---A3 | A1'--A2'--A3' >>| \ | >>| M | >>| / | >>\-B1---B2---B3 \-B1'--B2'--B3' >> >> >> That was commonly understandable part. > > Good. Let's assume that I want to do this interactively (because let's > face it, rebase is boring unless we shake up things a little). And let's > assume that A1 is my only change to the README, and that I realized that > it was incorrect and I do not want the world to see it, so I drop A1'. > > Let's see how things go from here: > >> Now, for "rebasing" the merge commit (keeping possible amendments), we >> do some extra work. First, we make two temporary commits on top of old >> merge parents, by using exact tree (snapshot) of commit M: >> >> (2) ---X1---o---o---o---o---o---X2 >>|\ |\ >>| A1---A2---A3---U1 | A1'--A2'--A3' >>| \ | >>| M | >>| / | >>\-B1---B2---B3---U2 \-B1'--B2'--B3' > > Okay, everything would still be the same except that I still have dropped > A1'. > >> So here, in terms of _snapshots_ (trees, not diffs), U1 = U2 = M. >> >> Now, we rebase these temporary commits, too: >> >> (3) ---X1---o---o---o---o---o---X2 >>|\ |\ >>| A1---A2---A3---U1 | A1'--A2'--A3'--U1' >>| \ | >>| M | >>| / | >>\-B1---B2---B3---U2 \-B1'--B2'--B3'--U2' > > I still want to drop A1 in this rebase, so A1' is still missing. > > And now it starts to get interesting. > > The diff between A3 and U1 does not touch the README, of course, as I said > that only A1 changed the README. But the diff between B3 and U2 does > change the README, thanks to M containing A1 change. > > Therefore, the diff between B3' and U2' will also have this change to the > README. That change that I wanted to drop. > >> As a next step, we merge these temporary commits to produce our >> "rebased" merged commit M: >> >> (4) ---X1---o---o---o---o---o---X2 >>|\ |\ >>| A1---A2---A3---U1 | A1'--A2'--A3'--U1' >>| \ | \ >>| M | M' >>| / | / >>\-B1---B2---B3---U2 \-B1'--B2'--B3'--U2' > > And here, thanks to B3'..U2' changing the README, M' will also have that > change that I wanted to see dropped. > > Note that A1' is still dropped in my example. > >> Finally, we drop temporary commits, and record rebased commits A3' >> and B3' as our "rebased" merge commit parents instead (merge commit >> M' keeps its same tree/snapshot state, just gets parents replaced): >> >> (5) ---X1---o---o---o---o---o---X2 >>|\ |\ >>| A1---A2---A3---U1 | A1'--A2'--A3' >>| \ | \
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Junio C Hamanowrites: > Igor Djordjevic writes: > >> On 27/02/2018 20:59, Igor Djordjevic wrote: >>> >>> (3) ---X1---o---o---o---o---o---X2 >>>|\ |\ >>>| A1---A2---A3---U1 | A1'--A2'--A3'--U1' >>>| \ | >>>| M | >>>| / | >>>\-B1---B2---B3---U2 \-B1'--B2'--B3'--U2' >>> >> >> Meh, I hope I`m rushing it now, but for example, if we had decided to >> drop commit A2 during an interactive rebase (so losing A2' from >> diagram above), wouldn`t U2' still introduce those changes back, once >> U1' and U2' are merged, being incorrect/unwanted behavior...? :/ >> >> p.s. Looks like Johannes already elaborated on this in the meantime, >> let`s see... (goes reading that other e-mail[1]) > > As long as we are talking about rebase that allows us users to > adjust and make changes ("rebase -i" being the prime and most > flexible example), it is easy to imagine that A1'--A3' and B1'--B3' > have almost no relation to their original counterparts. After all, > mechanical merge won't be able to guess the intention of the change > humans make, so depending on what happend during X1 and X2 that > happend outside of these two topics, what's required to bring series > A and B to series A' and B' can be unlimited. You discuss some different method here. In my original proposal U1' and U2' are to be merged. Nothing should be replayed on top of them. I.e., U1' is _already_ the result of replaying difference between M and A3 on top of A3'. > So from that alone, it should be clear that replaying difference > between M and A3 (and M and B3) on top of U1' and U2' is hopeless as a > general solution. Getting U1' from U1 is the same complexity as getting A3' from A3, with the same caveats. So, as general solution, it's as good as rebase of non-merge commit. > It is acceptable as long as a solution fails loudly when it does the > wrong thing, but I do not think the apporach can produce incorrect > result silently, as your example shows above. I still believe the method handles simple cases automatically and correctly and allows to immediately stop for amendment should something suspect appear. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Igor Djordjevicwrites: > On 28/02/2018 01:36, Jacob Keller wrote: >> >> > > (3) ---X1---o---o---o---o---o---X2 >> > >|\ |\ >> > >| A1---A2---A3---U1 | A1'--A2'--A3'--U1' >> > >| \ | >> > >| M | >> > >| / | >> > >\-B1---B2---B3---U2 \-B1'--B2'--B3'--U2' >> > > >> > >> > Meh, I hope I`m rushing it now, but for example, if we had decided to >> > drop commit A2 during an interactive rebase (so losing A2' from >> > diagram above), wouldn`t U2' still introduce those changes back, once >> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/ >> >> In that case, the method won't work well at all, so I think we need a >> different approach. >> > > Hmm, still rushing it, but what about adding an additional step, > something like this: I think it's unneeded, as it should work fine without it, see another reply. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Igor Djordjevicwrites: > On 27/02/2018 20:59, Igor Djordjevic wrote: >> >> (3) ---X1---o---o---o---o---o---X2 >>|\ |\ >>| A1---A2---A3---U1 | A1'--A2'--A3'--U1' >>| \ | >>| M | >>| / | >>\-B1---B2---B3---U2 \-B1'--B2'--B3'--U2' >> > > Meh, I hope I`m rushing it now, but for example, if we had decided to > drop commit A2 during an interactive rebase (so losing A2' from > diagram above), wouldn`t U2' still introduce those changes back, once > U1' and U2' are merged, being incorrect/unwanted behavior...? :/ I think the method will handle this nicely. When you "drop" A2, will A3' change, or stay intact? If it changes, say, to A3'', the U1' will change to U1'', and the method will propagate the change automatically. If it A3' doesn't change, then there are no changes to take. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Junio C Hamano <gits...@pobox.com> writes: > Sergey Organov <sorga...@gmail.com> writes: > >> You've already bit this poor thingy to death. Please rather try your >> teeth on the proposed Trivial Merge (TM) method. > > Whatever you do, do *NOT* call any part of your proposal "trivial > merge", unless you are actually using the term to mean what Git > calls "trivial merge". The phrase has an established meaning in Git > and your attempt to abuse it to mean something entirely different is > adding unnecessary hindrance for other people to understand what you > want to perform. Yeah, got it. It's confusing indeed. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelinwrites: > Hi Buga, > > On Tue, 20 Feb 2018, Igor Djordjevic wrote: > >> I`m really interested in this topic, which seems to (try to) address the >> only "bad feeling" I had with rebasing merges - being afraid of silently >> losing amendments by actually trying to "replay" the merge (where >> additional and possibly important context is missing), instead of really >> "rebasing" it (somehow). > > If those amendments are what you are worried about, why not address them > specifically? > > In other words, rather than performing the equivalent of > > git show ^! | git apply > > (which would of course completely ignore if the rewritten ^2 > dropped a patch, amended a patch, or even added a new patch), You've already bit this poor thingy to death. Please rather try your teeth on the proposed Trivial Merge (TM) method. Sorry, you will need to actually read the proposal should you decide to. > what you really want is to figure out what changes the user made when > merging, Exactly! It's all and only about changes, I'm glad you are starting to get it. > and what merge strategy was used to begin with. No. It's in Git core philosophy to store only result, independent on the way the result has been achieved. Only result matters. I could have got merge result out of thin air, and Git won't care, and will store it for me safely. The proposed (TM) method will ensure it's still stored safely after rebasing. > To see what I mean, look at the output of `git show 0fd90daba8`: it shows > how conflicts were resolved. By necessity, this is more complicated than a > simple diff: it is *not* as simple as taking a diff between two revisions > and applying that diff to a third revision. There were (at least) three > revisions involved in the original merge commit, and recreating that merge > commit faithfully means to represent the essence of the merge commit > faithfully enough to be able to replay it on a new set of at least three > revisions. Even better: we have at least 3 source revisions and 2 new revisions to base 3-rd new revision upon. Proposed (TM) method will use all of them. > That can be simplified to two-way diffs only in very, very special > circumstances, and in all other cases this simplification will simply > fall on its nose. No, Done Right (TM) it won't fall as N-way-diff is nothing more than N-1 simple diffs, trivially combined. > If the proposed solution was to extend `git apply` to process combined > diffs, I would agree that we're on to something. That is not the proposed > solution, though. I'm glad you finally got the point. Proposed (TM) method effectively 'git apply' combined diffs, yes. I just defined it in terms of commits rather than diffs, as it's simpler to understand and to reason about it that way. > > In short: while I am sympathetic to the desire to keep things simple, Proposed (TM) method is complex enough to solve the problem at hand. No need to ask for more complexity. > the idea to somehow side-step replaying the original merge seems to be > *prone* to be flawed. Exactly! That's why current approach to rebase merges is flawed, and that's why proposed (TM) method does reply entire original merges. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Johannes, Johannes Schindelinwrites: > Hi Buga, > > On Tue, 20 Feb 2018, Igor Djordjevic wrote: > >> I`m really interested in this topic, which seems to (try to) address the >> only "bad feeling" I had with rebasing merges - being afraid of silently >> losing amendments by actually trying to "replay" the merge (where >> additional and possibly important context is missing), instead of really >> "rebasing" it (somehow). [...] > In short: while I am sympathetic to the desire to keep things simple, > the idea to somehow side-step replaying the original merge seems to be > *prone* to be flawed. The proposed (TM) solution does replay the original merge. > Any system that cannot accommodate dropped/changed/added commits on > either side of a merge is likely to be too limited to be useful. I believe the proposed (TM) solution handles all that nicely. It does accommodate dropped/changed/added commits on either side of a merge, symmetrically, and never silently drops user modifications. If you think (TM) is flawed, please give us a test-case. -- Sergey
Re: cherry-pick '-m' curiosity
"G. Sylvie Davies" <syl...@bit-booster.com> writes: > On Mon, Feb 5, 2018 at 3:46 AM, Sergey Organov <sorga...@gmail.com> wrote: >> Hello, >> >> $ git help cherry-pick >> >> -m parent-number, --mainline parent-number >>Usually you cannot cherry-pick a merge because you do not >>know which side of the merge should be considered the >>mainline. >> >> Isn't it always the case that "mainline" is the first parent, as that's >> how "git merge" happens to work? >> > > First-parent will be whatever commit you were sitting on when you > typed "git merge". Right, but I believe it's also "mainline", see below. > If you're sitting on your branch and you type "git fetch; git merge > origin/master", then "mainline" will be 2nd parent. No. If you ever want to cherry-pick this commit, it'd still be -m1 side of it that likely makes sense, and it's exactly the side that makes sense to be picked that is called "mainline" in the manual page we are discussing, and there is no any other definition of "mainline" as far as I can tell. There is nothing about 'origin/master' that makes it "mainline" from the POV of future cherry-picks, if any, of this merge commit. I was also unable to find any git documentation that calls 'origin/master' "mainline". It's called "remote-tracking branch", or maybe sometimes "upstream". OTOH, when one merges something, he often merges "side branch" onto "mainline", so in the context of this particular merge, your local "master" happens to be "mainline" and "origin/master" happens to be "side branch". > "git revert -m" also has the same problem. Yes, as it's essentially just "git cherry-pick --reverse -m", provided cherry-pick has had the "--reverse" from regular "patch" utility [*]. It's also interesting to notice that manual page for "git revert" refers to the revert-a-faulty-merge How-To, that in turn again uses only "git revert -m 1". Overall, it's still a mystery to me why "-m 1" is not the default behavior for both "git revert" and "git cherry-pick". The only suspicion I have is that actual intention is to deny picking merge commits by default. Then, the usual git way would be to use --force or --enable-merges to overcome the denial, but if we still do need "-m 2" etc. even rarely, then rather re-using "-m 1" as "I mean it" indication is only logical. If my suspicion is true, how about something like this: -m parent-number, --mainline parent-number This option specifies the parent number (starting from 1) of a commit and instructs cherry-pick to replay the change relative to the specified parent. Cherry-pick will refuse to handle merge commits unless this option is given. Damn, it now has no "mainline" in the description at all, so it's unclear why it has been called --mainline in the first place, not that it was somehow clear to me before. And while we are at it, I just stumbled over "git cherry-pick -m 1" refusing to handle non-merge commits: $ git cherry-pick -m1 dd5c320 error: Mainline was specified but commit dd5c320a300520a044cfa73d17f6cbffbbef60ef is not a merge. fatal: cherry-pick failed $ I wonder whether this is intentional? What's the rationale then? It seems it could be useful to be able to cherry-pick multiple commits, some of which are merges, no? Footnote: [*] rebase, revert, and cherry-pick all look rather similar in git and could be calling for some unification. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Igor, Igor Djordjevicwrites: > Hi Sergey, > [...] > > Even though this behavior is known and documented, it still left some > to be desired. > > Might be I`m missing something, but so far I like how described > approach just "feels right" (to me, for now), being really simple, > yet robust :) > > As my humble contribution to the cause and discussion itself, I`m > providing possibly naive, yet simple demonstration script[1], and > clearly showing where current `git rebase --preserve-merges` is > lacking (in my opinion, even though being expected and documented), > and how your proposal seems to improve the situation here. Thanks for the test-case, -- it's nice to see this thingy working! > > Thanks for your thoughts, and hoping to see this going somewhere :) So do I. Even if nobody volunteers to adopt it, I hope I'll be able to implement something myself, not very soon though. -- Sergey
Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi Jake, Jacob Keller <jacob.kel...@gmail.com> writes: > On Fri, Feb 16, 2018 at 5:08 AM, Sergey Organov <sorga...@gmail.com> wrote: >> Hi, >> >> By accepting the challenges raised in recent discussion of advanced >> support for history rebasing and editing in Git, I hopefully figured out >> a clean and elegant method of rebasing merges that I think is "The Right >> Way (TM)" to perform this so far troublesome operation. ["(TM)" here has >> second meaning: a "Trivial Merge (TM)", see below.] >> >> Let me begin by outlining the method in git terms, and special thanks >> here must go to "Johannes Sixt" <j...@kdbg.org> for his original bright >> idea to use "cherry-pick -m1" to rebase merge commits. >> >> End of preface -- here we go. >> > > I hope to take a more detailed look at this, also possibly with some > attempts at re-creating the process by hand to see it in practice. Thank you for your interest and for the review, and yes, some testing is what the idea desperately needs. Unfortunately I don't have much time for it right now, nor am I fluent enough in git internals to actually make even a raw prototype really soon, sorry. Anybody who is interested is very welcome to volunteer! [...] > > This might be a bit tricky for a user to understand what the process > is, especially if they don't understand how it's creating special U1' > and U2' commits. However, it *is* the cleanest method I've either seen > or thought of for presenting the conflict to the user. > [...] >> - it appears shiny to the point that it will likely be able to handle >> even darkest evil merges nicely, no special treatment required. >> > > Yep, and I like that it has a pretty reasonable way of presenting > conflicts for resolution. It may be a bit tricky to explain the use of > the intermittent commits U1' and U2' though. Yeah, I see how all this sends somewhat unique challenges to the implementation to get user interaction in case of conflicts right, even though all the basic concepts are old buddies and should be familiar to the user. That said, the recursive merge strategy comes to mind, where creating virtual merge base may itself cause conflicts, so something similar enough is likely to already exist. -- Sergey
[RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)
Hi, By accepting the challenges raised in recent discussion of advanced support for history rebasing and editing in Git, I hopefully figured out a clean and elegant method of rebasing merges that I think is "The Right Way (TM)" to perform this so far troublesome operation. ["(TM)" here has second meaning: a "Trivial Merge (TM)", see below.] Let me begin by outlining the method in git terms, and special thanks here must go to "Johannes Sixt"for his original bright idea to use "cherry-pick -m1" to rebase merge commits. End of preface -- here we go. Given 2 original branches, b1 and b2, and a merge commit M that joins them, suppose we've already rebased b1 to b1', and b2 to b2'. Suppose also that B1' and B2' happen to be the tip commits on b1' and b2', respectively. To produce merge commit M' that joins b1' and b2', the following operations will suffice: 1. Checkout b2' and cherry-pick -m2 M, to produce U2' (and new b2'). 2. Checkout b1' and cherry-pick -m1 M, to produce U1' (and new b1'). 3. Merge --no-ff new b2' to current new b1', to produce UM'. 4. Get rid of U1' and U2' by re-writing parent references of UM' from U1' and U2' to B1' and B2', respectively, to produce M'. 5. Mission complete. Let's now see why and how the method actually works. Firs off, let me introduce you to my new friend, the Trivial Merge, or (TM) for short. By definition, (TM) is a merge that introduces absolutely no differences to the sides of the merge. (I also like to sometimes call him "Angel Merge", both as the most beautiful of all merges, and as direct antithesis to "evil merge".) One very nice thing about (TM) is that to safely rebase it, it suffices to merge its (rebased) parents. It is safe in this case, as (TM) itself doesn't posses any content changes, and thus none could be missed by replacing it with another merge commit. I bet most of us have never seen (TM) in practice though, so let's see how (TM) can help us handle general case of some random merge. What I'm going to do is to create a virtual (TM) and see how it goes from there. Let's start with this history: M / \ B1 B2 And let's transform it to the following one, contextually equivalent to the original, by introducing 2 simple utility commits U1 and U2, and a new utility merge commit UM: UM / \ U1 U2 || B1 B2 Here content of any of the created UM, U1, and U2 is the same, and is exact copy of original content of M. I.e., provided [A] denotes "content of commit A", we have: [UM] = [U1] = [U2] = [M] Stress again how these changes to the history preserve the exact content of the original merge ([UM] = [M]), and how U1 an U2 represent content changes due to merge on either side[*], and how neither preceding nor subsequent commits content would be affected by the change of representation. Now observe that as [U1] = [UM], and [U2] = [UM], the UM happens to be exactly our new friend -- the "Trivial Merge (TM)" his true self, introducing zero changes to content. Next we rebase our new representation of the history and we get: UM' / \ U1' U2' || B1' B2' Here UM' is bare merge of U1' and U2', in exact accordance with the method of rebasing a (TM) we've already discussed above, and U1' and U2' are rebased versions of U1 and U2, obtained by usual rebasing methods for non-merge commits. (Note, however, that at this point UM' is not necessarily a (TM) anymore, so in real implementation it may make sense to check if UM' is not a (TM) and stop for possible user amendment.) Finally, to get to our required merge commit M', we get the content of UM' and record two actual parents of the merge: M' / \ B1' B2' Where [M'] = [UM']. That's it. Mission complete. I expect the method to have the following nice features: - it carefully preserves user changes by rebasing the merge commit itself, in a way that is semantically similar to rebasing simple (non-merge) commits, yet it allows changes made to branches during history editing to propagate over corresponding merge commit that joins the branches, even automatically when the changes don't conflict, as expected. - it has provision for detection of even slightest chances of ending up with surprising merge (just check if UM' is still (TM)), so that implementation could stop for user inspection and amendment when appropriate, yet it is capable of handling trivial cases smoothly and automatically. - it never falls back to simple invocation of merge operation on rebased original branches themselves, thus avoiding the problem of lack of knowledge of how the merge at hand has been performed in the first place. It doesn't prevent implementation from letting user to manually perform whatever merge she wishes when suspect result is automatically detected though. - it extends trivially to octopus merges. - it appears shiny to the point that it will likely be able to handle even darkest evil merges nicely, no special treatment required. Footnote: [*] We may as well
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Hi Johannes, Johannes Schindelinwrites: [...] >> > I'd not argue this way myself. If there are out-of-git-tree non-human >> > users that accept and tweak todo _generated_ by current "git rebase -p" >> > _command_, I also vote for a new option. >> > >> >> To be fair, I have not seen anything that actually reads the todo list >> and tweaks it in such a manner. The closest example is the git garden >> shears script, which simply replaces the todo list. >> >> It's certainly *possible* that such a script would exist though, > > We actually know of such scripts. Please consider to explain this in the description of the change. I believe readers deserve an explanation of why you decided to invent new option instead of fixing the old one, even if it were only a suspicion, more so if it is confidence. -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi, > > On Tue, 13 Feb 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> > The wording is poor either way, but you are also not a native speaker so >> > we have to rely on, say, Eric to help us out here. >> >> Likely, but why didn't you keep original wording from --preserve-merges? >> Do you feel it's somehow poor either? > > Yes, I felt it is poor, especially when --recreate-merges is present, that > is indeed why I changed it. So, how about this (yeah, I noticed the option now got arguments, but please, tweak this to the new implementation yourself): --recreate-merges:: Recreate merge commits instead of flattening the history. Merge conflict resolutions or manual amendments to merge commits are not preserved. -p:: --preserve-merges:: (deprecated) This option is similar to --recreate-merges. It has no proper support for interactive mode and thus is deprecated. Use '--recreate-merges' instead. -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Johannes Schindelinwrites: [...] > Just to give you one concrete example: when I recently rebased some > patches (no reording or dropping involved here!) and one of the picks > failed with merge conflicts, I realized that that particular commit > introduced incorrect formatting and fixed that right away (verifying that > no other commits introduced incorrect formatting, of course). > > With your new cute idea to magically cherry-pick -m1, this change would > have been magically dropped from the subsequent merge commits! You put it as if the problem you describe is unsolvable short of getting back to your favorite blind re-merge. Do you really believe it? I thought it's obvious that I originally meant "cherry-pick -m1" to be an explanation facility, a proof of concept, not the final answer to all the problems of history editing. It's a nice base for actually approaching these problems though, unlike blind re-merge currently being used, the latter having no potential. The fact that bare naked "cherry-pick -m1" doesn't do what is often[1] required in such cases neither voids the general idea of reproducing merge-the-result, nor does it make current re-merge approach less broken. [1] Please take into consideration that it's _not always_ the case that one needs a change made to a side-branch to actually propagate to the main-line over the merge (think "merge -x ours", or something similar but not that simple), and then it's rather the cute idea to blindly re-merge that will wreak havoc, as in a lot of other cases. -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Hi Jake, Jacob Keller <jacob.kel...@gmail.com> writes: > On Mon, Feb 12, 2018 at 12:39 PM, Johannes Schindelin > <johannes.schinde...@gmx.de> wrote: >> Hi Sergey, >> >> On Mon, 12 Feb 2018, Sergey Organov wrote: >>> > Have a look at https://github.com/git/git/pull/447, especially the >>> > latest commit in there which is an early version of the deprecation I >>> > intend to bring about. >>> >>> You shouldn't want a deprecation at all should you have re-used >>> --preserve-merges in the first place, and I still don't see why you >>> haven't. >> >> Keep repeating it, and it won't become truer. >> >> If you break formats, you break scripts. Git has *so* many users, there >> are very likely some who script *every* part of it. >> >> We simply cannot do that. >> >> What we can is deprecate designs which we learned on the way were not only >> incomplete from the get-go, but bad overall and hard (or impossible) to >> fix. Like --preserve-merges. >> >> Or for that matter like the design you proposed, to use --first-parent for >> --recreate-merges. Or to use --first-parent for some --recreate-merges, >> surprising users in very bad ways when it is not used (or when it is >> used). I get the impression that you still think it would be a good idea, >> even if it should be obvious that it is not. > > If we consider the addition of new todo list elements as "user > breaking", then yes this change would be user-script breaking. It _is_ user script breaking, provided such script exists. Has anybody actually seen one? Not that it's wrong to be extra-cautious about it, just curios. Note that to be actually affected, such a script must invoke "git rebase -p" _command_ and then tweak its todo output to produce outcome. > Since we did not originally spell out that todo-list items are subject > to enhancement by addition of operations in the future, scripts are > likely not designed to allow addition of new elements. Out of curiosity, are you going to spell it now, for the new todo format? > Thus, adding recreate-merges, and deprecating preserve-merges, seems > to me to be the correct action to take here. Yes, sure, provided there is actual breakage, or at least informed suspicion there is one. > One could argue that users should have expected new todo list elements > to be added in the future and thus design their scripts to cope with > such a thing. If you can convincingly argue this, then I don't > necessarily see it as a complete user breaking change to fix > preserve-merges in order to allow it to handle re-ordering properly.. I'd not argue this way myself. If there are out-of-git-tree non-human users that accept and tweak todo _generated_ by current "git rebase -p" _command_, I also vote for a new option. > I think I lean towards agreeing with Johannes, and that adding > recreate-merges and removing preserve-merges is the better solution. On these grounds it is, no objections. -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Mon, 12 Feb 2018, Sergey Organov wrote: > >> Thanks for explanations, and could you please answer this one: >> >> [...] >> >> >> I also have trouble making sense of "Recreate merge commits instead of >> >> flattening the history by replaying merges." Is it "> >> commits by replaying merges> instead of " or is it >> >> rather " instead of > >> replaying merges>? > > I thought I had answered that one. No, not really, but now you did, please see below. > > Flattening the history is what happens in regular rebase (i.e. without > --recreate-merges and without --preserve-merges). > > The idea to recreate merges is of course to *not* flatten the history. Sure. Never supposed it is. > Maybe there should have been a comma after "history" to clarify what the > sentence means. That's the actual answer to my question, but it in turn raises another one: why did you change wording of --preserve-merges description for this new option? > The wording is poor either way, but you are also not a native speaker so > we have to rely on, say, Eric to help us out here. Likely, but why didn't you keep original wording from --preserve-merges? Do you feel it's somehow poor either? Anyway, please also refer to wording suggestion in the another (lengthy) answer in this thread. -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Mon, 12 Feb 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> > >> > On Fri, 9 Feb 2018, Sergey Organov wrote: >> > >> >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> >> >> [...] >> >> >> >> > With this patch, the goodness of the Git garden shears comes to `git >> >> > rebase -i` itself. Passing the `--recreate-merges` option will generate >> >> > a todo list that can be understood readily, and where it is obvious >> >> > how to reorder commits. New branches can be introduced by inserting >> >> > `label` commands and calling `merge - `. And once this >> >> > mode has become stable and universally accepted, we can deprecate the >> >> > design mistake that was `--preserve-merges`. >> >> >> >> This doesn't explain why you introduced this new --recreate-merges. Why >> >> didn't you rather fix --preserve-merges to generate and use new todo >> >> list format? >> > >> > Because that would of course break existing users of >> > --preserve-merges. >> >> How exactly? > > Power users of interactive rebase use scripting to augment Git's > functionality. One particularly powerful trick is to override > GIT_SEQUENCER_EDITOR with an invocation of such a script, to perform > automated edits. Such a script breaks when we change the format of the > content to edit. If we change the format of the todo list generated in > --preserve-merges mode, that is exactly what happens. We break existing > users. I didn't say a word against "--preserve-merges mode", whatever it is, only about re-using "--preserve-merges" command-line option to "git rebase", the git user interface. I'm sure you see the difference? Unless there are out-of-git scripts that do use "git rebase --preserve-merges" and simultaneously do rely on the todo list format this exact command generates, there should be no breakage of existing users caused by changing todo list format generated by "git rebase --preserve-merges". Old broken "--preserve-merges mode" could be then kept in the implementation for ages, unused by the new fixed "git rebase --preserve-merge", for the sake of compatibility. > BTW it seems that you did not really read my previous reply carefully > because I referenced such a use case: the Git garden shears. I thought I did. You confirm below that this script doesn't use "git rebase --preserve-merges" in the first place, nor will it break if "git rebase --preserve-merges" starts to generate new todo format, yet you expected I'd readily see how it's relevant? No, I'm not that clever, nor am I a mind-reader. > They do override the sequencer editor, and while they do not exactly > edit the todo list (they simply through the generated one away), they > generate a new todo list and would break if that format changes. Of > course, the shears do not use the --preserve-merges mode, > but from just reading about the way how the Git garden shears work, it > is quite obvious how similar users of --preserve-merges are likely to > exist? Maybe, I dunno. If even "garden shears" won't break, then what will? Do you know an example? Anyway, as it seems it's too late already for such a change, let me stop this and assume there are indeed such scripts that will break and that it's indeed a good idea to introduce new option. Case closed. The manual should still be fixed though, I think. >> Doesn't "--recreate-merges" produce the same result as >> "--preserve-merges" if run non-interactively? > > The final result of a rebase where you do not edit the todo list? Should > be identical, indeed. That's good to hear. > But that is the most boring, most uninteresting, and least important use > case. For you. Do you suddenly stop caring about compatibility? > So we might just as well forget about it when we focus on keeping > Git's usage stable. Why? It's good it behaves the same, so --preserve-merges could indeed be deprecated, as you apparently intend. >> > So why not --preserve-merges=v2? Because that would force me to >> > maintain --preserve-merges forever. And I don't want to. >> > >> >> It doesn't seem likely that todo list created by one Git version is >> >> to be ever used by another, right? >> > >> > No. But by scripts based on `git rebase -p`. >> > >> >> Is there some hidden reason here? Some tools outside of
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Johannes Sixt <j...@kdbg.org> writes: > Am 09.02.2018 um 07:11 schrieb Sergey Organov: >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >>> Let me explain the scenario which comes up plenty of times in my work with >>> Git for Windows. We have a thicket of some 70 branches on top of git.git's >>> latest release. These branches often include fixup! and squash! commits >>> and even more complicated constructs that rebase cannot handle at all at >>> the moment, such as reorder-before! and reorder-after! (for commits that >>> really need to go into a different branch). >> >> I sympathize, but a solution that breaks even in simple cases can't be >> used reliably to solve more complex problems, sorry. Being so deep >> into your problems, I think you maybe just aren't seeing forest for the >> trees [1]. > > Hold your horses! Dscho has a point here. --preserve-merges > --first-parent works only as long as you don't tamper with the side > branches. If you make changes in the side branches during the same > rebase operation, this --first-parent mode would undo that change. He has a point indeed, but it must not be used as an excuse to silently damage user data, as if there are no other options! Simple --first-parent won't always fit, it's obvious. I used --first-parent patch as mere illustration of concept, it's rather "rebase [-i] --keep-the-f*g-shape" itself that should behave. There should be no need for actual --first-parent that only fits no-manual-editing use-cases. Look at it as if it's a scale where --first-parent is on one side, and "blind re-merge" is on the other. The right answer(s) lie somewhere in-between, but I think they are much closer to --first-parent than they are to "blind re-merge". > (And, yes, its result would be called an "evil merge", and that scary > name _should_ frighten you!) (It won't always be "evil merge", and it still doesn't frighten even if it will, provided git stops making them more evil then they actually deserve, and it isn't an excuse to silently distort user data anyway!) -- Sergey [1] The "--first-parent" here would rather keep that change from propagation to the main-line, not undo it, and sometimes it's even the right thing to do ("-x ours" for the original merge being one example). Frequently though it is needed on main-line indeed, and there should be a way to tell git to propagate the change to the main-line, but even then automatic blind unattended re-merge is wrong answer and I'm sure git can be made to do better than that.
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Hi Johannes, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > Hi Sergey, > > On Fri, 9 Feb 2018, Sergey Organov wrote: > >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> [...] >> >> > With this patch, the goodness of the Git garden shears comes to `git >> > rebase -i` itself. Passing the `--recreate-merges` option will generate >> > a todo list that can be understood readily, and where it is obvious >> > how to reorder commits. New branches can be introduced by inserting >> > `label` commands and calling `merge - `. And once this >> > mode has become stable and universally accepted, we can deprecate the >> > design mistake that was `--preserve-merges`. >> >> This doesn't explain why you introduced this new --recreate-merges. Why >> didn't you rather fix --preserve-merges to generate and use new todo >> list format? > > Because that would of course break existing users of > --preserve-merges. How exactly? Doesn't "--recreate-merges" produce the same result as "--preserve-merges" if run non-interactively? > So why not --preserve-merges=v2? Because that would force me to maintain > --preserve-merges forever. And I don't want to. > >> It doesn't seem likely that todo list created by one Git version is to >> be ever used by another, right? > > No. But by scripts based on `git rebase -p`. > >> Is there some hidden reason here? Some tools outside of Git that use old >> todo list format, maybe? > > Exactly. > > I did mention such a tool: the Git garden shears: > > https://github.com/git-for-windows/build-extra/blob/master/shears.sh > > Have a look at it. It will inform the discussion. I've searched for "-p" in the script, but didn't find positives for either "-p" or "--preserve-merges". How it would break if it doesn't use them? What am I missing? > >> Then, if new option indeed required, please look at the resulting manual: >> >> --recreate-merges:: >> Recreate merge commits instead of flattening the history by replaying >> merges. Merge conflict resolutions or manual amendments to merge >> commits are not preserved. >> >> -p:: >> --preserve-merges:: >> Recreate merge commits instead of flattening the history by replaying >> commits a merge commit introduces. Merge conflict resolutions or manual >> amendments to merge commits are not preserved. > > As I stated in the cover letter, there are more patches lined up after > this patch series. Good, but I thought this one should better be self-consistent anyway. What if those that come later aren't included? > > Have a look at https://github.com/git/git/pull/447, especially the latest > commit in there which is an early version of the deprecation I intend to > bring about. You shouldn't want a deprecation at all should you have re-used --preserve-merges in the first place, and I still don't see why you haven't. > > Also, please refrain from saying things like... "Don't you think ..." > > If you don't like the wording, I wold much more appreciate it if a better > alternative was suggested. Sorry, but how can I suggest one if I don't understand what you are doing here in the first place? That's why I ask you. > >> Don't you think more explanations are needed there in the manual on >> why do we have 2 separate options with almost the same yet subtly >> different description? Is this subtle difference even important? How? >> >> I also have trouble making sense of "Recreate merge commits instead of >> flattening the history by replaying merges." Is it "> commits by replaying merges> instead of " or is it >> rather " instead of > replaying merges>? > > The documentation of the --recreate-merges option is not meant to explain > the difference to --preserve-merges. It is meant to explain the difference > to regular `git rebase -i`, which flattens the commit history into a > single branch without merge commits (in fact, all merge commits are simply > ignored). Yeah, that's obvious, but the point is that resulting manual is ended up being confusing. > And I would rather not start to describe the difference between > --recreate-merges and --preserve-merges because I want to deprecate the > latter, and describing the difference as I get the sense is your wish > would simply mean more work because it would have to be added and then > removed again. I suspect you actually didn't need those new option in the first place, and that's the core reason of these troubles. -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Hi Johannes, Thanks for explanations, and could you please answer this one: [...] >> I also have trouble making sense of "Recreate merge commits instead of >> flattening the history by replaying merges." Is it "> commits by replaying merges> instead of " or is it >> rather " instead of > replaying merges>? -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Johannes Schindelinwrites: [...] > With this patch, the goodness of the Git garden shears comes to `git > rebase -i` itself. Passing the `--recreate-merges` option will generate > a todo list that can be understood readily, and where it is obvious > how to reorder commits. New branches can be introduced by inserting > `label` commands and calling `merge - `. And once this > mode has become stable and universally accepted, we can deprecate the > design mistake that was `--preserve-merges`. This doesn't explain why you introduced this new --recreate-merges. Why didn't you rather fix --preserve-merges to generate and use new todo list format? It doesn't seem likely that todo list created by one Git version is to be ever used by another, right? Is there some hidden reason here? Some tools outside of Git that use old todo list format, maybe? Then, if new option indeed required, please look at the resulting manual: --recreate-merges:: Recreate merge commits instead of flattening the history by replaying merges. Merge conflict resolutions or manual amendments to merge commits are not preserved. -p:: --preserve-merges:: Recreate merge commits instead of flattening the history by replaying commits a merge commit introduces. Merge conflict resolutions or manual amendments to merge commits are not preserved. Don't you think more explanations are needed there in the manual on why do we have 2 separate options with almost the same yet subtly different description? Is this subtle difference even important? How? I also have trouble making sense of "Recreate merge commits instead of flattening the history by replaying merges." Is it " instead of " or is it rather " instead of ? -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Hi, Johannes Schindelin <johannes.schinde...@gmx.de> writes: > On Wed, 7 Feb 2018, Sergey Organov wrote: >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> > +--recreate-merges:: >> > + Recreate merge commits instead of flattening the history by replaying >> > + merges. Merge conflict resolutions or manual amendments to merge >> > + commits are not preserved. >> >> I wonder why you guys still hold on replaying "merge-the-operation" >> instead of replaying "merge-the-result"? > > This misses the point of rebasing: you want to replay the changes. What this comment has to do with the statement to which it's supposed to be a reply? Sounds like topic change to me. Please clarify if it isn't. > >> The latter, the merge commit itself, no matter how exactly it was >> created in the first place, is the most valuable thing git keeps about >> the merge, and you silently drop it entirely! > > You miss another very crucial point. What was the first crucial point I miss? Do you rather agree that the point you are replying to with this is very crucial one as well? > I don't blame you, as you certainly have not used the Git garden > shears for years. Thanks a lot! > Let me explain the scenario which comes up plenty of times in my work with > Git for Windows. We have a thicket of some 70 branches on top of git.git's > latest release. These branches often include fixup! and squash! commits > and even more complicated constructs that rebase cannot handle at all at > the moment, such as reorder-before! and reorder-after! (for commits that > really need to go into a different branch). I sympathize, but a solution that breaks even in simple cases can't be used reliably to solve more complex problems, sorry. Being so deep into your problems, I think you maybe just aren't seeing forest for the trees [1]. > Even if you do not have such a complicated setup, it is quite possible > that you need to include a commit in your development that needs to be > dropped before contributing your work. Think e.g. removing the `-O2` flag > when compiling with GCC because GDB gets utterly confused with executables > compiled with `-O2` while single-stepping. This could be an initial commit > called `TO-DROP` or some such. > > And guess what happens if you drop that `pick` line in your todo list and > then the `merge` command simply tries to re-create the original merge > commit's changes? > > Exactly. The merge will become an evil merge, and will introduce that very > much not-wanted and therefore-dropped changes. Okay, Houston, we've had a problem here. I'm sure you'll be able to come-up with suitable solution once you start to think about it positively, but automatic unguided silent re-merge is still not the right answer, for the same reason of distortion of user changes. As for "evil merges"... I don't want to get too far from original subject to even start discussing this. >> OTOH, git keeps almost no information about "merge-the-operation", so >> it's virtually impossible to reliably replay the operation >> automatically, and yet you try to. > > That is true. However, the intended use case is not to allow you to > recreate funny merges. Its use case is to allow you to recreate > merges. Then it at least should behave accordingly, e.g., stop after every such occurrence, for user assistance. As an example, see what rerere does when it fires, even though it's much more reliable than this blind re-merge. But the actual problem here is that almost any merge but those made with pure "git merge", no options, no conflicts, no edits, no nothing, becomes "funny" and is being destroyed, sometimes in a weird way, by silently creating something different instead of original. > At a later stage, I might introduce support to detect `-s ours` merges, > because they are easy to detect. But even then, it will be an opt-in. So you are going to fix one particular case that is "easy to detect" (and fix). Does it mean you do realize it's a problem, but fail to see that it's _fundamental_ problem with current approach? I think you start from the wrong end. I think that any merge should be made reproducible first (with possible guidance from the user when required, as usual), and then advanced features for complex history tweaking should come, not the other way around. I feel that any solution that fails to exactly reproduce original history, unless it is to be actually changed, is flawed, and we will continue to hit our heads on sharp corners like "merge -s ours", most of which will be not that simple to detect and fix, for an unforeseeable future. > >> IMHO that was severe mistake in the original --preserve-merges, and you >> b
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Jacob Keller <jacob.kel...@gmail.com> writes: > On Tue, Feb 6, 2018 at 10:16 PM, Sergey Organov <sorga...@gmail.com> wrote: >> Johannes Schindelin <johannes.schinde...@gmx.de> writes: >> >> [...] >> >>> +--recreate-merges:: >>> + Recreate merge commits instead of flattening the history by replaying >>> + merges. Merge conflict resolutions or manual amendments to merge >>> + commits are not preserved. >> >> I wonder why you guys still hold on replaying "merge-the-operation" >> instead of replaying "merge-the-result"? The latter, the merge commit >> itself, no matter how exactly it was created in the first place, is the >> most valuable thing git keeps about the merge, and you silently drop it >> entirely! OTOH, git keeps almost no information about >> "merge-the-operation", so it's virtually impossible to reliably replay >> the operation automatically, and yet you try to. >> > > I'm not sure I follow what you mean here? > > You mean that you'd want this to actually attempt to re-create the > original merge including conflict resolutions by taking the contents > of the result? I mean just cherry-pick the merge the same way all other commits are essentially cherry-picked during rebase. That's what Johannes Sixt did in his patch I was reffering to. > How do you handle if that result has conflicts? What UX do you present > to the user to handle such conflicts? I don't think the normal 3-way > conflicts would even be possible in this case? No problem here. It goes exactly the same way as for non-merge commits that are being rebased. You can try it right now using $ git cherry-pick -m1 that will induce conflicts. The (somewhat tricky) functional difference is only in recording correct additional parents to the final commit, but that part is hidden from the user. -- Sergey
Re: [PATCH 5/8] rebase: introduce the --recreate-merges option
Johannes Schindelinwrites: [...] > +--recreate-merges:: > + Recreate merge commits instead of flattening the history by replaying > + merges. Merge conflict resolutions or manual amendments to merge > + commits are not preserved. I wonder why you guys still hold on replaying "merge-the-operation" instead of replaying "merge-the-result"? The latter, the merge commit itself, no matter how exactly it was created in the first place, is the most valuable thing git keeps about the merge, and you silently drop it entirely! OTOH, git keeps almost no information about "merge-the-operation", so it's virtually impossible to reliably replay the operation automatically, and yet you try to. IMHO that was severe mistake in the original --preserve-merges, and you bring with you to this new --recreate-merges... It's sad. Even more sad as solution is already known for years: bc00341838a8faddcd101da9e746902994eef38a Author: Johannes Sixt Date: Sun Jun 16 15:50:42 2013 +0200 rebase -p --first-parent: redo merge by cherry-picking first-parent change and it works like a charm. -- Sergey
Re: cherry-pick '-m' curiosity
Junio C Hamano <gits...@pobox.com> writes: > Sergey Organov <sorga...@gmail.com> writes: > >> Isn't it always the case that "mainline" is the first parent, as that's >> how "git merge" happens to work? > > You may not be merging into the "mainline" in the first place. > > Imagine forking two topics at the same commit on the mainline, and > merging these two topics of equal importance together into a single > bigger topic, before asking the mainline to pull the whole. > > $ git checkout mainline > $ git tag fork-point > $ git checkout -b frontend-topic fork-point > $ work work work > $ git checkout -b backend-topic fork-point > $ work work work > $ git checkout -b combined > $ git merge frontend-topic > $ git tag merged > > The backend-topic may be recorded as the first-parent of the > resulting merge, but logically the two topics are of equal footing, > so merge^1..merge and merge^2..merge are both equally interesting. Point taken, thanks! Now, if I reformulate my original question as: "Isn't it _usually_ the case that "mainline" is the first parent?" what is the answer? For example, in the above case I'd likely rather: $ git checkout -b combined fork-point $ git merge --no-ff frontend-topic $ git merge --no-ff backend-topic and still have clear "mainline" on "-m1" for both merges. I'm asking because those: "Usually you cannot cherry-pick a merge because you do not know which side of the merge should be considered the mainline." in the manual page still feels confusing in the context of typical git usage (as opposed to the context of abstract DAG operations where it'd make sense indeed.) -- Sergey
Re: cherry-pick '-m' curiosity
Stefan Beller <sbel...@google.com> writes: > On Mon, Feb 5, 2018 at 3:46 AM, Sergey Organov <sorga...@gmail.com> wrote: >> Hello, >> >> $ git help cherry-pick >> >> -m parent-number, --mainline parent-number >>Usually you cannot cherry-pick a merge because you do not >>know which side of the merge should be considered the >>mainline. >> >> Isn't it always the case that "mainline" is the first parent, as that's >> how "git merge" happens to work? >> >> Is, say, "-m 2" ever useful? > > Say you want to backport everything except that topic using cherry-picks. > Then -m2 would be useful? Didn't get the idea, sorry. Care to clarify? -- Sergey
cherry-pick '-m' curiosity
Hello, $ git help cherry-pick -m parent-number, --mainline parent-number Usually you cannot cherry-pick a merge because you do not know which side of the merge should be considered the mainline. Isn't it always the case that "mainline" is the first parent, as that's how "git merge" happens to work? Is, say, "-m 2" ever useful? -- Sergey
Re: How to re-merge paths differently?
"Philip Oakley" <philipoak...@iee.org> writes: > From: "Sergey Organov" <sorga...@gmail.com> >> Is there anything like this: >> >> $ git merge b >> [... lot of conflicts ...] >> $ git re-merge -X ours -- x/ # Leaves 0 conflicts in x/ >> $ git re-merge -X theirs -- y/ # Leaves 0 conflicts in y/ >> [... resolve the rest of conflicts manually ...] >> $ git commit >> >> [*] I do mean '-X' above, not '-s'. >> > > By this I presume you mean that you have paths x and y that ate the > ones with conflicts within them following the `git merge b`. I rather mean huge amount of conflicting paths in 'x' and 'y' subdirectories of my working tree after a merge, plus a few conflicting paths elsewhere. > > You then want a variant of the `git merge` command that will apply the > `-X ours` policy *specifically to path x* so that its particular set of > conflicts is fully resolved in favour of 'ours'. Almost. I mean to apply 'ours' option to the default 'recursive' policy for all the files that reside in the directory 'x' of my working tree and all its subdirectories (i.e., all the paths 'x/*') > > You then want to repeat those path specific resolutions, on a path by > path basis, to either `-X ours` or `-X theirs` until they are done. No. I mean to apply '-X ours' to everything under 'x/', and '-X theirs' to everything under 'y/'. Avoiding to repeat anything is the intention. > You are also expecting that one or two conflicts will require to be > fully manually resolved, until finally you can commit the result. No, I expect no conflicts left in either 'x/' or 'y/' after "re-merge", as neither 'theirs' or 'ours' should leave anything unresolved, and all the other conflicting paths (left from original merge elsewhere) I mean to resolve manually. > > Would that be right? > > Also, how do you intend to identify the 'x' and the 'y' paths, so that > you can chose the ours/theirs/manual selection? (e.g. do you pre-know > a regex/blob expansion) All the 'x/*' paths need 'ours', and all the 'y/*' paths need 'theirs'. > > The answer for individual paths is probably in the mergetool of your > choice. There are a lot of files under 'x/' and a lot of them under 'y/'. My intention is to automate a lot of manual labor, and I'm not aware of a mergetool that provides either '-X ours' or '-X theirs' resolution automatically for all the paths specified. -- Sergey
How to re-merge paths differently?
Hello, Is there anything like this: $ git merge b [... lot of conflicts ...] $ git re-merge -X ours -- x/ # Leaves 0 conflicts in x/ $ git re-merge -X theirs -- y/ # Leaves 0 conflicts in y/ [... resolve the rest of conflicts manually ...] $ git commit [*] I do mean '-X' above, not '-s'. -- Sergey
git revert --continue refuses to, help!
Hi! What do I do next, to finish reverting multiple commits? I'd use '--skip' in 'git rebase', but 'revert' doesn't have one? [skeleton (tmp|REVERTING)]$ git revert --continue On branch tmp You are currently reverting commit d8a30d3. nothing to commit, working tree clean [skeleton (tmp|REVERTING)]$ git status On branch tmp You are currently reverting commit d8a30d3. (all conflicts fixed: run "git revert --continue") (use "git revert --abort" to cancel the revert operation) nothing to commit, working tree clean [skeleton (tmp|REVERTING)]$ git revert --continue On branch tmp You are currently reverting commit d8a30d3. nothing to commit, working tree clean [skeleton (tmp|REVERTING)]$ git revert --skip fatal: Option '--skip' requires a value [skeleton (tmp|REVERTING)]$ git --version git version 2.10.0.1.g57b01a3 [skeleton (tmp|REVERTING)]$ -- Sergey
Re: [PATCH] reset: --unmerge
Junio C Hamanowrites: > The procedure to resolve a merge conflict typically goes like this: > > - first open the file in the editor, and with the help of conflict >markers come up with a resolution. > > - save the file. > > - look at the output from "git diff" to see the combined diff to >double check if the resolution makes sense. > > - perform other tests, like trying to build the result with "make". > > - finally "git add file" to mark that you are done. > > and repeating the above until you are done with all the conflicted > paths. If you, for whatever reason, accidentally "git add file" by > mistake until you are convinced that you resolved it correctly (e.g. > doing "git add file" immediately after saving, without a chance to > peruse the output from "git diff"), there is no good way to recover. "git reset --unmerge file" to undo accidental "git add file" during conflict resolution? I'm afraid "unmerge" sounds like revert of "merge", rather than revert of "resolve". I'd rather prefer to see something like: git add --undo file git merge --unresolve file git reset --unresolve file in that order, to deal with the issue. -- Sergey
Re: [PATCH 5/6] Documentation/git-merge.txt: improve short description in DESCRIPTION
Junio C Hamano <gits...@pobox.com> writes: > Sergey Organov <sorga...@gmail.com> writes: > >>>> Last, if "reference" is not good enough and we get to internals anyway, >>>> why not say SHA1 then? >>> >>> Because that is still colloquial? I think s/name/object name/ is a >>> sensible change, but not s/name/reference/. >> >> No, "reference" is more sensible here than any of "name", "object name", >> or "SHA-1", the same way as here: >> >> $ git help glossary >> [...] >> chain >> A list of objects, where each object in the list contains a >> reference to its successor (for example, the successor of a >> commit could be one of its parents). >> [...] > > The entry for "chain" and the description under discussion have > stress on different aspect, though. The description of "chain" is > more general: an object refers to another object by referring to it, > by unspecified means. The reason why it is left unspecified is > because the way a tree object refers to blobs and trees is different > from the way a commit object refers to its parents (the former has > object names of blobs and trees in the tree entries; the latter uses > "parent" entries in the object header part to record object names of > parent commits). It wants to stress more on the fact that there is > some mechanism to associate one object to others, than how that > association/linkage is expressed. > > The way the resulting commit is described in the original text of > "git merge" description stresses more on "how" by being a lot more > specific to commit objects. It does not just say "refers to parents > (by unspecified means)"; instead it tries to say what exactly are > recorded, i.e. the parents are referred to by recording the object > names of them in a new commit object. It stresses more on "how" > (because it can afford to be more specific, unlike the description > of more general concept of a "chain"). That's were our disagreement actually is, and that's what I've tried to fix with s/name/reference/, and that's why I'm against s/name/object name/. Rather than being more (and more) specific at every opportunity, one needs a good reason to get more specific. In this particular case, general DAG terminology seems to be enough to describe git-merge semantics, thus using GIT specifics is unfounded. > It may be debatable if we want to give the description of what is > exactly recorded at that point of the document, Exactly. My point in this particular discussion is that details of recording of references to parents don't belong here, even though to tell the truth I think they don't belong to git _user_ documentation at all. > but I personally > think that the users deserve a chance to learn how a merge is > recorded in "git merge" documentation. I doubt a user will gain anything from this sacred knowledge suddenly being thrown on him when what she is looking for is understanding of basic merge semantics in GIT. That said, if you still disagree, please feel free to just drop the patch. -- Sergey
Re: [PATCH 6/6] Documentation/git-merge.txt: get rid of irrelevant references to git-pull
Junio C Hamano <gits...@pobox.com> writes: > Sergey Organov <sorga...@gmail.com> writes: > >> Ah, I now see. I tried to keep the text intact as much as possible, and >> only split it into description and a note. Well, how about this then: > > Much better than your earlier patch, but I am not sure if the > updated one is that much better compared to the original. It's not intended to be much better. It is aimed at single simple target: get rid of git-pull from descriptions of operations of git-merge. I'd just remove those git-pull reference, the only one that is left after the patch, but it looks like git-merge needs an excuse to have fast-forward on by default, and that excuse is the common git-pull case. [I'd prefer 'git-merge --ff' were called from 'git-pull' and --no-ff be the default for git-merge, but that's not the case, so I left the reference to git-pull intact.] > > The pre- and post- state of this "how about this" patch essentially > say the same thing, and I suspect that the primary reason why you > think the post- state is easier to read is because you wrote it, > while the reason why I do not see much difference is because I > didn't write the updated one ;-). > > I do find "In this case, ... store the combined history" in the > original a bit awkward to read, but most of that awkardness is > inherited by the updated text. It may benefit from hinting why a > new commit is not needed a bit stronger. Here is my attempt: > > When the commit we are merging is a descendant of the current > HEAD, the history leading to the named commit can be, and by > default is, taken as the combined history of the two. Our > history is "fast forwarded" to their history by updating `HEAD` > along with the index to point at the named commit. > > This often happens when you are following along somebody else's > work via "git pull" without doing your own development. > > I think the awkwardness I felt in the original and your version is > gone from the above attempt, but I doubt that it is better over > either of them in any other way. This is entirely different matter, and should be a subject of another patch, if any. My patch meant to only address git-pull references, with as few changes as possible. -- Sergey