Git Cherry-Pick: 특정 커밋 선택 및 적용하는 방법

협업 소프트웨어 개발 환경에서 브랜치 작업은 기능, 버그 수정 또는 실험을 분리하는 데 필수적입니다. 그러나 특정 브랜치에서 특정 변경 사항을 가져와 전체 브랜치를 병합하지 않고 다른 브랜치에 적용해야 할 때가 있습니다. 이때 git cherry-pick이 매우 유용해집니다.

이 튜토리얼의 목표는 git cherry-pick을 효과적으로 사용하는 방법에 대한 포괄적인 가이드를 제공하는 것입니다. 명령어의 구문을 배우고, 충돌을 처리하는 방법을 이해하며, 모범 사례와 피해야 할 일반적인 함정을 탐색할 것입니다. 시작해봅시다!

Git Cherry-Pick이란?

git cherry-pick 명령은 개발자에게 소스 코드에 대한 세밀한 제어를 제공하는 기본 Git 명령입니다.

다른 Git 작업과는 달리 merge 또는 rebase와 같이 전체 브랜치와 작동하는 것과는 달리, cherry-pick은 한 브랜치에서 특정 커밋을 가져와 다른 브랜치에 적용할 수 있습니다. 이는 특히 특정 변경 사항만 통합해야 하는 시나리오에서 정확성을 제공합니다.

git cherry-pick 명령은 선택한 커밋의 내용을 복사하여 대상 브랜치에 새로운 커밋을 생성하면서 커밋 히스토리의 무결성을 유지합니다.

git cherry-pick를 사용하는 시기

git cherry-pick을 사용하는 경우는 다음과 같습니다:

  • 버그 수정 역포팅: 개발 브랜치에서 버그를 해결하고 안정적이거나 릴리스 브랜치에서 동일한 수정을 필요로 할 때, 체리 피킹을 통해 불필요한 변경 사항을 가져오지 않고 버그 수정을 이동할 수 있습니다.
  • 핫픽스 적용: 프로덕션에서 중요한 수정이 필요한 상황에서 개발 브랜치가 계속 발전하는 경우, 체리 피킹을 통해 수정 사항을 추출하고 프로덕션 브랜치에 적용할 수 있습니다.
  • 테스트를 위한 기능 격리: 특정 기능과 관련된 특정 커밋만 테스트해야 할 수도 있습니다. 전체 기능 브랜치를 병합하는 대신 필요한 커밋을 체리 피킹하여 테스트 브랜치를 깨끗하고 효율적으로 유지할 수 있습니다.
  • 잘못 배치된 커밋 수정: 커밋이 실수로 잘못된 브랜치에 푸시된 경우, 프로젝트 기록을 방해하지 않고 적절한 브랜치에 커밋을 체리 피킹할 수 있습니다.
  • 여러 브랜치에서 변경 사항 재사용: 여러 브랜치에서 같은 업데이트가 필요할 때, 체리 피킹을 통해 작업을 다시 하지 않거나 브랜치 복잡성을 도입하지 않고도 다른 브랜치에서 변경 사항을 복제할 수 있습니다.

Git Cherry-Pick 문법

git cherry-pick 문법을 이해하는 것은 이 명령을 효과적으로 사용하는 데 핵심입니다. 단순히 커밋을 선택하는 것이 아니라, 원하는 결과를 얻기 위해 정확하게 적용하는 것이 중요합니다.

단일 커밋을 cherry-pick하는 기본 구문은 다음과 같습니다:

git cherry-pick <commit-hash>
  • git cherry-pick: 작업을 시작하는 명령어입니다.
  • <commit-hash>: cherry-pick하려는 커밋의 고유 식별자 (SHA-1 해시)입니다. 이 해시는 git log를 실행하여 커밋 히스토리를 나열하여 찾을 수 있습니다.

위 명령을 실행하면 Git은 지정된 커밋에서 변경 사항을 현재 브랜치에 적용하여 동일한 변경 사항을 가진 다른 해시를 가진 새 커밋을 만듭니다.

중요한 점은 해당 명령이 커밋 자체만 전송하고 원래 브랜치의 컨텍스트나 부모 히스토리를 전송하지 않는다는 것입니다.

