diff --git a/Annex/AdjustTreeItem.hs b/Annex/AdjustTreeItem.hs
new file mode 100644
--- /dev/null
+++ b/Annex/AdjustTreeItem.hs
@@ -0,0 +1,174 @@
+{- TreeItem adjustment implementation
+ -
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+{-# LANGUAGE BangPatterns, OverloadedStrings #-}
+
+module Annex.AdjustTreeItem (
+	AdjustTreeItem,
+	getAdjustTreeItem
+) where
+
+import Annex.Common
+import Types.AdjustedBranch
+import Types.AdjustTreeItem
+import Git
+import Git.Types
+import Git.Tree (TreeItem(..))
+import Git.FilePath
+import Annex.CatFile
+import Annex.Link
+import Annex.Content.Presence
+import {-# SOURCE #-} Annex.Wanted
+import qualified Database.Keys
+import Utility.FileMode
+import qualified Utility.RawFilePath as R
+
+import System.PosixCompat.Files (fileMode)
+
+getAdjustTreeItem :: AdjustTreeItem
+getAdjustTreeItem = AdjustTreeItem
+	{ adjustTreeItem = adjustTreeItemC
+	, adjustmentIsStable = adjustmentIsStableC
+	}
+
+class AdjustTreeItemClass t where
+	-- How to perform various adjustments to a TreeItem.
+	adjustTreeItemC :: t -> TreeItem -> Annex (Maybe TreeItem)
+	-- Will adjusting a given tree always yield the same adjusted tree?
+	adjustmentIsStableC :: t -> Bool
+
+instance AdjustTreeItemClass Adjustment where
+	adjustTreeItemC (LinkAdjustment l) t = adjustTreeItemC l t
+	adjustTreeItemC (PresenceAdjustment p Nothing) t = adjustTreeItemC p t
+	adjustTreeItemC (PresenceAdjustment p (Just l)) t =
+		adjustTreeItemC p t >>= \case
+			Nothing -> return Nothing
+			Just t' -> adjustTreeItemC l t'
+	adjustTreeItemC (LockUnlockPresentAdjustment l) t = adjustTreeItemC l t
+	adjustTreeItemC (WantedAdjustment p Nothing) t = adjustTreeItemC p t
+	adjustTreeItemC (WantedAdjustment p (Just l)) t =
+		adjustTreeItemC p t >>= \case
+			Nothing -> return Nothing
+			Just t' -> adjustTreeItemC l t'
+
+	adjustmentIsStableC (LinkAdjustment l) = adjustmentIsStableC l
+	adjustmentIsStableC (PresenceAdjustment p _) = adjustmentIsStableC p
+	adjustmentIsStableC (LockUnlockPresentAdjustment l) = adjustmentIsStableC l
+	adjustmentIsStableC (WantedAdjustment p _) = adjustmentIsStableC p
+
+instance AdjustTreeItemClass LinkAdjustment where
+	adjustTreeItemC UnlockAdjustment =
+		ifSymlink adjustToPointer noAdjust
+	adjustTreeItemC LockAdjustment =
+		ifSymlink noAdjust adjustToSymlink
+	adjustTreeItemC FixAdjustment =
+		ifSymlink adjustToSymlink noAdjust
+	adjustTreeItemC UnFixAdjustment =
+		ifSymlink (adjustToSymlink' gitAnnexLinkCanonical) noAdjust
+	
+	adjustmentIsStableC _ = True
+
+instance AdjustTreeItemClass PresenceAdjustment where
+	adjustTreeItemC HideMissingAdjustment = 
+		ifPresent noAdjust hideAdjust
+	adjustTreeItemC ShowMissingAdjustment =
+		noAdjust
+
+	adjustmentIsStableC HideMissingAdjustment = False
+	adjustmentIsStableC ShowMissingAdjustment = True
+
+instance AdjustTreeItemClass WantedAdjustment where
+	adjustTreeItemC HideUnwantedAdjustment = 
+		ifWanted noAdjust hideAdjust
+	adjustTreeItemC ShowUnwantedAdjustment =
+		noAdjust
+
+	adjustmentIsStableC HideUnwantedAdjustment = False
+	adjustmentIsStableC ShowUnwantedAdjustment = True
+
+instance AdjustTreeItemClass LockUnlockPresentAdjustment where
+	adjustTreeItemC UnlockPresentAdjustment = 
+		ifPresent adjustToPointer adjustToSymlink
+	adjustTreeItemC LockPresentAdjustment =
+		-- Turn all pointers back to symlinks, whether the content
+		-- is present or not. This is done because the content
+		-- availability may have changed and the branch not been
+		-- re-adjusted to keep up, so there may be pointers whose
+		-- content is not present.
+		ifSymlink noAdjust adjustToSymlink
+
+	adjustmentIsStableC UnlockPresentAdjustment = False
+	adjustmentIsStableC LockPresentAdjustment = True
+
+ifSymlink
+	:: (TreeItem -> Annex a)
+	-> (TreeItem -> Annex a)
+	-> TreeItem
+	-> Annex a
+ifSymlink issymlink notsymlink ti@(TreeItem _f m _s)
+	| toTreeItemType m == Just TreeSymlink = issymlink ti
+	| otherwise = notsymlink ti
+
+ifPresent
+	:: (TreeItem -> Annex (Maybe TreeItem))
+	-> (TreeItem -> Annex (Maybe TreeItem))
+	-> TreeItem
+	-> Annex (Maybe TreeItem)
+ifPresent ispresent notpresent ti@(TreeItem _ _ s) =
+	catKey s >>= \case
+		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
+			af <- AssociatedFile . Just
+				<$> fromRepo (fromTopFilePath topf)
+			ifM (wantGet NoLiveUpdate True (Just k) af)
+				( iswanted ti
+				, notwanted ti
+				)
+		Nothing -> return (Just ti)
+
+noAdjust :: TreeItem -> Annex (Maybe TreeItem)
+noAdjust = return . Just
+
+hideAdjust :: TreeItem -> Annex (Maybe TreeItem)
+hideAdjust _ = return Nothing
+
+adjustToPointer :: TreeItem -> Annex (Maybe TreeItem)
+adjustToPointer ti@(TreeItem f _m s) = catKey s >>= \case
+	Just k -> do
+		Database.Keys.addAssociatedFile k f
+		exe <- catchDefaultIO False $
+			(isExecutable . fileMode) <$> 
+				(liftIO . R.getFileStatus . fromOsPath
+					=<< calcRepo (gitAnnexLocation k))
+		let mode = fromTreeItemType $ 
+			if exe then TreeExecutable else TreeFile
+		Just . TreeItem f mode <$> hashPointerFile k
+	Nothing -> return (Just ti)
+
+adjustToSymlink :: TreeItem -> Annex (Maybe TreeItem)
+adjustToSymlink = adjustToSymlink' gitAnnexLink
+
+adjustToSymlink' :: (OsPath -> Key -> Git.Repo -> GitConfig -> IO OsPath) -> TreeItem -> Annex (Maybe TreeItem)
+adjustToSymlink' gitannexlink ti@(TreeItem f _m s) = catKey s >>= \case
+	Just k -> do
+		absf <- inRepo $ \r -> absPath $ fromTopFilePath f r
+		linktarget <- calcRepo $ gitannexlink absf k
+		Just . TreeItem f (fromTreeItemType TreeSymlink)
+			<$> hashSymlink (fromOsPath linktarget)
+	Nothing -> return (Just ti)
diff --git a/Annex/AdjustedBranch.hs b/Annex/AdjustedBranch.hs
--- 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.
  -}
@@ -12,6 +12,7 @@
 	LinkAdjustment(..),
 	PresenceAdjustment(..),
 	LockUnlockPresentAdjustment(..),
+	WantedAdjustment(..),
 	adjustmentHidesFiles,
 	adjustmentIsStable,
 	OrigBranch,
@@ -41,6 +42,7 @@
 
 import Annex.Common
 import Types.AdjustedBranch
+import Types.AdjustTreeItem
 import Annex.AdjustedBranch.Name
 import qualified Annex
 import Git
@@ -58,125 +60,16 @@
 import qualified Git.LockFile
 import Annex.CatFile
 import Annex.Link
-import Annex.Content.Presence
 import Annex.CurrentBranch
 import Types.CleanupActions
-import qualified Database.Keys
 import Config
 import Logs.View (is_branchView)
 import Logs.AdjustedBranchUpdate
-import Utility.FileMode
-import qualified Utility.RawFilePath as R
 import qualified Utility.FileIO as F
 
 import Data.Time.Clock.POSIX
 import qualified Data.Map as M
-import System.PosixCompat.Files (fileMode)
 
-class AdjustTreeItem t where
-	-- How to perform various adjustments to a TreeItem.
-	adjustTreeItem :: t -> TreeItem -> Annex (Maybe TreeItem)
-	-- Will adjusting a given tree always yield the same adjusted tree?
-	adjustmentIsStable :: t -> Bool
-
-instance AdjustTreeItem Adjustment where
-	adjustTreeItem (LinkAdjustment l) t = adjustTreeItem l t
-	adjustTreeItem (PresenceAdjustment p Nothing) t = adjustTreeItem p t
-	adjustTreeItem (PresenceAdjustment p (Just l)) t =
-		adjustTreeItem p t >>= \case
-			Nothing -> return Nothing
-			Just t' -> adjustTreeItem l t'
-	adjustTreeItem (LockUnlockPresentAdjustment l) t = adjustTreeItem l t
-
-	adjustmentIsStable (LinkAdjustment l) = adjustmentIsStable l
-	adjustmentIsStable (PresenceAdjustment p _) = adjustmentIsStable p
-	adjustmentIsStable (LockUnlockPresentAdjustment l) = adjustmentIsStable l
-
-instance AdjustTreeItem LinkAdjustment where
-	adjustTreeItem UnlockAdjustment =
-		ifSymlink adjustToPointer noAdjust
-	adjustTreeItem LockAdjustment =
-		ifSymlink noAdjust adjustToSymlink
-	adjustTreeItem FixAdjustment =
-		ifSymlink adjustToSymlink noAdjust
-	adjustTreeItem UnFixAdjustment =
-		ifSymlink (adjustToSymlink' gitAnnexLinkCanonical) noAdjust
-	
-	adjustmentIsStable _ = True
-
-instance AdjustTreeItem PresenceAdjustment where
-	adjustTreeItem HideMissingAdjustment = 
-		ifPresent noAdjust hideAdjust
-	adjustTreeItem ShowMissingAdjustment =
-		noAdjust
-
-	adjustmentIsStable HideMissingAdjustment = False
-	adjustmentIsStable ShowMissingAdjustment = True
-
-instance AdjustTreeItem LockUnlockPresentAdjustment where
-	adjustTreeItem UnlockPresentAdjustment = 
-		ifPresent adjustToPointer adjustToSymlink
-	adjustTreeItem LockPresentAdjustment =
-		-- Turn all pointers back to symlinks, whether the content
-		-- is present or not. This is done because the content
-		-- availability may have changed and the branch not been
-		-- re-adjusted to keep up, so there may be pointers whose
-		-- content is not present.
-		ifSymlink noAdjust adjustToSymlink
-
-	adjustmentIsStable UnlockPresentAdjustment = False
-	adjustmentIsStable LockPresentAdjustment = True
-
-ifSymlink
-	:: (TreeItem -> Annex a)
-	-> (TreeItem -> Annex a)
-	-> TreeItem
-	-> Annex a
-ifSymlink issymlink notsymlink ti@(TreeItem _f m _s)
-	| toTreeItemType m == Just TreeSymlink = issymlink ti
-	| otherwise = notsymlink ti
-
-ifPresent
-	:: (TreeItem -> Annex (Maybe TreeItem))
-	-> (TreeItem -> Annex (Maybe TreeItem))
-	-> TreeItem
-	-> Annex (Maybe TreeItem)
-ifPresent ispresent notpresent ti@(TreeItem _ _ s) =
-	catKey s >>= \case
-		Just k -> ifM (inAnnex k) (ispresent ti, notpresent ti)
-		Nothing -> return (Just ti)
-
-noAdjust :: TreeItem -> Annex (Maybe TreeItem)
-noAdjust = return . Just
-
-hideAdjust :: TreeItem -> Annex (Maybe TreeItem)
-hideAdjust _ = return Nothing
-
-adjustToPointer :: TreeItem -> Annex (Maybe TreeItem)
-adjustToPointer ti@(TreeItem f _m s) = catKey s >>= \case
-	Just k -> do
-		Database.Keys.addAssociatedFile k f
-		exe <- catchDefaultIO False $
-			(isExecutable . fileMode) <$> 
-				(liftIO . R.getFileStatus . fromOsPath
-					=<< calcRepo (gitAnnexLocation k))
-		let mode = fromTreeItemType $ 
-			if exe then TreeExecutable else TreeFile
-		Just . TreeItem f mode <$> hashPointerFile k
-	Nothing -> return (Just ti)
-
-adjustToSymlink :: TreeItem -> Annex (Maybe TreeItem)
-adjustToSymlink = adjustToSymlink' gitAnnexLink
-
-adjustToSymlink' :: (OsPath -> Key -> Git.Repo -> GitConfig -> IO OsPath) -> TreeItem -> Annex (Maybe TreeItem)
-adjustToSymlink' gitannexlink ti@(TreeItem f _m s) = catKey s >>= \case
-	Just k -> do
-		absf <- inRepo $ \r -> absPath $ fromTopFilePath f r
-		linktarget <- calcRepo $ gitannexlink absf k
-		Just . TreeItem f (fromTreeItemType TreeSymlink)
-			<$> hashSymlink (fromOsPath linktarget)
-	Nothing -> return (Just ti)
-
 -- This is a hidden branch ref, that's used as the basis for the AdjBranch,
 -- since pushes can overwrite the OrigBranch at any time. So, changes
 -- are propagated from the AdjBranch to the head of the BasisBranch.
@@ -201,11 +94,11 @@
  - Can fail, if no branch is checked out, or if the adjusted branch already
  - exists, or if staged changes prevent a checkout.
  -}
-enterAdjustedBranch :: Adjustment -> Annex Bool
-enterAdjustedBranch adj = inRepo Git.Branch.current >>= \case
+enterAdjustedBranch :: Adjustment -> AdjustTreeItem -> Annex Bool
+enterAdjustedBranch adj ati = inRepo Git.Branch.current >>= \case
 	Just currbranch -> case getAdjustment currbranch of
 		Just curradj | curradj == adj ->
-			updateAdjustedBranch adj (AdjBranch currbranch)
+			updateAdjustedBranch adj ati (AdjBranch currbranch)
 				(fromAdjustedBranch currbranch)
 		_ -> go currbranch
 	Nothing -> do
@@ -233,7 +126,7 @@
 			, do
 				starttime <- liftIO getPOSIXTime
 				b <- preventCommits $ const $ 
-					adjustBranch adj origbranch
+					adjustBranch adj ati origbranch
 				ok <- checkoutAdjustedBranch b False
 				when ok $
 					recordAdjustedBranchUpdateFinished starttime
@@ -257,19 +150,19 @@
  - and rebuilding the adjusted branch, and then checking it out.
  - But, it can be implemented more efficiently than that.
  -}
-updateAdjustedBranch :: Adjustment -> AdjBranch -> OrigBranch -> Annex Bool
-updateAdjustedBranch adj (AdjBranch currbranch) origbranch
-	| not (adjustmentIsStable adj) = do
+updateAdjustedBranch :: Adjustment -> AdjustTreeItem -> AdjBranch -> OrigBranch -> Annex Bool
+updateAdjustedBranch adj ati (AdjBranch currbranch) origbranch
+	| not (adjustmentIsStable ati adj) = do
 		(b, origheadfile, newheadfile) <- preventCommits $ \commitlck -> do
 			-- Avoid losing any commits that the adjusted branch
 			-- has that have not yet been propagated back to the
 			-- origbranch.
-			_ <- propigateAdjustedCommits' True origbranch adj commitlck
+			_ <- propigateAdjustedCommits' True origbranch adj ati commitlck
 			
 			origheadfile <- inRepo $ F.readFile' . Git.Ref.headFile
 			origheadsha <- inRepo (Git.Ref.sha currbranch)
 			
-			b <- adjustBranch adj origbranch
+			b <- adjustBranch adj ati origbranch
 
 			-- Git normally won't do anything when asked to check
 			-- out the currently checked out branch, even when its
@@ -300,7 +193,7 @@
 		return ok
 	| otherwise = preventCommits $ \commitlck -> do
 		-- Done for consistency.
-		_ <- propigateAdjustedCommits' True origbranch adj commitlck
+		_ <- propigateAdjustedCommits' True origbranch adj ati commitlck
 		-- No need to actually update the branch because the
 		-- adjustment is stable.
 		return True
@@ -309,15 +202,15 @@
  - When the adjusted branch needs to be refreshed to reflect
  - those changes, it's handled here.
  -}
-adjustedBranchRefresh :: Annex a -> Annex a
-adjustedBranchRefresh a = do
+adjustedBranchRefresh :: AdjustTreeItem -> Annex a -> Annex a
+adjustedBranchRefresh ati a = do
 	r <- a
 	go
 	return r
   where
 	go = getCurrentBranch >>= \case
 		(Just origbranch, Just adj) ->
-			unless (adjustmentIsStable adj) $ do
+			unless (adjustmentIsStable ati adj) $ do
 				recordAdjustedBranchUpdateNeeded
 				n <- annexAdjustedBranchRefresh <$> Annex.getGitConfig
 				unless (n == 0) $ ifM (checkcounter n)
@@ -325,9 +218,9 @@
 					-- adjust the AssociatedFile, and only call this once
 					-- at shutdown to handle cases where not all
 					-- AssociatedFiles are known.
-					( adjustedBranchRefreshFull' adj origbranch
+					( adjustedBranchRefreshFull' adj ati origbranch
 					, Annex.addCleanupAction AdjustedBranchUpdate $
-						adjustedBranchRefreshFull' adj origbranch
+						adjustedBranchRefreshFull' adj ati origbranch
 					)
 		_ -> return ()
 	
@@ -343,25 +236,25 @@
 
 {- Slow, but more dependable version of adjustedBranchRefresh that
  - does not rely on all AssociatedFiles being known. -}
-adjustedBranchRefreshFull :: Adjustment -> OrigBranch -> Annex ()
-adjustedBranchRefreshFull adj origbranch =
+adjustedBranchRefreshFull :: Adjustment -> AdjustTreeItem -> OrigBranch -> Annex ()
+adjustedBranchRefreshFull adj ati origbranch =
 	whenM isAdjustedBranchUpdateNeeded $ do
-		adjustedBranchRefreshFull' adj origbranch
+		adjustedBranchRefreshFull' adj ati origbranch
 
-adjustedBranchRefreshFull' :: Adjustment -> OrigBranch -> Annex ()
-adjustedBranchRefreshFull' adj origbranch = do
+adjustedBranchRefreshFull' :: Adjustment -> AdjustTreeItem -> OrigBranch -> Annex ()
+adjustedBranchRefreshFull' adj ati origbranch = do
 	-- Restage pointer files so modifications to them due to get/drop
 	-- do not prevent checking out the updated adjusted branch.
 	restagePointerFiles =<< Annex.gitRepo
 	starttime <- liftIO getPOSIXTime
 	let adjbranch = originalToAdjusted origbranch adj
-	ifM (updateAdjustedBranch adj adjbranch origbranch)
+	ifM (updateAdjustedBranch adj ati adjbranch origbranch)
 		( recordAdjustedBranchUpdateFinished starttime
 		, warning "Updating adjusted branch failed."
 		)
 
-adjustToCrippledFileSystem :: Annex ()
-adjustToCrippledFileSystem = do
+adjustToCrippledFileSystem :: AdjustTreeItem -> Annex ()
+adjustToCrippledFileSystem ati = do
 	warning "Entering an adjusted branch where files are unlocked as this filesystem does not support locked files."
 	whenM (isNothing <$> inRepo Git.Branch.current) $
 		commitForAdjustedBranch []
@@ -373,7 +266,7 @@
 				ifM (inRepo (Git.Ref.exists $ adjBranch adjbranch))
 					( unlessM (checkoutAdjustedBranch adjbranch False) $
 						failedenter
-					, unlessM (enterAdjustedBranch adj) $
+					, unlessM (enterAdjustedBranch adj ati) $
 						failedenter
 					)
 		Nothing -> failedenter
@@ -404,25 +297,25 @@
 setAdjustedBranch :: String -> AdjBranch -> Ref -> Annex ()
 setAdjustedBranch msg (AdjBranch b) r = inRepo $ Git.Branch.update msg b r
 
-adjustBranch :: Adjustment -> OrigBranch -> Annex AdjBranch
-adjustBranch adj origbranch = do
+adjustBranch :: Adjustment -> AdjustTreeItem -> OrigBranch -> Annex AdjBranch
+adjustBranch adj ati origbranch = do
 	-- Start basis off with the current value of the origbranch.
 	setBasisBranch basis origbranch
-	sha <- adjustCommit adj basis
+	sha <- adjustCommit adj ati basis
 	setAdjustedBranch "entering adjusted branch" adjbranch sha
 	return adjbranch
   where
 	adjbranch = originalToAdjusted origbranch adj
 	basis = basisBranch adjbranch
 
-adjustCommit :: Adjustment -> BasisBranch -> Annex Sha
-adjustCommit adj basis = do
-	treesha <- adjustTree adj basis
+adjustCommit :: Adjustment -> AdjustTreeItem -> BasisBranch -> Annex Sha
+adjustCommit adj ati basis = do
+	treesha <- adjustTree adj ati basis
 	commitAdjustedTree treesha basis
 
-adjustTree :: Adjustment -> BasisBranch -> Annex Sha
-adjustTree adj (BasisBranch basis) = do
-	let toadj = adjustTreeItem adj
+adjustTree :: Adjustment -> AdjustTreeItem -> BasisBranch -> Annex Sha
+adjustTree adj ati (BasisBranch basis) = do
+	let toadj = adjustTreeItem ati adj
 	treesha <- Git.Tree.adjustTree
 		toadj 
 		[] 
@@ -504,10 +397,10 @@
  - After propagating the commits back to the basis branch,
  - rebase the adjusted branch on top of the updated basis branch.
  -}
-propigateAdjustedCommits :: OrigBranch -> Adjustment -> Annex ()
-propigateAdjustedCommits origbranch adj = 
+propigateAdjustedCommits :: OrigBranch -> Adjustment -> AdjustTreeItem -> Annex ()
+propigateAdjustedCommits origbranch adj ati = 
 	preventCommits $ \commitsprevented ->
-		join $ snd <$> propigateAdjustedCommits' True origbranch adj commitsprevented
+		join $ snd <$> propigateAdjustedCommits' True origbranch adj ati commitsprevented
 		
 {- Returns sha of updated basis branch, and action which will rebase
  - the adjusted branch on top of the updated basis branch. -}
@@ -515,9 +408,10 @@
 	:: Bool
 	-> OrigBranch
 	-> Adjustment
+	-> AdjustTreeItem
 	-> CommitsPrevented
 	-> Annex (Maybe Sha, Annex ())
-propigateAdjustedCommits' warnwhendiverged origbranch adj _commitsprevented =
+propigateAdjustedCommits' warnwhendiverged origbranch adj ati _commitsprevented =
 	inRepo (Git.Ref.sha basis) >>= \case
 		Just origsha -> catCommit currbranch >>= \case
 			Just currcommit -> do
@@ -552,7 +446,7 @@
 			| hasAdjustedBranchCommitMessage c ->
 				go origsha parent True l
 			| pastadjcommit -> do
-				commit <- reverseAdjustedCommit parent adj (sha, c) origbranch
+				commit <- reverseAdjustedCommit parent adj ati (sha, c) origbranch
 				go origsha commit pastadjcommit l
 		_ -> go origsha parent pastadjcommit l
 	rebase currcommit newparent = do
@@ -573,12 +467,12 @@
  - The commit message, and the author and committer metadata are
  - copied over from the basiscommit. However, any gpg signature
  - will be lost, and any other headers are not copied either. -}
