diff --git a/Annex/View.hs b/Annex/View.hs index 21f585d845..dd0025df13 100644 --- a/Annex/View.hs +++ b/Annex/View.hs @@ -19,6 +19,7 @@ import qualified Git import qualified Git.DiffTree as DiffTree import qualified Git.Branch import qualified Git.LsFiles +import qualified Git.LsTree import qualified Git.Ref import Git.UpdateIndex import Git.Sha @@ -428,21 +429,30 @@ narrowView = applyView' viewedFileReuse getViewedFileMetaData - or a file in a dotdir in the top. - Look up the metadata of annexed files, and generate any ViewedFiles, - and stage them. - - - - Must be run from top of repository. -} applyView' :: MkViewedFile -> (FilePath -> MetaData) -> View -> Annex Git.Branch applyView' mkviewedfile getfilemetadata view = do top <- fromRepo Git.repoPath (l, clean) <- inRepo $ Git.LsFiles.inRepoDetails [] [top] - liftIO . removeWhenExistsWith R.removeLink =<< fromRepo gitAnnexViewIndex - viewg <- withViewIndex gitRepo - withUpdateIndex viewg $ \uh -> do - forM_ l $ \(f, sha, mode) -> do + applyView'' mkviewedfile getfilemetadata view l clean $ + \go (f, sha, mode) -> do topf <- inRepo (toTopFilePath f) - go uh topf sha (toTreeItemType mode) =<< lookupKey f - liftIO $ void clean + go topf sha (toTreeItemType mode) =<< lookupKey f genViewBranch view + +applyView'' + :: MkViewedFile + -> (FilePath -> MetaData) + -> View + -> [t] + -> IO Bool + -> ((TopFilePath -> Sha -> Maybe TreeItemType -> Maybe Key -> Annex ()) -> t -> Annex ()) + -> Annex () +applyView'' mkviewedfile getfilemetadata view l clean a = do + viewg <- withNewViewIndex gitRepo + withUpdateIndex viewg $ \uh -> do + forM_ l $ a (go uh) + liftIO $ void clean where genviewedfiles = viewedFiles view mkviewedfile -- enables memoization @@ -464,6 +474,44 @@ applyView' mkviewedfile getfilemetadata view = do liftIO . Git.UpdateIndex.streamUpdateIndex' uh =<< inRepo (Git.UpdateIndex.stageSymlink f sha) +{- Updates the current view with any changes that have been made to its + - parent branch or the metadata since the view was created or last updated. + - + - When there were changes, returns a ref to a commit for the updated view. + - Does not update the view branch with it. + - + - This is not very optimised. An incremental update would be possible to + - implement and would be faster, but more complicated. + -} +updateView :: View -> Annex (Maybe Git.Ref) +updateView view = do + (l, clean) <- inRepo $ Git.LsTree.lsTree + Git.LsTree.LsTreeRecursive + (Git.LsTree.LsTreeLong True) + (viewParentBranch view) + applyView'' viewedFileFromReference getWorkTreeMetaData view l clean $ + \go ti -> do + let ref = Git.Ref.branchFileRef (viewParentBranch view) + (getTopFilePath (Git.LsTree.file ti)) + k <- case Git.LsTree.size ti of + Nothing -> catKey ref + Just sz -> catKey' ref sz + go + (Git.LsTree.file ti) + (Git.LsTree.sha ti) + (toTreeItemType (Git.LsTree.mode ti)) + k + oldcommit <- inRepo $ Git.Ref.sha (branchView view) + oldtree <- maybe (pure Nothing) (inRepo . Git.Ref.tree) oldcommit + newtree <- withViewIndex $ inRepo Git.Branch.writeTree + if oldtree /= Just newtree + then Just <$> do + cmode <- annexCommitMode <$> Annex.getGitConfig + let msg = "updated " ++ fromRef (branchView view) + let parent = catMaybes [oldcommit] + inRepo (Git.Branch.commitTree cmode msg parent newtree) + else return Nothing + {- Diff between currently checked out branch and staged changes, and - update metadata to reflect the changes that are being committed to the - view. @@ -501,6 +549,11 @@ withViewChanges addmeta removemeta = do withViewIndex :: Annex a -> Annex a withViewIndex = withIndexFile ViewIndexFile . const +withNewViewIndex :: Annex a -> Annex a +withNewViewIndex a = do + liftIO . removeWhenExistsWith R.removeLink =<< fromRepo gitAnnexViewIndex + withViewIndex a + {- Generates a branch for a view, using the view index file - to make a commit to the view branch. The view branch is not - checked out, but entering it will display the view. -} diff --git a/CHANGELOG b/CHANGELOG index 5917aeb4e8..f2bd1dc924 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,6 +9,8 @@ git-annex (10.20230127) UNRELEASED; urgency=medium * Changed the name of view branches to include the parent branch. Existing view branches checked out using an old name will still work. * sync: Avoid pushing view branches to remotes. + * sync: When run in a view branch, refresh the view branch to reflect any + changes that have been made to the parent branch or metadata. -- Joey Hess Mon, 06 Feb 2023 13:39:18 -0400 diff --git a/Command/Sync.hs b/Command/Sync.hs index 2348f2ea14..fb4c79f135 100644 --- a/Command/Sync.hs +++ b/Command/Sync.hs @@ -1,7 +1,7 @@ {- git-annex command - - Copyright 2011 Joachim Breitner - - Copyright 2011-2021 Joey Hess + - Copyright 2011-2023 Joey Hess - - Licensed under the GNU AGPL version 3 or higher. -} @@ -59,10 +59,11 @@ import Annex.UUID import Logs.UUID import Logs.Export import Logs.PreferredContent -import Logs.View (fromViewBranch) +import Logs.View import Annex.AutoMerge import Annex.AdjustedBranch import Annex.AdjustedBranch.Merge +import Annex.View import Annex.Ssh import Annex.BloomFilter import Annex.UpdateInstead @@ -440,7 +441,6 @@ updateBranches (Just branch, madj) = do -- to be updated, if the adjustment is not stable, and the usual -- configuration does not update it. case madj of - Nothing -> noop Just adj -> do let origbranch = branch propigateAdjustedCommits origbranch adj @@ -448,13 +448,27 @@ updateBranches (Just branch, madj) = do annexAdjustedBranchRefresh <$> Annex.getGitConfig >>= \case 0 -> adjustedBranchRefreshFull adj origbranch _ -> return () + -- When in a view branch, update it to reflect any changes + -- of its parent branch or the metadata. + Nothing -> currentView >>= \case + Nothing -> noop + Just view -> updateView view >>= \case + Nothing -> noop + Just newcommit -> do + ok <- inRepo $ Git.Command.runBool + [ Param "merge" + , Param (Git.fromRef newcommit) + ] + unless ok $ + giveup $ "failed to update view" -- Update the sync branch to match the new state of the branch inRepo $ updateBranch (syncBranch branch) branch updateBranch :: Git.Branch -> Git.Branch -> Git.Repo -> IO () updateBranch syncbranch updateto g = - unlessM go $ giveup $ "failed to update " ++ Git.fromRef syncbranch + unlessM go $ + giveup $ "failed to update " ++ Git.fromRef syncbranch where go = Git.Command.runBool [ Param "branch" diff --git a/Command/View.hs b/Command/View.hs index a22d78bc4c..9954229e10 100644 --- a/Command/View.hs +++ b/Command/View.hs @@ -35,7 +35,7 @@ start [] = giveup "Specify metadata to include in view" start ps = ifM safeToEnterView ( do view <- mkView ps - go view =<< currentView + go view =<< currentView , giveup "Not safe to enter view." ) where diff --git a/doc/git-annex-sync.mdwn b/doc/git-annex-sync.mdwn index 4f5b66e247..634b110918 100644 --- a/doc/git-annex-sync.mdwn +++ b/doc/git-annex-sync.mdwn @@ -47,7 +47,10 @@ have the same value as the currently checked out branch. When [[git-annex-adjust]](1) has been used to check out an adjusted branch, running sync will propagate changes that have been made back to the -parent branch, without propagating the adjustments. +parent branch, without propagating the adjustments. When +[[git-annex-view]](1) has been used to check out a view branch, +running sync will update the view branch to reflect any changes +to the parent branch or metadata. # OPTIONS diff --git a/doc/todo/Metadata_changes_are_not_reflected_in_a_view/comment_4_6ab0e38d8be8a70d501108f207d41d82._comment b/doc/todo/Metadata_changes_are_not_reflected_in_a_view/comment_4_6ab0e38d8be8a70d501108f207d41d82._comment new file mode 100644 index 0000000000..75af01c6c8 --- /dev/null +++ b/doc/todo/Metadata_changes_are_not_reflected_in_a_view/comment_4_6ab0e38d8be8a70d501108f207d41d82._comment @@ -0,0 +1,29 @@ +[[!comment format=mdwn + username="joey" + subject="""comment 4""" + date="2023-02-08T19:32:34Z" + content=""" +`git-annex sync` when in a view branch will now update it. + +Leaving this open for optimising it. + +Also because of this problem: + + joey@darkstar:~/tmp/m#master(author=_)>git-annex sync + commit + On branch views/master(author=_) + nothing to commit, working tree clean + ok + merge synced/master + fatal: refusing to merge unrelated histories + failed + +Looks like it should not be trying to merge the synced/master +branch into the view branch. But, this makes me wonder, does the master branch +get updated with new files pulled from remotes? If not, the view branch +won't be updated to have them either. + +Also, I think that it may try to import trees from importree special remotes, +into the view branch. Perhaps those should also get imported but merged into +the master branch... +"""]]