git 또는 mercurial과 svn의 병합 사이에 차이가 있습니까? 어려움 ‘. 왜

내 이해에서 SVN은 ‘쉬운 지점입니다. 병합하기 어려움 ‘. 왜 그런 겁니까? 병합 방법에 차이가 있습니까?



답변

Mercurial (및 Git)이 문제없이 병합되고 Subversion이 가짜 충돌을 일으키는 매우 구체적인 상황에 대해서는 Stack Overflow 답변 을 참조하십시오 . 상황은 일부 파일의 이름을 바꾸는 지점에서 수행되는 간단한 리팩토링입니다.

tdammers 답변과 관련하여 여러 가지 오해가 있습니다.

  • Subversion, Mercurial 및 Git은 모두 프로젝트의 저장소 전체 스냅 샷을 추적합니다. 버전 , 개정판 또는 변경 세트를 호출해도 차이가 없습니다. 그것들은 모두 파일 세트의 논리적으로 스냅 샷입니다.

  • 커밋의 크기는 병합과 관련하여 아무런 차이가 없습니다 . 세 시스템 모두 표준 3 방향 병합 알고리즘과 병합되며 해당 알고리즘의 입력은

    • 가장 큰 공통 조상 버전
    • 한 지점의 버전
    • 다른 지점의 버전

    중요하지 않습니다 두 가지 버전이 만들어진 방법에 대해 설명합니다. 상위 버전 이후 1000 개의 작은 커밋을 사용했거나 1 개의 커밋을 사용할 수 있습니다. 중요한 것은 파일의 최종 버전입니다. (예, 이것은 놀라운 일입니다! 그렇습니다. 많은 DVCS 가이드가이 끔찍한 잘못을 저지 릅니다.)

또한 차이점에 대한 몇 가지 좋은 점을 제기합니다.

  • 서브 버전은 당신이에서 병합 할 수 있습니다 일부 “부두”이 /trunk말,로를, /branches/foo. Mercurial과 Git은이 모델을 사용하지 않습니다. 대신 분기는 히스토리에서 직접 모델링됩니다. 따라서 히스토리 는 선형이 아닌 방향성 비순환 그래프가 됩니다. 이것은 Subversion에서 사용하는 것보다 훨씬 간단한 모델이며 많은 코너 사례를 제거합니다.

  • 병합을 쉽게 지연 시키거나 다른 사람 이 병합 하도록 할 수도 있습니다. 당신 hg merge에게 많은 갈등을 준다면 동료에게 당신에게 요청할 수 hg pull있으며, 그는 똑같은 상태를 갖습니다. 그래서 그는 hg merge당신보다 갈등을 해결하는 데 더 잘할 수 있습니다.

    커밋 하기 전에 업데이트해야하는 Subversion에서는 매우 어렵습니다 . 서버의 변경 사항을 무시하고 익명 분기를 계속 커밋 할 수는 없습니다. 일반적으로 Subversion은 작업 할 때 더티 작업 복사본 을 가지고 놀도록 합니다 svn update. 변경 사항을 안전한 곳에 저장하지 않았기 때문에 위험합니다. Git and Mercurial을 사용하면 먼저 커밋 한 다음 필요에 따라 업데이트 및 병합 할 수 있습니다.

Git과 Mercurial이 Subversion보다 병합에 더 나은 실제 이유는 구현의 문제입니다. Subversion은 정답이 무엇인지 분명하다고 생각하더라도 단순히 처리 할 수없는 이름 바꾸기 충돌이 있습니다. Mercurial과 Git은 쉽게 처리합니다. 그러나 Subversion이 이러한 기능을 제대로 처리하지 못한 이유는 없습니다. 중앙 집중화가 반드시 그런 것은 아닙니다.


답변

핵심 문제는 이러한 시스템이 버전이 지정된 디렉토리 구조를 나타내는 방식에 있습니다.

전체 시스템이 돌아가는 Subversion의 기본 개념은 버전 (또는 svn lingo에서 “revision”)의 개념입니다. 특정 지점에서 파일의 스냅 샷입니다. 히스토리가 완벽하게 선형 인 한 모든 것이 정상이지만 두 개의 독립적 인 개발 라인의 변경 사항을 병합해야하는 경우 svn은 두 버전의 현재 버전을 비교 한 다음 마지막 공유 버전간에 3 방향 비교를 수행해야합니다. 그리고 두 헤드 버전. 헤드 중 하나에서 변경된 것처럼 보이지만 다른 라인은 쉽게 해결할 수 없습니다. 두 헤드에서 정확히 같은 방식으로 벗어나는 선은 더 어렵지만 일반적으로 가능합니다. svn은 “다른 방법으로 이탈 한 줄은 이것을 이해할 수 없습니다. 인간은 이것을 해결해주세요.”라고 말합니다.

