avoid removing old associated file when there is a merge conflict
authorJoey Hess <joeyh@joeyh.name>
Tue, 1 Jun 2021 15:24:15 +0000 (11:24 -0400)
committerJoey Hess <joeyh@joeyh.name>
Tue, 1 Jun 2021 15:43:00 +0000 (11:43 -0400)
It makes sense to keep the key used by the old version of an
associated file, until the merge conflict is resolved.

Note that, since in this case git diff is being run with --index, it's
not possible to use -1 or -3, which would let the keys
associated with the new versions of the file also be added. That would
be better, because it's possible that the local modification to the file
that caused the merge conflict has not yet gotten its new key recorded
in the db.

Opened a bug about a case this is thus not able to address.

Sponsored-by: Boyd Stephen Smith Jr. on Patreon
Database/Keys.hs
doc/bugs/case_where_keys_db_lags_reality.mdwn [new file with mode: 0644]

index 842b53f1d1415977e6e8aa12335d3acc2d169263..3154118fdb957999926e254e9c09e702c3eed84f 100644 (file)
@@ -309,14 +309,18 @@ reconcileStaged qh = do
        
        procdiff (info:file:rest) changed
                | ":" `S.isPrefixOf` info = case S8.words info of
-                       (_colonsrcmode:dstmode:srcsha:dstsha:_change:[]) -> do
-                               removed <- catKey (Ref srcsha) >>= \case
-                                       Just oldkey -> do
-                                               liftIO $ SQL.removeAssociatedFile oldkey
-                                                       (asTopFilePath file)
-                                                       (SQL.WriteHandle qh)
-                                               return True
-                                       Nothing -> return False
+                       (_colonsrcmode:dstmode:srcsha:dstsha:status:[]) -> do
+                               -- avoid removing associated file when
+                               -- there is a merge conflict
+                               removed <- if status /= "U" 
+                                       then catKey (Ref srcsha) >>= \case
+                                               Just oldkey -> do
+                                                       liftIO $ SQL.removeAssociatedFile oldkey
+                                                               (asTopFilePath file)
+                                                               (SQL.WriteHandle qh)
+                                                       return True
+                                               Nothing -> return False
+                                       else return False
                                added <- catKey (Ref dstsha) >>= \case
                                        Just key -> do
                                                liftIO $ SQL.addAssociatedFile key
diff --git a/doc/bugs/case_where_keys_db_lags_reality.mdwn b/doc/bugs/case_where_keys_db_lags_reality.mdwn
new file mode 100644 (file)
index 0000000..17a799d
--- /dev/null
@@ -0,0 +1,28 @@
+Found a case where the associated files in the keys db end up out-of-date.
+Make a repo with an unlocked file, clone it to a second repo, and set up a
+conflict involving that file in both repos, using git-annex add to add the
+conflicting version, and not running other git-annex commands after that,
+before pulling the conflicting branch. When the associated files db
+gets updated in the conflict situation, only 1 key has the conflicting file
+associated with it, rather than 2 or 3.
+
+The original key before the conflict has the file associated with it, but
+the new local key and new remote key do not.
+
+The result is that a drop of another file that uses the same key may not
+honor the preferred content of the file that is in conflict.
+
+Once the conflict is resolved, git-annex will recover, the problem only
+occurs while there's an unmerged conflict, and only when git-annex did not
+get a change to notice the local modification before the conflict happened.
+
+This only affected locked files, because when an unlocked file is staged,
+git-annex updates the keys db. So, one solution to this bug will be for
+git-annex to also update the keys db when staging locked files.
+(Unfortunately this would make mass adds somewhat slower.)
+
+Or, possibly, for reconcileStaged to not use git diff --index in this case,
+but git diff with -1 and -3. That lets both sides of the merge conflict be
+accessed, and it could then add the file to both keys. As well as not
+slowing down git-annex add, this would let it honor the preferred content
+of the conflicting file for all 3 keys. --[[Joey]]