Skip to content

Commit 0e606d2

Browse files
authored
Merge pull request #7876 from gitbutlerapp/make-refs-authoritative
make-refs-authoritative
2 parents b42d168 + 04c60cc commit 0e606d2

File tree

46 files changed

+953
-1841
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+953
-1841
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but-cli/src/command/diff.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn locks(current_dir: &Path) -> anyhow::Result<()> {
4343
let worktree_changes = but_core::diff::worktree_changes(&repo)?;
4444
let input_stacks = but_hunk_dependency::workspace_stacks_to_input_stacks(
4545
&repo,
46-
&but_workspace::stacks(&project.gb_dir())?,
46+
&but_workspace::stacks(&project.gb_dir(), &repo)?,
4747
but_workspace::common_merge_base_with_target_branch(&project.gb_dir())?,
4848
)?;
4949
let ranges = but_hunk_dependency::WorkspaceRanges::try_from_stacks(input_stacks)?;

crates/but-cli/src/command/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ pub mod stacks {
116116

117117
pub fn list(current_dir: &Path) -> anyhow::Result<()> {
118118
let project = project_from_path(current_dir)?;
119-
debug_print(but_workspace::stacks(&project.gb_dir()))
119+
let ctx = CommandContext::open(&project, AppSettings::default())?;
120+
let repo = ctx.gix_repository()?;
121+
debug_print(but_workspace::stacks(&project.gb_dir(), &repo))
120122
}
121123

122124
pub fn branches(id: &str, current_dir: &Path) -> anyhow::Result<()> {

crates/but-hunk-dependency/src/ui.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn hunk_dependencies_for_workspace_changes_by_worktree_dir(
1414
) -> anyhow::Result<HunkDependencies> {
1515
let repo = gix::open(worktree_dir).map_err(anyhow::Error::from)?;
1616
let worktree_changes = but_core::diff::worktree_changes(&repo)?;
17-
let stacks = but_workspace::stacks(gitbutler_dir)?;
17+
let stacks = but_workspace::stacks(gitbutler_dir, &repo)?;
1818
let common_merge_base = gitbutler_stack::VirtualBranchesHandle::new(gitbutler_dir)
1919
.get_default_target()?
2020
.sha;

crates/but-hunk-dependency/tests/hunk_dependency/ui.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ mod util {
241241

242242
fn test_ctx_at(script_name: &str, name: &str) -> anyhow::Result<TestContext> {
243243
let ctx = gitbutler_testsupport::read_only::fixture(script_name, name)?;
244-
let stacks = but_workspace::stacks(&ctx.project().gb_dir())?;
244+
let stacks = but_workspace::stacks(&ctx.project().gb_dir(), &ctx.gix_repository()?)?;
245245

246246
Ok(TestContext {
247247
repo: gix::open_opts(&ctx.project().path, gix::open::Options::isolated())?,

crates/but-hunk-dependency/tests/hunk_dependency/workspace_dependencies.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,7 @@ mod util {
901901

902902
fn test_ctx_at(script_name: &str, name: &str) -> anyhow::Result<TestContext> {
903903
let ctx = gitbutler_testsupport::read_only::fixture(script_name, name)?;
904-
let stacks = but_workspace::stacks(&ctx.project().gb_dir())?;
904+
let stacks = but_workspace::stacks(&ctx.project().gb_dir(), &ctx.gix_repository()?)?;
905905
let handle = VirtualBranchesHandle::new(ctx.project().gb_dir());
906906

907907
Ok(TestContext {

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,6 @@ pub fn create_commit_and_update_refs(
381381
refs::rewrite(
382382
repo,
383383
vb,
384-
None,
385384
all_refs_by_id,
386385
[(commit_in_graph, new_commit)],
387386
&mut out.references,
@@ -442,7 +441,6 @@ pub fn create_commit_and_update_refs(
442441
refs::rewrite(
443442
repo,
444443
vb,
445-
workspace_tip,
446444
all_refs_by_id,
447445
rebase
448446
.commit_mapping

crates/but-workspace/src/commit_engine/reference_frame.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ impl ReferenceFrame {
5656
.context("Didn't find stack - was it deleted just now?")?;
5757
Ok(ReferenceFrame {
5858
workspace_tip: Some(head_id.detach()),
59-
branch_tip: Some(stack.head.to_gix()),
59+
branch_tip: Some(stack.head(repo)?.to_gix()),
6060
})
6161
}
6262
InferenceMode::CommitIdInStack(commit_id) => {
6363
for stack in vb.branches.values() {
64-
let stack_tip = stack.head.to_gix();
64+
let stack_tip = stack.head(repo)?.to_gix();
6565
if stack_tip
6666
.attach(repo)
6767
.ancestors()

crates/but-workspace/src/commit_engine/refs.rs

Lines changed: 9 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ use gitbutler_oxidize::{ObjectIdExt, OidExt};
44
use gitbutler_stack::{CommitOrChangeId, VirtualBranchesState};
55
use gix::prelude::ObjectIdExt as _;
66
use gix::refs::transaction::PreviousValue;
7-
use gix::revision::walk::Sorting;
8-
use std::collections::BTreeMap;
97

108
use super::StackSegmentId;
119

@@ -18,16 +16,18 @@ use super::StackSegmentId;
1816
pub fn rewrite(
1917
repo: &gix::Repository,
2018
state: &mut VirtualBranchesState,
21-
workspace_tip: Option<gix::ObjectId>,
2219
mut refs_by_commit_id: gix::hashtable::HashMap<gix::ObjectId, Vec<gix::refs::FullName>>,
2320
changed_commits: impl IntoIterator<Item = (gix::ObjectId, gix::ObjectId)>,
2421
updated_refs: &mut Vec<UpdatedReference>,
2522
stack_segment: Option<&StackSegmentId>,
2623
) -> anyhow::Result<()> {
2724
let mut ref_edits = Vec::new();
2825
let changed_commits: Vec<_> = changed_commits.into_iter().collect();
29-
let change_id_to_id_map = generate_change_ids_to_commit_mapping(repo, &*state, workspace_tip)?;
30-
let mut stacks_ordered: Vec<_> = state.branches.values_mut().collect();
26+
let mut stacks_ordered: Vec<_> = state
27+
.branches
28+
.values_mut()
29+
.filter(|stack| stack.in_workspace)
30+
.collect();
3131
stacks_ordered.sort_by(|a, b| a.name.cmp(&b.name));
3232
for (old, new) in changed_commits {
3333
let old_git2 = old.to_git2();
@@ -38,8 +38,9 @@ pub fn rewrite(
3838
continue; // Dont rewrite refs for other stacks
3939
}
4040
}
41-
if stack.head == old_git2 {
42-
stack.head = new.to_git2();
41+
if stack.head(repo)? == old_git2 {
42+
// Perhaps skip this - the head will be updated later in this call
43+
// stack.set_stack_head_without_persisting(repo, new.to_git2(), None)?;
4344
stack.tree = new
4445
.attach(repo)
4546
.object()?
@@ -65,21 +66,7 @@ pub fn rewrite(
6566
.find_map(|(idx, h)| (h.name == short_name).then_some(idx))
6667
});
6768
for (idx, branch) in stack.heads.iter_mut().rev().enumerate() {
68-
let id = match &mut branch.head() {
69-
CommitOrChangeId::CommitId(id_hex) => {
70-
let Some(id) = gix::ObjectId::from_hex(id_hex.as_bytes()).ok() else {
71-
continue;
72-
};
73-
id
74-
}
75-
#[allow(deprecated)]
76-
CommitOrChangeId::ChangeId(change_id) => {
77-
let Some(id) = change_id_to_id_map.get(change_id) else {
78-
continue;
79-
};
80-
*id
81-
}
82-
};
69+
let id = branch.head_oid(repo)?.to_gix();
8370
if id == old {
8471
if update_up_to_idx.is_some() && Some(idx) > update_up_to_idx {
8572
// Make sure the actual refs also don't update (later)
@@ -135,63 +122,3 @@ pub fn rewrite(
135122
repo.edit_references(ref_edits)?;
136123
Ok(())
137124
}
138-
139-
fn generate_change_ids_to_commit_mapping(
140-
repo: &gix::Repository,
141-
vb: &VirtualBranchesState,
142-
workspace_tip: Option<gix::ObjectId>,
143-
) -> anyhow::Result<BTreeMap<String, gix::ObjectId>> {
144-
let cache = repo.commit_graph_if_enabled()?;
145-
let mut graph = repo.revision_graph(cache.as_ref());
146-
let default_target_tip = vb
147-
.default_target
148-
.as_ref()
149-
.map(|target| -> anyhow::Result<_> {
150-
let r = repo.find_reference(&target.branch.to_string())?;
151-
Ok(r.try_id())
152-
})
153-
.and_then(Result::ok)
154-
.flatten();
155-
156-
let mut out = BTreeMap::new();
157-
let merge_base = if default_target_tip.is_none() {
158-
let Some(workspace_tip) = workspace_tip else {
159-
return Ok(out);
160-
};
161-
let workspace_commit = workspace_tip
162-
.attach(repo)
163-
.object()?
164-
.into_commit()
165-
.decode()?
166-
.to_owned();
167-
if workspace_commit.parents.len() < 2 {
168-
None
169-
} else {
170-
Some(repo.merge_base_octopus(workspace_commit.parents)?)
171-
}
172-
} else {
173-
None
174-
};
175-
for stack in vb.branches.values().filter(|b| b.in_workspace) {
176-
let stack_tip = stack.head.to_gix();
177-
for info in stack_tip
178-
.attach(repo)
179-
.ancestors()
180-
.with_boundary(match default_target_tip {
181-
Some(target_tip) => {
182-
Some(repo.merge_base_with_graph(stack_tip, target_tip, &mut graph)?)
183-
}
184-
None => merge_base,
185-
})
186-
.sorting(Sorting::BreadthFirst)
187-
.all()?
188-
.filter_map(Result::ok)
189-
{
190-
let Some(headers) = but_core::Commit::from_id(info.id.attach(repo))?.headers() else {
191-
continue;
192-
};
193-
out.insert(headers.change_id, info.id);
194-
}
195-
}
196-
Ok(out)
197-
}

crates/but-workspace/src/lib.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,21 @@ impl StackEntry {
127127
/// If the GitButler state file in the provided path is missing or invalid, an error is returned.
128128
///
129129
/// - `gb_dir`: The path to the GitButler state for the project. Normally this is `.git/gitbutler` in the project's repository.
130-
pub fn stacks(gb_dir: &Path) -> Result<Vec<StackEntry>> {
130+
pub fn stacks(gb_dir: &Path, repo: &gix::Repository) -> Result<Vec<StackEntry>> {
131131
let state = state_handle(gb_dir);
132-
Ok(state
132+
133+
state
133134
.list_stacks_in_workspace()?
134135
.into_iter()
135136
.sorted_by_key(|s| s.order)
136-
.map(|stack| StackEntry {
137-
id: stack.id,
138-
branch_names: stack.heads().into_iter().map(Into::into).collect(),
139-
tip: stack.head().to_gix(),
137+
.map(|stack| {
138+
Ok(StackEntry {
139+
id: stack.id,
140+
branch_names: stack.heads().into_iter().map(Into::into).collect(),
141+
tip: stack.head(repo).map(|h| h.to_gix())?,
142+
})
140143
})
141-
.collect())
144+
.collect()
142145
}
143146

144147
/// Represents the pushable status for the current stack.
@@ -213,12 +216,7 @@ pub struct StackDetails {
213216
}
214217

215218
/// Determines if a force push is required to push a branch to its remote.
216-
fn requires_force(
217-
ctx: &CommandContext,
218-
stack: &Stack,
219-
branch: &StackBranch,
220-
remote: &str,
221-
) -> Result<bool> {
219+
fn requires_force(ctx: &CommandContext, branch: &StackBranch, remote: &str) -> Result<bool> {
222220
let upstream = branch.remote_reference(remote);
223221

224222
let reference = match ctx.repo().refname_to_id(&upstream) {
@@ -232,7 +230,7 @@ fn requires_force(
232230
.find_commit(reference)
233231
.context("failed to find upstream commit")?;
234232

235-
let branch_head = branch.head_oid(&ctx.to_stack_context()?, stack)?;
233+
let branch_head = branch.head_oid(&ctx.gix_repository()?)?;
236234
let merge_base = ctx.repo().merge_base(upstream_commit.id(), branch_head)?;
237235

238236
Ok(merge_base != upstream_commit.id())
@@ -260,7 +258,7 @@ pub fn stack_info(gb_dir: &Path, stack_id: StackId, ctx: &CommandContext) -> Res
260258

261259
for branch in branches {
262260
let mut branch_state = BranchState {
263-
requires_force: requires_force(ctx, &stack, &branch, &remote)?,
261+
requires_force: requires_force(ctx, &branch, &remote)?,
264262
..Default::default()
265263
};
266264

@@ -426,6 +424,7 @@ pub fn stack_branches(stack_id: String, ctx: &CommandContext) -> Result<Vec<Bran
426424
let mut stack = state.get_stack(Id::from_str(&stack_id)?)?;
427425
let stack_ctx = ctx.to_stack_context()?;
428426
let mut current_base = stack.merge_base(&stack_ctx)?.to_gix();
427+
let repo = ctx.gix_repository()?;
429428
for internal in stack.branches() {
430429
let upstream_reference = ctx
431430
.repo()
@@ -441,7 +440,7 @@ pub fn stack_branches(stack_id: String, ctx: &CommandContext) -> Result<Vec<Bran
441440
archived: internal.archived,
442441
base_commit: current_base,
443442
};
444-
current_base = internal.head_oid(&stack_ctx, &stack)?.to_gix();
443+
current_base = internal.head_oid(&repo)?.to_gix();
445444
stack_branches.push(result);
446445
}
447446
stack.migrate_change_ids(ctx).ok(); // If it fails thats ok - best effort migration

0 commit comments

Comments
 (0)