Skip to content

Commit 45784ce

Browse files
committed
Add support for creating dependent branches in workspaces
With and without workspace commits
1 parent 0236892 commit 45784ce

File tree

8 files changed

+106
-8
lines changed

8 files changed

+106
-8
lines changed

crates/but-workspace/src/branch.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ mod create_reference {
611611
pub use create_reference::*;
612612

613613
/// Create a new reference named `ref_name` to point at a commit relative to `anchor`.
614+
/// If `anchor` is `None` this means the branch should be placed above the lower bound of the workspace if this
615+
/// is unambiguous, i.e. if there is no stack, or a single stack.
614616
/// The resulting reference will be created in `repo` and `meta` will be updated for `ref_name` so the workspace
615617
/// contains it, but only if it's a managed workspace, along with branch metadata.
616618
///
@@ -622,20 +624,24 @@ pub use create_reference::*;
622624
/// Return a regenerated Graph that contains the new reference, and from which a new workspace can be derived.
623625
pub fn create_reference_as_segment(
624626
ref_name: &gix::refs::FullNameRef,
625-
anchor: ReferenceAnchor,
627+
anchor: impl Into<Option<ReferenceAnchor>>,
626628
repo: &gix::Repository,
627629
workspace: &but_graph::projection::Workspace<'_>,
628630
meta: &mut impl RefMetadata,
629631
) -> anyhow::Result<but_graph::Graph> {
632+
let anchor = anchor.into();
630633
let commit_id = {
631634
match anchor {
632-
ReferenceAnchor::AtCommit {
635+
None => {
636+
todo!("on top of singular stack/no stack")
637+
}
638+
Some(ReferenceAnchor::AtCommit {
633639
commit_id,
634640
position,
635-
} => position.resolve_commit(
641+
}) => position.resolve_commit(
636642
workspace.lookup_commit(workspace.try_find_owner_indexes_by_commit_id(commit_id)?),
637643
)?,
638-
ReferenceAnchor::AtSegment { ref_name, position } => {
644+
Some(ReferenceAnchor::AtSegment { ref_name, position }) => {
639645
// TODO: can this be unified?
640646
if workspace.has_metadata() {
641647
let (stack_idx, seg_idx) =

crates/but-workspace/tests/fixtures/generated-archives/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@
3131
/with-remotes-and-workspace.tar
3232
/with-conflict.tar
3333
/journey*.tar
34+
/single-branch*.tar

crates/but-workspace/tests/fixtures/scenario/shared.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2+
# Just to save a line in the scripts that use this module
3+
set -eu -o pipefail
4+
15
function remote_tracking_caught_up() {
26
setup_remote_tracking "$1"
37
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#!/usr/bin/env bash
22

33
### Description
4-
# A single default branch with 10 commits in it.
54
set -eu -o pipefail
65

76
git init
7+
echo "A single default branch with 10 commits in it." >.git/description
88
for count in $(seq 10); do
99
echo $count >file && git add . && git commit -m $count
1010
done
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
3+
### Description
4+
source "${BASH_SOURCE[0]%/*}/shared.sh"
5+
6+
git init
7+
echo "Single commit, no main remote/target, no ws commit, but ws-reference" >.git/description
8+
9+
commit M1
10+
git checkout -b gitbutler/workspace
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env bash
2+
3+
### Description
4+
source "${BASH_SOURCE[0]%/*}/shared.sh"
5+
6+
git init
7+
echo "Single commit, target, no ws commit, but ws-reference" >.git/description
8+
9+
commit M1
10+
setup_target_to_match_main
11+
git checkout -b gitbutler/workspace

crates/but-workspace/tests/workspace/branch.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod create_reference_as_segment {
1313
mod with_workspace {
1414
use crate::ref_info::with_workspace_commit::utils::{
1515
StackState, add_stack_with_segments, named_read_only_in_memory_scenario,
16+
named_writable_scenario_with_description,
1617
};
1718
use crate::utils::r;
1819
use but_core::RefMetadata;
@@ -22,6 +23,58 @@ mod create_reference_as_segment {
2223
use but_workspace::branch::ReferenceAnchor;
2324
use but_workspace::branch::ReferencePosition::*;
2425

26+
#[test]
27+
fn journey_no_ws_commit_no_target() -> anyhow::Result<()> {
28+
let (_tmp, repo, meta, desc) =
29+
named_writable_scenario_with_description("single-branch-no-ws-commit-no-target")?;
30+
insta::assert_snapshot!(desc, @"Single commit, no main remote/target, no ws commit, but ws-reference");
31+
32+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @"* 3183e43 (HEAD -> gitbutler/workspace, main) M1");
33+
34+
let graph = but_graph::Graph::from_head(
35+
&repo,
36+
&meta,
37+
Options {
38+
extra_target_commit_id: id_by_rev(&repo, "main").detach().into(),
39+
..Options::limited()
40+
},
41+
)?;
42+
let ws = graph.to_workspace()?;
43+
44+
// And even though setting an extra-target works like it should, i.e a simulated target
45+
// which we can store in absence of a selected target branch…
46+
insta::assert_snapshot!(graph_workspace(&ws), @"📕🏘️⚠️:0:gitbutler/workspace <> ✓! on 3183e43");
47+
48+
// …we chose to work with an open-ended workspace just to struggle more.
49+
let graph = but_graph::Graph::from_head(&repo, &meta, Options::limited())?;
50+
let ws = graph.to_workspace()?;
51+
insta::assert_snapshot!(graph_workspace(&ws), @r"
52+
📕🏘️⚠️:0:gitbutler/workspace <> ✓!
53+
└── ≡:1:main
54+
└── :1:main
55+
└── ·3183e43 (🏘️)
56+
");
57+
58+
Ok(())
59+
}
60+
61+
#[test]
62+
fn journey_no_ws_commit() -> anyhow::Result<()> {
63+
let (_tmp, repo, meta, desc) =
64+
named_writable_scenario_with_description("single-branch-no-ws-commit")?;
65+
insta::assert_snapshot!(desc, @"Single commit, target, no ws commit, but ws-reference");
66+
67+
insta::assert_snapshot!(visualize_commit_graph_all(&repo)?, @"* 3183e43 (HEAD -> gitbutler/workspace, origin/main, main) M1");
68+
69+
let graph = but_graph::Graph::from_head(&repo, &meta, Options::limited())?;
70+
let ws = graph.to_workspace()?;
71+
72+
insta::assert_snapshot!(graph_workspace(&ws), @"📕🏘️⚠️:0:gitbutler/workspace <> ✓refs/remotes/origin/main on 3183e43");
73+
// TODO: more anchor tests.
74+
75+
Ok(())
76+
}
77+
2578
#[test]
2679
fn error1() -> anyhow::Result<()> {
2780
let (repo, mut meta) = named_read_only_in_memory_scenario(

crates/but-workspace/tests/workspace/ref_info/with_workspace_commit/mod.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,9 +3364,14 @@ pub(crate) mod utils {
33643364
Ok((repo, meta))
33653365
}
33663366

3367-
pub fn named_writable_scenario(
3367+
pub fn named_writable_scenario_with_description(
33683368
name: &str,
3369-
) -> anyhow::Result<(TempDir, gix::Repository, VirtualBranchesTomlMetadata)> {
3369+
) -> anyhow::Result<(
3370+
TempDir,
3371+
gix::Repository,
3372+
VirtualBranchesTomlMetadata,
3373+
String,
3374+
)> {
33703375
let (tmp, repo, mut meta) = crate::ref_info::utils::named_writable_scenario(name)?;
33713376
let vb = meta.data_mut();
33723377
vb.default_target = Some(Target {
@@ -3382,7 +3387,15 @@ pub(crate) mod utils {
33823387
.unwrap_or_else(|| gix::hash::Kind::Sha1.null()),
33833388
push_remote_name: None,
33843389
});
3385-
Ok((tmp, repo, meta))
3390+
let desc = std::fs::read_to_string(repo.git_dir().join("description"))?;
3391+
Ok((tmp, repo, meta, desc))
3392+
}
3393+
3394+
pub fn named_writable_scenario(
3395+
name: &str,
3396+
) -> anyhow::Result<(TempDir, gix::Repository, VirtualBranchesTomlMetadata)> {
3397+
let (a, b, c, _desc) = named_writable_scenario_with_description(name)?;
3398+
Ok((a, b, c))
33863399
}
33873400

33883401
pub fn named_read_only_in_memory_scenario_with_description(

0 commit comments

Comments
 (0)