vmerge inconsistency with regards to revert (and a suggested fix)
(1.1) By Stephan Beal (stephan) on 2021-12-15 03:55:10 edited from 1.0 [source]
It seems that we have bit of an inconsistency in the vmerge table handling with regards to revert. Namely: revert only clears vmerge if the revert is a whole-checkout revert, not individual files. That effectively allows a user to bypass the limitation of not being able to check in a partial merge:
$ fossil merge some-branch
$ fossil revert merged-file-X
$ fossil ci -m "...."
We've just effectively done a checkin of a partial merge.
However, that revert (before we do the checkin) leaves the vmerge state for merged-file-X (if any) intact because the revert was for a specific file, not a full-checkout revert.
That all seems harmless enough but it is an inconsistency.
My proposal is that when we do a revert, and at the end of vfile_scan()
, we cleanup up vmerge as follows:
- Delete all vmerge entries which map to a vfile entry which has a
chnged
value of 0 (i.e. was reverted or has been otherwise modified back to its original state). - If all entries in vmerge have an
id<=0
then delete them all. In this case, there are no file-level merged pending, so that state would seem to be stale/not useful. (IDs of 0 and lower are used for storing non-file-level merge metadata.)
In terms of code, that looks something like this new snippet from libfossil:
int fsl__ckout_clear_merge_state( fsl_cx * const f, bool fullWipe ){
int rc;
if(fullWipe){
rc = fsl_cx_exec(f,"DELETE FROM vmerge /*%s()*/", __func__);
}else{
rc = fsl_cx_exec_multi(f,
"DELETE FROM vmerge WHERE id IN("
"SELECT vm.id FROM vmerge vm, vfile vf "
"WHERE vm.id=vf.id AND vf.chnged=0);"
"DELETE FROM vmerge WHERE NOT EXISTS("
"SELECT 1 FROM vmerge WHERE id>0) "
"AND NOT EXISTS(SELECT 1 FROM vfile WHERE chnged>1);"
"/*%s()*/", __func__ );
}
return rc;
}
(Edited to add an AND clause to the second final DELETE.)
(Sidebar: the __func__
part allows me to quickly track down the origin of SQL tracing output.)
My initial testing with that implementation shows it to behave just how i want it to, but the real question is whether my expectations and assumptions here are valid.
Opinions on this change are very welcomed.
(2) By Richard Hipp (drh) on 2021-12-15 11:15:51 in reply to 1.1 [link] [source]
I'm not overly concerned about this interaction with "merge" and "revert". In fact, I think I have used it on occasion. Notice that you could still achieve a partial merge without using revert via something like this:
$ cp merged-file-X /tmp/merged-file-X $ fossil merge some-branch $ mv /tmp/merged-file-X merged-file-X $ fossil ci -m "..."
You might also overwrite and undo changes using the "fossil artifact" command. I had to do that earlier this morning, as a matter of fact, in order to fix a merge conflict in a private repo.
Has anyone actually run into problems from doing a merge and partial revert then committing? Is this really an issue someone has had, or might potentially have? Am I missing something?
(3) By Stephan Beal (stephan) on 2021-12-15 11:30:53 in reply to 2 [link] [source]
Has anyone actually run into problems from doing a merge and partial revert then committing? Is this really an issue someone has had, or might potentially have? Am I missing something?
i should have pointed out that i don't believe this is a "bug." My proposed change doesn't, to the best of my knowledge, keep a user from doing any of those things to check in a "partial" merge, that was just the context it initially came up in during testing.
The proposed change simply keeps vmerge in stricter consistency with vfile without (AFAIK) removing any existing functionality/workarounds. That said: it's still being tested as i finalize libfossil's merge port, so there's still a chance some misbehavior will be uncovered ;).