Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions VISION.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ branches are stacked on which branches.

This is now v0.

5. Build `branch attach` (Scope creep) - `branch delete` & `branch switch`
5. Build `branch move` ✅ (Scope creep) - `branch delete` & `branch switch`
6. Build `continue` ✅

This is now v0.1.X
Expand All @@ -97,6 +97,6 @@ This is v0.2.X

This is v0.3.X

13. Build `sync` ✅\* (tentative, needs testing)
13. Build `sync` ✅

This is v1.
5 changes: 5 additions & 0 deletions src/command-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Hop, { hopConfig } from './commands/hop.js';
import Sync, { syncConfig } from './commands/sync.js';
import { CommandGroup } from './types.js';
import { List, listConfig } from './commands/list.js';
import { Move, moveConfig } from './commands/move.js';
import { Switch, switchConfig } from './commands/switch.js';

export const REGISTERED_COMMANDS: CommandGroup = {
Expand Down Expand Up @@ -37,6 +38,10 @@ export const REGISTERED_COMMANDS: CommandGroup = {
component: Switch,
config: switchConfig,
},
move: {
component: Move,
config: moveConfig,
},
continue: {
component: Continue,
config: continueConfig,
Expand Down
115 changes: 115 additions & 0 deletions src/commands/move.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useCallback, useState } from 'react';
import SelectInput from 'ink-select-input';
import { Box, Text } from 'ink';
import { CommandConfig } from '../types.js';
import { Loading } from '../components/loading.js';
import { RecursiveRebaser } from '../components/recursive-rebaser.js';
import { SelectRootBranch } from '../components/select-root-branch.js';
import { TreeDisplayItemComponent } from '../components/tree-display-item-component.js';
import {
TreeDisplayProvider,
useTreeDisplay,
} from '../contexts/tree-display.context.js';
import { useGit } from '../hooks/use-git.js';
import { useGitHelpers } from '../hooks/use-git-helpers.js';
import { useTree } from '../hooks/use-tree.js';

export const Move = () => {
const { currentBranch } = useGitHelpers();
const { rootBranchName } = useTree();

if (!rootBranchName) {
return <SelectRootBranch />;
}

if (currentBranch.isLoading) {
return <Loading />;
}

return (
<TreeDisplayProvider>
<TreeBranchSelector />
</TreeDisplayProvider>
);
};

const TreeBranchSelector = () => {
const git = useGit();
const { moveOnto } = useTree();
const { currentBranch } = useGitHelpers();
const { nodes, isLoading: isLoadingTreeDisplay } = useTreeDisplay();
const [isFirstRebaseComplete, setIsFirstRebaseComplete] = useState(false);

const moveCurrentBranchToParent = useCallback(
async ({
currentBranchName,
newParentBranchName,
}: {
currentBranchName: string;
newParentBranchName: string;
}) => {
// assign a new parent in the tree and rebase. Do the rebase first since it's more error prone.
await git.rebaseBranchOnto({
branch: currentBranchName,
ontoBranch: newParentBranchName,
});
moveOnto({
branch: currentBranchName,
parent: newParentBranchName,
});
},
[git, moveOnto]
);

if (isLoadingTreeDisplay || currentBranch.isLoading) {
return <Loading />;
}

if (!isFirstRebaseComplete && currentBranch.value) {
return (
<Box flexDirection="column">
<Text color="white" bold>
Select the new parent for{' '}
<Text color="yellow">{currentBranch.value}</Text>
</Text>
<SelectInput
items={nodes.map((n) => ({ label: n.name, value: n.name }))}
itemComponent={TreeDisplayItemComponent}
onSelect={(item) => {
if (currentBranch.isLoading) return;

void moveCurrentBranchToParent({
currentBranchName: currentBranch.value,
newParentBranchName: item.value,
}).then(() => {
setIsFirstRebaseComplete(true);
});
}}
limit={nodes.length}
/>
</Box>
);
}

return (
<RecursiveRebaser
baseBranch={currentBranch.value}
endBranch={currentBranch.value}
successStateNode={<Text color="green">Moved successfully</Text>}
/>
);
};

export const moveConfig: CommandConfig = {
description:
'Move the current branch onto a new parent, rebasing it on that new parent accordingly.',
usage: 'move',
key: 'move',
aliases: ['mv'],
getProps: () => {
return {
valid: true,
props: {},
};
},
};
1 change: 1 addition & 0 deletions src/services/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const recursiveRebase = async ({

for (const rebaseAction of rebaseActions) {
rebasedEventHandler(rebaseAction, 'STARTED');
// todo: probably only do this if it's needed though, right?
await git.rebaseBranchOnto({
branch: rebaseAction.branch,
ontoBranch: rebaseAction.ontoBranch,
Expand Down
Loading