-reverseAdjustedCommit :: Sha -> Adjustment -> (Sha, Commit) -> OrigBranch -> Annex Sha
-reverseAdjustedCommit commitparent adj (csha, basiscommit) origbranch
+reverseAdjustedCommit :: Sha -> Adjustment -> AdjustTreeItem -> (Sha, Commit) -> OrigBranch -> Annex Sha
+reverseAdjustedCommit commitparent adj ati (csha, basiscommit) origbranch
 	| length (commitParent basiscommit) > 1 = giveup mergeerror
 	| otherwise = do
 		cmode <- annexCommitMode <$> Annex.getGitConfig
-		treesha <- reverseAdjustedTree commitparent adj csha
+		treesha <- reverseAdjustedTree commitparent adj ati csha
 		revadjcommit <- inRepo $ commitWithMetaData
 			(commitAuthorMetaData basiscommit)
 			(commitCommitterMetaData basiscommit) $
@@ -598,13 +492,13 @@
  -
  - commitDiff does not support merge commits, so the csha must not be a
  - merge commit. -}
-reverseAdjustedTree :: Sha -> Adjustment -> Sha -> Annex Sha
-reverseAdjustedTree basis adj csha = do
+reverseAdjustedTree :: Sha -> Adjustment -> AdjustTreeItem -> Sha -> Annex Sha
+reverseAdjustedTree basis adj ati csha = do
 	(diff, cleanup) <- inRepo (Git.DiffTree.commitDiff csha)
 	let (adds, others) = partition (\dti -> Git.DiffTree.srcsha dti `elem` nullShas) diff
 	let (removes, changes) = partition (\dti -> Git.DiffTree.dstsha dti `elem` nullShas) others
 	adds' <- catMaybes <$>
