Skip to content

Commit dbe397c

Browse files
committed
Show non-main worktrees in but status
Note that this is just a first take, and more integrations are likely needed to get it right. For one, legacy APIs shouldn't be used.
1 parent a771d39 commit dbe397c

File tree

9 files changed

+191
-13
lines changed

9 files changed

+191
-13
lines changed

crates/but-graph/tests/fixtures/scenarios.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,6 @@ mkdir ws
214214
(cd ws
215215
git init ambiguous-worktrees
216216
(cd ambiguous-worktrees
217-
set -x
218217
commit M1
219218
commit M-base
220219

crates/but-workspace/src/branch_details.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub fn branch_details(
8686

8787
Ok(ui::BranchDetails {
8888
name: branch_name.into(),
89+
linked_worktree_id: None, /* not implemented in legacy mode */
8990
remote_tracking_branch: upstream
9091
.as_ref()
9192
.and_then(|upstream| upstream.get().name())
@@ -228,6 +229,7 @@ pub fn branch_details_v3(
228229

229230
Ok(ui::BranchDetails {
230231
name: name.as_bstr().into(),
232+
linked_worktree_id: None, /* probably not needed here */
231233
remote_tracking_branch: remote_tracking_branch.map(|b| b.name().as_bstr().to_owned()),
232234
description: meta.description.clone(),
233235
pr_number: meta.review.pull_request,

crates/but-workspace/src/stacks.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ pub fn stack_details(
391391

392392
branch_details.push(ui::BranchDetails {
393393
name: branch.name().to_owned().into(),
394+
linked_worktree_id: None, /* not implemented in legacy mode */
394395
remote_tracking_branch: upstream_reference.map(Into::into),
395396
description: branch.description.clone(),
396397
pr_number: branch.pr_number,
@@ -549,10 +550,9 @@ impl ui::BranchDetails {
549550
base,
550551
}: &Segment,
551552
) -> anyhow::Result<Self> {
552-
let ref_name = ref_info
553+
let ref_info = ref_info
553554
.clone()
554-
.context("Can't handle a stack yet whose tip isn't pointed to by a ref")?
555-
.ref_name;
555+
.context("Can't handle a stack yet whose tip isn't pointed to by a ref")?;
556556
let (description, updated_at, review_id, pr_number) = metadata
557557
.clone()
558558
.map(|meta| {
@@ -566,10 +566,15 @@ impl ui::BranchDetails {
566566
.unwrap_or_default();
567567
let base_commit = base.unwrap_or(gix::hash::Kind::Sha1.null());
568568
Ok(ui::BranchDetails {
569-
is_remote_head: ref_name
569+
is_remote_head: ref_info
570+
.ref_name
570571
.category()
571572
.is_some_and(|c| matches!(c, gix::refs::Category::RemoteBranch)),
572-
name: ref_name.shorten().into(),
573+
name: ref_info.ref_name.shorten().into(),
574+
linked_worktree_id: ref_info.worktree.and_then(|ws| match ws {
575+
but_graph::Worktree::Main => None,
576+
but_graph::Worktree::LinkedId(id) => Some(id),
577+
}),
573578
remote_tracking_branch: remote_tracking_ref_name
574579
.as_ref()
575580
.map(|full_name| full_name.as_bstr().into()),

crates/but-workspace/src/ui/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ pub struct BranchDetails {
362362
/// The name of the branch.
363363
#[serde(with = "gitbutler_serde::bstring_lossy")]
364364
pub name: BString,
365+
/// The id of the linked worktree that has the reference of `name` checked out.
366+
/// Note that we don't list the main worktree here.
367+
#[serde(with = "gitbutler_serde::bstring_opt_lossy")]
368+
pub linked_worktree_id: Option<BString>,
365369
/// Upstream reference, e.g. `refs/remotes/origin/base-branch-improvements`
366370
#[serde(with = "gitbutler_serde::bstring_opt_lossy")]
367371
pub remote_tracking_branch: Option<BString>,

crates/but/src/status/mod.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ pub fn print_group(
216216
review_map: &std::collections::HashMap<String, Vec<gitbutler_forge::review::ForgeReview>>,
217217
) -> anyhow::Result<()> {
218218
let mut stdout = std::io::stdout();
219+
let repo = project.open_isolated()?;
219220
if let Some(group) = &group {
220221
let mut first = true;
221222
for branch in &group.branch_details {
@@ -244,13 +245,19 @@ pub fn print_group(
244245

245246
writeln!(
246247
stdout,
247-
"┊{}┄{} [{}]{} {} {}",
248-
notch,
249-
id,
250-
branch.name.to_string().green().bold(),
251-
reviews,
252-
no_commits,
253-
stack_mark.clone().unwrap_or_default()
248+
"┊{notch}┄{id} [{branch}{workspace}]{reviews} {no_commits} {stack_mark}",
249+
stack_mark = stack_mark.clone().unwrap_or_default(),
250+
branch = branch.name.to_string().green().bold(),
251+
workspace = branch
252+
.linked_worktree_id
253+
.as_ref()
254+
.and_then(|id| {
255+
let ws = repo.worktree_proxy_by_id(id.as_bstr())?;
256+
let base = ws.base().ok()?;
257+
let base = base.strip_prefix(repo.git_dir()).unwrap_or_else(|_| &base);
258+
format!(" 📁 {base}", base = base.display()).into()
259+
})
260+
.unwrap_or_default()
254261
)
255262
.ok();
256263
*stack_mark = None; // Only show the stack mark for the first branch
Lines changed: 54 additions & 0 deletions
Loading
Lines changed: 50 additions & 0 deletions
Loading

crates/but/tests/but/status.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
use crate::utils::Sandbox;
22
use crate::utils::setup_metadata;
33

4+
#[test]
5+
fn worktrees() -> anyhow::Result<()> {
6+
let env = Sandbox::init_scenario_with_target("two-stacks")?;
7+
8+
// Must set metadata to match the scenario, or else the old APIs used here won't deliver.
9+
setup_metadata(&env, &["A", "B"])?;
10+
11+
env.but("status")
12+
.with_assert(env.assert_with_uuid_and_timestamp_redactions())
13+
.assert()
14+
.success()
15+
.stderr_eq(snapbox::str![])
16+
.stdout_eq(snapbox::file![
17+
"snapshots/two-worktrees/status-with-worktrees.stdout.term.svg"
18+
]);
19+
20+
env.but("status --verbose")
21+
.with_assert(env.assert_with_uuid_and_timestamp_redactions())
22+
.assert()
23+
.success()
24+
.stderr_eq(snapbox::str![])
25+
.stdout_eq(snapbox::file![
26+
"snapshots/two-worktrees/status-with-worktrees-verbose.stdout.term.svg"
27+
]);
28+
Ok(())
29+
}
30+
431
#[test]
532
fn json_shows_paths_as_strings() -> anyhow::Result<()> {
633
let env = Sandbox::init_scenario_with_target("two-stacks")?;
@@ -72,6 +99,7 @@ fn json_shows_paths_as_strings() -> anyhow::Result<()> {
7299
"branchDetails": [
73100
{
74101
"name": "A",
102+
"linkedWorktreeId": null,
75103
"remoteTrackingBranch": null,
76104
"description": null,
77105
"prNumber": null,
@@ -126,6 +154,7 @@ fn json_shows_paths_as_strings() -> anyhow::Result<()> {
126154
"branchDetails": [
127155
{
128156
"name": "B",
157+
"linkedWorktreeId": null,
129158
"remoteTrackingBranch": null,
130159
"description": null,
131160
"prNumber": null,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu -o pipefail
4+
5+
source "${BASH_SOURCE[0]%/*}/shared.sh"
6+
7+
### General Description
8+
9+
# A ws-ref points to a workspace commit, with two stacks inside, each with their own commit.
10+
git init
11+
commit M1
12+
commit M-base
13+
14+
git worktree add -b A .git/gitbutler/worktrees/A
15+
16+
git checkout -b soon-origin-A main
17+
commit A-remote
18+
git checkout main
19+
commit M-advanced
20+
setup_target_to_match_main
21+
22+
git checkout -b B A
23+
commit B
24+
git checkout A
25+
git worktree add .git/gitbutler/worktrees/B B
26+
27+
create_workspace_commit_once A B
28+
setup_remote_tracking soon-origin-A A "move"

0 commit comments

Comments
 (0)