Recent comments posted to this site:

comment 8

It's fine to force-push your git-annex branch to the server in this situation.

Comment by joey —
comment 5

Your log shows that you did not have refs/remotes/hub-con/git-annex at the point where git-annex sync would have merged it:

may be because it was not yet created by forgejo+aneksjo or I have not fetched yet... oh, well

If your local git-annex branch contains a git-annex forget transition, git-annex necessarily cannot merge unrelated remote git-annex branches into it, because they may contain exactly the historical information that was requested to be forgotten. Instead, the new information is extracted from the remote git-annex branch and put into the local git-annex branch.

oh, what how that magical addition has happened! I still have transition information

❯ git ls-tree git-annex | grep transitions
100644 blob 891a754697d1602294fe8619878aeb9bb22b1586    transitions.log
❯ git show git-annex:transitions.log
ForgetGitHistory 1789701492s
ForgetDeadRemotes 1789701492s

but when should it get gone -- any step I could do to fascilitate besides just going and killing that file? Or it to remain there forever to be sure not pick up from "old history"? (here new forgejo though was newer AFAIK)

Comment by yarikoptic —
comment 6

Maybe I was mistaken about whether you have refs/remotes/hub-con/git-annex. I don't think it matters; as far as I can see there's nothing here that would be unexpected when there's a git-annex forget transition involved.

