From 107ee21a48c0824f14e98bfb35847996067a8a91 Mon Sep 17 00:00:00 2001 From: "yyimba@qq.com" Date: Sat, 21 Mar 2026 14:45:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96git=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/commands/folders.rs | 12 +++++- src/contexts/git-credential-context.tsx | 54 ++++++++++++------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src-tauri/src/commands/folders.rs b/src-tauri/src/commands/folders.rs index 3ead34c..1f4a615 100644 --- a/src-tauri/src/commands/folders.rs +++ b/src-tauri/src/commands/folders.rs @@ -91,8 +91,10 @@ fn classify_remote_git_error(operation: &str, stderr: &[u8]) -> AppCommandError || lower.contains("could not read username") || lower.contains("could not read password") || lower.contains("logon failed") - || lower.contains("401") - || lower.contains("403") + || lower.contains("terminal prompts disabled") + || lower.contains("the requested url returned error: 401") + || lower.contains("the requested url returned error: 403") + || lower.contains("http basic: access denied") { return AppCommandError::authentication_failed(format!( "git {operation}: authentication failed. Configure a GitHub account in Settings → Version Control." @@ -565,6 +567,12 @@ fn classify_git_clone_error(stderr: &str) -> AppCommandError { if normalized.contains("authentication failed") || normalized.contains("could not read username") + || normalized.contains("could not read password") + || normalized.contains("logon failed") + || normalized.contains("terminal prompts disabled") + || normalized.contains("the requested url returned error: 401") + || normalized.contains("the requested url returned error: 403") + || normalized.contains("http basic: access denied") || normalized.contains("permission denied (publickey)") { return AppCommandError::authentication_failed( diff --git a/src/contexts/git-credential-context.tsx b/src/contexts/git-credential-context.tsx index f3ef42a..1e46f70 100644 --- a/src/contexts/git-credential-context.tsx +++ b/src/contexts/git-credential-context.tsx @@ -325,6 +325,7 @@ export function GitCredentialProvider({ operation: (credentials?: GitCredentials) => Promise, hint: GitRemoteHint ): Promise => { + // First attempt — no explicit credentials try { return await operation() } catch (firstError) { @@ -336,13 +337,6 @@ export function GitCredentialProvider({ ? "github" : "generic" - // Show credential dialog - const creds = await requestCredentials(dialogMode, host) - if (!creds) { - setOpen(false) - throw firstError - } - // Helper: save credentials after successful operation const maybeSave = async (c: GitCredentials) => { if (modeRef.current === "generic" && saveCredentialsRef.current) { @@ -351,15 +345,31 @@ export function GitCredentialProvider({ // GitHub mode saves during handleGitHubSubmit, no extra work needed } - // Retry with credentials - try { - const result = await operation(creds) - await maybeSave(creds) + // Show credential dialog for the first time + let creds = await requestCredentials(dialogMode, host) + if (!creds) { setOpen(false) - return result - } catch (retryError) { - setSubmitting(false) - if (isAuthError(retryError)) { + throw firstError + } + + // Retry loop — keep trying until success or user cancels + let lastError: unknown = firstError + // eslint-disable-next-line no-constant-condition + while (true) { + try { + const result = await operation(creds) + await maybeSave(creds) + setOpen(false) + return result + } catch (retryError) { + lastError = retryError + if (!isAuthError(retryError)) { + // Non-auth error — stop retrying + setOpen(false) + throw retryError + } + // Auth error — show error and let user try again + setSubmitting(false) setError(t("invalidCredentials")) const retryCreds = await new Promise( (resolve) => { @@ -368,20 +378,10 @@ export function GitCredentialProvider({ ) if (!retryCreds) { setOpen(false) - throw retryError - } - try { - const result = await operation(retryCreds) - await maybeSave(retryCreds) - setOpen(false) - return result - } catch (thirdError) { - setOpen(false) - throw thirdError + throw lastError } + creds = retryCreds } - setOpen(false) - throw retryError } } },