복잡한 병합에 어떻게 접근합니까


25

거래는 다음과 같습니다. 저는 새로운 회사에 합류했으며 거의 ​​1 년 동안 손대지 않은 지점에서 작업을 완료하라는 요청을 받았습니다. 한편, 마스터 지점은 꾸준한 속도로 성장하고 있습니다. 이상적으로 마스터 브랜치의 모든 변경 사항을 피처 브랜치로 병합하고 거기서부터 작업을 계속하고 싶지만 어떻게 접근 해야할지 모르겠습니다.

지점의 양쪽에서 중요한 변경 사항을 유지하면서이 병합을 안전하게 수행하려면 어떻게해야합니까?


멋진 의견을 보내 주셔서 감사합니다. 나는 git-imerge에 갈 것입니다.
Vlad Spreys

왜 우리가 git cherry-pick여기서 사용할 수 없는지 설명 할 수 있습니까 ?
Santosh Kumar

1.기도. 2. 리베이스. 3. 테스트. 4. 병합.
AK_

1
커밋으로 커밋 되므로이 상황에서 rebasing을 선호합니다. 또한 병합 된 코드를 사용 가능하게하기 전에 새 기능을 스쿼시 할 수 있습니다. YMMV.
Stephen

답변:


27

핵심으로, 두 가지 (호환되지 않는) 코드 조각을 결합하는 방법 은 버전 관리 문제 가 아니라 개발 문제입니다. Git merge 명령은이 과정에서 도움이 될 수 있지만 문제의 형태에 따라 다릅니다.

두 버전을 기본 버전과 먼저 비교하는 것이 가장 좋습니다. 이것은 당신에게 이것을 진전시키기위한 최고의 전략에 대한 아이디어를 줄 것입니다. 각 지점의 변경 사항의 특성과 겹침에 따라 접근 방식이 다를 수 있습니다.

이상적인 시나리오를 상상해보십시오. 메인 브랜치와 피처 브랜치는 각각 코드의 상호 배타적 인 부분 만 수정했기 때문에 모든 변경 사항을 커밋하고 잘 수행 할 수 있습니다.

물론, 그것은 사실이 아닐 것입니다. 그러나 문제는이 이상적인 시나리오에서 얼마나 멀리 떨어져 있을까요? 즉, 변경 사항이 어떻게 혼합되어 있습니까?

또한 이전 기능 지점은 얼마나 성숙 했습니까? 작동 상태가 양호 했습니까, 아니면 알려지지 않았습니까? 기능이 얼마나 완성 되었습니까?

작년에 주요 지점의 관련 코드가 많이 변경되었거나 기능이 매우 성숙한 상태가 아닌 경우 최신 포크를 새로 작성하고 이전 기능을 수동으로 다시 통합하는 것을 고려할 수 있습니다 . 이를 통해 작동하도록 점진적으로 접근 할 수 있습니다.

많은 코드를 혼란스럽게 병합해도 작동하지 않으면 디버깅하기가 매우 어렵습니다. 지난 한 해 동안 주요 지점이 많이 변경된 경우 기능을 작동 시키려면 주요 디자인 변경이 필요할 수 있습니다. "충돌 해결"을 통해 이러한 변경을 수행하는 것은 적절하지 않습니다. 모든 변경을 한 번에 수행하고 작동하기를 원하기 때문입니다. 이 문제는 부분적으로 완성 된 오래된 브랜치의 버그 가능성으로 인해 더욱 악화 될 수 있습니다.


+1 "최신의 새로운 포크를 만들고 이전 기능을 수동으로 다시 통합하는 것을 고려할 수 있습니다"
mika

1
첫 번째 주요 질문은 다음과 같습니다. 이전 기능 분기가 구축됩니까? 실행됩니까? 그렇지 않으면 병합을 테스트하기가 매우 어려울 것입니다.
Móż

22

제한된 git 경험에서 마스터가 분리 지점에서 너무 멀리 떨어진 경우 기능 분기를 다시 시작하는 것이 더 빠르다는 것을 말할 수 있습니다.

코드 뒤의 역사를 알지 못하고 두 프로젝트를 합병하는 것은 정말 어렵습니다. 프로젝트를 처음 시작한 개발자조차도 병합에 실수를 범할 가능성이 높습니다.

물론 기능 분기가 크지 않은 경우에는 의미가 있지만 이전 기능 분기를 열린 상태로 유지하고 마스터에서 다시 분기 한 다음 해당 기능을 구성하는 변경 사항수동으로 다시 소개 할 수 있습니다. 이것이 가장 수동적 인 접근 방법이라는 것을 알고 있지만 코드가 누락되거나 이동하는 경우 완전히 제어 할 수 있습니다.

