[Git 만들어보기 - Geet] geet branch 명령어로 브랜치 생성, 삭제, 목록 출력 하기

송준섭 Junseop Song·2024년 3월 18일

Git 만들어보기 - Geet

목록 보기
11/21
post-thumbnail

2024-02-18 구현

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
}

결과는 아래와 같이 잘 작동되는 모습

0개의 댓글