Git 및 GitHub가 처음이신가요? 이 초보자 친화적인 GitHub 및 Git 튜토리얼로 버전 관리를 시작해 보세요.

Git Cherry-Pick 사용법: 단계별 예제

이제 git cherry-pick의 기본 구문을 이해했으니, 명령어를 실제로 실행해 볼 시간입니다.

이 섹션에서는 체리픽이 유용한 일반적인 기본 및 더 복잡한 시나리오를 안내하는 실습 예제를 제공합니다. 각 예제는 하나 이상의 커밋에서 변경 사항을 다른 브랜치에 적용하는 방법을 설명합니다.

예제 1: 단일 커밋 체리픽

기능 브랜치에서 수정한 내용을 메인 브랜치에 병합하지 않고 적용하고 싶다고 가정해 보겠습니다.

  • 먼저 다음을 실행하여 cherry-pick하려는 커밋의 해시를 찾으세요:
git log
  • 커밋의 해시를 찾습니다.
  • 메인 브랜치로 전환하십시오:
git checkout main
  • cherry-pick 명령을 실행하십시오 (해시가 abc1234라고 가정):
git cherry-pick abc1234

이 명령을 실행하면 Git은 현재 브랜치(이 경우에는 main)에 커밋 abc1234에서 변경 사항을 적용합니다. Git은 원본 커밋과 동일한 변경 사항을 포함하고 새로운 커밋 해시를 가진 main 브랜치에 새로운 커밋을 생성합니다.

예제 2: 복수의 커밋 체리픽하기

일부 상황에서 한 브랜치에서 다른 브랜치로 여러 개의 구분된 커밋을 적용해야 할 수 있습니다. 예를 들어 feature 브랜치에 세 개의 별도 커밋이 있고 이를 main 브랜치로 가져와야 할 경우가 있습니다.

  • git log를 사용하여 체리픽하려는 각 커밋의 커밋 해시를 찾습니다:
git log
  • main 브랜치로 전환합니다:
git checkout main
  • 체리픽 명령을 실행하여 커밋을 나열합니다:
git cherry-pick abc1234 def5678 ghi7890

예제 3: 커밋 범위를 체리픽하는 방법

피처 브랜치에서 일련의 커밋을 만들었고 각 커밋을 개별적으로 지정하지 않고 한 번에 메인 브랜치에 적용하려면 어떻게 해야 합니까?

  • git log를 사용하여 체리픽하려는 시작 및 끝 커밋을 식별합니다 (예: abc1234부터 ghi7890까지).
  • 메인 브랜치로 전환:
git checkout main
  • 커밋 범위를 지정하여 체리픽 명령을 실행하세요:
git cherry-pick abc1234...ghi7890

예제 4: 원격 브랜치로부터 커밋을 체리픽하기

때때로, 원격 브랜치에 중요한 수정 사항이 존재하고 전체 브랜치를 병합하지 않고 이를 로컬 브랜치에 적용하고 싶을 수 있습니다. 다음은 그 방법입니다:

  • 원격 리포지토리에서 최신 변경 사항 가져오기
git fetch origin
  • 원격 브랜치에서 필요한 해시를 찾기 위해 커밋 목록을 확인합니다:
git log origin/feature_branch --oneline
  • 필요한 커밋 해시가 abc1234라고 가정합니다.
  • 로컬 메인 브랜치로 전환합니다:
git checkout main
  • 원격 브랜치에서 커밋을 체리픽합니다:
git cherry-pick abc1234

이 기능을 사용하면 전체 브랜치를 병합하지 않고도 원격 브랜치에서 커밋을 적용할 수 있습니다.

원격 브랜치를 체크아웃해야 하나요? 원격 브랜치에 대한 Git 체크아웃 단계별 가이드를 따라하세요.

예시 5: 커밋을 체리픽하고 수정하기

커밋을 체리픽했지만 커밋하기 전에 약간의 수정을 해야 한다면, Git의 대화형 모드를 사용할 수 있습니다. 방법은 다음과 같습니다:

  • 대상 브랜치로 전환:
git checkout main
  • 커밋하기 전에 커밋을 체리픽하지만 중지합니다:
git cherry-pick -n abc1234

명령어 -n (또는 --no-commit) 플래그는 변경 사항을 적용하지만 커밋을 생성하지 않습니다.

  • 필요에 따라 파일을 수정하십시오.
  • 변경 사항을 수동으로 스테이지하고 커밋하십시오:
