summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2013-08-29 14:15:32 -0400
committerGravatar Joey Hess <joey@kitenet.net>2013-08-29 14:27:53 -0400
commit6a67b257f0083bb944cd132ac4a515fd4fb99a47 (patch)
treebfa9bf8c403521af9c5f939c88585c565c67b700
parent74c1d2ec3e6693adf1b2233f984059da02400feb (diff)
sync, assistant: Force push of the git-annex branch.
Necessary to ensure it gets pushed to remotes after being rewritten by forget. See inline rationalles for why I think this is safe!
-rw-r--r--Annex/TaggedPush.hs10
-rw-r--r--Command/Sync.hs42
-rw-r--r--Git/Branch.hs4
-rw-r--r--debian/changelog10
4 files changed, 48 insertions, 18 deletions
diff --git a/Annex/TaggedPush.hs b/Annex/TaggedPush.hs
index 2a5f823fd..039dc0e17 100644
--- a/Annex/TaggedPush.hs
+++ b/Annex/TaggedPush.hs
@@ -13,6 +13,7 @@ import qualified Annex.Branch
import qualified Git
import qualified Git.Ref
import qualified Git.Command
+import qualified Git.Branch
import Utility.Base64
{- Converts a git branch into a branch that is tagged with a UUID, typically
@@ -49,12 +50,11 @@ fromTaggedBranch b = case split "/" $ show b of
taggedPush :: UUID -> Maybe String -> Git.Ref -> Remote -> Git.Repo -> IO Bool
taggedPush u info branch remote = Git.Command.runBool
[ Param "push"
- -- This is safe because we "own" the tagged branch we're pushing;
- -- it has no other writers. Ensures it is pushed even if it has
- -- been rewritten by a transition.
- , Param "--force"
, Param $ Remote.name remote
- , Param $ refspec Annex.Branch.name
+ {- Using forcePush here is safe because we "own" the tagged branch
+ - we're pushing; it has no other writers. Ensures it is pushed
+ - even if it has been rewritten by a transition. -}
+ , Param $ Git.Branch.forcePush $ refspec Annex.Branch.name
, Param $ refspec branch
]
where
diff --git a/Command/Sync.hs b/Command/Sync.hs
index 551c2fa69..567e3146b 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -167,29 +167,45 @@ pushRemote remote branch = go =<< needpush
showOutput
inRepo $ pushBranch remote branch
-{- If the remote is a bare git repository, it's best to push the branch
- - directly to it. On the other hand, if it's not bare, pushing to the
- - checked out branch will fail, and this is why we use the syncBranch.
+{- Pushes a regular branch like master to a remote. Also pushes the git-annex
+ - branch.
+ -
+ - If the remote is a bare git repository, it's best to push the regular
+ - branch directly to it, so that cloning/pulling will get it.
+ - On the other hand, if it's not bare, pushing to the checked out branch
+ - will fail, and this is why we push to its syncBranch.
-
- Git offers no way to tell if a remote is bare or not, so both methods
- are tried.
-
- The direct push is likely to spew an ugly error message, so stderr is
- - elided. Since progress is output to stderr too, the sync push is done
- - first, and actually sends the data. Then the direct push is tried,
- - with stderr discarded, to update the branch ref on the remote.
+ - elided. Since git progress display goes to stderr too, the sync push
+ - is done first, and actually sends the data. Then the direct push is
+ - tried, with stderr discarded, to update the branch ref on the remote.
+ -
+ - The sync push forces the update of the remote synced/git-annex branch.
+ - This is necessary if a transition has rewritten the git-annex branch.
+ - Normally any changes to the git-annex branch get pulled and merged before
+ - this push, so this forcing is unlikely to overwrite new data pushed
+ - in from another repository that is also syncing.
+ -
+ - But overwriting of data on synced/git-annex can happen, in a race.
+ - The only difference caused by using a forced push in that case is that
+ - the last repository to push wins the race, rather than the first to push.
-}
pushBranch :: Remote -> Git.Ref -> Git.Repo -> IO Bool
-pushBranch remote branch g = tryIO directpush `after` syncpush
+pushBranch remote branch g = tryIO (directpush g) `after` syncpush g
where
- syncpush = Git.Command.runBool (pushparams (refspec branch)) g
- directpush = Git.Command.runQuiet (pushparams (show $ Git.Ref.base branch)) g
- pushparams b =
+ syncpush = Git.Command.runBool $ pushparams
+ [ Git.Branch.forcePush $ refspec Annex.Branch.name
+ , refspec branch
+ ]
+ directpush = Git.Command.runQuiet $ pushparams
+ [show $ Git.Ref.base branch]
+ pushparams branches =
[ Param "push"
, Param $ Remote.name remote
- , Param $ refspec Annex.Branch.name
- , Param b
- ]
+ ] ++ map Param branches
refspec b = concat
[ show $ Git.Ref.base b
, ":"
diff --git a/Git/Branch.hs b/Git/Branch.hs
index d4a684016..fed53d767 100644
--- a/Git/Branch.hs
+++ b/Git/Branch.hs
@@ -101,3 +101,7 @@ commit message branch parentrefs repo = do
return sha
where
ps = concatMap (\r -> ["-p", show r]) parentrefs
+
+{- A leading + makes git-push force pushing a branch. -}
+forcePush :: String -> String
+forcePush b = "+" ++ b
diff --git a/debian/changelog b/debian/changelog
index 68ba98b8b..cb6fbee5a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+git-annex (4.20130828) UNRELEASED; urgency=low
+
+ * forget: New command, causes git-annex branch history to be forgotten
+ in a way that will spread to other clones of the repository.
+ (As long as they're running this version or newer of git-annex.)
+ * sync, assistant: Force push of the git-annex branch. Necessary
+ to ensure it gets pushed to remotes after being rewritten by forget.
+
+ -- Joey Hess <joeyh@debian.org> Tue, 27 Aug 2013 11:03:00 -0400
+
git-annex (4.20130827) unstable; urgency=low
* Youtube support! (And 53 other video hosts). When quvi is installed,