Disable uncommit button for parentless commits (#25983)

Closes #25976

There's a couple states that this covers:
- upon `git init`, no footer is shown at all
- after 1 commit (or when on any parentless commit), the uncommit button
is ~disabled~ hidden
- otherwise commit button is shown

Also updated the button with "meta" tooltip showing human readable
description and git command.

Release Notes:

- N/A

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
This commit is contained in:
Julia Ryan 2025-03-05 15:23:05 -08:00 committed by GitHub
parent 4db9ab15a7
commit 0200dda83d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 31 additions and 15 deletions

View file

@ -106,6 +106,7 @@ pub struct CommitSummary {
pub subject: SharedString, pub subject: SharedString,
/// This is a unix timestamp /// This is a unix timestamp
pub commit_timestamp: i64, pub commit_timestamp: i64,
pub has_parent: bool,
} }
#[derive(Clone, Debug, Hash, PartialEq, Eq)] #[derive(Clone, Debug, Hash, PartialEq, Eq)]
@ -471,6 +472,7 @@ impl GitRepository for RealGitRepository {
let fields = [ let fields = [
"%(HEAD)", "%(HEAD)",
"%(objectname)", "%(objectname)",
"%(parent)",
"%(refname)", "%(refname)",
"%(upstream)", "%(upstream)",
"%(upstream:track)", "%(upstream:track)",
@ -1126,6 +1128,7 @@ fn parse_branch_input(input: &str) -> Result<Vec<Branch>> {
let mut fields = line.split('\x00'); let mut fields = line.split('\x00');
let is_current_branch = fields.next().context("no HEAD")? == "*"; let is_current_branch = fields.next().context("no HEAD")? == "*";
let head_sha: SharedString = fields.next().context("no objectname")?.to_string().into(); 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 let ref_name: SharedString = fields
.next() .next()
.context("no refname")? .context("no refname")?
@ -1149,6 +1152,7 @@ fn parse_branch_input(input: &str) -> Result<Vec<Branch>> {
sha: head_sha, sha: head_sha,
subject, subject,
commit_timestamp: commiterdate, commit_timestamp: commiterdate,
has_parent: !parent_sha.is_empty(),
}), }),
upstream: if upstream_name.is_empty() { upstream: if upstream_name.is_empty() {
None None
@ -1201,7 +1205,7 @@ fn parse_upstream_track(upstream_track: &str) -> Result<UpstreamTracking> {
fn test_branches_parsing() { fn test_branches_parsing() {
// suppress "help: octal escapes are not supported, `\0` is always null" // suppress "help: octal escapes are not supported, `\0` is always null"
#[allow(clippy::octal_escapes)] #[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!( assert_eq!(
parse_branch_input(&input).unwrap(), parse_branch_input(&input).unwrap(),
vec![Branch { vec![Branch {
@ -1218,6 +1222,7 @@ fn test_branches_parsing() {
sha: "060964da10574cd9bf06463a53bf6e0769c5c45e".into(), sha: "060964da10574cd9bf06463a53bf6e0769c5c45e".into(),
subject: "generated protobuf".into(), subject: "generated protobuf".into(),
commit_timestamp: 1733187470, commit_timestamp: 1733187470,
has_parent: false,
}) })
}] }]
) )

View file

@ -2237,20 +2237,28 @@ index 1234567..abcdef0 100644
}), }),
) )
.child(div().flex_1()) .child(div().flex_1())
.child( .when(commit.has_parent, |this| {
panel_icon_button("undo", IconName::Undo) let has_unstaged = self.has_unstaged_changes();
.icon_size(IconSize::Small) this.child(
.icon_color(Color::Muted) panel_icon_button("undo", IconName::Undo)
.tooltip(Tooltip::for_action_title( .icon_size(IconSize::Small)
if self.has_staged_changes() { .icon_color(Color::Muted)
"git reset HEAD^ --soft" .tooltip(move |window, cx| {
} else { Tooltip::with_meta(
"git reset HEAD^" "Uncommit",
}, Some(&git::Uncommit),
&git::Uncommit, if has_unstaged {
)) "git reset HEAD^ --soft"
.on_click(cx.listener(|this, _, window, cx| this.uncommit(window, cx))), } 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(), sha: "abc123".into(),
subject: "Modify stuff".into(), subject: "Modify stuff".into(),
commit_timestamp: 1710932954, commit_timestamp: 1710932954,
has_parent: true,
}), }),
} }
} }
@ -3575,6 +3584,7 @@ impl ComponentPreview for PanelRepoFooter {
sha: "abc123".into(), sha: "abc123".into(),
subject: "Modify stuff".into(), subject: "Modify stuff".into(),
commit_timestamp: 1710932954, commit_timestamp: 1710932954,
has_parent: true,
}), }),
} }
} }

View file

@ -382,6 +382,7 @@ pub fn proto_to_branch(proto: &proto::Branch) -> git::repository::Branch {
sha: commit.sha.to_string().into(), sha: commit.sha.to_string().into(),
subject: commit.subject.to_string().into(), subject: commit.subject.to_string().into(),
commit_timestamp: commit.commit_timestamp, commit_timestamp: commit.commit_timestamp,
has_parent: true,
} }
}), }),
} }