From 1bf27de9fdf4ff291606a7223044fe1e27d56935 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Wed, 1 Jul 2020 02:03:26 -0400 Subject: [PATCH] Adds better ref validation/resolve --- src/git/git.ts | 62 +++++++++++++++++++++------------------------------ src/git/gitService.ts | 24 ++++++++++---------- 2 files changed, 37 insertions(+), 49 deletions(-) diff --git a/src/git/git.ts b/src/git/git.ts index 6ab4b5c..4983a71 100644 --- a/src/git/git.ts +++ b/src/git/git.ts @@ -448,38 +448,6 @@ export namespace Git { return git({ cwd: repoPath, configs: ['-c', 'color.branch=false'] }, ...params, ref); } - export async function cat_file__resolve(repoPath: string, fileName: string, ref: string) { - if (GitRevision.isUncommitted(ref)) return ref; - - try { - void (await git( - { cwd: repoPath, errors: GitErrorHandling.Throw }, - 'cat-file', - '-e', - `${ref}:./${fileName}`, - )); - return ref; - } catch (ex) { - const msg: string = ex?.toString(); - if (GitErrors.notAValidObjectName.test(msg)) { - return GitRevision.deletedOrMissing; - } - - return undefined; - } - } - - export async function cat_file__validate(repoPath: string, ref: string) { - if (GitRevision.isUncommitted(ref)) return true; - - try { - void (await git({ cwd: repoPath, errors: GitErrorHandling.Throw }, 'cat-file', '-t', ref)); - return true; - } catch (ex) { - return false; - } - } - export function check_ignore(repoPath: string, ...files: string[]) { return git( { cwd: repoPath, errors: GitErrorHandling.Ignore, stdin: files.join('\0') }, @@ -922,6 +890,17 @@ export namespace Git { return data.length === 0 ? undefined : data.trim(); } + export async function log__find_object(repoPath: string, objectId: string) { + const data = await git( + { cwd: repoPath, errors: GitErrorHandling.Ignore }, + 'log', + '-n1', + '--format=%H', + `--find-object=${objectId}`, + ); + return data.length === 0 ? undefined : data.trim(); + } + export async function log__recent(repoPath: string) { const data = await git( { cwd: repoPath, errors: GitErrorHandling.Ignore }, @@ -1072,11 +1051,6 @@ export namespace Git { return data.length === 0 ? undefined : Number(data.trim()) || undefined; } - export async function rev_parse(repoPath: string, ref: string): Promise { - const data = await git({ cwd: repoPath, errors: GitErrorHandling.Ignore }, 'rev-parse', ref); - return data.length === 0 ? undefined : data.trim(); - } - export async function rev_parse__currentBranch( repoPath: string, ): Promise<[string, string | undefined] | undefined> { @@ -1139,6 +1113,20 @@ export namespace Git { } } + export async function rev_parse__verify( + repoPath: string, + ref: string, + filename?: string, + ): Promise { + const data = await git( + { cwd: repoPath, errors: GitErrorHandling.Ignore }, + 'rev-parse', + '--verify', + filename ? `${ref}:./${filename}` : `${ref}^{commit}`, + ); + return data.length === 0 ? undefined : data.trim(); + } + export function shortlog(repoPath: string) { return git({ cwd: repoPath }, 'shortlog', '-sne', '--all', '--no-merges'); } diff --git a/src/git/gitService.ts b/src/git/gitService.ts index d3c3797..ea502e8 100644 --- a/src/git/gitService.ts +++ b/src/git/gitService.ts @@ -3144,12 +3144,14 @@ export class GitService implements Disposable { async resolveReference(repoPath: string, ref: string, uri?: Uri): Promise; @log() async resolveReference(repoPath: string, ref: string, fileNameOrUri?: string | Uri) { - if (ref == null || ref.length === 0 || ref === GitRevision.deletedOrMissing) return ref; + if (ref == null || ref.length === 0 || ref === GitRevision.deletedOrMissing || GitRevision.isUncommitted(ref)) { + return ref; + } if (fileNameOrUri == null) { if (GitRevision.isSha(ref) || !GitRevision.isShaLike(ref) || ref.endsWith('^3')) return ref; - return (await Git.rev_parse(repoPath, ref)) ?? ref; + return (await Git.rev_parse__verify(repoPath, ref)) ?? ref; } const fileName = @@ -3157,15 +3159,10 @@ export class GitService implements Disposable { ? fileNameOrUri : Strings.normalizePath(paths.relative(repoPath, fileNameOrUri.fsPath)); - if (GitRevision.isShaParent(ref)) { - const parentRef = await Git.log__file_recent(repoPath, fileName, { ref: ref }); - if (parentRef != null) return parentRef; - } - - const ensuredRef = await Git.cat_file__resolve(repoPath, fileName, ref); - if (ensuredRef == null) return ref; + const blob = await Git.rev_parse__verify(repoPath, ref, fileName); + if (blob == null) return ref; - return ensuredRef; + return (await Git.log__find_object(repoPath, blob)) ?? ref; } @log() @@ -3174,8 +3171,11 @@ export class GitService implements Disposable { } @log() - validateReference(repoPath: string, ref: string) { - return Git.cat_file__validate(repoPath, ref); + async validateReference(repoPath: string, ref: string) { + if (ref == null || ref.length === 0) return false; + if (ref === GitRevision.deletedOrMissing || GitRevision.isUncommitted(ref)) return true; + + return (await Git.rev_parse__verify(repoPath, ref)) != null; } stageFile(repoPath: string, fileName: string): Promise;