diff --git a/packages/git/src/browser/history/git-history-widget.tsx b/packages/git/src/browser/history/git-history-widget.tsx
index dd7aef756dfc7..ea2d72c3c4066 100644
--- a/packages/git/src/browser/history/git-history-widget.tsx
+++ b/packages/git/src/browser/history/git-history-widget.tsx
@@ -52,14 +52,21 @@ export type GitHistoryListNode = (GitCommitNode | GitFileChangeNode);
 @injectable()
 export class GitHistoryWidget extends GitNavigableListWidget<GitHistoryListNode> implements StatefulWidget {
     protected options: Git.Options.Log;
-    protected commits: GitCommitNode[];
-    protected ready: boolean;
     protected singleFileMode: boolean;
     private cancelIndicator: CancellationTokenSource;
     protected listView: GitHistoryList | undefined;
     protected hasMoreCommits: boolean;
     protected allowScrollToSelected: boolean;
-    protected errorMessage: React.ReactNode;
+
+    protected status: {
+        state: 'loading',
+    } | {
+        state: 'ready',
+        commits: GitCommitNode[];
+    } | {
+        state: 'error',
+        errorMessage: React.ReactNode
+    };
 
     constructor(
         @inject(OpenerService) protected readonly openerService: OpenerService,
@@ -103,7 +110,6 @@ export class GitHistoryWidget extends GitNavigableListWidget<GitHistoryListNode>
 
     async setContent(options?: Git.Options.Log) {
         this.resetState(options);
-        this.ready = false;
         if (options && options.uri) {
             const fileStat = await this.fileSystem.getFileStat(options.uri);
             this.singleFileMode = !!fileStat && !fileStat.isDirectory;
@@ -117,7 +123,7 @@ export class GitHistoryWidget extends GitNavigableListWidget<GitHistoryListNode>
 
     protected resetState(options?: Git.Options.Log) {
         this.options = options || {};
-        this.commits = [];
+        this.status = { state: 'loading' };
         this.gitNodes = [];
         this.hasMoreCommits = true;
         this.allowScrollToSelected = true;
@@ -127,21 +133,22 @@ export class GitHistoryWidget extends GitNavigableListWidget<GitHistoryListNode>
         let repository: Repository | undefined;
         repository = this.repositoryProvider.findRepositoryOrSelected(options);
 
-        this.errorMessage = undefined;
         this.cancelIndicator.cancel();
         this.cancelIndicator = new CancellationTokenSource();
         const token = this.cancelIndicator.token;
 
         if (repository) {
             try {
+                const currentCommits = this.status.state === 'ready' ? this.status.commits : [];
+
                 let changes = await this.git.log(repository, options);
                 if (token.isCancellationRequested || !this.hasMoreCommits) {
                     return;
                 }
-                if (options && ((options.maxCount && changes.length < options.maxCount) || (!options.maxCount && this.commits))) {
+                if (options && ((options.maxCount && changes.length < options.maxCount) || (!options.maxCount && currentCommits))) {
                     this.hasMoreCommits = false;
                 }
-                if (this.commits.length > 0) {
+                if (currentCommits.length > 0) {
                     changes = changes.slice(1);
                 }
                 if (changes.length > 0) {
@@ -164,21 +171,23 @@ export class GitHistoryWidget extends GitNavigableListWidget<GitHistoryListNode>
                             selected: false
                         });
                     }
-                    this.commits.push(...commits);
+                    currentCommits.push(...commits);
+                    this.status = { state: 'ready', commits: currentCommits };
                 } else if (options && options.uri && repository) {
                     const pathIsUnderVersionControl = await this.git.lsFiles(repository, options.uri, { errorUnmatch: true });
                     if (!pathIsUnderVersionControl) {
-                        this.errorMessage = <React.Fragment>It is not under version control.</React.Fragment>;
+                        this.status = { state: 'error', errorMessage: <React.Fragment> It is not under version control.</React.Fragment> };
+                    } else {
+                        this.status = { state: 'error', errorMessage: <React.Fragment> No commits have been committed.</React.Fragment> };
                     }
                 }
 
             } catch (error) {
-                this.errorMessage = error.message;
+                this.status = { state: 'error', errorMessage: error.message };
             }
 
         } else {
-            this.commits = [];
-            this.errorMessage = <React.Fragment>There is no repository selected in this workspace.</React.Fragment>;
+            this.status = { state: 'error', errorMessage: <React.Fragment>There is no repository selected in this workspace.</React.Fragment> };
         }
     }
 
@@ -232,37 +241,48 @@ export class GitHistoryWidget extends GitNavigableListWidget<GitHistoryListNode>
     }
 
     protected onDataReady(): void {
-        this.ready = true;
-        this.gitNodes = this.commits;
+        if (this.status.state === 'ready') {
+            this.gitNodes = this.status.commits;
+        }
         this.update();
     }
 
     protected render(): React.ReactNode {
         let content: React.ReactNode;
-        if (this.ready && this.gitNodes.length > 0) {
-            content = < React.Fragment >
-                {this.renderHistoryHeader()}
-                {this.renderCommitList()}
-            </React.Fragment>;
-        } else if (this.errorMessage) {
-            let path: React.ReactNode = '';
-            let reason: React.ReactNode;
-            reason = this.errorMessage;
-            if (this.options.uri) {
-                const relPath = this.relativePath(this.options.uri);
-                const repo = this.repositoryProvider.findRepository(new URI(this.options.uri));
-                const repoName = repo ? ` in ${new URI(repo.localUri).displayName}` : '';
-                path = ` for ${decodeURIComponent(relPath)}${repoName}`;
-            }
-            content = <AlertMessage
-                type='WARNING'
-                header={`There is no Git history available${path}`}>
-                {reason}
-            </AlertMessage>;
-        } else {
-            content = <div className='spinnerContainer'>
-                <span className='fa fa-spinner fa-pulse fa-3x fa-fw'></span>
-            </div>;
+        switch (this.status.state) {
+            case 'ready':
+                content = < React.Fragment >
+                    {this.renderHistoryHeader()}
+                    {this.renderCommitList()}
+                </React.Fragment>;
+                break;
+
+            case 'error':
+                let path: React.ReactNode = '';
+                let reason: React.ReactNode;
+                reason = this.status.errorMessage;
+                if (this.options.uri) {
+                    const relPathEncoded = this.relativePath(this.options.uri);
+                    const relPath = relPathEncoded ? `${decodeURIComponent(relPathEncoded)}` : '';
+
+                    const repo = this.repositoryProvider.findRepository(new URI(this.options.uri));
+                    const repoName = repo ? `${new URI(repo.localUri).displayName}` : '';
+
+                    const relPathAndRepo = [relPath, repoName].filter(Boolean).join(' in ');
+                    path = ` for ${relPathAndRepo}`;
+                }
+                content = <AlertMessage
+                    type='WARNING'
+                    header={`There is no Git history available${path}.`}>
+                    {reason}
+                </AlertMessage>;
+                break;
+
+            case 'loading':
+                content = <div className='spinnerContainer'>
+                    <span className='fa fa-spinner fa-pulse fa-3x fa-fw'></span>
+                </div>;
+                break;
         }
         return <div className='git-diff-container'>
             {content}
@@ -425,18 +445,18 @@ export class GitHistoryWidget extends GitNavigableListWidget<GitHistoryListNode>
 
     protected navigateLeft(): void {
         const selected = this.getSelected();
-        if (selected) {
-            const idx = this.commits.findIndex(c => c.commitSha === selected.commitSha);
+        if (selected && this.status.state === 'ready') {
+            const idx = this.status.commits.findIndex(c => c.commitSha === selected.commitSha);
             if (GitCommitNode.is(selected)) {
                 if (selected.expanded) {
                     this.addOrRemoveFileChangeNodes(selected);
                 } else {
                     if (idx > 0) {
-                        this.selectNode(this.commits[idx - 1]);
+                        this.selectNode(this.status.commits[idx - 1]);
                     }
                 }
             } else if (GitFileChangeNode.is(selected)) {
-                this.selectNode(this.commits[idx]);
+                this.selectNode(this.status.commits[idx]);
             }
         }
         this.update();
diff --git a/packages/git/src/common/git.ts b/packages/git/src/common/git.ts
index b8e6cfefd0fcb..198c35a116db4 100644
--- a/packages/git/src/common/git.ts
+++ b/packages/git/src/common/git.ts
@@ -583,6 +583,18 @@ export namespace Git {
 
         }
 
+        /**
+         * Options for the `git rev-parse` command.
+         */
+        export interface RevParse {
+
+            /**
+             * The reference to parse.
+             */
+            readonly ref: string;
+
+        }
+
     }
 }
 
@@ -797,6 +809,15 @@ export interface Git extends Disposable {
      */
     log(repository: Repository, options?: Git.Options.Log): Promise<CommitWithChanges[]>;
 
+    /**
+     * Returns the commit SHA of the given ref if the ref exists, or returns 'undefined' if the
+     * given ref does not exist.
+     *
+     * @param repository the repository where the ref may be found.
+     * @param options configuration containing the ref and optionally other properties for further refining the `git rev-parse` command execution.
+     */
+    revParse(repository: Repository, options: Git.Options.RevParse): Promise<string | undefined>;
+
     /**
      * Returns the annotations of each line in the given file.
      *
diff --git a/packages/git/src/node/dugite-git.spec.ts b/packages/git/src/node/dugite-git.spec.ts
index 563a2715b9c8d..7401d12233917 100644
--- a/packages/git/src/node/dugite-git.spec.ts
+++ b/packages/git/src/node/dugite-git.spec.ts
@@ -772,10 +772,18 @@ describe('log', function () {
         const repository = { localUri };
         const git = await createGit();
         const result = await git.log(repository, { uri: localUri });
-        expect(result.length === 1).to.be.true;
-        expect(result[0].author.email === 'jon@doe.com').to.be.true;
+        expect(result.length).to.be.equal(1);
+        expect(result[0].author.email).to.be.equal('jon@doe.com');
     });
 
+    it('should not fail when executed against an empty repository', async () => {
+        const root = await initRepository(track.mkdirSync('empty-log-test'));
+        const localUri = FileUri.create(root).toString();
+        const repository = { localUri };
+        const git = await createGit();
+        const result = await git.log(repository, { uri: localUri });
+        expect(result.length).to.be.equal(0);
+    });
 });
 
 function toPathSegment(repository: Repository, uri: string): string {
diff --git a/packages/git/src/node/dugite-git.ts b/packages/git/src/node/dugite-git.ts
index b6ef4885970f4..cc2be3d450fb7 100644
--- a/packages/git/src/node/dugite-git.ts
+++ b/packages/git/src/node/dugite-git.ts
@@ -657,13 +657,39 @@ export class DugiteGit implements Git {
             const file = Path.relative(this.getFsPath(repository), this.getFsPath(options.uri)) || '.';
             args.push(...[file]);
         }
-        const result = await this.exec(repository, args);
+
+        const successExitCodes = new Set([0, 128]);
+        let result = await this.exec(repository, args, { successExitCodes });
+        if (result.exitCode !== 0) {
+            // Note that if no range specified then the 'to revision' defaults to HEAD
+            const rangeInvolvesHead = !options || !options.range || options.range.toRevision === 'HEAD';
+            const repositoryHasNoHead = !await this.revParse(repository, { ref: 'HEAD' });
+            // The 'log' command could potentially be valid when no HEAD if the revision range does not involve HEAD */
+            if (rangeInvolvesHead && repositoryHasNoHead) {
+                // The range involves HEAD but there is no HEAD.  'no head' most likely means a newly created repository with
+                // no commits, but could potentially have commits with no HEAD.  This is effectively an empty repository.
+                return [];
+            }
+            // Either the range did not involve HEAD or HEAD exists.  The error must be something else,
+            // so re-run but this time we don't ignore the error.
+            result = await this.exec(repository, args);
+        }
+
         return this.commitDetailsParser.parse(
             repository.localUri, result.stdout.trim()
                 .split(CommitDetailsParser.COMMIT_CHUNK_DELIMITER)
                 .filter(item => item && item.length > 0));
     }
 
+    async revParse(repository: Repository, options: Git.Options.RevParse): Promise<string | undefined> {
+        const ref = options.ref;
+        const successExitCodes = new Set([0, 128]);
+        const result = await this.exec(repository, ['rev-parse', ref], { successExitCodes });
+        if (result.exitCode === 0) {
+            return result.stdout; // sha
+        }
+    }
+
     async blame(repository: Repository, uri: string, options?: Git.Options.Blame): Promise<GitFileBlame | undefined> {
         await this.ready.promise;
         const args = ['blame', '--root', '--incremental'];
diff --git a/packages/scm/src/browser/scm-amend-component.tsx b/packages/scm/src/browser/scm-amend-component.tsx
index cf139dc433049..a7d375c1c3ade 100644
--- a/packages/scm/src/browser/scm-amend-component.tsx
+++ b/packages/scm/src/browser/scm-amend-component.tsx
@@ -104,21 +104,20 @@ export class ScmAmendComponent extends React.Component<ScmAmendComponentProps, S
         } else if (nextCommit === undefined && this.state.lastCommit === undefined) {
             // No change here
         } else if (this.transitionHint === 'none') {
-            if (this.state.lastCommit) {
-                // If the 'last' commit changes, but we are not expecting an 'amend'
-                // or 'unamend' to occur, then we clear out the list of amended commits.
-                // This is because an unexpected change has happened to the repoistory,
-                // perhaps the user commited, merged, or something.  The amended commits
-                // will no longer be valid.
-                await this.clearAmendingCommits();
-                // There is a change to the last commit, but no transition hint so
-                // the view just updates without transition.
-                this.setState({ amendingCommits: [], lastCommit: nextCommit });
-            } else {
-                // There should always be a previous 'last commit'
-                throw new Error('unexpected state');
-                // this.setState({ amendingCommits: await this.buildAmendingList(), lastCommit: nextCommit });
-            }
+            // If the 'last' commit changes, but we are not expecting an 'amend'
+            // or 'unamend' to occur, then we clear out the list of amended commits.
+            // This is because an unexpected change has happened to the repoistory,
+            // perhaps the user commited, merged, or something.  The amended commits
+            // will no longer be valid.
+
+            // Note that there may or may not have been a previous lastCommit (if the
+            // repository was previously empty with no initial commit then lastCommit
+            // will be undefined).  Either way we clear the amending commits.
+            await this.clearAmendingCommits();
+
+            // There is a change to the last commit, but no transition hint so
+            // the view just updates without transition.
+            this.setState({ amendingCommits: [], lastCommit: nextCommit });
         } else {
             if (this.state.lastCommit && nextCommit) {
                 const direction: 'up' | 'down' = this.transitionHint === 'amend' ? 'up' : 'down';