-		mapM (adjustTreeItem reverseadj) (map diffTreeToTreeItem adds)
+		mapM (adjustTreeItem ati reverseadj) (map diffTreeToTreeItem adds)
 	treesha <- Git.Tree.adjustTree
 		(propchanges changes)
 		adds'
@@ -619,7 +513,7 @@
 	propchanges changes ti@(TreeItem f _ _) =
 		case M.lookup (norm f) m of
 			Nothing -> return (Just ti) -- not changed
-			Just change -> adjustTreeItem reverseadj change
+			Just change -> adjustTreeItem ati reverseadj change
 	  where
 		m = M.fromList $ map (\i@(TreeItem f' _ _) -> (norm f', i)) $
 			map diffTreeToTreeItem changes
diff --git a/Annex/AdjustedBranch/Merge.hs b/Annex/AdjustedBranch/Merge.hs
--- a/Annex/AdjustedBranch/Merge.hs
+++ b/Annex/AdjustedBranch/Merge.hs
@@ -14,6 +14,7 @@
 
 import Annex.Common
 import Annex.AdjustedBranch
+import Annex.AdjustTreeItem
 import qualified Annex
 import Git
 import Git.Types
@@ -49,7 +50,7 @@
 
 	go commitsprevented = do
 		(updatedorig, _) <- propigateAdjustedCommits'
