Skip to content

Commit 69ded82

Browse files
authored
Merge pull request #9885 from gitbutlerapp/branch-ref-api
Changes: Use full RefName
2 parents 4579b53 + d2c6c06 commit 69ded82

File tree

13 files changed

+90
-75
lines changed

13 files changed

+90
-75
lines changed

apps/desktop/cypress/e2e/selection.cy.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ describe('Selection', () => {
5151
.scrollIntoView()
5252
.should('be.visible')
5353
.within(() => {
54-
const changedFileNames = mockBackend.getBranchChangesFileNames(stackId, stackName);
54+
const branch = `refs/heads/${stackName}`;
55+
const changedFileNames = mockBackend.getBranchChangesFileNames(stackId, branch);
5556
for (const fileName of changedFileNames) {
5657
cy.getByTestId('file-list-item', fileName).should('be.visible');
5758
}

apps/desktop/cypress/e2e/support/mock/backend.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,10 @@ export default class MockBackend {
442442

443443
public getBranchChanges(args: InvokeArgs | undefined): TreeChanges {
444444
if (!args || !isGetBranchChangesParams(args)) {
445-
throw new Error('Invalid arguments for getBranchChanges');
445+
throw new Error('Invalid arguments for getBranchChanges: ' + JSON.stringify(args));
446446
}
447447

448-
const { stackId, branchName } = args;
448+
const { stackId, branch } = args;
449449

450450
if (!stackId) {
451451
return {
@@ -463,9 +463,9 @@ export default class MockBackend {
463463
throw new Error(`No changes found for stack with ID ${stackId}`);
464464
}
465465

466-
const branchChanges = stackBranchChanges.get(branchName);
466+
const branchChanges = stackBranchChanges.get(branch);
467467
if (!branchChanges) {
468-
throw new Error(`No changes found for branch with name ${branchName}`);
468+
throw new Error(`No changes found for branch with name ${branch}`);
469469
}
470470

471471
return {
@@ -480,10 +480,10 @@ export default class MockBackend {
480480

481481
public getBranchChangesFileNames(
482482
stackId: string,
483-
branchName: string,
483+
branch: string,
484484
projectId: string = PROJECT_ID
485485
): string[] {
486-
const changes = this.getBranchChanges({ projectId, stackId, branchName });
486+
const changes = this.getBranchChanges({ projectId, stackId, branch });
487487
return changes.changes.map((change) => change.path).map((path) => path.split('/').pop()!);
488488
}
489489

apps/desktop/cypress/e2e/support/mock/changes.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,7 @@ export function isGetCommitChangesParams(args: unknown): args is GetCommitChange
148148
export type GetBranchChangesParams = {
149149
projectId: string;
150150
stackId?: string;
151-
branchName: string;
152-
remote?: string;
151+
branch: string;
153152
};
154153

155154
export function isGetBranchChangesParams(args: unknown): args is GetBranchChangesParams {
@@ -159,9 +158,8 @@ export function isGetBranchChangesParams(args: unknown): args is GetBranchChange
159158
'projectId' in args &&
160159
typeof args['projectId'] === 'string' &&
161160
(typeof (args as any).stackId === 'string' || (args as any).stackId === undefined) &&
162-
'branchName' in args &&
163-
typeof args['branchName'] === 'string' &&
164-
(typeof (args as any).remote === 'string' || (args as any).remote === undefined)
161+
'branch' in args &&
162+
typeof args['branch'] === 'string'
165163
);
166164
}
167165

apps/desktop/cypress/e2e/support/scenarios/branchesWithChanges.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -635,13 +635,16 @@ export default class BranchesWithChanges extends MockBackend {
635635
this.stackDetails.set(MOCK_STACK_C_ID, MOCK_STACK_DETAILS_C);
636636

637637
const stackAChanges = new Map<string, TreeChange[]>();
638-
stackAChanges.set(MOCK_STACK_A_ID, MOCK_BRANCH_A_CHANGES);
638+
const branchARef = `refs/heads/${MOCK_STACK_A_ID}`;
639+
stackAChanges.set(branchARef, MOCK_BRANCH_A_CHANGES);
639640

640641
const stackBChanges = new Map<string, TreeChange[]>();
641-
stackBChanges.set(MOCK_STACK_B_ID, MOCK_BRANCH_B_CHANGES);
642+
const branchBRef = `refs/heads/${MOCK_STACK_B_ID}`;
643+
stackBChanges.set(branchBRef, MOCK_BRANCH_B_CHANGES);
642644

643645
const stackCChanges = new Map<string, TreeChange[]>();
644-
stackCChanges.set(MOCK_STACK_C_ID, MOCK_BRANCH_C_CHANGES);
646+
const branchCRef = `refs/heads/${MOCK_STACK_C_ID}`;
647+
stackCChanges.set(branchCRef, MOCK_BRANCH_C_CHANGES);
645648

646649
this.branchChanges.set(MOCK_STACK_A_ID, stackAChanges);
647650
this.branchChanges.set(MOCK_STACK_B_ID, stackBChanges);

apps/desktop/src/components/BranchesView.svelte

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@
6767
return createCommitSelection({ commitId: current.commitId, stackId: current.stackId });
6868
}
6969
if (current.branchName) {
70-
const branchName = current.remote
71-
? current.remote + '/' + current.branchName
72-
: current.branchName;
73-
return createBranchSelection({ stackId: current.stackId, branchName });
70+
return createBranchSelection({
71+
stackId: current.stackId,
72+
branchName: current.branchName,
73+
remote: current.remote
74+
});
7475
}
7576
});
7677

apps/desktop/src/components/StackView.svelte

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import { STACK_SERVICE } from '$lib/stacks/stackService.svelte';
3131
import { UI_STATE } from '$lib/state/uiState.svelte';
3232
33+
import { createBranchRef } from '$lib/utils/branch';
3334
import { computeChangeStatus } from '$lib/utils/fileStatus';
3435
import { inject } from '@gitbutler/shared/context';
3536
import { persistWithExpiration } from '@gitbutler/shared/persisted';
@@ -111,7 +112,7 @@
111112
if (commitId) {
112113
return createCommitSelection({ commitId, stackId: stackId });
113114
} else if (branchName) {
114-
return createBranchSelection({ stackId: stackId, branchName });
115+
return createBranchSelection({ stackId: stackId, branchName, remote: undefined });
115116
}
116117
});
117118
@@ -229,7 +230,7 @@
229230
This file is growing complex, and should be simplified where possible. It
230231
is also intentionally intriciate, as it allows us to render the components
231232
in two different configurations.
232-
233+
233234
While tedious to maintain, it is also a good forcing function for making
234235
components that compose better. Be careful when changing, especially since
235236
integration tests only covers the default layout.
@@ -344,7 +345,7 @@
344345
{@const changesResult = stackService.branchChanges({
345346
projectId,
346347
stackId: stackId,
347-
branchName
348+
branch: createBranchRef(branchName, undefined)
348349
})}
349350
<ReduxResult {projectId} {stackId} result={changesResult.current}>
350351
{#snippet children(changes, { projectId, stackId })}
@@ -354,7 +355,7 @@
354355
{stackId}
355356
draggableFiles
356357
autoselect
357-
selectionId={createBranchSelection({ stackId: stackId, branchName })}
358+
selectionId={createBranchSelection({ stackId: stackId, branchName, remote: undefined })}
358359
noshrink={!!previewKey}
359360
ontoggle={() => {
360361
changedFilesCollapsed = !changedFilesCollapsed;

apps/desktop/src/components/UnappliedBranchView.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import ReduxResult from '$components/ReduxResult.svelte';
88
import { createBranchSelection, type SelectionId } from '$lib/selection/key';
99
import { STACK_SERVICE } from '$lib/stacks/stackService.svelte';
10+
import { createBranchRef } from '$lib/utils/branch';
1011
import { inject } from '@gitbutler/shared/context';
1112
import { Icon, TestId, Tooltip } from '@gitbutler/ui';
1213
@@ -29,12 +30,12 @@
2930
? stackService.branchDetails(projectId, stackId, branchName)
3031
: stackService.unstackedBranchDetails(projectId, branchName, remote)
3132
);
32-
const changesResult = $derived(stackService.branchChanges({ projectId, branchName, remote }));
3333
3434
const selectionId: SelectionId = $derived.by(() => {
35-
const bname = remote ? remote + '/' + branchName : branchName;
36-
return createBranchSelection({ stackId, branchName: bname });
35+
return createBranchSelection({ stackId, branchName, remote });
3736
});
37+
38+
const branchRef = $derived(createBranchRef(branchName, remote));
3839
</script>
3940

4041
<ReduxResult {projectId} result={branchResult.current} {onerror}>
@@ -94,6 +95,7 @@
9495
</div>
9596
</Drawer>
9697

98+
{@const changesResult = stackService.branchChanges({ projectId, branch: branchRef })}
9799
<ReduxResult {projectId} result={changesResult.current}>
98100
{#snippet children(changes, env)}
99101
<ChangedFiles

apps/desktop/src/lib/selection/idSelection.svelte.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
type SelectionId,
88
type SelectedFile
99
} from '$lib/selection/key';
10+
import { createBranchRef } from '$lib/utils/branch';
1011
import { InjectionToken } from '@gitbutler/shared/context';
1112
import { reactive } from '@gitbutler/shared/reactiveUtils.svelte';
1213
import { SvelteSet } from 'svelte/reactivity';
@@ -148,13 +149,16 @@ export class IdSelection {
148149
return this.uncommittedService
149150
.getChangesByStackId(params.stackId || null)
150151
.filter((c) => paths.includes(c.path));
151-
case 'branch':
152+
case 'branch': {
153+
const { remote, branchName } = params;
154+
const branch = createBranchRef(branchName, remote);
152155
return await this.stackService.branchChangesByPaths({
153156
projectId,
154157
stackId: params.stackId,
155-
branchName: params.branchName,
158+
branch,
156159
paths: paths
157160
});
161+
}
158162
case 'commit':
159163
return await this.stackService.commitChangesByPaths(projectId, params.commitId, paths);
160164
case 'snapshot':
@@ -236,13 +240,16 @@ export class IdSelection {
236240
switch (selectedFile.type) {
237241
case 'commit':
238242
return this.stackService.commitChange(projectId, selectedFile.commitId, selectedFile.path);
239-
case 'branch':
243+
case 'branch': {
244+
const { remote, branchName } = selectedFile;
245+
const branch = createBranchRef(branchName, remote);
240246
return this.stackService.branchChange({
241247
projectId,
242248
stackId: selectedFile.stackId,
243-
branchName: selectedFile.branchName,
249+
branch,
244250
path: selectedFile.path
245251
});
252+
}
246253
case 'worktree':
247254
this.uncommittedService.assignmentsByPath(selectedFile.stackId || null, selectedFile.path);
248255
return this.worktreeService.treeChangeByPath(projectId, selectedFile.path);

apps/desktop/src/lib/selection/key.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { BrandedId } from '@gitbutler/shared/utils/branding';
22

33
// ASCII Unit Separator, used to separate data units within a record or field.
44
const UNIT_SEP = '\u001F';
5+
const UNDEFINED_REMOTE = '<<no-remote>>';
56

67
const SELECTION_TYPES = ['commit', 'branch', 'worktree', 'snapshot'] as const;
78

@@ -26,6 +27,7 @@ export type SelectionId = {
2627
| {
2728
type: 'branch';
2829
stackId?: string;
30+
remote: string | undefined;
2931
branchName: string;
3032
}
3133
| {
@@ -47,7 +49,7 @@ export function key(params: SelectedFile): SelectedFileKey {
4749
case 'commit':
4850
return `${params.type}${UNIT_SEP}${params.path}${UNIT_SEP}${params.commitId}${UNIT_SEP}${params.stackId}` as SelectedFileKey;
4951
case 'branch':
50-
return `${params.type}${UNIT_SEP}${params.path}${UNIT_SEP}${params.stackId}${UNIT_SEP}${params.branchName}` as SelectedFileKey;
52+
return `${params.type}${UNIT_SEP}${params.path}${UNIT_SEP}${params.stackId}${UNIT_SEP}${params.remote ?? UNDEFINED_REMOTE}${UNIT_SEP}${params.branchName}` as SelectedFileKey;
5153
case 'worktree':
5254
return `${params.type}${UNIT_SEP}${params.path}${UNIT_SEP}${params.stackId}` as SelectedFileKey;
5355
case 'snapshot':
@@ -70,13 +72,14 @@ export function readKey(key: SelectedFileKey): SelectedFile {
7072
stackId: parts[2]!
7173
};
7274
case 'branch':
73-
if (parts.length !== 3) throw new Error('Invalid branch key');
75+
if (parts.length !== 4) throw new Error('Invalid branch key');
7476
return {
7577
type,
7678
path: parts[0]!,
7779
// TODO: Fix this by adding a new type for regular branches.
7880
stackId: parts[1] === 'undefined' ? undefined : parts[1]!,
79-
branchName: parts[2]!
81+
remote: parts[2] === UNDEFINED_REMOTE ? undefined : parts[2]!,
82+
branchName: parts[3]!
8083
};
8184
case 'worktree':
8285
if (parts.length !== 2) throw new Error('Invalid worktree key');
@@ -100,7 +103,7 @@ export function selectionKey(id: SelectionId): SelectionKey {
100103
case 'commit':
101104
return `${id.type}${UNIT_SEP}${id.commitId}` as SelectionKey;
102105
case 'branch':
103-
return `${id.type}${UNIT_SEP}${id.stackId}${UNIT_SEP}${id.branchName}` as SelectionKey;
106+
return `${id.type}${UNIT_SEP}${id.stackId}${UNIT_SEP}${id.remote ?? UNDEFINED_REMOTE}${UNIT_SEP}${id.branchName}` as SelectionKey;
104107
case 'worktree':
105108
return `${id.type}${UNIT_SEP}${id.stackId}` as SelectionKey;
106109
case 'snapshot':
@@ -132,11 +135,13 @@ export function createCommitSelection(params: { commitId: string; stackId?: stri
132135
export function createBranchSelection(params: {
133136
stackId?: string;
134137
branchName: string;
138+
remote: string | undefined;
135139
}): SelectionId {
136140
return createSelectionId({
137141
type: 'branch',
138142
stackId: params.stackId,
139-
branchName: params.branchName
143+
branchName: params.branchName,
144+
remote: params.remote
140145
});
141146
}
142147

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

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
type UiState,
1919
updateStaleStackState
2020
} from '$lib/state/uiState.svelte';
21-
import { getBranchNameFromRef } from '$lib/utils/branch';
21+
import { getBranchNameFromRef, type BranchRef } from '$lib/utils/branch';
2222
import { InjectionToken } from '@gitbutler/shared/context';
2323
import { isDefined } from '@gitbutler/ui/utils/typeguards';
2424
import {
@@ -536,18 +536,12 @@ export class StackService {
536536
* If the branch is part of a stack and if the stackId is provided, this will include only the changes up to the next branch in the stack.
537537
* Otherwise, if stackId is not provided, this will include all changes as compared to the target branch
538538
*/
539-
branchChanges(args: {
540-
projectId: string;
541-
stackId?: string;
542-
branchName: string;
543-
remote?: string;
544-
}) {
539+
branchChanges(args: { projectId: string; stackId?: string; branch: BranchRef }) {
545540
return this.api.endpoints.branchChanges.useQuery(
546541
{
547542
projectId: args.projectId,
548543
stackId: args.stackId,
549-
branchName: args.branchName,
550-
remote: args.remote
544+
branch: args.branch
551545
},
552546
{
553547
transform: (result) => ({
@@ -558,19 +552,12 @@ export class StackService {
558552
);
559553
}
560554

561-
branchChange(args: {
562-
projectId: string;
563-
stackId?: string;
564-
branchName: string;
565-
remote?: string;
566-
path: string;
567-
}) {
555+
branchChange(args: { projectId: string; stackId?: string; branch: BranchRef; path: string }) {
568556
return this.api.endpoints.branchChanges.useQuery(
569557
{
570558
projectId: args.projectId,
571559
stackId: args.stackId,
572-
branchName: args.branchName,
573-
remote: args.remote
560+
branch: args.branch
574561
},
575562
{ transform: (result) => changesSelectors.selectById(result.changes, args.path) }
576563
);
@@ -579,16 +566,14 @@ export class StackService {
579566
async branchChangesByPaths(args: {
580567
projectId: string;
581568
stackId?: string;
582-
branchName: string;
583-
remote?: string;
569+
branch: BranchRef;
584570
paths: string[];
585571
}) {
586572
const result = await this.api.endpoints.branchChanges.fetch(
587573
{
588574
projectId: args.projectId,
589575
stackId: args.stackId,
590-
branchName: args.branchName,
591-
remote: args.remote
576+
branch: args.branch
592577
},
593578
{ transform: (result) => selectChangesByPaths(result.changes, args.paths) }
594579
);
@@ -1145,7 +1130,7 @@ function injectEndpoints(api: ClientState['backendApi'], uiState: UiState) {
11451130
}),
11461131
branchChanges: build.query<
11471132
{ changes: EntityState<TreeChange, string>; stats: TreeStats },
1148-
{ projectId: string; stackId?: string; branchName: string; remote?: string }
1133+
{ projectId: string; stackId?: string; branch: BranchRef }
11491134
>({
11501135
extraOptions: { command: 'changes_in_branch' },
11511136
query: (args) => args,

0 commit comments

Comments
 (0)