반대로 git 및 mercurial 은 버전이 아닌 변경 세트를 추적 합니다. 전체 리포지토리는 변경 집합 트리로, 각각 부모에 따라 달라지며 부모 변경 집합은 여러 자식을 가질 수 있으며 트리 루트는 빈 디렉터리를 나타냅니다. 다시 말해, git / hg는 “먼저 아무 것도 갖고 있지 않다가이 패치를 적용한 다음 패치를 적용했습니다”라고 말합니다. 두 줄의 개발을 병합해야 할 때, git / hg는 각 헤드가 현재 어떻게 보이는지, 그리고 마지막 공통 버전이 무엇인지 알뿐만 아니라 전환이 어떻게 발생했는지를 알고 훨씬 더 스마트하게 병합 할 수 있습니다.

DVCS에서 쉽게 병합 할 수있는 또 다른 사항은 커밋푸시 의 개념을 분리함으로써 발생하는 간접적 인 결과입니다.동일한 저장소의 두 복제본간에 언제든지 모든 종류의 교차 병합을 허용합니다. svn을 사용하면 커밋은 다른 모든 팀 구성원에게 영향을 미치는 중앙 저장소의 업데이트이기 때문에 사람들은 종종 관련이없는 변경으로 큰 변경 세트를 커밋하는 경향이 있습니다. 깨진 버전을 커밋하면 모두가 화를 낼 것입니다. 대부분의 설정에는 네트워크로 연결된 svn 서버가 포함되므로 커밋에는 네트워크를 통한 데이터 펌핑도 포함됩니다. 즉 커밋하면 워크 플로에 상당한 지연이 발생합니다 (특히 작업 사본이 오래되어 먼저 가져와야하는 경우). git과 mercurial을 사용하면 커밋이 로컬에서 발생하며 로컬 파일 시스템을 처리하는 데 매우 효율적이기 때문에 일반적으로 즉시 완료됩니다. 결과적으로 사람들은 일단 익숙해지면 조금씩 조금씩 변화를 일으킨다. 한 번에 수십 가지 정도의 커밋을 푸시하십시오. 그런 다음 병합 시간이 다가 오면 SCM은 훨씬 더 자세한 정보를 얻을 수 있으며 충돌을 안전하고 자동으로 해결하는 더 나은 작업을 수행 할 수 있습니다.

그리고 일을 더 쉽게 만드는 멋진 세부 사항이 있습니다.

  • 헤드를 여러 개 가질 수 있으며 여전히 어느 쪽이든 커밋 할 수 있습니다. Subversion과 달리 다시 커밋하기 전에 끌어 오기, 업데이트 및 병합을 결합 할 필요가 없습니다. 병합을 선택할 때까지 여러 헤드가 그대로 유지됩니다.
  • 디렉토리는 특별하게 취급되지 않습니다. 대신, 경로는 하나의 큰 파일 이름으로 간주되며 모든 디렉토리는 항상 동일한 버전이어야합니다. 즉, 프로젝트의 하위 폴더가 다른 버전으로 바뀌는 Subversion 부두를 수행 할 수는 없지만 작업 복사본이 관리하기 어려운 큰 혼란이 될 가능성이 적고 더 흥미롭게도 이동은 삭제로 표시되지 않습니다 그리고 add (추가 개조 메타 데이터가 아닌 경우 svn에서 완전히 중단됨), 단순히 이름 바꾸기로; 파일을 이동하면 전체 기록이 유지됩니다. 병합하면 다른 분기에서 이동 동일한 파일의 이동하지 않은 버전으로 작성된 이동 된 파일에 변경 사항을 적용 할 수도 있습니다.
  • 대부분의 경우 실제로 분기 할 필요 조차 없습니다 . 대신 전체 저장소를 복제하면됩니다. 복제는 저렴합니다. 특히 동일한 파일 시스템에서 수행 한 경우 복제를 제거하기로 결정한 경우에는 그 디렉토리에있는 디렉토리 만 삭제하면됩니다. 이를 위해 hg 또는 git을 사용할 필요조차 없습니다.
  • 병합 할 수있는 항목에는 제한이 거의 없습니다. 동일한 저장소에 대해 6 개의 복제본을 가질 수 있으며 A에서 B로, C에서 B로, B에서 D로, C에서 D로, B로 다시 병합 (또는 밀거나 당기기; 명시 적 병합은 종종 필요하지 않음) 언제든지 A, D, E로
  • 병합하려는 리포지토리 중 하나를 복제 한 다음 다른 리포지토리에서 가져 와서 병합을 테스트 할 수 있습니다. 원하는 것을 수행하면 실제 대상으로 되돌릴 수 있습니다. 그렇지 않은 경우 복제본을 버리고 새로 시작할 수 있습니다.