Skip to content

Commit 250482a

Browse files
authored
Merge pull request #140 from acunniffe/fix/range-not-on-branch
commit range on branch fix
2 parents 2d758ff + e5cf94c commit 250482a

File tree

1 file changed

+64
-6
lines changed

1 file changed

+64
-6
lines changed

src/git/repository.rs

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -994,11 +994,71 @@ impl Repository {
994994
}
995995

996996
pub fn commit_range_on_branch(&self, branch_refname: &str) -> Result<CommitRange, GitAiError> {
997+
// Normalize the provided branch ref to fully qualified using rev-parse
998+
let fq_branch = {
999+
let mut rp_args = self.global_args_for_exec();
1000+
rp_args.push("rev-parse".to_string());
1001+
rp_args.push("--verify".to_string());
1002+
rp_args.push("--symbolic-full-name".to_string());
1003+
rp_args.push(branch_refname.to_string());
1004+
1005+
match exec_git(&rp_args) {
1006+
Ok(output) => {
1007+
let s = String::from_utf8(output.stdout).unwrap_or_default();
1008+
let s = s.trim();
1009+
if s.is_empty() {
1010+
if branch_refname.starts_with("refs/") {
1011+
branch_refname.to_string()
1012+
} else {
1013+
format!("refs/heads/{}", branch_refname)
1014+
}
1015+
} else {
1016+
s.to_string()
1017+
}
1018+
}
1019+
Err(_) => {
1020+
if branch_refname.starts_with("refs/") {
1021+
branch_refname.to_string()
1022+
} else {
1023+
format!("refs/heads/{}", branch_refname)
1024+
}
1025+
}
1026+
}
1027+
};
1028+
1029+
// List all local branches
1030+
let mut refs_args = self.global_args_for_exec();
1031+
refs_args.push("for-each-ref".to_string());
1032+
refs_args.push("--format=%(refname)".to_string());
1033+
refs_args.push("refs/heads".to_string());
1034+
let refs_output = exec_git(&refs_args)?;
1035+
let refs_str = String::from_utf8(refs_output.stdout)?;
1036+
let mut other_branches: Vec<String> = Vec::new();
1037+
1038+
for line in refs_str.lines() {
1039+
let refname = line.trim();
1040+
if refname.is_empty() {
1041+
continue;
1042+
}
1043+
if refname == fq_branch {
1044+
continue;
1045+
}
1046+
other_branches.push(refname.to_string());
1047+
}
1048+
1049+
// Build: git log --format=%H --reverse --ancestry-path <branch> --not <other branches>
9971050
let mut log_args = self.global_args_for_exec();
9981051
log_args.push("log".to_string());
999-
log_args.push("--format=%H".to_string()); // Just the commit hash
1000-
log_args.push("--reverse".to_string()); // Oldest first
1052+
log_args.push("--format=%H".to_string());
1053+
log_args.push("--reverse".to_string());
1054+
log_args.push("--ancestry-path".to_string());
10011055
log_args.push(branch_refname.to_string());
1056+
if !other_branches.is_empty() {
1057+
log_args.push("--not".to_string());
1058+
for ob in other_branches {
1059+
log_args.push(ob);
1060+
}
1061+
}
10021062

10031063
let log_output = exec_git(&log_args).map_err(|e| {
10041064
GitAiError::Generic(format!(
@@ -1010,18 +1070,16 @@ impl Repository {
10101070
let log_str = String::from_utf8(log_output.stdout)
10111071
.map_err(|e| GitAiError::Generic(format!("Failed to parse log output: {:?}", e)))?;
10121072

1013-
let commits: Vec<&str> = log_str.lines().collect();
1073+
let commits: Vec<&str> = log_str.lines().filter(|line| !line.is_empty()).collect();
10141074

10151075
if commits.is_empty() {
10161076
return Err(GitAiError::Generic(format!(
1017-
"No commits found on branch {}",
1077+
"No commits found on branch {} unique to this branch",
10181078
branch_refname
10191079
)));
10201080
}
10211081

1022-
// First commit is the oldest (beginning of branch)
10231082
let first_commit = commits.first().unwrap().to_string();
1024-
// Last commit is the newest (tip of branch)
10251083
let last_commit = commits.last().unwrap().to_string();
10261084

10271085
Ok(CommitRange::new(

0 commit comments

Comments
 (0)