git add . git commit -m "Modified cherry-picked commit from feature_branch"

이 방법은 최종화하기 전에 체리 픽한 커밋을 조정해야 할 때 유용합니다.

Git 체리 픽 중 충돌 처리

브랜치 간 커밋을 체리 픽할 때 충돌은 불가피하며, 특히 코드베이스가 크게 분기된 경우에 더욱 그렇습니다.

체리 픽(cherry-pick)은 변경 사항을 깔끔하게 적용하도록 설계되었지만, 항상 차이를 자동으로 조정할 수는 없습니다. 이러한 경우, 충돌은 수동으로 해결해야 합니다. 충돌이 발생하는 방식과 이를 처리하는 방법을 이해하는 것은 cherry-pick 작업을 완료하는 데 매우 중요합니다.

충돌이 발생하는 방법

충돌은 일반적으로 체리 픽한 커밋의 변경 사항이 대상 브랜치에 이미 존재하는 변경 사항과 겹치거나 모순될 때 발생합니다. 예를 들어:

  • 두 브랜치에서 동일한 줄이 수정된 경우: 소스 브랜치와 대상 브랜치 모두에서 동일한 코드 줄이 수정된 경우, Git은 어떤 버전을 적용해야 할지 알 수 없습니다.
  • 한 브랜치에서 파일이 삭제되었지만 다른 브랜치에서 수정된 경우: 한 브랜치에서 파일이 삭제되었지만 체리픽된 커밋에서 수정된 경우, Git은 해당 파일을 유지할지 변경 사항을 적용할지 알지 못합니다.
  • 무관한 변경 사항이지만 동일한 파일인 경우: 변경 사항이 무관해 보이더라도 동일한 파일 내에서 발생하면 Git은 이를 잠재적인 충돌로 표시할 수 있습니다.

충돌이 발생하면, Git은 cherry-pick 작업을 중단하고 작업 디렉토리를 충돌 상태로 남겨 두며, 진행하기 전에 해결해야 합니다.

충돌 해결

충돌이 발생하면 Git은 충돌하는 파일의 지시자를 제공하며, 불일치를 수동으로 해결해야 합니다. 충돌 해결 방법은 다음과 같습니다:

1. 충돌하는 파일을 확인하세요: 다음 명령을 실행하여 충돌하는 파일을 확인합니다:

git status

해당 명령은 충돌이 발생한 파일 목록을 표시합니다.

2. 충돌 해결하기: 충돌하는 파일을 수동으로 편집하여 문제를 해결할 수 있습니다. 충돌 표시자(<<<<<<<, =======, >>>>>>>)를 제거하고 어떤 변경 사항을 유지할지 또는 어떻게 결합할지를 결정하십시오.

3. Git 병합 도구 사용하기 (선택 사항): 수동으로 충돌을 해결하는 것이 번거롭다면, 병합 도구를 사용하여 충돌을 시각화하고 해결할 수 있습니다:

git mergetool

설정에 따라 위의 도구는 시각적 병합 도구를 열며, 이를 통해 충돌을 검토하고 해결하기가 더 쉬워집니다.

4. 충돌을 해결된 것으로 표시하기: 충돌을 해결한 후, 파일을 해결된 것으로 표시하려면:

git add <conflicted-file>

5. 완료된 cherry-pick: 모든 충돌이 해결되고 파일이 스테이징된 후, 다음을 실행하여 cherry-pick을 완료하세요:

git cherry-pick --continue

현대적인 IDE 및 도구인 Visual Studio Code 및 GitHub과 같은 많은 도구들은 내장된 병합 충돌 해결 기능을 제공합니다. GitHub의 웹 인터페이스를 통해 pull request에서 충돌을 직접 해결할 수 있어 로컬 환경으로 전환하지 않고도 공유 저장소에서 협업하기가 더 쉬워집니다.

충돌 후 커밋 건너뛰기

가끔 충돌을 해결하는 것이 너무 복잡하거나 해당 커밋이 전혀 필요하지 않다는 것을 깨닫는 경우가 있습니다. 이러한 경우에는 해당 커밋을 완전히 건너뛸 수 있습니다.

