Skip to content

Commit 457ab38

Browse files
committed
Fixes #468 - better handles detached head state
1 parent 5990d93 commit 457ab38

File tree

14 files changed

+72
-28
lines changed

14 files changed

+72
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
88
### Fixed
99
- Fixes [#471](https://github.com/eamodio/vscode-gitlens/issues/471) - Don't use Ctrl+Alt+[character] as a shortcut
1010
- Fixes [#478](https://github.com/eamodio/vscode-gitlens/issues/478) - `suppressShowKeyBindingsNotice` gets saved even when it is not required
11+
- Fixes [#468](https://github.com/eamodio/vscode-gitlens/issues/468) - Commit history for detached HEAD doesn't work properly
1112

1213
## [8.5.4] - 2018-07-31
1314
### Added

src/commands/diffWithRevision.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
4545
try {
4646
const log = await Container.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, {
4747
maxCount: args.maxCount,
48-
ref: (args.branchOrTag && args.branchOrTag.name) || gitUri.sha
48+
ref: (args.branchOrTag && args.branchOrTag.ref) || gitUri.sha
4949
});
5050
if (log === undefined) {
5151
if (args.branchOrTag) {

src/commands/openFileRevision.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export class OpenFileRevisionCommand extends ActiveEditorCommand {
7575

7676
const log = await Container.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, {
7777
maxCount: args.maxCount,
78-
ref: (args.branchOrTag && args.branchOrTag.name) || gitUri.sha
78+
ref: (args.branchOrTag && args.branchOrTag.ref) || gitUri.sha
7979
});
8080
if (log === undefined) {
8181
if (args.branchOrTag) {

src/commands/showQuickFileHistory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class ShowQuickFileHistoryCommand extends ActiveEditorCachedCommand {
4949
args.log = await Container.git.getLogForFile(gitUri.repoPath, gitUri.fsPath, {
5050
maxCount: args.maxCount,
5151
range: args.range,
52-
ref: (args.branchOrTag && args.branchOrTag.name) || gitUri.sha
52+
ref: (args.branchOrTag && args.branchOrTag.ref) || gitUri.sha
5353
});
5454
if (args.log === undefined) {
5555
if (args.branchOrTag) {

src/git/git.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -603,33 +603,47 @@ export class Git {
603603
}
604604
}
605605

606-
static async revparse_currentBranch(repoPath: string): Promise<string | undefined> {
606+
static async revparse_currentBranch(repoPath: string): Promise<[string, string?] | undefined> {
607607
const params = ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@', '@{u}'];
608608

609609
const opts = { cwd: repoPath } as CommandOptions;
610610
try {
611611
const data = await gitCommandCore(opts, ...params);
612-
return data;
612+
return [data, undefined];
613613
}
614614
catch (ex) {
615615
const msg = ex && ex.toString();
616-
if (GitWarnings.headNotABranch.test(msg)) return undefined;
616+
if (GitWarnings.headNotABranch.test(msg)) {
617+
try {
618+
const params = ['log', '-n1', '--format=%H', '--'];
619+
const data = await gitCommandCore(opts, ...params);
620+
if (data === undefined) return undefined;
621+
622+
// Matches output of `git branch -vv`
623+
const sha = data.trim();
624+
return [`(HEAD detached at ${this.shortenSha(sha)})`, sha];
625+
}
626+
catch {
627+
return undefined;
628+
}
629+
}
617630

618631
const result = GitWarnings.noUpstream.exec(msg);
619-
if (result !== null) return result[1];
632+
if (result !== null) return [result[1], undefined];
620633

621634
if (GitWarnings.unknownRevision.test(msg)) {
622635
try {
623636
const params = ['symbolic-ref', '-q', '--short', 'HEAD'];
624637
const data = await gitCommandCore(opts, ...params);
625-
return data;
638+
return [data, undefined];
626639
}
627640
catch {
628641
return undefined;
629642
}
630643
}
631644

632-
return gitCommandDefaultErrorHandler(ex, opts, ...params);
645+
gitCommandDefaultErrorHandler(ex, opts, ...params);
646+
return undefined;
633647
}
634648
}
635649

src/git/models/branch.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import { Git } from '../git';
12
import { GitStatus } from './status';
23

34
'use strict';
45

56
export class GitBranch {
7+
readonly detached: boolean;
68
readonly name: string;
79
readonly remote: boolean;
810
readonly tracking?: string;
@@ -18,7 +20,8 @@ export class GitBranch {
1820
public readonly sha?: string,
1921
tracking?: string,
2022
ahead: number = 0,
21-
behind: number = 0
23+
behind: number = 0,
24+
detached: boolean = false
2225
) {
2326
if (branch.startsWith('remotes/')) {
2427
branch = branch.substring(8);
@@ -28,14 +31,25 @@ export class GitBranch {
2831
this.remote = false;
2932
}
3033

31-
this.name = branch;
34+
this.detached = detached || (this.current ? GitBranch.isDetached(branch) : false);
35+
if (this.detached) {
36+
this.name = GitBranch.formatDetached(this.sha!);
37+
}
38+
else {
39+
this.name = branch;
40+
}
41+
3242
this.tracking = tracking === '' || tracking == null ? undefined : tracking;
3343
this.state = {
3444
ahead: ahead,
3545
behind: behind
3646
};
3747
}
3848

49+
get ref() {
50+
return this.detached ? this.sha! : this.name;
51+
}
52+
3953
private _basename: string | undefined;
4054
getBasename(): string {
4155
if (this._basename === undefined) {
@@ -73,17 +87,17 @@ export class GitBranch {
7387
return GitStatus.getUpstreamStatus(this.tracking, this.state, options);
7488
}
7589

76-
isValid(): boolean {
77-
return GitBranch.isValid(this.name);
78-
}
79-
8090
static getRemote(branch: string): string {
8191
return branch.substring(0, branch.indexOf('/'));
8292
}
8393

84-
static isValid(name: string): boolean {
94+
static formatDetached(sha: string): string {
95+
return `(${Git.shortenSha(sha)}...)`;
96+
}
97+
98+
static isDetached(name: string): boolean {
8599
// If there is whitespace in the name assume this is not a valid branch name
86100
// Deals with detached HEAD states
87-
return name.match(/\s/) === null;
101+
return name.match(/\s/) !== null || name.match(/\(detached\)/) !== null;
88102
}
89103
}

src/git/models/status.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Uri } from 'vscode';
44
import { GlyphChars } from '../../constants';
55
import { Strings } from '../../system';
66
import { GitUri } from '../gitUri';
7+
import { GitBranch } from './branch';
78
import { GitLogCommit } from './logCommit';
89

910
export interface GitStatusUpstreamState {
@@ -19,7 +20,11 @@ export class GitStatus {
1920
public readonly files: GitStatusFile[],
2021
public readonly state: GitStatusUpstreamState,
2122
public readonly upstream?: string
22-
) {}
23+
) {
24+
if (GitBranch.isDetached(branch)) {
25+
this.branch = GitBranch.formatDetached(this.sha);
26+
}
27+
}
2328

2429
private _diff?: {
2530
added: number;

src/git/models/tag.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ export class GitTag {
77
public readonly annotation?: string
88
) {}
99

10+
get ref() {
11+
return this.name;
12+
}
13+
1014
private _basename: string | undefined;
1115
getBasename(): string {
1216
if (this._basename === undefined) {

src/gitService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -891,8 +891,8 @@ export class GitService implements Disposable {
891891
const data = await Git.revparse_currentBranch(repoPath);
892892
if (data === undefined) return undefined;
893893

894-
const branch = data.split('\n');
895-
return new GitBranch(repoPath, branch[0], true, undefined, branch[1]);
894+
const branch = data[0].split('\n');
895+
return new GitBranch(repoPath, branch[0], true, data[1], branch[1]);
896896
}
897897

898898
async getBranches(repoPath: string | undefined): Promise<GitBranch[]> {

src/views/explorerCommands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ export class ExplorerCommands implements Disposable {
134134
const branch = await Container.git.getBranch(node.repoPath);
135135
if (branch === undefined) return;
136136

137-
const commonAncestor = await Container.git.getMergeBase(node.repoPath, branch.name, node.ref);
137+
const commonAncestor = await Container.git.getMergeBase(node.repoPath, branch.ref, node.ref);
138138
if (commonAncestor === undefined) return;
139139

140140
Container.resultsExplorer.showComparisonInResults(

0 commit comments

Comments
 (0)