3-5. Git의 advanced merging: merge 전략
1. Git Merge 전략의 이해
Git의 merge는 두 분기(branch)의 변경 사항을 통합하는 핵심적인 기능입니다. 하지만 단순히 변경 사항을 합치는 것 외에도, merge를 수행하는 방식, 즉 "merge 전략"을 선택하여 병합 과정을 제어할 수 있습니다. 이러한 전략들은 프로젝트의 복잡성, 팀 협업 방식, 그리고 특정 상황에 따라 최적의 병합 결과를 얻기 위해 고안되었습니다.
Git은 기본적으로 세 가지 기본적인 merge 전략을 제공하며, 이를 통해 개발자는 병합 방식을 세밀하게 조정할 수 있습니다. 이번 포스트에서는 이러한 merge 전략들의 개념과 실용적인 활용법을 자세히 살펴보겠습니다.
1) 왜 Merge 전략이 필요할까요?
프로젝트가 커지고 여러 개발자가 동시에 작업하게 되면, 서로 다른 브랜치에서 변경된 내용들이 충돌(conflict)하는 경우가 빈번하게 발생합니다. 이러한 충돌은 Git이 자동으로 해결할 수 없는 부분으로, 개발자가 직접 수정해야 합니다. Merge 전략은 이러한 충돌을 최소화하고, 병합 과정을 보다 효율적으로 관리할 수 있도록 돕습니다.
Merge 전략을 선택함으로써 다음을 제어할 수 있습니다.
- 충돌 해결 방식: 충돌 발생 시 Git이 자동으로 해결하는 방식을 변경하거나, 특정 브랜치의 변경 사항을 우선시하도록 설정할 수 있습니다.
- 병합 히스토리: 병합 과정에서 생성되는 커밋의 형태를 제어하여, 프로젝트 히스토리의 가독성을 높일 수 있습니다.
- 성능: 대규모 프로젝트에서 병합 속도를 최적화할 수 있습니다.
2) Merge 전략의 종류
Git은 다양한 merge 전략을 제공하며, 각 전략은 고유한 특징과 사용 사례를 가지고 있습니다. 주요 merge 전략은 다음과 같습니다.
recursive: 두 개 이상의 부모를 가진 merge를 처리하기 위한 기본적인 전략입니다. 가장 일반적으로 사용되는 전략이며, 2개의 브랜치를 병합할 때 기본적으로 사용됩니다.ours: 항상 현재 브랜치의 내용을 사용합니다. 다른 브랜치의 변경 사항은 무시됩니다.theirs: 항상 병합 대상 브랜치의 내용을 사용합니다. 현재 브랜치의 변경 사항은 무시됩니다.subtree: 특정 하위 디렉토리를 다른 브랜치로 병합하는 데 사용됩니다. 프로젝트의 하위 디렉토리를 독립적인 Git 저장소처럼 취급할 수 있도록 해줍니다.
2. Recursive Merge 전략
recursive merge 전략은 Git의 기본 병합 전략이며, 두 개의 브랜치를 병합할 때 사용됩니다. 이 전략은 두 브랜치의 공통 조상(common ancestor)을 찾아, 각 브랜치에서 해당 조상까지의 변경 사항을 비교하고, 이를 병합합니다. 충돌이 발생하면 개발자가 직접 해결해야 합니다.
1) 작동 방식
recursive 전략은 다음과 같은 단계를 거쳐 병합을 수행합니다.
- 공통 조상 찾기: 병합하려는 두 브랜치의 공통 조상을 찾습니다. 이는 두 브랜치 모두에 존재하는 가장 오래된 커밋입니다.
- 변경 사항 비교: 각 브랜치에서 공통 조상 이후의 변경 사항을 비교합니다.
- 병합: 변경 사항을 병합합니다. Git은 자동 병합이 가능한 경우(충돌이 없는 경우) 자동으로 병합을 수행하고, 충돌이 발생하면 사용자에게 해결을 요청합니다.
2) 예시
예를 들어, main 브랜치와 feature 브랜치를 병합한다고 가정해 보겠습니다. main 브랜치와 feature 브랜치의 공통 조상이 존재하고, 각 브랜치에서 서로 다른 파일이 수정되었다면, recursive 전략은 이러한 변경 사항들을 병합하여 새로운 커밋을 생성합니다. 만약, 동일한 파일의 동일한 부분을 수정했다면, 충돌이 발생하고 개발자가 직접 해결해야 합니다.

