diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index 1bf47ac670..15406cb6c2 100644 --- a/crates/git/src/repository.rs +++ b/crates/git/src/repository.rs @@ -106,6 +106,7 @@ pub struct CommitSummary { pub subject: SharedString, /// This is a unix timestamp pub commit_timestamp: i64, + pub has_parent: bool, } #[derive(Clone, Debug, Hash, PartialEq, Eq)] @@ -471,6 +472,7 @@ impl GitRepository for RealGitRepository { let fields = [ "%(HEAD)", "%(objectname)", + "%(parent)", "%(refname)", "%(upstream)", "%(upstream:track)", @@ -1126,6 +1128,7 @@ fn parse_branch_input(input: &str) -> Result> { let mut fields = line.split('\x00'); let is_current_branch = fields.next().context("no HEAD")? == "*"; let head_sha: SharedString = fields.next().context("no objectname")?.to_string().into(); + let parent_sha: SharedString = fields.next().context("no parent")?.to_string().into(); let ref_name: SharedString = fields .next() .context("no refname")? @@ -1149,6 +1152,7 @@ fn parse_branch_input(input: &str) -> Result> { sha: head_sha, subject, commit_timestamp: commiterdate, + has_parent: !parent_sha.is_empty(), }), upstream: if upstream_name.is_empty() { None @@ -1201,7 +1205,7 @@ fn parse_upstream_track(upstream_track: &str) -> Result { fn test_branches_parsing() { // suppress "help: octal escapes are not supported, `\0` is always null" #[allow(clippy::octal_escapes)] - let input = "*\0060964da10574cd9bf06463a53bf6e0769c5c45e\0refs/heads/zed-patches\0refs/remotes/origin/zed-patches\0\01733187470\0generated protobuf\n"; + let input = "*\0060964da10574cd9bf06463a53bf6e0769c5c45e\0\0refs/heads/zed-patches\0refs/remotes/origin/zed-patches\0\01733187470\0generated protobuf\n"; assert_eq!( parse_branch_input(&input).unwrap(), vec![Branch { @@ -1218,6 +1222,7 @@ fn test_branches_parsing() { sha: "060964da10574cd9bf06463a53bf6e0769c5c45e".into(), subject: "generated protobuf".into(), commit_timestamp: 1733187470, + has_parent: false, }) }] ) diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 2616f292e1..09eec43413 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -2237,20 +2237,28 @@ index 1234567..abcdef0 100644 }), ) .child(div().flex_1()) - .child( - panel_icon_button("undo", IconName::Undo) - .icon_size(IconSize::Small) - .icon_color(Color::Muted) - .tooltip(Tooltip::for_action_title( - if self.has_staged_changes() { - "git reset HEAD^ --soft" - } else { - "git reset HEAD^" - }, - &git::Uncommit, - )) - .on_click(cx.listener(|this, _, window, cx| this.uncommit(window, cx))), - ), + .when(commit.has_parent, |this| { + let has_unstaged = self.has_unstaged_changes(); + this.child( + panel_icon_button("undo", IconName::Undo) + .icon_size(IconSize::Small) + .icon_color(Color::Muted) + .tooltip(move |window, cx| { + Tooltip::with_meta( + "Uncommit", + Some(&git::Uncommit), + if has_unstaged { + "git reset HEAD^ --soft" + } else { + "git reset HEAD^" + }, + window, + cx, + ) + }) + .on_click(cx.listener(|this, _, window, cx| this.uncommit(window, cx))), + ) + }), ) } @@ -3559,6 +3567,7 @@ impl ComponentPreview for PanelRepoFooter { sha: "abc123".into(), subject: "Modify stuff".into(), commit_timestamp: 1710932954, + has_parent: true, }), } } @@ -3575,6 +3584,7 @@ impl ComponentPreview for PanelRepoFooter { sha: "abc123".into(), subject: "Modify stuff".into(), commit_timestamp: 1710932954, + has_parent: true, }), } } diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 647d783075..e3430d2183 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -382,6 +382,7 @@ pub fn proto_to_branch(proto: &proto::Branch) -> git::repository::Branch { sha: commit.sha.to_string().into(), subject: commit.subject.to_string().into(), commit_timestamp: commit.commit_timestamp, + has_parent: true, } }), }