이 경우 선임과 쌍으로 프로그래밍하는 것이 가장 좋은 시나리오이므로 코드를 더 잘 알 수 있습니다.
병합 충돌과 테스트 시간을 고려하면 더 빠를 수도 있습니다!

적어도 병합을 시도 하는 것이 최선의 방법이라고 생각합니다. 그것이 실패하거나 너무 어려운 것으로 판명되면 체리 따기를 시도하십시오. 잘못되면 수동으로 진행하십시오.


2
확실히 올바른 접근법은 아닙니다.
Andy

12
아니요, 이것은 올바른 접근법입니다. 고대 지점이 있고 코드를 모르는 경우 병합 시도가 성공하지 못하고 매우 위험합니다. 원래 변경 사항을 확인하고 새로운 코드와 관련이 있는지 여부를 조사한 다음 이해하기 쉽게 적용하는 방법입니다. 이것은 수동 접근 방식이지만 이러한 상황에서는 유일하게 안전한 방법입니다. 물론, 나는 여전히 어떤 일이 일어나는지보기 위해 먼저 병합을 시도하고, 지점에서 얼마나 많은 변화가 발생했는지 로그를 검사하여 사소한 것일 수 있습니다.
gbjbaanb

10
@DavidPacker : GavianoGrifoni가 모든 작업을 배 밖으로 던질 것을 제안하지는 않습니다. 그는 변경 사항을 단계별로 수동으로 기존 지점에서 현재 개발 라인으로 이전 할 것을 제안합니다. 그것은 더 이상 오래된 역사를 버릴 것입니다.
Doc Brown

3
@DavidPacker 1st : 지점은 1 년이 지났습니다. 두 번째 : 마무리 작업을 한 사람은 코드를 전혀 모릅니다. 이러한 두 가지 요소를 고려할 때 수동 재 적용이 작업에 접근하는 유일한 현실적인 방법입니다. 아무도 이전 브랜치 팁 개정의 간단한 복사 붙여 넣기를 제안하지 않습니다.
gbjbaanb

5
@DavidPacker : 병합 충돌은 악의가 될 수 있습니다. 프로그램을 다시 컴파일 가능하고 테스트 가능한 상태로 만들기 전에 500 개의 충돌을 한 번에 해결해야하는 경우. 이것이 OP가 기대하는 상황입니다. 이 "모두 또는 전혀없는"상황을 피하기 위해 효율적인 방법으로 git을 사용할 수 있다고 생각한다면, 답변을 편집하고 OP에게 이것이 어떻게 달성 될 수 있는지 알려주지 않겠습니까?
Doc Brown

16

git-imerge 는이 목적을 위해 정확하게 설계되었습니다. 증분 병합 방법을 제공하는 git 도구입니다 . 점진적으로 병합하면 두 버전 간의 충돌 만 처리하면됩니다. 또한 개별 변경 집합이 작을수록 훨씬 더 많은 수의 병합을 자동으로 수행 할 수 있습니다.


6

메인 라인 헤드를 1 년의 오래된 지점으로 병합하려고하면 좌절감을 느끼고 이마로 책상의 찌그러짐을 심화시킬 수 있습니다.

메인 라인은 수개월에 걸쳐 한 번에 어디로 가지 않았습니까? 그것도 개발과 출시가있었습니다. 하나의 모 놀리 식 병합으로 모든 것을 최신 상태로 유지하는 것은 압도적 일 수 있습니다.

대신 오래된 브랜치 분할 후 첫 번째 기능 병합에서 다시 메인 라인으로 병합하여 시작하십시오. 취득 병합 작업을. 그런 다음 다음 기능이 병합됩니다. 등등. 이러한 기능 병합 중 많은 부분이 충돌없이 병합됩니다. 부실 브랜치의 현재 기능이 메인 라인이 진행 한 방향과 호환되는지 확인하는 것이 여전히 중요합니다.

다른 변경에서 병합하는 역할을 위해 오래된 브랜치 헤드에서 브랜치 할 수 있습니다. 이것은 누군가가 그것을 되돌아 볼 때 커밋과 히스토리가 명확하고 각 브랜치의 역할과 정책이 무엇인지 알리는 것입니다. 오래된 지점은 기능 지점입니다. 당신이 일하고있는 것은 축적과 화해 지점입니다.

