git 또는 mercurial과 svn의 병합 사이에 차이가 있습니까?


12

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

git  svn  mercurial  dvcs 

답변:


21

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이 이러한 기능을 제대로 처리하지 못한 이유는 없습니다. 중앙 집중화가 반드시 그런 것은 아닙니다.


4
좋은 답변입니다! 내가 할 수 있다면 나는 두 번 공표했다. SO에 대답에 :) 나는 또한 SVN 책은 당신이 참조하는 것이 추가 할 것 분명하게 인정 하는 "Subversion의 병합 추적 기능은 매우 복잡한 내부 구현을 가지고 ..." 혼자이 기능은 신뢰할 수있는 꽤 좋은 표시입니다 -
모기

2
... 매우 복잡한 구현이라도 단순한 경우를 제외하고는 공통 조상을 정확하게 파악할 수 없습니다.
Jan Hudec

병합 지연에 대해-이해하지 마십시오-SVN을 사용하면 동료가 트렁크로 업데이트 / 체크 아웃 한 다음 지점에서 병합 할 수 있습니다.
길 베이츠

@GillBates : trunkSVN에서 작업 할 때 작업을 시작하지 않은 상황에 대해 이야기하고 있습니다 . DVCS를 사용하면 공유하지 않고 커밋 할 수 있지만 SVN svn commit에서는 같은 지점에서 일하는 다른 사람들에게 직접 영향을 미칩니다. 우리 두 사람이 SVN의 지점에서 일하더라도 즉시 작업과 병합하지 않고는 내 일을 할 수 없습니다. 이것은 커밋을 다소 무섭게 만듭니다. 이것은 버전 제어 시스템의 무서운 속성입니다! :-)
Martin Geisler 2013 년

6

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

전체 시스템이 돌아가는 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로
  • 병합하려는 리포지토리 중 하나를 복제 한 다음 다른 리포지토리에서 가져 와서 병합을 테스트 할 수 있습니다. 원하는 것을 수행하면 실제 대상으로 되돌릴 수 있습니다. 그렇지 않은 경우 복제본을 버리고 새로 시작할 수 있습니다.

2
1. 몇 가지 수정 사항을 언급하고 답변에 추가해야합니다. 1. SVN 개정판은 저장소마다 전역 적 이며 개정판은 즉시 repo의 모든 파일을 나타냅니다. 2. 병합 기술은 기본적으로 SVN 및 DVCS에서 일반적입니다 . 같은 방식 으로 병합하면 SVN 및 DVCS에 대해 동일한 양의 충돌이 발생합니다. 모든 SCM은 여전히 ​​논리 블록이 아닌 문자열 수준에서 작동합니다. SVN의 큰 커밋은 아키텍처 약점의 결과는 아니지만 사용자가 종종 게으른 바보이기 때문에 -기본 패턴을 무시합니다. 지점 | SVN에서 병합 작품의 경우는 / dev / 뇌와는 / dev / 손 작업
게으른 오소리

2
제 2 부 : DVCS 스마트 병합은 대부분 파괴는 달리, 그들은 추적하고, 때문에 발생하는 핸들을 이동 | 파일과 SVN 따라서, 전혀 그렇게하지 않습니다의 이름 변경 - 프로세스 파일에 한쪽에 변경 한 이름이 모든 작업을, 둘째, 실패합니다. 가지와 복제가있는 가지는 같은 권리를 가진 가지의 다른 전략 일 뿐이며, "...에 따라 다릅니다 ..."
Lazy Badger

@LazyBadger : Au contraire. Subversion 이동 / 이름 변경을 추적합니다. 병합에서 이름 바꾸기를 처리하는 것은 단순히 버그가 있고 부분적으로 올바르게 처리하기 어렵거나 불가능한 코너 사례가 있기 때문에 스퓨리어스 충돌을 일으 킵니다. 나중에 디자인에 의해 git (및 수은이 복사 한)이 이름 바꾸기를 추적 하지 않고 병합 할 때 이름을 추측하는 이유 입니다. 내용이 여전히 병합 될만큼 유사하고 (필요할 때) 어리석은 일을하지 않으면 제대로 작동합니다.
Jan Hudec

@JanHudec-죄송합니다. SVN은 원자 하나의 동작 (DVCS 방식- "이름 바꾸기")으로 이름을 바꾸지 않고 "삭제 + ..."로 DVCS에서 발생하지 않는 트리 충돌을 일으 킵니다 (진명 이름 바꾸기) ). Mercital 트랙은 명시 적으로 ( hg mv또는 hg addremove --similarity...) 이름이 바뀌지 만 Git은 휴리스틱을 사용하지만 둘 다 이름 바꾸기를 처리 합니다. 병합 된 파일에서 1 문자열 차이 로 도 트리 충돌이 발생할 수 있습니다! 서브 버전 측면을 다시 배워야합니다. 죄송합니다.
게으른 오소리

5
이제 우리는 매우 기술적 있어요 :-) 서브 버전과 의욕 트랙 모두 복사 , 이름을 변경하지. 두 시스템 모두 추적 rename a b으로 copy a b; remove a둘 다 원자 커밋 하나에 그것을 할. 병합 동작의 차이는 코너 케이스의 다른 처리와 Subversion의 영향으로 인해 Mercurial 및 Git보다 더 많은 병합을 허용합니다. 마지막으로 Git 병합 및 로그 타임에 이름 변경을 감지 합니다. Mercurial에서도이 이름을 추가 할 생각입니다.
Martin Geisler
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.