-			False origbranch adj commitsprevented
+			False origbranch adj getAdjustTreeItem commitsprevented
 		changestomerge updatedorig
 
 	{- Since the adjusted branch changes files, merging tomerge
@@ -131,7 +132,7 @@
 	postmerge (Just mergecommit) = do
 		setBasisBranch basis mergecommit
 		inRepo $ Git.Branch.update' origbranch mergecommit
-		adjtree <- adjustTree adj (BasisBranch mergecommit)
+		adjtree <- adjustTree adj getAdjustTreeItem (BasisBranch mergecommit)
 		adjmergecommit <- commitAdjustedTree adjtree (BasisBranch mergecommit)
 		-- Make currbranch be the parent, so that merging
 		-- this commit will be a fast-forward.
@@ -155,7 +156,7 @@
 					[adjmergecommit]
 					(commitTree currentcommit)
 				inRepo $ Git.Branch.update "updating adjusted branch" currbranch c
-				propigateAdjustedCommits origbranch adj
+				propigateAdjustedCommits origbranch adj getAdjustTreeItem
 			else inRepo $ Git.Branch.update "updating adjusted branch" currbranch adjmergecommit
 		return True
 	reparent _ _ Nothing = return False
diff --git a/Annex/AdjustedBranch/Name.hs b/Annex/AdjustedBranch/Name.hs
--- 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 @@
 		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 @@
 		(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
 
@@ -73,6 +81,13 @@
 	serializeAdjustment LockPresentAdjustment = "lockpresent"
 	deserializeAdjustment "unlockpresent" = Just UnlockPresentAdjustment
 	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 }
diff --git a/Annex/Branch.hs b/Annex/Branch.hs
--- a/Annex/Branch.hs
+++ b/Annex/Branch.hs
@@ -38,6 +38,7 @@
 	files,
 	rememberTreeish,
 	performTransitions,
+	checkTransitionedRef,
 	withIndex,
 	precache,
 	UnmergedBranches(..),
@@ -807,6 +808,18 @@
 			ignoreRefs untransitionedrefs
 			return True
 
+{- Checks if the passed ref is to a sha that has been merged into the
+ - git-annex branch already, but was not able to be listed as a parent due
+ - to a transition. If so, returns the sha. -}
+checkTransitionedRef :: Git.Ref -> Annex (Maybe Git.Sha)
+checkTransitionedRef r = do
+	ir <- getIgnoredRefs
+	if S.null ir
+		then return Nothing
+		else inRepo (Git.Ref.sha r) >>= \case
+			Just sha | S.member sha ir -> return (Just sha)
+			_ -> return Nothing
+
 {- Performs the specified transitions on the contents of the index file,
  - commits it to the branch, or creates a new branch.
  -}
@@ -846,7 +859,7 @@
 	message
 		| neednewlocalbranch && null transitionedrefs = "new branch for transition " ++ tdesc
 		| otherwise = "continuing transition " ++ tdesc
-	tdesc = show $ map describeTransition tlist
+	tdesc = intercalate ", " (map describeTransition tlist)
 	tlist = knownTransitionList ts
 
 	{- The changes to make to the branch are calculated and applied to
diff --git a/Annex/Content.hs b/Annex/Content.hs
--- a/Annex/Content.hs
+++ b/Annex/Content.hs
@@ -94,6 +94,7 @@
 import Annex.InodeSentinal
 import Annex.ReplaceFile
 import Annex.AdjustedBranch (adjustedBranchRefresh)
+import Annex.AdjustTreeItem
 import Annex.DirHashes
 import Messages.Progress
 import Types.Remote (RetrievalSecurityPolicy(..), VerifyConfigA(..), name, storeKey, uuid)
@@ -538,7 +539,7 @@
   where
 	storeobject dest = ifM (liftIO $ doesPathExist dest)
 		( alreadyhave
-		, adjustedBranchRefresh $ modifyContentDir dest $ do
+		, adjustedBranchRefresh getAdjustTreeItem $ modifyContentDir dest $ do
 			liftIO $ moveFile src dest
 			-- Freeze the object file now that it is in place.
 			-- Waiting until now to freeze it allows for freeze
@@ -793,7 +794,7 @@
 	-- it's unmodified.
 	resetpointer file = unlessM (liftIO $ isSymbolicLink <$> R.getSymbolicLinkStatus (fromOsPath file)) $
 		ifM (isUnmodified key file)
-			( adjustedBranchRefresh $ 
+			( adjustedBranchRefresh getAdjustTreeItem $ 
 				depopulatePointerFile QueueRestage key file
 			-- Modified file, so leave it alone.
 			-- If it was a hard link to the annex object,
diff --git a/Annex/Ingest.hs b/Annex/Ingest.hs
--- a/Annex/Ingest.hs
+++ b/Annex/Ingest.hs
@@ -257,7 +257,7 @@
 cleanCruft source = when (contentLocation source /= keyFilename source) $
 	liftIO $ removeWhenExistsWith removeFile $ contentLocation source
 
--- If a worktree file was was hard linked to an annex object before,
+-- If a worktree file was hard linked to an annex object before,
 -- modifying the file would have caused the object to have the wrong
 -- content. Clean up from that.
 cleanOldKeys :: OsPath -> Key -> Annex ()
@@ -351,6 +351,8 @@
 	go (LinkAdjustment UnFixAdjustment) = False
 	go (PresenceAdjustment _ (Just la)) = go (LinkAdjustment la)
 	go (PresenceAdjustment _ Nothing) = False
+	go (WantedAdjustment _ (Just la)) = go (LinkAdjustment la)
+	go (WantedAdjustment _ Nothing) = False
 	go (LockUnlockPresentAdjustment UnlockPresentAdjustment) = contentpresent
 	go (LockUnlockPresentAdjustment LockPresentAdjustment) = False
 
diff --git a/Annex/Init.hs b/Annex/Init.hs
--- a/Annex/Init.hs
+++ b/Annex/Init.hs
@@ -49,6 +49,7 @@
 import Config.Smudge
 import qualified Upgrade.V5.Direct as Direct
 import qualified Annex.AdjustedBranch as AdjustedBranch
+import Annex.AdjustTreeItem
 import Remote.List.Util (remotesChanged)
 import Annex.Environment
 import Annex.Hook
@@ -169,7 +170,7 @@
 		AdjustedBranch.InAdjustedClone -> return ()
 		AdjustedBranch.NotInAdjustedClone ->
 			ifM (crippledFileSystem <&&> (not <$> isBareRepo))
-				( AdjustedBranch.adjustToCrippledFileSystem
+				( AdjustedBranch.adjustToCrippledFileSystem getAdjustTreeItem
 				-- Handle case where this repo was cloned from a
 				-- direct mode repo
 				, unlessM isBareRepo
diff --git a/Annex/SpecialRemote/Config.hs b/Annex/SpecialRemote/Config.hs
--- a/Annex/SpecialRemote/Config.hs
+++ b/Annex/SpecialRemote/Config.hs
@@ -159,6 +159,7 @@
 	, cipherField
 	, cipherkeysField
 	, pubkeysField
+	, onlyEncryptCredsField
 	-- legacy chunking was either enabled or not, so has to be the same
 	-- across configs for remotes that access the same data
 	, chunksizeField
diff --git a/Annex/Wanted.hs-boot b/Annex/Wanted.hs-boot
new file mode 100644
--- /dev/null
+++ b/Annex/Wanted.hs-boot
@@ -0,0 +1,5 @@
+module Annex.Wanted where
+
+import Annex.Common
+
+wantGet :: LiveUpdate -> Bool -> Maybe Key -> AssociatedFile -> Annex Bool
diff --git a/Assistant/MakeRepo.hs b/Assistant/MakeRepo.hs
--- a/Assistant/MakeRepo.hs
+++ b/Assistant/MakeRepo.hs
@@ -18,6 +18,7 @@
 import qualified Annex
 import Annex.UUID
 import Annex.AdjustedBranch
+import Annex.AdjustTreeItem
 import Annex.Action
 import Annex.Startup
 import Types.StandardGroups
@@ -73,7 +74,7 @@
 	 - once a day.
 	 -}
 	when primary_assistant_repo $ do
-		void $ enterAdjustedBranch (LinkAdjustment UnlockAdjustment)
+		void $ enterAdjustedBranch (LinkAdjustment UnlockAdjustment) getAdjustTreeItem
 		setConfig (annexConfig "thin") (Git.Config.boolConfig True)
 		inRepo $ Git.Command.run
 			[Param "config", Param "gc.auto", Param "0"]
diff --git a/Assistant/Sync.hs b/Assistant/Sync.hs
--- a/Assistant/Sync.hs
+++ b/Assistant/Sync.hs
@@ -1,6 +1,6 @@
 {- git-annex assistant repo syncing
  -
- - Copyright 2012 Joey Hess <id@joeyh.name>
+ - Copyright 2012-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -39,6 +39,7 @@
 import Assistant.Commits
 import Types.Transfer
 import Database.Export
+import Utility.Tuple
 
 import Data.Time.Clock
 import qualified Data.Map as M
@@ -162,20 +163,23 @@
 
 	fallback branch g u rs = do
 		debug ["fallback pushing to", show rs]
-		(succeeded, failed) <- parallelPush g rs (taggedPush u Nothing branch)
+		(succeeded, failed) <- parallelPush g rs
+			(\r -> return $ taggedPush u Nothing branch r)
 		updatemap succeeded failed
 		return failed
-		
+	
 	push ms branch remote = Command.Sync.pushBranch remote (Just branch) ms
 
-parallelPush :: Git.Repo -> [Remote] -> (Remote -> Git.Repo -> IO Bool)-> Assistant ([Remote], [Remote])
+parallelPush :: Git.Repo -> [Remote] -> (Remote -> Annex (Git.Repo -> IO Bool)) -> Assistant ([Remote], [Remote])
 parallelPush g rs a = do
-	rgs <- liftAnnex $ mapM topush rs
-	(succeededrgs, failedrgs) <- liftIO $ inParallel (uncurry a) rgs
-	return (map fst succeededrgs, map fst failedrgs)
+	ars <- liftAnnex $ mapM topush rs
+	(succeeded, failed) <- liftIO $
+		inParallel (\(_, a', r) -> a' r) ars
+	return (map fst3 succeeded, map fst3 failed)
   where
-	topush r = (,)
+	topush r = (,,)
 		<$> pure r
+		<*> a r
 		<*> (Remote.getRepo r >>= \repo ->
 			sshOptionsTo repo (Remote.gitconfig r) g)
 
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,15 @@
+git-annex (10.20261020) upstream; urgency=medium
+
+  * adjust --hide-unwanted: New option to make an adjusted branch
+    containing only wanted files.
+  * push: Force push to remote git-annex branch when it has been
+    supersceded by a transition.
+  * Fix handling of --sameas special remotes with onlyencryptcreds=yes.
+  * Linux standalone builds bundled CA certs updated for
+    EMudhra Intermediate CA Compromise.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 20 Oct 2026 16:45:06 -0400
+
 git-annex (10.20261006) upstream; urgency=medium
 
   * Fix stack build.
diff --git a/Command/Adjust.hs b/Command/Adjust.hs
--- a/Command/Adjust.hs
+++ b/Command/Adjust.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2016-2018 Joey Hess <id@joeyh.name>
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -9,6 +9,7 @@
 
 import Command
 import Annex.AdjustedBranch
+import Annex.AdjustTreeItem
 
 cmd :: Command
 cmd = notBareRepo $ noDaemonRunning $
@@ -17,22 +18,27 @@
 
 optParser :: CmdParamsDesc -> Parser Adjustment
 optParser _ =
-	linkPresentAdjustmentParser
+	linkPresentWantedAdjustmentParser
 	<|> (LockUnlockPresentAdjustment <$> lockUnlockPresentAdjustmentParser)
 	
-linkPresentAdjustmentParser :: Parser Adjustment
-linkPresentAdjustmentParser = comb <$> some ps
+linkPresentWantedAdjustmentParser :: Parser Adjustment
+linkPresentWantedAdjustmentParser = comb <$> some ps
   where
 	ps = (LinkAdjustment <$> linkAdjustmentParser)
 		<|> (PresenceAdjustment <$> presenceAdjustmentParser <*> pure Nothing)
+		<|> (WantedAdjustment <$> wantedAdjustmentParser <*> pure Nothing)
 	comb (LinkAdjustment _ : LinkAdjustment b : c) =
 		comb (LinkAdjustment b : c)
 	comb (PresenceAdjustment _a1 a2 : PresenceAdjustment b1 b2 : c) = 
 		comb (PresenceAdjustment b1 (b2 <|> a2) : c)
+	comb (WantedAdjustment _a1 a2 : WantedAdjustment b1 b2 : c) = 
+		comb (WantedAdjustment b1 (b2 <|> a2) : c)
 	comb (LinkAdjustment a : PresenceAdjustment b1 b2 : c) =
 		comb (PresenceAdjustment b1 (b2 <|> Just a) : c)
 	comb (PresenceAdjustment a1 _a2 : LinkAdjustment b : c) =
 		comb (PresenceAdjustment a1 (Just b) : c)
+	comb (WantedAdjustment a1 _a2 : LinkAdjustment b : c) =
+		comb (WantedAdjustment a1 (Just b) : c)
 	comb (a : _) = a
 	comb [] = error "internal"
 
@@ -58,6 +64,13 @@
 		<> help "hide annexed files whose content is not present"
 		)
 
+wantedAdjustmentParser :: Parser WantedAdjustment
+wantedAdjustmentParser =
+	flag' HideUnwantedAdjustment
+		( long "hide-unwanted"
+		<> help "hide annexed files that are not wanted"
+		)
+
 lockUnlockPresentAdjustmentParser :: Parser LockUnlockPresentAdjustment
 lockUnlockPresentAdjustmentParser =
 	flag' UnlockPresentAdjustment
@@ -71,4 +84,4 @@
 start :: Adjustment -> CommandStart
 start adj = 
 	starting "adjust" (ActionItemOther Nothing) (SeekInput []) $
-		next $ enterAdjustedBranch adj
+		next $ enterAdjustedBranch adj getAdjustTreeItem
diff --git a/Command/EnableRemote.hs b/Command/EnableRemote.hs
--- a/Command/EnableRemote.hs
+++ b/Command/EnableRemote.hs
@@ -16,7 +16,6 @@
 import qualified Git
 import qualified Annex.SpecialRemote as SpecialRemote
 import qualified Remote
-import qualified Types.Remote as Remote
 import qualified Remote.Git
 import qualified Command.InitRemote
 import Logs.UUID
@@ -67,7 +66,7 @@
 			-- remote that has an url (eg gcrypt).
 			rs <- Remote.remoteList
 			case filter (\rmt -> Remote.name rmt == name) rs of
-				(rmt:_) | Remote.remotetype rmt == Remote.Git.remote ->
+				(rmt:_) | R.remotetype rmt == Remote.Git.remote ->
 					startNormalRemote name r
 				_  -> go []
 
@@ -83,12 +82,12 @@
 	ai = ActionItemOther (Just (UnquotedString name))
 	si = SeekInput [name]
 
-startSpecialRemote :: EnableRemoteOptions -> RemoteName -> Remote.RemoteConfig -> [(UUID, Remote.RemoteConfig, Maybe (SpecialRemote.ConfigFrom UUID))] -> CommandStart
+startSpecialRemote :: EnableRemoteOptions -> RemoteName -> R.RemoteConfig -> [(UUID, R.RemoteConfig, Maybe (SpecialRemote.ConfigFrom UUID))] -> CommandStart
 startSpecialRemote o = startSpecialRemote' "enableremote" (performSpecialRemote o)
 
 type PerformSpecialRemote = RemoteType -> UUID -> RemoteName -> R.RemoteConfig -> R.RemoteConfig -> RemoteGitConfig -> Maybe (SpecialRemote.ConfigFrom UUID) -> CommandPerform
 
-startSpecialRemote' :: String -> PerformSpecialRemote -> RemoteName -> Remote.RemoteConfig -> [(UUID, Remote.RemoteConfig, Maybe (SpecialRemote.ConfigFrom UUID))] -> CommandStart
+startSpecialRemote' :: String -> PerformSpecialRemote -> RemoteName -> R.RemoteConfig -> [(UUID, R.RemoteConfig, Maybe (SpecialRemote.ConfigFrom UUID))] -> CommandStart
 startSpecialRemote' cname perform name config [] = do
 	m <- SpecialRemote.specialRemoteMap
 	confm <- Logs.Remote.remoteConfigMap
@@ -106,7 +105,7 @@
 				giveup "Cannot change type= of existing special remote. Instead, use: git-annex initremote --sameas"
 			_ -> noop
 		gc <- maybe (liftIO dummyRemoteGitConfig) 
-			(return . Remote.gitconfig)
+			(return . R.gitconfig)
 			=<< Remote.byUUID u
 		perform t u name c fullconfig gc mcu
   where
@@ -169,7 +168,7 @@
 
 -- Use dead remote only when there is no other remote
 -- with the same name
-deadLast :: RemoteName -> ([(UUID, Remote.RemoteConfig, Maybe (SpecialRemote.ConfigFrom UUID))] -> Annex a) -> Annex a
+deadLast :: RemoteName -> ([(UUID, R.RemoteConfig, Maybe (SpecialRemote.ConfigFrom UUID))] -> Annex a) -> Annex a
 deadLast name use =
 	SpecialRemote.findExisting' name >>= \case
 		([], l) -> use l
diff --git a/Command/Sync.hs b/Command/Sync.hs
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -8,6 +8,7 @@
 
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
 
 module Command.Sync (
 	cmd,
@@ -68,6 +69,7 @@
 import Annex.AutoMerge
 import Annex.AdjustedBranch
 import Annex.AdjustedBranch.Merge
+import Annex.AdjustTreeItem
 import Annex.View
 import Annex.Ssh
 import Annex.BloomFilter
@@ -551,17 +553,18 @@
 		Nothing -> case madj of
 			Just adj -> do
 				when forpush $
-					propigateAdjustedCommits branch adj
+					propigateAdjustedCommits branch adj getAdjustTreeItem
 				when forpull $
 					updateadjustedbranch adj
 			Nothing -> noop
   where
 	-- The adjusted branch may need to be updated, if the adjustment
 	-- is not stable, and the usual configuration does not update it.
-	updateadjustedbranch adj = unless (adjustmentIsStable adj) $
-		annexAdjustedBranchRefresh <$> Annex.getGitConfig >>= \case
-			0 -> adjustedBranchRefreshFull adj branch
-			_ -> return ()
+	updateadjustedbranch adj = 
+		unless (adjustmentIsStable getAdjustTreeItem adj) $
+			annexAdjustedBranchRefresh <$> Annex.getGitConfig >>= \case
+				0 -> adjustedBranchRefreshFull adj getAdjustTreeItem branch
+				_ -> return ()
 	
 	updateview view madj' = updateView view madj' >>= \case
 		Nothing -> noop
@@ -710,8 +713,8 @@
 			repo <- Remote.getRepo remote
 			showOutput
 			ms <- Annex.getState Annex.output
-			ok <- inRepoWithSshOptionsTo repo gc $
-				pushBranch remote mainbranch ms
+			pb <- pushBranch remote mainbranch ms
+			ok <- inRepoWithSshOptionsTo repo gc pb
 			if ok
 				then postpushupdate repo
 				else do
@@ -753,8 +756,8 @@
 				<&&>
 			needUpdateInsteadEmulation			
 
-{- Pushes a regular branch like master to a remote. Also pushes the git-annex
- - branch.
+{- Returns an IO action that pushes a regular branch like master to a remote,
+ - and 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.
@@ -788,13 +791,23 @@
  - new data is usually sent in this push (due to synced/git-annex already
  - having been pushed), it's ok to hide git's output to avoid displaying
  - a push error.
+ - 
+ - When the remote's git-annex branch has been incorporated in a
+ - transition, push of the git-annex branch is forced, with a lease, 
+ - to avoid the push failing due to a non fast-forward.
  -}
-pushBranch :: Remote -> Maybe Git.Branch -> MessageState -> Git.Repo -> IO Bool
-pushBranch remote mbranch ms g = do
-	directpushed <- directpush
-	annexpush `after` syncpush directpushed
+pushBranch
+	:: Remote
+	-> Maybe Git.Branch
+	-> MessageState
+	-> Annex (Git.Repo -> IO Bool)
+pushBranch remote mbranch ms = do
+	annexpush <- getannexpush
+	return $ \g -> do
+		directpushed <- directpush g
+		annexpush g `after` syncpush directpushed g
   where
-	directpush = case mbranch of
+	directpush g = case mbranch of
 		Just branch -> do
 			let p = flip Git.Command.gitCreateProcess g $
 				pushparams True
@@ -806,7 +819,7 @@
 			return (True, exitcode == ExitSuccess)
 		Nothing -> return (False, False)
 	
-	syncpush (directpushed, directbranchupdated) =  do
+	syncpush (directpushed, directbranchupdated) g = do
 		let p = flip Git.Command.gitCreateProcess g $
 			pushparams (not directpushed) $ catMaybes
 				[ if not directbranchupdated
@@ -822,8 +835,22 @@
 			relaystderr (stderrHandle h) (processHandle h)
 			checkSuccessProcess (processHandle h)
 	
-	annexpush = void $ tryIO $ flip Git.Command.runQuiet g $ pushparams False
-		[ Git.fromRef $ Git.Ref.base $ Annex.Branch.name ]
+	getannexpush = do
+		let rb = remoteBranch remote Annex.Branch.name
+		leaseopt <- Annex.Branch.checkTransitionedRef rb >>= return . \case
+			Just sha -> Just $ concat
+				[ "--force-with-lease="
+				, Git.fromRef Annex.Branch.name
+				, ":"
+				, Git.fromRef sha
+				]
+			Nothing -> Nothing
+		return $ \g ->
+			void $ tryIO $ flip Git.Command.runQuiet g $
+				pushparams False $ catMaybes 
+					[ Just $ Git.fromRef $ Git.Ref.base $ Annex.Branch.name
+					, leaseopt
+					]
 	
 	-- In the default configuration of receive.denyCurrentBranch,
 	-- git's stderr message mentions that config setting
@@ -853,7 +880,7 @@
 			relaystderr herr pid
 		Nothing -> return ()
 
-	pushparams forceprogress branches = catMaybes
+	pushparams forceprogress ps = catMaybes
 		[ Just $ Param "push"
 		, if commandProgressDisabled' ms
 			then Just $ Param "--quiet"
@@ -861,7 +888,7 @@
 				then Just $ Param "--progress"
 				else Nothing
 		, Just $ Param $ Remote.name remote
-		] ++ map Param branches
+		] ++ map Param ps
 	
 	syncrefspec b = concat 
 		[ Git.fromRef $ Git.Ref.base b
@@ -1100,7 +1127,7 @@
 		-- branch, it will be up-to-date.
 		case (mcurrbranch, madj) of
 			(Just currbranch, Just adj) ->
-				propigateAdjustedCommits currbranch adj
+				propigateAdjustedCommits currbranch adj getAdjustTreeItem
 			_ -> noop
 		or <$> forM rs go
   where
diff --git a/Logs/File.hs b/Logs/File.hs
--- a/Logs/File.hs
+++ b/Logs/File.hs
@@ -131,7 +131,7 @@
 -- streamed. It is run even if the log file does not exist. If the
 -- finalizer throws an exception, the log file is left unchanged.
 -- 
--- Locking is used to prevent writes to to the log file while this
+-- Locking is used to prevent writes to the log file while this
 -- is running.
 streamLogFile :: OsPath -> OsPath -> Annex () -> (String -> Annex ()) -> Annex ()
 streamLogFile f lck finalizer processor = 
diff --git a/Types/AdjustTreeItem.hs b/Types/AdjustTreeItem.hs
new file mode 100644
--- /dev/null
+++ b/Types/AdjustTreeItem.hs
@@ -0,0 +1,19 @@
+{- type for adjusting a TreeItem
+ -
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module Types.AdjustTreeItem where
+
+import Annex.Common
+import Types.AdjustedBranch
+import Git.Tree (TreeItem(..))
+
+data AdjustTreeItem = AdjustTreeItem
+	-- How to perform various adjustments to a TreeItem.
+	{ adjustTreeItem :: Adjustment -> TreeItem -> Annex (Maybe TreeItem)
+	-- Will adjusting a given tree always yield the same adjusted tree?
+	, adjustmentIsStable :: Adjustment -> Bool
+	}
diff --git a/Types/AdjustedBranch.hs b/Types/AdjustedBranch.hs
--- 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 @@
 	= LinkAdjustment LinkAdjustment
 	| PresenceAdjustment PresenceAdjustment (Maybe LinkAdjustment)
 	| LockUnlockPresentAdjustment LockUnlockPresentAdjustment
+	| WantedAdjustment WantedAdjustment (Maybe LinkAdjustment)
 	deriving (Show, Eq)
 
 data LinkAdjustment
@@ -30,6 +31,11 @@
 	| 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 @@
 		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 @@
 	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/Upgrade/V5.hs b/Upgrade/V5.hs
--- a/Upgrade/V5.hs
+++ b/Upgrade/V5.hs
@@ -31,6 +31,7 @@
 import Git.Ref
 import Utility.InodeCache
 import Annex.AdjustedBranch
+import Annex.AdjustTreeItem
 import qualified Utility.FileIO as F
 
 upgrade :: Bool -> Annex UpgradeResult
@@ -71,7 +72,7 @@
 	{- Create adjusted branch where all files are unlocked.
 	 - This should have the same content for each file as
 	 - have been staged in upgradeDirectWorkTree. -}
-	AdjBranch b <- adjustBranch (LinkAdjustment UnlockAdjustment) cur
+	AdjBranch b <- adjustBranch (LinkAdjustment UnlockAdjustment) getAdjustTreeItem cur
 	{- Since the work tree was already set up by
 	 - upgradeDirectWorkTree, and contains unlocked file
 	 - contents too, don't use git checkout to check out the
diff --git a/git-annex.cabal b/git-annex.cabal
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -1,5 +1,5 @@
 Name: git-annex
-Version: 10.20261006
+Version: 10.20261020
 Cabal-Version: 1.12
 License: AGPL-3
 Maintainer: Joey Hess <id@joeyh.name>
@@ -561,6 +561,7 @@
     Annex.AdjustedBranch
     Annex.AdjustedBranch.Merge
     Annex.AdjustedBranch.Name
+    Annex.AdjustTreeItem
     Annex.AutoMerge
     Annex.Balanced
     Annex.BloomFilter
@@ -1023,6 +1024,7 @@
     Types
     Types.ActionItem
     Types.AdjustedBranch
+    Types.AdjustTreeItem
     Types.Availability
     Types.Backend
     Types.Benchmark