But what I wonder now is if the server ever replaced its git-annex branch with the synced/git-annex branch that got pushed to it. (Update: Based on comment #5 it has not.)

That needs git-annex to run on the server, and it may be that nothing causes forgejo+aneksajo to run git-annex in this situation, and so it leaves its git-annex branch at the initial git-annex init value.

The same could happen with a git remote that doesn't have git-annex installed.

And that would leave synced/git-annex as the only place where new git-annex branch information is being communicate. The problem with that being that multiple clients can force push that, which can result in information sent by one getting overwritten by another. While the clients would eventually converge on a single merged git-annex branch via only synced/git-annex, it might take some time.

I think that git-annex sync could deal with this better, by checking if the remote git-annex branch's sha is in gitAnnexIgnoredRefs. And if so, forcing a push to the remote git-annex branch, using --force-with-lease to avoid overwriting any changes that might get made to it at the same time.

Comment by joey —
comment 4
continuing transition ["forget git history","forget dead remotes"]

If your local git-annex branch contains a git-annex forget transition, git-annex necessarily cannot merge unrelated remote git-annex branches into it, because they may contain exactly the historical information that was requested to be forgotten. Instead, the new information is extracted from the remote git-annex branch and put into the local git-annex branch.

Once the local git-annex branch is pushed to the remote as synced/git-annex, and git-annex is run on the server, it will replace the unrelated git-annex branch.

Comment by joey —
comment 3

Your log shows that you did not have refs/remotes/hub-con/git-annex at the point where git-annex sync would have merged it:

[2026-10-07 13:09:57.61588097] (Utility.Process) process [2221134] call: git ["--git-dir=.git","--work-tree=.","--literal-pathspecs","-c","annex.debug=true","show-ref","--verify","-q","refs/remotes/hub-con/git-annex"]
[2026-10-07 13:09:57.615954038] (Utility.Process) process [2221131] done ExitFailure 1
Comment by joey —
comment 2

you do not have a remotes/hub-con/git-annex You do have a local branch named hub-con/git-annex

hm, did I cut paste something incorrectly somewhere? I do not think it is the case:

❯ git br -a
  git-annex
* master
  remotes/con@falkor/HEAD -> con@falkor/master
  remotes/con@falkor/git-annex
  remotes/con@falkor/master
  remotes/con@falkor/synced/git-annex
  remotes/con@falkor/synced/master
  remotes/falkor/HEAD -> falkor/master
  remotes/falkor/git-annex
  remotes/falkor/master
  remotes/falkor/synced/git-annex
  remotes/falkor/synced/master
  remotes/hub-con/HEAD -> hub-con/master
  remotes/hub-con/git-annex
  remotes/hub-con/master
  remotes/hub-con/synced/git-annex
  remotes/hub-con/synced/master
  remotes/typhon/HEAD -> typhon/master
  remotes/typhon/git-annex
  remotes/typhon/master
  remotes/typhon/synced/git-annex
  remotes/typhon/synced/master

❯ ls -l .git/refs/heads .git/refs/remotes/hub-con
.git/refs/heads:
total 8
-rw-rw-r-- 1 yoh yoh 41 Oct  7 12:49 git-annex
-rw-rw-r-- 1 yoh yoh 41 Oct  7 12:49 master

.git/refs/remotes/hub-con:
total 12
-rw-rw-r-- 1 yoh yoh 33 Oct  7 12:49 HEAD
-rw-rw-r-- 1 yoh yoh 41 Oct  7 12:48 git-annex
-rw-rw-r-- 1 yoh yoh 41 Oct  7 12:50 master
drwxrwsr-x 1 yoh yoh 30 Oct  7 15:11 synced/

since it has already sent the same information to the remote in a successful force-push of the synced/git-annex branch. So that is all a red herring.

indeed! it seems that somehow, in that most recent merge it did add that UUID, and that was done in a commit TODAY catching up on a "transition" (done as AFAIK finished days ago! and IIRC on a different host but I could be mistaken and may be it was done on this) when this repo was produced by splitting off the tree of a larger "original repo".

❯ git show hub-con/git-annex:uuid.log | grep e9147e49-a1d5-49b1-bd50-74010d401463
e9147e49-a1d5-49b1-bd50-74010d401463 git@b16fdd44ad3a:/var/lib/gitea/git/repositories/con/liab-falkor-hub.git timestamp=1791391708s
❯ git show git-annex^1:uuid.log | grep e9147e49-a1d5-49b1-bd50-74010d401463
e9147e49-a1d5-49b1-bd50-74010d401463 git@b16fdd44ad3a:/var/lib/gitea/git/repositories/con/liab-falkor-hub.git timestamp=1791391708s
❯ git show git-annex^1
commit 09524451b82e929afe3eaacedc906033311382c0
Author: Yaroslav Halchenko <debian@onerussian.com>
Date:   Wed Oct 7 12:48:56 2026 -0400

    continuing transition ["forget git history","forget dead remotes"]

diff --git a/uuid.log b/uuid.log
index f8582b9..5c4adc9 100644
--- a/uuid.log
+++ b/uuid.log
@@ -5,4 +5,5 @@
 60ab5caa-8d02-4a25-ae23-80e6cfcf8955 split-falkor-hub timestamp=1789701480s
 885697c4-a371-484f-8332-ebdce2f5cce6 yoh@falkor:~/hardware/washoe/2026-revamp timestamp=1773954781s
 adc21e14-c327-4051-bc7c-a95b706ea64d yoh@bilena:~/hardware/washoe/2026-revamp timestamp=1773928564s
+e9147e49-a1d5-49b1-bd50-74010d401463 git@b16fdd44ad3a:/var/lib/gitea/git/repositories/con/liab-falkor-hub.git timestamp=1791391708s
 f0af65a3-fef7-4127-9fb6-910e266ebc09 yoh@typhon:~/hardware/washoe/2026-revamp/deployments/falkor-hub timestamp=1788183516s

so indeed info is there! but how that continuing transition came up again?

since info is there -- may be I could just force push git-annex branch (if would be allowed) or manually merge directly and push, correct?

Comment by yarikoptic —
comment 1

What's weird about your situation and I don't understand is you do not have a remotes/hub-con/git-annex, which would be the usual name of the remote tracking branch that git-annex would normally automatically merge.

You do have a local branch named hub-con/git-annex. I don't understand where that came from. Maybe that ought to be merged and isn't being merged, but you're clearly doing something unusual to have that rather than the regular remote tracking branch.

Anyway, to dispell some of the other confusion in this bug report:

git-annex push does not treat a failure to push the git-annex branch as an error since it has already sent the same information to the remote in a successful force-push of the synced/git-annex branch. So that is all a red herring.

And when you ran "git annex merge hub-con", that is the wrong command to merge the git-annex branch from the remote. That command merges a branch named "hub-con" into the current branch.

Comment by joey —
comment 6

I think the solution will involve depedency injection, so ifWanted can access wantGet from a structure passed into that module from the caller. Maybe by converting it to a wrapper monad around Annex.

Comment by joey —
comment 5

The patch below implements that. Unfortunately, it fails to build due to several import cycles. I spent a while trying to resolve those and could not, so I think it would need HS boot files to get this to build.

diff --git a/Annex/AdjustedBranch.hs b/Annex/AdjustedBranch.hs
index a9ff9849c0..ec885e13c1 100644
--- a/Annex/AdjustedBranch.hs
+++ b/Annex/AdjustedBranch.hs
@@ -1,6 +1,6 @@
 {- adjusted branch
  -
- - Copyright 2016-2024 Joey Hess <id@joeyh.name>
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -60,6 +60,7 @@ import Annex.CatFile
 import Annex.Link
 import Annex.Content.Presence
 import Annex.CurrentBranch
+import Annex.Wanted
 import Types.CleanupActions
 import qualified Database.Keys
 import Config
@@ -87,10 +88,16 @@ instance AdjustTreeItem Adjustment where
            Nothing -> return Nothing
            Just t' -> adjustTreeItem l t'
    adjustTreeItem (LockUnlockPresentAdjustment l) t = adjustTreeItem l t
+   adjustTreeItem (WantedAdjustment p Nothing) t = adjustTreeItem p t
+   adjustTreeItem (WantedAdjustment p (Just l)) t =
+       adjustTreeItem p t >>= \case
+           Nothing -> return Nothing
+           Just t' -> adjustTreeItem l t'

    adjustmentIsStable (LinkAdjustment l) = adjustmentIsStable l
    adjustmentIsStable (PresenceAdjustment p _) = adjustmentIsStable p
    adjustmentIsStable (LockUnlockPresentAdjustment l) = adjustmentIsStable l
+   adjustmentIsStable (WantedAdjustment p _) = adjustmentIsStable p

 instance AdjustTreeItem LinkAdjustment where
    adjustTreeItem UnlockAdjustment =
@@ -127,6 +134,15 @@ instance AdjustTreeItem LockUnlockPresentAdjustment where
    adjustmentIsStable UnlockPresentAdjustment = False
    adjustmentIsStable LockPresentAdjustment = True

+instance AdjustTreeItem WantedAdjustment where
+   adjustTreeItem HideUnwantedAdjustment = 
+       ifWanted noAdjust hideAdjust
+   adjustTreeItem ShowUnwantedAdjustment =
+       noAdjust
+
+   adjustmentIsStable HideUnwantedAdjustment = False
+   adjustmentIsStable ShowUnwantedAdjustment = True
+
 ifSymlink
    :: (TreeItem -> Annex a)
    -> (TreeItem -> Annex a)
@@ -143,7 +159,21 @@ ifPresent
    -> Annex (Maybe TreeItem)
 ifPresent ispresent notpresent ti@(TreeItem _ _ s) =
    catKey s >>= \case
-       Just k -> ifM (inAnnex k) (ispresent ti, notpresent ti)
+       Just k -> ifM (inAnnex k) 
+           (ispresent ti, notpresent ti)
+       Nothing -> return (Just ti)
+
+ifWanted
+   :: (TreeItem -> Annex (Maybe TreeItem))
+   -> (TreeItem -> Annex (Maybe TreeItem))
+   -> TreeItem
+   -> Annex (Maybe TreeItem)
+ifWanted iswanted notwanted ti@(TreeItem topf _ s) =
+   catKey s >>= \case
+       Just k -> do
+           f <- inRepo $ fromTopFilePath topf
+           ifM (wantGet NoLiveUpdate True (Just k) f)
+               (iswanted ti, notwanted ti)
        Nothing -> return (Just ti)

 noAdjust :: TreeItem -> Annex (Maybe TreeItem)
diff --git a/Annex/AdjustedBranch/Name.hs b/Annex/AdjustedBranch/Name.hs
index 5a85b6ef9a..41ed48936a 100644
--- a/Annex/AdjustedBranch/Name.hs
+++ b/Annex/AdjustedBranch/Name.hs
@@ -1,6 +1,6 @@
 {- adjusted branch names
  -
- - Copyright 2016-2020 Joey Hess <id@joeyh.name>
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -39,6 +39,10 @@ instance SerializeAdjustment Adjustment where
        serializeAdjustment p <> "-" <> serializeAdjustment l
    serializeAdjustment (LockUnlockPresentAdjustment l) =
        serializeAdjustment l
+   serializeAdjustment (WantedAdjustment p Nothing) =
+       serializeAdjustment p
+   serializeAdjustment (WantedAdjustment p (Just l)) = 
+       serializeAdjustment p <> "-" <> serializeAdjustment l
    deserializeAdjustment s = 
        (LinkAdjustment <$> deserializeAdjustment s)
            <|>
@@ -47,6 +51,10 @@ instance SerializeAdjustment Adjustment where
        (PresenceAdjustment <$> deserializeAdjustment s <*> pure Nothing)
            <|>
        (LockUnlockPresentAdjustment <$> deserializeAdjustment s)
+           <|>
+       (WantedAdjustment <$> deserializeAdjustment s1 <*> pure (deserializeAdjustment s2))
+           <|>
+       (WantedAdjustment <$> deserializeAdjustment s <*> pure Nothing)
      where
        (s1, s2) = separate' (== (fromIntegral (ord '-'))) s

@@ -75,6 +83,13 @@ instance SerializeAdjustment LockUnlockPresentAdjustment where
    deserializeAdjustment "lockpresent" = Just LockPresentAdjustment
    deserializeAdjustment _ = Nothing

+instance SerializeAdjustment WantedAdjustment where
+   serializeAdjustment HideUnwantedAdjustment = "hideunwanted"
+   serializeAdjustment ShowUnwantedAdjustment = "showunwanted"
+   deserializeAdjustment "hideunwanted" = Just HideUnwantedAdjustment
+   deserializeAdjustment "showunwanted" = Just ShowUnwantedAdjustment
+   deserializeAdjustment _ = Nothing
+
 newtype AdjBranch = AdjBranch { adjBranch :: Branch }

 originalToAdjusted :: OrigBranch -> Adjustment -> AdjBranch
diff --git a/CHANGELOG b/CHANGELOG
index ea4832f783..207c68d8fd 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,10 @@
+git-annex (10.20261007) UNRELEASED; urgency=medium
+
+  * adjust --wanted: New option to make an adjusted branch containing only
+    wanted files.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 06 Oct 2026 11:03:57 -0400
+
 git-annex (10.20261006) upstream; urgency=medium

   * Fix stack build.
diff --git a/Types/AdjustedBranch.hs b/Types/AdjustedBranch.hs
index 3c73d5e06c..422fe7da5c 100644
--- a/Types/AdjustedBranch.hs
+++ b/Types/AdjustedBranch.hs
@@ -1,6 +1,6 @@
 {- adjusted branch types
  -
- - Copyright 2016-2020 Joey Hess <id@joeyh.name>
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -11,6 +11,7 @@ data Adjustment
    = LinkAdjustment LinkAdjustment
    | PresenceAdjustment PresenceAdjustment (Maybe LinkAdjustment)
    | LockUnlockPresentAdjustment LockUnlockPresentAdjustment
+   | WantedAdjustment WantedAdjustment (Maybe LinkAdjustment)
    deriving (Show, Eq)

 data LinkAdjustment
@@ -30,6 +31,11 @@ data LockUnlockPresentAdjustment
    | LockPresentAdjustment
    deriving (Show, Eq)

+data WantedAdjustment
+   = HideUnwantedAdjustment
+   | ShowUnwantedAdjustment
+   deriving (Show, Eq)
+
 -- Adjustments have to be able to be reversed, so that commits made to the
 -- adjusted branch can be reversed to the commit that would have been made
 -- without the adjustment and applied to the original branch.
@@ -43,6 +49,8 @@ instance ReversableAdjustment Adjustment where
        PresenceAdjustment (reverseAdjustment p) (fmap reverseAdjustment ml)
    reverseAdjustment (LockUnlockPresentAdjustment l) =
        LockUnlockPresentAdjustment (reverseAdjustment l)
+   reverseAdjustment (WantedAdjustment l ml) = 
+       WantedAdjustment (reverseAdjustment l) (fmap reverseAdjustment ml)

 instance ReversableAdjustment LinkAdjustment where
    reverseAdjustment UnlockAdjustment = LockAdjustment
@@ -59,6 +67,11 @@ instance ReversableAdjustment LockUnlockPresentAdjustment where
    reverseAdjustment UnlockPresentAdjustment = LockPresentAdjustment
    reverseAdjustment LockPresentAdjustment = UnlockPresentAdjustment

+instance ReversableAdjustment WantedAdjustment where
+   reverseAdjustment HideUnwantedAdjustment = ShowUnwantedAdjustment
+   reverseAdjustment ShowUnwantedAdjustment = HideUnwantedAdjustment
+
 adjustmentHidesFiles :: Adjustment -> Bool
 adjustmentHidesFiles (PresenceAdjustment HideMissingAdjustment _) = True
+adjustmentHidesFiles (WantedAdjustment HideUnwantedAdjustment _) = True
 adjustmentHidesFiles _ = False
diff --git a/doc/git-annex-adjust.mdwn b/doc/git-annex-adjust.mdwn
index eccdf843cf..693a4285a2 100644
--- a/doc/git-annex-adjust.mdwn
+++ b/doc/git-annex-adjust.mdwn
@@ -4,7 +4,7 @@ git-annex adjust - enter an adjusted branch

 # SYNOPSIS

-git annex adjust `--unlock|--lock|--fix|--hide-missing [--unlock|--lock|--fix]|--unlock-present`
+git annex adjust `--unlock|--lock|--fix|--hide-missing|--unlock-present|--wanted`

 # DESCRIPTION

@@ -37,7 +37,7 @@ To avoid those problems, use `git annex merge otherbranch`.

 Re-running this command with the same options
 while inside the adjusted branch will update the adjusted branch
-as necessary (eg for `--hide-missing` and `--unlock-present`), 
+as necessary (eg for `--hide-missing`, `--unlock-present`, and `--wanted`), 
 and will also propagate commits back to the original branch.

 # OPTIONS
@@ -119,6 +119,21 @@ and will also propagate commits back to the original branch.
   set the `annex.adjustedbranchrefresh` config. Or use `git-annex sync
   --content`, which updates the branch after transferring content.

+* `--wanted`
+
+  Only include annexed files in the adjusted branch when they are preferred
+  content of the repository, as configured by `git-annex wanted`.
+
+  Note that when the preferred content expression uses `present`, files are
+  only wanted when their content is present. The adjusted branch is not
+  immediately changed when content availability changes. To update the
+  adjusted branch to reflect changes to content availability, run
+  `git-annex adjust --wanted` again. Or, to automate updates,
+  set the `annex.adjustedbranchrefresh` config.
+  
+  The `--wanted` option can be combined with 
+  `--unlock`, `--lock`, or `--fix`.
+
 * `--force`

   Allow overwriting an existing adjusted branch with a new version.
@@ -145,6 +160,8 @@ and will also propagate commits back to the original branch.

 git-annex-view(1)

+git-annex-wanted(1)
+
 # AUTHOR

 Joey Hess <id@joeyh.name>
diff --git a/doc/todo/Filter_a_tree_with_pattern.mdwn b/doc/todo/Filter_a_tree_with_pattern.mdwn
index c32996446a..de1c478d4c 100644
--- a/doc/todo/Filter_a_tree_with_pattern.mdwn
+++ b/doc/todo/Filter_a_tree_with_pattern.mdwn
@@ -53,3 +53,5 @@ $ git annex filterview root=Movies/
 $ ls
 movie.mkv movie.iso movie.mp4 movie.en_US.ass movie.de_DE.ass
 ```
+
+> `git-annex adjust --wanted` done --Joey
Comment by joey —
comment 4

git-annex export filters the exported tree to the preferred content of the remote.

That is not quite what's being asked for here, which is a new feature to generate a filtered tree. But clearly the code to create such a tree is all present in git-annex already.

In fact, an export to a special remote does write such a tree to a git ref. So a dummy special remote that didn't write any files would be one way to implement this. (Not a good way.)

I think the question is, what command would it make sense to put this feature in? And this seems like a good candiate: git-annex adjust --wanted That would adjust the tree to only contain files that are preferred content of the local repository.

That seems broadly useful. Although similarly to --hide-missing, with some preferred content expressions (ones using present), the adjusted branch sometimes needs to be updated when content availability changes, eg after a git-annex drop.

Comment by joey —