1. 현재 cherry-pick 프로세스를 중단하려면: 충돌이 너무 복잡하고 커밋을 적용하고 싶지 않은 경우 다음을 실행하여 건너뛸 수 있습니다:

git cherry-pick --skip

이렇게 하면 충돌하는 커밋이 포기되고 다음으로 넘어갑니다 (여러 커밋을 cherry-pick하는 경우).

2. 전체 cherry-pick을 중단하려면: cherry-pick 작업을 완전히 중단하려면 다음을 실행할 수 있습니다:

git cherry-pick --abort

이 명령은 cherry-pick을 시작하기 전의 작업 디렉토리 상태로 복원합니다.

커밋 히스토리를 정리하고 싶나요? 여러 커밋을 하나로 합치는 방법을 배워보세요 Git squash 튜토리얼으로.

Git Cherry-Pick 사용의 최상의 실천법

cherry-pick을 오용하면 프로젝트 버전 관리에서 복잡한 이력과 혼란을 초래할 수 있습니다. 이러한 함정을 피하려면 최상의 실천법을 준수하여 코드베이스에 불필요한 복잡성을 도입하지 않고 효과적으로 cherry-pick을 사용하는 것이 중요합니다.

작고 구체적으로 유지

버그 수정이나 작은 기능 향상과 같이 명확한 작업을 다루는 작고 구체적인 커밋에 대해 cherry-pick을 사용할 때 가장 효과적입니다. 

대규모이고 복잡한 변경 사항을 번들로 묶은 커밋을 선택하는 것을 피하십시오. 이는 충돌을 일으키고 코드베이스를 관리하기 어렵게 만들 수 있습니다. 커밋이 더 명확할수록 의도하지 않은 부작용 없이 적용하기 쉬워집니다.

체리픽에 대한 문서화

명확한 히스토리를 유지하기 위해 항상 체리픽할 때 적절한 문맥을 제공하십시오. 이는 자세한 커밋 메시지나 문서 주석을 통해 수행할 수 있습니다.

핵심은 왜 체리픽이 필요했는지 설명해야 한다는 것입니다. 특히 장기 브랜치나 협업 환경을 통해 체리픽하는 경우에는 미래 기여자가 변경 사항이 선택적으로 적용된 이유를 이해할 수 있도록 도움이 됩니다.

커밋 히스토리 검토

체리픽하기 전에 출발지 브랜치와 대상 브랜치의 커밋 히스토리를 검토하세요. 이 단계는 체리픽하려는 커밋이 다른 변경 사항에 의존하는지 여부를 확인하는 데 도움이 됩니다. 필요한 종속성이 빠지면 불완전한 기능이나 버그가 발생할 수 있으므로, 체리픽이 반숙한 기능이나 업데이트를 도입하지 않도록 합니다.

체리픽 과용 피하기

특정 변경 사항을 적용할 때 체리픽은 편리하지만, 과도한 사용은 중복된 커밋이 브랜치 간에 생기며 단편화된 히스토리를 유발할 수 있습니다. 이로 인해 특정 변경의 원천을 추적하거나 더 넓은 개발 맥락을 이해하기 어려울 수 있습니다.

항상 체리픽하기 전에 병합 또는 리베이스가 더 적합한 전략인지를 평가하세요. 커밋 히스토리를 혼란스럽게 만들지 않도록 cherry-pick을 적게하고 목적을 가지고 사용하세요.

Git에서 불필요한 파일에 곤란하신가요? .gitignore를 효과적으로 사용하는 방법을 배우세요 Git 무시 튜토리얼.

Git Cherry-Pick에서 발생하는 일반적인 문제 해결

cherry-pick을 사용할 때 발생하는 문제를 해결하려면 Git의 기본 메커니즘을 명확히 이해해야 합니다. 이 섹션에서는 cherry-picking 중에 발생할 수 있는 몇 가지 일반적인 문제와 해결 방법에 대해 다룰 것입니다.

존재하지 않는 커밋을 cherry-pick하기

가끔 현재 브랜치에서 액세스할 수 없거나 이미 병합된 커밋을 cherry-pick하려고 할 수 있습니다. 이는 일반적으로 해당 커밋을 찾거나 적용할 수 없다는 오류 메시지로 나타납니다.

