Skip to content

Commit 947c584

Browse files
authored
fix: paths with spaces (#22)
1 parent eb2d24e commit 947c584

File tree

2 files changed

+82
-3
lines changed

2 files changed

+82
-3
lines changed

Sources/GitKit/Git.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public final class Git: Shell {
7676
case .clone(let url, let dirname):
7777
params = [Command.clone.rawValue, url]
7878
if let dirName = dirname {
79-
params.append(dirName)
79+
params.append("\"\(dirName)\"")
8080
}
8181
case .checkout(let branch, let create, let tracking):
8282
params = [Command.checkout.rawValue]
@@ -281,14 +281,15 @@ public final class Git: Shell {
281281
var cmd: [String] = []
282282
// if there is a path let's change directory first
283283
if let path = self.path {
284+
let quotedPath = "\"\(path)\""
284285
// try to create work dir at given path for init or clone commands
285286
if
286287
alias.rawValue.hasPrefix(Command.initialize.rawValue) ||
287288
alias.rawValue.hasPrefix(Command.clone.rawValue)
288289
{
289-
cmd += ["mkdir", "-p", path, "&&"]
290+
cmd += ["mkdir", "-p", quotedPath, "&&"]
290291
}
291-
cmd += ["cd", path, "&&"]
292+
cmd += ["cd", quotedPath, "&&"]
292293
}
293294
cmd += ["git", alias.rawValue]
294295

Tests/GitKitTests/GitKitTests.swift

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ final class GitKitTests: XCTestCase {
3838
("testCommitVariations", testCommitVariations),
3939
("testLogVariations", testLogVariations),
4040
("testLogWithRevisions", testLogWithRevisions),
41+
("testPathsWithSpaces", testPathsWithSpaces),
42+
("testCloneWithSpacesInDirectoryName", testCloneWithSpacesInDirectoryName),
4143
]
4244

4345
// MARK: - helpers
@@ -586,6 +588,82 @@ final class GitKitTests: XCTestCase {
586588
try self.clean(path: path)
587589
}
588590

591+
func testPathsWithSpaces() throws {
592+
let basePath = self.currentPath()
593+
let pathWithSpaces = "\(basePath) with spaces"
594+
595+
try self.clean(path: pathWithSpaces)
596+
597+
let git = Git(path: pathWithSpaces)
598+
599+
// Test basic operations in a path with spaces
600+
try git.run(.raw("init"))
601+
try git.run(.raw("config user.name 'Test User'"))
602+
try git.run(.raw("config user.email 'test@example.com'"))
603+
604+
// Create a file and test git operations
605+
FileManager.default.createFile(atPath: "\(pathWithSpaces)/test file.txt", contents: "test content".data(using: .utf8))
606+
607+
try git.run(.addAll)
608+
let statusOutput = try git.run(.status(short: true))
609+
XCTAssertTrue(statusOutput.contains("A"), "File should be staged")
610+
611+
try git.run(.commit(message: "test commit with spaces in path", allowEmpty: false))
612+
613+
let logOutput = try git.run(.log(numberOfCommits: 1, options: ["--oneline"]))
614+
XCTAssertTrue(logOutput.contains("test commit with spaces in path"), "Commit should be successful")
615+
616+
// Test status after commit
617+
let cleanStatus = try git.run(.status(short: true))
618+
XCTAssertTrue(cleanStatus.isEmpty, "Working directory should be clean after commit")
619+
620+
try self.clean(path: pathWithSpaces)
621+
}
622+
623+
func testCloneWithSpacesInDirectoryName() throws {
624+
let basePath = self.currentPath()
625+
let currentDirectory = FileManager.default.currentDirectoryPath
626+
let sourcePath = "\(currentDirectory)/\(basePath)-source"
627+
let clonePath = "\(currentDirectory)/\(basePath) clone path"
628+
let targetDirName = "repo with spaces"
629+
630+
try self.clean(path: sourcePath)
631+
try self.clean(path: clonePath)
632+
633+
// Create source repository
634+
let sourceGit = Git(path: sourcePath)
635+
try sourceGit.run(.raw("init"))
636+
try sourceGit.run(.raw("config user.name 'Test User'"))
637+
try sourceGit.run(.raw("config user.email 'test@example.com'"))
638+
try sourceGit.run(.raw("commit -m 'initial commit' --allow-empty --no-gpg-sign"))
639+
640+
// Test cloning into a path with spaces
641+
let git = Git(path: clonePath)
642+
try git.run(.clone(url: sourcePath, dirName: targetDirName))
643+
644+
// Verify the clone was successful
645+
let clonedRepoPath = "\(clonePath)/\(targetDirName)"
646+
XCTAssertTrue(FileManager.default.fileExists(atPath: clonedRepoPath), "Cloned repository should exist")
647+
XCTAssertTrue(FileManager.default.fileExists(atPath: "\(clonedRepoPath)/.git"), "Cloned repository should have .git directory")
648+
649+
// Test git operations in the cloned repo with spaces in path
650+
let clonedGit = Git(path: clonedRepoPath)
651+
let statusOutput = try clonedGit.run(.status())
652+
XCTAssertTrue(statusOutput.contains("On branch main"), "Should be on main branch")
653+
XCTAssertTrue(statusOutput.contains("nothing to commit"), "Should be clean working directory")
654+
655+
// Test creating and committing a file with spaces in the repo path
656+
FileManager.default.createFile(atPath: "\(clonedRepoPath)/file with spaces.txt", contents: "content".data(using: .utf8))
657+
try clonedGit.run(.addAll)
658+
try clonedGit.run(.commit(message: "add file with spaces"))
659+
660+
let logOutput = try clonedGit.run(.log(numberOfCommits: 1, options: ["--oneline"]))
661+
XCTAssertTrue(logOutput.contains("add file with spaces"), "New commit should exist")
662+
663+
try self.clean(path: sourcePath)
664+
try self.clean(path: clonePath)
665+
}
666+
589667
#if os(macOS)
590668
func testAsyncRun() throws {
591669
let path = self.currentPath()

0 commit comments

Comments
 (0)