> 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. >> +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.