"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
Re: Should merge (and rebase) allow modified files when fast-forwarding?
To:
James Cook <falsifian@falsifian.org>
Cc:
gameoftrees@openbsd.org
Date:
Thu, 8 Jun 2023 09:17:02 +0200

Download raw body.

Thread
On Wed, Jun 07, 2023 at 09:54:16PM +0000, James Cook wrote:
> TL;DR: When got merge can fast-forward, should it still check for local
> changes / staged files? got rebase does.
> 
> 
> Consider the following short history from newest to oldest:
> 
> o [main] Another commit
> |
> o [br] A commit
> 
> If you do the following:
> 
> 1. got update -b main
> 2. echo 'some new text' >> ./some_tracked_file
> 3. got rebase br
> 
> got will complain:
> 
> 	got: work tree contains local changes; these changes must be committed or reverted first
> 
> Arguably, "got rebase" could have proceeded anyway, since there's
> nothing to do except update a reference.
> 
> I have some WIP* on making "got merge" fast-forward when possible. My
> question is, should "got merge" be as strict as "got rebase" is in the
> fast-forwarding case?
> 
> One argument for refusing is that fast-forwarding when there are local
> changes could cause confusion. If there are conflicts updating the
> changed files, you get a message like:
> 
> 	Files with new merge conflicts: 1
> 
> This seems potentially confusing, since the word "merge" refers both to
> the process of creating a merge commit and the process of reconciling
> changes.
> 
> On the other hand, skipping the check could save a bit of time for users
> who know what they're doing.
> 
> I don't know which I prefer. Leaning toward refusing, like got rebase
> does.
> 
> (Returning to the rebase example, note that if you try to rebase "main"
> onto "br" instead, the check gets skipped; that feels a tiny bit
> inconsistent.)
> 
> *The WIP is just new tests and an update to the man page. No code
> changes yet. Happy to share what I have.

Bailing out on local changes is the safe option.
There is a reason why some commands are currently very strict about this.

Even in a fast-forward scenario, any commits between the old tip and the
new tip could have moved files around, have deleted arbitrary parts of the
tree, or have added new files in arbitrary places. And local changes in
the work tree can have similar effects on the tree configuration.
Checking out files from the new tip on top of local changes could then
result in tree conflicts, such as one file having moved to disparate
destinations, two different files being added at the same path, and so on.

For now, Got is just merging text and skips any files that aren't present
at their expected path. This leaves tree conflicts for the user to figure
out, which can be difficult. In the long term I want to implement assisted
tree conflict resolution and then a clean work tree to start from becomes
a lot more important than it is now.
During merges it will be much easier when only already committed changes
can conflict in this way. Adding local changes into the mix complicates
the resolution process since the work tree's configuration could then differ
from everything that has been committed to the repository. We would then
have 3 conflicting tree configurations to reconcile, instead of just two.

Given this, the only commands which would need to worry about tree conflicts
involving local work tree state are 'got update', 'got patch',
'got cherrypick', 'got backout', and 'got unstage'.
Other commands should require a clean work tree as their starting point.