이전 기능 또는 릴리스 브랜치가 여전히 존재하고 쉽게 액세스 할 수있는 경우이 중 대부분이 더 쉬워집니다 (일부 장소는 특정 날짜보다 오래된 브랜치 이름을 정리하여 브랜치 목록이 압도적이지 않음) ).

이 모든 것에서 중요한 것은 메인 라인 히스토리의 각 부분을 성공적으로 병합 한 후 테스트하고 수정했는지 확인하는 것입니다. 충돌없이 무언가가 병합 될 수 있지만 이는 코드 가 충돌하지 않았 음을 의미합니다 . 오래된 기능에 액세스 한 방법이 더 이상 사용되지 않거나 제거 된 경우 성공적인 병합 후 수정이 필요할 수 있습니다.

옆으로, 이것은 다른 버전 제어 시스템에서도 작동합니다. 때로는 특정 svn 커밋 그룹을 하나의 기능에 대한 브랜치 (체리 피킹)로 병합하고 지점을 해당 기능으로 작동하도록 수정 한 다음 도매 svn을 수행하는 대신 다음 svn 커밋 그룹을 병합해야했습니다. 병합하십시오.

한 동안 자식 어떻게 여기에 체리 - 선택, 그것이 초래 할 수 않는 특정의 커밋이 과정을 복잡하게 수있는 몇 가지 단점이 있습니다. cherry pick에는 선택한 커밋에 대한 정보가 표시되지 않습니다 (커밋 메시지에 추가 할 수 있음). 이것은 실제로 기록의 커밋을 추적하는 것을 어렵게 만듭니다.

또한, 마스터가 오래된 브랜치로 효과적으로 재생하지 않고 불완전한 기능을 선택하게되며 해당 기능이 순서대로 재생되지 않을 수 있습니다.

히스토리 커밋에서 오래된 브랜치로 마스터하기 위해 병합 해야하는 주요 이유 는이를 유지할 수 있기 때문입니다. 히스토리에서 오래된 브랜치로의 병합과 기능을 다시 통합하기위한 수정 사항을 명확하게 볼 수 있습니다. 기능은 마스터와 동일한 순서로 추가됩니다. 그리고 완료되면 마지막으로 마스터 헤드에서 오래된 지점 으로 병합을 수행하면 모든 것이 병합되었으며 커밋이 누락되지 않은 것을 알 수 있습니다.


+1 이것은 병합을 사용하여 큰 변화를 통합하는 흥미로운 잠재적 대안 솔루션입니다. 그러나 단점은 다음과 같습니다. 주요 버전 ABCDE가 있고 기능 분기 A1을 E에 통합하려고한다고 가정합니다. 코드를 BC와 D에 병합하는 데 많은 노력이 낭비 될 수 있습니다. 예를 들어 D에서 E가 B, C 및 D의 증분 변경을 무의미하게 만든 큰 디자인 변경? 또한 기능이 처음에 얼마나 성숙했는지에 달려 있습니다. 유용한 잠재적 접근 방법이 있지만 시작하기 전에 그 적절성을 고려해야합니다.

1

1 단계. 코드에 대해 배우고, 아키텍처를 분석하고, 최신 공통 조상 이후 두 지점에서 이루어진 변경 사항을 확인하십시오.

2 단계. 기능이 광범위하게 독립적으로 나타나고 주로 코드의 서로 다른 영역에 닿으면 병합, 충돌 수정, 테스트, 수정 등이 행복한 경로입니다. 좋은 길입니다. 그렇지 않으면 3 단계로 이동하십시오.

3 단계. 갈등 영역을 분석하고 기능적 영향과 이유를 자세히 이해합니다. 여기에서 밝혀지는 비즈니스 요구 사항에 쉽게 충돌이있을 수 있습니다. BA, 다른 개발자들과 적절히 토론하십시오. 간섭 해결과 관련된 복잡성을 느끼십시오.

단계 4. 위의 내용에 비추어 충돌하지 않는 부분 만 병합 / 체리 픽 / 잘라 내기-붙여 넣기를 목표로할지 여부와 충돌하는 부분을 다시 쓰거나 전체 기능을 처음부터 다시 작성할지 여부를 결정하십시오. .


0

1. 주요 개발자 / 릴리스 지점으로 사용되는 지점으로 전환하십시오.

시스템에 대한 최신 변경 사항이 포함 된 지점입니다. 일 수있다 master, core, dev,는 회사에 따라 달라집니다. 귀하의 경우에는 아마도 master직접적 일 것입니다 .

