
branch 명령어로 브랜치를 생성하거나, 삭제 또는 존재하는 브랜치들을 출력해줄 수 있다.
이 외에도 다른 옵션들이 많지만 위의 세 옵션만 처리하도록 하였다.
// geet/commands/porcelain/geetBranch.kt
package geet.commands.porcelain
import geet.exceptions.BadRequest
import geet.utils.commandutil.porcelainutil.branch
data class GeetBranchOptions( // 입력된 커맨드 라인의 옵션 정보를 저장하는 데이터 클래스
val branchName: String? = null, // 지정 브랜치 네임
val delete: Boolean = false // 삭제할 것인지
)
fun geetBranch(commandLines: Array<String>) {
val geetBranchOptions = getGeetBranchOptions(commandLines)
branch(geetBranchOptions)
}
fun getGeetBranchOptions(commandLines: Array<String>): GeetBranchOptions {
if (commandLines.size == 1) {
return GeetBranchOptions()
}
if (commandLines.size == 2) {
return GeetBranchOptions(branchName = commandLines[1])
}
if (commandLines.size == 3 && commandLines[1] == "-d") {
return GeetBranchOptions(branchName = commandLines[2], delete = true)
}
throw BadRequest("branch 명령어에 대하여 올바르지 않은 옵션입니다. : ${commandLines.joinToString(" ")}")
}
// geet/utils/commandutil/porcelainutil/branchUtil.kt
package geet.utils.commandutil.porcelainutil
import geet.commands.porcelain.GeetBranchOptions
import geet.exceptions.BadRequest
import geet.utils.GEET_REFS_HEADS_DIR_PATH
import java.io.File
fun branch(geetBranchOptions: GeetBranchOptions) {
if (geetBranchOptions.delete) { // 삭제 명령인 경우
deleteBranch(geetBranchOptions.branchName!!)
return
}
if (geetBranchOptions.branchName != null) { // 생성 명령인 경우
createBranch(geetBranchOptions.branchName)
return
}
// 출력 명령인 경우
showBranchList()
}
fun createBranch(branchName: String) { // 브랜치 생성
var file = File("${GEET_REFS_HEADS_DIR_PATH}/${branchName}")
if (file.exists()) { // 이미 존재하면 에러
throw BadRequest("브랜치가 이미 존재합니다. : ${branchName}")
}
if ("/" in branchName) { // 브랜치명에 '/'가 존재하는 경우 각 상위 폴더를 만들어 줘야 함
var branchDir = ""
val splitBranchName = branchName.trim().split("/")
splitBranchName.subList(0, splitBranchName.size - 1).forEach {
branchDir += "/${it}"
val dir = File("${GEET_REFS_HEADS_DIR_PATH}${branchDir}")
if (!dir.exists()) {
dir.mkdir()
}
}
file = File("${GEET_REFS_HEADS_DIR_PATH}${branchDir}/${splitBranchName.last()}")
}
file.createNewFile()
file.writeText(getCurrentRefCommitHash()) // 브랜치 파일엔 현재 브랜치의 커밋 해시값 저장
}
fun deleteBranch(branchName: String) { // 브랜치 삭제
val file = File("${GEET_REFS_HEADS_DIR_PATH}/${branchName}")
if (!file.exists()) { // 존재하지 않는 브랜치라면 에러
throw BadRequest("브랜치가 존재하지 않습니다. : ${branchName}")
}
file.delete()
}
fun showBranchList() { // 목록 출력
val headsDir = File(".geet/refs/heads")
headsDir.listFiles()?.forEach { headFile ->
getBranchNames(headFile).forEach { branchName ->
println(branchName)
}
}
}
fun getBranchNames(file: File): List<String> { // 브랜치 목록 얻어오기
val branchNames = mutableListOf<String>()
if (file.isDirectory) { // 파일이 폴더라면 재귀
file.listFiles()?.forEach {
branchNames.addAll(getBranchNames(it).map { branchName -> "${file.name}/${branchName}" })
}
}
if (!file.isDirectory) {
branchNames.add(file.name)
}
return branchNames
}
결과는 아래와 같이 잘 작동되는 모습
