Skip to content

Commit 227d540

Browse files
committed
Implement reword_commit as an example of rebase engine usage
1 parent 885a370 commit 227d540

File tree

10 files changed

+137
-7
lines changed

10 files changed

+137
-7
lines changed

apps/desktop/src/components/profileSettings/ExperimentalSettings.svelte

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { SETTINGS_SERVICE } from '$lib/config/appSettingsV2';
3-
import { ircEnabled, ircServer, fModeEnabled } from '$lib/config/uiFeatureFlags';
3+
import { ircEnabled, ircServer, fModeEnabled, useNewRebaseEngine } from '$lib/config/uiFeatureFlags';
44
import { USER } from '$lib/user/user';
55
import { inject } from '@gitbutler/core/context';
66
import { CardGroup, Textbox, Toggle } from '@gitbutler/ui';
@@ -83,6 +83,21 @@
8383
/>
8484
{/snippet}
8585
</CardGroup.Item>
86+
<CardGroup.Item labelFor="new-rebase-engine">
87+
{#snippet title()}
88+
New rebase engine
89+
{/snippet}
90+
{#snippet caption()}
91+
Use the new graph-based rebase engine for stack operations.
92+
{/snippet}
93+
{#snippet actions()}
94+
<Toggle
95+
id="new-rebase-engine"
96+
checked={$useNewRebaseEngine}
97+
onclick={() => useNewRebaseEngine.set(!$useNewRebaseEngine)}
98+
/>
99+
{/snippet}
100+
</CardGroup.Item>
86101

87102
{#if $user?.role === 'admin'}
88103
<CardGroup.Item labelFor="single-branch">

apps/desktop/src/lib/config/uiFeatureFlags.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ export type StagingBehavior = 'all' | 'selection' | 'none';
1515
export const stagingBehaviorFeature = persisted<StagingBehavior>('all', 'feature-staging-behavior');
1616
export const fModeEnabled = persisted(true, 'f-mode');
1717
export const newlineOnEnter = persisted(false, 'feature-newline-on-enter');
18+
export const useNewRebaseEngine = persisted(false, 'feature-use-new-rebase-engine');

apps/desktop/src/lib/stacks/stackService.svelte.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useNewRebaseEngine } from '$lib/config/uiFeatureFlags';
12
import { ConflictEntries, type ConflictEntriesObj } from '$lib/files/conflicts';
23
import { sortLikeFileTree } from '$lib/files/filetreeV3';
34
import { showToast } from '$lib/notifications/toasts';
@@ -28,6 +29,7 @@ import {
2829
type ThunkDispatch,
2930
type UnknownAction
3031
} from '@reduxjs/toolkit';
32+
import { get } from 'svelte/store';
3133
import type { StackOrder } from '$lib/branches/branch';
3234
import type { Commit, CommitDetails, UpstreamCommit } from '$lib/branches/v3';
3335
import type { MoveCommitIllegalAction } from '$lib/commits/commit';
@@ -630,7 +632,11 @@ export class StackService {
630632
}
631633

632634
get updateCommitMessage() {
633-
return this.api.endpoints.updateCommitMessage.useMutation();
635+
if (get(useNewRebaseEngine)) {
636+
return this.api.endpoints.updateCommitMessage.useMutation();
637+
} else {
638+
return this.api.endpoints.legacyUpdateCommitMessage.useMutation();
639+
}
634640
}
635641

636642
get newBranch() {
@@ -1181,7 +1187,7 @@ function injectEndpoints(api: ClientState['backendApi'], uiState: UiState) {
11811187
};
11821188
}
11831189
}),
1184-
updateCommitMessage: build.mutation<
1190+
legacyUpdateCommitMessage: build.mutation<
11851191
string,
11861192
{ projectId: string; stackId: string; commitId: string; message: string }
11871193
>({
@@ -1192,6 +1198,17 @@ function injectEndpoints(api: ClientState['backendApi'], uiState: UiState) {
11921198
query: (args) => args,
11931199
invalidatesTags: () => [invalidatesList(ReduxTag.HeadSha)]
11941200
}),
1201+
updateCommitMessage: build.mutation<
1202+
string,
1203+
{ projectId: string; commitId: string; message: string }
1204+
>({
1205+
extraOptions: {
1206+
command: 'reword_commit',
1207+
actionName: 'Update Commit Message'
1208+
},
1209+
query: (args) => args,
1210+
invalidatesTags: () => [invalidatesList(ReduxTag.HeadSha)]
1211+
}),
11951212
newBranch: build.mutation<
11961213
void,
11971214
{ projectId: string; stackId: string; request: { targetPatch?: string; name: string } }

crates/but-api/src/commit.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use bstr::{BString, ByteSlice};
2+
use but_api_macros::but_api;
3+
use but_oplog::legacy::{OperationKind, SnapshotDetails};
4+
use tracing::instrument;
5+
6+
/// Rewords a commit, but without updating the oplog.
7+
///
8+
/// Returns the ID of the newly renamed commit
9+
#[but_api]
10+
#[instrument(err(Debug))]
11+
pub fn reword_commit_only(
12+
ctx: &but_ctx::Context,
13+
commit_id: gix::ObjectId,
14+
message: BString,
15+
) -> anyhow::Result<gix::ObjectId> {
16+
let mut guard = ctx.exclusive_worktree_access();
17+
let (repo, _, graph) = ctx.graph_and_meta_mut_and_repo_from_head(guard.write_permission())?;
18+
19+
but_workspace::commit::reword(&graph, &repo, commit_id, message.as_bstr())
20+
}
21+
22+
/// Apply `existing_branch` to the workspace in the repository that `ctx` refers to, or create the workspace with default name.
23+
///
24+
/// Returns the ID of the newly renamed commit
25+
#[but_api]
26+
#[instrument(err(Debug))]
27+
pub fn reword_commit(
28+
ctx: &but_ctx::Context,
29+
commit_id: gix::ObjectId,
30+
message: BString,
31+
) -> anyhow::Result<gix::ObjectId> {
32+
// NOTE: since this is optional by nature, the same would be true if snapshotting/undo would be disabled via `ctx` app settings, for instance.
33+
let maybe_oplog_entry = but_oplog::UnmaterializedOplogSnapshot::from_details(
34+
ctx,
35+
SnapshotDetails::new(OperationKind::UpdateCommitMessage),
36+
)
37+
.ok();
38+
39+
let res = reword_commit_only(ctx, commit_id, message);
40+
if let Some(snapshot) = maybe_oplog_entry.filter(|_| res.is_ok()) {
41+
snapshot.commit(ctx).ok();
42+
};
43+
res
44+
}

crates/but-api/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ pub mod github;
1616
/// Functions that take a branch as input.
1717
pub mod branch;
1818

19+
/// Functions that operate commits
20+
pub mod commit;
21+
1922
/// Functions that show what changed in various Git entities, like trees, commits and the worktree.
2023
pub mod diff;
2124

crates/but-rebase/src/graph_rebase/materialize.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//! Functions for materializing a rebase
2+
use std::collections::HashMap;
3+
24
use crate::graph_rebase::{Checkouts, rebase::SuccessfulRebase};
35
use anyhow::Result;
46
use but_core::{
@@ -9,9 +11,16 @@ use but_core::{
911
},
1012
};
1113

14+
/// The outcome of a materialize
15+
#[derive(Debug, Clone)]
16+
pub struct MaterializeOutcome {
17+
/// A mapping of any commits that were rewritten as part of the rebase
18+
pub commit_mapping: HashMap<gix::ObjectId, gix::ObjectId>,
19+
}
20+
1221
impl SuccessfulRebase {
1322
/// Materializes a history rewrite
14-
pub fn materialize(mut self) -> Result<()> {
23+
pub fn materialize(mut self) -> Result<MaterializeOutcome> {
1524
let repo = self.repo.clone();
1625
if let Some(memory) = self.repo.objects.take_object_memory() {
1726
memory.persist(self.repo)?;
@@ -40,6 +49,8 @@ impl SuccessfulRebase {
4049

4150
repo.edit_references(self.ref_edits.clone())?;
4251

43-
Ok(())
52+
Ok(MaterializeOutcome {
53+
commit_mapping: self.commit_mapping,
54+
})
4455
}
4556
}

crates/but-workspace/src/commit.rs renamed to crates/but-workspace/src/commit/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use but_core::ref_metadata::MaybeDebug;
44

55
use crate::WorkspaceCommit;
66

7+
pub mod reword;
8+
pub use reword::function::reword;
9+
710
/// A minimal stack for use by [WorkspaceCommit::new_from_stacks()].
811
#[derive(Clone)]
912
pub struct Stack {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! An action to perform a reword of a commit
2+
3+
pub(crate) mod function {
4+
use anyhow::Result;
5+
use bstr::BStr;
6+
use but_rebase::{
7+
commit::DateMode,
8+
graph_rebase::{GraphExt, Step},
9+
};
10+
11+
/// This action will rewrite a commit and any relevant history so it uses
12+
/// the new name.
13+
///
14+
/// Returns the ID of the newly renamed commit
15+
pub fn reword(
16+
graph: &but_graph::Graph,
17+
repo: &gix::Repository,
18+
commit_id: gix::ObjectId,
19+
new_message: &BStr,
20+
) -> Result<gix::ObjectId> {
21+
let mut editor = graph.to_editor(repo)?;
22+
let target_selector = editor.select_commit(commit_id)?;
23+
24+
let mut commit = editor.find_commit(commit_id)?;
25+
commit.message = new_message.to_owned();
26+
let new_id = editor.write_commit(commit, DateMode::CommitterUpdateAuthorKeep)?;
27+
28+
editor.replace(&target_selector, Step::new_pick(new_id));
29+
30+
let outcome = editor.rebase()?;
31+
outcome.materialize()?;
32+
33+
Ok(new_id)
34+
}
35+
}

crates/but-workspace/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub mod branch;
4747
mod changeset;
4848

4949
/// Utility types for the [`WorkspaceCommit`].
50-
pub(crate) mod commit;
50+
pub mod commit;
5151

5252
/// Types used only when obtaining head-information.
5353
///

crates/gitbutler-tauri/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use std::sync::Arc;
1515

1616
use anyhow::bail;
17-
use but_api::{diff, github, legacy};
17+
use but_api::{commit, diff, github, legacy};
1818
use but_claude::{Broadcaster, Claude};
1919
use but_settings::AppSettingsWithDiskSync;
2020
use gitbutler_tauri::{
@@ -383,6 +383,7 @@ fn main() -> anyhow::Result<()> {
383383
claude::claude_cancel_session,
384384
claude::claude_is_stack_active,
385385
claude::claude_compact_history,
386+
commit::tauri_reword_commit::reword_commit
386387
])
387388
.menu(move |handle| menu::build(handle, &app_settings_for_menu))
388389
.on_window_event(|window, event| match event {

0 commit comments

Comments
 (0)