Skip to content

Commit 3d40291

Browse files
authored
Merge pull request #13144 from gitbutlerapp/push-yxrrsmornyko
Lite: add ability to delete (discard) commits
2 parents d64f321 + 8b24363 commit 3d40291

6 files changed

Lines changed: 157 additions & 30 deletions

File tree

apps/lite/electron/src/ipc.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
TreeChange,
1717
TreeChanges,
1818
UICommitCreateResult,
19+
UICommitDiscardResult,
1920
UICommitInsertBlankResult,
2021
UICommitMoveResult,
2122
UICommitRewordResult,
@@ -84,6 +85,11 @@ export interface CommitCreateParams {
8485
message: string;
8586
}
8687

88+
export interface CommitDiscardParams {
89+
projectId: string;
90+
subjectCommitId: string;
91+
}
92+
8793
export interface CommitMoveChangesBetweenParams {
8894
projectId: string;
8995
sourceCommitId: string;
@@ -166,6 +172,7 @@ export interface LiteElectronApi {
166172
changesInWorktree: (projectId: string) => Promise<WorktreeChanges>;
167173
commitAmend: (params: CommitAmendParams) => Promise<UICommitCreateResult>;
168174
commitCreate: (params: CommitCreateParams) => Promise<UICommitCreateResult>;
175+
commitDiscard: (params: CommitDiscardParams) => Promise<UICommitDiscardResult>;
169176
commitDetailsWithLineStats: (params: CommitDetailsWithLineStatsParams) => Promise<CommitDetails>;
170177
commitInsertBlank: (params: CommitInsertBlankParams) => Promise<UICommitInsertBlankResult>;
171178
commitMove: (params: CommitMoveParams) => Promise<UICommitMoveResult>;
@@ -203,6 +210,7 @@ export const liteIpcChannels = {
203210
changesInWorktree: "workspace:changes-in-worktree",
204211
commitAmend: "workspace:commit-amend",
205212
commitCreate: "workspace:commit-create",
213+
commitDiscard: "workspace:commit-discard",
206214
commitDetailsWithLineStats: "workspace:commit-details-with-line-stats",
207215
commitInsertBlank: "workspace:commit-insert-blank",
208216
commitMove: "workspace:commit-move",

apps/lite/electron/src/main.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
type BranchDiffParams,
99
type CommitAmendParams,
1010
type CommitCreateParams,
11+
type CommitDiscardParams,
1112
type CommitDetailsWithLineStatsParams,
1213
type CommitInsertBlankParams,
1314
type CommitMoveParams,
@@ -34,6 +35,7 @@ import {
3435
changesInWorktree,
3536
commitAmend,
3637
commitCreate,
38+
commitDiscard,
3739
commitInsertBlank,
3840
commitReword,
3941
commitUncommitChanges,
@@ -94,6 +96,11 @@ function registerIpcHandlers(): void {
9496
(_e, { projectId, relativeTo, side, changes, message }: CommitCreateParams) =>
9597
commitCreate(projectId, relativeTo, side, changes, message),
9698
);
99+
ipcMain.handle(
100+
liteIpcChannels.commitDiscard,
101+
(_e, { projectId, subjectCommitId }: CommitDiscardParams) =>
102+
commitDiscard(projectId, subjectCommitId),
103+
);
97104
ipcMain.handle(
98105
liteIpcChannels.commitDetailsWithLineStats,
99106
(_e, { projectId, commitId }: CommitDetailsWithLineStatsParams) =>

apps/lite/electron/src/preload.cts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type {
1111
RefInfo,
1212
TreeChanges,
1313
UICommitCreateResult,
14+
UICommitDiscardResult,
1415
UICommitInsertBlankResult,
1516
UICommitMoveResult,
1617
UICommitRewordResult,
@@ -51,6 +52,8 @@ const api: LiteElectronApi = {
5152
ipcRenderer.invoke("workspace:commit-amend", params) as Promise<UICommitCreateResult>,
5253
commitCreate: (params) =>
5354
ipcRenderer.invoke("workspace:commit-create", params) as Promise<UICommitCreateResult>,
55+
commitDiscard: (params) =>
56+
ipcRenderer.invoke("workspace:commit-discard", params) as Promise<UICommitDiscardResult>,
5457
commitDetailsWithLineStats: (params) =>
5558
ipcRenderer.invoke(
5659
"workspace:commit-details-with-line-stats",

apps/lite/ui/src/api/mutations.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ export const commitCreateMutationOptions = mutationOptions({
4040
},
4141
});
4242

43+
export const commitDiscardMutationOptions = mutationOptions({
44+
mutationFn: window.lite.commitDiscard,
45+
onSuccess: async (_data, _input, _ctx, { client }) => {
46+
await client.invalidateQueries();
47+
},
48+
});
49+
4350
export const commitRewordMutationOptions = mutationOptions({
4451
mutationFn: window.lite.commitReword,
4552
onSuccess: async (_data, _input, _ctx, { client }) => {

apps/lite/ui/src/routes/project/$id/workspace/route.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
commitCreateMutationOptions,
3+
commitDiscardMutationOptions,
34
commitInsertBlankMutationOptions,
45
commitRewordMutationOptions,
56
updateBranchNameMutationOptions,
@@ -780,6 +781,7 @@ const CommitMenuPopup: FC<{
780781
parts: typeof Menu | typeof ContextMenu;
781782
}> = ({ projectId, commitId, canReword, onReword, parts }) => {
782783
const commitInsertBlank = useMutation(commitInsertBlankMutationOptions);
784+
const commitDiscard = useMutation(commitDiscardMutationOptions);
783785
const { Popup, Item, SubmenuRoot, SubmenuTrigger, Positioner } = parts;
784786

785787
return (
@@ -818,6 +820,18 @@ const CommitMenuPopup: FC<{
818820
</Popup>
819821
</Positioner>
820822
</SubmenuRoot>
823+
<Item
824+
className={uiStyles.menuItem}
825+
disabled={commitDiscard.isPending}
826+
onClick={() => {
827+
commitDiscard.mutate({
828+
projectId,
829+
subjectCommitId: commitId,
830+
});
831+
}}
832+
>
833+
{commitDiscard.isPending ? "Deleting commit…" : "Delete commit"}
834+
</Item>
821835
</Popup>
822836
);
823837
};

packages/but-sdk/src/generated/index.d.ts

Lines changed: 118 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,50 @@
11
/* auto-generated by NAPI-RS */
22
/* eslint-disable */
33
/**
4-
* Absorb multiple changes into their target commits as per the provided absorption plan.
4+
* Absorb the changes described by `absorption_plan` using the behavior documented by
5+
* [`absorb_with_perm()`].
56
*
6-
* Returns the total amount of rejected diff specs.
7+
* This acquires exclusive worktree access from `ctx` before creating the
8+
* snapshot and rewriting commits.
9+
*
10+
* Before applying the plan, this records an `Absorb` oplog snapshot and refreshes the
11+
* synthetic workspace commit after the rewritten commits are in place.
712
*/
813
export declare function absorb(projectId: string, absorptionPlan: Array<CommitAbsorption>): Promise<number>
914

10-
/** Generate an absorption plan based on the provided target, based on hunk dependencies, assignments and other heuristics */
15+
/**
16+
* Build an absorption plan for `target` using the behavior documented by
17+
* [`absorption_plan_with_perm()`].
18+
*/
1119
export declare function absorptionPlan(projectId: string, target: AbsorptionTarget): Promise<Array<CommitAbsorption>>
1220

13-
/** Just like [apply_only()], but will create an oplog entry as well on success. */
21+
/**
22+
* Applies `existing_branch` using the behavior described by
23+
* [`apply_with_perm()`].
24+
*
25+
* This acquires exclusive worktree access from `ctx`, applies
26+
* `existing_branch`, and records an oplog snapshot on success.
27+
*/
1428
export declare function apply(projectId: string, existingBranch: string): Promise<ApplyOutcome>
1529

1630
/**
17-
* Persist hunk-to-commit assignments for the current workspace.
31+
* Persists `assignments` for the current workspace.
1832
*
19-
* `assignments` is a list of hunk assignment requests produced by the UI.
33+
* `assignments` is applied against the current workspace state and stored in
34+
* the hunk-assignment database. For lower-level implementation details, see
35+
* [`but_hunk_assignment::assign()`].
2036
*/
2137
export declare function assignHunk(projectId: string, assignments: Array<HunkAssignmentRequest>): Promise<void>
2238

2339
export declare function branchDetails(projectId: string, branchName: string, remote: string | null): Promise<BranchDetails>
2440

25-
/** Gets the changes for a given branch. */
41+
/**
42+
* Computes the worktree-visible diff for `branch` in the current workspace.
43+
*
44+
* `branch` is resolved by name in the repository referenced by `ctx`, and the
45+
* diff is computed against the current workspace state. For lower-level
46+
* implementation details, see [`but_workspace::ui::diff::changes_in_branch()`].
47+
*/
2648
export declare function branchDiff(projectId: string, branch: string): Promise<TreeChanges>
2749

2850
/** See [`changes_in_worktree_with_perm()`]. */
@@ -38,58 +60,96 @@ export declare function changesInWorktree(projectId: string): Promise<WorktreeCh
3860
* * conflicts are ignored
3961
*
4062
* All ignored status changes are also provided so they can be displayed separately.
63+
*
64+
* For lower-level implementation details, see
65+
* [`but_core::diff::worktree_changes()`],
66+
* [`but_hunk_assignment::assignments_with_fallback()`], and
67+
* [`but_hunk_dependency::ui::hunk_dependencies_for_workspace_changes_by_worktree_dir()`].
4168
*/
4269
export declare function changesInWorktreeWithPerm(projectId: string): Promise<WorktreeChanges>
4370

44-
/** Amends an existing commit with selected changes, with oplog support. */
71+
/**
72+
* Amend the commit at `commit_id` with `changes` and record an oplog snapshot on success.
73+
*
74+
* This performs the rewrite under exclusive worktree access and creates a
75+
* best-effort `AmendCommit` oplog entry if the operation succeeds. For
76+
* lower-level implementation details, see
77+
* [`but_workspace::commit::commit_amend()`].
78+
*/
4579
export declare function commitAmend(projectId: string, commitId: string, changes: Array<DiffSpec>): Promise<UICommitCreateResult>
4680

47-
/** Creates and inserts a commit relative to either a commit or a reference, with oplog support. */
81+
/**
82+
* Insert a new commit built from `changes` and record an oplog snapshot on
83+
* success.
84+
*
85+
* `relative_to` and `side` choose where the commit is inserted. `message` is
86+
* the entire commit message text, not just the title. On success, this commits
87+
* a best-effort `CreateCommit` oplog snapshot using the same lock. For
88+
* lower-level implementation details, see
89+
* [`but_workspace::commit::commit_create()`].
90+
*/
4891
export declare function commitCreate(projectId: string, relativeTo: RelativeTo, side: InsertSide, changes: Array<DiffSpec>, message: string): Promise<UICommitCreateResult>
4992

50-
/** This function just exists for the frontend to work without the need for line-stats to be enabled explicitly. */
93+
/**
94+
* Computes commit details for `commit_id` with line statistics enabled.
95+
*
96+
* This exists for callers that always want line statistics without passing
97+
* `line_stats` explicitly.
98+
*/
5199
export declare function commitDetailsWithLineStats(projectId: string, commitId: string): Promise<CommitDetails>
52100

53101
/**
54-
* Discards a commit.
55-
*
56-
* Returns the replaced commits that resulted from the operation.
102+
* Discard `subject_commit_id` using the behavior described by
103+
* [`commit_discard_with_perm()`].
57104
*/
58105
export declare function commitDiscard(projectId: string, subjectCommitId: string): Promise<UICommitDiscardResult>
59106

60107
/**
61-
* Inserts a blank commit relative to either a commit or a reference, with oplog support.
108+
* Inserts a blank commit on `side` of `relative_to` and records an oplog
109+
* snapshot on success.
62110
*
63-
* Returns the result including the new commit ID and any replaced commits.
111+
* For details, see [`commit_insert_blank_with_perm()`].
64112
*/
65113
export declare function commitInsertBlank(projectId: string, relativeTo: RelativeTo, side: InsertSide): Promise<UICommitInsertBlankResult>
66114

67115
/**
68-
* Moves a commit within or across stacks.
116+
* Moves `subject_commit_id` to `side` of `relative_to` and records an oplog
117+
* snapshot on success.
118+
*
119+
* This acquires exclusive worktree access from `ctx` before moving the
120+
* commit.
69121
*
70-
* Returns the replaced that resulted from the operation.
122+
* For details, see [`commit_move_with_perm()`].
71123
*/
72124
export declare function commitMove(projectId: string, subjectCommitId: string, relativeTo: RelativeTo, side: InsertSide): Promise<UICommitMoveResult>
73125

74126
/**
75-
* Moves changes between two commits.
127+
* Moves `changes` from `source_commit_id` to `destination_commit_id` and
128+
* records an oplog snapshot on success.
76129
*
77-
* Returns where the source and destination commits were mapped to.
130+
* This acquires exclusive worktree access from `ctx` before moving the
131+
* changes.
132+
*
133+
* For details, see [`commit_move_changes_between_with_perm()`].
78134
*/
79135
export declare function commitMoveChangesBetween(projectId: string, sourceCommitId: string, destinationCommitId: string, changes: Array<DiffSpec>): Promise<UIMoveChangesResult>
80136

81137
/**
82-
* Rewords a commit, with oplog support.
138+
* Reword `commit_id` to `message` using the behavior described by
139+
* [`commit_reword_with_perm()`].
83140
*
84-
* Returns the result including the new commit ID and any replaced commits.
141+
* This acquires exclusive worktree access from `ctx` before rewriting the
142+
* commit message and recording the oplog entry.
85143
*/
86144
export declare function commitReword(projectId: string, commitId: string, message: string): Promise<UICommitRewordResult>
87145

88146
/**
89-
* Uncommits changes from a commit, with oplog and optional assign_to support.
147+
* Extract `changes` from `commit_id` and record the rewrite in the oplog.
148+
*
149+
* This acquires exclusive worktree access from `ctx` before extracting the
150+
* changes.
90151
*
91-
* If `assign_to` is provided, the newly uncommitted changes will be assigned
92-
* to the specified stack.
152+
* See [`commit_uncommit_changes_with_perm()`] for details.
93153
*/
94154
export declare function commitUncommitChanges(projectId: string, commitId: string, changes: Array<DiffSpec>, assignTo: string | null): Promise<UIMoveChangesResult>
95155

@@ -120,7 +180,12 @@ export declare function listReviewsForBranch(projectId: string, branch: string,
120180
/** Merge a review on the forge. */
121181
export declare function mergeReview(projectId: string, reviewId: number): Promise<void>
122182

123-
/** Move a branch on top of another */
183+
/**
184+
* Moves a branch using the behavior described by [`move_branch_with_perm()`].
185+
*
186+
* This acquires exclusive worktree access from `ctx`, moves `subject_branch`
187+
* on top of `target_branch`, and records an oplog snapshot on success.
188+
*/
124189
export declare function moveBranch(projectId: string, subjectBranch: string, targetBranch: string): Promise<UIMoveBranchResult>
125190

126191
export declare function publishReview(projectId: string, params: CreateForgeReviewParams): Promise<ForgeReview>
@@ -130,6 +195,9 @@ export declare function pushStackLegacy(projectId: string, stackId: string, with
130195
/**
131196
* Remove a branch from a stack.
132197
*
198+
* This acquires exclusive worktree access from `ctx` before creating the
199+
* removal snapshot and detaching the branch.
200+
*
133201
* This can only be called on a branch that's inside of a stack of multiple branches and is not the top branch,
134202
* or on a branch that's empty.
135203
*/
@@ -156,21 +224,41 @@ export declare function setReviewDraftiness(projectId: string, reviewId: number,
156224
export declare function setReviewTemplate(projectId: string, templatePath: string | null): Promise<void>
157225

158226
/**
159-
* Take a branch out of a stack
227+
* Tears off a branch using the behavior described by [`tear_off_branch_with_perm()`].
160228
*
161-
* `subject_branch` - The branch to take out of its stack, and create a new one out of.
229+
* This acquires exclusive worktree access from `ctx`, tears `subject_branch`
230+
* out of its current stack, and records an oplog snapshot on success.
162231
*/
163232
export declare function tearOffBranch(projectId: string, subjectBranch: string): Promise<UIMoveBranchResult>
164233

165234
/**
166-
* Provide a unified diff for `change`, but fail if `change` is a [type-change](but_core::ModeFlags::TypeChange)
167-
* or if it involves a change to a [submodule](gix::object::Kind::Commit).
235+
* Produces a unified patch for `change`.
236+
*
237+
* `change` must not be a type change or a submodule change. For lower-level
238+
* implementation details, see [`but_core::TreeChange::unified_patch()`].
168239
*/
169240
export declare function treeChangeDiffs(projectId: string, change: TreeChange): Promise<UnifiedPatch | null>
170241

242+
/**
243+
* Take the stack identified by `stack_id` out of the workspace.
244+
*
245+
* This acquires exclusive worktree access from `ctx` before collecting the
246+
* assigned changes and unapplying the stack.
247+
*
248+
* See [`unapply_stack_with_perm()`] for how assigned changes are collected before
249+
* delegating to the underlying mutation.
250+
*/
171251
export declare function unapplyStack(projectId: string, stackId: string): Promise<void>
172252

173-
/** Rename a branch */
253+
/**
254+
* Change the branch name from `branch_name` to `new_name` in the stack
255+
* identified by `stack_id`.
256+
*
257+
* This acquires exclusive worktree access from `ctx` before applying the
258+
* rename.
259+
*
260+
* See [`update_branch_name_with_perm()`] for the underlying mutation.
261+
*/
174262
export declare function updateBranchName(projectId: string, stackId: string, branchName: string, newName: string): Promise<void>
175263

176264
/** Update the stacked review descriptions to have the correct footers. */

0 commit comments

Comments
 (0)