diff --git a/Annex/Import.hs b/Annex/Import.hs
--- a/Annex/Import.hs
+++ b/Annex/Import.hs
@@ -1,6 +1,6 @@
 {- git-annex import from remotes
  -
- - Copyright 2019-2024 Joey Hess <id@joeyh.name>
+ - Copyright 2019-2025 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -64,6 +64,7 @@
 import qualified Database.Export as Export
 import qualified Database.ContentIdentifier as CIDDb
 import qualified Logs.ContentIdentifier as CIDLog
+import qualified Utility.OsString as OS
 import Backend.Utilities
 
 import Control.Concurrent.STM
@@ -1048,6 +1049,10 @@
  - write a git tree that contains that, git will complain and refuse to
  - check it out.
  -
+ - Filters out any paths that contain an empty filename, because git cannot
+ - represent an empty filename in a tree, but some special remotes do
+ - support empty filenames.
+ -
  - Filters out new things not matching the FileMatcher or that are
  - gitignored. However, files that are already in git get imported
  - regardless. (Similar to how git add behaves on gitignored files.)
@@ -1094,19 +1099,35 @@
 
 	wanted dbhandle (loc, (_cid, sz))
 		| ingitdir = pure False
+		| OS.null (fromImportLocation loc) = do
+			warning $ UnquotedString "Cannot import a file with an empty filename"
+			return False
+		| isdirectory = do
+			warning $ UnquotedString "Cannot import a file with a name that appears to be a directory: "
+				<> QuotedPath (fromImportLocation loc)
+			return False
 		| otherwise =
 			isknown <||> (matches <&&> notignored)
 	  where
 		-- Checks, from least to most expensive.
 #ifdef mingw32_HOST_OS
-		ingitdir = ".git" `elem` Posix.splitDirectories (fromOsPath (fromImportLocation loc))
+		ingitdir = ".git" `elem` Posix.splitDirectories loc'
 #else
 		ingitdir = literalOsPath ".git" `elem` splitDirectories (fromImportLocation loc)
 #endif
+#ifdef mingw32_HOST_OS
+		isdirectory = Posix.dropFileName loc' == loc'
+#else
+		isdirectory = dropFileName (fromImportLocation loc) == fromImportLocation loc
+#endif
 		matches = matchesImportLocation matcher loc sz
 		isknown = isKnownImportLocation dbhandle loc
 		notignored = notIgnoredImportLocation importtreeconfig ci loc
-	
+
+#ifdef mingw32_HOST_OS
+		loc' = fromOsPath (fromImportLocation loc)
+#endif
+
 	wantedunder dbhandle root (loc, v) = 
 		wanted dbhandle (importableContentsChunkFullLocation root loc, v)
 
diff --git a/Assistant/WebApp/Configurators/Edit.hs b/Assistant/WebApp/Configurators/Edit.hs
--- a/Assistant/WebApp/Configurators/Edit.hs
+++ b/Assistant/WebApp/Configurators/Edit.hs
@@ -291,9 +291,9 @@
 |]
 getRepoEncryption _ _ = return () -- local repo
 
-getUpgradeRepositoryR  :: RepoId -> Handler ()
-getUpgradeRepositoryR (RepoUUID _) = redirect DashboardR
-getUpgradeRepositoryR r = go =<< liftAnnex (repoIdRemote r)
+getConvertRepositoryR  :: RepoId -> Handler ()
+getConvertRepositoryR (RepoUUID _) = redirect DashboardR
+getConvertRepositoryR r = go =<< liftAnnex (repoIdRemote r)
   where
 	go Nothing = redirect DashboardR
 	go (Just rmt) = do
diff --git a/Assistant/WebApp/routes b/Assistant/WebApp/routes
--- a/Assistant/WebApp/routes
+++ b/Assistant/WebApp/routes
@@ -36,7 +36,7 @@
 /config/repository/edit/new/cloud/#UUID EditNewCloudRepositoryR GET POST
 /config/repository/sync/disable/#RepoId DisableSyncR GET
 /config/repository/sync/enable/#RepoId EnableSyncR GET
