From 67dccc053ae5652684d45e94396f3ceb6fcc68d4 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Tue, 26 May 2026 22:02:09 +0700 Subject: [PATCH 1/2] Fix tracking for git default branch --- src/cook/fetch.rs | 23 ++++++++---- src/cook/fs.rs | 89 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/cook/fetch.rs b/src/cook/fetch.rs index 2d869bde..e5267fa7 100644 --- a/src/cook/fetch.rs +++ b/src/cook/fetch.rs @@ -253,19 +253,28 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result } } (None, false) => { - let (_, remote_branch, remote_name, remote_url) = - get_git_remote_tracking(&source_dir)?; - // TODO: how to get default branch and compare it here? - if let Some(branch) = branch - && branch != &remote_branch + let remote = get_git_remote_tracking(&source_dir)?; + if remote.local_branch != remote.tracking_branch { + false + } else if let Some(branch) = branch + && branch != &remote.tracking_branch { false - } else if remote_name != "origin" || &remote_url != chop_dot_git(git) { + } else if branch.is_none() && remote.remote_branch != remote.tracking_branch + { + false + } else if remote.remote_name != "origin" + || &remote.remote_url != chop_dot_git(git) + { false } else { git_run_fetch(logger, &source_dir, git)?; fetch_is_ran = true; - match get_git_fetch_rev(&source_dir, &remote_url, &remote_branch) { + match get_git_fetch_rev( + &source_dir, + &remote.remote_url, + &remote.remote_branch, + ) { Ok(fetch_rev) => fetch_rev == head_rev, Err(e) => { log_to_pty!(logger, "{}", e); diff --git a/src/cook/fs.rs b/src/cook/fs.rs index 87f9a344..c7fe1c0e 100644 --- a/src/cook/fs.rs +++ b/src/cook/fs.rs @@ -367,25 +367,45 @@ pub fn get_git_fetch_rev(dir: &PathBuf, remote_url: &str, remote_branch: &str) - )()) } -/// (local_branch_name, remote_branch, remote_name, remote_url) -/// -> ("fix_stuff", "master", "origin", "https://gitlab.redox-os.org/willnode/redox") -pub fn get_git_remote_tracking(dir: &PathBuf) -> Result<(String, String, String, String)> { - let git_head = dir.join(".git/HEAD"); - let git_config = dir.join(".git/config"); +#[derive(Default, Debug)] +pub struct GitRemoteTracking { + /// from .git/HEAD + pub local_branch: String, + /// from .git/config -> [branch ].merge + pub tracking_branch: String, + /// from .git/config -> [branch ].remote (usually "origin") + pub remote_name: String, + /// from refs/remotes//HEAD (the default branch on remote) + pub remote_branch: String, + /// from .git/config -> [remote ].url + pub remote_url: String, +} - let head_content = read_to_string(&git_head)?; - - if !head_content.starts_with("ref: ") { - let sha = head_content.trim_end().to_string(); - return Ok((sha, "".to_string(), "".to_string(), "".to_string())); +impl GitRemoteTracking { + pub fn detached(rev: String) -> Self { + Self { + local_branch: rev, + ..Default::default() + } } +} - let local_branch_path = head_content["ref: ".len()..].trim_end(); - let local_branch_name = get_git_branch_name(local_branch_path)?; +pub fn get_git_remote_tracking(dir: &PathBuf) -> Result { + let git_head = dir.join(".git/HEAD"); + let local_branch = { + let head_content = read_to_string(&git_head)?; + if !head_content.starts_with("ref: ") { + let rev = head_content.trim_end().to_string(); + return Ok(GitRemoteTracking::detached(rev)); + } + let path = &head_content["ref: ".len()..]; + get_git_branch_name(path.trim_end())? + }; + let git_config = dir.join(".git/config"); let config_content = read_to_string(&git_config)?; - let branch_section = format!("[branch \"{}\"]", local_branch_name); + let branch_section = format!("[branch \"{}\"]", local_branch); let mut remote_name: Option = None; let mut remote_branch: Option = None; let mut parsing_branch_section = false; @@ -413,13 +433,13 @@ pub fn get_git_remote_tracking(dir: &PathBuf) -> Result<(String, String, String, } } - let remote_name_str = remote_name.ok_or_else(wrap_other_err!( + let remote_name = remote_name.ok_or_else(wrap_other_err!( "Branch {:?} is not tracking a remote", - local_branch_name + local_branch ))?; - let remote_branch_str = remote_branch.unwrap_or("".into()); + let tracking_branch = remote_branch.unwrap_or("".into()); - let remote_section = format!("[remote \"{}\"]", remote_name_str); + let remote_section = format!("[remote \"{}\"]", remote_name); let mut remote_url: Option = None; let mut parsing_remote_section = false; @@ -445,17 +465,30 @@ pub fn get_git_remote_tracking(dir: &PathBuf) -> Result<(String, String, String, } } - let remote_url_str = remote_url.ok_or_else(wrap_other_err!( + let remote_url = remote_url.ok_or_else(wrap_other_err!( "Could not find URL for remote {:?} in .git/config.", - remote_name_str + remote_name ))?; - Ok(( - local_branch_name, - remote_branch_str, - remote_name_str, - remote_url_str, - )) + let remote_branch = { + let head_path = format!(".git/refs/remotes/{remote_name}/HEAD"); + let git_remote_head = dir.join(&head_path); + let head_content = read_to_string(&git_remote_head)?; + let path = head_content + .get("ref: ".len()..) + .ok_or_else(wrap_other_err!( + "Malformed content {:?} in {head_path}", + head_content + ))?; + get_git_branch_name(path.trim_end())? + }; + Ok(GitRemoteTracking { + local_branch, + tracking_branch, + remote_name, + remote_branch, + remote_url, + }) } pub(crate) fn chop_dot_git(url: &str) -> &str { @@ -465,14 +498,14 @@ pub(crate) fn chop_dot_git(url: &str) -> &str { url } -fn get_git_branch_name(local_branch_path: &str) -> Result { +fn get_git_branch_name(branch_path: &str) -> Result { // TODO: incorrectly handle branch with slashes - Ok(local_branch_path + Ok(branch_path .split('/') .last() .ok_or_else(wrap_other_err!( "Failed to parse branch name of {:?}", - local_branch_path + branch_path ))? .to_string()) } From 0fd6b596ef5a4812ce126a5e5e7288dda98b7175 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Tue, 26 May 2026 22:52:51 +0700 Subject: [PATCH 2/2] Replace git checkout branch logic from bash --- src/cook/fetch.rs | 44 +++++++++++++++++++------------------------- src/cook/fs.rs | 38 ++++++++++++++++++++++++++++++-------- src/cook/script.rs | 12 ------------ 3 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/cook/fetch.rs b/src/cook/fetch.rs index e5267fa7..8c30205e 100644 --- a/src/cook/fetch.rs +++ b/src/cook/fetch.rs @@ -252,22 +252,9 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result } } } - (None, false) => { - let remote = get_git_remote_tracking(&source_dir)?; - if remote.local_branch != remote.tracking_branch { - false - } else if let Some(branch) = branch - && branch != &remote.tracking_branch - { - false - } else if branch.is_none() && remote.remote_branch != remote.tracking_branch - { - false - } else if remote.remote_name != "origin" - || &remote.remote_url != chop_dot_git(git) - { - false - } else { + (None, false) => match get_git_remote_tracking(&source_dir) { + Ok(remote) if !remote.check_updated(git, branch) => false, + Ok(remote) => { git_run_fetch(logger, &source_dir, git)?; fetch_is_ran = true; match get_git_fetch_rev( @@ -282,7 +269,11 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result } } } - } + Err(e) => { + log_to_pty!(logger, "{}", e); + false + } + }, _ => false, } }; @@ -312,14 +303,17 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result command.arg("-C").arg(&source_dir); command.arg("checkout").arg(rev); run_command(command, logger)?; - } else if !is_redox() { - //TODO: complicated stuff to check and reset branch to origin - //TODO: redox can't undestand this (got exit status 1) - let mut command = Command::new("bash"); - command.arg("-c").arg(GIT_RESET_BRANCH); - if let Some(branch) = branch { - command.env("BRANCH", branch); - } + } else { + let branch = match branch { + Some(branch) => branch.clone(), + None => get_git_remote_branch(&source_dir, "origin")?, + }; + let mut command = Command::new("git"); + command + .arg("checkout") + .arg("-B") + .arg(&branch) + .arg(format!("remotes/origin/{branch}")); command.current_dir(&source_dir); run_command(command, logger)?; } diff --git a/src/cook/fs.rs b/src/cook/fs.rs index c7fe1c0e..c3c5f864 100644 --- a/src/cook/fs.rs +++ b/src/cook/fs.rs @@ -388,6 +388,23 @@ impl GitRemoteTracking { ..Default::default() } } + pub fn check_updated(&self, url: &str, branch: &Option) -> bool { + if self.local_branch != self.tracking_branch { + return false; + } + if let Some(branch) = branch + && branch != &self.tracking_branch + { + return false; + } + if branch.is_none() && self.remote_branch != self.tracking_branch { + return false; + } + if self.remote_name != "origin" || &self.remote_url != chop_dot_git(url) { + return false; + } + true + } } pub fn get_git_remote_tracking(dir: &PathBuf) -> Result { @@ -470,6 +487,17 @@ pub fn get_git_remote_tracking(dir: &PathBuf) -> Result { remote_name ))?; + let remote_branch = get_git_remote_branch(dir, &remote_name)?; + Ok(GitRemoteTracking { + local_branch, + tracking_branch, + remote_name, + remote_branch, + remote_url, + }) +} + +pub fn get_git_remote_branch(dir: &PathBuf, remote_name: &str) -> Result { let remote_branch = { let head_path = format!(".git/refs/remotes/{remote_name}/HEAD"); let git_remote_head = dir.join(&head_path); @@ -482,16 +510,10 @@ pub fn get_git_remote_tracking(dir: &PathBuf) -> Result { ))?; get_git_branch_name(path.trim_end())? }; - Ok(GitRemoteTracking { - local_branch, - tracking_branch, - remote_name, - remote_branch, - remote_url, - }) + Ok(remote_branch) } -pub(crate) fn chop_dot_git(url: &str) -> &str { +fn chop_dot_git(url: &str) -> &str { if url.ends_with(".git") { return &url[..url.len() - ".git".len()]; } diff --git a/src/cook/script.rs b/src/cook/script.rs index f3f32eef..8db59215 100644 --- a/src/cook/script.rs +++ b/src/cook/script.rs @@ -401,18 +401,6 @@ do done "#; -pub(crate) static GIT_RESET_BRANCH: &str = r#" -ORIGIN_BRANCH="$(git branch --remotes | grep '^ origin/HEAD -> ' | cut -d ' ' -f 5-)" -if [ -n "$BRANCH" ] -then - ORIGIN_BRANCH="origin/$BRANCH" -fi - -if [ "$(git rev-parse HEAD)" != "$(git rev-parse $ORIGIN_BRANCH)" ] -then - git checkout -B "$(echo "$ORIGIN_BRANCH" | cut -d / -f 2-)" "$ORIGIN_BRANCH" -fi"#; - pub static KILL_ALL_PID: &str = r#" THISPID=$$ CHILDREN=$(ps -o pid= --ppid $PID | grep -v $THISPID);