fsck: Fix location of annexed files when run in linked worktrees
authorJoey Hess <joeyh@joeyh.name>
Tue, 15 Jul 2025 17:09:45 +0000 (13:09 -0400)
committerJoey Hess <joeyh@joeyh.name>
Tue, 15 Jul 2025 17:09:45 +0000 (13:09 -0400)
This cleans up after the bug that was fixed in commit
6a9e923c74a1ae5c4c904e7a28e9339bdc241427
Object files that were stored in the wrong location are rescued,
and after that any wrong location logs will be fixed by the usual fsck.

Annex.hs
CHANGELOG
Command/Fsck.hs
doc/bugs/Missing_file_content_in_secondary_worktree___40__win__41__.mdwn
doc/bugs/Missing_file_content_in_secondary_worktree___40__win__41__/comment_7_cfb97162cd21818995f9d71a5ce3a0d0._comment [new file with mode: 0644]

index 84b2bda0ad11710a384312e4e30274920cb9cac8..aba23587fb328589bec6066ce70385fbdb22c3c1 100644 (file)
--- a/Annex.hs
+++ b/Annex.hs
@@ -12,6 +12,7 @@ module Annex (
        AnnexState(..),
        AnnexRead(..),
        new,
+       new',
        run,
        eval,
        makeRunner,
@@ -291,10 +292,13 @@ newAnnexState c r = do
  - Ensures the config is read, if it was not already, and performs
  - any necessary git repo fixups. -}
 new :: Git.Repo -> IO (AnnexState, AnnexRead)
-new r = do
+new = new' fixupRepo
+
+new' :: (Git.Repo -> GitConfig -> IO Git.Repo) -> Git.Repo -> IO (AnnexState, AnnexRead)
+new' f r = do
        r' <- Git.Config.read r
        let c = extractGitConfig FromGitConfig r'
-       st <- newAnnexState c =<< fixupRepo r' c
+       st <- newAnnexState c =<< f r' c
        rd <- newAnnexRead c
        return (st, rd)
 
index d85abaa2c1293abc1f0b5da5a18637e334bb60d2..7216b21fbb29306e2b1bee49bd74723610266846 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,8 @@ git-annex (10.20250631) UNRELEASED; urgency=medium
     symlinks, that caused annexed file content to be stored in the wrong
     location inside the git directory, and also caused pointer files to not
     get populated.
+  * fsck: Fix location of annexed files when run in linked worktrees
+    that have experienced the above bug.
   * Fix symlinks generated to annexed content when in adjusted unlocked
     branch in a linked worktree on a filesystem not supporting symlinks.
 
index 50c21149b3757c86369cbf8cc594bf675c0f56a2..cd9dd335e1043435ed58360c113012e2abf38987 100644 (file)
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2010-2023 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2025 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -15,6 +15,7 @@ import qualified Annex
 import qualified Remote
 import qualified Types.Backend
 import qualified Backend
+import qualified Git
 import Annex.Content
 import Annex.Verify
 #ifndef mingw32_HOST_OS
@@ -24,6 +25,7 @@ import Annex.Content.Presence
 import Annex.Content.Presence.LowLevel
 import Annex.Perms
 import Annex.Link
+import Annex.Fixup
 import Logs.Location
 import Logs.Trust
 import Logs.Activity
@@ -102,6 +104,8 @@ seek o = startConcurrency commandStages $ do
        from <- maybe (pure Nothing) (Just <$$> getParsed) (fsckFromOption o)
        u <- maybe getUUID (pure . Remote.uuid) from
        checkDeadRepo u
+       when (isNothing from) $
+               cleanupLinkedWorkTreeBug
        i <- prepIncremental u (incrementalOpt o)
        let seeker = AnnexedFileSeeker
                { startAction = const $ start from i
@@ -768,4 +772,38 @@ withFsckDb (ContIncremental h) a = a h
 withFsckDb (StartIncremental h) a = a h
 withFsckDb (NonIncremental mh) a = maybe noop a mh
 withFsckDb (ScheduleIncremental _ _ i) a = withFsckDb i a
-
+-- A bug caused linked worktrees on filesystems not supporting symlinks
+-- to not use the common annex directory, but one annex directory per
+-- linked worktree. Object files could end up stored in those directories.
+--
+-- When run in a linked worktree with its own annex directory that is not a
+-- symlink, move any object files to the right location, and delete the
+-- annex directory.
+cleanupLinkedWorkTreeBug :: Annex ()
+cleanupLinkedWorkTreeBug = 
+       whenM (Annex.inRepo needsGitLinkFixup) $ do
+               r <- Annex.gitRepo
+               -- mainWorkTreePath is set by fixupUnusualRepos.
+               -- Unsetting it makes a version of the Repo that uses
+               -- the wrong object location.
+               let r' = r { Git.mainWorkTreePath = Nothing }
+               let dir = gitAnnexDir r'
+               whenM (liftIO $ dirnotsymlink dir) $ do
+                       showSideAction $ "Cleaning up directory " 
+                               <> QuotedPath dir
+                               <> " created by buggy version of git-annex"
+                       (st, rd) <- liftIO $ Annex.new' (\r'' _c -> pure r'') r'
+                       ks <- liftIO $ Annex.eval (st, rd) $
+                               listKeys InAnnex
+                       forM_ ks $ \k -> void $ tryNonAsync $ do
+                               loc <- liftIO $ gitAnnexLocation k r'
+                                       (Annex.gitconfig st)
+                               moveAnnex k loc
+                       void $ tryNonAsync $ liftIO $
+                               removeDirectoryRecursive dir
+  where
+       dirnotsymlink dir = 
+               tryIO (R.getSymbolicLinkStatus (fromOsPath dir)) >>= \case
+                       Right st -> return $ not (isSymbolicLink st)
+                       Left _ -> return False
index bbbb8143b3edfafc237380fa162c4511cc51f44e..9aa0d48d6dc04e80c22bbec7f39ac72e354ec76c 100644 (file)
@@ -97,3 +97,5 @@ This is on win11.
 Absolutely! Approaching 15 years of bigger, better, faster, more ;-)
 
 [[!tag projects/INM7]]
+
+> [[fixed|done]] --[[Joey]]
diff --git a/doc/bugs/Missing_file_content_in_secondary_worktree___40__win__41__/comment_7_cfb97162cd21818995f9d71a5ce3a0d0._comment b/doc/bugs/Missing_file_content_in_secondary_worktree___40__win__41__/comment_7_cfb97162cd21818995f9d71a5ce3a0d0._comment
new file mode 100644 (file)
index 0000000..bb75266
--- /dev/null
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2025-07-15T17:07:43Z"
+ content="""
+Running `git-annex fsck` in the affected worktree will clean up from this
+bug.
+"""]]