fix unannex data overwrite bug
authorJoey Hess <joeyh@joeyh.name>
Mon, 22 Feb 2021 17:35:00 +0000 (13:35 -0400)
committerJoey Hess <joeyh@joeyh.name>
Mon, 22 Feb 2021 17:35:00 +0000 (13:35 -0400)
unannex, uninit: When an annexed file is modified, don't overwrite the
modified version with an older version from the annex

This commit was sponsored by Mark Reidenbach on Patreon.

CHANGELOG
Command/Unannex.hs
doc/bugs/unannex_of_modified_file_loses_modification.mdwn

index cd27e8a44d9bfba2d05812ccc0934cf8e8cc402b..fc99e6e64eb506c3651651f5a3947676f09c7b90 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -28,7 +28,9 @@ git-annex (8.20210128) UNRELEASED; urgency=medium
     rather than doing it in a second pass.
   * Bugfix: fsck --from a ssh remote did not actually check that the
     content on the remote is not corrupted.
-  * unannex, uninit: Avoid running git rm once per annexed file,
+  * unannex, uninit: When an annexed file is modified, don't overwrite
+    the modified version with an older version from the annex.
+  * unannex, uninit: Don't run git rm once per annexed file, 
     for a large speedup.
 
  -- Joey Hess <id@joeyh.name>  Thu, 28 Jan 2021 12:34:32 -0400
index 690a946be617256151f512eb515e0c8726c7de0a..94a89f15023991705524718b466d13a6eb3d8582 100644 (file)
@@ -10,6 +10,7 @@ module Command.Unannex where
 import Command
 import qualified Annex
 import Annex.Perms
+import Annex.Link
 import qualified Annex.Queue
 import Utility.CopyFile
 import qualified Database.Keys
@@ -41,7 +42,6 @@ start si file key =
 
 perform :: RawFilePath -> Key -> CommandPerform
 perform file key = do
-       liftIO $ removeFile (fromRawFilePath file)
        Annex.Queue.addCommand [] "rm"
                [ Param "--cached"
                , Param "--force"
@@ -49,19 +49,34 @@ perform file key = do
                , Param "--"
                ]
                [fromRawFilePath file]
-       next $ cleanup file key
+       isAnnexLink file >>= \case
+               -- If the file is locked, it needs to be replaced with
+               -- the content from the annex. Note that it's possible
+               -- for key' (read from the symlink) to differ from key
+               -- (cached in git).
+               Just key' -> do
+                       removeassociated
+                       next $ cleanup file key'
+               -- If the file is unlocked, it can be unmodified or not and
+               -- does not need to be replaced either way.
+               Nothing -> do
+                       removeassociated
+                       next $ return True
+  where
+       removeassociated = 
+               Database.Keys.removeAssociatedFile key
+                       =<< inRepo (toTopFilePath file)
 
 cleanup :: RawFilePath -> Key -> CommandCleanup
 cleanup file key = do
-       Database.Keys.removeAssociatedFile key =<< inRepo (toTopFilePath file)
+       liftIO $ removeFile (fromRawFilePath file)
        src <- calcRepo (gitAnnexLocation key)
        ifM (Annex.getState Annex.fast)
                ( do
                        -- Only make a hard link if the annexed file does not
-                       -- already have other hard links pointing at it.
-                       -- This avoids unannexing (and uninit) ending up
-                       -- hard linking files together, which would be
-                       -- surprising.
+                       -- already have other hard links pointing at it. This
+                       -- avoids unannexing (and uninit) ending up hard
+                       -- linking files together, which would be surprising.
                        s <- liftIO $ R.getFileStatus src
                        if linkCount s > 1
                                then copyfrom src
index 28a0f1d18240a7282ccbc52a12b91b1bb2105551..54a6d811909c52a1a27c2f3607fb98af97023fa8 100644 (file)
@@ -4,3 +4,5 @@ This is a data loss bug.
 
 Command.Unannex.cleanup just overwrites whatever's there without checking.
 Happens with both locked and unlocked files. --[[Joey]]
+
+> [[fixed|done]] --[[Joey]]