@johnlindquist/file-forge
Version:
File Forge is a powerful CLI tool for deep analysis of codebases, generating markdown reports to feed AI reasoning models.
117 lines • 4.65 kB
JavaScript
import { execSync } from "node:child_process";
import { simpleGit as createGit } from "simple-git";
import * as p from "@clack/prompts";
import { formatErrorMessage, formatSpinnerMessage } from "./formatter.js";
import { CHECKOUT_BRANCH_STATUS, CHECKOUT_COMMIT_STATUS, REPO_RESET_COMPLETE, } from "./constants.js";
/**
* Checks if a branch exists in the repository
*/
async function branchExists(repoPath, branch, useRegularGit) {
try {
if (useRegularGit) {
execSync(`git show-ref --verify --quiet refs/heads/${branch}`, {
cwd: repoPath,
});
return true;
}
else {
const git = createGit(repoPath);
const branches = await git.branch();
return branches.all.includes(branch);
}
}
catch {
return false;
}
}
/**
* Resets and optionally checks out a specific branch or commit in a git repository.
* Handles both regular git commands and simple-git API.
*
* @param options - Git reset options including branch, commit, and git mode
* @returns A Promise that resolves when the operation is complete
*/
export async function resetGitRepo(options = {}) {
const { branch, commit, useRegularGit, repoPath } = options;
if (!repoPath) {
throw new Error("Repository path is required");
}
const spinner = p.spinner();
try {
if (useRegularGit) {
if (commit) {
spinner.start(formatSpinnerMessage(`Checking out commit ${commit}...`));
try {
// First try to fetch if this is a cloned repo
execSync("git fetch", { cwd: repoPath, stdio: "ignore" });
}
catch {
// Ignore fetch errors for local repos
}
execSync(`git -c advice.detachedHead=false checkout ${commit}`, {
cwd: repoPath,
stdio: "ignore",
});
console.log(CHECKOUT_COMMIT_STATUS(commit));
spinner.stop(formatSpinnerMessage(CHECKOUT_COMMIT_STATUS(commit)));
}
else if (typeof branch === "string") {
// Type guard for branch
spinner.start(formatSpinnerMessage(`Checking out branch ${branch}...`));
const exists = await branchExists(repoPath, branch, true);
if (exists) {
execSync(`git checkout ${branch}`, {
cwd: repoPath,
stdio: "ignore",
});
}
else {
execSync(`git checkout -b ${branch}`, {
cwd: repoPath,
stdio: "ignore",
});
}
console.log(CHECKOUT_BRANCH_STATUS(branch));
spinner.stop(formatSpinnerMessage(CHECKOUT_BRANCH_STATUS(branch)));
}
}
else {
const git = createGit(repoPath);
if (commit) {
spinner.start(formatSpinnerMessage(`Checking out commit ${commit}...`));
try {
// First try to fetch if this is a cloned repo
await git.fetch();
}
catch {
// Ignore fetch errors for local repos
}
// Set config before checkout
await git.addConfig("advice.detachedHead", "false", false, "local");
await git.checkout(commit);
console.log(CHECKOUT_COMMIT_STATUS(commit));
spinner.stop(formatSpinnerMessage(CHECKOUT_COMMIT_STATUS(commit)));
}
else if (typeof branch === "string") {
// Type guard for branch
spinner.start(formatSpinnerMessage(`Checking out branch ${branch}...`));
const exists = await branchExists(repoPath, branch, false);
if (exists) {
await git.checkout(branch);
}
else {
await git.checkoutLocalBranch(branch);
}
console.log(CHECKOUT_BRANCH_STATUS(branch));
spinner.stop(formatSpinnerMessage(CHECKOUT_BRANCH_STATUS(branch)));
}
}
console.log(REPO_RESET_COMPLETE);
spinner.stop(formatSpinnerMessage(REPO_RESET_COMPLETE));
}
catch (error) {
spinner.stop(formatErrorMessage(`Failed to reset repository: ${error}`));
throw error;
}
}
//# sourceMappingURL=gitUtils.js.map