microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
163.97k stars 29.19k forks source link

fatal: Not a valid object name wt #185856

Open Timmmm opened 1 year ago

Timmmm commented 1 year ago

Does this issue occur when all extensions are disabled?: Yes/No

Steps to Reproduce:

  1. Clone a repo with submodules
  2. Change the commit of one of the submodules
  3. Try to revert the change in VSCode using the Discard Changes button

This definitely used to work, but now I get this in the Git log and nothing happens:

2023-06-22 11:51:36.873 [info] > git ls-tree -l wt -- /path/to/the/submodule[1ms]
2023-06-22 11:51:36.873 [info] fatal: Not a valid object name wt
Timmmm commented 1 year ago

Actually I think the wt issue is unrelated to the fact that the "Discard Changes" button does nothing, because I get that error just for looking at the submodule changes. Following the code I'm not sure how it is supposed to work: Here's where it tries to stat a file. It gets the ref from fromGitUri() and then sends it to getObjectDetails() via sanitizeRef().

    async stat(uri: Uri): Promise<FileStat> {
        await this.model.isInitialized;

        const { submoduleOf, path, ref } = fromGitUri(uri);
        const repository = submoduleOf ? this.model.getRepository(submoduleOf) : this.model.getRepository(uri);
        if (!repository) {
            throw FileSystemError.FileNotFound();
        }

        let size = 0;
        try {
            const details = await repository.getObjectDetails(sanitizeRef(ref, path, repository), path);
            size = details.size;
        } catch {
            // noop
        }
        return { type: FileType.File, size: size, mtime: this.mtime, ctime: 0 };
    }

    export function fromGitUri(uri: Uri): GitUriParams {
        return JSON.parse(uri.query);
    }

sanitizeRef() doesn't do anything notable in our case.

    function sanitizeRef(ref: string, path: string, repository: Repository): string {
        if (ref === '~') {
            const fileUri = Uri.file(path);
            const uriString = fileUri.toString();
            const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);
            return indexStatus ? '' : 'HEAD';
        }

        if (/^~\d$/.test(ref)) {
            return `:${ref[1]}`;
        }

        return ref;
    }

getObjectDetails() calls lstree(treeish).

        async getObjectDetails(treeish: string, path: string): Promise<{ mode: string; object: string; size: number }> {
            if (!treeish) { // index
                const elements = await this.lsfiles(path);

                if (elements.length === 0) {
                    throw new GitError({ message: 'Path not known by git', gitErrorCode: GitErrorCodes.UnknownPath });
                }

                const { mode, object } = elements[0];
                const catFile = await this.exec(['cat-file', '-s', object]);
                const size = parseInt(catFile.stdout);

                return { mode, object, size };
            }

            const elements = await this.lstree(treeish, path);

            if (elements.length === 0) {
                throw new GitError({ message: 'Path not known by git', gitErrorCode: GitErrorCodes.UnknownPath });
            }

            const { mode, object, size } = elements[0];
            return { mode, object, size: parseInt(size) };
        }

Which runs the failing command, because treeish is "wt".

        async lstree(treeish: string, path: string): Promise<LsTreeElement[]> {
            const { stdout } = await this.exec(['ls-tree', '-l', treeish, '--', sanitizePath(path)]);
            return parseLsTree(stdout);
        }

That comes from here I think:

    getResources(resource: Resource): [Uri | undefined, Uri | undefined] {
        for (const submodule of this.repository.submodules) {
            if (path.join(this.repository.root, submodule.path) === resource.resourceUri.fsPath) {
                return [undefined, toGitUri(resource.resourceUri, resource.resourceGroupType === ResourceGroupType.Index ? 'index' : 'wt', { submoduleOf: this.repository.root })];
            }
        }

        return [this.getLeftResource(resource), this.getRightResource(resource)];
    }

// As a mitigation for extensions like ESLint showing warnings and errors
// for git URIs, let's change the file extension of these uris to .git,
// when `replaceFileExtension` is true.
export function toGitUri(uri: Uri, ref: string, options: GitUriOptions = {}): Uri {
    const params: GitUriParams = {
        path: uri.fsPath,
        ref
    };

    if (options.submoduleOf) {
        params.submoduleOf = options.submoduleOf;
    }

    let path = uri.path;

    if (options.replaceFileExtension) {
        path = `${path}.git`;
    } else if (options.submoduleOf) {
        path = `${path}.diff`;
    }

    return uri.with({
        scheme: 'git',
        path,
        query: JSON.stringify(params)
    });
}
imDanSable commented 6 months ago

VSCode Version: 1.88.1 git version 2.34.1

[info] > git ls-tree -l wt -- /home/***/dev/Rack/dep/Catch2 [0ms] [info] fatal: Not a valid object name wt

Just ran into this after adding a submodule and running git submodule update --init --recursive and building it

c0d3h4x0r commented 2 months ago

VSCode Version: 1.92.1 git version 2.46.0.windows.1

Just hit the same error while working in a repo with submodules.

Can someone who understands what's going wrong here please fix this?