Skip to content

Commit 28f1e12

Browse files
committed
docs: Add some more docs for move commit and branch
Add documentation explaining the usage of some parameters for move_commit and move_branch. Also document the reasoning behind using the workspace projection for this operations.
1 parent 34f5cd2 commit 28f1e12

File tree

2 files changed

+82
-15
lines changed

2 files changed

+82
-15
lines changed

crates/but-workspace/src/branch/move_branch.rs

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub(super) mod function {
3030

3131
/// Move a branch between stacks in the `workspace`.
3232
///
33+
/// `editor` is assumed to have been generated from the given `workspace`
34+
/// and therefore aligned.
35+
///
3336
/// `subject_branch_name` is the full reference name of the branch to move.
3437
///
3538
/// `target_branch_name` is the full reference name of the branch to move the subject
@@ -43,18 +46,8 @@ pub(super) mod function {
4346
subject_branch_name: &FullNameRef,
4447
target_branch_name: &FullNameRef,
4548
) -> anyhow::Result<Outcome> {
46-
let Some(source) = workspace.find_segment_and_stack_by_refname(subject_branch_name) else {
47-
bail!(
48-
"Couldn't find branch to move in workspace with reference name: {subject_branch_name}"
49-
);
50-
};
51-
52-
let Some(destination) = workspace.find_segment_and_stack_by_refname(target_branch_name)
53-
else {
54-
bail!(
55-
"Couldn't find target branch to move in workspace with reference name: {target_branch_name}"
56-
);
57-
};
49+
let (source, destination) =
50+
retrieve_branches_and_containers(workspace, subject_branch_name, target_branch_name)?;
5851

5952
let Some(workspace_head) = workspace.tip_commit().map(|commit| commit.id) else {
6053
bail!("Couldn't find workspace head.")
@@ -123,6 +116,56 @@ pub(super) mod function {
123116
ws_meta,
124117
})
125118
}
119+
120+
/// A segment and its container stack.
121+
type WorkspaceSegmentContext<'a> = (
122+
&'a but_graph::projection::Stack,
123+
&'a but_graph::projection::StackSegment,
124+
);
125+
126+
/// Determine the surrounding context of the subject and target branches.
127+
///
128+
/// Currently, this looks into the workspace projection in order to determine **where to take the branch from and to**.
129+
///
130+
/// ### The issue
131+
/// It's impossible to know for sure what is the exact intention of 'moving a branch' inside a complex git graph.
132+
/// Any commit, can have N children and M parents. 'Moving' it somewhere else can imply:
133+
/// - Disconnecting all parents and children, and inserting it somewhere else.
134+
/// - Disconnecting the first parent and all children, and then inserting.
135+
/// - Disconnecting *some* parents and *some* children, and then inserting it.
136+
///
137+
/// This condition holds for every commit in a branch.
138+
///
139+
/// ### The GitButler assumption
140+
/// In the context of a GitButler workspace (as of this writting), we want to disconnect the branch (segment) from
141+
/// the stack, and insert it on top of another. In graph terms, this means that we:
142+
/// - Disconnect the reference node from the base segment (the branch under the subject or the target base)
143+
/// - Disconnect the last commit node of the child segment (the branch over the subject or the workspace commit)
144+
/// - Nothing else. Other parentage and childrent are kept, since this is what we care about in a GB workspace world.
145+
///
146+
/// ### What the future holds
147+
/// In the future, where we're not afraid of complex graphs, we've figured out UX and data wrangling,
148+
/// the concept of a segment might not hold, and hence we'll have to figure out a better way of dermining
149+
/// what to cut (e.g. letting the clients decide what to cut).
150+
fn retrieve_branches_and_containers<'a>(
151+
workspace: &'a but_graph::projection::Workspace,
152+
subject_branch_name: &FullNameRef,
153+
target_branch_name: &FullNameRef,
154+
) -> anyhow::Result<(WorkspaceSegmentContext<'a>, WorkspaceSegmentContext<'a>)> {
155+
let Some(source) = workspace.find_segment_and_stack_by_refname(subject_branch_name) else {
156+
bail!(
157+
"Couldn't find branch to move in workspace with reference name: {subject_branch_name}"
158+
);
159+
};
160+
161+
let Some(destination) = workspace.find_segment_and_stack_by_refname(target_branch_name)
162+
else {
163+
bail!(
164+
"Couldn't find target branch to move in workspace with reference name: {target_branch_name}"
165+
);
166+
};
167+
Ok((source, destination))
168+
}
126169
}
127170

128171
/// Get the right disconnect parameters for the given subject segment and source stack.

crates/but-workspace/src/commit/move_commit.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ pub(crate) mod function {
99

1010
/// Move a commit.
1111
///
12+
/// `editor` is assumed to have been generated from the given `workspace`
13+
/// and therefore aligned.
14+
///
15+
/// `subject_commit` - The commit to be moved.
16+
///
17+
/// `anchor` - A git graph node selector to move the subject commit relative to.
18+
///
19+
/// `side` - The side relative to the anchor at which to insert the subject commit.
20+
///
1221
/// The subject commit will be detached from the source segment, and inserted relative
1322
/// to a given anchor (branch or commit).
1423
pub fn move_commit(
@@ -21,9 +30,7 @@ pub(crate) mod function {
2130
let (subject_commit_selector, subject_commit) =
2231
editor.find_selectable_commit(subject_commit)?;
2332

24-
let Some(subject) = workspace.find_commit_and_containers(&subject_commit.id) else {
25-
bail!("Failed to find the commit to move in the workspace.");
26-
};
33+
let subject = retrieve_commit_and_containers(workspace, &subject_commit)?;
2734

2835
let (source_stack, source_segment, _) = subject;
2936

@@ -50,16 +57,33 @@ pub(crate) mod function {
5057
index_of_subject_commit,
5158
)?;
5259

60+
// Step 2: Disconnect
5361
editor.disconnect_segment_from(
5462
commit_delimiter.clone(),
5563
child_to_disconnect,
5664
parent_to_disconnect,
5765
false,
5866
)?;
67+
68+
// Step 3: Insert
5969
editor.insert_segment(anchor, commit_delimiter, side)?;
6070
editor.rebase()
6171
}
6272

73+
fn retrieve_commit_and_containers<'a>(
74+
workspace: &'a but_graph::projection::Workspace,
75+
subject_commit: &but_core::CommitOwned,
76+
) -> anyhow::Result<(
77+
&'a but_graph::projection::Stack,
78+
&'a but_graph::projection::StackSegment,
79+
&'a but_graph::projection::StackCommit,
80+
)> {
81+
let Some(subject) = workspace.find_commit_and_containers(&subject_commit.id) else {
82+
bail!("Failed to find the commit to move in the workspace.");
83+
};
84+
Ok(subject)
85+
}
86+
6387
/// Determine which children to disconnect, based on the position of the subject commit in the segment.
6488
fn determine_child_selector(
6589
editor: &Editor,

0 commit comments

Comments
 (0)