From 9f8800aacbf33f17160a37729d00293974d3170b Mon Sep 17 00:00:00 2001
From: Opey Adeyemi <60050089+Opeyem1a@users.noreply.github.com>
Date: Sun, 3 Nov 2024 15:19:54 -0700
Subject: [PATCH] add move command (#59)
---
VISION.md | 4 +-
src/command-registry.ts | 5 ++
src/commands/move.tsx | 115 +++++++++++++++++++++++++++++++++++++++
src/services/resolver.ts | 1 +
4 files changed, 123 insertions(+), 2 deletions(-)
create mode 100644 src/commands/move.tsx
diff --git a/VISION.md b/VISION.md
index 302a4c5..595c32c 100644
--- a/VISION.md
+++ b/VISION.md
@@ -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
@@ -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.
diff --git a/src/command-registry.ts b/src/command-registry.ts
index 27289f6..711f67f 100644
--- a/src/command-registry.ts
+++ b/src/command-registry.ts
@@ -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 = {
@@ -37,6 +38,10 @@ export const REGISTERED_COMMANDS: CommandGroup = {
component: Switch,
config: switchConfig,
},
+ move: {
+ component: Move,
+ config: moveConfig,
+ },
continue: {
component: Continue,
config: continueConfig,
diff --git a/src/commands/move.tsx b/src/commands/move.tsx
new file mode 100644
index 0000000..4b74bdf
--- /dev/null
+++ b/src/commands/move.tsx
@@ -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 ;
+ }
+
+ if (currentBranch.isLoading) {
+ return ;
+ }
+
+ return (
+
+
+
+ );
+};
+
+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 ;
+ }
+
+ if (!isFirstRebaseComplete && currentBranch.value) {
+ return (
+
+
+ Select the new parent for{' '}
+ {currentBranch.value}
+
+ ({ 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}
+ />
+
+ );
+ }
+
+ return (
+ Moved successfully}
+ />
+ );
+};
+
+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: {},
+ };
+ },
+};
diff --git a/src/services/resolver.ts b/src/services/resolver.ts
index c63f4c3..dd285ce 100644
--- a/src/services/resolver.ts
+++ b/src/services/resolver.ts
@@ -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,