From 5d62127b67231e210d792817303f123de5134cfd Mon Sep 17 00:00:00 2001 From: Phil Hord Date: Mon, 21 Sep 2015 17:29:22 -0400 Subject: [PATCH 1/3] :bug: Teach git-repository-provider to recognize .git-files Git repositories may be contained in a .git directory or a .git file in the workdir hierarchy, but Atom only recognizes the directory format. Teach Atom to recognize the filesystem-agnostic Git symbolic link used by default in many situations including, for example, submodules. The .git file contains a relative or absolute path to the location of the real git-dir, preceded by the 8-byte string "gitdir: ". Here's a console log showing the normal creation of such a symbolic link. /tmp $ git init --separate-git-dir foo.git bar Initialized empty Git repository in /tmp/foo.git/ /tmp $ ls /tmp $ bar foo.git /tmp $ ls -la bar drwxr-xr-x 2 hordp hordp 4096 Sep 18 15:54 . drwxr-xr-x 4 hordp hordp 4096 Sep 18 15:54 .. -rw-r--r-- 1 hordp hordp 25 Sep 18 15:54 .git /tmp $ ls foo.git branches config description HEAD hooks info objects refs /tmp $ cat bar/.git gitdir: /tmp/foo.git Fixes #8876 --- src/git-repository-provider.coffee | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/git-repository-provider.coffee b/src/git-repository-provider.coffee index 850d30f22..3b4df5d2b 100644 --- a/src/git-repository-provider.coffee +++ b/src/git-repository-provider.coffee @@ -1,6 +1,17 @@ fs = require 'fs' +{Directory} = require 'pathwatcher' GitRepository = require './git-repository' +# Returns the .gitdir path in the agnostic Git symlink .git file given, or +# null if the path is not a valid gitfile. +# +# * `gitFile` {String} path of gitfile to parse +gitFileRegex = RegExp "^gitdir: (.+)" +pathFromGitFile = (gitFile) -> + try + gitFileBuff = fs.readFileSync(gitFile, 'utf8') + return gitFileBuff?.match(gitFileRegex)[1] + # Checks whether a valid `.git` directory is contained within the given # directory or one of its ancestors. If so, a Directory that corresponds to the # `.git` folder will be returned. Otherwise, returns `null`. @@ -11,6 +22,9 @@ findGitDirectorySync = (directory) -> # can return cached values rather than always returning new objects: # getParent(), getFile(), getSubdirectory(). gitDir = directory.getSubdirectory('.git') + gitDirPath = pathFromGitFile(gitDir.getPath?()) + if gitDirPath + gitDir = new Directory(directory.resolve(gitDirPath)) if gitDir.existsSync?() and isValidGitDirectorySync gitDir gitDir else if directory.isRoot() From 7445857c821dce07e5f5a027628cf0d3fde04709 Mon Sep 17 00:00:00 2001 From: Phil Hord Date: Mon, 21 Sep 2015 17:16:45 -0400 Subject: [PATCH 2/3] :white_check_mark: Add test for .git-files --- spec/git-repository-provider-spec.coffee | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/git-repository-provider-spec.coffee b/spec/git-repository-provider-spec.coffee index 15e1dcc60..176acee7d 100644 --- a/spec/git-repository-provider-spec.coffee +++ b/spec/git-repository-provider-spec.coffee @@ -56,6 +56,21 @@ describe "GitRepositoryProvider", -> provider.repositoryForDirectory(directory).then (result) -> expect(result).toBe null + describe "when specified a Directory with a valid gitfile-linked repository", -> + it "returns a Promise that resolves to a GitRepository", -> + waitsForPromise -> + provider = new GitRepositoryProvider atom.project + gitDirPath = path.join(__dirname, 'fixtures/git/master.git') + workDirPath = temp.mkdirSync('git-workdir') + fs.writeFileSync(path.join(workDirPath, '.git'), 'gitdir: ' + gitDirPath+'\n') + + directory = new Directory workDirPath + provider.repositoryForDirectory(directory).then (result) -> + expect(result).toBeInstanceOf GitRepository + expect(provider.pathToRepository[result.getPath()]).toBeTruthy() + expect(result.statusTask).toBeTruthy() + expect(result.getType()).toBe 'git' + describe "when specified a Directory without existsSync()", -> directory = null provider = null From 212886817e7fae2c59a14a8e4fdf7e19e8e859b5 Mon Sep 17 00:00:00 2001 From: Phil Hord Date: Thu, 1 Oct 2015 09:41:24 -0400 Subject: [PATCH 3/3] Clean up *nix-specific paths in spec There remain a few others in other specs, but someone who can test them reliably should clean those up. --- spec/git-repository-provider-spec.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/git-repository-provider-spec.coffee b/spec/git-repository-provider-spec.coffee index 176acee7d..13a0724d6 100644 --- a/spec/git-repository-provider-spec.coffee +++ b/spec/git-repository-provider-spec.coffee @@ -11,7 +11,7 @@ describe "GitRepositoryProvider", -> it "returns a Promise that resolves to a GitRepository", -> waitsForPromise -> provider = new GitRepositoryProvider atom.project - directory = new Directory path.join(__dirname, 'fixtures/git/master.git') + directory = new Directory path.join(__dirname, 'fixtures', 'git', 'master.git') provider.repositoryForDirectory(directory).then (result) -> expect(result).toBeInstanceOf GitRepository expect(provider.pathToRepository[result.getPath()]).toBeTruthy() @@ -24,11 +24,11 @@ describe "GitRepositoryProvider", -> secondRepo = null waitsForPromise -> - directory = new Directory path.join(__dirname, 'fixtures/git/master.git') + directory = new Directory path.join(__dirname, 'fixtures', 'git', 'master.git') provider.repositoryForDirectory(directory).then (result) -> firstRepo = result waitsForPromise -> - directory = new Directory path.join(__dirname, 'fixtures/git/master.git/objects') + directory = new Directory path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects') provider.repositoryForDirectory(directory).then (result) -> secondRepo = result runs -> @@ -60,7 +60,7 @@ describe "GitRepositoryProvider", -> it "returns a Promise that resolves to a GitRepository", -> waitsForPromise -> provider = new GitRepositoryProvider atom.project - gitDirPath = path.join(__dirname, 'fixtures/git/master.git') + gitDirPath = path.join(__dirname, 'fixtures', 'git', 'master.git') workDirPath = temp.mkdirSync('git-workdir') fs.writeFileSync(path.join(workDirPath, '.git'), 'gitdir: ' + gitDirPath+'\n')