Skip to content

Commit

Permalink
Fixes Git 2.25+ issues with mapped drives
Browse files Browse the repository at this point in the history
  • Loading branch information
eamodio committed Jun 11, 2020
1 parent 9248ba7 commit 3d1808b
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
32 changes: 30 additions & 2 deletions src/git/gitService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ import {
import { GitUri } from './gitUri';
import { RemoteProvider, RemoteProviderFactory, RemoteProviders, RemoteProviderWithApi } from './remotes/factory';
import { GitReflogParser, GitShortLogParser } from './parsers/parsers';
import { fsExists, isWindows } from './shell';
import { fsExists, getNetworkPathForDrive, isWindows } from './shell';
import { GitRevision, PullRequest, PullRequestDateFormatting } from './models/models';

export * from './gitUri';
Expand All @@ -100,6 +100,7 @@ const RepoSearchWarnings = {
};

const doubleQuoteRegex = /"/g;
const driveLetterRegex = /(?<=^\/?)([a-zA-Z])(?=:\/)/;
const userConfigRegex = /^user\.(name|email) (.*)$/gm;
const mappedAuthorRegex = /(.+)\s<(.+)>/;
const searchMessageOperationRegex = /(?=(.*?)\s?(?:(?:=:|message:|@:|author:|#:|commit:|\?:|file:|~:|change:)|$))/;
Expand Down Expand Up @@ -2586,7 +2587,34 @@ export class GitService implements Disposable {
const path = isDirectory ? filePath : paths.dirname(filePath);

let repoPath = await Git.rev_parse__show_toplevel(path);
if (repoPath === undefined || isWindows) return repoPath;
if (repoPath === undefined) return repoPath;

if (isWindows) {
// On Git 2.25+ if you call `rev-parse --show-toplevel` on a mapped drive, instead of getting the mapped drive path back, you get the UNC path for the mapped drive.
// So try to normalize it back to the mapped drive path, if possible

const repoUri = Uri.file(repoPath);
const pathUri = Uri.file(path);
if (repoUri.authority.length !== 0 && pathUri.authority.length === 0) {
const match = driveLetterRegex.exec(pathUri.path);
if (match != null) {
const [, letter] = match;

try {
const networkPath = await getNetworkPathForDrive(letter);
if (networkPath != null) {
return Strings.normalizePath(
repoUri.fsPath.replace(networkPath, `${letter.toLowerCase()}:`),
);
}
} catch {}
}

return Strings.normalizePath(pathUri.fsPath);
}

return repoPath;
}

// If we are not on Windows (symlinks don't seem to have the same issue on Windows), check if we are a symlink and if so, use the symlink path (not its resolved path)
// This is because VS Code will provide document Uris using the symlinked path
Expand Down
20 changes: 19 additions & 1 deletion src/git/shell.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
'use strict';
import { execFile } from 'child_process';
import { exec, execFile } from 'child_process';
import * as fs from 'fs';
import * as paths from 'path';
import { promisify } from 'util';
import * as iconv from 'iconv-lite';
import { Logger } from '../logger';

Expand Down Expand Up @@ -190,3 +191,20 @@ export function run<TOut extends string | Buffer>(
export function fsExists(path: string) {
return new Promise<boolean>(resolve => fs.exists(path, exists => resolve(exists)));
}

const networkDriveRegex = /([A-Z]):\s+(.*?)\s*$/m;

export async function getNetworkPathForDrive(letter: string): Promise<string | undefined> {
const result = await promisify(exec)(
`wmic logicaldisk where 'drivetype=4 and deviceid="${letter}:"' get deviceid,providername`,
{
maxBuffer: 2000 * 1024,
},
);

const match = networkDriveRegex.exec(result.stdout);
if (match == null) return undefined;

const [, , path] = match;
return path;
}

0 comments on commit 3d1808b

Please sign in to comment.