Previously exited non-zero if ANY remote failed, even when others
succeeded. Now fetches each remote individually, prints warnings for
failures, and exits 0 if at least one remote succeeded.
Assisted-by: Claude Opus 4.5 via Amp
@@ -9,7 +9,25 @@ local git = require("wt.git")
---@class wt.cmd.fetch
local M = {}
----Fetch all remotes with pruning
+---Get list of configured remotes
+---@param git_dir string
+---@return string[] remotes
+local function get_remotes(git_dir)
+ local output, code = shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote")
+ if code ~= 0 then
+ return {}
+ end
+ local remotes = {}
+ for line in output:gmatch("[^\n]+") do
+ local trimmed = line:match("^%s*(.-)%s*$")
+ if trimmed and trimmed ~= "" then
+ table.insert(remotes, trimmed)
+ end
+ end
+ return remotes
+end
+
+---Fetch all remotes with pruning, tolerating partial failures
function M.cmd_fetch()
local root, err = git.find_project_root()
if not root then
@@ -18,9 +36,35 @@ function M.cmd_fetch()
end
local git_dir = root .. "/.bare"
- local output, code = shell.run_cmd("GIT_DIR=" .. git_dir .. " git fetch --all --prune")- io.write(output)- if code ~= 0 then
+ local remotes = get_remotes(git_dir)
+
+ if #remotes == 0 then
+ shell.die("no remotes configured", exit.EXIT_USER_ERROR)
+ return
+ end
+
+ local succeeded = 0
+ local failures = {}
+
+ for _, remote in ipairs(remotes) do
+ local output, code = shell.run_cmd("GIT_DIR=" .. git_dir .. " git fetch --prune " .. shell.quote(remote))
+ if code == 0 then
+ succeeded = succeeded + 1
+ io.write(output)
+ else
+ table.insert(failures, { remote = remote, output = output })
+ end
+ end
+
+ for _, f in ipairs(failures) do
+ io.stderr:write("warning: failed to fetch " .. f.remote .. "\n")
+ if f.output and f.output ~= "" then
+ io.stderr:write(f.output)
+ end
+ end
+
+ if succeeded == 0 then
+ io.stderr:write("error: all remotes failed to fetch\n")
os.exit(exit.EXIT_SYSTEM_ERROR)
end
end