slow, stupid, and safe index updating

Always merge the git-annex branch into .git/annex/index before making a
commit from the index.

This ensures that, when the branch has been changed in any way
(by a push being received, or changes pulled directly into it, or
even by the user checking it out, and committing a change), the index
reflects those changes.

This is much too slow; it needs to be optimised to only update the
index when the branch has really changed, not every time.

Also, there is an unhandled race, when a change is made to the branch
right after the index gets updated. I left it in for now because it's
unlikely and I didn't want to complicate things with additional locking
yet.
This commit is contained in:
Joey Hess 2011-12-11 14:51:20 -04:00
parent 59971c9230
commit 8680c415de
4 changed files with 34 additions and 25 deletions

View file

@ -45,14 +45,26 @@ originname = Git.Ref $ "origin/" ++ show name
{- Populates the branch's index file with the current branch contents. {- Populates the branch's index file with the current branch contents.
- -
- Usually, this is only done when the index doesn't yet exist, and - This is only done when the index doesn't yet exist, and the index
- the index is used to build up changes to be commited to the branch, - is used to build up changes to be commited to the branch, and merge
- and merge in changes from other branches. - in changes from other branches.
-} -}
genIndex :: Git.Repo -> IO () genIndex :: Git.Repo -> IO ()
genIndex g = Git.UnionMerge.stream_update_index g genIndex g = Git.UnionMerge.stream_update_index g
[Git.UnionMerge.ls_tree fullname g] [Git.UnionMerge.ls_tree fullname g]
{- Merges the specified branches into the index.
- Any changes staged in the index will be preserved. -}
mergeIndex :: [Git.Ref] -> Annex ()
mergeIndex branches = do
h <- catFileHandle
inRepo $ \g -> Git.UnionMerge.merge_index h g branches
{- Updates the branch's index to reflect the current contents of the branch.
- Any changes staged in the index will be preserved. -}
updateIndex :: Annex ()
updateIndex = withIndex $ mergeIndex [fullname]
{- Runs an action using the branch's index file. -} {- Runs an action using the branch's index file. -}
withIndex :: Annex a -> Annex a withIndex :: Annex a -> Annex a
withIndex = withIndex' False withIndex = withIndex' False
@ -66,6 +78,8 @@ withIndex' bootstrapping a = do
unless bootstrapping $ inRepo genIndex unless bootstrapping $ inRepo genIndex
a a
{- Runs an action using the branch's index file, first making sure that
- the branch and index are up-to-date. -}
withIndexUpdate :: Annex a -> Annex a withIndexUpdate :: Annex a -> Annex a
withIndexUpdate a = update >> withIndex a withIndexUpdate a = update >> withIndex a
@ -106,11 +120,12 @@ create = unlessM hasBranch $ do
{- Stages the journal, and commits staged changes to the branch. -} {- Stages the journal, and commits staged changes to the branch. -}
commit :: String -> Annex () commit :: String -> Annex ()
commit message = whenM journalDirty $ lockJournal $ do commit message = whenM journalDirty $ lockJournal $ do
updateIndex
stageJournalFiles stageJournalFiles
withIndex $ inRepo $ Git.commit message fullname [fullname] withIndex $ inRepo $ Git.commit message fullname [fullname]
{- Ensures that the branch is up-to-date; should be called before data is {- Ensures that the branch and index are is up-to-date; should be
- read from it. Runs only once per git-annex run. - called before data is read from it. Runs only once per git-annex run.
- -
- Before refs are merged into the index, it's important to first stage the - Before refs are merged into the index, it's important to first stage the
- journal into the index. Otherwise, any changes in the journal would - journal into the index. Otherwise, any changes in the journal would
@ -126,8 +141,9 @@ commit message = whenM journalDirty $ lockJournal $ do
-} -}
update :: Annex () update :: Annex ()
update = onceonly $ do update = onceonly $ do
-- ensure branch exists -- ensure branch exists, and index is up-to-date
create create
updateIndex
-- check what needs updating before taking the lock -- check what needs updating before taking the lock
dirty <- journalDirty dirty <- journalDirty
c <- filterM (changedBranch name . snd) =<< siblingBranches c <- filterM (changedBranch name . snd) =<< siblingBranches
@ -141,14 +157,7 @@ update = onceonly $ do
" into " ++ show name " into " ++ show name
unless (null branches) $ do unless (null branches) $ do
showSideAction merge_desc showSideAction merge_desc
{- Note: This merges the branches into the index. mergeIndex branches
- Any unstaged changes in the git-annex branch
- (if it's checked out) will be removed. So,
- documentation advises users not to directly
- modify the branch.
-}
h <- catFileHandle
inRepo $ \g -> Git.UnionMerge.merge_index h g branches
ff <- if dirty then return False else tryFastForwardTo refs ff <- if dirty then return False else tryFastForwardTo refs
unless ff $ inRepo $ unless ff $ inRepo $
Git.commit merge_desc fullname (nub $ fullname:refs) Git.commit merge_desc fullname (nub $ fullname:refs)

5
debian/changelog vendored
View file

@ -13,6 +13,11 @@ git-annex (3.20111204) UNRELEASED; urgency=low
remote, by running git commit, pull, and push for you. remote, by running git commit, pull, and push for you.
* Version monad-control dependency in cabal file. * Version monad-control dependency in cabal file.
* Fix bug in last version in getting contents from bare repositories. * Fix bug in last version in getting contents from bare repositories.
* Ensure that git-annex branch changes are merged into git-annex's index,
which fixes a bug that could cause changes that were pushed to the
git-annex branch to get reverted. As a side effect, it's now safe
for users to check out and commit changes directly to the git-annex
branch.
-- Joey Hess <joeyh@debian.org> Sun, 04 Dec 2011 12:22:37 -0400 -- Joey Hess <joeyh@debian.org> Sun, 04 Dec 2011 12:22:37 -0400

View file

@ -39,6 +39,9 @@ corresponds to its index, and if the branch is at a different ref,
merge it into the index. I am still considering how to do that atomically; merge it into the index. I am still considering how to do that atomically;
what if a push comes in while git-annex is updating its index? what if a push comes in while git-annex is updating its index?
> Now git-annex always updates the index with the git-annex branch, which
> is a slow, but safe way to avoid this problem. [[done]] --[[Joey]]
--- ---
## Workaround ## Workaround

View file

@ -22,17 +22,9 @@ deleting or changing the file contents.
This branch is managed by git-annex, with the contents listed below. This branch is managed by git-annex, with the contents listed below.
The file `.git/annex/index` is a separate git index file it uses The file `.git/annex/index` is a separate git index file it uses
to accumulate changes for the git-annex. Also, `.git/annex/journal/` is used to accumulate changes for the git-annex branch.
to record changes before they are added to git. Also, `.git/annex/journal/` is used to record changes before they
are added to git.
Note that for speed reasons, git-annex assumes only it will modify this
branch. If you go in and make changes directly, it will probably revert
your changes in its next commit to the branch.
The best way to make changes to the git-annex branch is instead
to create a branch of it, with a name like "my/git-annex", and then
use "git annex merge" to automerge your branch into the main git-annex
branch.
### `uuid.log` ### `uuid.log`