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,