3. Ours Merge 전략
ours merge 전략은 현재 브랜치의 내용을 "항상" 우선시합니다. 즉, 병합 대상 브랜치의 변경 사항은 모두 무시되고, 현재 브랜치의 내용만 유지됩니다. 이 전략은 특정 브랜치의 변경 사항을 완전히 무시하고 싶을 때 유용합니다.
1) 사용 목적
ours 전략은 다음과 같은 상황에서 유용하게 사용될 수 있습니다.
- 특정 기능 제거: 특정 브랜치에서 개발된 기능을 완전히 제거하고 싶을 때.
- 설정 파일 유지: 설정 파일과 같이 특정 브랜치에서 변경이 이루어지지 않도록 유지하고 싶을 때.
- 임시 브랜치 병합: 임시 브랜치에서 실험적인 변경 사항을 적용한 후, 해당 변경 사항을 무시하고 싶을 때.
2) 사용법
ours 전략을 사용하여 병합하려면, git merge 명령에 --strategy=ours 옵션을 사용합니다.
git merge --strategy=ours <병합 대상 브랜치>
예를 들어, feature 브랜치의 변경 사항을 무시하고 main 브랜치의 내용만 유지하려면, 다음과 같이 명령을 실행합니다.
git checkout main
git merge --strategy=ours feature
이 명령을 실행하면, feature 브랜치의 모든 변경 사항이 무시되고, main 브랜치의 내용이 유지된 채로 병합이 완료됩니다. 이 경우, Git은 자동으로 병합을 완료하며, 충돌 해결 과정은 필요하지 않습니다.
3) 주의사항
ours 전략은 매우 강력한 기능을 제공하지만, 신중하게 사용해야 합니다. 병합 대상 브랜치의 변경 사항을 완전히 무시하기 때문에, 중요한 변경 사항이 손실될 수 있습니다. 따라서, ours 전략을 사용하기 전에, 변경 사항의 중요성을 충분히 검토해야 합니다.
4. Theirs Merge 전략
theirs merge 전략은 ours 전략과 정반대의 기능을 수행합니다. theirs 전략은 병합 대상 브랜치의 내용을 "항상" 우선시합니다. 즉, 현재 브랜치의 변경 사항은 모두 무시되고, 병합 대상 브랜치의 내용이 유지됩니다. 이 전략은 특정 브랜치의 변경 사항을 완전히 적용하고 싶을 때 유용합니다.
1) 사용 목적
theirs 전략은 다음과 같은 상황에서 유용하게 사용될 수 있습니다.
- 원격 브랜치 내용 동기화: 원격 브랜치의 내용을 로컬 브랜치에 완전히 적용하고 싶을 때.
- 특정 브랜치의 내용 덮어쓰기: 로컬 브랜치의 내용을 병합 대상 브랜치의 내용으로 덮어쓰고 싶을 때.
- 외부 라이브러리 업데이트: 외부 라이브러리의 최신 버전을 로컬 프로젝트에 적용할 때.
2) 사용법
theirs 전략을 사용하여 병합하려면, git merge 명령에 --strategy=theirs 옵션을 사용합니다.
git merge --strategy=theirs <병합 대상 브랜치>
예를 들어, origin/develop (원격 저장소의 develop 브랜치)의 내용을 로컬의 develop 브랜치에 적용하려면, 다음과 같이 명령을 실행합니다.
git checkout develop
git merge --strategy=theirs origin/develop
이 명령을 실행하면, 로컬 develop 브랜치의 모든 변경 사항이 무시되고, origin/develop 브랜치의 내용이 적용됩니다.
3) 주의사항
theirs 전략 역시 ours 전략과 마찬가지로 신중하게 사용해야 합니다. 현재 브랜치의 변경 사항을 모두 잃을 수 있기 때문에, 사용 전에 반드시 변경 사항의 중요성을 확인해야 합니다. 특히, 로컬에서 작업한 내용을 잃지 않도록 주의해야 합니다. theirs 전략을 사용하기 전에, 로컬 브랜치의 변경 사항을 백업하거나, 다른 브랜치에 임시로 저장하는 것이 좋습니다.
5. Subtree Merge 전략
subtree merge 전략은 Git을 사용하여 프로젝트의 하위 디렉토리를 다른 Git 저장소처럼 취급하는 고급 전략입니다. 이 전략은 특정 하위 디렉토리를 다른 브랜치나 저장소에서 가져와 병합하는 데 사용됩니다. 이를 통해 여러 프로젝트를 하나의 저장소에서 관리하거나, 외부 라이브러리를 프로젝트에 쉽게 통합할 수 있습니다.
1) Subtree의 개념
subtree는 전체 프로젝트를 복사하는 대신, 특정 하위 디렉토리만 병합하는 전략입니다. Subtree는 Git의 subtree 명령이나 merge --strategy=subtree 옵션을 사용하여 구현됩니다. Subtree 병합은 병합된 하위 디렉토리에 대한 "역사(history)"를 유지하므로, 해당 디렉토리의 변경 사항을 추적하고 관리할 수 있습니다. 즉, Subtree는 하위 디렉토리가 독립적인 Git 저장소인 것처럼 동작하면서, 전체 프로젝트의 히스토리에 통합됩니다.
2) 사용 목적
subtree merge 전략은 다음과 같은 상황에서 유용합니다.
- 외부 라이브러리 통합: 외부 라이브러리를 프로젝트의 특정 디렉토리에 통합하고, 라이브러리의 변경 사항을 쉽게 업데이트할 수 있습니다.
- 모노레포: 여러 프로젝트를 하나의 Git 저장소에서 관리하고, 각 프로젝트를 하위 디렉토리로 구성할 수 있습니다.
- 코드 재사용: 프로젝트 간에 코드를 재사용하고, 변경 사항을 쉽게 공유할 수 있습니다.
3) Subtree 병합 과정
subtree 병합은 다음과 같은 단계를 거칩니다.
- 병합 대상 지정: 병합하려는 하위 디렉토리와 병합 대상 브랜치를 지정합니다.
- 변경 사항 가져오기: 병합 대상 브랜치의 해당 디렉토리의 변경 사항을 가져옵니다.
- 병합: 가져온 변경 사항을 현재 브랜치의 해당 디렉토리에 병합합니다.
4) Subtree 병합 방법
Subtree 병합에는 주로 두 가지 방법이 있습니다.
git subtree merge명령 사용: 이 명령은 Subtree 병합을 위한 전용 명령입니다. 간편하게 Subtree 병합을 수행할 수 있습니다.git merge --strategy=subtree옵션 사용:git merge명령에--strategy=subtree옵션을 사용하여 Subtree 병합을 수행할 수 있습니다. 더욱 유연한 제어가 가능합니다.
5) 예시: 외부 라이브러리 통합
예를 들어, my-project라는 프로젝트에서 external-library라는 외부 라이브러리를 사용하고 싶다고 가정해 봅시다. external-library는 별도의 Git 저장소에서 관리되고 있습니다.
-
라이브러리 추가:
external-library를my-project의lib디렉토리에 추가합니다.bash git subtree add --prefix=lib/external-library <라이브러리_저장소_URL> <브랜치>예를 들어:
bash git subtree add --prefix=lib/external-library https://github.com/example/external-library.git main -
라이브러리 업데이트:
external-library의 최신 변경 사항을 가져오려면 다음과 같이 명령을 실행합니다.bash git subtree pull --prefix=lib/external-library <라이브러리_저장소_URL> <브랜치>예를 들어:
bash git subtree pull --prefix=lib/external-library https://github.com/example/external-library.git main이 명령은
external-library저장소에서 최신 변경 사항을 가져와lib/external-library디렉토리에 병합합니다.

