Skip to content

Commit d8e15e0

Browse files
authored
Merge pull request #698 from aciidb0mb3r/git-branch
[GitRepo] Add methods to check and create branches
2 parents 7821152 + 05259d2 commit d8e15e0

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

Sources/SourceControl/GitRepository.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,21 @@ public class GitRepository: Repository, WorkingCheckout {
349349
try runCommandQuietly([Git.tool, "-C", path.asString, "reset", "--hard", revision.identifier])
350350
}
351351

352+
/// Returns true if a revision exists.
353+
public func exists(revision: Revision) -> Bool {
354+
do {
355+
_ = try runCommandQuietly([Git.tool, "-C", path.asString, "rev-parse", "--verify", revision.identifier])
356+
} catch {
357+
return false
358+
}
359+
return true
360+
}
361+
362+
public func checkout(newBranch: String) throws {
363+
precondition(isWorkingRepo, "This operation should run in a working repo.")
364+
try runCommandQuietly([Git.tool, "-C", path.asString, "checkout", "-b", newBranch])
365+
}
366+
352367
// MARK: Git Operations
353368

354369
/// Resolve a "treeish" to a concrete hash.

Sources/SourceControl/Repository.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ public protocol WorkingCheckout {
156156

157157
/// Check out the given revision.
158158
func checkout(revision: Revision) throws
159+
160+
/// Returns true if the given revision exists.
161+
func exists(revision: Revision) -> Bool
162+
163+
/// Create a new branch and checkout HEAD to it.
164+
///
165+
/// Note: It is an error to provide a branch name which already exists.
166+
func checkout(newBranch: String) throws
159167
}
160168

161169
/// A single repository revision.

Tests/SourceControlTests/GitRepositoryTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,41 @@ class GitRepositoryTests: XCTestCase {
382382
}
383383
}
384384

385+
func testBranchOperations() throws {
386+
mktmpdir { path in
387+
// Create a repo.
388+
let testRepoPath = path.appending(component: "test-repo")
389+
try makeDirectories(testRepoPath)
390+
initGitRepo(testRepoPath)
391+
392+
let repo = GitRepository(path: testRepoPath)
393+
var currentRevision = try repo.getCurrentRevision()
394+
// This is the default branch of a new repo.
395+
XCTAssert(repo.exists(revision: Revision(identifier: "master")))
396+
// Check a non existent revision.
397+
XCTAssertFalse(repo.exists(revision: Revision(identifier: "nonExistent")))
398+
// Checkout a new branch using command line.
399+
try systemQuietly([Git.tool, "-C", testRepoPath.asString, "checkout", "-b", "TestBranch1"])
400+
XCTAssert(repo.exists(revision: Revision(identifier: "TestBranch1")))
401+
XCTAssertEqual(try repo.getCurrentRevision(), currentRevision)
402+
403+
func getCurrentBranch() throws -> String {
404+
return try popen([Git.tool, "-C", testRepoPath.asString, "rev-parse", "--abbrev-ref", "HEAD"]).chomp()
405+
}
406+
// Make sure we're on the new branch right now.
407+
XCTAssertEqual(try getCurrentBranch(), "TestBranch1")
408+
409+
// Checkout new branch using our API.
410+
currentRevision = try repo.getCurrentRevision()
411+
try repo.checkout(newBranch: "TestBranch2")
412+
XCTAssert(repo.exists(revision: Revision(identifier: "TestBranch2")))
413+
XCTAssertEqual(try repo.getCurrentRevision(), currentRevision)
414+
XCTAssertEqual(try getCurrentBranch(), "TestBranch2")
415+
}
416+
}
417+
385418
static var allTests = [
419+
("testBranchOperations", testBranchOperations),
386420
("testFetch", testFetch),
387421
("testRepositorySpecifier", testRepositorySpecifier),
388422
("testProvider", testProvider),

0 commit comments

Comments
 (0)