Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 39 additions & 21 deletions crates/git/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -757,20 +757,22 @@ pub enum LogSource {
}

impl LogSource {
fn get_args(&self) -> Result<Vec<&str>> {
fn get_args(&self) -> Vec<OsString> {
match self {
LogSource::All => Ok(vec![
"--ignore-missing", // needed in case of unborn HEAD
"--branches",
"--remotes",
"--tags",
"HEAD",
]),
LogSource::Branch(branch) => Ok(vec![branch.as_str()]),
LogSource::Sha(oid) => Ok(vec![
str::from_utf8(oid.as_bytes()).context("Failed to build str from sha")?,
]),
LogSource::Path(path) => Ok(vec!["--follow", "--", path.as_unix_str()]),
LogSource::All => vec![
OsString::from("--ignore-missing"), // needed in case of unborn HEAD
OsString::from("--branches"),
OsString::from("--remotes"),
OsString::from("--tags"),
OsString::from("HEAD"),
],
LogSource::Branch(branch) => vec![OsString::from(branch.as_ref())],
LogSource::Sha(oid) => vec![OsString::from(oid.to_string())],
LogSource::Path(path) => vec![
OsString::from("--follow"),
OsString::from("--"),
OsString::from(path.as_unix_str()),
],
}
}
}
Expand Down Expand Up @@ -3111,8 +3113,12 @@ impl GitRepository for RealGitRepository {
let git = self.git_binary();

async move {
let mut git_log_command = vec!["log", GRAPH_COMMIT_FORMAT, log_order.as_arg()];
git_log_command.extend(log_source.get_args()?);
let mut git_log_command = vec![
OsString::from("log"),
OsString::from(GRAPH_COMMIT_FORMAT),
OsString::from(log_order.as_arg()),
];
git_log_command.extend(log_source.get_args());
let mut command = git.build_command(&git_log_command);
command.stdout(Stdio::piped());
command.stderr(Stdio::piped());
Expand Down Expand Up @@ -3182,22 +3188,22 @@ impl GitRepository for RealGitRepository {
let git = self.git_binary();

async move {
let mut args = vec!["log", SEARCH_COMMIT_FORMAT];
let mut args = vec![OsString::from("log"), OsString::from(SEARCH_COMMIT_FORMAT)];
let hash_query = commit_hash_search_query(search_args.query.as_str())
.map(|query| query.to_ascii_lowercase());

if hash_query.is_none() {
args.push("--fixed-strings");
args.push(OsString::from("--fixed-strings"));

if !search_args.case_sensitive {
args.push("--regexp-ignore-case");
args.push(OsString::from("--regexp-ignore-case"));
}

args.push("--grep");
args.push(search_args.query.as_str());
args.push(OsString::from("--grep"));
args.push(OsString::from(search_args.query.as_ref()));
}

args.extend(log_source.get_args()?);
args.extend(log_source.get_args());
let mut command = git.build_command(&args);
command.stdout(Stdio::piped());
command.stderr(Stdio::null());
Expand Down Expand Up @@ -3970,6 +3976,18 @@ mod tests {
git_command(path, ["init", "-b", "main"]);
}

#[test]
fn test_log_source_sha_uses_hex_arg() {
let sha = "0123456789abcdef0123456789abcdef01234567";
let args = LogSource::Sha(sha.parse().unwrap())
.get_args()
.into_iter()
.map(|arg| arg.into_string().unwrap())
.collect::<Vec<_>>();

assert_eq!(args, vec![sha]);
}

fn clone_remote_repository_with_main_and_feature(temp_dir: &Path) -> (PathBuf, PathBuf) {
let remote_directory = temp_dir.join("remote.git");
let seed_directory = temp_dir.join("seed");
Expand Down
88 changes: 73 additions & 15 deletions crates/git_ui/src/git_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5838,12 +5838,17 @@ impl GitPanel {
return;
};

let Some(branch) = active_repository.read(cx).branch.as_ref() else {
let log_source = {
let repository = active_repository.read(cx);
Self::commit_history_log_source(
repository.branch.as_ref(),
repository.head_commit.as_ref(),
)
};
let Some(log_source) = log_source else {
return;
};

let branch_name = branch.name().to_string();
let log_source = LogSource::Branch(branch_name.into());
let log_order = LogOrder::DateOrder;

// Kick off the git log fetch so data is ready when the user switches to History.
Expand Down Expand Up @@ -5883,22 +5888,56 @@ impl GitPanel {
return;
};

let Some(branch) = active_repository.read(cx).branch.as_ref() else {
let log_source = {
let repository = active_repository.read(cx);
Self::commit_history_log_source(
repository.branch.as_ref(),
repository.head_commit.as_ref(),
)
};
let Some(log_source) = log_source else {
self.commit_history_entries = Some(Rc::from([]));
return;
};

let branch_name = branch.name().to_string();
let log_source = LogSource::Branch(branch_name.into());
let log_order = LogOrder::DateOrder;

self.commit_history_entries = Some(active_repository.update(cx, |repository, cx| {
let response = repository.graph_data(log_source, log_order, 0..usize::MAX, cx);
response
.commits
.iter()
.map(CommitHistoryEntry::from)
.collect()
}));
let (entries, is_loading): (Rc<[CommitHistoryEntry]>, bool) =
active_repository.update(cx, |repository, cx| {
let response = repository.graph_data(log_source, log_order, 0..usize::MAX, cx);
(
response
.commits
.iter()
.map(CommitHistoryEntry::from)
.collect(),
response.is_loading,
)
});
self.commit_history_entries = if is_loading && entries.is_empty() {
None
} else {
Some(entries)
};
}

fn commit_history_log_source(
branch: Option<&Branch>,
head_commit: Option<&CommitDetails>,
) -> Option<LogSource> {
if let Some(branch) = branch {
return Some(LogSource::Branch(branch.name().to_string().into()));
}

let sha = match head_commit?.sha.as_ref().parse::<Oid>() {
Ok(sha) => sha,
Err(error) => {
log::warn!("failed to parse HEAD commit sha for commit history: {error}");
return None;
}
};

Some(LogSource::Sha(sha))
}

fn git_remote(&self, cx: &mut App) -> Option<GitRemote> {
Expand Down Expand Up @@ -8156,7 +8195,7 @@ pub(crate) fn commit_title_exceeds_limit(title: &str, max_length: usize) -> bool
#[cfg(test)]
mod tests {
use git::{
repository::repo_path,
repository::{CommitDetails, repo_path},
status::{StatusCode, UnmergedStatus, UnmergedStatusCode},
};
use gpui::{TestAppContext, UpdateGlobal, VisualTestContext, px};
Expand Down Expand Up @@ -8268,6 +8307,25 @@ mod tests {
handle.await;
}

#[test]
fn test_commit_history_log_source_uses_head_commit_when_detached() {
let sha = "0123456789abcdef0123456789abcdef01234567";
let source = GitPanel::commit_history_log_source(
None,
Some(&CommitDetails {
sha: sha.into(),
..Default::default()
}),
);

assert_eq!(source, Some(LogSource::Sha(sha.parse().unwrap())));
}

#[test]
fn test_commit_history_log_source_is_empty_without_branch_or_head() {
assert_eq!(GitPanel::commit_history_log_source(None, None), None);
}

fn assert_editor_opened_with_path(
workspace: &Entity<Workspace>,
expected_path: &Path,
Expand Down
Loading