diff --git a/SwiftGit2.xcodeproj/project.pbxproj b/SwiftGit2.xcodeproj/project.pbxproj index c5f52d1..afabe69 100644 --- a/SwiftGit2.xcodeproj/project.pbxproj +++ b/SwiftGit2.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ BE0991F71A578FB1007D4E6A /* Mantle.zip in Resources */ = {isa = PBXBuildFile; fileRef = BE0991F61A578FB1007D4E6A /* Mantle.zip */; }; + BE0B1C5D1A9978890004726D /* detached-head.zip in Resources */ = {isa = PBXBuildFile; fileRef = BE0B1C5C1A9978890004726D /* detached-head.zip */; }; BE14AA321A15AA510015B439 /* LlamaKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE14AA311A15AA510015B439 /* LlamaKit.framework */; }; BE14AA501A1974010015B439 /* SwiftGit2.m in Sources */ = {isa = PBXBuildFile; fileRef = BE14AA4F1A1974010015B439 /* SwiftGit2.m */; }; BE14AA551A1984550015B439 /* Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE14AA541A1984550015B439 /* Fixtures.swift */; }; @@ -71,6 +72,7 @@ /* Begin PBXFileReference section */ BE0991F61A578FB1007D4E6A /* Mantle.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = Mantle.zip; sourceTree = ""; }; + BE0B1C5C1A9978890004726D /* detached-head.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "detached-head.zip"; sourceTree = ""; }; BE14AA311A15AA510015B439 /* LlamaKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LlamaKit.framework; path = External/LlamaKit/build/Debug/LlamaKit.framework; sourceTree = ""; }; BE14AA4F1A1974010015B439 /* SwiftGit2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SwiftGit2.m; sourceTree = ""; }; BE14AA541A1984550015B439 /* Fixtures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fixtures.swift; sourceTree = ""; }; @@ -151,6 +153,7 @@ BE14AA531A1983520015B439 /* Fixtures */ = { isa = PBXGroup; children = ( + BE0B1C5C1A9978890004726D /* detached-head.zip */, BE14AA541A1984550015B439 /* Fixtures.swift */, BE0991F61A578FB1007D4E6A /* Mantle.zip */, BE14AA561A198C6E0015B439 /* simple-repository.zip */, @@ -439,6 +442,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + BE0B1C5D1A9978890004726D /* detached-head.zip in Resources */, BE0991F71A578FB1007D4E6A /* Mantle.zip in Resources */, BE14AA571A198C6E0015B439 /* simple-repository.zip in Resources */, ); diff --git a/SwiftGit2/References.swift b/SwiftGit2/References.swift index 47b9404..fa3e724 100644 --- a/SwiftGit2/References.swift +++ b/SwiftGit2/References.swift @@ -23,6 +23,17 @@ public func ==(lhs: T, rhs: T) -> Bool { && lhs.oid == rhs.oid } +/// Create a Reference, Branch, or TagReference from a libgit2 `git_reference`. +internal func referenceWithLibGit2Reference(pointer: COpaquePointer) -> ReferenceType { + if git_reference_is_branch(pointer) != 0 || git_reference_is_remote(pointer) != 0 { + return Branch(pointer)! + } else if git_reference_is_tag(pointer) != 0 { + return TagReference(pointer)! + } else { + return Reference(pointer) + } +} + /// A generic reference to a git object. public struct Reference: ReferenceType { /// The full name of the reference (e.g., `refs/heads/master`). diff --git a/SwiftGit2/Repository.swift b/SwiftGit2/Repository.swift index ce61f05..7981cb2 100644 --- a/SwiftGit2/Repository.swift +++ b/SwiftGit2/Repository.swift @@ -291,14 +291,7 @@ final public class Repository { return failure(libGit2Error(result, libGit2PointOfFailure: "git_reference_lookup")) } - var value: ReferenceType - if git_reference_is_branch(pointer.memory) != 0 || git_reference_is_remote(pointer.memory) != 0 { - value = Branch(pointer.memory)! - } else if git_reference_is_tag(pointer.memory) != 0 { - value = TagReference(pointer.memory)! - } else { - value = Reference(pointer.memory) - } + let value = referenceWithLibGit2Reference(pointer.memory) git_reference_free(pointer.memory) pointer.dealloc(1) @@ -343,4 +336,18 @@ final public class Repository { public func tagWithName(name: String) -> Result { return referenceWithName("refs/tags/" + name).map { $0 as! TagReference } } + + // MARK: - Working Directory + + /// Load the reference pointed at by HEAD. + /// + /// When on a branch, this will return the current `Branch`. + public func HEAD() -> Result { + var pointer = COpaquePointer.null() + let result = git_repository_head(&pointer, self.pointer) + if result != GIT_OK.value { + return failure(libGit2Error(result, libGit2PointOfFailure: "git_repository_head")) + } + return success(referenceWithLibGit2Reference(pointer)) + } } diff --git a/SwiftGit2Tests/Fixtures/Fixtures.swift b/SwiftGit2Tests/Fixtures/Fixtures.swift index cf31e88..574efc6 100644 --- a/SwiftGit2Tests/Fixtures/Fixtures.swift +++ b/SwiftGit2Tests/Fixtures/Fixtures.swift @@ -64,6 +64,10 @@ final class Fixtures { // MARK: - The Fixtures + class var detachedHeadRepository: Repository { + return Fixtures.sharedInstance.repositoryWithName("detached-head") + } + class var simpleRepository: Repository { return Fixtures.sharedInstance.repositoryWithName("simple-repository") } diff --git a/SwiftGit2Tests/Fixtures/detached-head.zip b/SwiftGit2Tests/Fixtures/detached-head.zip new file mode 100644 index 0000000..c819ab8 Binary files /dev/null and b/SwiftGit2Tests/Fixtures/detached-head.zip differ diff --git a/SwiftGit2Tests/RepositorySpec.swift b/SwiftGit2Tests/RepositorySpec.swift index 6c5d7d4..3c69267 100644 --- a/SwiftGit2Tests/RepositorySpec.swift +++ b/SwiftGit2Tests/RepositorySpec.swift @@ -412,5 +412,22 @@ class RepositorySpec: QuickSpec { expect(result).to(haveFailed(beAnError(domain: equal(libGit2ErrorDomain)))) } } + + describe("-HEAD()") { + it("should work when on a branch") { + let result = Fixtures.simpleRepository.HEAD() + expect(result.value?.longName).to(equal("refs/heads/master")) + expect(result.value?.shortName).to(equal("master")) + expect(result.value? as? Branch).notTo(beNil()) + } + + it("should work when on a detached HEAD") { + let result = Fixtures.detachedHeadRepository.HEAD() + expect(result.value?.longName).to(equal("HEAD")) + expect(result.value?.shortName).to(beNil()) + expect(result.value?.oid).to(equal(OID(string: "315b3f344221db91ddc54b269f3c9af422da0f2e")!)) + expect(result.value? as? Reference).notTo(beNil()) + } + } } }