From 73789bcb9f37d2d2e53c097c050b008bd10586ef Mon Sep 17 00:00:00 2001 From: xintaofei Date: Mon, 23 Mar 2026 16:49:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8E=A8=E9=80=81=E6=97=B6?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E8=BF=9C=E7=A8=8B=E5=90=8E=E7=9A=84=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E4=BF=A1=E6=81=AF=E4=B8=8D=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/commands/folders.rs | 26 +++++++++++++++++----- src-tauri/src/git_credential.rs | 28 +++++++++++++++++++++--- src/components/layout/push-workspace.tsx | 12 ++++++++-- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src-tauri/src/commands/folders.rs b/src-tauri/src/commands/folders.rs index 3a25490..7d0a054 100644 --- a/src-tauri/src/commands/folders.rs +++ b/src-tauri/src/commands/folders.rs @@ -32,6 +32,19 @@ async fn prepare_remote_git_cmd( credentials: Option<&GitCredentials>, db: &AppDatabase, app_handle: &tauri::AppHandle, +) { + prepare_remote_git_cmd_with_remote(cmd, repo_path, None, credentials, db, app_handle).await; +} + +/// Same as `prepare_remote_git_cmd` but allows specifying a remote name +/// to match credentials against the correct remote URL. +async fn prepare_remote_git_cmd_with_remote( + cmd: &mut tokio::process::Command, + repo_path: &str, + remote_name: Option<&str>, + credentials: Option<&GitCredentials>, + db: &AppDatabase, + app_handle: &tauri::AppHandle, ) { cmd.env("GIT_TERMINAL_PROMPT", "0") .stdin(Stdio::null()); @@ -48,8 +61,11 @@ async fn prepare_remote_git_cmd( ); } } else { - // Fall back to stored accounts - crate::git_credential::try_inject_for_repo(cmd, repo_path, &db.conn, &data_dir).await; + // Fall back to stored accounts, matching against the specified remote + crate::git_credential::try_inject_for_repo_remote( + cmd, repo_path, remote_name, &db.conn, &data_dir, + ) + .await; } } } @@ -948,13 +964,13 @@ pub async fn git_push( let mut cmd = crate::process::tokio_command("git"); cmd.args(["push", "--set-upstream", &target_remote, &branch]) .current_dir(&path); - prepare_remote_git_cmd(&mut cmd, &path, credentials.as_ref(), &db, &app).await; + prepare_remote_git_cmd_with_remote(&mut cmd, &path, Some(&target_remote), credentials.as_ref(), &db, &app).await; cmd.output().await.map_err(AppCommandError::io)? } else { let mut cmd = crate::process::tokio_command("git"); cmd.args(["push", &target_remote, &branch]) .current_dir(&path); - prepare_remote_git_cmd(&mut cmd, &path, credentials.as_ref(), &db, &app).await; + prepare_remote_git_cmd_with_remote(&mut cmd, &path, Some(&target_remote), credentials.as_ref(), &db, &app).await; cmd.output().await.map_err(AppCommandError::io)? }; @@ -1745,7 +1761,7 @@ pub async fn git_fetch_remote( ) -> Result { let mut cmd = crate::process::tokio_command("git"); cmd.args(["fetch", &name]).current_dir(&path); - prepare_remote_git_cmd(&mut cmd, &path, credentials.as_ref(), &db, &app_handle).await; + prepare_remote_git_cmd_with_remote(&mut cmd, &path, Some(&name), credentials.as_ref(), &db, &app_handle).await; let output = cmd .output() diff --git a/src-tauri/src/git_credential.rs b/src-tauri/src/git_credential.rs index e7c07f1..e61474b 100644 --- a/src-tauri/src/git_credential.rs +++ b/src-tauri/src/git_credential.rs @@ -215,8 +215,16 @@ pub fn inject_credentials( /// Get the remote URL for the "origin" remote of a repository. pub async fn get_remote_url(repo_path: &str) -> Option { + get_remote_url_by_name(repo_path, "origin").await +} + +/// Get the remote URL for a specific named remote. +pub async fn get_remote_url_by_name( + repo_path: &str, + remote_name: &str, +) -> Option { let output = crate::process::tokio_command("git") - .args(["remote", "get-url", "origin"]) + .args(["remote", "get-url", remote_name]) .current_dir(repo_path) .output() .await @@ -335,12 +343,25 @@ pub async fn resolve_commit_author( /// /// This is the main entry point: given a repo path and a git command, /// it finds the matching GitHub account and injects credentials. +/// When `remote_name` is provided, uses that remote's URL for credential matching; +/// otherwise defaults to "origin". /// Returns `true` if credentials were injected. pub async fn try_inject_for_repo( cmd: &mut tokio::process::Command, repo_path: &str, conn: &DatabaseConnection, app_data_dir: &Path, +) -> bool { + try_inject_for_repo_remote(cmd, repo_path, None, conn, app_data_dir).await +} + +/// Same as `try_inject_for_repo` but allows specifying the remote name. +pub async fn try_inject_for_repo_remote( + cmd: &mut tokio::process::Command, + repo_path: &str, + remote_name: Option<&str>, + conn: &DatabaseConnection, + app_data_dir: &Path, ) -> bool { let settings = match load_github_accounts(conn).await { Some(s) if !s.accounts.is_empty() => s, @@ -350,10 +371,11 @@ pub async fn try_inject_for_repo( } }; - let remote_url = match get_remote_url(repo_path).await { + let target_remote = remote_name.unwrap_or("origin"); + let remote_url = match get_remote_url_by_name(repo_path, target_remote).await { Some(url) => url, None => { - eprintln!("[GIT_CRED] no remote URL found for {}", repo_path); + eprintln!("[GIT_CRED] no remote URL found for {} (remote: {})", repo_path, target_remote); return false; } }; diff --git a/src/components/layout/push-workspace.tsx b/src/components/layout/push-workspace.tsx index 4d3b986..8263957 100644 --- a/src/components/layout/push-workspace.tsx +++ b/src/components/layout/push-workspace.tsx @@ -55,7 +55,10 @@ import { gitLog, gitPush, gitPushInfo, gitShowFile } from "@/lib/tauri" import { toErrorMessage } from "@/lib/app-error" import { languageFromPath } from "@/lib/language-detect" import type { GitLogEntry, GitLogFileChange, GitPushInfo } from "@/lib/types" -import { useGitCredential } from "@/contexts/git-credential-context" +import { + useGitCredential, + type GitRemoteHint, +} from "@/contexts/git-credential-context" // --- File tree types & builder (same as aux-panel-git-log-tab) --- @@ -383,9 +386,14 @@ export function PushWorkspace({ async function handlePush() { setPushing(true) try { + // Resolve the selected remote's URL for credential matching + const remoteUrl = pushInfoData?.remotes.find( + (r) => r.name === selectedRemote + )?.url + const hint: GitRemoteHint = remoteUrl ? { remoteUrl } : { folderPath } await withCredentialRetry( (creds) => gitPush(folderPath, selectedRemote, creds), - { folderPath } + hint ) onPushed?.() } catch (err) {