sync in view branch updates the view branch

* 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.

This is basically working, but probably needs some more work to deal with
all the edge cases of things sync does.

Sponsored-by: Lawrence Brogan on Patreon
This commit is contained in:
Joey Hess 2023-02-08 15:37:28 -04:00
parent a11d6e0baf
commit 5f9bf51438
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
6 changed files with 115 additions and 14 deletions

View file

@ -19,6 +19,7 @@ import qualified Git
import qualified Git.DiffTree as DiffTree import qualified Git.DiffTree as DiffTree
import qualified Git.Branch import qualified Git.Branch
import qualified Git.LsFiles import qualified Git.LsFiles
import qualified Git.LsTree
import qualified Git.Ref import qualified Git.Ref
import Git.UpdateIndex import Git.UpdateIndex
import Git.Sha import Git.Sha
@ -428,21 +429,30 @@ narrowView = applyView' viewedFileReuse getViewedFileMetaData
- or a file in a dotdir in the top. - or a file in a dotdir in the top.
- Look up the metadata of annexed files, and generate any ViewedFiles, - Look up the metadata of annexed files, and generate any ViewedFiles,
- and stage them. - and stage them.
-
- Must be run from top of repository.
-} -}
applyView' :: MkViewedFile -> (FilePath -> MetaData) -> View -> Annex Git.Branch applyView' :: MkViewedFile -> (FilePath -> MetaData) -> View -> Annex Git.Branch
applyView' mkviewedfile getfilemetadata view = do applyView' mkviewedfile getfilemetadata view = do
top <- fromRepo Git.repoPath top <- fromRepo Git.repoPath
(l, clean) <- inRepo $ Git.LsFiles.inRepoDetails [] [top] (l, clean) <- inRepo $ Git.LsFiles.inRepoDetails [] [top]
liftIO . removeWhenExistsWith R.removeLink =<< fromRepo gitAnnexViewIndex applyView'' mkviewedfile getfilemetadata view l clean $
viewg <- withViewIndex gitRepo \go (f, sha, mode) -> do
withUpdateIndex viewg $ \uh -> do
forM_ l $ \(f, sha, mode) -> do
topf <- inRepo (toTopFilePath f) topf <- inRepo (toTopFilePath f)
go uh topf sha (toTreeItemType mode) =<< lookupKey f go topf sha (toTreeItemType mode) =<< lookupKey f
liftIO $ void clean
genViewBranch view 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 where
genviewedfiles = viewedFiles view mkviewedfile -- enables memoization genviewedfiles = viewedFiles view mkviewedfile -- enables memoization
@ -464,6 +474,44 @@ applyView' mkviewedfile getfilemetadata view = do
liftIO . Git.UpdateIndex.streamUpdateIndex' uh liftIO . Git.UpdateIndex.streamUpdateIndex' uh
=<< inRepo (Git.UpdateIndex.stageSymlink f sha) =<< 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 {- Diff between currently checked out branch and staged changes, and
- update metadata to reflect the changes that are being committed to the - update metadata to reflect the changes that are being committed to the
- view. - view.
@ -501,6 +549,11 @@ withViewChanges addmeta removemeta = do
withViewIndex :: Annex a -> Annex a withViewIndex :: Annex a -> Annex a
withViewIndex = withIndexFile ViewIndexFile . const 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 {- Generates a branch for a view, using the view index file
- to make a commit to the view branch. The view branch is not - to make a commit to the view branch. The view branch is not
- checked out, but entering it will display the view. -} - checked out, but entering it will display the view. -}

View file

@ -9,6 +9,8 @@ git-annex (10.20230127) UNRELEASED; urgency=medium
* Changed the name of view branches to include the parent branch. * Changed the name of view branches to include the parent branch.
Existing view branches checked out using an old name will still work. Existing view branches checked out using an old name will still work.
* sync: Avoid pushing view branches to remotes. * 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 <id@joeyh.name> Mon, 06 Feb 2023 13:39:18 -0400 -- Joey Hess <id@joeyh.name> Mon, 06 Feb 2023 13:39:18 -0400

View file

@ -1,7 +1,7 @@
{- git-annex command {- git-annex command
- -
- Copyright 2011 Joachim Breitner <mail@joachim-breitner.de> - Copyright 2011 Joachim Breitner <mail@joachim-breitner.de>
- Copyright 2011-2021 Joey Hess <id@joeyh.name> - Copyright 2011-2023 Joey Hess <id@joeyh.name>
- -
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
@ -59,10 +59,11 @@ import Annex.UUID
import Logs.UUID import Logs.UUID
import Logs.Export import Logs.Export
import Logs.PreferredContent import Logs.PreferredContent
import Logs.View (fromViewBranch) import Logs.View
import Annex.AutoMerge import Annex.AutoMerge
import Annex.AdjustedBranch import Annex.AdjustedBranch
import Annex.AdjustedBranch.Merge import Annex.AdjustedBranch.Merge
import Annex.View
import Annex.Ssh import Annex.Ssh
import Annex.BloomFilter import Annex.BloomFilter
import Annex.UpdateInstead import Annex.UpdateInstead
@ -440,7 +441,6 @@ updateBranches (Just branch, madj) = do
-- to be updated, if the adjustment is not stable, and the usual -- to be updated, if the adjustment is not stable, and the usual
-- configuration does not update it. -- configuration does not update it.
case madj of case madj of
Nothing -> noop
Just adj -> do Just adj -> do
let origbranch = branch let origbranch = branch
propigateAdjustedCommits origbranch adj propigateAdjustedCommits origbranch adj
@ -448,13 +448,27 @@ updateBranches (Just branch, madj) = do
annexAdjustedBranchRefresh <$> Annex.getGitConfig >>= \case annexAdjustedBranchRefresh <$> Annex.getGitConfig >>= \case
0 -> adjustedBranchRefreshFull adj origbranch 0 -> adjustedBranchRefreshFull adj origbranch
_ -> return () _ -> 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 -- Update the sync branch to match the new state of the branch
inRepo $ updateBranch (syncBranch branch) branch inRepo $ updateBranch (syncBranch branch) branch
updateBranch :: Git.Branch -> Git.Branch -> Git.Repo -> IO () updateBranch :: Git.Branch -> Git.Branch -> Git.Repo -> IO ()
updateBranch syncbranch updateto g = updateBranch syncbranch updateto g =
unlessM go $ giveup $ "failed to update " ++ Git.fromRef syncbranch unlessM go $
giveup $ "failed to update " ++ Git.fromRef syncbranch
where where
go = Git.Command.runBool go = Git.Command.runBool
[ Param "branch" [ Param "branch"

View file

@ -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, 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 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 # OPTIONS

View file

@ -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...
"""]]