修复推送时指定远程后的授权信息不匹配
This commit is contained in:
@@ -32,6 +32,19 @@ async fn prepare_remote_git_cmd(
|
|||||||
credentials: Option<&GitCredentials>,
|
credentials: Option<&GitCredentials>,
|
||||||
db: &AppDatabase,
|
db: &AppDatabase,
|
||||||
app_handle: &tauri::AppHandle,
|
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")
|
cmd.env("GIT_TERMINAL_PROMPT", "0")
|
||||||
.stdin(Stdio::null());
|
.stdin(Stdio::null());
|
||||||
@@ -48,8 +61,11 @@ async fn prepare_remote_git_cmd(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fall back to stored accounts
|
// Fall back to stored accounts, matching against the specified remote
|
||||||
crate::git_credential::try_inject_for_repo(cmd, repo_path, &db.conn, &data_dir).await;
|
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");
|
let mut cmd = crate::process::tokio_command("git");
|
||||||
cmd.args(["push", "--set-upstream", &target_remote, &branch])
|
cmd.args(["push", "--set-upstream", &target_remote, &branch])
|
||||||
.current_dir(&path);
|
.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)?
|
cmd.output().await.map_err(AppCommandError::io)?
|
||||||
} else {
|
} else {
|
||||||
let mut cmd = crate::process::tokio_command("git");
|
let mut cmd = crate::process::tokio_command("git");
|
||||||
cmd.args(["push", &target_remote, &branch])
|
cmd.args(["push", &target_remote, &branch])
|
||||||
.current_dir(&path);
|
.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)?
|
cmd.output().await.map_err(AppCommandError::io)?
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1745,7 +1761,7 @@ pub async fn git_fetch_remote(
|
|||||||
) -> Result<String, AppCommandError> {
|
) -> Result<String, AppCommandError> {
|
||||||
let mut cmd = crate::process::tokio_command("git");
|
let mut cmd = crate::process::tokio_command("git");
|
||||||
cmd.args(["fetch", &name]).current_dir(&path);
|
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
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
|
|||||||
@@ -215,8 +215,16 @@ pub fn inject_credentials(
|
|||||||
|
|
||||||
/// Get the remote URL for the "origin" remote of a repository.
|
/// Get the remote URL for the "origin" remote of a repository.
|
||||||
pub async fn get_remote_url(repo_path: &str) -> Option<String> {
|
pub async fn get_remote_url(repo_path: &str) -> Option<String> {
|
||||||
|
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<String> {
|
||||||
let output = crate::process::tokio_command("git")
|
let output = crate::process::tokio_command("git")
|
||||||
.args(["remote", "get-url", "origin"])
|
.args(["remote", "get-url", remote_name])
|
||||||
.current_dir(repo_path)
|
.current_dir(repo_path)
|
||||||
.output()
|
.output()
|
||||||
.await
|
.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,
|
/// This is the main entry point: given a repo path and a git command,
|
||||||
/// it finds the matching GitHub account and injects credentials.
|
/// 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.
|
/// Returns `true` if credentials were injected.
|
||||||
pub async fn try_inject_for_repo(
|
pub async fn try_inject_for_repo(
|
||||||
cmd: &mut tokio::process::Command,
|
cmd: &mut tokio::process::Command,
|
||||||
repo_path: &str,
|
repo_path: &str,
|
||||||
conn: &DatabaseConnection,
|
conn: &DatabaseConnection,
|
||||||
app_data_dir: &Path,
|
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 {
|
) -> bool {
|
||||||
let settings = match load_github_accounts(conn).await {
|
let settings = match load_github_accounts(conn).await {
|
||||||
Some(s) if !s.accounts.is_empty() => s,
|
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,
|
Some(url) => url,
|
||||||
None => {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ import { gitLog, gitPush, gitPushInfo, gitShowFile } from "@/lib/tauri"
|
|||||||
import { toErrorMessage } from "@/lib/app-error"
|
import { toErrorMessage } from "@/lib/app-error"
|
||||||
import { languageFromPath } from "@/lib/language-detect"
|
import { languageFromPath } from "@/lib/language-detect"
|
||||||
import type { GitLogEntry, GitLogFileChange, GitPushInfo } from "@/lib/types"
|
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) ---
|
// --- File tree types & builder (same as aux-panel-git-log-tab) ---
|
||||||
|
|
||||||
@@ -383,9 +386,14 @@ export function PushWorkspace({
|
|||||||
async function handlePush() {
|
async function handlePush() {
|
||||||
setPushing(true)
|
setPushing(true)
|
||||||
try {
|
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(
|
await withCredentialRetry(
|
||||||
(creds) => gitPush(folderPath, selectedRemote, creds),
|
(creds) => gitPush(folderPath, selectedRemote, creds),
|
||||||
{ folderPath }
|
hint
|
||||||
)
|
)
|
||||||
onPushed?.()
|
onPushed?.()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user