Fossil User Forum

vmerge inconsistency with regards to revert (and a suggested fix)
Login

vmerge inconsistency with regards to revert (and a suggested fix)

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 ;).