UNPKG

@shutootaki/gwm

Version:
178 lines 5.76 kB
import { execSync } from 'child_process'; import { execAsync } from '../shell.js'; import { loadConfig } from '../../config.js'; import { isGitRepository } from './core.js'; /** * worktreeエントリを処理する */ function processWorktreeEntry(line, currentWorktree) { if (line.startsWith('HEAD ')) { currentWorktree.head = line.substring(5); } else if (line.startsWith('branch ')) { currentWorktree.branch = line.substring(7); } else if (line === 'bare') { currentWorktree.branch = '(bare)'; currentWorktree.isMain = true; currentWorktree.status = 'MAIN'; } else if (line === 'detached') { currentWorktree.branch = '(detached)'; } } /** * worktreeエントリを完成させる */ function finalizeWorktreeEntry(currentWorktree) { if (!currentWorktree.branch) currentWorktree.branch = '(detached)'; if (!currentWorktree.head) currentWorktree.head = 'UNKNOWN'; return currentWorktree; } /** * アクティブworktreeを設定する */ function setActiveWorktree(worktrees) { const currentDir = process.cwd(); worktrees.forEach((worktree) => { if (worktree.path === currentDir) { worktree.isActive = true; worktree.status = 'ACTIVE'; } }); } /** * メインworktreeを設定する */ function setMainWorktree(worktrees) { if (worktrees.length > 0 && !worktrees.some((w) => w.isMain)) { worktrees[0].isMain = true; worktrees[0].status = 'MAIN'; } } /** * git worktree list --porcelain の出力をパースする */ export function parseWorktrees(output) { const lines = output.trim().split('\n'); const worktrees = []; let currentWorktree = {}; for (const line of lines) { if (line.startsWith('worktree ')) { if (currentWorktree.path) { worktrees.push(finalizeWorktreeEntry(currentWorktree)); } currentWorktree = { path: line.substring(9), status: 'OTHER', isActive: false, isMain: false, }; } else if (line === 'locked') { // lockedの情報は保持するが、ステータスは変更しない } else { processWorktreeEntry(line, currentWorktree); } } if (currentWorktree.path) { worktrees.push(finalizeWorktreeEntry(currentWorktree)); } setMainWorktree(worktrees); setActiveWorktree(worktrees); return worktrees; } /** * worktreeのリストを取得し、PRUNABLE状態を判定する */ export async function getWorktreesWithStatus() { try { if (!isGitRepository()) { throw new Error('Not a git repository. Please run this command from within a git repository.'); } const { stdout } = await execAsync('git worktree list --porcelain', { encoding: 'utf8', cwd: process.cwd(), }); return parseWorktrees(stdout); } catch (err) { if (err instanceof Error) { throw err; } throw new Error(`Failed to get worktrees: ${err}`); } } /** * メインブランチ(複数可)のworktreeでgit pullを実行する */ export async function pullMainBranch() { try { const config = loadConfig(); const worktrees = await getWorktreesWithStatus(); const results = []; // メインブランチに該当するworktreeを特定 const mainWorktrees = worktrees.filter((worktree) => config.main_branches.some((mainBranch) => worktree.branch === mainBranch || worktree.branch === `refs/heads/${mainBranch}`)); if (mainWorktrees.length === 0) { throw new Error(`No worktrees found for main branches: ${config.main_branches.join(', ')}`); } // 各メインワークツリーでpullを実行 for (const worktree of mainWorktrees) { try { const output = execSync('git pull', { cwd: worktree.path, encoding: 'utf8', }); results.push({ branch: worktree.branch, path: worktree.path, success: true, message: output.trim(), }); } catch (err) { const errorMessage = err instanceof Error ? err.message : String(err); results.push({ branch: worktree.branch, path: worktree.path, success: false, message: `Failed to pull: ${errorMessage}`, }); } } return results; } catch (err) { throw new Error(`Failed to pull main branches: ${err instanceof Error ? err.message : 'Unknown error'}`); } } /** * メインワークツリーのパスを取得する * 通常、最初のワークツリーがメインとなる */ export function getMainWorktreePath() { try { const worktrees = parseWorktrees(execSync('git worktree list --porcelain', { encoding: 'utf8', cwd: process.cwd(), })); // isMainフラグが設定されているワークツリーを探す const mainWorktree = worktrees.find((wt) => wt.isMain); if (mainWorktree) { return mainWorktree.path; } // フォールバック: 最初のワークツリーをメインとして扱う if (worktrees.length > 0) { return worktrees[0].path; } return null; } catch { return null; } } //# sourceMappingURL=worktree.js.map