Recent changes to this wiki:

comment
diff --git a/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_4_49ad0811cab9f1565528b202c6b0d953._comment b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_4_49ad0811cab9f1565528b202c6b0d953._comment
new file mode 100644
index 0000000000..b97a49c0ab
--- /dev/null
+++ b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_4_49ad0811cab9f1565528b202c6b0d953._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""Re: annex-security-allow-unverified-downloads"""
+ date="2026-06-12T15:16:21Z"
+ content="""
+The reason downloading from the web special remote with just an URL key is
+allowed is because it avoids the specific security holes that
+annex-security-allow-unverified-downloads was added to deal with.
+"""]]

comment
diff --git a/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_3_cd276dcc85b3793e3b0bc2367e6081cf._comment b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_3_cd276dcc85b3793e3b0bc2367e6081cf._comment
new file mode 100644
index 0000000000..285ed740a3
--- /dev/null
+++ b/doc/bugs/migrate_removes_associated_URLs_with_custom_scheme/comment_3_cd276dcc85b3793e3b0bc2367e6081cf._comment
@@ -0,0 +1,24 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2026-06-12T15:01:37Z"
+ content="""
+The urls are actually being copied to the new key. But `whereis` only displays
+an url when it's located in a remote that contains a key. After the migration,
+git-annex does not think that your special remote contains the new key,
+so it does not display urls that are claimed by that special remote.
+
+For the web, there is a special case that handles this, recording that the
+new key is present in the web special remote. (setUrlPresent does it)
+
+I don't think it makes sense to make that be done for other types of
+special remotes generally. Consider that `git-annex get`
+would request the special remote get the new key. If the special remote
+is a key/value store, the new key is not located on it, so the get would
+fail. Similarly, `git-annex fsck --from specialremote` would detect a
+problem.
+
+Maybe there are other special remotes that are also url based in a way that
+it would make sense to update the location log when migrating a key.
+The bittorrent special remote comes to mind.
+"""]]

fixed earlier
diff --git a/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn
index ec02c06846..041623ecbb 100644
--- a/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn
+++ b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests.mdwn
@@ -83,3 +83,5 @@ icg149@icg1911:~/Playground/c1$ curl --head http://localhost:54321/git-annex/df5
 
 
 [[!tag projects/INM7]]
+
+> [[done]] --[[Joey]]

close old polls
being botspammed
diff --git a/doc/design/assistant/polls/goals_for_April.mdwn b/doc/design/assistant/polls/goals_for_April.mdwn
index 53132dd441..dc0e6a3d7a 100644
--- a/doc/design/assistant/polls/goals_for_April.mdwn
+++ b/doc/design/assistant/polls/goals_for_April.mdwn
@@ -3,7 +3,7 @@ features done in a month if I'm lucky. I have only 3 more funded months,
 and parts of one will be spent working on porting to Windows, so choose wisely!
 --[[Joey]]
 
-[[!poll open=yes expandable=yes 4 "upload and download rate limiting" 15 "get webapp working on Android" 5 "deltas: speed up syncing modified versions of existing files" 8 "encrypted git remotes using git-remote-gcrypt" 0 "add support for more cloud storage remotes" 19 "don't work on features, work on making it easier to install and use" 2 "Handle duplicate files" 6 "direct mode (aka real files instead of symlinks) [already done --joey]" 3 "start windows port now"]]
+[[!poll open=no expandable=yes 4 "upload and download rate limiting" 15 "get webapp working on Android" 5 "deltas: speed up syncing modified versions of existing files" 8 "encrypted git remotes using git-remote-gcrypt" 0 "add support for more cloud storage remotes" 19 "don't work on features, work on making it easier to install and use" 2 "Handle duplicate files" 6 "direct mode (aka real files instead of symlinks) [already done --joey]" 3 "start windows port now"]]
 
 References:
 
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 91fcb1e274..34ae925bee 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=no 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

close
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn b/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn
index f87496718d..2884e49447 100644
--- a/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content.mdwn
@@ -53,3 +53,9 @@ NixOS 21.11
 
 
 [[!meta title="cryptonite does not use SHA instructions for sha256"]]
+
+> git-annex can now be built with the Botan build flag, which accellerates
+> SHA3 and also some other hashing. It will take a while for all builds
+> to have it, since the C++ library needs to be installed separately
+> from other dependencies. There is a build warning when building without
+> botab. [[done]] --[[Joey]]

correction
diff --git a/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
index bfdc2c44d9..e7f1f8b7d6 100644
--- a/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
+++ b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
@@ -3,7 +3,8 @@
  subject="""comment 6"""
  date="2026-06-09T19:44:56Z"
  content="""
-Another route might be to use botan, which supports blake3.
+Another route might be to use botan, once it supports blake3.
+
 There is some work toward using botan in
 [[git-annex_is_slow_at_reading_file_content]]
 and once it's used, adding blake3 would just be adding another hash.
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
index f1e206356c..9b7493afb9 100644
--- a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
@@ -3,6 +3,6 @@
  subject="""comment 15"""
  date="2026-06-09T19:46:55Z"
  content="""
-botan includes the blake3 hash, so [[blake3_hash_support]] could happen
+Once botan includes the blake3 hash, [[blake3_hash_support]] could happen
 more or less for free..
 """]]

comment
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
new file mode 100644
index 0000000000..f1e206356c
--- /dev/null
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_15_6b7596c7a54c9d6d014998ec31478840._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 15"""
+ date="2026-06-09T19:46:55Z"
+ content="""
+botan includes the blake3 hash, so [[blake3_hash_support]] could happen
+more or less for free..
+"""]]

botan
diff --git a/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
new file mode 100644
index 0000000000..bfdc2c44d9
--- /dev/null
+++ b/doc/bugs/blake3_hash_support/comment_6_86c121634d68400fffccd630dbce0b76._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2026-06-09T19:44:56Z"
+ content="""
+Another route might be to use botan, which supports blake3.
+There is some work toward using botan in
+[[git-annex_is_slow_at_reading_file_content]]
+and once it's used, adding blake3 would just be adding another hash.
+"""]]

comment
diff --git a/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_14_badb9dcd455bf56a43c0035894084631._comment b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_14_badb9dcd455bf56a43c0035894084631._comment
new file mode 100644
index 0000000000..e5e6cf0d3b
--- /dev/null
+++ b/doc/bugs/git-annex_is_slow_at_reading_file_content/comment_14_badb9dcd455bf56a43c0035894084631._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 14"""
+ date="2026-06-09T19:34:42Z"
+ content="""
+Botan3 can also accellerate sha1 and sha3 (on machines with AVX-512).
+<https://botan.randombit.net/handbook/hardware_acceleration.html>
+
+I think it would make sense at this point to have a botan build flag
+that uses botan for all hashing. It may be that it's faster at other
+hashes than crypton too.
+
+The build flag would need to not be default, since it needs the C++ library
+to be installed. They seem to be moving toward vendoring the C++ library
+in the haskell package:
+<https://github.com/haskell-cryptography/botan/issues/98>
+At which point the build flag could become the default.
+
+I have some early work toward this in the `botan` branch. A proof of
+concept implementation for SHA256 keys benchmarked roughly  
+twice as fast on my laptop.
+"""]]

done
diff --git a/doc/todo/avoid_uncessary_synced_branches.mdwn b/doc/todo/avoid_uncessary_synced_branches.mdwn
index 9158ee8a9b..c0060a170f 100644
--- a/doc/todo/avoid_uncessary_synced_branches.mdwn
+++ b/doc/todo/avoid_uncessary_synced_branches.mdwn
@@ -14,3 +14,7 @@ distributed mode. Once those are merged, it should be deleted.
 And a bare repository should never have a synced/master branch.
 
 (synced/git-annex is another matter, and is fine as it is) --[[Joey]]
+
+> [[done]] --[[Joey]]
+
+[[!tag projects/INM7]]

reduce synced/ branch clutter in centralized git repo workflow
Avoid pushing synced/master branch when a remote accepts a push of
master.
Avoid creating a local synced/master branch when git-annex sync (or
related commands) is run.
Some code that assumed the existance of the local synced/master branch
had to be fixed.
This is to simplify workflows with centralized git repos, where a branch
might get rebased or rewound and force pushed. The existence of
synced/master (etc) branches complicates that because the user has to
clean them up.
This will mean that a decentralized situation, where pushes are to
non-bare git repos that don't allow updating their master, will
need a different workflow for such forced pushes. But, in a
decentralized situation, it's harder to rewrite history anyway.
So a difference in workflow is ok.
synced/git-annex is not affected.
diff --git a/CHANGELOG b/CHANGELOG
index 98636bc58e..d67b0b8930 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,9 @@
 git-annex (10.20260602) UNRELEASED; urgency=medium
 
+  * Improve handling of synced/master and similar branches, by
+    only creating such branches when necessary to push to a non-bare
+    remote, and by removing the local synced branch once its changes
+    are merged.
   * put: New command.
   * move: Fix bug where an interrupted command other than move could
     be treated as an interrupted move, resulting in dropping content
diff --git a/Command/Sync.hs b/Command/Sync.hs
index b7332bcf16..b545c8cdd0 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -518,9 +518,6 @@ updateBranches forpull forpush (Just branch, madj) = do
 				when forpull $
 					updateadjustedbranch adj
 			Nothing -> noop
-	
-	-- Update the sync branch to match the new state of the branch
-	inRepo $ updateBranch (syncBranch branch) (fromViewBranch branch)
   where
 	-- The adjusted branch may need to be updated, if the adjustment
 	-- is not stable, and the usual configuration does not update it.
@@ -635,7 +632,7 @@ pullThirdPartyPopulated o remote
 	
 	wantpull = remoteAnnexPull (Remote.gitconfig remote)
 
