내 이해에서 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이 이러한 기능을 제대로 처리하지 못한 이유는 없습니다. 중앙 집중화가 반드시 그런 것은 아닙니다.
trunk
SVN에서 작업 할 때 작업을 시작하지 않은 상황에 대해 이야기하고 있습니다 . DVCS를 사용하면 공유하지 않고 커밋 할 수 있지만 SVN svn commit
에서는 같은 지점에서 일하는 다른 사람들에게 직접 영향을 미칩니다. 우리 두 사람이 SVN의 지점에서 일하더라도 즉시 작업과 병합하지 않고는 내 일을 할 수 없습니다. 이것은 커밋을 다소 무섭게 만듭니다. 이것은 버전 제어 시스템의 무서운 속성입니다! :-)
핵심 문제는 이러한 시스템이 버전이 지정된 디렉토리 구조를 나타내는 방식에 있습니다.
전체 시스템이 돌아가는 Subversion의 기본 개념은 버전 (또는 svn lingo에서 "revision")의 개념입니다. 특정 지점에서 파일의 스냅 샷입니다. 히스토리가 완벽하게 선형 인 한 모든 것이 정상이지만 두 개의 독립적 인 개발 라인의 변경 사항을 병합해야하는 경우 svn은 두 버전의 현재 버전을 비교 한 다음 마지막 공유 버전간에 3 방향 비교를 수행해야합니다. 그리고 두 헤드 버전. 헤드 중 하나에서 변경된 것처럼 보이지만 다른 라인은 쉽게 해결할 수 없습니다. 두 헤드에서 정확히 같은 방식으로 벗어나는 선은 더 어렵지만 일반적으로 가능합니다. svn은 "다른 방법으로 이탈 한 줄은 이것을 이해할 수 없습니다. 인간은 이것을 해결해주세요."라고 말합니다.
반대로 git 및 mercurial 은 버전이 아닌 변경 세트를 추적 합니다. 전체 리포지토리는 변경 집합 트리로, 각각 부모에 따라 달라지며 부모 변경 집합은 여러 자식을 가질 수 있으며 트리 루트는 빈 디렉터리를 나타냅니다. 다시 말해, git / hg는 "먼저 아무 것도 갖고 있지 않다가이 패치를 적용한 다음 패치를 적용했습니다"라고 말합니다. 두 줄의 개발을 병합해야 할 때, git / hg는 각 헤드가 현재 어떻게 보이는지, 그리고 마지막 공통 버전이 무엇인지 알뿐만 아니라 전환이 어떻게 발생했는지를 알고 훨씬 더 스마트하게 병합 할 수 있습니다.
DVCS에서 쉽게 병합 할 수있는 또 다른 사항은 커밋 과 푸시 의 개념을 분리함으로써 발생하는 간접적 인 결과입니다.동일한 저장소의 두 복제본간에 언제든지 모든 종류의 교차 병합을 허용합니다. svn을 사용하면 커밋은 다른 모든 팀 구성원에게 영향을 미치는 중앙 저장소의 업데이트이기 때문에 사람들은 종종 관련이없는 변경으로 큰 변경 세트를 커밋하는 경향이 있습니다. 깨진 버전을 커밋하면 모두가 화를 낼 것입니다. 대부분의 설정에는 네트워크로 연결된 svn 서버가 포함되므로 커밋에는 네트워크를 통한 데이터 펌핑도 포함됩니다. 즉 커밋하면 워크 플로에 상당한 지연이 발생합니다 (특히 작업 사본이 오래되어 먼저 가져와야하는 경우). git과 mercurial을 사용하면 커밋이 로컬에서 발생하며 로컬 파일 시스템을 처리하는 데 매우 효율적이기 때문에 일반적으로 즉시 완료됩니다. 결과적으로 사람들은 일단 익숙해지면 조금씩 조금씩 변화를 일으킨다. 한 번에 수십 가지 정도의 커밋을 푸시하십시오. 그런 다음 병합 시간이 다가 오면 SCM은 훨씬 더 자세한 정보를 얻을 수 있으며 충돌을 안전하고 자동으로 해결하는 더 나은 작업을 수행 할 수 있습니다.
그리고 일을 더 쉽게 만드는 멋진 세부 사항이 있습니다.
hg mv
또는 hg addremove --similarity...
) 이름이 바뀌지 만 Git은 휴리스틱을 사용하지만 둘 다 이름 바꾸기를 처리 합니다. 병합 된 파일에서 1 문자열 차이 로 도 트리 충돌이 발생할 수 있습니다! 서브 버전 측면을 다시 배워야합니다. 죄송합니다.
rename a b
으로 copy a b; remove a
둘 다 원자 커밋 하나에 그것을 할. 병합 동작의 차이는 코너 케이스의 다른 처리와 Subversion의 영향으로 인해 Mercurial 및 Git보다 더 많은 병합을 허용합니다. 마지막으로 Git 은 병합 및 로그 타임에 이름 변경을 감지 합니다. Mercurial에서도이 이름을 추가 할 생각입니다.