2017-02-17 18:04:43 +00:00
|
|
|
{- git-annex command
|
|
|
|
-
|
2024-08-06 18:18:30 +00:00
|
|
|
- Copyright 2017-2024 Joey Hess <id@joeyh.name>
|
2017-02-17 18:04:43 +00:00
|
|
|
-
|
2019-03-13 19:48:14 +00:00
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
2017-02-17 18:04:43 +00:00
|
|
|
-}
|
|
|
|
|
2019-12-09 17:49:05 +00:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
2017-02-17 18:04:43 +00:00
|
|
|
module Command.PostReceive where
|
|
|
|
|
|
|
|
import Command
|
|
|
|
import qualified Annex
|
2017-02-17 19:21:39 +00:00
|
|
|
import Annex.UpdateInstead
|
2018-10-19 19:17:48 +00:00
|
|
|
import Annex.CurrentBranch
|
sync --only-annex and annex.synconlyannex
* Added sync --only-annex, which syncs the git-annex branch and annexed
content but leaves managing the other git branches up to you.
* Added annex.synconlyannex git config setting, which can also be set with
git-annex config to configure sync in all clones of the repo.
Use case is then the user has their own git workflow, and wants to use
git-annex without disrupting that, so they sync --only-annex to get the
git-annex stuff in sync in addition to their usual git workflow.
When annex.synconlyannex is set, --not-only-annex can be used to override
it.
It's not entirely clear what --only-annex --commit or --only-annex
--push should do, and I left that combination not documented because I
don't know if I might want to change the current behavior, which is that
such options do not override the --only-annex. My gut feeling is that
there is no good reasons to use such combinations; if you want to use
your own git workflow, you'll be doing your own committing and pulling
and pushing.
A subtle question is, how should import/export special remotes be handled?
Importing updates their remote tracking branch and merges it into master.
If --only-annex prevented that git branch stuff, then it would prevent
exporting to the special remote, in the case where it has changes that
were not imported yet, because there would be a unresolved conflict.
I decided that it's best to treat the fact that there's a remote tracking
branch for import/export as an implementation detail in this case. The more
important thing is that an import/export special remote is entirely annexed
content, and so it makes a lot of sense that --only-annex will still sync
with it.
2020-02-17 19:19:58 +00:00
|
|
|
import Command.Sync (mergeLocal, prepMerge, mergeConfig, SyncOptions(..))
|
2024-08-06 18:18:30 +00:00
|
|
|
import Annex.Proxy
|
|
|
|
import Remote
|
|
|
|
import qualified Types.Remote as Remote
|
|
|
|
import Config
|
|
|
|
import Git.Types
|
|
|
|
import Git.Sha
|
post-receive: use the exporttree=yes remote as a source
This handles cases where a single key is used by multiple files in the
exported tree. When using `git-annex push`, the key's content gets
stored in the annexobjects location, and then when the branch is pushed,
it gets renamed from the annexobjects location to the first exported
file. For subsequent exported files, a copy of the content needs to be
made. This causes it to download the key from the remote in order to
upload another copy to it.
This is not needed when using `git push` followed by `git-annex copy --to`
the proxied remote, because the received key is stored at all export
locations then.
Also, fixed handling of the synced branch push, it was exporting master
when synced/master was pushed.
Note that currently, the first push to the remote does not see that it
is able to get a key from it in order to upload it back. It displays
"(not available)". The second push is able to. Since git-annex push
pushes first the synced branch and then the branch, this does end up
with a full export being made, but it is not quite right.
2024-08-08 16:28:12 +00:00
|
|
|
import Git.FilePath
|
2024-08-06 18:18:30 +00:00
|
|
|
import qualified Git.Ref
|
|
|
|
import Command.Export (filterExport, getExportCommit, seekExport)
|
2024-08-07 17:11:06 +00:00
|
|
|
import Command.Sync (syncBranch)
|
2024-08-06 18:18:30 +00:00
|
|
|
|
|
|
|
import qualified Data.Set as S
|
|
|
|
import qualified Data.ByteString as B
|
|
|
|
import qualified Data.ByteString.Char8 as B8
|
2017-02-17 18:04:43 +00:00
|
|
|
|
2017-02-23 22:37:02 +00:00
|
|
|
-- This does not need to modify the git-annex branch to update the
|
|
|
|
-- work tree, but auto-initialization might change the git-annex branch.
|
|
|
|
-- Since it would be surprising for a post-receive hook to make such a
|
|
|
|
-- change, that's prevented by noCommit.
|
2017-02-17 18:04:43 +00:00
|
|
|
cmd :: Command
|
2017-02-23 22:37:02 +00:00
|
|
|
cmd = noCommit $
|
|
|
|
command "post-receive" SectionPlumbing
|
|
|
|
"run by git post-receive hook"
|
|
|
|
paramNothing
|
|
|
|
(withParams seek)
|
2017-02-17 18:04:43 +00:00
|
|
|
|
|
|
|
seek :: CmdParams -> CommandSeek
|
2024-08-06 18:18:30 +00:00
|
|
|
seek _ = do
|
2017-02-17 18:04:43 +00:00
|
|
|
fixPostReceiveHookEnv
|
2024-08-06 18:18:30 +00:00
|
|
|
whenM needUpdateInsteadEmulation $
|
|
|
|
commandAction updateInsteadEmulation
|
|
|
|
proxyExportTree
|
|
|
|
|
|
|
|
updateInsteadEmulation :: CommandStart
|
|
|
|
updateInsteadEmulation = do
|
|
|
|
prepMerge
|
|
|
|
let o = def { notOnlyAnnexOption = True }
|
|
|
|
mc <- mergeConfig False
|
|
|
|
mergeLocal mc o =<< getCurrentBranch
|
|
|
|
|
|
|
|
proxyExportTree :: CommandSeek
|
|
|
|
proxyExportTree = do
|
|
|
|
rbs <- catMaybes <$> (mapM canexport =<< proxyForRemotes)
|
|
|
|
unless (null rbs) $ do
|
|
|
|
pushedbranches <- liftIO $
|
|
|
|
S.fromList . map snd . parseHookInput
|
|
|
|
<$> B.hGetContents stdin
|
post-receive: use the exporttree=yes remote as a source
This handles cases where a single key is used by multiple files in the
exported tree. When using `git-annex push`, the key's content gets
stored in the annexobjects location, and then when the branch is pushed,
it gets renamed from the annexobjects location to the first exported
file. For subsequent exported files, a copy of the content needs to be
made. This causes it to download the key from the remote in order to
upload another copy to it.
This is not needed when using `git push` followed by `git-annex copy --to`
the proxied remote, because the received key is stored at all export
locations then.
Also, fixed handling of the synced branch push, it was exporting master
when synced/master was pushed.
Note that currently, the first push to the remote does not see that it
is able to get a key from it in order to upload it back. It displays
"(not available)". The second push is able to. Since git-annex push
pushes first the synced branch and then the branch, this does end up
with a full export being made, but it is not quite right.
2024-08-08 16:28:12 +00:00
|
|
|
let waspushed (r, (b, d))
|
|
|
|
| S.member (Git.Ref.branchRef b) pushedbranches =
|
|
|
|
Just (r, b, d)
|
|
|
|
| S.member (Git.Ref.branchRef (syncBranch b)) pushedbranches =
|
|
|
|
Just (r, syncBranch b, d)
|
|
|
|
| otherwise = Nothing
|
|
|
|
case headMaybe (mapMaybe waspushed rbs) of
|
|
|
|
Just (r, b, Nothing) -> go r b
|
|
|
|
Just (r, b, Just d) -> go r $
|
|
|
|
Git.Ref.branchFileRef b (getTopFilePath d)
|
|
|
|
Nothing -> noop
|
2024-08-06 18:18:30 +00:00
|
|
|
where
|
|
|
|
canexport r = case remoteAnnexTrackingBranch (Remote.gitconfig r) of
|
|
|
|
Nothing -> return Nothing
|
|
|
|
Just branch ->
|
|
|
|
ifM (isExportSupported r)
|
post-receive: use the exporttree=yes remote as a source
This handles cases where a single key is used by multiple files in the
exported tree. When using `git-annex push`, the key's content gets
stored in the annexobjects location, and then when the branch is pushed,
it gets renamed from the annexobjects location to the first exported
file. For subsequent exported files, a copy of the content needs to be
made. This causes it to download the key from the remote in order to
upload another copy to it.
This is not needed when using `git push` followed by `git-annex copy --to`
the proxied remote, because the received key is stored at all export
locations then.
Also, fixed handling of the synced branch push, it was exporting master
when synced/master was pushed.
Note that currently, the first push to the remote does not see that it
is able to get a key from it in order to upload it back. It displays
"(not available)". The second push is able to. Since git-annex push
pushes first the synced branch and then the branch, this does end up
with a full export being made, but it is not quite right.
2024-08-08 16:28:12 +00:00
|
|
|
( return (Just (r, splitRemoteAnnexTrackingBranchSubdir branch))
|
2024-08-06 18:18:30 +00:00
|
|
|
, return Nothing
|
|
|
|
)
|
|
|
|
|
|
|
|
go r b = inRepo (Git.Ref.tree b) >>= \case
|
|
|
|
Nothing -> return ()
|
|
|
|
Just t -> do
|
|
|
|
tree <- filterExport r t
|
|
|
|
mtbcommitsha <- getExportCommit r b
|
post-receive: use the exporttree=yes remote as a source
This handles cases where a single key is used by multiple files in the
exported tree. When using `git-annex push`, the key's content gets
stored in the annexobjects location, and then when the branch is pushed,
it gets renamed from the annexobjects location to the first exported
file. For subsequent exported files, a copy of the content needs to be
made. This causes it to download the key from the remote in order to
upload another copy to it.
This is not needed when using `git push` followed by `git-annex copy --to`
the proxied remote, because the received key is stored at all export
locations then.
Also, fixed handling of the synced branch push, it was exporting master
when synced/master was pushed.
Note that currently, the first push to the remote does not see that it
is able to get a key from it in order to upload it back. It displays
"(not available)". The second push is able to. Since git-annex push
pushes first the synced branch and then the branch, this does end up
with a full export being made, but it is not quite right.
2024-08-08 16:28:12 +00:00
|
|
|
seekExport r tree mtbcommitsha [r]
|
2024-08-06 18:18:30 +00:00
|
|
|
|
|
|
|
parseHookInput :: B.ByteString -> [((Sha, Sha), Ref)]
|
|
|
|
parseHookInput = mapMaybe parse . B8.lines
|
|
|
|
where
|
|
|
|
parse l = case B8.words l of
|
|
|
|
(oldb:newb:refb:[]) -> do
|
|
|
|
old <- extractSha oldb
|
|
|
|
new <- extractSha newb
|
|
|
|
return ((old, new), Ref refb)
|
|
|
|
_ -> Nothing
|
2017-02-17 18:04:43 +00:00
|
|
|
|
|
|
|
{- When run by the post-receive hook, the cwd is the .git directory,
|
|
|
|
- and GIT_DIR=. It's not clear why git does this.
|
|
|
|
-
|
|
|
|
- Fix up from that unusual situation, so that git commands
|
|
|
|
- won't try to treat .git as the work tree. -}
|
|
|
|
fixPostReceiveHookEnv :: Annex ()
|
|
|
|
fixPostReceiveHookEnv = do
|
|
|
|
g <- Annex.gitRepo
|
|
|
|
case location g of
|
|
|
|
Local { gitdir = ".", worktree = Just "." } ->
|
|
|
|
Annex.adjustGitRepo $ \g' -> pure $ g'
|
2023-09-21 17:40:22 +00:00
|
|
|
{ location = case location g' of
|
|
|
|
loc@(Local {}) -> loc
|
|
|
|
{ worktree = Just ".." }
|
|
|
|
loc -> loc
|
2017-02-17 18:04:43 +00:00
|
|
|
}
|
|
|
|
_ -> noop
|
|
|
|
|