-{- The remote probably has both a master and a synced/master branch.
+{- The remote often has both a master and a synced/master branch.
  - Which to merge from? Well, the master has whatever latest changes
  - were committed (or pushed changes, if this is a bare remote),
  - while the synced/master may have changes that some
@@ -646,20 +643,22 @@ mergeRemote remote currbranch mergeconfig o = ifM isBareRepo
 	, case currbranch of
 		(Nothing, _) -> do
 			branch <- inRepo Git.Branch.currentUnsafe
-			mergelisted (pure (branchlist branch))
-		(Just branch, _) -> do
-			inRepo $ updateBranch (syncBranch branch) branch
-			mergelisted (tomerge (branchlist (Just branch)))
+			domerge =<< branchlist branch
+		(Just branch, _) ->
+			domerge
+				=<< changedfrom branch
+				=<< branchlist (Just branch)
 	)
   where
-	mergelisted getlist =
-		merge currbranch mergeconfig o Git.Branch.ManualCommit
-			=<< map (remoteBranch remote) <$> getlist
-	tomerge = filterM (changed remote)
-	branchlist Nothing = []
+	domerge = merge currbranch mergeconfig o Git.Branch.ManualCommit
+	changedfrom branch = filterM (inRepo . Git.Branch.changed branch)
+	branchlist Nothing = pure []
 	branchlist (Just branch)
-		| is_branchView branch = []
-		| otherwise = [origBranch branch, syncBranch branch]
+		| is_branchView branch = pure []
+		| otherwise = filterM (inRepo . Git.Ref.exists)
+			[ remoteBranch remote (origBranch branch)
+			, remoteBranch remote (syncBranch branch)
+			]
 
 pushRemote :: SyncOptions -> Remote -> CurrBranch -> CommandStart
 pushRemote _o _remote (Nothing, _) = stop
@@ -685,9 +684,14 @@ pushRemote o remote (Just branch, _) = do
 	needpush mainbranch
 		| remoteAnnexReadOnly gc = return False
 		| not (remoteAnnexPush gc) = return False
-		| otherwise = anyM (newer remote) $ catMaybes
-			[ syncBranch <$> mainbranch
-			, Just (Annex.Branch.name)
+		| otherwise = anyM id $ concat
+			[ case mainbranch of
+				Just b ->
+					[ newer remote b b True
+					, newer remote (syncBranch b) b False
+					]
+				Nothing -> []
+			, [ newer remote Annex.Branch.name Annex.Branch.name True ]
 			]
 	-- Older remotes on crippled filesystems may not have a
 	-- post-receive hook set up, so when updateInstead emulation
@@ -716,7 +720,7 @@ pushRemote o remote (Just branch, _) = do
  - 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 generally fail (except with receive.denyCurrentBranch=updateInstead),
- - and this is why we push to its syncBranch.
+ - and this is when it's useful to push to its syncBranch.
  -
  - Git offers no way to tell if a remote is bare or not, so both methods
  - are tried.
@@ -725,8 +729,9 @@ pushRemote o remote (Just branch, _) = do
  - github may treat the first branch pushed to a new repository as the
  - default branch for that repository.
  -
- - The sync push first sends the synced/master branch,
- - and then forces the update of the remote synced/git-annex branch.
+ - The sync push first sends the synced/master branch
+ - (when the direct push failed), and then forces the update of 
+ - the remote synced/git-annex branch.
  -
  - The forcing is necessary if a transition has rewritten the git-annex branch.
  - Normally any changes to the git-annex branch get pulled and merged before
@@ -755,16 +760,18 @@ pushBranch remote mbranch ms g = do
 				pushparams True
 					[ Git.fromRef $ Git.Ref.base $ origBranch branch ]
 			let p' = p { std_err = CreatePipe }
-			bracket (createProcess p') cleanupProcess $ \h -> do
+			exitcode <- bracket (createProcess p') cleanupProcess $ \h -> do
 				filterstderr [] (stderrHandle h) (processHandle h)
-				void $ waitForProcess (processHandle h)
-			return True
-		Nothing -> return False
-				
-	syncpush directpushed =  do
+				waitForProcess (processHandle h)
+			return (True, exitcode == ExitSuccess)
+		Nothing -> return (False, False)
+	
+	syncpush (directpushed, directbranchupdated) =  do
 		let p = flip Git.Command.gitCreateProcess g $
 			pushparams (not directpushed) $ catMaybes
-				[ (syncrefspec . origBranch) <$> mbranch
+				[ if not directbranchupdated
+					then (syncrefspec . origBranch) <$> mbranch
+					else Nothing
 				, Just $ Git.Branch.forcePush $ syncrefspec Annex.Branch.name
 				]
 		-- stderr is relayed through a pipe so that the push
@@ -832,20 +839,12 @@ mergeAnnex = do
 	void Annex.Branch.forceUpdate
 	stop
 
-changed :: Remote -> Git.Ref -> Annex Bool
-changed remote b = do
-	let r = remoteBranch remote b
-	ifM (inRepo $ Git.Ref.exists r)
-		( inRepo $ Git.Branch.changed b r
-		, return False
-		)
-
-newer :: Remote -> Git.Ref -> Annex Bool
-newer remote b = do
-	let r = remoteBranch remote b
+newer :: Remote -> Git.Ref -> Git.Ref -> Bool -> Annex Bool
+newer remote rb b dne = do
+	let r = remoteBranch remote rb
 	ifM (inRepo $ Git.Ref.exists r)
 		( inRepo $ Git.Branch.changed r b
-		, return True
+		, return dne
 		)
 
 {- Without --all, only looks at files in the work tree.
diff --git a/doc/git-annex-push.mdwn b/doc/git-annex-push.mdwn
index 6a1509a86e..886cf4ae6a 100644
--- a/doc/git-annex-push.mdwn
+++ b/doc/git-annex-push.mdwn
@@ -20,10 +20,8 @@ it's helpful to add remotes for nearby machines that you want
 to access the same annexed content. Pushing to a non-bare remote will
 not normally update the remote's current branch with changes from the local
 repository. (Unless the remote is configured with
-receive.denyCurrentBranch=updateInstead.)
-
-To make working with such non-bare remotes easier, this command pushes not
-only local `master` to remote `master`, but also to remote `synced/master`
+receive.denyCurrentBranch=updateInstead.) Instead, when it detects
+such a remote, this command pushes to the remote's `synced/master`
 (and similar with other branches). When `git-annex pull` (or `git-annex
 sync`) is later run on the remote, it will merge the `synced/` branches
 that were pushed to it.
@@ -118,14 +116,6 @@ See [[git-annex-preferred-content]](1).
   and pushed by `git-annex push` or `git-annex sync`. This option
   prevents all other activities.
 
-  This can come in handy when you've pushed a change to remotes and now
-  want to reset your master branch back before that change. So you
-  run `git reset` and force-push the master branch to remotes, only
-  to find that the next `git annex merge` or `git annex pull` brings the
-  changes back. Why? Because the `synced/master` branch is hanging
-  around and still has the change in it. Cleaning up the `synced/` branches
-  prevents that problem.
-
 * Also the [[git-annex-common-options]](1) can be used.
 
 # SEE ALSO
diff --git a/doc/sync.mdwn b/doc/sync.mdwn
index 2caae47c43..7b17ab5edf 100644
--- a/doc/sync.mdwn
+++ b/doc/sync.mdwn
@@ -20,8 +20,10 @@ When you run `git annex sync`, it merges the `synced/master` branch
 into `master`, receiving anything that's been pushed to it. (If there is a
 conflict in this merge, [[automatic_conflict_resolution]] is used to

(Diff truncated)
todo
diff --git a/doc/todo/avoid_uncessary_synced_branches.mdwn b/doc/todo/avoid_uncessary_synced_branches.mdwn
new file mode 100644
index 0000000000..9158ee8a9b
--- /dev/null
+++ b/doc/todo/avoid_uncessary_synced_branches.mdwn
@@ -0,0 +1,16 @@
+Sending synced/master to a bare git remote is unnecessary because master
+can be pushed directly to it.
+
+This would be good to avoid, because the existence of synced branches
+can complicate situations such as a force push of master that
+discards commits from the tip of the branch. In that case, the user needs
+to worry about cleaning up the synced/master branches, on remote and the
+remote tracking branches, and the local synced/master branch, 
+to avoid them getting merged back in.
+
+Ideally the local synced/master branch should only exist when there are
+un-merged changes that have been pushed from another repository in
+distributed mode. Once those are merged, it should be deleted.
+And a bare repository should never have a synced/master branch.
+
+(synced/git-annex is another matter, and is fine as it is) --[[Joey]]

remove out of date para about --content
diff --git a/doc/sync.mdwn b/doc/sync.mdwn
index eb86133f46..2caae47c43 100644
--- a/doc/sync.mdwn
+++ b/doc/sync.mdwn
@@ -40,10 +40,4 @@ The workflow for using `git annex sync` is simple:
 * Next time you're working on a different clone of that repository,
   run `git annex sync` to update it.
 
-Note that by default, `git annex sync` only synchronises the git
-repositories, but does not transfer the content of annexed files. If you
-want to fully synchronise two repositories content,
-you can use `git annex sync --content`. You can also configure
-[[preferred_content]] settings to make only some content be synced.
-
 See [[git-annex-sync]] for the command's man page.

document --force
diff --git a/doc/git-annex-adjust.mdwn b/doc/git-annex-adjust.mdwn
index bd2964779d..eccdf843cf 100644
--- a/doc/git-annex-adjust.mdwn
+++ b/doc/git-annex-adjust.mdwn
@@ -119,6 +119,16 @@ 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.
 
+* `--force`
+
+  Allow overwriting an existing adjusted branch with a new version.
+
+  For example, suppose you started with branch foo checked out
+  and used  `git-annex adjust --unlock`. But then foo was rebased,
+  and you checked out that new version of foo. Running `git-annex adjust
+  --unlock` again would fail because of the existing adjusted branch.
+  Using `--force` would overwrite that adjusted branch.
+
 * Also the [[git-annex-common-options]](1) can be used.
 
 # SEE ALSO

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..91fcb1e274 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

add
diff --git a/doc/security/p2phttp_denial_of_service.mdwn b/doc/security/p2phttp_denial_of_service.mdwn
new file mode 100644
index 0000000000..b8720a46bd
--- /dev/null
+++ b/doc/security/p2phttp_denial_of_service.mdwn
@@ -0,0 +1,9 @@
+The `git-annex p2phttp` server could be caused to hang by a simple HEAD
+request to it. This denial of service attack was fixed in version
+10.20260525.
+
+Before version 10.20251114, `p2phttp` had several other bugs that could
+cause it to stall. That version also fixed a file descriptor leak.
+
+Since p2phttp is still somewhat new, and the impact is only a DOS,
+no CVEs were assigned for these.

update
diff --git a/doc/thanks/list b/doc/thanks/list
index 0e8eb59c97..22e43a3de4 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -130,3 +130,4 @@ joshingly,
 Melody Tolly, 
 username, 
 Steffen Vogel, 
+Jan, 

Revert "update"
This reverts commit 2afeeebc41d447ad6f51d662ec9b3662f21c5c95.
script broken
diff --git a/doc/thanks/list b/doc/thanks/list
index 50f233b5ca..0e8eb59c97 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -130,101 +130,3 @@ joshingly,
 Melody Tolly, 
 username, 
 Steffen Vogel, 
-AlexS, 
-Amitai Schleier, 
-Andrew, 
-anon, 
-Anthony DeRobertis, 
-Anton Grensjö, 
-Anton Y, 
-Art S, 
-Arthur Lutz, 
-Ben, 
-Boyd Stephen Smith, 
-Bruno BEAUFILS, 
-Caleb Allen, 
-Calvin Beck, 
-Chris Lamb, 
-Christian Diller, 
-Christopher Baines, 
-Christopher Goes, 
-Dave Pifke, 
-don haraway, 
-DuncanConstruction, 
-encryptio, 
-Eric Drechsel, 
-ers35, 
-Evgeni Ku, 
-Farran, 
-Fernando Jimenez, 
-fiatjaf, 
-Francois Marier, 
-Gabriel Lee, 
-Greg Grossmeier, 
-HeartBreak KB Official, 
-Ignacio, 
-Ilya Baryshnikov, 
-James (purpleidea), 
-James Valleroy, 
-Jan, 
-Jason Woofenden, 
-Jeff Goeke-Smith, 
-Jim, 
-Jo, 
-Johannes Schlatow, 
-John Peloquin, 
-Jon D, 
-jose_d, 
-Josh Taylor, 
-Josh Tilles, 
-Lacnic, 
-Land Reaver, 
-Lee Hinman, 
-Lee-kai Wang, 
-Lukas Scheel-Platz, 
-Lukas Waymann, 
-Madison McGaffin, 
-Maggie Hess, 
-Matthew Willcockson, 
-Matthias Urlichs, 
-Matthieu, 
-Mattias J, 
-Mica, 
-Michal Politowski, 
-Mika Pflüger, 
-mo, 
-Mohit Munjani, 
-Nahum Shalman, 
-NinjaTrappeur, 
-Ole-Morten Duesund, 
-Paul Tötterman, 
-Pedro Luz, 
-Pig Monkey, 
-Renaud Casenave-Péré, 
-rjbl, 
-Ryan Newton, 
-Rémi Vanicat, 
-Sergey Karpukhin, 
-Shane-o, 
-Shawn Butts, 
-Stan Yamane, 
-Stephan Burkhardt, 
-Stephan Meister, 
-SvenDowideit, 
-sww, 
-Teremu HAMBLIN, 
-Thom May, 
-Thomas Ferris Nicolaisen, 
-Thomas Hochstein, 
-Thomas Schwinge, 
-Tim Howes, 
-tj, 
-Trent Lloyd, 
-Tyler Cipriani, 
-Valeria_, 
-Walltime, 
-wawatcz, 
-Will Hughes, 
-Willard Korfhage, 
-wzhd, 
-Zoé Cassiopée Gauthier, 

update
diff --git a/doc/thanks/list b/doc/thanks/list
index 0e8eb59c97..50f233b5ca 100644
--- a/doc/thanks/list
+++ b/doc/thanks/list
@@ -130,3 +130,101 @@ joshingly,
 Melody Tolly, 
 username, 
 Steffen Vogel, 
+AlexS, 
+Amitai Schleier, 
+Andrew, 
+anon, 
+Anthony DeRobertis, 
+Anton Grensjö, 
+Anton Y, 
+Art S, 
+Arthur Lutz, 
+Ben, 
+Boyd Stephen Smith, 
+Bruno BEAUFILS, 
+Caleb Allen, 
+Calvin Beck, 
+Chris Lamb, 
+Christian Diller, 
+Christopher Baines, 
+Christopher Goes, 
+Dave Pifke, 
+don haraway, 
+DuncanConstruction, 
+encryptio, 
+Eric Drechsel, 
+ers35, 
+Evgeni Ku, 
+Farran, 
+Fernando Jimenez, 
+fiatjaf, 
+Francois Marier, 
+Gabriel Lee, 
+Greg Grossmeier, 
+HeartBreak KB Official, 
+Ignacio, 
+Ilya Baryshnikov, 
+James (purpleidea), 
+James Valleroy, 
+Jan, 
+Jason Woofenden, 
+Jeff Goeke-Smith, 
+Jim, 
+Jo, 
+Johannes Schlatow, 
+John Peloquin, 
+Jon D, 
+jose_d, 
+Josh Taylor, 
+Josh Tilles, 
+Lacnic, 
+Land Reaver, 
+Lee Hinman, 
+Lee-kai Wang, 
+Lukas Scheel-Platz, 
+Lukas Waymann, 
+Madison McGaffin, 
+Maggie Hess, 
+Matthew Willcockson, 
+Matthias Urlichs, 
+Matthieu, 
+Mattias J, 
+Mica, 
+Michal Politowski, 
+Mika Pflüger, 
+mo, 
+Mohit Munjani, 
+Nahum Shalman, 
+NinjaTrappeur, 
+Ole-Morten Duesund, 
+Paul Tötterman, 
+Pedro Luz, 
+Pig Monkey, 
+Renaud Casenave-Péré, 
+rjbl, 
+Ryan Newton, 
+Rémi Vanicat, 
+Sergey Karpukhin, 
+Shane-o, 
+Shawn Butts, 
+Stan Yamane, 
+Stephan Burkhardt, 
+Stephan Meister, 
+SvenDowideit, 
+sww, 
+Teremu HAMBLIN, 
+Thom May, 
+Thomas Ferris Nicolaisen, 
+Thomas Hochstein, 
+Thomas Schwinge, 
+Tim Howes, 
+tj, 
+Trent Lloyd, 
+Tyler Cipriani, 
+Valeria_, 
+Walltime, 
+wawatcz, 
+Will Hughes, 
+Willard Korfhage, 
+wzhd, 
+Zoé Cassiopée Gauthier, 

close
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn b/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn
index 4e18897297..ed8c677093 100644
--- a/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull.mdwn
@@ -1,3 +1,6 @@
 The pull and push commands do not have --json-progress support.  Please add.
 
 [[!tag projects/INM7]]
+
+> [[wontfix|done]] but see my comment at the end for alternatives.
+> --[[Joey]]

update my comment
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
index 2bdeacf1cb..a19ac50449 100644
--- a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
@@ -1,46 +1,53 @@
 [[!comment format=mdwn
  username="joey"
  subject="""comment 10"""
- date="2026-05-29T13:59:25Z"
+ date="2026-06-04T13:59:25Z"
  content="""
-Summarizing the current status of this todo, if someone wants 
-the equivilant of `git-annex pull --json $someremote`, they can run:
+I have done some work adjacent to this todo, implmenting a `--wanted`
+option and `git-annex put` command.
+
+Now, if someone wants  the equivilant of `git-annex pull --json
+$someremote`, they can run:
 
 	git-annex pull --no-content $someremote
-	git-annex get --auto --json --from $someremote
-	git-annex drop --auto --json
+	git-annex get --wanted --json --from $someremote
+	git-annex drop --wanted --json
 
-The first command above does not have json output, but outputs the
+The `git-annex pull` above does not have json output, but outputs the
 usual `git pull` messages for the user to deal with as they see fit.
 
 And, if someone wants the equivilant of `git-annex push --json
 $someremote`, they can run:
 
-	git-annex copy --auto --json --to $someremote
-	git-annex drop --auto --json --from $someremote
+	git-annex copy --wanted --json --to $someremote
+	git-annex drop --wanted --json --from $someremote
 	git-annex push --no-content $someremote
 
-The last command above does not have json output, but outputs the
+The `git-annex push` above does not have json output, but outputs the
 usual `git push` messages for the user to deal with as they see fit.
 
-The argument for adding --json to pull/push now seems to be reduced.
-But not gone entirely I suppose. 
-
-For example, `git-annex push` without
-a remote pushes content to all remotes that want it. That needs
-multiple runs of `git-annex copy`, one per remote. Notice that
-in the `git-annex pull` case, it can be made to operate on all remotes:
+Similarly, the equivilant of `git-annex pull --json` with no remote
+specified:
 
 	git-annex pull --no-content
-	git-annex get --auto --json
-	git-annex drop --auto --json
+	git-annex get --wanted --json
+	git-annex drop --wanted --json
+
+And, the equivilant of `git-annex push` without a remote specified:
+
+	git-annex put --wanted --json
+	git-annex drop --wanted --json
+	git-annex push --no-content
+
+So, the argument for adding --json to pull/push now seems to be reduced.
+Here are all the arguments I can think of for still doing that:
 
-This seems like an argument for adding a `git-annex put`
-command that copies to all remotes that want content. Which is nicely
-symmetric with `git-annex get`.
+* These command sequences won't behave completely identically to pull/push
+  in all configurations, eg they don't look at `remote.<name>.annex-pull`
+  and `remote.<name>.annex-push` configs.
 
-Another difference is that a single `git-annex push` or `pull`
-(or `sync`) does less work than several git-annex commands.
-In the scripts above, git-annex has to traverse the tree twice.
-That is a pretty small difference in overhead.
+* A single `git-annex push` or `pull` (or `sync`) does less work than several
+  git-annex commands. In the command sequences above, git-annex has to
+  traverse the tree twice. That is a pretty small difference in overhead
+  though most of the time.
 """]]
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
deleted file mode 100644
index 727dd711d3..0000000000
--- a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
+++ /dev/null
@@ -1,17 +0,0 @@
-[[!comment format=mdwn
- username="joey"
- subject="""comment 11"""
- date="2026-05-29T15:09:31Z"
- content="""
-Hmm, `git-annex get --auto` and `git-annex copy --auto` don't just check
-preferred content, they will also make a copy if numcopies is not satisfied
-for the file.
-
-That's something that `git-annex pull` and `git-annex push` don't do.
-
-I think it would be a good idea to add a `--wanted` option to commands
-that support `--auto`. It would only operate on preferred content, avoiding
-making copies only to work toward satisfying numcopies.
-
-Update: Added `--wanted`
-"""]]

decided this is not actually a bug
diff --git a/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn b/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
index 6458160415..e4da8e7d3f 100644
--- a/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
+++ b/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
@@ -1,4 +1,29 @@
 `git-annex put -J2` with the same file needing to go to 2 remotes only runs
-1 transfer at a time. Same with `git-annex push -J2`.
+1 transfer at a time. Same with `git-annex push -J2` and `git-annex copy
+-J2`.
 
 This is because of the use of OnlyActionOn. --[[Joey]]
+
+> That is the thing that prevents it, but there is a good reason for it to
+> be prevented in some cases. Consider `git-annex copy -J2 --auto`, where
+> there are 2 archive remotes. It should only send to 1 of them, not
+> to both. And if the first one it tries to send to fails, it ought to
+> send to the other one. So the second thread needs to block waiting on the
+> first thread and check again if the action ought to be run. Which is what
+> OnlyActionOn does.
+> 
+> So this seems to only make sense to do if preferred content is not being
+> checked, or if the remote does not have a preferred content expression,
+> or if the preferred content expression does not use "copies=" or
+> similar.
+> 
+> Also, this doesn't fully serialize eg `put -J2`, as long as there are
+> several files to put. The 1st file will be sent to the 1st remote
+> and concurrently the 2nd file to the 2nd remote, and once those transfers
+> complete it will move on to sending the 1st file to the 2nd remote and
+> the 2nd file to the 1st remote.
+> 
+> Is it worth supporting this where it can be supported? It might seem
+> like inconsistent behavior.
+> 
+> I think not. [[done]] --[[Joey]]

typo
diff --git a/doc/git-annex-put.mdwn b/doc/git-annex-put.mdwn
index 831fa146b1..13eb06515c 100644
--- a/doc/git-annex-put.mdwn
+++ b/doc/git-annex-put.mdwn
@@ -25,7 +25,7 @@ Paths of files or directories to operate on can be specified.
 * `--auto`
 
   Only send files to remotes that want them, or when there are not
-  yet have the desired number of copies.
+  yet the desired number of copies.
 
 * `--fast`
 

this is a bug
diff --git a/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn b/doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn
similarity index 100%
rename from doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn
rename to doc/bugs/push_and_put_-J_OnlyActionOn_problem.mdwn

fix todo
diff --git a/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn b/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn
new file mode 100644
index 0000000000..6458160415
--- /dev/null
+++ b/doc/todo/push_and_put_-J_OnlyActionOn_problem.mdwn
@@ -0,0 +1,4 @@
+`git-annex put -J2` with the same file needing to go to 2 remotes only runs
+1 transfer at a time. Same with `git-annex push -J2`.
+
+This is because of the use of OnlyActionOn. --[[Joey]]
diff --git a/doc/todo/put_--json_lacks_uuid.mdwn b/doc/todo/put_--json_lacks_uuid.mdwn
index 387a780f6f..f60e04fac1 100644
--- a/doc/todo/put_--json_lacks_uuid.mdwn
+++ b/doc/todo/put_--json_lacks_uuid.mdwn
@@ -1,2 +1,4 @@
 `git annex put --json` does not include the uuid of the remote that content
 is sent to. It ought to, since it can send to multiple remotes. --[[Joey]]
+
+> [[fixed|done]] --[[Joey]]
diff --git a/doc/todo/put_-J_OnlyActionOn_problem.mdwn b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
deleted file mode 100644
index b4f189c485..0000000000
--- a/doc/todo/put_-J_OnlyActionOn_problem.mdwn
+++ /dev/null
@@ -1,5 +0,0 @@
-`git-annex put -J2` with the same file needing to go to 2 remotes only runs
-1 transfer at a time. This is because of the use of OnlyActionOn in
-Command.Move. --[[Joey]]
-
-[[fixed|done]] --[[Joey]] 

include uuid in put --json
diff --git a/Command/Copy.hs b/Command/Copy.hs
index bbc08fda04..247584327b 100644
--- a/Command/Copy.hs
+++ b/Command/Copy.hs
@@ -64,16 +64,16 @@ seek' o fto = startConcurrency (Command.Move.stages fto) $ do
 	case batchOption o of
 		NoBatch -> withKeyOptions
 			(keyOptions o) (autoMode o || wantedMode o) seeker
-			(commandAction . startKey o fto)
+			(commandAction . startKey o fto id)
 			(withFilesInGitAnnex ww seeker)
 			=<< workTreeItems ww (copyFiles o)
 		Batch fmt -> batchOnly (keyOptions o) (copyFiles o) $
-			batchAnnexed fmt seeker (startKey o fto)
+			batchAnnexed fmt seeker (startKey o fto id)
   where
 	ww = WarnUnmatchLsFiles "copy"
 	
 	seeker = AnnexedFileSeeker
-		{ startAction = startSingle $ const $ start o fto
+		{ startAction = startSingle $ const $ start o fto id
 		, checkContentPresent = case fto of
 			FromOrToRemote (FromRemote _) -> Just False
 			FromOrToRemote (ToRemote _) -> Just True
@@ -86,8 +86,15 @@ seek' o fto = startConcurrency (Command.Move.stages fto) $ do
 {- A copy is just a move that does not delete the source file.
  - However, auto mode avoids unnecessary copies, and avoids getting or
  - sending non-preferred content. -}
-start :: CopyOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
-start o fto si file key = do
+start
+	:: CopyOptions
+	-> FromToHereOptions
+	-> (ActionItem -> ActionItem)
+	-> SeekInput
+	-> OsPath
+	-> Key
+	-> CommandStart
+start o fto fai si file key = do
 	ru <- case fto of
 		FromOrToRemote (ToRemote dest) -> getru dest
 		FromOrToRemote (FromRemote _) -> pure Nothing
@@ -95,13 +102,26 @@ start o fto si file key = do
 		FromRemoteToRemote _ dest -> getru dest
 		FromAnywhereToRemote dest -> getru dest
 	lu <- prepareLiveUpdate ru key AddingKey
-	start' lu o fto si file key
+
+	start' lu o fto afile si file key ai
   where
 	getru dest = Just . Remote.uuid <$> getParsed dest
+	
+	afile = AssociatedFile (Just file)
+	ai = fai $ mkActionItem (key, afile)
 
-start' :: LiveUpdate -> CopyOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
-start' lu o fto si file key = stopUnless shouldCopy $ 
-	Command.Move.start lu fto (moveAction o) si file key
+start'
+	:: LiveUpdate
+	-> CopyOptions
+	-> FromToHereOptions
+	-> AssociatedFile
+	-> SeekInput
+	-> OsPath
+	-> Key
+	-> ActionItem
+	-> CommandStart
+start' lu o fto afile si file key ai = stopUnless shouldCopy $ 
+	Command.Move.start' lu fto (moveAction o) afile si key ai
   where
 	shouldCopy
 		| autoMode o = want <||> numCopiesCheck file key (<)
@@ -119,5 +139,11 @@ start' lu o fto si file key = stopUnless shouldCopy $
 			wantGetBy lu False (Just key) (AssociatedFile (Just file))
 	checkwantget = wantGet lu False (Just key) (AssociatedFile (Just file))
 
-startKey :: CopyOptions -> FromToHereOptions -> (SeekInput, Key, ActionItem) -> CommandStart
-startKey o fto = Command.Move.startKey NoLiveUpdate fto (moveAction o)
+startKey
+	:: CopyOptions
+	-> FromToHereOptions
+	-> (ActionItem -> ActionItem)
+	-> (SeekInput, Key, ActionItem)
+	-> CommandStart
+startKey o fto fai (si, k, ai) = 
+	Command.Move.startKey NoLiveUpdate fto (moveAction o) (si, k, fai ai)
diff --git a/Command/Put.hs b/Command/Put.hs
index ed4b70d256..d32e9b9245 100644
--- a/Command/Put.hs
+++ b/Command/Put.hs
@@ -46,13 +46,13 @@ seek o = startConcurrency commandStages $ do
 	let seeker = AnnexedFileSeeker
 		{ startAction = \_ si p k ->
 			return $ flip map contentremotes $ \r ->
-				Command.Copy.start co (to r) si p k
+				Command.Copy.start co (to r) (fai r) si p k
 		, checkContentPresent = Just True
 		, usesLocationLog = True
 		}
 	let keyaction v = 
 		return $ flip map contentremotes $ \r ->
-			Command.Copy.startKey co (to r) v
+			Command.Copy.startKey co (to r) (fai r) v
 	case batchOption o of
 		NoBatch -> withKeyOptions
 			(keyOptions o) (autoMode o || wantedMode o) seeker
@@ -75,3 +75,9 @@ seek o = startConcurrency commandStages $ do
 		}
 	
 	to = FromOrToRemote . ToRemote . ReadyParse
+
+	-- Since put can send to remotes of its choosing, suppliment the
+	-- ActionItem with the uuid. This makes the json include the remote
+	-- uuid.
+	fai r ai = ActionItemForUUID (Remote.uuid r) ai
+
diff --git a/Types/ActionItem.hs b/Types/ActionItem.hs
index 53e7822a74..84e26b8e2f 100644
--- a/Types/ActionItem.hs
+++ b/Types/ActionItem.hs
@@ -1,6 +1,6 @@
 {- items that a command can act on
  -
- - Copyright 2016-2023 Joey Hess <id@joeyh.name>
+ - Copyright 2016-2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -29,6 +29,7 @@ data ActionItem
 	| ActionItemUUID UUID StringContainingQuotedPath
 	-- ^ UUID with a description or name of the repository
 	| ActionItemOther (Maybe StringContainingQuotedPath)
+	| ActionItemForUUID UUID ActionItem
 	| OnlyActionOn Key ActionItem
 	-- ^ Use to avoid more than one thread concurrently processing the
 	-- same Key.
@@ -85,6 +86,7 @@ actionItemDesc (ActionItemTreeFile f) = QuotedPath f
 actionItemDesc (ActionItemUUID _ desc) = desc
 actionItemDesc (ActionItemOther Nothing) = mempty
 actionItemDesc (ActionItemOther (Just v)) = v
+actionItemDesc (ActionItemForUUID _ ai) = actionItemDesc ai
 actionItemDesc (OnlyActionOn _ ai) = actionItemDesc ai
 
 actionItemKey :: ActionItem -> Maybe Key
@@ -95,21 +97,26 @@ actionItemKey (ActionItemFailedTransfer t _) = Just (transferKey t)
 actionItemKey (ActionItemTreeFile _) = Nothing
 actionItemKey (ActionItemUUID _ _) = Nothing
 actionItemKey (ActionItemOther _) = Nothing
+actionItemKey (ActionItemForUUID _ ai) = actionItemKey ai
 actionItemKey (OnlyActionOn _ ai) = actionItemKey ai
 
 actionItemFile :: ActionItem -> Maybe OsPath
 actionItemFile (ActionItemAssociatedFile (AssociatedFile af) _) = af
 actionItemFile (ActionItemTreeFile f) = Just f
 actionItemFile (ActionItemUUID _ _) = Nothing
+actionItemFile (ActionItemForUUID _ ai) = actionItemFile ai
 actionItemFile (OnlyActionOn _ ai) = actionItemFile ai
 actionItemFile _ = Nothing
 
 actionItemUUID :: ActionItem -> Maybe UUID
 actionItemUUID (ActionItemUUID uuid _) = Just uuid
+actionItemUUID (ActionItemForUUID uuid _) = Just uuid
+actionItemUUID (OnlyActionOn _ ai) = actionItemUUID ai
 actionItemUUID _ = Nothing
 
 actionItemTransferDirection :: ActionItem -> Maybe Direction
 actionItemTransferDirection (ActionItemFailedTransfer t _) = Just $
 	transferDirection t
+actionItemTransferDirection (ActionItemForUUID _ ai) = actionItemTransferDirection ai
 actionItemTransferDirection (OnlyActionOn _ ai) = actionItemTransferDirection ai
 actionItemTransferDirection _ = Nothing
diff --git a/doc/todo/put_-J_OnlyActionOn_problem.mdwn b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
index 88cb783723..b4f189c485 100644
--- a/doc/todo/put_-J_OnlyActionOn_problem.mdwn
+++ b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
@@ -1,3 +1,5 @@
 `git-annex put -J2` with the same file needing to go to 2 remotes only runs
 1 transfer at a time. This is because of the use of OnlyActionOn in
 Command.Move. --[[Joey]]
+
+[[fixed|done]] --[[Joey]] 

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index a92964f743..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Google Drive)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..a92964f743 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 0090d9b91d..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Box.com (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 859324f795..0090d9b91d 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon Glacier (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..859324f795 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index a92964f743..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Google Drive)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..a92964f743 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 0090d9b91d..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Box.com (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 859324f795..0090d9b91d 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon Glacier (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..859324f795 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index a92964f743..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Google Drive)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..a92964f743 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 0090d9b91d..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Box.com (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 859324f795..0090d9b91d 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon Glacier (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..859324f795 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index a92964f743..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Google Drive)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index d1bdb81324..a92964f743 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 38 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (OpenStack SWIFT)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index be9e779b44..d1bdb81324 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 20 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Tahoe-LAFS)
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 05feed7d11..be9e779b44 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 30 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (My phone (or MP3 player))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 0090d9b91d..05feed7d11 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 82 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Box.com (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 859324f795..0090d9b91d 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 11 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon Glacier (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 1e5b6c172f..859324f795 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 18 "Amazon S3 (done)" 14 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

poll vote (Amazon S3 (done))
diff --git a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
index 2c6d62e9c2..1e5b6c172f 100644
--- a/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
+++ b/doc/design/assistant/polls/prioritizing_special_remotes.mdwn
@@ -6,7 +6,7 @@ locally paired systems, and remote servers with rsync.
 Help me prioritize my work: What special remote would you most like
 to use with the git-annex assistant?
 
-[[!poll open=yes 18 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
+[[!poll open=yes 19 "Amazon S3 (done)" 13 "Amazon Glacier (done)" 10 "Box.com (done)" 81 "My phone (or MP3 player)" 29 "Tahoe-LAFS" 19 "OpenStack SWIFT" 37 "Google Drive"]]
 
 This poll is ordered with the options I consider easiest to build
 listed first. Mostly because git-annex already supports them and they

put todos
diff --git a/doc/todo/put_--json_lacks_uuid.mdwn b/doc/todo/put_--json_lacks_uuid.mdwn
new file mode 100644
index 0000000000..387a780f6f
--- /dev/null
+++ b/doc/todo/put_--json_lacks_uuid.mdwn
@@ -0,0 +1,2 @@
+`git annex put --json` does not include the uuid of the remote that content
+is sent to. It ought to, since it can send to multiple remotes. --[[Joey]]
diff --git a/doc/todo/put_-J_OnlyActionOn_problem.mdwn b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
new file mode 100644
index 0000000000..88cb783723
--- /dev/null
+++ b/doc/todo/put_-J_OnlyActionOn_problem.mdwn
@@ -0,0 +1,3 @@
+`git-annex put -J2` with the same file needing to go to 2 remotes only runs
+1 transfer at a time. This is because of the use of OnlyActionOn in
+Command.Move. --[[Joey]]

close
diff --git a/doc/todo/git-annex_put.mdwn b/doc/todo/git-annex_put.mdwn
index ca5a17b55f..449f112e0a 100644
--- a/doc/todo/git-annex_put.mdwn
+++ b/doc/todo/git-annex_put.mdwn
@@ -34,3 +34,5 @@ Another way to look at it is this tower has a missing leg:
 
 
 --[[Joey]]
+
+> [[done]]

put --fast like push --fast
Sponsored-by: Luke T. Shumaker
diff --git a/Command/Put.hs b/Command/Put.hs
index afa2ebbde2..ed4b70d256 100644
--- a/Command/Put.hs
+++ b/Command/Put.hs
@@ -8,6 +8,7 @@
 module Command.Put where
 
 import Command
+import qualified Annex
 import qualified Command.Copy
 import qualified Command.Move (MoveAction(..))
 import qualified Remote
@@ -36,8 +37,11 @@ optParser desc = PutOptions
 
 seek :: PutOptions -> CommandSeek
 seek o = startConcurrency commandStages $ do
+	fast <- Annex.getRead Annex.fast
+	let fastest = fromMaybe [] . headMaybe
 	contentremotes <- filter Remote.canPut
-		. concat . Remote.byCost 
+		. (if fast then fastest else concat)
+		. Remote.byCost 
 		<$> (Remote.contentRemotes =<< Remote.remoteList)
 	let seeker = AnnexedFileSeeker
 		{ startAction = \_ si p k ->
diff --git a/doc/git-annex-put.mdwn b/doc/git-annex-put.mdwn
index 554e705409..831fa146b1 100644
--- a/doc/git-annex-put.mdwn
+++ b/doc/git-annex-put.mdwn
@@ -27,6 +27,10 @@ Paths of files or directories to operate on can be specified.
   Only send files to remotes that want them, or when there are not
   yet have the desired number of copies.
 
+* `--fast`
+
+  Only send files to remotes with the lowest annex-cost value configured.
+
 * `--jobs=N` `-JN`
 
   Enables parallel transfers with up to the specified number of jobs

remove --fast option from put
put, like push, will always trust location logs
The main reason for doing this is that otherwise, put would always
do a lot of work, with ugly verbose output.
But also, best to leave copy --to a special case. It's useful in
some circumstances for copy to have a way to not be --fast, but no
need for two commands that both do it. And it's hard for users to understand.
Also, this leaves open the possibility of making put --fast behave like
push --fast.
Sponsored-by: Kevin Mueller
diff --git a/Command/Copy.hs b/Command/Copy.hs
index d483db6c6a..a550793c34 100644
--- a/Command/Copy.hs
+++ b/Command/Copy.hs
@@ -8,6 +8,7 @@
 module Command.Copy where
 
 import Command
+import qualified Annex
 import qualified Command.Move
 import qualified Remote
 import Annex.Wanted
@@ -37,7 +38,7 @@ optParser desc = CopyOptions
 	<*> parseAutoOption
 	<*> parseWantedOption
 	<*> parseBatchOption True
-	<*> pure Command.Move.Copy
+	<*> pure (Command.Move.Copy False)
 
 instance DeferredParseClass CopyOptions where
 	finishParse v = CopyOptions
@@ -52,7 +53,10 @@ instance DeferredParseClass CopyOptions where
 
 seek :: CopyOptions -> CommandSeek
 seek o = case fromToOptions o of
-	Just fto -> seek' o fto
+	Just fto -> do
+		fast <- Annex.getRead Annex.fast
+		let o' = o { moveAction = Command.Move.Copy fast }
+		seek' o' fto
 	Nothing -> giveup "Specify --from or --to"
 
 seek' :: CopyOptions -> FromToHereOptions -> CommandSeek
diff --git a/Command/Mirror.hs b/Command/Mirror.hs
index 67aac3f74b..42232f31c0 100644
--- a/Command/Mirror.hs
+++ b/Command/Mirror.hs
@@ -66,7 +66,7 @@ start o si file k = startKey o afile (si, k, ai)
 startKey :: MirrorOptions -> AssociatedFile -> (SeekInput, Key, ActionItem) -> CommandStart
 startKey o afile (si, key, ai) = case fromToOptions o of
 	ToRemote r -> checkFailedTransferDirection ai Upload $ ifM (inAnnex key)
-		( Command.Move.toStart NoLiveUpdate Command.Move.Copy afile key ai si =<< getParsed r
+		( Command.Move.toStart NoLiveUpdate (Command.Move.Copy False) afile key ai si =<< getParsed r
 		, do
 			(numcopies, mincopies) <- getSafestNumMinCopies afile key
 			Command.Drop.startRemote NoLiveUpdate pcc afile ai si numcopies mincopies key (Command.Drop.DroppingUnused False)
diff --git a/Command/Move.hs b/Command/Move.hs
index de01527832..1d7412b14c 100644
--- a/Command/Move.hs
+++ b/Command/Move.hs
@@ -57,12 +57,16 @@ instance DeferredParseClass MoveOptions where
 		<*> pure (keyOptions v)
 		<*> pure (batchOption v)
 
-data MoveAction = Move | Copy | Put | Get
+data MoveAction
+	= Move
+	| Copy { copyFast :: Bool }
+	| Put
+	| Get
 	deriving (Show, Eq)
 
 describeMoveAction :: MoveAction -> String
 describeMoveAction Move = "move"
-describeMoveAction Copy = "copy"
+describeMoveAction (Copy _) = "copy"
 describeMoveAction Put = "put"
 describeMoveAction Get = "get"
 
@@ -140,15 +144,16 @@ toStart lu moveaction afile key ai si dest = do
 		else toStart' lu dest moveaction afile key ai si
 
 toStart' :: LiveUpdate -> Remote -> MoveAction -> AssociatedFile -> Key -> ActionItem -> SeekInput -> CommandStart
-toStart' lu dest moveaction afile key ai si = do
-	fast <- Annex.getRead Annex.fast
-	if fast && moveaction /= Move
-		then ifM (expectedPresent dest key)
+toStart' lu dest moveaction afile key ai si =
+	case moveaction of
+		Move -> checkhaskey
+		Copy { copyFast = False } -> checkhaskey
+		_ -> ifM (expectedPresent dest key)
 			( stop
 			, go True (pure $ Right False)
 			)
-		else go False (Remote.hasKey dest key)
   where
+	checkhaskey = go False (Remote.hasKey dest key)
 	go fastcheck isthere =
 		starting (describeMoveAction moveaction) (OnlyActionOn key ai) si $
 			toPerform lu dest moveaction key afile fastcheck =<< isthere
@@ -364,11 +369,10 @@ fromToStart lu moveaction afile key ai si src dest =
   where
 	somethingtodo
 		| Remote.uuid src == Remote.uuid dest = return False
-		| otherwise = do
-			fast <- Annex.getRead Annex.fast
-			if fast && moveaction /= Move
-				then not <$> expectedPresent dest key
-				else return True
+		| otherwise = case moveaction of
+			Move -> return True
+			Copy { copyFast = False } -> return True
+			_ -> not <$> expectedPresent dest key
 
 fromAnywhereToStart :: LiveUpdate -> MoveAction -> AssociatedFile -> Key -> ActionItem -> SeekInput -> Remote -> CommandStart
 fromAnywhereToStart lu moveaction afile key ai si dest =
@@ -388,11 +392,10 @@ fromAnywhereToStart lu moveaction afile key ai si dest =
 						toStart lu moveaction afile key ai si dest 
 				next $ return True
   where
-	somethingtodo = do
-		fast <- Annex.getRead Annex.fast
-		if fast && moveaction /= Move
-			then not <$> expectedPresent dest key
-			else return True
+	somethingtodo = case moveaction of
+		Move -> return True
+		Copy { copyFast = False } -> return True
+		_ -> not <$> expectedPresent dest key
 
 {- When there is a local copy, transfer it to the dest, and drop from the src.
  -
@@ -432,7 +435,7 @@ fromToPerform lu src dest moveaction key afile = do
 		dropsrc <- fromsrc True
 		combinecleanups 
 			-- Send to dest, preserve local copy.
-			(todest Nothing Copy haskey)
+			(todest Nothing (Copy False) haskey)
 			(\senttodest -> if senttodest
 				then dropsrc moveaction
 				else stop
@@ -474,7 +477,7 @@ fromToPerform lu src dest moveaction key afile = do
 							-- Drop from src, checking
 							-- copies including dest.
 							combinecleanups
-								(cleanupfromsrc Copy)
+								(cleanupfromsrc (Copy False))
 								(\_ -> if senttodest
 									then dropfromsrc (\l -> UnVerifiedRemote dest : l)
 									else stop
diff --git a/doc/git-annex-put.mdwn b/doc/git-annex-put.mdwn
index 03a8620563..554e705409 100644
--- a/doc/git-annex-put.mdwn
+++ b/doc/git-annex-put.mdwn
@@ -34,12 +34,6 @@ Paths of files or directories to operate on can be specified.
 
   Setting this to "cpus" will run one job per CPU core.
 
-* `--fast`
-
-  Avoid doing round trips to check if a remote already has content.
-  This can be faster, but might skip sending content to a remote in
-  some cases.
-
 * `--all` `-A`
 
   Rather than specifying a filename or path to send, this option can be

git-annex put working
(Except it says it's copying, a small wart.)
Implementing this in terms of copy is a little bit weird, but copy came
first. And copy is in some senses lower-level, since the user has to
tell it which remote to copy to, while put picks where the content
should go.
In that way, put is similar to push, but it does not drop unwanted
content from remotes, or send git content. Which is why it supports
--json, unlike push.
Sponsored-by: Joshua Antonishen
diff --git a/CHANGELOG b/CHANGELOG
index 6687c63ad9..9497f783ed 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,9 @@
+git-annex (10.20260602) UNRELEASED; urgency=medium
+
+  * put: New command.
+
+ -- Joey Hess <id@joeyh.name>  Wed, 03 Jun 2026 14:49:39 -0400
+
 git-annex (10.20260601) upstream; urgency=medium
 
   * Avoid an error message displaying a password embedded in a git remote url.
diff --git a/CmdLine/GitAnnex.hs b/CmdLine/GitAnnex.hs
index 65b5fac680..b2adcfa6f1 100644
--- a/CmdLine/GitAnnex.hs
+++ b/CmdLine/GitAnnex.hs
@@ -104,6 +104,7 @@ import qualified Command.Sync
 import qualified Command.Assist
 import qualified Command.Pull
 import qualified Command.Push
+import qualified Command.Put
 import qualified Command.Satisfy
 import qualified Command.Mirror
 import qualified Command.AddUrl
@@ -161,6 +162,7 @@ cmds testoptparser testrunner mkbenchmarkgenerator = map addGitAnnexCommonOption
 	, Command.Assist.cmd
 	, Command.Pull.cmd
 	, Command.Push.cmd
+	, Command.Put.cmd
 	, Command.Satisfy.cmd
 	, Command.Mirror.cmd
 	, Command.AddUrl.cmd
diff --git a/Command/Put.hs b/Command/Put.hs
index 1c2b48108c..ba29cde2be 100644
--- a/Command/Put.hs
+++ b/Command/Put.hs
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2010-2026 Joey Hess <id@joeyh.name>
+ - Copyright 2026 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -8,22 +8,20 @@
 module Command.Put where
 
 import Command
-import qualified Command.Move
+import qualified Command.Copy
 import qualified Remote
-import Annex.Wanted
-import Annex.NumCopies
 
 cmd :: Command
 cmd = withAnnexOptions [jobsOption, jsonOptions, jsonProgressOption, annexedMatchingOptions] $
 	command "put" SectionCommon
 		"send content of files to other repositories"
-		paramPaths (seek <--< optParser)
+		paramPaths (seek <$$> optParser)
 
 data PutOptions = PutOptions
 	{ putFiles :: CmdParams
 	, keyOptions :: Maybe KeyOptions
-	, autoMode :: Bool
 	, wantedMode :: Bool
+	, autoMode :: Bool
 	, batchOption :: BatchMode
 	}
 
@@ -31,67 +29,43 @@ optParser :: CmdParamsDesc -> Parser PutOptions
 optParser desc = PutOptions
 	<$> cmdParams desc
 	<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
-	<*> parseAutoOption
 	<*> parseWantedOption
+	<*> parseAutoOption
 	<*> parseBatchOption True
 
 seek :: PutOptions -> CommandSeek
 seek o = startConcurrency commandStages $ do
+	contentremotes <- filter Remote.canPut
+		. concat . Remote.byCost 
+		<$> (Remote.contentRemotes =<< Remote.remoteList)
+	let seeker = AnnexedFileSeeker
+		{ startAction = \_ si p k ->
+			return $ flip map contentremotes $ \r ->
+				Command.Copy.start co (to r) si p k
+		, checkContentPresent = Just True
+		, usesLocationLog = True
+		}
+	let keyaction v = 
+		return $ flip map contentremotes $ \r ->
+			Command.Copy.startKey (to r) v
 	case batchOption o of
 		NoBatch -> withKeyOptions
 			(keyOptions o) (autoMode o || wantedMode o) seeker
-			(commandAction . keyaction)
+			(\v -> commandActions =<< keyaction v)
 			(withFilesInGitAnnex ww seeker)
 			=<< workTreeItems ww (putFiles o)
 		Batch fmt -> batchOnly (keyOptions o) (putFiles o) $
-			batchAnnexed fmt seeker keyaction
+			batchAnnexed' fmt seeker keyaction
   where
 	ww = WarnUnmatchLsFiles "put"
-	
-	seeker = AnnexedFileSeeker
-		{ startAction = startSingle $ const $ start o
-		, checkContentPresent = case fto of
-			FromOrToRemote (FromRemote _) -> Just False
-			FromOrToRemote (ToRemote _) -> Just True
-			ToHere -> Just False
-			FromRemoteToRemote _ _ -> Nothing
-			FromAnywhereToRemote _ -> Nothing
-		, usesLocationLog = True
-		}
-	keyaction = Command.Move.startKey NoLiveUpdate fto Command.Move.RemoveNever
-
-{- A copy is just a move that does not delete the source file.
- - However, auto mode avoids unnecessary copies, and avoids getting or
- - sending non-preferred content. -}
-start :: PutOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
-start o fto si file key = do
-	ru <- case fto of
-		FromOrToRemote (ToRemote dest) -> getru dest
-		FromOrToRemote (FromRemote _) -> pure Nothing
-		ToHere -> pure Nothing
-		FromRemoteToRemote _ dest -> getru dest
-		FromAnywhereToRemote dest -> getru dest
-	lu <- prepareLiveUpdate ru key AddingKey
-	start' lu o fto si file key
-  where
-	getru dest = Just . Remote.uuid <$> getParsed dest
 
-start' :: LiveUpdate -> PutOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
-start' lu o fto si file key = stopUnless shouldCopy $ 
-	Command.Move.start lu fto Command.Move.RemoveNever si file key
-  where
-	shouldCopy
-		| autoMode o = want <||> numCopiesCheck file key (<)
-		| wantedMode o = want
-		| otherwise = return True
-	want = case fto of
-		FromOrToRemote (ToRemote dest) -> checkwantsend dest
-		FromOrToRemote (FromRemote _) -> checkwantget
-		ToHere -> checkwantget
-		FromRemoteToRemote _ dest -> checkwantsend dest
-		FromAnywhereToRemote dest -> checkwantsend dest
-
-	checkwantsend dest = 
-		(Remote.uuid <$> getParsed dest) >>=
-			wantGetBy lu False (Just key) (AssociatedFile (Just file))
-	checkwantget = wantGet lu False (Just key) (AssociatedFile (Just file))
+	co = Command.Copy.CopyOptions
+		{ Command.Copy.copyFiles = putFiles o
+		, Command.Copy.fromToOptions = Nothing
+		, Command.Copy.keyOptions = keyOptions o
+		, Command.Copy.autoMode = autoMode o
+		, Command.Copy.wantedMode = wantedMode o
+		, Command.Copy.batchOption = batchOption o
+		}
+	
+	to = FromOrToRemote . ToRemote . ReadyParse
diff --git a/doc/git-annex-put.mdwn b/doc/git-annex-put.mdwn
index fe14cfe45b..03a8620563 100644
--- a/doc/git-annex-put.mdwn
+++ b/doc/git-annex-put.mdwn
@@ -8,7 +8,7 @@ git annex put `[path ...]`
 
 # DESCRIPTION
 
-Copies the content of annexed files to other remotes. By default,
+Sends the content of annexed files to remotes. By default,
 files are sent to all remotes (except for certian special remotes
 that have to be populated using `git-annex export`).
 
@@ -17,9 +17,15 @@ Paths of files or directories to operate on can be specified.
 
 # OPTIONS
 
-* `--to=remote`
+* `--wanted` `-w`
+
+  Send files only to remotes that want them.
+  See [[git-annex-preferred-content]](1)
 
-  Only send the content of files to the specified remote.
+* `--auto`
+
+  Only send files to remotes that want them, or when there are not
+  yet have the desired number of copies.
 
 * `--jobs=N` `-JN`
 
@@ -28,18 +34,6 @@ Paths of files or directories to operate on can be specified.
 
   Setting this to "cpus" will run one job per CPU core.

(Diff truncated)
Merge branch 'master' into put
update
diff --git a/doc/todo/git-annex_put/comment_1_e71f2d3a103e84812977620706ee6542._comment b/doc/todo/git-annex_put/comment_1_e71f2d3a103e84812977620706ee6542._comment
index 7666345901..fccda0bc0d 100644
--- a/doc/todo/git-annex_put/comment_1_e71f2d3a103e84812977620706ee6542._comment
+++ b/doc/todo/git-annex_put/comment_1_e71f2d3a103e84812977620706ee6542._comment
@@ -7,15 +7,31 @@
 another remote if the first is not available, and of course does nothing
 if the content is present already. 
 
-It would be most symmetric if `git-annex put` picked one remote to send
-content to (ie, the fastest one that wants it), fell back to
-the next best remote if that one was not available, and avoided 
+It would be perhaps most symmetric with that if `git-annex put` picked one
+remote to send content to (ie, the lowest cost one that wants it), fell
+back to the next best remote if that one was not available, and avoided
 sending any content for files that are in some other repository already.
 
 As well as just being symmetric, that feels like a useful behavior that
-is not currently possible to get from any git-annex command. 
+is not currently possible to get from any git-annex command.
 
 That's in tension with the idea that `git-annex put --json` would
 send to the same remotes that `git-annex push` would. Maybe that
 behavior should be an option? Or maybe that belongs in yet another command.
+
+Just how useful would the 1 copy behavior be? One indication maybe is that
+noone has ever asked for that behavior. And it seems like it would be easy
+for the content to go to an unexpected place and break a workflow. Eg,
+suppose a user starts using `git-annex put`, which sends the content
+to `origin` and makes it available to others. But they also have a remote
+for a local USB drive, which has been disconnected all that time. When
+they one day reconnect that drive, it has a lower cost, and so their
+puts start going there, preventing others from accessing the files.
+
+Also it's worth noting that `pull` picks a remote to get to, but
+`push` sends to all remotes that want it. So this particular symmetry
+is not maintained all the way up. So perhaps it's not a useful symmetry.
+
+Overall, it seems like something that could be an option and not the
+default. If someone has a good use case.
 """]]

improve wording
diff --git a/Command/Get.hs b/Command/Get.hs
index 073b6bbb6f..6688bdf42e 100644
--- a/Command/Get.hs
+++ b/Command/Get.hs
@@ -18,7 +18,7 @@ import Logs.Location
 cmd :: Command
 cmd = withAnnexOptions [jobsOption, jsonOptions, jsonProgressOption, annexedMatchingOptions] $ 
 	command "get" SectionCommon 
-		"make content of annexed files available"
+		"get content of annexed files"
 		paramPaths (seek <$$> optParser)
 
 data GetOptions = GetOptions
diff --git a/doc/git-annex-drop.mdwn b/doc/git-annex-drop.mdwn
index ea610d5b05..94c9dd4f45 100644
--- a/doc/git-annex-drop.mdwn
+++ b/doc/git-annex-drop.mdwn
@@ -1,6 +1,6 @@
 # NAME
 
-git-annex drop - remove content of files from repository
+git-annex drop - remove content of annexed files from repository
 
 # SYNOPSIS
 
diff --git a/doc/git-annex-get.mdwn b/doc/git-annex-get.mdwn
index 5c49c39669..9c45b0ece4 100644
--- a/doc/git-annex-get.mdwn
+++ b/doc/git-annex-get.mdwn
@@ -1,6 +1,6 @@
 # NAME
 
-git-annex get - make content of annexed files available
+git-annex get - get content of annexed files
 
 # SYNOPSIS
 
diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn
index 3cb7e4f6d8..1dd8a4506b 100644
--- a/doc/git-annex.mdwn
+++ b/doc/git-annex.mdwn
@@ -68,7 +68,7 @@ content from the key-value store.
 
 * `get [path ...]`
 
-  Makes the content of annexed files available in this repository.
+  Gets the content of annexed files.
   
   See [[git-annex-get]](1) for details.
 

comment
diff --git a/doc/todo/git-annex_put/comment_1_e71f2d3a103e84812977620706ee6542._comment b/doc/todo/git-annex_put/comment_1_e71f2d3a103e84812977620706ee6542._comment
new file mode 100644
index 0000000000..7666345901
--- /dev/null
+++ b/doc/todo/git-annex_put/comment_1_e71f2d3a103e84812977620706ee6542._comment
@@ -0,0 +1,21 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-06-03T16:02:58Z"
+ content="""
+`git-annex get` picks which remote to use, and falls back as needed to
+another remote if the first is not available, and of course does nothing
+if the content is present already. 
+
+It would be most symmetric if `git-annex put` picked one remote to send
+content to (ie, the fastest one that wants it), fell back to
+the next best remote if that one was not available, and avoided 
+sending any content for files that are in some other repository already.
+
+As well as just being symmetric, that feels like a useful behavior that
+is not currently possible to get from any git-annex command. 
+
+That's in tension with the idea that `git-annex put --json` would
+send to the same remotes that `git-annex push` would. Maybe that
+behavior should be an option? Or maybe that belongs in yet another command.
+"""]]

add news item for git-annex 10.20260601
diff --git a/doc/news/version_10.20260213.mdwn b/doc/news/version_10.20260213.mdwn
deleted file mode 100644
index 873cee77a3..0000000000
--- a/doc/news/version_10.20260213.mdwn
+++ /dev/null
@@ -1,30 +0,0 @@
-git-annex 10.20260213 released with [[!toggle text="these changes"]]
-[[!toggleable text="""  * When used with git forges that allow Push to Create, the remote's
-    annex-uuid is re-probed after the initial push.
-  * addurl, importfeed: Enable --verifiable by default.
-  * fromkey, registerurl: When passed an url, generate a VURL key.
-  * unregisterurl: Unregister both VURL and URL keys.
-  * Fix behavior of local git remotes that have annex-ignore
-    set to be the same as ssh git remotes.
-  * Added annex.security.allow-insecure-https config, which allows
-    using old http servers that use TLS 1.2 without Extended Main
-    Secret support.
-  * p2phttp: Commit git-annex branch changes promptly.
-  * p2phttp: Fix a server stall by disabling warp's slowloris attack
-    prevention.
-  * p2phttp: Added --cpus option.
-  * Avoid ever starting more capabilities than the number of cpus.
-  * fsck: Support repairing a corrupted file in a versioned S3 remote.
-  * Fix incorrect transfer direction in remote transfer log when
-    downloading from a local git remote.
-  * Fix bug that prevented 2 clones of a local git remote
-    from concurrently downloading the same file.
-  * rsync: Avoid deleting contents of a non-empty directory when
-    removing the last exported file from the directory.
-  * unregisterurl: Fix display of action to not be "registerurl".
-  * The OsPath build flag requires file-io 0.2.0, which fixes several
-    issues.
-  * Remove deprecated commands direct, indirect, proxy, and transferkeys.
-  * Deprecate undo command.
-  * Remove undo action from kde and nautilus integrations.
-  * Fix build on BSDs. Thanks, Greg Steuck"""]]
\ No newline at end of file
diff --git a/doc/news/version_10.20260601.mdwn b/doc/news/version_10.20260601.mdwn
new file mode 100644
index 0000000000..ebf553e703
--- /dev/null
+++ b/doc/news/version_10.20260601.mdwn
@@ -0,0 +1,18 @@
+git-annex 10.20260601 released with [[!toggle text="these changes"]]
+[[!toggleable text="""  * Avoid an error message displaying a password embedded in a git remote url.
+    (Reversion introduced in 10.20260421)
+  * Fix use of annex.commitmessage
+    (Reversion introduced in 10.20250115)
+  * disableremote: Avoid (temporarily) clearing size tracking information
+    for other repos than the one being disabled.
+  * Fix bug that prevented remote.name.annex-web-options from always taking
+    effect, and sometimes caused it to be used in situations where it
+    should not be.
+  * map: Don't try to use dot -Tx11 to display the map, that no longer
+    works in commonly available builds of graphviz.
+  * push: Avoid updating a view branch or adjusted branch.
+  * pull: Avoid propagating adjusted branch changes to the original branch.
+  * get, copy: Added --wanted option, which only transfers files
+    that are preferred content.
+  * fsck, drop, whereis: Support --failed option.
+  * Display an introduction before other debug output."""]]
\ No newline at end of file

drop, whereis: support --failed option
Looked over the other commands and these seemed like the only ones left
that could usefully support it.
Sponsored-by: Leon Schuermann
diff --git a/CHANGELOG b/CHANGELOG
index 8c32fff47c..d9d16c2154 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,7 +15,7 @@ git-annex (10.20260526) UNRELEASED; urgency=medium
   * pull: Avoid propagating adjusted branch changes to the original branch.
   * get, copy: Added --wanted option, which only transfers files
     that are preferred content.
-  * fsck: Support --failed option. 
+  * fsck, drop, whereis: Support --failed option. 
   * Display an introduction before other debug output.
 
  -- Joey Hess <id@joeyh.name>  Thu, 28 May 2026 13:13:21 -0400
diff --git a/Command/Drop.hs b/Command/Drop.hs
index 95b6bf062a..a50921fb31 100644
--- a/Command/Drop.hs
+++ b/Command/Drop.hs
@@ -41,7 +41,7 @@ optParser desc = DropOptions
 	<$> cmdParams desc
 	<*> optional parseDropFromOption
 	<*> parseAutoOption
-	<*> optional parseKeyOptions
+	<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
 	<*> parseBatchOption True
 
 parseDropFromOption :: Parser (DeferredParse Remote)
diff --git a/Command/Whereis.hs b/Command/Whereis.hs
index 919d96b322..a193232982 100644
--- a/Command/Whereis.hs
+++ b/Command/Whereis.hs
@@ -38,7 +38,7 @@ data WhereisOptions = WhereisOptions
 optParser :: CmdParamsDesc -> Parser WhereisOptions
 optParser desc = WhereisOptions
 	<$> cmdParams desc
-	<*> optional parseKeyOptions
+	<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
 	<*> parseBatchOption True
 	<*> optional parseFormatOption
 
diff --git a/doc/git-annex-drop.mdwn b/doc/git-annex-drop.mdwn
index 3d1307700a..ea610d5b05 100644
--- a/doc/git-annex-drop.mdwn
+++ b/doc/git-annex-drop.mdwn
@@ -88,6 +88,13 @@ Paths of files or directories to drop can be specified.
   Note that this bypasses checking the .gitattributes annex.numcopies
   setting and required content settings.
 
+* `--failed`
+
+  Drop files that have recently failed to be transferred.
+  
+  Note that this bypasses checking the .gitattributes annex.numcopies
+  setting and required content settings.
+
 * `--key=keyname`
 
   Use this option to drop a specified key.
diff --git a/doc/git-annex-whereis.mdwn b/doc/git-annex-whereis.mdwn
index 84678709f0..8771afcbab 100644
--- a/doc/git-annex-whereis.mdwn
+++ b/doc/git-annex-whereis.mdwn
@@ -50,6 +50,10 @@ received from remotes.
 
   Show whereis information for files found by last run of git-annex unused.
 
+* `--failed`
+
+  Operate on files that have recently failed to be transferred.
+
 * `--batch`
 
   Enables batch mode, in which a file is read in a line from stdin,

fsck: Support --failed option
Example use: I was running a long git-annex copy and it failed on a few
files, which have apparently gotten corrupted. So I want to fsck those to
let it deal with them, but fscking the whole repo or specific files would
be too much bother. With --failed fsck will check just those files.
Sponsored-by: Graham Spencer on Patreon
diff --git a/CHANGELOG b/CHANGELOG
index 3f15c1baa3..8c32fff47c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@ git-annex (10.20260526) UNRELEASED; urgency=medium
   * pull: Avoid propagating adjusted branch changes to the original branch.
   * get, copy: Added --wanted option, which only transfers files
     that are preferred content.
+  * fsck: Support --failed option. 
   * Display an introduction before other debug output.
 
  -- Joey Hess <id@joeyh.name>  Thu, 28 May 2026 13:13:21 -0400
diff --git a/Command/Fsck.hs b/Command/Fsck.hs
index a17ca0d2c3..645576c117 100644
--- a/Command/Fsck.hs
+++ b/Command/Fsck.hs
@@ -83,7 +83,7 @@ optParser desc = FsckOptions
 		<> completeRemotes
 		))
 	<*> optional parseincremental
-	<*> optional parseKeyOptions
+	<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
   where
 	parseincremental =
 		flag' StartIncrementalO
diff --git a/doc/git-annex-fsck.mdwn b/doc/git-annex-fsck.mdwn
index 89760119d8..5873799af6 100644
--- a/doc/git-annex-fsck.mdwn
+++ b/doc/git-annex-fsck.mdwn
@@ -92,6 +92,10 @@ better format.
 
   Operate on files found by last run of git-annex unused.
 
+* `--failed`
+
+  Operate on files that have recently failed to be transferred.
+
 * `--key=keyname`
 
   Use this option to fsck a specified key.

wip git-annex put
diff --git a/Command/Put.hs b/Command/Put.hs
new file mode 100644
index 0000000000..f5aadc2ccb
--- /dev/null
+++ b/Command/Put.hs
@@ -0,0 +1,97 @@
+{- git-annex command
+ -
+ - Copyright 2010-2026 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU AGPL version 3 or higher.
+ -}
+
+module Command.Put where
+
+import Command
+import qualified Command.Move
+import qualified Remote
+import Annex.Wanted
+import Annex.NumCopies
+
+cmd :: Command
+cmd = withAnnexOptions [jobsOption, jsonOptions, jsonProgressOption, annexedMatchingOptions] $
+	command "put" SectionCommon
+		"put content of files to other repositories"
+		paramPaths (seek <--< optParser)
+
+data PutOptions = PutOptions
+	{ putFiles :: CmdParams
+	, keyOptions :: Maybe KeyOptions
+	, autoMode :: Bool
+	, wantedMode :: Bool
+	, batchOption :: BatchMode
+	}
+
+optParser :: CmdParamsDesc -> Parser PutOptions
+optParser desc = PutOptions
+	<$> cmdParams desc
+	<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
+	<*> parseAutoOption
+	<*> parseWantedOption
+	<*> parseBatchOption True
+
+seek :: CopyOptions -> CommandSeek
+seek o = startConcurrency commandStages $ do
+	case batchOption o of
+		NoBatch -> withKeyOptions
+			(keyOptions o) (autoMode o || wantedMode o) seeker
+			(commandAction . keyaction)
+			(withFilesInGitAnnex ww seeker)
+			=<< workTreeItems ww (copyFiles o)
+		Batch fmt -> batchOnly (keyOptions o) (copyFiles o) $
+			batchAnnexed fmt seeker keyaction
+  where
+	ww = WarnUnmatchLsFiles "put"
+	
+	seeker = AnnexedFileSeeker
+		{ startAction = const $ start o
+		, checkContentPresent = case fto of
+			FromOrToRemote (FromRemote _) -> Just False
+			FromOrToRemote (ToRemote _) -> Just True
+			ToHere -> Just False
+			FromRemoteToRemote _ _ -> Nothing
+			FromAnywhereToRemote _ -> Nothing
+		, usesLocationLog = True
+		}
+	keyaction = Command.Move.startKey NoLiveUpdate fto Command.Move.RemoveNever
+
+{- A copy is just a move that does not delete the source file.
+ - However, auto mode avoids unnecessary copies, and avoids getting or
+ - sending non-preferred content. -}
+start :: CopyOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
+start o fto si file key = do
+	ru <- case fto of
+		FromOrToRemote (ToRemote dest) -> getru dest
+		FromOrToRemote (FromRemote _) -> pure Nothing
+		ToHere -> pure Nothing
+		FromRemoteToRemote _ dest -> getru dest
+		FromAnywhereToRemote dest -> getru dest
+	lu <- prepareLiveUpdate ru key AddingKey
+	start' lu o fto si file key
+  where
+	getru dest = Just . Remote.uuid <$> getParsed dest
+
+start' :: LiveUpdate -> CopyOptions -> FromToHereOptions -> SeekInput -> OsPath -> Key -> CommandStart
+start' lu o fto si file key = stopUnless shouldCopy $ 
+	Command.Move.start lu fto Command.Move.RemoveNever si file key
+  where
+	shouldCopy
+		| autoMode o = want <||> numCopiesCheck file key (<)
+		| wantedMode o = want
+		| otherwise = return True
+	want = case fto of
+		FromOrToRemote (ToRemote dest) -> checkwantsend dest
+		FromOrToRemote (FromRemote _) -> checkwantget
+		ToHere -> checkwantget
+		FromRemoteToRemote _ dest -> checkwantsend dest
+		FromAnywhereToRemote dest -> checkwantsend dest
+
+	checkwantsend dest = 
+		(Remote.uuid <$> getParsed dest) >>=
+			wantGetBy lu False (Just key) (AssociatedFile (Just file))
+	checkwantget = wantGet lu False (Just key) (AssociatedFile (Just file))
diff --git a/doc/git-annex-put.mdwn b/doc/git-annex-put.mdwn
new file mode 100644
index 0000000000..fe14cfe45b
--- /dev/null
+++ b/doc/git-annex-put.mdwn
@@ -0,0 +1,127 @@
+# NAME
+
+git-annex put - send content of files to other repositories
+
+# SYNOPSIS
+
+git annex put `[path ...]`
+
+# DESCRIPTION
+
+Copies the content of annexed files to other remotes. By default,
+files are sent to all remotes (except for certian special remotes
+that have to be populated using `git-annex export`).
+
+With no parameters, operates on all annexed files in the current directory.
+Paths of files or directories to operate on can be specified.
+
+# OPTIONS
+
+* `--to=remote`
+
+  Only send the content of files to the specified remote.
+
+* `--jobs=N` `-JN`
+
+  Enables parallel transfers with up to the specified number of jobs
+  running at once. For example: `-J10`
+
+  Setting this to "cpus" will run one job per CPU core.
+
+* `--wanted` `-w`
+
+  Rather than sending all specified files, only send those that
+  are preferred content of the destination repository.
+  See [[git-annex-preferred-content]](1)
+
+* `--auto`
+
+  Rather than sending all specified files, only send those that don't yet have
+  the desired number of copies, or that are preferred content of the
+  destination repository.
+
+* `--fast`
+
+  Avoid doing round trips to check if a remote already has content.
+  This can be faster, but might skip sending content to a remote in
+  some cases.
+
+* `--all` `-A`
+
+  Rather than specifying a filename or path to send, this option can be
+  used to send all available versions of all files.
+
+  This is the default behavior when running git-annex in a bare repository.
+
+* `--branch=ref`
+
+  Operate on files in the specified branch or treeish.
+
+* `--unused`
+
+  Operate on files found by last run of git-annex unused.
+
+* `--failed`
+
+  Operate on files that have recently failed to be transferred.
+
+* `--key=keyname`
+
+  Use this option to send a specified key.
+
+* matching options
+
+  The [[git-annex-matching-options]](1)
+  can be used to specify what to send.
+
+* `--batch`
+
+  Enables batch mode, in which lines containing names of files to send
+  are read from stdin.
+
+  As each specified file is processed, the usual progress output is
+  displayed. If a file's content does not need to be sent, or it does not
+  match specified matching options, or it is not an annexed file,
+  a blank line is output in response instead.
+
+  Since the usual output while sending a file is verbose and not
+  machine-parseable, you may want to use --json in combination with
+  --batch.
+
+* `--batch-keys`

(Diff truncated)
wording
diff --git a/doc/git-annex-copy.mdwn b/doc/git-annex-copy.mdwn
index 88a94fabdf..d837256e3b 100644
--- a/doc/git-annex-copy.mdwn
+++ b/doc/git-annex-copy.mdwn
@@ -8,7 +8,7 @@ git annex copy `[path ...] [--from=remote|--to=remote]`
 
 # DESCRIPTION
 
-Copies the content of files from or to another remote.
+Copies the content of files from or to another repository.
 
 With no parameters, operates on all annexed files in the current directory.
 Paths of files or directories to operate on can be specified.
diff --git a/doc/git-annex-move.mdwn b/doc/git-annex-move.mdwn
index c93953f985..03785bc910 100644
--- a/doc/git-annex-move.mdwn
+++ b/doc/git-annex-move.mdwn
@@ -8,7 +8,7 @@ git annex move `[path ...] [--from=remote|--to=remote|--to=here]`
 
 # DESCRIPTION
 
-Moves the content of files from or to another remote.
+Moves the content of files from or to another repository.
 
 With no parameters, operates on all annexed files in the current directory.
 Paths of files or directories to operate on can be specified.

typo
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
index 098d34ecee..727dd711d3 100644
--- a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
@@ -13,5 +13,5 @@ I think it would be a good idea to add a `--wanted` option to commands
 that support `--auto`. It would only operate on preferred content, avoiding
 making copies only to work toward satisfying numcopies.
 
-Update: Added `--wanted.
+Update: Added `--wanted`
 """]]

--wanted
get, copy: Added --wanted option, which only transfers files that are
preferred content, not taking numcopies into account.
The only other command that supports --auto is drop. I considered
making it support --wanted. However, since drop always honors numcopies,
the behavior of --wanted would necessarily be the same as --auto. I
don't think it's worth adding a new option that behaves the same as an
existing option.
Sponsored-by: unqueued
diff --git a/CHANGELOG b/CHANGELOG
index 8d4bebd4d3..f68a512e9c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,7 @@
 git-annex (10.20260526) UNRELEASED; urgency=medium
 
+  * get, copy: Added --wanted option, which only transfers files
+    that are preferred content.
   * Avoid an error message displaying a password embedded in a git remote url.
     (Reversion introduced in 10.20260421)
   * Fix use of annex.commitmessage
diff --git a/CmdLine/GitAnnex/Options.hs b/CmdLine/GitAnnex/Options.hs
index cb969c8c21..5bc6f0074e 100644
--- a/CmdLine/GitAnnex/Options.hs
+++ b/CmdLine/GitAnnex/Options.hs
@@ -129,6 +129,12 @@ parseAutoOption = switch
 	<> help "automatic mode"
 	)
 
+parseWantedOption :: Parser Bool
+parseWantedOption = switch
+	( long "wanted" <> short 'w'
+	<> help "operate on preferred content"
+	)
+
 mkParseRemoteOption :: RemoteName -> DeferredParse Remote
 mkParseRemoteOption = DeferredParse 
 	. (fromJust <$$> Remote.byNameWithUUID)
diff --git a/CmdLine/Seek.hs b/CmdLine/Seek.hs
index c012811ac3..f8a981ee7a 100644
--- a/CmdLine/Seek.hs
+++ b/CmdLine/Seek.hs
@@ -233,10 +233,10 @@ withKeyOptions'
 	-> (WorkTreeItems -> CommandSeek)
 	-> WorkTreeItems
 	-> CommandSeek
-withKeyOptions' ko auto mkkeyaction fallbackaction worktreeitems = do
+withKeyOptions' ko autoorwanted mkkeyaction fallbackaction worktreeitems = do
 	bare <- fromRepo Git.repoIsLocalBare
-	when (auto && bare) $
-		giveup "Cannot use --auto in a bare repository"
+	when (autoorwanted && bare) $
+		giveup "Cannot use --auto or --wanted in a bare repository"
 	case (nospecifiedworktreeitems, ko) of
 		(True, Nothing)
 			| bare -> nofilename $ noauto runallkeys
@@ -251,7 +251,7 @@ withKeyOptions' ko auto mkkeyaction fallbackaction worktreeitems = do
 		(False, Just _) -> giveup "Can only specify one of file names, --all, --branch, --unused, --failed, --key, or --incomplete"
   where
 	noauto a
-		| auto = giveup "Cannot use --auto with --all or --branch or --unused or --key or --incomplete"
+		| autoorwanted = giveup "Cannot use --auto or --wanted with --all or --branch or --unused or --key or --incomplete"
 		| otherwise = a
 			
 	nofilename a = ifM (Limit.introspect matchNeedsFileName)
diff --git a/Command/Copy.hs b/Command/Copy.hs
index dce01ddefe..59c476aba9 100644
--- a/Command/Copy.hs
+++ b/Command/Copy.hs
@@ -24,6 +24,7 @@ data CopyOptions = CopyOptions
 	, fromToOptions :: Maybe FromToHereOptions
 	, keyOptions :: Maybe KeyOptions
 	, autoMode :: Bool
+	, wantedMode :: Bool
 	, batchOption :: BatchMode
 	}
 
@@ -33,6 +34,7 @@ optParser desc = CopyOptions
 	<*> parseFromToHereOptions
 	<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
 	<*> parseAutoOption
+	<*> parseWantedOption
 	<*> parseBatchOption True
 
 instance DeferredParseClass CopyOptions where
@@ -42,6 +44,7 @@ instance DeferredParseClass CopyOptions where
 			(fromToOptions v)
 		<*> pure (keyOptions v)
 		<*> pure (autoMode v)
+		<*> pure (wantedMode v)
 		<*> pure (batchOption v)
 
 seek :: CopyOptions -> CommandSeek
@@ -53,7 +56,7 @@ seek' :: CopyOptions -> FromToHereOptions -> CommandSeek
 seek' o fto = startConcurrency (Command.Move.stages fto) $ do
 	case batchOption o of
 		NoBatch -> withKeyOptions
-			(keyOptions o) (autoMode o) seeker
+			(keyOptions o) (autoMode o || wantedMode o) seeker
 			(commandAction . keyaction)
 			(withFilesInGitAnnex ww seeker)
 			=<< workTreeItems ww (copyFiles o)
@@ -96,6 +99,7 @@ start' lu o fto si file key = stopUnless shouldCopy $
   where
 	shouldCopy
 		| autoMode o = want <||> numCopiesCheck file key (<)
+		| wantedMode o = want
 		| otherwise = return True
 	want = case fto of
 		FromOrToRemote (ToRemote dest) -> checkwantsend dest
diff --git a/Command/Get.hs b/Command/Get.hs
index 880aa03198..073b6bbb6f 100644
--- a/Command/Get.hs
+++ b/Command/Get.hs
@@ -25,6 +25,7 @@ data GetOptions = GetOptions
 	{ getFiles :: CmdParams
 	, getFrom :: Maybe (DeferredParse Remote)
 	, autoMode :: Bool
+	, wantedMode :: Bool
 	, keyOptions :: Maybe KeyOptions
 	, batchOption :: BatchMode
 	}
@@ -34,6 +35,7 @@ optParser desc = GetOptions
 	<$> cmdParams desc
 	<*> optional (mkParseRemoteOption <$> parseFromOption)
 	<*> parseAutoOption
+	<*> parseWantedOption
 	<*> optional (parseIncompleteOption <|> parseKeyOptions <|> parseFailedTransfersOption)
 	<*> parseBatchOption True
 
@@ -46,7 +48,7 @@ seek o = startConcurrency transferStages $ do
 		, usesLocationLog = True
 		}
 	case batchOption o of
-		NoBatch -> withKeyOptions (keyOptions o) (autoMode o) seeker
+		NoBatch -> withKeyOptions (keyOptions o) (autoMode o || wantedMode o) seeker
 			(commandAction . startKeys from)
 			(withFilesInGitAnnex ww seeker)
 			=<< workTreeItems ww (getFiles o)
@@ -63,9 +65,10 @@ start o from si file key = do
 	afile = AssociatedFile (Just file)
 	ai = mkActionItem (key, afile)
 	expensivecheck lu
-		| autoMode o = numCopiesCheck file key (<)
-			<||> wantGet lu False (Just key) afile
+		| autoMode o = numCopiesCheck file key (<) <||> wantget lu
+		| wantedMode o = wantget lu
 		| otherwise = return True
+	wantget lu = wantGet lu False (Just key) afile
 
 startKeys :: Maybe Remote -> (SeekInput, Key, ActionItem) -> CommandStart
 startKeys from (si, key, ai) = checkFailedTransferDirection ai Download $
diff --git a/doc/git-annex-copy.mdwn b/doc/git-annex-copy.mdwn
index add7a96f06..88a94fabdf 100644
--- a/doc/git-annex-copy.mdwn
+++ b/doc/git-annex-copy.mdwn
@@ -56,11 +56,17 @@ Paths of files or directories to operate on can be specified.
   Note that when using --from with --to, twice this many jobs will
   run at once, evenly split between the two remotes.
 
+* `--wanted` `-w`
+
+  Rather than copying all specified files, only copy those that
+  are preferred content of the destination repository.
+  See [[git-annex-preferred-content]](1)
+
 * `--auto`
 
   Rather than copying all specified files, only copy those that don't yet have
   the desired number of copies, or that are preferred content of the
-  destination repository. See [[git-annex-preferred-content]](1)
+  destination repository.
 
 * `--fast`
 
diff --git a/doc/git-annex-get.mdwn b/doc/git-annex-get.mdwn
index 208188171f..5c49c39669 100644
--- a/doc/git-annex-get.mdwn
+++ b/doc/git-annex-get.mdwn
@@ -28,11 +28,17 @@ be specified.
 
 # OPTIONS
 
+* `--wanted`
+
+  Rather than getting all the specified files, get only those that
+  are preferred content of the repository.
+  See [[git-annex-preferred-content]](1)
+
 * `--auto`
 
   Rather than getting all the specified files, get only those that don't yet
   have the desired number of copies, or that are preferred content of the
-  repository. See [[git-annex-preferred-content]](1)
+  repository.
 
 * `--from=remote`
 
diff --git a/doc/git-annex-preferred-content.mdwn b/doc/git-annex-preferred-content.mdwn
index 6b9fc521ac..3de39961b8 100644
--- a/doc/git-annex-preferred-content.mdwn
+++ b/doc/git-annex-preferred-content.mdwn
@@ -7,8 +7,8 @@ git-annex-preferred-content - which files are wanted in a repository
 Each repository has a preferred content setting, which specifies content
 that the repository wants to have present. These settings can be configured
 using `git annex vicfg` or `git annex wanted`.
-They are used by the `--auto` option, by `git annex sync --content`,
-by clusters, and by the git-annex assistant.
+They are used by the `--wanted` and `--auto` options, 

(Diff truncated)
comment
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
new file mode 100644
index 0000000000..9e908771c3
--- /dev/null
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_11_ee87ba949945446dc324981bdf92329f._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 11"""
+ date="2026-05-29T15:09:31Z"
+ content="""
+Hmm, `git-annex get --auto` and `git-annex copy --auto` don't just check
+preferred content, they will also make a copy if numcopies is not satisfied
+for the file.
+
+That's something that `git-annex pull` and `git-annex push` don't do.
+
+I think it would be a good idea to add a `--wanted` option to commands
+that support `--auto`. It would only operate on preferred content, avoiding
+making copies only to work toward satisfying numcopies.
+"""]]

todo
diff --git a/doc/todo/git-annex_put.mdwn b/doc/todo/git-annex_put.mdwn
new file mode 100644
index 0000000000..ca5a17b55f
--- /dev/null
+++ b/doc/todo/git-annex_put.mdwn
@@ -0,0 +1,36 @@
+In [[todo/add_--json-progress_support_in_push_and_pull]]
+I noticed that it might be good to have a `git-annex put` command
+that is symmetric with `git-annex get`. That is, it picks which 
+remotes to send content to.
+
+One use case is emulating `git-annex push` but with json output.
+When operating on a single remote, that can be done using `copy --to`:
+
+	git-annex copy --auto --json --to $someremote
+	git-annex drop --auto --json --from $someremote
+	git-annex push --no-content $someremote
+
+But to operate on all remotes needs `git-annex put`:
+
+    git-annex put --auto --json
+    git-annex drop --auto --json
+    git-annex push --no-content
+
+So `git-annex put` would default to putting to all remotes,
+but with `--auto` would honor preferred content and numcopies.
+It's essentially `git-annex copy --to` run over each remote in turn.
+
+Another way to look at it is this tower has a missing leg:
+
+	           assist
+                  |
+	          --sync--
+              |      |
+           push      pull
+              |      |
+           copy --to copy --from
+              |      |
+                     get
+
+
+--[[Joey]]

current status update
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
new file mode 100644
index 0000000000..2bdeacf1cb
--- /dev/null
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_10_71fa338205298e0c929d16e470684e02._comment
@@ -0,0 +1,46 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 10"""
+ date="2026-05-29T13:59:25Z"
+ content="""
+Summarizing the current status of this todo, if someone wants 
+the equivilant of `git-annex pull --json $someremote`, they can run:
+
+	git-annex pull --no-content $someremote
+	git-annex get --auto --json --from $someremote
+	git-annex drop --auto --json
+
+The first command above does not have json output, but outputs the
+usual `git pull` messages for the user to deal with as they see fit.
+
+And, if someone wants the equivilant of `git-annex push --json
+$someremote`, they can run:
+
+	git-annex copy --auto --json --to $someremote
+	git-annex drop --auto --json --from $someremote
+	git-annex push --no-content $someremote
+
+The last command above does not have json output, but outputs the
+usual `git push` messages for the user to deal with as they see fit.
+
+The argument for adding --json to pull/push now seems to be reduced.
+But not gone entirely I suppose. 
+
+For example, `git-annex push` without
+a remote pushes content to all remotes that want it. That needs
+multiple runs of `git-annex copy`, one per remote. Notice that
+in the `git-annex pull` case, it can be made to operate on all remotes:
+
+	git-annex pull --no-content
+	git-annex get --auto --json
+	git-annex drop --auto --json
+
+This seems like an argument for adding a `git-annex put`
+command that copies to all remotes that want content. Which is nicely
+symmetric with `git-annex get`.
+
+Another difference is that a single `git-annex push` or `pull`
+(or `sync`) does less work than several git-annex commands.
+In the scripts above, git-annex has to traverse the tree twice.
+That is a pretty small difference in overhead.
+"""]]

split local branch updates between push and pull commands
Before both push and pull did all local git branch updates the same as
sync, despite not being documented to behave that way.
diff --git a/Assistant/Threads/Committer.hs b/Assistant/Threads/Committer.hs
index 7e41ca8e01..7c11ecc05c 100644
--- a/Assistant/Threads/Committer.hs
+++ b/Assistant/Threads/Committer.hs
@@ -253,7 +253,7 @@ commitStaged msg = do
 				, Param msg
 				]
 			when ok $
-				Command.Sync.updateBranches =<< getCurrentBranch
+				Command.Sync.updateBranches True True =<< getCurrentBranch
 			{- Commit the git-annex branch. This comes after
 			 - the commit of the staged changes, so that
 			 - annex.commitmessage-command can examine that
diff --git a/CHANGELOG b/CHANGELOG
index bbc6ccde7f..8d4bebd4d3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,8 @@ git-annex (10.20260526) UNRELEASED; urgency=medium
     should not be.
   * map: Don't try to use dot -Tx11 to display the map, that no longer
     works in commonly available builds of graphviz.
+  * push: Avoid updating a view branch or adjusted branch.
+  * pull: Avoid propagating adjusted branch changes to the original branch.
 
  -- Joey Hess <id@joeyh.name>  Thu, 28 May 2026 13:13:21 -0400
 
diff --git a/Command/Sync.hs b/Command/Sync.hs
index e7f4d5f38a..c0971bf911 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -334,7 +334,7 @@ seek' o = startConcurrency transferStages $ do
 						, [ commitAnnex, mergeAnnex ]
 						]
 	
-			void $ includeCommandAction $ withbranch $ pushLocal o
+			void $ includeCommandAction $ withbranch $ updateLocal o
 			-- Pushes to remotes can run concurrently.
 			mapM_ (commandAction . withbranch . pushRemote o) gitremotes
   where
@@ -439,8 +439,10 @@ commitMsg = do
 		++ maybe "unknown" fromUUIDDesc (M.lookup u m)
 
 mergeLocal :: [Git.Merge.MergeConfig] -> SyncOptions -> CurrBranch -> CommandStart
-mergeLocal mergeconfig o currbranch = stopUnless (notOnlyAnnex o) $
+mergeLocal mergeconfig o currbranch = stopUnless shouldmerge $
 	mergeLocal' mergeconfig o currbranch
+  where
+	shouldmerge = pure (pullOption o) <&&> notOnlyAnnex o
 
 mergeLocal' :: [Git.Merge.MergeConfig] -> SyncOptions -> CurrBranch -> CommandStart
 mergeLocal' mergeconfig o currbranch@(Just branch, _) =
@@ -494,46 +496,50 @@ needMerge currbranch headbranch
 		let branch' = maybe headbranch (adjBranch . originalToAdjusted headbranch) madj
 		in hassyncbranch <&&> inRepo (Git.Branch.changed branch' syncbranch)
 
-pushLocal :: SyncOptions -> CurrBranch -> CommandStart
-pushLocal o b = stopUnless (notOnlyAnnex o) $ do
-	updateBranches b
+updateLocal :: SyncOptions -> CurrBranch -> CommandStart
+updateLocal o b = stopUnless (notOnlyAnnex o) $ do
+	updateBranches (pullOption o) (pushOption o) b
 	stop
 
-updateBranches :: CurrBranch -> Annex ()
-updateBranches (Nothing, _) = noop
-updateBranches (Just branch, madj) = do
-	-- When in a view branch, update it to reflect any changes
-	-- of its parent branch or the metadata.
+updateBranches :: Bool -> Bool -> CurrBranch -> Annex ()
+updateBranches _ _ (Nothing, _) = noop
+updateBranches forpull forpush (Just branch, madj) = do
 	currentView >>= \case
-		Just (view, madj') -> updateView view madj' >>= \case
-			Nothing -> noop
-			Just newcommit -> do
-				ok <- inRepo $ Git.Command.runBool
-					[ Param "merge"
-					, Param (Git.fromRef newcommit)
-					]
-				unless ok $
-					giveup $ "failed to update view"
-				case madj' of
-					Nothing -> noop
-					Just adj -> updateadjustedbranch adj
+		Just (view, madj')
+			| forpull -> updateview view madj'
+			| otherwise -> noop
 		-- When in an adjusted branch, propagate any changes
 		-- made to it back to the original branch.
 		Nothing -> case madj of
 			Just adj -> do
-				propigateAdjustedCommits branch adj
-				updateadjustedbranch adj
+				when forpush $
+					propigateAdjustedCommits branch adj
+				when forpull $
+					updateadjustedbranch adj
 			Nothing -> noop
 	
 	-- Update the sync branch to match the new state of the branch
 	inRepo $ updateBranch (syncBranch branch) (fromViewBranch branch)
   where
-	-- The adjusted branch may also need to be updated, if the adjustment
+	-- 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 ()
+	
+	updateview view madj' = updateView view madj' >>= \case
+		Nothing -> noop
+		Just newcommit -> do
+			ok <- inRepo $ Git.Command.runBool
+				[ Param "merge"
+				, Param (Git.fromRef newcommit)
+				]
+			unless ok $
+				giveup $ "failed to update view"
+			case madj' of
+				Nothing -> noop
+				Just adj -> updateadjustedbranch adj
 
 updateBranch :: Git.Branch -> Git.Branch -> Git.Repo -> IO ()
 updateBranch syncbranch updateto g = 
diff --git a/doc/todo/add_--json-progress_support_in_push_and_pull/comment_9_41c737bc7488fc440e07b53504caf06b._comment b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_9_41c737bc7488fc440e07b53504caf06b._comment
new file mode 100644
index 0000000000..d5ff8a6b41
--- /dev/null
+++ b/doc/todo/add_--json-progress_support_in_push_and_pull/comment_9_41c737bc7488fc440e07b53504caf06b._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 9"""
+ date="2026-05-29T13:49:46Z"
+ content="""
+FWIW, I've split updateBranches between pull and push now.
+
+On `git-annex push` all it does is propagate adjusted branches
+changes back to the original branch.
+
+On `git-annex pull` it handles updating the view branch and/or
+propagating changes from the original branch to the adjusted branch.
+
+Also, `git-annex push` was fixed to not merge synced/master into master
+and to not update the adjusted branch when the original branch has changed.
+"""]]

map: Don't try to use dot -Tx11 to display the map
That no longer works in commonly available builds of graphviz,
eg 14.1.2-1 on Debian unstable. In debian stable, it looks like it is still
linked with X and would work. And on OSX it wasn't working a decade ago.
In any case, xdot is better.
diff --git a/CHANGELOG b/CHANGELOG
index c84f72fc43..bbc6ccde7f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,8 @@ git-annex (10.20260526) UNRELEASED; urgency=medium
   * Fix bug that prevented remote.name.annex-web-options from always taking
     effect, and sometimes caused it to be used in situations where it
     should not be.
+  * map: Don't try to use dot -Tx11 to display the map, that no longer
+    works in commonly available builds of graphviz.
 
  -- Joey Hess <id@joeyh.name>  Thu, 28 May 2026 13:13:21 -0400
 
diff --git a/Command/Map.hs b/Command/Map.hs
index 45ee8325f8..ef51c643a8 100644
--- a/Command/Map.hs
+++ b/Command/Map.hs
@@ -61,7 +61,6 @@ start = startingNoMessage (ActionItemOther Nothing) $ do
 					( runViewer file []
 					, runViewer file
 			 			[ ("xdot", [File (fromOsPath file)])
-						, ("dot", [Param "-Tx11", File (fromOsPath file)])
 						]	
 					)
 		)
diff --git a/doc/git-annex-map.mdwn b/doc/git-annex-map.mdwn
index 23585fdae2..dab1505cb2 100644
--- a/doc/git-annex-map.mdwn
+++ b/doc/git-annex-map.mdwn
@@ -10,7 +10,7 @@ git annex map
 
 Helps you keep track of your repositories, and the connections between them,
 by going out and looking at all the ones it can get to, and generating a
-Graphviz file displaying it all. If the `xdot` or `dot` command is available,
+Graphviz file displaying it all. If the `xdot` command is available,
 it is used to display the file to your screen.
   
 This command only connects to hosts that the host it's run on can

bug report
diff --git a/doc/bugs/annex.trashbin_of_local_git_remote_not_supported.mdwn b/doc/bugs/annex.trashbin_of_local_git_remote_not_supported.mdwn
new file mode 100644
index 0000000000..19d4a668e5
--- /dev/null
+++ b/doc/bugs/annex.trashbin_of_local_git_remote_not_supported.mdwn
@@ -0,0 +1,27 @@
+When dropping content from a local git remote that has annex.trashbin
+configured in its git config, there will be an error
+"annex.trashbin is set to the name of an unknown remote" and it will fail
+to drop.
+
+I think this unfortunately is rather difficult to fix.
+
+There is a simple workaround: Change the url of the local 
+git remote to a ssh url.
+
+Fixing this would need Remote.Git to get a list of all the remotes of a git
+remote, in order to pass it to Annex.Content.removeAnnex. But that would
+mean depending on Remote.List. Which depends on Remote.Git. I do think it
+would be possible to work around that by making a version of Remote.List
+which does not include Remote.Git.remote, but takes that as a parameter.
+
+But, bear in mind that code running in Remote.Git in the Annex monad of a
+local git remote is running with pwd not set to that repository. Which
+works fine for all the code in there. But if we then try to use the code
+of every other remote, including all external special remotes, it seems
+very likely that something would break.
+
+Likely the only way to avoid such problems is to have a helper program.
+Ie, git-annex-shell. And if Remote.Git wanted to, it could use
+git-annex-shell for accessing a local git remote. Changing it to do so
+broadly would be a big change. Would it be possible to only do it only
+in this one specifict case? --[[Joey]]

add news item for git-annex 10.20260525
diff --git a/doc/news/version_10.20260115.mdwn b/doc/news/version_10.20260115.mdwn
deleted file mode 100644
index 9835c5150a..0000000000
--- a/doc/news/version_10.20260115.mdwn
+++ /dev/null
@@ -1,20 +0,0 @@
-git-annex 10.20260115 released with [[!toggle text="these changes"]]
-[[!toggleable text="""  * New git configs annex.initwanted, annex.initrequired, and
-    annex.initgroups.
-  * Fix bug that could result in a tree imported from a remote containing
-    missing git blobs.
-  * fix: Populate unlocked pointer files in situations where a git command,
-    like git reset or git stash, leaves them unpopulated.
-  * Pass www-authenticate headers in to to git credential, to support
-    eg, git-credential-oauth.
-  * import: Fix display of some import errors.
-  * external: Respond to GETGITREMOTENAME during INITREMOTE with the remote
-    name.
-  * When displaying sqlite error messages, include the path to the database.
-  * webapp: Remove support for local pairing; use wormhole pairing instead.
-  * git-annex.cabal: Removed pairing build flag, and no longer depends
-    on network-multicast or network-info.
-  * Remove support for building with old versions of persistent and
-    persistent-sqlite.
-  * Removed support for building with ghc older than 9.6.6.
-  * stack.yaml: Update to lts-24.26."""]]
\ No newline at end of file
diff --git a/doc/news/version_10.20260525.mdwn b/doc/news/version_10.20260525.mdwn
new file mode 100644
index 0000000000..16196f945a
--- /dev/null
+++ b/doc/news/version_10.20260525.mdwn
@@ -0,0 +1,4 @@
+git-annex 10.20260525 released with [[!toggle text="these changes"]]
+[[!toggleable text="""  * Fix reversion introduced in 10.20260421 that caused commands
+    like git-annex copy to stop early due to SIGPIPE.
+  * p2phttp: Avoid hanging after HEAD request."""]]
\ No newline at end of file

Added a comment
diff --git a/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_3_fb014cd50ecc1e284b317418fed513c0._comment b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_3_fb014cd50ecc1e284b317418fed513c0._comment
new file mode 100644
index 0000000000..cc3873f4be
--- /dev/null
+++ b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_3_fb014cd50ecc1e284b317418fed513c0._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="matrss"
+ avatar="http://cdn.libravatar.org/avatar/cd1c0b3be1af288012e49197918395f0"
+ subject="comment 3"
+ date="2026-05-25T21:51:04Z"
+ content="""
+> I'm surprised it responds to HEAD at all. It's not a documented part of the p2phttp API, and the implementation is only a GET endpoint. I guess that servant makes GET endpoints also support HEAD? Urk.
+
+Yes, I think all of the \"higher-level http server frameworks\" I've encountered (definitely Flask and the construct Forgejo is using, but also others) automatically support HEAD for all GET endpoints, because a properly implemented HEAD is a subset of GET anyway. I'd expect servant to do the same.
+
+> (I do think it could have also happened without HEAD with just the right timing of the client hanging up on GET, still have not verified that. Of course, we had a whole bug about p2phttp can get stuck with interrupted clients that was dealt with previously, but maybe we missed it back then.)
+
+At least I didn't get the p2phttp server stuck with interrupted clients while investigating this issue (that was my initial guess on what was causing the server to get stuck in the first place), but I did see a different bug that I didn't yet report which caused the p2phttp server to exit with exit code 141 if a client was interrupted at the \"right\" time. This one might already be fixed by <https://git-annex.branchable.com/bugs/SIGPIPE_behavior_change/> though.
+
+> I've also documented HEAD /git-annex/$uuid/key/$key as supported by p2phttp because if you give a HTTP client an URL, I suppose it may try HEAD.
+
+The initial use-case by mih was to point `git annex addurl` at this key endpoint, and that does try HEAD, which triggered the bug. So even git-annex itself does it, it just fell out of the report when I reduced the reproducer as far as possible :)
+
+> Fixed this.
+
+Thank you!
+"""]]

comment
diff --git a/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_2_035e5516ac056ffab476fa9b6727532d._comment b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_2_035e5516ac056ffab476fa9b6727532d._comment
new file mode 100644
index 0000000000..1f457f9e6f
--- /dev/null
+++ b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_2_035e5516ac056ffab476fa9b6727532d._comment
@@ -0,0 +1,22 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2026-05-25T19:11:06Z"
+ content="""
+Fixed this. 
+
+(I do think it could have also happened without HEAD with just the right
+timing of the client hanging up on GET, still have not verified that.
+Of course, we had a whole bug about
+[[bugs/p2phttp_can_get_stuck_with_interrupted_clients]] that was dealt with
+previously, but maybe we missed it back then.)
+
+I've also documented `HEAD /git-annex/$uuid/key/$key` as supported by
+p2phttp because if you give a HTTP client an URL, I suppose it may try
+HEAD.
+
+I would rather that the versioned GET endpoints not also support HEAD,
+just because it's not part of the interface git-annex uses. If I find a way
+to prevent `servant` from automatically supporting HEAD for those, I will
+use it.
+"""]]

p2phttp: Avoid hanging after HEAD request
Fix closeP2PConnection to call closeConnection on both sides.
This fixes a hang when runNet SendBytes is waiting for the
whole bytestring to be processed. In a HEAD request
that never happens. That caused the connection servicer thread
to get stuck waiting on the P2P protocol action to finish.
Documented the HEAD request as supported, since it seems
to make sense to support it.
diff --git a/CHANGELOG b/CHANGELOG
index 5d1308e292..1505164ff0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,7 @@ git-annex (10.20260521) UNRELEASED; urgency=medium
 
   * Fix reversion introduced in 10.20260421 that caused commands
     like git-annex copy to stop early due to SIGPIPE.
+  * p2phttp: Avoid hanging after HEAD request.
 
  -- Joey Hess <id@joeyh.name>  Mon, 25 May 2026 11:29:22 -0400
 
diff --git a/P2P/Http/State.hs b/P2P/Http/State.hs
index 873c24f382..5ed7fc1834 100644
--- a/P2P/Http/State.hs
+++ b/P2P/Http/State.hs
@@ -440,15 +440,18 @@ localP2PConnectionPair connparams relv startworker = do
 	serverrunst <- mkServerRunState connparams
 	asyncworker <- async $
 		startworker serverrunst serverconn
-	let releaseconn = atomically $ void $ tryPutTMVar relv $
+	let releaseconn closeit = atomically $ void $ tryPutTMVar relv $ do
+		when closeit $ do
+			liftIO $ closeConnection clientconn
+			liftIO $ closeConnection serverconn
 		liftIO $ wait asyncworker
 			>>= either throwM return
 	return $ Right $ P2PConnectionPair
 		{ clientRunState = clientrunst
 		, clientP2PConnection = clientconn
 		, serverP2PConnection = serverconn
-		, releaseP2PConnection = releaseconn
-		, closeP2PConnection = releaseconn
+		, releaseP2PConnection = releaseconn False
+		, closeP2PConnection = releaseconn True
 		}
 
 mkP2PConnectionPair
diff --git a/doc/design/p2p_protocol_over_http.mdwn b/doc/design/p2p_protocol_over_http.mdwn
index de9edbc558..76072a05c4 100644
--- a/doc/design/p2p_protocol_over_http.mdwn
+++ b/doc/design/p2p_protocol_over_http.mdwn
@@ -99,6 +99,10 @@ with 404 Not Found.
 Note that the common parameters bypass and clientuuid, while
 accepted, have no effect. Both are optional for this request.
 
+### HEAD /git-annex/$uuid/key/$key
+
+Also supported, like the GET request above.
+
 ### GET /git-annex/$uuid/v4/key/$key
 
 Get the content of a key from the repository with the specified uuid.

comment
diff --git a/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_1_32832c02603ebdb79b23cef9ad3c58d0._comment b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_1_32832c02603ebdb79b23cef9ad3c58d0._comment
new file mode 100644
index 0000000000..640e395ab5
--- /dev/null
+++ b/doc/bugs/p2phttp_key_endpoints_stuck_after_2_head_requests/comment_1_32832c02603ebdb79b23cef9ad3c58d0._comment
@@ -0,0 +1,21 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-05-25T17:38:58Z"
+ content="""
+Reproduced this.
+
+I'm surprised it responds to HEAD at all. It's not a documented part
+of the p2phttp API, and the implementation is only a GET endpoint. 
+I guess that `servant` makes GET endpoints also support HEAD? Urk.
+
+It seems possible that this doesn't only happen on HEAD, but also
+on a GET where the client disconnects without reading any of the
+response body. The code path through looks like it would possibly 
+be the same.
+
+It is getting stuck on `getP2PConnection`. So far I've determined that
+the connection servicer thread gets stuck handling a connection release.
+Which is why the subsequent HEAD fails. So will any subsequent request
+actually. So this can take down a p2phttp server with a single request.
+"""]]

comment
diff --git a/doc/bugs/Better_p2phttp_error_on_full_remote_disk/comment_1_21b78f023ce5ac8f2f9f9029a2801d51._comment b/doc/bugs/Better_p2phttp_error_on_full_remote_disk/comment_1_21b78f023ce5ac8f2f9f9029a2801d51._comment
new file mode 100644
index 0000000000..d179696290
--- /dev/null
+++ b/doc/bugs/Better_p2phttp_error_on_full_remote_disk/comment_1_21b78f023ce5ac8f2f9f9029a2801d51._comment
@@ -0,0 +1,46 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2026-05-25T14:35:11Z"
+ content="""
+Note that the transcripts are not quite what git-annex usually
+outputs, due to [[this bug|bugs/SIGPIPE_behavior_change]], which has now
+been fixed.
+
+I have long disliked how this is displayed in the ssh case too.
+
+---
+
+At the level of the P2P protocol, a solution to this could be for the
+server to send an ERROR message back while the client is still in the
+process of sending the file with DATA. The P2P protocol allows ERROR to be
+sent at any time.
+
+This would look something like P2P.IO.runNet in SendBytes on error,
+trying to getProtocolLine, and when it gets an ERROR returning
+the error message as the `Left ProtoFailureMessage` rather than the current
+exception.
+
+(Something would need to be done in the P2PHandleTMVar to handle proxying
+too.)
+
+For the P2P protocol over http, the `/put` response would 
+look something like:
+
+	{"stored": false, "error-message": "not enough free space, need 1.05 GB more}"}
+
+Currently p2phttp actually replies with `500 Internal Server Error`,
+which git-annex does display to the user. 
+
+----
+
+The other side of the problem though is that the disk space message is displayed
+as a warning. So how would git-annex-shell, or p2phttp intercept it to send
+it along to the client? There would need to be quite a lot of restructuring
+to make that an exception.
+
+There are other warnings as well that it would be good to send to the
+client. One that comes to mind is 
+"transfer already in progress, or unable to take transfer lock".
+So this is a more general problem.
+"""]]

keep default ghc sigPIPE handler
Fix reversion introduced in de5dee49da1dc9ca7733f723299235da1da52b10
It's not acceptable for code in a tryNonAsync to crash the outer context
due to SIGPIPE.
To keep git-annex | head from displaying "resource vanished (Broken pipe)",
made sanitizeTopLevelExceptionMessages Sanitize the content of
IOExceptions, while passing them to the ghc toplevel exception handler,
which will avoid displaying that one.
Sponsored-by: Dartmouth College's OpenNeuro project
diff --git a/CHANGELOG b/CHANGELOG
index e732f509af..5d1308e292 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,10 @@
+git-annex (10.20260521) UNRELEASED; urgency=medium
+
+  * Fix reversion introduced in 10.20260421 that caused commands
+    like git-annex copy to stop early due to SIGPIPE.
+
+ -- Joey Hess <id@joeyh.name>  Mon, 25 May 2026 11:29:22 -0400
+
 git-annex (10.20260520) upstream; urgency=medium
 
   * Behavior change: git-annex sync now defaults to syncing content,
diff --git a/Messages.hs b/Messages.hs
index 25b129e93d..cf76136616 100644
--- a/Messages.hs
+++ b/Messages.hs
@@ -65,9 +65,7 @@ import qualified Data.ByteString.Char8 as S8
 import System.Exit
 import qualified Control.Monad.Catch as M
 import Data.String
-#ifndef mingw32_HOST_OS
-import System.Posix.Signals
-#endif
+import GHC.IO.Exception
 
 import Common
 import Types
@@ -355,27 +353,27 @@ mkPrompter = getConcurrency >>= \case
 				(\v -> putMVar l v >> cleanup)
 				(const $ run a)
 
-{- Catch all (non-async and not ExitCode) exceptions and display, 
- - sanitizing any control characters in the exceptions.
+{- Catch all (non-async) exceptions and display, sanitizing any control
+ - characters in the exceptions.
  -
  - Should only be used at topmost level.
  -}
 sanitizeTopLevelExceptionMessages :: IO a -> IO a
 sanitizeTopLevelExceptionMessages a = do
-#ifndef mingw32_HOST_OS
-	-- By default ghc Ignores sigPIPE, and then does not display
-	-- exceptions like <stdout>: hFlush: resource vanished (Broken pipe)
-	--
-	-- Since this would display such exceptions, instead restore the
-	-- Default sigPIPE behavior, which is for the program to
-	-- immediately exit.
-	void $ installHandler sigPIPE Default Nothing
-#endif
-	a `catches`
-		((M.Handler (\ (e :: ExitCode) -> throwM e)) : nonAsyncHandler go)
+	a `catches` (ignoreExitCode : ignoreBrokenPipe : nonAsyncHandler go)
   where
 	go e = giveup $ show e
 
+	-- Propigate ExitCode exceptions so the program exits with the code
+	-- as usual.
+	ignoreExitCode = M.Handler $ \(e :: ExitCode) -> throwM e
+
+	-- ghc's default toplevel exception handler avoids displaying
+	-- IOExceptions caused by SIGPIPE. So, rethrow the IOException
+	-- to it. But sanitize the exception description first.
+	ignoreBrokenPipe = M.Handler $ \(e :: IOException) ->
+		throwM $ e { ioe_description = safeOutput (ioe_description e) }
+
 {- Used to only run an action that displays a message after the specified
  - number of steps. This is useful when performing an action that can
  - sometimes take a long time, but often does not.
diff --git a/doc/bugs/SIGPIPE_behavior_change.mdwn b/doc/bugs/SIGPIPE_behavior_change.mdwn
new file mode 100644
index 0000000000..0b38d2ade7
--- /dev/null
+++ b/doc/bugs/SIGPIPE_behavior_change.mdwn
@@ -0,0 +1,14 @@
+[[!commit de5dee49da1dc9ca7733f723299235da1da52b10]] changed the SIGPIPE
+behavior. Unfortunately, this causes a `git-annex copy` of 2 files to a ssh
+remote, when the 1st file doesn't fit, to now die of a SIGPIPE, and never
+get a chance to send the 2nd file.
+
+In P2P.IO.runNet, the SendBytes case runs sendExactly inside a tryNonAsync.
+When the peer closes the connection due to the file being too large,
+a SIGPIPE happens at some point when writing to the handle, and it is not
+caught as an exception as a result of this change.
+
+My conclusion is that the SIGPIPE handler needs to be put back the way it
+was. --[[Joey]]
+
+> [[fixed|done]] --[[Joey]] 

yt-dlp with --flat-playlist is not able to provide dates
diff --git a/doc/git-annex-importfeed.mdwn b/doc/git-annex-importfeed.mdwn
index 134afbd80a..11b8aed7f7 100644
--- a/doc/git-annex-importfeed.mdwn
+++ b/doc/git-annex-importfeed.mdwn
@@ -70,6 +70,8 @@ resulting in the new url being downloaded to such a filename.
   or sometimes ".m" if no extension can be determined.
 
   The template also has some variables for when an item was published.
+  (These may not be available when using --scrape, depending on the
+  website.)
   
   itempubyear (YYYY), itempubmonth (MM), itempubday (DD), itempubhour (HH),
   itempubminute (MM), itempubsecond (SS),

add news item for git-annex 10.20260520
diff --git a/doc/news/version_10.20251215.mdwn b/doc/news/version_10.20251215.mdwn
deleted file mode 100644
index e6aa18e260..0000000000
--- a/doc/news/version_10.20251215.mdwn
+++ /dev/null
@@ -1,16 +0,0 @@
-git-annex 10.20251215 released with [[!toggle text="these changes"]]
-[[!toggleable text="""  * Added annex.trashbin configuration.
-  * Added --presentsince, --lackingsince, and --changedsince file
-    matching options.
-  * Added TRANSFER-RETRIEVE-URL extension to the external special remote
-    protocol.
-  * S3: Remote can be configured with an x-amz-tagging header.
-    (Needs aws-0.25)
-  * S3: Support Google Cloud Storage
-    (Needs aws-0.25.1)
-  * S3: Support restore=yes, when used with storageclass=DEEP\_ARCHIVE and
-    similar. This is equivilant to the now deprecated Amazon Glacier.
-    (Needs aws-0.25.2)
-  * Add a build warning when the version of aws being built against is
-    too old to support all features.
-  * stack.yaml: Use aws-0.25.2."""]]
\ No newline at end of file
diff --git a/doc/news/version_10.20260520.mdwn b/doc/news/version_10.20260520.mdwn
new file mode 100644
index 0000000000..3744b131a7
--- /dev/null
+++ b/doc/news/version_10.20260520.mdwn
@@ -0,0 +1,24 @@
+git-annex 10.20260520 released with [[!toggle text="these changes"]]
+[[!toggleable text="""  * Behavior change: git-annex sync now defaults to syncing content,
+    for consistency with push and pull. However, to avoid surprising
+    behavior, this only affects repositories that have preferred content
+    configured.
+    (Use --no-content or configure annex.synccontent to avoid this.)
+  * Behavior change to git-annex pull and push's handling of unwanted
+    files. While previously both commands dropped unwanted files from
+    both the remote and the local repository, now pull only drops unwanted
+    files from the local repository, and push only drops unwanted files
+    from the remote.
+  * info: Report the total size of unused keys found by the last run
+    of git-annex unused.
+  * push: When pushing to a bare git repository, display git push
+    progress before the display of pushed branches.
+  * push, pull, assist: Fix behavior of --content to override the
+    annex.synccontent configuration.
+  * Send git-annex (or other configured) User-Agent when connecting to
+    annex+http remotes.
+  * Support GIT\_SSL\_CAINFO, GIT\_SSL\_CAPATH, http.sslCAPath, and http.sslCAPath
+    when connecting to https servers.
+  * Linux standalone builds now bundle CA certs. They are used only when
+    the system does not have its own CA cert store.
+  * Linux standalone build supports using Fedora's CA cert store location."""]]
\ No newline at end of file

update list of code contributors
I had not updated it since 2018 and since then there have been many
other people sending patches etc. Some on this list may have filed good
bug reports, or only contributed an idea. I grepped the CHANGELOG for
"thanks" to get the list.
Broken out to a separate file to ease updates.
diff --git a/doc/thanks.mdwn b/doc/thanks.mdwn
index f17dc5e749..89e20d22f7 100644
--- a/doc/thanks.mdwn
+++ b/doc/thanks.mdwn
@@ -1,7 +1,8 @@
 Financially, the development of git-annex was made possible by the generous
-donations of many people. I want to say "Thank You!" to each of
-you individually, but until I meet all 1500+ of you, this page will have to
-do. You have my most sincere thanks. --[[Joey]]
+donations of many people, and the feedback and encouragement of many more. 
+I want to say "Thank You!" to each of you individually, but until I meet all
+1500+ of you, this page will have to do. You have my most sincere thanks.
+--[[Joey]]
 
 You can support my git-annex development
 [on Patreon](https://www.patreon.com/joeyh) or
@@ -13,23 +14,10 @@ email <id@joeyh.name>.)
 
 ## code and other bits
 
-git-annex is mostly developed by Joey Hess, with code contributions
-from Sören Brunk, Robie Basak, Klaus Ethgen, Sebastian Reuße, Oliver
-Matthews, guilhem, fftehnik, Ben Gamari, Eric Siegerman, Sean T Parsons,
-Félix Sipma, aristidb, Daniel Brooks, Alper Nebi Yasak,
-James MacMahon, Farhan Kathawala, divergentdave, Gabor Greif, wzhd, Pieter
-Kitslaar, Øyvind A. Holm, Michael Alan Dorman, Ben Boeckel, Robert Schütz,
-Magnus Therning, Yaroslav Halchenko, silvio, Magnus Therning,
-Justin Geibel, Trent, Jon Ander Peñalba, divB, Fraser Tweedale,
-jlebar, Johan Kiviniemi, Alberto Berti, ion, Anarcat, Adam Spiers,
-Peter Simmons, Nicolas Pouillard, Eskild Hustvedt, Nathan Collins,
-Sergei Trofimovich, Mark Wright, Jimmy Tang, Josh Triplett,
-and Joachim Breitner.
-
-Many folks have [[contributed|contribute]] documentation fixes, 
-tips, user support, etc. Two names that come to mind are Anarcat and
-CandyAngel. John Lawrence made the logo. And many others have
-contributed good bug reports and great ideas.
+git-annex is mostly developed by Joey Hess, with contributions
+from [[!inline raw=yes pages="thanks/contributor-list"]] and
+many others who have [[contributed|contribute]] documentation fixes,
+tips, user support, etc. John Lawrence made the logo.
 
 ## financial support, 2024-2025
 
diff --git a/doc/thanks/contributor-list b/doc/thanks/contributor-list
new file mode 100644
index 0000000000..ed4fd05472
--- /dev/null
+++ b/doc/thanks/contributor-list
@@ -0,0 +1,76 @@
+Fraser Tweedale,
+silvio,
+Magnus Therning,
+Ben Boeckel,
+Kitslaar,
+Pieter,
+Eric Siegerman,
+Matthews,
+Oliver,
+Sebastian Reuße,
+Lars Wirzenius,
+Josh Triplett,
+Jimmy Tang,
+Greg Heartsfield,
+Valentin Haenel,
+Mark Wright,
+Joachim Breitner,
+Sergei Trofimovich,
+Nathan Collins,
+Eskild Hustvedt,
+Nicolas Pouillard,
+gregor herrmann,
+Justin Azoff,
+Peter Simmons,
+Oliver Matthews,
+Adam Spiers,
+guilhem,
+Anarcat,
+CandyAngel,
+ion,
+Alberto Berti,
+Johan Kiviniemi,
+jlebar,
+Fraser Tweedale,
+Sören Brunk,
+Ben Gamari,
+divB,
+Jon Ander Peñalba,
+Trent,
+Justin Geibel,
+Yury V. Zaytsev,
+Michael Alan Dorman,
+Øyvind A. Holm,
+wzhd,
+Klaus Ethgen,
+Gabor Greif,
+Robie Basak,
+divergentdave,
+freewheelinfranks,
+Farhan Kathawala,
+Jim Paris,
+James MacMahon,
+Alper Nebi Yasak,
+Daniel Brooks,
+aristidb,
+Félix Sipma,
+Sean T Parsons,
+Eric Siegerman,
+fftehnik,
+Sean Parsons,
+Robert Schütz,
+4omecha,
+Sean Whitton,
+Lukey,
+John Thorvald Wodder II,
+Grond,
+Kyle Meyer,
+James Cook,
+sternenseemann,
+gnezdo,
+Reiko Asakura,
+Peter Simons,
+Gergely Risko,
+Yaroslav Halchenko,
+Oleg Tolmatcev,
+Greg Steuck,

finish sync content transition
Behavior change: git-annex sync now defaults to syncing content,
for consistency with push and pull. However, to avoid surprising
behavior, this only affects repositories that have preferred content
configured.
Note that empty preferred content is treated the same as it not being
configured. See commit 7d8558548b371c669c958b72d216b47893a3ba78.
Remove the warning about the transition.
Sponsored-by: joshingly
diff --git a/CHANGELOG b/CHANGELOG
index 18521b8255..0d43031e89 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,12 +1,17 @@
 git-annex (10.20260422) UNRELEASED; urgency=medium
 
-  * info: Report the total size of unused keys found by the last run
-    of git-annex unused.
+  * Behavior change: git-annex sync now defaults to syncing content,
+    for consistency with push and pull. However, to avoid surprising
+    behavior, this only affects repositories that have preferred content
+    configured.
+    (Use --no-content or configure annex.synccontent to avoid this.)
   * Behavior change to git-annex pull and push's handling of unwanted
     files. While previously both commands dropped unwanted files from
     both the remote and the local repository, now pull only drops unwanted
     files from the local repository, and push only drops unwanted files
     from the remote.
+  * info: Report the total size of unused keys found by the last run
+    of git-annex unused.
   * push: When pushing to a bare git repository, display git push
     progress before the display of pushed branches.
   * Send git-annex (or other configured) User-Agent when connecting to
diff --git a/Command/Sync.hs b/Command/Sync.hs
index 9fda21b21c..099ef88edd 100644
--- a/Command/Sync.hs
+++ b/Command/Sync.hs
@@ -273,7 +273,6 @@ seek' o = startConcurrency transferStages $ do
 			]
 	
 	remotes <- mapM (pushToCreate o) =<< syncRemotes (syncWith o)
-	warnSyncContentTransition o remotes
 	-- Remotes that git can push to and pull from.
 	let gitremotes = filter Remote.gitSyncableRemote remotes
 	-- Remotes that contain annex object content.
@@ -291,22 +290,27 @@ seek' o = startConcurrency transferStages $ do
 				]
 			
 			content <- shouldSyncContent o
+			changehere <- if content
+				then shouldSyncContentWith o =<< getUUID
+				else pure False
 
 			when content $
 				whenM (annexSyncMigrations <$> Annex.getGitConfig) $
 					Command.Migrate.seekDistributedMigrations True
 
 			forM_ (filter isImport contentremotes) $
-				withbranch . importRemote content o
+				withbranch . importRemote changehere o
 			forM_ (filter isThirdPartyPopulated contentremotes) $
 				pullThirdPartyPopulated o
 			
 			when content $ do
+				pushremotes <- filterM (shouldSyncContentWith o . Remote.uuid) contentremotes
+
 				-- Send content to any exports before other
 				-- repositories, in case that lets content
 				-- be dropped from other repositories.
 				exportedcontent <- withbranch $
-					seekExportContent (Just o) contentremotes
+					seekExportContent (Just o) pushremotes
 
 				-- Sync content with remotes, including
 				-- importing from import remotes (since
@@ -319,6 +323,8 @@ seek' o = startConcurrency transferStages $ do
 				syncedcontent <- withbranch $
 					seekSyncContent o
 						(filter shouldsynccontent contentremotes)
+						(filter shouldsynccontent pushremotes)
+						changehere
 
 				-- Transferring content can take a while,
 				-- and other changes can be pushed to the
@@ -852,9 +858,10 @@ newer remote b = do
  -
  - When concurrency is enabled, files are processed concurrently.
  -}
-seekSyncContent :: SyncOptions -> [Remote] -> CurrBranch -> Annex Bool
-seekSyncContent _ [] _ = return False
-seekSyncContent o rs currbranch = do
+seekSyncContent :: SyncOptions -> [Remote] -> [Remote] -> Bool -> CurrBranch -> Annex Bool
+seekSyncContent _ [] _ _ _ = return False
+seekSyncContent _ _ [] False _ = return False
+seekSyncContent o rs pushrs changehere currbranch = do
 	mvar <- liftIO newEmptyMVar
 	bloom <- case keyOptions o of
 		Just WantAllKeys -> ifM preferredcontentmatchesfilenames
@@ -913,7 +920,7 @@ seekSyncContent o rs currbranch = do
 	go ebloom mvar af k = do
 		let ai = OnlyActionOn k (ActionItemKey k)
 		startingNoMessage ai $ do
-			whenM (syncFile o ebloom rs af k) $
+			whenM (syncFile o ebloom rs pushrs changehere af k) $
 				void $ liftIO $ tryPutMVar mvar ()
 			next $ return True
 
@@ -926,7 +933,7 @@ seekSyncContent o rs currbranch = do
 {- If it's preferred content, and we don't have it, get it from one of the
  - listed remotes (preferring the cheaper earlier ones).
  -
- - Send it to each remote that doesn't have it, and for which it's
+ - Send it to each pushrs that doesn't have it, and for which it's
  - preferred content.
  -
  - When pulling, drop it locally if it's not preferred content
@@ -937,11 +944,12 @@ seekSyncContent o rs currbranch = do
  -
  - Returns True if any file transfers were made.
  -}
-syncFile :: SyncOptions -> Either (Maybe (Bloom Key)) (Key -> Annex ()) -> [Remote] -> AssociatedFile -> Key -> Annex Bool
-syncFile o ebloom rs af k = do
+syncFile :: SyncOptions -> Either (Maybe (Bloom Key)) (Key -> Annex ()) -> [Remote] -> [Remote] -> Bool -> AssociatedFile -> Key -> Annex Bool
+syncFile o ebloom rs pushrs changehere af k = do
 	inhere <- inAnnex k
 	locs <- map Remote.uuid <$> Remote.keyPossibilities (Remote.IncludeIgnored False) k
-	let (have, lack) = partition (\r -> Remote.uuid r `elem` locs) rs
+	let have = filter (\r -> Remote.uuid r `elem` locs) rs
+	let lack = filter (\r -> Remote.uuid r `notElem` locs) pushrs
 
 	got <- anyM id =<< handleget have inhere
 	let inhere' = inhere || got
@@ -981,12 +989,14 @@ syncFile o ebloom rs af k = do
 		, pure (not inhere)
 		, wantGet lu True (Just k) af
 		]
-	handleget have inhere = do
-		lu <- prepareLiveUpdate Nothing k AddingKey
-		ifM (wantget lu have inhere)
-			( return [ get lu have ]
-			, return []
-			)
+	handleget have inhere
+		| changehere = do
+			lu <- prepareLiveUpdate Nothing k AddingKey
+			ifM (wantget lu have inhere)
+				( return [ get lu have ]
+				, return []
+				)
+		| otherwise = return []
 	get lu have = includeCommandAction $ starting "get" ai si $
 		stopUnless (getKey' lu k af have) $
 			next $ return True
@@ -1011,10 +1021,10 @@ syncFile o ebloom rs af k = do
 	put lu dest = includeCommandAction $ 
 		Command.Move.toStart' lu dest Command.Move.RemoveNever af k ai si
 	
-	dropfromhere = pullOption o || satisfymode
+	dropfromhere = changehere && (pullOption o || satisfymode)
 
 	dropfromrs
-		| pushOption o || satisfymode = rs
+		| pushOption o || satisfymode = pushrs
 		| otherwise = []
 	
 	satisfymode = operationMode o == SatisfyMode
@@ -1157,48 +1167,43 @@ cleanupRemote remote (Just b, _) =
 	ai = ActionItemOther (Just (UnquotedString (Remote.name remote)))
 	si = SeekInput []
 
+getAnnexSyncContent :: Annex (Maybe Bool)
+getAnnexSyncContent = 
+	getGitConfigVal' annexSyncContent >>= return . \case
+		HasGlobalConfig (Just c) -> Just c
+		HasGitConfig (Just c) -> Just c
+		_ -> Nothing
+
 shouldSyncContent :: SyncOptions -> Annex Bool
 shouldSyncContent o
 	| fromMaybe False (noContentOption o) = pure False
 	| operationMode o == SatisfyMode = pure True
-	-- For git-annex pull and git-annex push and git-annex assist,
-	-- annex.syncontent defaults to True unless set
-	| operationMode o /= SyncMode = annexsynccontent True
+	| operationMode o /= SyncMode = annexsynccontent
 	| fromMaybe False (contentOption o) || not (null (contentOfOption o)) = pure True
-	-- For git-annex sync, 
-	-- annex.syncontent defaults to False unless set
-	| otherwise = annexsynccontent False <||> onlyAnnex o
-  where
-	annexsynccontent d = 
-		getGitConfigVal' annexSyncContent >>= \case
-			HasGlobalConfig (Just c) -> return c
-			HasGitConfig (Just c) -> return c
-			_ -> return d
-
--- See doc/todo/finish_sync_content_transition.mdwn
-warnSyncContentTransition :: SyncOptions -> [Remote] -> Annex ()
-warnSyncContentTransition o remotes
-	| operationMode o /= SyncMode = noop
-	| isJust (noContentOption o) || isJust (contentOption o) = noop
-	| not (null (contentOfOption o)) = noop
-	| otherwise = getGitConfigVal' annexSyncContent >>= \case
-		HasGlobalConfig (Just _) -> noop
-		HasGitConfig (Just _) -> noop
-		_ -> do
-			m <- preferredContentMap
-			hereu <- getUUID
-			when (any (preferredcontentconfigured m) (hereu:map Remote.uuid remotes)) $

(Diff truncated)
Added a comment: Red herring
diff --git a/doc/bugs/auth/comment_3_f118298a40d53b6b49efc88440860f85._comment b/doc/bugs/auth/comment_3_f118298a40d53b6b49efc88440860f85._comment
new file mode 100644
index 0000000000..68412cebf6
--- /dev/null
+++ b/doc/bugs/auth/comment_3_f118298a40d53b6b49efc88440860f85._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mih"
+ avatar="http://cdn.libravatar.org/avatar/f881df265a423e4f24eff27c623148fd"
+ subject="Red herring"
+ date="2026-05-17T07:54:31Z"
+ content="""
+The last two updates (posted yesterday by myself) are misleading and the underlying cause is different. At least some aspects are explained by differences in handling access tokens provisioned by forgejo for action runs vs longer-lived access tokens. A fix for this other issue is in the works for forgejo-aneksajo.
+"""]]

Added a comment: Credential is rejected!
diff --git a/doc/bugs/auth/comment_2_8179e7dc00caf4fea5e47f515f940820._comment b/doc/bugs/auth/comment_2_8179e7dc00caf4fea5e47f515f940820._comment
new file mode 100644
index 0000000000..4516085fb6
--- /dev/null
+++ b/doc/bugs/auth/comment_2_8179e7dc00caf4fea5e47f515f940820._comment
@@ -0,0 +1,81 @@
+[[!comment format=mdwn
+ username="mih"
+ avatar="http://cdn.libravatar.org/avatar/f881df265a423e4f24eff27c623148fd"
+ subject="Credential is rejected!"
+ date="2026-05-16T10:09:34Z"
+ content="""
+I wanted to investigate further and added a credential \"helper\" that documents what was queried
+
+```
+cat << EOT > /usr/local/bin/git-credential-echo
+#!/usr/bin/env bash
+exec cat >&2
+EOT
+chmod +x /usr/local/bin/git-credential-echo
+git config --global --add credential.helper echo
+```
+
+I also switched from `annex push` to `annex copy` (because this is the aspect that failed). I now see (what I could have seen in the log above already). The issue is not that the credential isn't retrieved properly. It is actually rejected, and the superficial/original error is the result of prompting for another valid credential. Here is the log of a copy call:
+
+```
+git annex --debug copy -t origin .
+[2026-05-16 10:01:43.073507233] (Utility.Process) process [639] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"git-annex\"]
+[2026-05-16 10:01:43.075431464] (Utility.Process) process [639] done ExitSuccess
+[2026-05-16 10:01:43.075932187] (Utility.Process) process [640] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/heads/git-annex\"]
+[2026-05-16 10:01:43.077917969] (Utility.Process) process [640] done ExitSuccess
+[2026-05-16 10:01:43.078259638] (Annex.Branch) read remote.log
+[2026-05-16 10:01:43.079214293] (Utility.Process) process [641] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch\"]
+[2026-05-16 10:01:43.081261767] (Annex.Branch) read proxy.log
+[2026-05-16 10:01:43.082419578] (Utility.Process) process [642] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"ls-files\",\"--stage\",\"-z\",\"--error-unmatch\",\"--\",\".\"]
+[2026-05-16 10:01:43.082798858] (Utility.Process) process [643] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch-check=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.083296281] (Utility.Process) process [644] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.083778403] (Utility.Process) process [641] done ExitSuccess
+[2026-05-16 10:01:43.086359241] (Utility.Process) process [645] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+copy static/graph.json (to origin...) [2026-05-16 10:01:43.210382475] (Utility.Process) process [647] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"-c\",\"filter.annex.smudge=\",\"-c\",\"filter.annex.clean=\",\"-c\",\"filter.annex.process=\",\"write-tree\"]
+[2026-05-16 10:01:43.214071033] (Utility.Process) process [647] done ExitSuccess
+[2026-05-16 10:01:43.214666158] (Utility.Process) process [648] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"show-ref\",\"--hash\",\"refs/annex/last-index\"]
+[2026-05-16 10:01:43.218272853] (Utility.Process) process [648] done ExitSuccess
+[2026-05-16 10:01:43.218310804] (Database.Keys) reconcileStaged start
+[2026-05-16 10:01:43.218806637] (Utility.Process) process [649] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch-check=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.219327951] (Utility.Process) process [650] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"cat-file\",\"--batch=%(objectname) %(objecttype) %(objectsize)\",\"--buffer\"]
+[2026-05-16 10:01:43.219921627] (Utility.Process) process [651] read: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"-c\",\"filter.annex.smudge=\",\"-c\",\"filter.annex.clean=\",\"-c\",\"filter.annex.process=\",\"-c\",\"diff.external=\",\"diff\",\"ee47aafecb91c163b0eb9e7ef1a35b07d5b1e0b9\",\"8ea4ce9a4065396e07306bc2f30bcf295837ad6f\",\"--raw\",\"-z\",\"--no-abbrev\",\"-G/annex/objects/\",\"--no-renames\",\"--ignore-submodules=all\",\"--no-textconv\",\"--no-ext-diff\"]
+[2026-05-16 10:01:43.223295855] (Utility.Process) process [651] done ExitSuccess
+[2026-05-16 10:01:43.225251807] (Database.Handle) commitDb start
+[2026-05-16 10:01:43.225610276] (Database.Handle) commitDb done
+[2026-05-16 10:01:43.225676608] (Utility.Process) process [650] done ExitSuccess
+[2026-05-16 10:01:43.2257297] (Utility.Process) process [649] done ExitSuccess
+[2026-05-16 10:01:43.226178161] (Utility.Process) process [652] call: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"update-ref\",\"refs/annex/last-index\",\"8ea4ce9a4065396e07306bc2f30bcf295837ad6f\"]
+[2026-05-16 10:01:43.228765129] (Utility.Process) process [652] done ExitSuccess
+[2026-05-16 10:01:43.22880699] (Database.Keys) reconcileStaged end
+[2026-05-16 10:01:43.246406143] (Utility.Process) process [653] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+[2026-05-16 10:01:43.253477499] (Utility.Process) process [653] done ExitSuccess
+[2026-05-16 10:01:43.274667127] (Utility.Process) process [656] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"reject\"]
+protocol=https
+host=hub.psychoinformatics.de
+username=myuser
+password=***
+[2026-05-16 10:01:43.2873155] (Utility.Process) process [656] done ExitSuccess
+25%   31.98 KiB        70 MiB/s 0s
+100%  126.9 KiB       179 MiB/s 0s[2026-05-16 10:01:43.330200019] (Utility.Process) process [662] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+protocol=https
+host=hub.psychoinformatics.de
+fatal: could not read Username for 'https://hub.psychoinformatics.de': No such device or address
+[2026-05-16 10:01:43.341958838] (Utility.Process) process [662] done ExitFailure 128
+                                  
+  user error (git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"] exited 128)
+[2026-05-16 10:01:43.357710043] (Utility.Process) process [668] chat: git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"]
+protocol=https
+host=hub.psychoinformatics.de
+fatal: could not read Username for 'https://hub.psychoinformatics.de': No such device or address
+[2026-05-16 10:01:43.369272597] (Utility.Process) process [668] done ExitFailure 128
+                                  
+  user error (git [\"--git-dir=.git\",\"--work-tree=.\",\"--literal-pathspecs\",\"-c\",\"annex.debug=true\",\"credential\",\"fill\"] exited 128)
+                                  
+failed
+[2026-05-16 10:01:43.371334491] (Utility.Process) process [645] done ExitSuccess
+[2026-05-16 10:01:43.371445144] (Utility.Process) process [644] done ExitSuccess
+[2026-05-16 10:01:43.371533016] (Utility.Process) process [643] done ExitSuccess
+[2026-05-16 10:01:43.371599238] (Utility.Process) process [642] done ExitSuccess
+copy: 1 failed
+```
+"""]]

diff --git a/doc/bugs/auth.mdwn b/doc/bugs/auth.mdwn
index 187c59fb10..170aa3be31 100644
--- a/doc/bugs/auth.mdwn
+++ b/doc/bugs/auth.mdwn
@@ -64,3 +64,5 @@ My expectation would be that a git-annex push would be able to trigger the oauth
 ### What version of git-annex are you using? On what operating system?
 
 `git-annex version: 10.20260316-gf01ba218ffb36e8607516d9895dfaeaeaf101a05` on Debian forky/sid
+
+[[!tag projects/INM7]]