-/config/repository/upgrade/#RepoId UpgradeRepositoryR GET
+/config/repository/convert/#RepoId ConvertRepositoryR GET
 
 /config/repository/add/drive AddDriveR GET POST
 /config/repository/add/drive/confirm/#RemovableDrive ConfirmAddDriveR GET
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,16 @@
+git-annex (10.20250630) upstream; urgency=medium
+
+  * Work around git 2.50 bug that caused it to crash when there is a merge
+    conflict with an unlocked annexed file.
+  * Skip and warn when a tree import includes empty filenames,
+    which can happen with eg a S3 bucket.
+  * Avoid a problem with temp file names ending in whitespace on
+    filesystems like VFAT that don't support such filenames.
+  * webapp: Rename "Upgrade Repository" to "Convert Repository"
+    to avoid confusion with git-annex upgrade.
+
+ -- Joey Hess <id@joeyh.name>  Mon, 30 Jun 2025 10:05:18 -0400
+
 git-annex (10.20250605) upstream; urgency=medium
 
   * sync: Push the current branch first, rather than a synced branch,
diff --git a/Database/Keys.hs b/Database/Keys.hs
--- a/Database/Keys.hs
+++ b/Database/Keys.hs
@@ -1,6 +1,6 @@
 {- Sqlite database of information about Keys
  -
- - Copyright 2015-2022 Joey Hess <id@joeyh.name>
+ - Copyright 2015-2025 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -260,7 +260,7 @@
  - is an associated file.
  -}
 reconcileStaged :: Bool -> H.DbQueue -> Annex DbTablesChanged
-reconcileStaged dbisnew qh = ifM isBareRepo
+reconcileStaged dbisnew qh = ifM notneeded
 	( return mempty
 	, do
 		gitindex <- inRepo currentIndexFile
@@ -334,6 +334,14 @@
 	-- index or on the tree that gets written from it.
 	getindextree = inRepo $ \r -> writeTreeQuiet $ r
 		{ gitGlobalOpts = gitGlobalOpts r ++ bypassSmudgeConfig }
+	
+	notneeded = isBareRepo
+		-- Avoid doing anything when run by the 
+	 	-- smudge clean filter. When that happens in a conflicted
+		-- merge situation, running git write-tree
+		-- here would cause git merge to fail with an internal
+		-- error. This works around around that bug in git.
+		<||> Annex.getState Annex.insmudgecleanfilter
 	
 	diff old new =
 		-- Avoid running smudge clean filter, since we want the
diff --git a/Utility/Tmp.hs b/Utility/Tmp.hs
--- a/Utility/Tmp.hs
+++ b/Utility/Tmp.hs
@@ -117,13 +117,15 @@
 relatedTemplate' f
 	| len > templateAddedLength = 
 		{- Some filesystems like FAT have issues with filenames
-		 - ending in ".", so avoid truncating a filename to end
-		 - that way. -}
-		B.dropWhileEnd (== dot) $
+		 - ending in ".", and others like VFAT don't allow a
+		 - filename to end with trailing whitespace, so avoid
+		 - truncating a filename to end that way. -}
+		B.dropWhileEnd disallowed $
 			truncateFilePath (len - templateAddedLength) f
 	| otherwise = f
   where
 	len = B.length f
+	disallowed c = c == dot || isSpace (chr (fromIntegral c))
 	dot = fromIntegral (ord '.')
 #else
 -- Avoids a test suite failure on windows, reason unknown, but
diff --git a/git-annex.cabal b/git-annex.cabal
--- a/git-annex.cabal
+++ b/git-annex.cabal
@@ -1,5 +1,5 @@
 Name: git-annex
-Version: 10.20250605
+Version: 10.20250630
 Cabal-Version: 1.12
 License: AGPL-3
 Maintainer: Joey Hess <id@joeyh.name>
diff --git a/templates/configurators/edit/nonannexremote.hamlet b/templates/configurators/edit/nonannexremote.hamlet
--- a/templates/configurators/edit/nonannexremote.hamlet
+++ b/templates/configurators/edit/nonannexremote.hamlet
@@ -8,11 +8,11 @@
     $if sshrepo
       <p>
         If this repository's ssh server has git-annex installed, you can #
-        upgrade this repository to a full git annex, which will store the
+        convert this repository to a full git annex, which will store the
         contents of your files, not only their metadata.
       <p>
-        <a .btn .btn-default href="@{UpgradeRepositoryR r}">
-          Upgrade Repository
+        <a .btn .btn-default href="@{ConvertRepositoryR r}">
+          Convert Repository
     <h2>
       Repository information
     <p>