git checkout master
git pull

주요 개발 지점의 최신 버전이 필요한지 확인하십시오.

2. 완료해야 할 작업이 포함 된 지점을 체크 아웃하고 당기십시오.

당신은 실제로 지점의 최신 내용을 가지고 있는지 확인하기 위해 당기십시오. 로컬에서 먼저 작성하지 않고 직접 체크 아웃하면 새 컨텐츠 master(또는 각각 기본 개발자 브랜치)가 새 컨텐츠를 가지지 않아야 합니다.

git checkout <name of the obsolete branch>
git pull origin <name of the obsolete branch>

3. 기본 개발 지점을 더 이상 사용하지 않는 지점으로 병합하십시오.

다음 명령을 실행하기 전에 입력 git branch하거나 git status사용하지 않는 분기에 있는지 확인하십시오 .

git merge master

git merge명령은이 경우, 지정된 지점에서 내용을 병합하려고합니다 master현재에있는 지점에.

에 중점을 하려고합니다 . 병합 충돌이있을 수 있으며이 문제는 귀하와 귀하 만 해결해야합니다.

4. 병합 충돌을 수정하고 충돌 수정을 커밋하고 푸시합니다.

병합 충돌이있는 모든 파일에서 병합 충돌을 수정 한 후에는 충돌 해결을 준비, 커밋 및 푸시하십시오 origin.

git add .
git commit -m "fixed the merge conflict from the past year to update the branch"
git push

일반적으로 git add .커밋을 위해 모든 파일을 준비하기 위해 호출 할 수 있습니다 . 병합 충돌을 처리 할 때 필요한 모든 파일을 업데이트하려고합니다.

추가 참고 사항

병합 충돌을 해결하는 것은 지루한 작업이 될 수 있습니다. 특히 당신이 회사에서 새로운 경우. 아직 모든 병합 충돌 만 해결하기위한 적절한 지식이 없을 수도 있습니다.

작업을 계속하기 전에 발생한 모든 충돌을주의 깊게 검사하고 적절하게 수정하십시오.


1 년 된 지점에서 작업을 시작하고 현재 개발 상태를 병합하여 병합 충돌이 발생하지 않을 수 있습니다.

이는 시스템이 1 년 동안 많이 바뀌 었더라도 1 년 전 지점에서 실제로 변경된 파일을 건드리지 않은 사람이 발생합니다.


6
# 4는 잠재적으로 문제입니다. 작년에 많은 변경이 있었으면 이전 기능에 대한 주요 변경이 필요할 수 있습니다. 병합으로이를 수행하려면 코드를 한 번에 크게 변경하고 작동하기를 바랍니다. 이는 좋은 개발 관행이 아닙니다. 그리고 완성되지 않은 기능의 상태를 누가 알겠습니까? 작동하지 않는 코드가 엉망이 될 수 있으며 원래 코드의 문제로 인한 것인지 또는 변경 한 것인지 누가 알 수 있습니까?

David는이 표준 접근 방식이 작동하는 한 문제가 없으며 OP가 먼저 시도해야합니다. 그러나 설명 된 상황에서이 "모두"방식으로 충돌을 처리하기에는 너무 많은 병합 충돌이 발생할 위험이 있습니다.
Doc Brown

@ dan1111 병합 충돌이 있다는 것은 완전히 괜찮습니다. 실제로 그것들을 통과하는 것이 좋습니다. 지점이 1 년 동안 손대지 않은 상태로 유지 되었기 때문에 그 지점이 그다지 중요하지 않으며 시스템의 많은 부분에 영향을 미치지 않을 것임을 확신 할 수 있습니다. 따라서 지점이 1 년 뒤이어도 병합 충돌이 2에서 1로 줄어 듭니다.
Andy

4
이 지점이 중요하지 않다는 가정은 보증되지 않습니다. 포기 된 기본 설계 변경 일 수 있으며 이제 다시 포착되고 있습니다. 무엇이든 될 수 있습니다. 당신은 그 권리입니다 수있는 간단한 문제를하고있을 당신의 대답은 올바른 것입니다 경우에 - 거의 또는 전혀 충돌합니다. 그러나 이것이 유일한 가능성은 아닙니다.

@ dan1111 누군가 1 년 동안 별도의 지점에있는 기능 장소를 건드리지 않은 경우 시스템 변경 사항에는 그다지 반영되지 않습니다. 이것은 쓸모없는 (6 개월 이상) 지점에 대한 내 자신의 경험에서 비롯됩니다.
Andy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.