1. Commit을 찾을 수 없음:이는 cherry-pick하려는 커밋 해시가 현재 저장소나 브랜치 컨텍스트에 존재하지 않을 때 발생합니다. 해당 커밋이 존재하는 브랜치에서 git log를 사용하여 커밋 히스토리를 확인하여 올바른 커밋을 참조하는지 확인하십시오. 해결 방법:

  • 커밋 해시가 올바른지 다시 한번 확인하십시오.
  • 접근할 수 있는 브랜치에 커밋이 존재하는지 확인하십시오.
  • 커밋이 원격 브랜치에 있는 경우 git fetch로 브랜치를 가져왔는지 확인하십시오.

2. 이미 적용된 커밋: 커밋이 이미 대상 브랜치에 병합되거나 체리픽되었을 경우 Git은 중복 방지를 위해 해당 동작을 제한합니다. 이 방어 기능을 통해 히스토리를 깨끗하게 유지하고 중복 변경을 피할 수 있습니다. 해결 방법:

  • git log을 사용하여 대상 브랜치에 이미 커밋이 있는지 확인하세요.
  • 필요하다면 변경 사항이 이미 적용되었으므로 cherry-pick 작업을 건너뛰세요.

리베이스나 병합 이후 체리픽하기

리베이스나 병합 이후 체리픽을 하는 경우 브랜치의 변경된 히스토리로 인해 복잡성이 발생할 수 있습니다. 리베이스는 커밋 히스토리를 다시 작성하며 병합은 브랜치를 결합하므로 둘 다 체리픽의 적용 가능성에 영향을 줄 수 있습니다.

1. 리베이스된 커밋으로 인한 충돌: 리베이스 후에는 커밋 히스토리가 다시 작성되므로, 리베이스 프로세스 중 변경된 커밋을 cherry-pick하려고 하면 문제가 발생할 수 있습니다. cherry-pick이 다시 작성된 히스토리와 일치하지 않는 변경 사항을 적용하려고 시도하면 충돌이 발생할 수 있습니다. 해결 방법:

  • 리베이스 후 git log를 사용하여 cherry-pick하려는 커밋이 이미 수정되었는지를 신중히 검토하십시오.
  • 충돌을 해결할 때는 표준 cherry-pick 프로세스와 동일하게 git status 및 수동 편집을 사용하십시오.

2. 병합 후 중복 커밋: 브랜치를 병합하면 체리픽하려는 커밋이 이미 병합된 히스토리에 포함되어 있는 상황이 발생할 수 있습니다. 이를 다시 체리픽하면 중복된 커밋이 발생하여 히스토리를 혼란스럽게 만들고 변경 사항을 추적하기 어렵게 할 수 있습니다. 해결책:

  • 체리픽하기 전에 두 브랜치의 커밋 히스토리를 검토하여 해당 커밋이 이미 병합되었는지 확인하십시오.
  • 대상 브랜치에 이미 해당 커밋이 있는 경우 동일한 커밋을 체리픽하지 마십시오.

Git에서 변경 사항을 되돌릴 필요가 있나요? git reset vs. git revert를 사용할 때 알아보세요. Git reset 및 revert 튜토리얼.

결론

git cherry-pick은 전체 브랜치를 병합하지 않고 특정 커밋을 한 브랜치에서 다른 브랜치로 적용하는 강력한 방법입니다. 버그 수정, 기능 업데이트 또는 선택적으로 변경 사항을 적용하는 경우에 관계없이 Git 기록을 깔끔하고 집중적으로 유지하는 데 도움이 됩니다.

이 가이드에서는 단일 및 여러 커밋을 cherry-pick하는 방법, 충돌을 해결하는 방법, 일반적인 함정을 피하기 위한 모범 사례를 다루었습니다. cherry-pick을 현명하게 사용하면 리포지토리를 정리된 상태로 유지하면서 작업 흐름을 개선할 수 있습니다.

Git 기술을 심화하고 싶다면 Git 기초를 강력한 출발점으로 확인해 보세요. 또한 GitHub 개념 소개를 탐색하거나 GitHub 기초 기술 트랙을 통해 체계적인 접근 방식을 취할 수도 있습니다.

이제 프로처럼 cherry-pick하는 방법을 알았으니, 다음 프로젝트에서 시도해 보세요!

Source:
https://www.datacamp.com/tutorial/git-cherry-pick