sourcecontrol
Version:
A modern TypeScript CLI application for source control
97 lines • 4.42 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.BranchCheckout = void 0;
const repo_1 = require("../../../core/repo");
const utils_1 = require("../../../utils");
class BranchCheckout {
constructor(repository, refService, branchCreator, workdirManager) {
this.repository = repository;
this.refService = refService;
this.branchCreator = branchCreator;
this.workdirManager = workdirManager;
}
async checkout(target, options = {}) {
await this.validateTarget(target, options);
await this.checkWorkingDirectoryStatus(options.force || false);
if (options.create) {
await this.branchCreator.createBranch(target);
}
const isBranch = await this.refService.exists(target);
if (isBranch && !options.detach) {
await this.checkoutBranch(target, options.force || false);
}
else {
await this.checkoutCommit(target, options.force || false);
}
}
async validateTarget(target, options) {
const branchExists = await this.refService.exists(target);
if (branchExists || options.create) {
return;
}
try {
await repo_1.ObjectReader.readCommit(this.repository, target);
}
catch {
}
if (target.length >= 4 && target.length < 40 && /^[0-9a-f]+$/i.test(target)) {
utils_1.logger.warn(`Partial SHA matching not yet implemented for: ${target}`);
}
throw new Error(`pathspec '${target}' did not match any file(s) known to git.\n` +
`Did you forget to 'git add'?`);
}
async checkoutBranch(branchName, force) {
const commitSha = await this.refService.getBranchSha(branchName);
const currentBranch = await this.refService.getCurrentBranch();
if (currentBranch === branchName) {
utils_1.logger.info(`Already on '${branchName}'`);
return;
}
const changes = await this.workdirManager.updateToCommit(commitSha, { force: force });
await this.refService.setCurrentBranch(branchName);
this.logCheckoutResult(branchName, commitSha, changes.filesChanged, false);
}
async checkoutCommit(commitSha, force) {
await repo_1.ObjectReader.readCommit(this.repository, commitSha);
const { filesChanged } = await this.workdirManager.updateToCommit(commitSha, { force });
await this.refService.setDetachedHead(commitSha);
this.logCheckoutResult(commitSha, commitSha, filesChanged, true);
}
logCheckoutResult(target, commitSha, fileChangeCount, isDetached) {
const shortSha = commitSha.substring(0, 7);
if (isDetached) {
utils_1.logger.info(`Note: switching to '${target}'.`);
utils_1.logger.info('');
utils_1.logger.info("You are in 'detached HEAD' state. You can look around, make experimental");
utils_1.logger.info('changes and commit them, and you can discard any commits you make in this');
utils_1.logger.info('state without impacting any branches by switching back to a branch.');
utils_1.logger.info('');
utils_1.logger.info(`HEAD is now at ${shortSha}`);
}
else {
utils_1.logger.info(`Switched to branch '${target}'`);
}
if (fileChangeCount > 0) {
utils_1.logger.debug(`Updated ${fileChangeCount} file(s) in working directory`);
}
}
async checkWorkingDirectoryStatus(force) {
if (force) {
utils_1.logger.warn('Force checkout: local changes will be discarded');
return;
}
const status = await this.workdirManager.isClean();
if (!status.clean) {
const filesList = status.modifiedFiles.slice(0, 10).join('\n ');
const moreFiles = status.modifiedFiles.length > 10
? `\n ... and ${status.modifiedFiles.length - 10} more files`
: '';
throw new Error(`error: Your local changes to the following files would be overwritten by checkout:\n` +
` ${filesList}${moreFiles}\n` +
`Please commit your changes or stash them before you switch branches.\n` +
`Aborting`);
}
}
}
exports.BranchCheckout = BranchCheckout;
//# sourceMappingURL=branch-checkout.js.map
;