git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] technical doc: add a design doc for the evolve command

From
SXStefan Xenos <sxenos@google.com>
Date
Nov 20, 2018, 20:19 UTC
Message-ID
<CAPL8ZivzMR30bt62SzOnmwmMnVZdMSiYSUhRSTg6uxyQUGcHLw@mail.gmail.com>
In-Reply-To
<a4c5d89c-cf82-6b1d-2690-82c7f8a95cc4@talktalk.net>
Show 5 quoted lines
> This explains why we have 'origin' fields in the meta commits, it might
> be worth putting a forward reference or note earlier on to explain why
> recording the origin is useful. (I didn't find gerrit needs it very
> convincing on its own but it is actually more general than gerrit's
> specific use case)
I'll add the forward reference.

TBH, gerrit is the main reason I added it - so I'm interested in why you didn't find the gerrit use-case convincing. Can you elaborate? (If there's some other way around the gerrit requirement, we might not need the origin parents)

> Should this be meta/mychange:refs/for/master or have I missed something?
It should be metas/mychange/.... It's already fixed in the v2 patch.

I really wanted to use the namespace "changes", but gerrit is squatting on that. I tried "change", but that brakes the plural naming scheme and may get confused with gerrit's namespace, so I settled on "metas".

> I think it would make sense to have this next to the sections on commit
> --amend and merge I was wondering what about rebase when I was reading
> those sections.
Will do.
> I'm a bit confused why it is creating a meta ref per commit rather than
> one for the current branch.
I tried to explain that later in the doc. meta refs serve two purposes
- they act as stable names for changes (or at least the commits at the
head of each change) and they point to the metacommits that are
currently in use. For both purposes, we need a ref per commit. For the
"stable name" case, this should be obvious - something that just
points to a branch couldn't provide different names for each commit on
that branch. The metacommit case is less obvious - the set of
metacommits for one change aren't connected to the metacommits for any
other change. The "parents" of a metacommit are older versions of the
same change. They don't point to the metacommits from the parent
change. That means that there is no single ref we could create for a
branch that would reach all the necessary metacommits.
> I got the impression they had put quite a lot of effort
> into having evolve automatically run and resolve divergences when
> pulling and rebasing, is there a long term plan for git to do the same?

IMO, we should add anything to the plan if doing so improves the workflow of our users... but it sounds like you're referring to mercurial features I've never used. Could you point me to specific docs on the feature you want and/or make a concrete suggestion about how it might work?

I never use pull so it slipped my mind. It would probably make sense to have the option of doing an automatic evolve after pull (actually, once the feature is stable, most users would probably want it to be the default). How do you think it should be triggered? "git pull --evolve"? or perhaps "git pull --rebase=evolve"? We should probably also introduce a new "evolve" enum value to branch.<name>.rebase config value. I'll use "--evolve" for now. If may make sense to add "--evolve" to every git command that performs an automatic evolve when done.

> What happens if the original commit are currently checked out with local
> changes?

For a start, I'll probably just display an error message if the current working tree is dirty ("Please stash"). Long term, I'd like it to work like rebase --autostash. It should stash your changes, do the evolve, return to the evolved version of the original change, and reapply the stash. I'll add this to the doc.

> Can I suggest using refs/remote/<remotenome>/metas. I
Ooh! Great idea! I'll update the doc.
> I think this could be useful (although I guess you can get the branches
> you've been working on recently from HEAD's reflog quite easily).

The changes list is different from the reflog. It's a list of all your unsubmitted patches - regardless of their age or what branch they're on. They may not have corresponding branches: you may have been working on them with a detached head, or there may be multiple changes on the same branch. You might not have visited them recently, in which case they wouldn't be in the reflog at all. You may have reset to an older version of the change, in which case they'd be in the reflog but the reflog and change point to different places. If you've used gerrit before, the "changes" list will contain pretty much the same content as the gerrit dashboard, except that it works locally.

Show 12 quoted lines
>> +Much like a merge conflict, divergence is a situation that requires user
>> +intervention to resolve. The evolve command will stop when it encounters
>> +divergence and prompt the user to resolve the problem. Users can solve the
>> +problem in several ways:
>> +
>> +- Discard one of the changes (by deleting its change branch).
>> +- Merge the two changes (producing a single change branch).
>
>I assume this wont create merge commits for the actual commits though,
>just merge the meta branches and create some new commits that are each
>the result of something like 'merge-recursive original-commit
>our-new-version their-new-version'

It depends on which version of merge you use. I've proposed a new "merge --amend" argument specifically for resolving divergence. It avoids creating merge commits as long as there's only one parent remaining after combining the parents of the commits being merged. Basically, if the two things being merged are divergent commits, it would resolve the divergence without creating a new merge commit... but if the divergent commits had different parents or were themselves merge commits, the result may still be a merge commit.

If you run the normal version of merge, it *would* create a merge commit and leave the changes divergent. However, one of the transformations on the evolve command will look for this situation and resolve it. Specifically, if it encounters two divergent changes but exactly one child change contains a merge that would resolve that divergence, the transformation will merge all three changes, squash them together, and make all three changes point to the result. I'm not sure what to call this transformation, but it serves a useful purpose: it allows users to use either form of merge to resolve the divergence. If they use the "--amend" version of merge, no merge commit is created and the divergence is resolved immediately. If they use the normal version of merge, a merge commit is created (as it is now) and the evolve command figures out later whether that merge was intended to resolve divergence. This avoids putting any magic in the merge command itself, avoids changing the existing behavior of the merge command, and it means that most users won't need to learn about "merge --amend" and can't accidentally paint themselves into a corner by accidentally using the wrong kind of merge. Power users can disable this transformation and resolve their divergence explicitly using --amend. Novices can just use the defaults and things will probably work.

It can get more complex, though. If there are two or more child changes containing merge commits that resolve divergence, this transformation would happen separately for each one and the resulting merges would themselves become divergent (since they are two conflicting solutions to the same problem). This may happen if the user unnecessarily resolved the same divergence multiple times with different merge commits. At that point, one of several things would happen. If after rebasing the merge, the result automerges to exactly the same thing (which would happen if both merges were the result of running the automerger on incremental versions of the same two changes), the divergence would instantly resolve itself because the two changes are aliases. Otherwise, this new divergence would be treated like any other and evolve would eventually try to apply the same algorithm recursively on the new divergent changes.

I'll elaborate more on the supported transformations in the doc for the evolve command.

Previous: Phillip WoodNext: Phillip Wood
Message 33 of 37 in “technical doc: add a design doc for the evolve command”
  1. technical doc: add a design doc for the evolve commandsxenos@google.com, Nov 15, 2018
  2. Johannes SchindelinNov 15, 2018
  3. Stefan XenosNov 17, 2018
  4. SZEDER GáborNov 19, 2018
  5. Stefan XenosNov 19, 2018
  6. Jonathan NiederNov 20, 2018
  7. Ævar Arnfjörð BjarmasonNov 15, 2018
  8. Jonathan NiederNov 20, 2018
  9. Ævar Arnfjörð BjarmasonNov 20, 2018
  10. Stefan XenosNov 20, 2018
  11. Jonathan NiederNov 20, 2018
  12. Stefan XenosNov 20, 2018
  13. Jonathan NiederNov 21, 2018
  14. Stefan XenosNov 21, 2018
  15. Derrick StoleeNov 16, 2018
  16. Stefan XenosNov 17, 2018
  17. Duy NguyenNov 17, 2018
  18. Stefan XenosNov 18, 2018
  19. Stefan XenosNov 18, 2018
  20. Junio C HamanoNov 18, 2018
  21. Junio C HamanoNov 17, 2018
  22. Stefan XenosNov 19, 2018
  23. Junio C HamanoNov 19, 2018
  24. Stefan XenosNov 19, 2018
  25. Junio C HamanoNov 19, 2018
  26. Junio C HamanoNov 19, 2018
  27. Stefan XenosNov 19, 2018
  28. Jonathan NiederNov 19, 2018
  29. Junio C HamanoNov 20, 2018
  30. Stefan XenosNov 20, 2018
  31. Phillip WoodNov 20, 2018
  32. Phillip WoodNov 20, 2018
  33. Stefan XenosNov 20, 2018
  34. technical doc: add a design doc for the evolve commandPhillip Wood, Jan 15, 2019
  35. Phillip WoodNov 20, 2018
  36. Stefan XenosNov 20, 2018
  37. Phillip WoodNov 21, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.