takt/src/features/tasks/list/taskPullAction.ts
nrs 9ba05d8598
[#395] github-issue-395-add-pull-from (#397)
* takt: github-issue-395-add-pull-from

* ci: trigger CI checks

* fix: taskDiffActions のコンフリクトマーカーを解消

origin/main でリネームされた「Merge from root」ラベル(PR #394)と、
このPR (#395) で追加した「Pull from remote」行を統合する。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: trigger CI checks

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: masanobu-naruse <m_naruse@codmon.co.jp>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 14:13:06 +09:00

96 lines
3.0 KiB
TypeScript

import { execFileSync } from 'node:child_process';
import { success, error as logError } from '../../../shared/ui/index.js';
import { createLogger, getErrorMessage } from '../../../shared/utils/index.js';
import {
type BranchActionTarget,
resolveTargetBranch,
validateWorktreeTarget,
pushWorktreeToOrigin,
} from './taskActionTarget.js';
const log = createLogger('list-tasks');
const TEMP_REMOTE_NAME = 'origin';
function getOriginUrl(projectDir: string): string {
return execFileSync(
'git', ['config', '--get', 'remote.origin.url'],
{ cwd: projectDir, encoding: 'utf-8', stdio: 'pipe' },
).trim();
}
export function pullFromRemote(
projectDir: string,
target: BranchActionTarget,
): boolean {
if (!validateWorktreeTarget(target, 'Pull')) {
return false;
}
const worktreePath = target.worktreePath;
const branch = resolveTargetBranch(target);
let originUrl: string;
try {
originUrl = getOriginUrl(projectDir);
} catch (err) {
logError(`Failed to get origin URL: ${getErrorMessage(err)}`);
log.error('getOriginUrl failed', { projectDir, error: getErrorMessage(err) });
return false;
}
log.info('Retrieved origin URL from root repo', { projectDir, originUrl });
try {
execFileSync('git', ['remote', 'add', TEMP_REMOTE_NAME, originUrl], {
cwd: worktreePath,
encoding: 'utf-8',
stdio: 'pipe',
});
log.info('Added temporary origin remote', { worktreePath, originUrl });
try {
execFileSync('git', ['pull', '--ff-only', TEMP_REMOTE_NAME, branch], {
cwd: worktreePath,
encoding: 'utf-8',
stdio: 'pipe',
});
log.info('Pull succeeded', { worktreePath, branch });
} catch (err) {
const msg = getErrorMessage(err);
logError(`Pull failed (not fast-forwardable?): ${msg}`);
logError('If the branch has diverged, use "Sync with root" instead.');
log.error('git pull --ff-only failed', { worktreePath, branch, error: msg });
return false;
}
} catch (err) {
logError(`Failed to add temporary remote: ${getErrorMessage(err)}`);
log.error('git remote add failed', { worktreePath, originUrl, error: getErrorMessage(err) });
return false;
} finally {
removeTemporaryRemote(worktreePath);
}
try {
pushWorktreeToOrigin(worktreePath, projectDir, branch);
} catch (err) {
logError(`Push failed after pull: ${getErrorMessage(err)}`);
log.error('pushWorktreeToOrigin failed', { worktreePath, projectDir, branch, error: getErrorMessage(err) });
return false;
}
success('Pulled & pushed.');
return true;
}
function removeTemporaryRemote(worktreePath: string): void {
try {
execFileSync('git', ['remote', 'remove', TEMP_REMOTE_NAME], {
cwd: worktreePath,
encoding: 'utf-8',
stdio: 'pipe',
});
log.info('Removed temporary origin remote', { worktreePath });
} catch (err) {
logError(`Failed to remove temporary remote: ${getErrorMessage(err)}`);
log.error('git remote remove failed', { worktreePath, error: getErrorMessage(err) });
}
}