6) 주의사항
- Subtree 히스토리: Subtree 병합은 하위 디렉토리의 히스토리를 유지하지만, 전체 프로젝트의 히스토리를 복잡하게 만들 수 있습니다. Subtree를 남용하면, 프로젝트의 유지 보수성이 저하될 수 있습니다.
- 병합 충돌: Subtree 병합 과정에서도 충돌이 발생할 수 있습니다. 충돌을 해결하기 위해서는, 하위 디렉토리의 변경 사항과 현재 프로젝트의 변경 사항을 신중하게 검토해야 합니다.
- Git 버전: Subtree 관련 명령은 Git 버전에 따라 다르게 동작할 수 있습니다. 사용하기 전에, Git 버전을 확인하고, 해당 버전에 맞는 문서를 참조하는 것이 좋습니다.
6. Merge 전략 선택과 활용
다양한 merge 전략을 이해했다면, 이제 상황에 맞는 전략을 선택하고 활용하는 방법을 알아야 합니다. 어떤 전략을 사용할지는 프로젝트의 특성, 팀의 협업 방식, 그리고 병합하려는 변경 사항의 성격에 따라 달라집니다.
1) 전략 선택 가이드
다음은 merge 전략을 선택하기 위한 몇 가지 가이드라인입니다.
- 일반적인 병합: 두 개의 브랜치를 병합하고, 충돌을 해결해야 하는 경우에는
recursive전략을 사용합니다. 대부분의 경우에 적합합니다. - 특정 변경 사항 무시: 특정 브랜치의 변경 사항을 무시하고 싶을 때는
ours전략을 사용합니다. 예를 들어, 특정 기능의 개발을 중단하고 해당 브랜치의 변경 사항을 제거하려는 경우에 유용합니다. - 변경 사항 덮어쓰기: 병합 대상 브랜치의 내용을 로컬 브랜치에 완전히 적용하고 싶을 때는
theirs전략을 사용합니다. 예를 들어, 원격 저장소의 최신 설정을 로컬에 적용하려는 경우에 유용합니다. - 외부 라이브러리 통합 또는 모노레포 구성: 외부 라이브러리를 프로젝트에 통합하거나, 여러 프로젝트를 하나의 저장소에서 관리하려는 경우에는
subtree전략을 사용합니다.
2) 실용적인 활용 팁
git mergetool사용: 충돌이 발생했을 때,git mergetool명령을 사용하여 시각적인 병합 도구를 사용할 수 있습니다. 이 도구를 사용하면, 충돌을 보다 쉽게 해결할 수 있습니다. (예:git mergetool -t meld)- 병합 전 검토: 병합을 수행하기 전에, 변경 사항을 충분히 검토해야 합니다.
git diff명령을 사용하여 변경 사항을 확인하고, 예상치 못한 변경 사항이 있는지 확인합니다. - 작은 단위로 병합: 가능하면, 작은 단위로 병합을 수행합니다. 이렇게 하면, 충돌을 해결하기가 더 쉬워지고, 병합 과정의 안정성을 높일 수 있습니다.
- 브랜치 전략: 프로젝트의 규모와 팀 규모에 맞는 브랜치 전략을 사용하는 것이 중요합니다. 예를 들어, Gitflow, GitHub Flow, Feature Branch Workflow 등 다양한 브랜치 전략을 고려할 수 있습니다.
- 히스토리 정리: 병합 후, 불필요한 커밋을 정리하여 프로젝트 히스토리를 깔끔하게 유지합니다.
git rebase명령을 사용하여 커밋을 정리할 수 있습니다.
3) 사례 연구
-
사례 1: 기능 개발 중단:
feature-a브랜치에서 개발 중인 기능의 개발을 중단하고, 해당 브랜치의 변경 사항을 모두 제거하려는 경우.bash git checkout main git merge --strategy=ours feature-afeature-a브랜치의 변경 사항은 모두 무시되고,main브랜치의 내용만 유지됩니다.
-
사례 2: 원격 설정 동기화: 원격 저장소의 설정을 로컬에 동기화하려는 경우.
bash git checkout main git merge --strategy=theirs origin/main원격
main브랜치의 설정이 로컬main브랜치에 적용됩니다.
-
사례 3: 외부 라이브러리 업데이트:
external-library의 최신 버전을 프로젝트에 적용하려는 경우.bash git subtree pull --prefix=lib/external-library https://github.com/example/external-library.git mainexternal-library의 최신 버전이lib/external-library디렉토리에 병합됩니다.
7. 결론
Git의 merge 전략은 효율적인 협업과 프로젝트 관리에 필수적인 기능입니다. recursive, ours, theirs, 그리고 subtree 전략을 이해하고, 상황에 맞게 활용함으로써, 개발 생산성을 향상시키고, 프로젝트의 품질을 높일 수 있습니다. Merge 전략은 Git 사용의 숙련도를 높이는 중요한 부분이며, 지속적인 학습과 실습을 통해 자신의 프로젝트에 최적화된 전략을 찾아가는 것이 중요합니다.
비슷한 글 추천
2-3. Git의 branch: 브랜치 생성 및 관리
브랜치의 개념과 브랜치를 생성, 전환, 병합하는 방법을 배우고, 브랜치 전략의 기본을 익힙니다.
2-4. Git의 merge: 브랜치 병합
브랜치를 병합하는 다양한 방법(`git merge`)을 살펴보고, 충돌(conflict) 해결 방법을 다룹니다.
3-1. Git의 stash: 변경 사항 임시 저장
stash 기능을 사용하여 변경 사항을 임시로 저장하고 다시 불러오는 방법을 익힙니다.
4-4. Git의 workflow: Feature Branch Workflow
Feature Branch Workflow를 이해하고, 실무에 적용하는 방법을 설명합니다.
Comments (0)
No comments yet. Be the first to comment!
Please to write a comment.