힘내와 머큐리얼-비교 및 대조


520

한동안 저는 개인 프로젝트에 서브 버전을 사용하고 있습니다.

점점 더 Git과 Mercurial, 그리고 DVCS에 대한 좋은 소식을 계속 듣고 있습니다.

DVCS 전체에 소용돌이를 드리고 싶지만 어느 옵션에도 익숙하지 않습니다.

Mercurial과 Git의 차이점은 무엇입니까?

참고 : 나는 어느 것이 "최고"인지 또는 어느 것을 시작해야하는지 찾으려고 하지 않습니다 . 나는 주로 구현과 철학 측면에서 어떻게 다른지 알고 싶어하기 때문에 비슷한 부분과 다른 부분을 주로 찾고 있습니다.



답변:


451

면책 조항 : 나는 Git을 사용하고 git 메일 링리스트에서 Git 개발을 따르고 심지어 Git (주로 gitweb)에 약간 기여합니다. 나는 설명서와 FreeNode의 #revctrl IRC 채널에 대한 토론에서 Mercurial을 알고 있습니다.

이 글에 Mercurial에 대한 도움을 주신 #mercurial IRC 채널의 모든 분들께 감사드립니다



요약

여기에 MarkMark의 PHPMarkdown / MultiMarkdown / Maruku 확장과 같은 테이블에 대한 구문이 있으면 좋을 것입니다.

  • 리포지토리 구조 : Mercurial에서는 문어 병합 (부모가 둘 이상) 또는 커밋되지 않은 객체에 태그를 지정할 수 없습니다.
  • 태그 : Mercurial은 .hgtags리포지토리 당 태그에 대한 특수 규칙이있는 버전이 지정된 파일을 사용 하며 로컬 태그도 지원합니다 .hg/localtags. Git에서 태그는 refs/tags/네임 스페이스에 상주하며 기본적으로 페치시 자동 추적되며 명시적인 푸시가 필요합니다.
  • 지점 : Mercurial의 기본 워크 플로우는 익명 헤드를 기반 으로합니다 . Git은 가벼운 이름의 브랜치를 사용하며, 원격 저장소의 브랜치를 따르는 특별한 종류의 브랜치 ( 원격 추적 브랜치 )를 가지고 있습니다.
  • 수정 명명 및 범위 : 의욕 제공 버전 번호 , 로컬 저장소, 염기 상대적인 변경 (팁으로부터 계산, 즉 현재 브랜치) 및 이에 대한 수정 범위 지역 번호를; Git은 브랜치 팁을 기준으로 개정을 참조하는 방법을 제공하며 개정 범위는 토폴로지입니다 (개정 그래프 기준).
  • Mercurial은 이름 변경 추적을 사용 하고 Git은 이름 변경 감지 를 사용 하여 파일 이름 변경을 처리합니다.
  • 네트워크 : Mercurial은 SSH 및 HTTP "스마트"프로토콜 및 정적 HTTP 프로토콜을 지원합니다. 최신 Git은 SSH, HTTP 및 GIT "스마트"프로토콜 및 HTTP (S) "덤"프로토콜을 지원합니다. 둘 다 오프라인 전송을위한 번들 파일을 지원합니다.
  • Mercurial은 확장 (플러그인) 및 설정된 API를 사용합니다. Git은 스크립팅 기능 과 확립 된 형식을 가지고 있습니다.

Git과 Mercurial과 다른 점이 몇 가지 있지만 비슷한 점이 있습니다. 두 프로젝트 모두 서로 아이디어를 빌립니다. 예를 들어 hg bisectMercurial의 명령 (이전의 이등분 확장 )은 git bisectGit의 명령에서 영감을 얻은 반면 아이디어는 git bundle에서 영감을 얻었습니다 hg bundle.

리포지토리 구조, 수정본 저장

Git에는 파일의 내용을 포함하는 blob 객체 , 파일 이름 및 파일 권한의 관련 부분 (파일에 대한 실행 권한, 심볼릭 링크)을 포함하여 디렉토리 구조를 저장하는 계층 적 트리 객체의 4 가지 유형의 객체가 객체 데이터베이스에 있습니다. , 소유권 정보를 포함하는 커밋 객체, 커밋 (프로젝트의 최상위 디렉토리의 트리 객체를 통해)으로 표시되는 개정시 저장소 상태의 스냅 샷에 대한 포인터 및 0 개 이상의 상위 커밋에 대한 참조 및 다른 객체를 참조하고 할 수있는 태그 객체 PGP / GPG를 사용하여 서명하십시오.

: 자식 객체를 저장하는 두 가지 방법이 사용 느슨한 각 객체 (그 파일이 추기 및 변성되지 않습니다)는 별도의 파일에 저장되는 형식과 압축 많은 개체 델타 압축 된 하나의 파일에 저장되는 형식. 작업의 원자 성은 객체를 작성한 후 새 객체에 대한 참조가 (원자 적으로 create + rename trick을 사용하여) 작성된다는 사실에 의해 제공됩니다.

Git 리포지토리에는 git gc(디스크 공간을 줄이고 성능을 향상시키기 위해) 정기적 인 유지 관리가 필요 하지만 요즘에는 Git이 자동으로 수행합니다. (이 방법은 리포지토리를 더 잘 압축합니다.)

Mercurial (내가 이해하는 한)은 파일의 기록을 파일 로그에 저장합니다 (이름 변경 추적과 같은 추가 메타 데이터 및 일부 도우미 정보와 함께). 디렉토리 구조를 저장하기 위해 manifest 라는 플랫 구조를 사용 하고 커밋 메시지 및 0, 1, 2 개의 부모를 포함하여 변경 세트 (개정)에 대한 정보를 저장하는 changelog 구조 를 사용합니다.

Mercurial은 트랜잭션 저널 을 사용하여 작업의 원 자성을 제공하며, 실패하거나 중단 된 작업 후 파일을 정리하여 파일을 잘라 냅니다. Revlog는 추가 전용입니다.

Git과 Mercurial의 저장소 구조를 살펴보면 Git이 객체 데이터베이스 (또는 컨텐츠 주소가 지정된 파일 시스템)와 비슷하고 Mercurial이 기존 고정 필드 관계형 데이터베이스와 더 유사하다는 것을 알 수 있습니다.

차이점 :
Git에서 트리 객체는 계층 구조를 형성합니다 . Mercurial 매니페스트 파일은 평평한 구조입니다. Git Blob 객체 에는 파일 내용의 한 버전 이 저장 됩니다. Mercurial 파일 로그 에는 단일 파일의 전체 히스토리가 저장 됩니다 (이름 변경과 관련된 합병증을 고려하지 않은 경우). 즉, Git이 Mercurial보다 빠른 운영 영역, 병합 또는 프로젝트 기록 표시와 같이 동등한 것으로 간주되는 다른 모든 영역 및 패치 적용 또는 표시와 같은 Mercurial이 Git보다 빠른 영역이 있음을 의미합니다. 단일 파일의 기록).이 문제는 최종 사용자에게는 중요하지 않을 수 있습니다.

Mercurial 변경 기록 구조의 고정 레코드 구조로 인해 Mercurial의 커밋은 최대 두 명의 부모 만 가질 수 있습니다 . Git의 커밋은 둘 이상의 부모 ( "문어 병합"이라고 함)를 가질 수 있습니다. (이론적으로) 문어 병합을 일련의 두 부모 병합으로 대체 할 수 있지만, 이는 Mercurial과 Git 리포지토리 간 변환시 합병증을 유발할 수 있습니다.

내가 아는 한 Mercurial에는 Git 의 주석달린 태그 (태그 객체) 가 없습니다 . 주석이 달린 태그의 특별한 경우는 서명 된 태그 (PGP / GPG 서명 포함)입니다. Mercurial과 동등한 것은 GpgExtension을 사용하여 수행 할 수 있으며 확장은 Mercurial과 함께 배포됩니다. Git에서와 같이 Mercurial에서 커밋 되지 않은 객체태그를 지정할 수는 없지만 그렇게 중요하지는 않습니다 (일부 git 리포지토리는 태그가있는 blob을 사용하여 서명 된 태그를 확인하는 데 공개 PGP 키를 배포합니다).

참조 : 브랜치 및 태그

Git 참조 (분기, 원격 추적 분기 및 태그)는 커밋의 DAG 외부에 있습니다 (필요한 경우). refs/heads/네임 스페이스 ( 로컬 브랜치 )의 참조는 커밋을 가리키며 일반적으로 "git commit"에 의해 업데이트됩니다. 그들은 가지의 끝 (머리)을 가리 키므로 그러한 이름입니다. refs/remotes/<remotename>/네임 스페이스 ( 원격 추적 분기 )의 참조는 커밋을 가리키고 원격 저장소의 분기를 따르며 <remotename>"git fetch"또는 이와 동등한 것으로 업데이트됩니다. refs/tags/네임 스페이스 ( tags )의 참조는 일반적으로 커밋 (경량 태그) 또는 태그 객체 (주석 및 서명 된 태그 )를 가리키며 변경하려는 것은 아닙니다.

태그

Mercurial에서는 tag를 사용하여 수정 이름을 영구적으로 지정할 수 있습니다 . 태그는 무시 패턴과 유사하게 저장됩니다. 전역 적으로 볼 수있는 태그는 .hgtags리포지토리의 개정 제어 파일에 저장됩니다. 그 결과 두 가지 결과가 발생합니다. 첫째, Mercurial은이 파일에 대한 모든 규칙을 사용하여 모든 태그의 현재 목록을 가져 와서 해당 파일을 업데이트해야합니다 (예 : 현재 체크 아웃 된 버전이 아니라 가장 최근에 커밋 된 파일 개정판을 읽습니다). 둘째, 다른 사용자 / 다른 저장소에 새 태그를 표시하려면이 파일에 변경 사항을 커밋해야합니다 (내가 이해하는 한).

Mercurial은 에 저장된 로컬 태그를 지원하며 다른 태그hg/localtags 는 볼 수 없으며 물론 양도 할 수 없습니다.

Git에서 태그는 refs/tags/네임 스페이스에 저장된 다른 객체 (보통 커밋을 가리키는 태그 객체)에 대한 고정 된 (일정한) 명명 된 참조 입니다. 기본적으로 리비전 세트를 가져 오거나 푸시 할 때 git은 페치 또는 푸시 된 리비전을 가리키는 태그를 자동으로 가져 오거나 푸시합니다. 그럼에도 불구하고 어떤 태그를 가져 오거나 푸시 할지 어느 정도 제어 할 수 있습니다 .

Git은 경량 태그 (커밋을 직접 가리킴)와 주석이 달린 태그 (PGP 서명을 선택적으로 포함하는 태그 메시지를 포함하는 태그 메시지를 포함하는 태그 객체를 가리킴)를 약간 다르게 처리합니다. 예를 들어 기본적으로 설명 할 때 주석이 달린 태그 만 고려합니다 "git describe"를 사용하여 커밋합니다.

Git은 Mercurial에 엄격한 로컬 태그가 없습니다. 그럼에도 불구하고 자식 모범 사례는 준비된 변경 사항을 푸시하고 다른 변경 사항을 복제하고 가져 오는 별도의 공개 베어 저장소를 설정하는 것이 좋습니다. 이것은 사용자가 푸시하지 않은 태그 (및 브랜치)가 리포지토리에 대해 비공개임을 의미합니다. 반면에 당신은 또한 이상의 네임 스페이스를 사용할 수 있습니다 heads, remotes또는 tags예를 들어, local-tags지역 태그.

개인적 견해 : 내 의견으로는 태그는 외부에있는 수정 그래프 외부에 있어야합니다 (수정 그래프에 대한 포인터 임). 태그는 버전이 아닌, 양도 할 수 있어야합니다. Mercurial은 파일을 무시할 때와 유사한 메커니즘을 사용하기로 선택했습니다. 즉, .hgtags트리에서 특수하게 처리하거나 (파일 내에서 파일을 전송할 수 있지만 보통 버전 화됨) 로컬에만있는 태그 ( .hg/localtags버전이 지정되지 않은, 그러나 양도 할 수 없음).

지점

Git 로컬 브랜치 (브랜치 팁 또는 브랜치 헤드)는 커밋에 대한 명명 된 참조로, 새로운 커밋을 증가시킬 수 있습니다. 지점은 또한 활발한 개발 라인, 즉 지점 끝에서 도달 할 수있는 모든 커밋을 의미 할 수 있습니다. 로컬 브랜치는 refs/heads/네임 스페이스에 상주 하므로 예를 들어 '마스터'브랜치의 정규화 된 이름은 'refs / heads / master'입니다.

Git의 현재 분기 (체크 아웃 된 분기 및 새로운 커밋이 진행되는 분기를 의미)는 HEAD ref가 참조하는 분기입니다. HEAD가 기호 참조가 아닌 커밋을 직접 가리 키도록 할 수 있습니다. 익명의 이름없는 브랜치에있는 이러한 상황을 분리 된 HEAD 라고합니다 ( "git branch"는 사용자가 '(브랜치 없음)'에 있음을 나타냅니다).

Mercurial에는 익명 브랜치 (브랜치 헤드)가 있으며 책갈피 확장을 통해 책갈피를 사용할 수 있습니다 . 이러한 책갈피 분기 는 순전히 로컬이며 해당 이름은 Mercurial을 사용하여 이전 할 수 없었습니다 (버전 1.6까지). rsync 또는 scp를 사용하여 .hg/bookmarks파일을 원격 저장소 에 복사 할 수 있습니다 . hg id -r <bookmark> <url>책갈피의 현재 팁의 개정 ID를 얻는 데 사용할 수도 있습니다 .

1.6 북마크 이후로 밀거나 끌 수 있습니다. BookmarksExtension의 페이지에 섹션이 원격 저장소 작업을 . Mercurial 북마크 이름이 전역 이라는 점에서 차이가 있지만 Git에서 '원격'의 정의는 원격 저장소의 이름에서 로컬 원격 추적 분기의 이름 으로 분기 이름의 맵핑 도 설명 합니다. 예를 들어 refs/heads/*:refs/remotes/origin/*매핑은 'origin / master'원격 추적 분기 ( 'refs / remotes / origin / master')의 원격 저장소에서 'master'분기 ( 'refs / heads / master')의 상태를 찾을 수 있음을 의미합니다.

의욕은 또한 소위있다 라는 이름의 지점 지점 이름이되고, 내장 A는 (변경 집합에) 커밋합니다. 이러한 이름은 전역입니다 (페치시 전송 됨). 이러한 분기 이름은 changeset \ u2019s 메타 데이터의 일부로 영구적으로 기록됩니다. 최신 Mercurial을 사용하면 "명명 된 지점"을 닫고 지점 이름 기록을 중지 할 수 있습니다. 이 메커니즘에서 분기의 팁은 즉시 계산됩니다.

머큐리얼의 "명명 된 브랜치"는 제 생각에 커밋 레이블 이라고 합니다. "명명 된 브랜치"에 여러 가지 팁 (여러 개의 자식이없는 커밋)이있을 수 있으며 여러 개의 불완전한 수정 그래프 부분으로 구성 될 수도 있습니다.

Git에는 Mercurial "임베디드 브랜치"에 해당하는 것이 없습니다. 게다가 Git의 철학은 브랜치에 커밋이 포함되어 있다고 말할 수 있지만 커밋이 일부 브랜치에 속한다는 것을 의미하지는 않습니다.

Mercurial 문서에서는 여전히 복제에 의해 분기되는 장기 브랜치 (저장소 당 단일 브랜치 워크 플로우)에 대해 별도의 클론 (별도의 리포지토리)을 사용하도록 제안합니다 .

추진 지점

Mercurial은 기본적으로 모든 헤드를 푸시 합니다 . 단일 분기 ( 단일 헤드 )를 푸시하려면 푸시하려는 분기의 팁 개정을 지정해야합니다. 개정판 번호 (로컬에서 저장소로), 개정 식별자, 책갈피 이름 (로컬에서 저장소로, 전송되지 않음) 또는 임베드 된 분기 이름 (지점으로)으로 분기 팁을 지정할 수 있습니다.

내가 이해하는 한, Mercurial 용어로 "명명 된 지점"에있는 것으로 표시된 커밋이 포함 된 범위의 개정판을 푸시하면,이 "명명 된 지점"은 푸시 한 저장소에 있습니다. 이것은 그러한 내장 된 브랜치 ( "이름이있는 브랜치")의 이름이 전역 적이라는 것을 의미합니다 (주어진 리포지토리 / 프로젝트의 클론과 관련하여).

기본적으로 ( push.default구성 변수에 따라) "git push"또는 "git push < remote >"Git은 일치하는 브랜치를 푸시합니다 . 즉, 원격 리포지토리에 해당 항목이 이미있는 로컬 브랜치 만 푸시합니다. --allgit-push ( "git push --all") 옵션을 사용 하여 모든 분기 를 푸시 하고 "git push < remote > < branch >"를 사용하여 지정된 단일 분기 를 푸시하고 "git push < remote > HEAD "를 눌러 현재 분기 를 푸시 합니다.

위의 모든 것은 Git이 remote.<remotename>.push 구성 변수 를 통해 푸시 할 분기를 구성하지 않았다고 가정 합니다.

가져 오는 지점

참고 : 여기서 "fetch"는 변경 사항을 로컬 작업과 통합 하지 않고 원격 저장소에서 변경 사항을 다운로드하는 것을 의미하는 Git 용어를 사용 합니다. 이것이 " git fetch"와 " hg pull"의 역할입니다.

올바르게 이해하면 Mercurial은 기본적으로 원격 저장소에서 모든 헤드 를 가져 오지만 " hg pull --rev <rev> <url>"또는 " hg pull <url>#<rev>"를 통해 가져올 분기를 지정 하여 단일 분기 를 가져올 수 있습니다. 개정 식별자, "명명 된 브랜치"이름 (변경 로그에 포함 된 브랜치) 또는 책갈피 이름을 사용하여 <rev>를 지정할 수 있습니다. 그러나 북마크 이름은 (적어도 현재) 전송되지 않습니다. 소속 된 모든 "명명 된 브랜치"개정판이 이전됩니다. "hg pull"은 익명의 익명 헤드로 가져온 브랜치의 팁을 저장합니다.

기본적으로 Git ( "git clone"에 의해 생성 된 '원점'원격 및 "git remote add"를 사용하여 생성 된 원격)의 경우 " git fetch"(또는 " git fetch <remote>")는 원격 저장소 ( 네임 스페이스) 에서 모든 분기 를 가져 와서 refs/heads/저장합니다. refs/remotes/네임 스페이스. 예를 들어 원격 'origin'에서 'master'(이름 : 'refs / heads / master') 라는 브랜치가 'origin / master' 원격 추적 브랜치 (전체 이름 : 'refs / 리모컨 / 원산지 / 마스터 ').

당신은 가져올 수 있습니다 단일 지점을 사용하여 힘내에서 git fetch <remote> <branch>- 힘내 의욕 이름이 머리에 비슷한입니다 FETCH_HEAD에 요청 지점 (들)을 저장한다.

이것들은 강력한 refspec Git 구문 의 기본 사례의 예일뿐입니다. refspecs를 사용하면 가져올 브랜치 및 저장 위치를 ​​지정 및 / 또는 구성 할 수 있습니다. 예를 들어 기본 "모든 분기 가져 오기"사례는 '+ refs / heads / * : refs / remotes / origin / *'와일드 카드 참조 스펙으로 표시되고 "단일 분기 가져 오기"는 'refs / heads / <branch> :'의 약어입니다. . Refspec은 원격 저장소의 브랜치 (refs) 이름을 로컬 참조 이름에 매핑하는 데 사용됩니다. 그러나 Git (주로 "git remote"명령 덕분에)으로 효과적으로 작업 할 수 있도록 refspec에 대해 많이 알 필요는 없습니다.

개인적 의견 : 저는 개인적으로 Mercurial의 "명명 된 브랜치"(변경점 메타 데이터에 포함 된 브랜치 이름을 가진)가 특히 분산 버전 제어 시스템 의 경우 글로벌 네임 스페이스를 사용하여 잘못 설계되었다고 생각합니다 . 예를 들어 Alice와 Bob이 모두 저장소에 공통 이름이없는 "for-joe"라는 이름의 "named branch"가있는 경우를 예로 들어 보겠습니다. 그러나 Joe의 저장소에서이 두 분기는 단일 분기로 잘못 취급됩니다. 그래서 어떻게 든 브랜치 이름 충돌로부터 보호하는 규칙을 마련했습니다. 이것은 Joe의 저장소 'for-joe'분기에서 Alice의 'alice / for-joe'가되고 Bob의 경우 'bob / for-joe'가되는 Git에는 문제가되지 않습니다.

Mercurial의 "북마크 지점"에는 현재 핵심 배포 메커니즘이 없습니다.

차이점 : James woodyattSteve Losh 가 대답 한
것처럼 Mercurial과 Git의 주요 차이점 중 하나입니다 . Mercurial은 기본적으로 익명의 경량 코드 라인을 사용하는데, 그 용어로 "헤드"라고합니다. Git은 경량 저장소를 사용하여 원격 저장소의 분기 이름을 원격 추적 분기 이름에 매핑하기 위해 인젝 티브 매핑을 사용합니다. Git은 분기 이름을 지정하도록 강제합니다 (단 하나의 명명되지 않은 분기, 분리 된 HEAD라고하는 상황 제외). 이것은 단일 저장소 패러다임의 여러 분기를 의미하는 주제 분기 워크 플로우와 같은 분기가 많은 워크 플로우에서 더 효과적이라고 생각합니다.

이름 수정

Git에는 여러 가지 방법으로 이름을 바꾸는 방법이 있습니다 (예 : git rev-parse 맨 페이지에 설명되어 있음).

  • 전체 SHA1 오브젝트 이름 (40 바이트 16 진 문자열) 또는 저장소 내에서 고유 한 서브 스트링
  • '마스터'( '마스터'분기 참조) 또는 'v1.5.0'(태그 참조) 또는 '원점 / 다음'(원격 추적 분기 참조)과 같은 상징적 참조 이름
  • ^수정 접미사 매개 변수는 커밋 개체의 첫 번째 부모를 ^n의미하고 병합 커밋의 n 번째 부모를 의미합니다. ~n수정 접미사 매개 변수는 첫 번째 부모 행에서 커밋의 n 번째 조상을 의미합니다. 이러한 접미사를 조합하여 기호 참조에서 경로를 따라 수정 자 지정자를 형성 할 수 있습니다 (예 : 'pu ~ 3 ^ 2 ~ 3'
  • "git describe"의 결과, 즉 가장 가까운 태그, 선택적으로 대시 및 다수의 커밋, 대시, 'g'및 축약 된 오브젝트 이름 (예 : 'v1.6.5.1-75- g5bf8097 '.

여기에 언급되지 않은 reflog와 관련된 개정 지정자도 있습니다. Git에서 각 객체는 commit, tag, tree 또는 blob에 SHA-1 식별자가 있습니다. 지정된 개정판에서 트리 (디렉토리) 또는 BLOB (파일 내용)을 참조하는 'next : Documentation'또는 'next : README'와 같은 특수 구문이 있습니다.

Mercurial은 또한 변경 세트의 이름을 지정하는 여러 가지 방법을 가지고 있습니다 (예 : hg 맨 페이지에 설명되어 있음 ).

  • 일반 정수는 개정 번호로 취급됩니다. 개정 번호는 지정된 저장소에 대해 로컬 임을 기억해야 합니다 . 다른 저장소에서는 다를 수 있습니다.
  • 음의 정수는 팁을 순차적으로 오프셋으로 처리하며, -1은 팁을, -2는 팁 이전의 개정을 나타냅니다. 또한 저장소에 로컬 입니다.
  • 고유 한 개정 식별자 (40 자리 16 진 문자열) 또는 고유 한 접 두부.
  • 태그 이름 (지정된 개정과 연관된 기호 이름) 또는 책갈피 이름 (확장자 : 지정된 헤드와 연관된 기호 이름, 저장소에 로컬) 또는 "명명 된 분기"(커밋 레이블; "명명 된 분기"에 의해 제공된 개정판은 주어진 커밋 레이블이있는 모든 커밋의 팁 (자식없는 커밋) (팁이 둘 이상인 경우 개정 번호가 가장 큼)
  • 예약 이름 "tip"은 항상 최신 개정을 식별하는 특수 태그입니다.
  • 예약 된 이름 "널"은 널 개정을 나타냅니다.
  • 예약 된 이름 "." 작업 디렉토리 상위를 나타냅니다.

차이점
위의 목록을 비교할 수 있듯이 Mercurial은 저장소에 대해 로컬 인 개정 번호를 제공하지만 Git은 그렇지 않습니다. 반면 Mercurial은 리포지토리에 로컬 인 'tip'(현재 분기)에서만 상대적 오프셋을 제공하지만 ( GrantrevspecExtension 없이는 ) 최소한 Git은 모든 팁에서 커밋을 지정할 수 있습니다.

가장 최근의 개정판은 Git에서 HEAD로, ​​Mercurial에서 "tip"으로 명명되었습니다. Git에는 널 개정이 없습니다. Mercurial과 Git 모두 루트가 많을 수 있습니다 (부모없는 커밋이 둘 이상있을 수 있음).

또한 엘리야 블로그 (Newren 's Blog)에있는 여러 종류의 개정 지정자 기사를 참조하십시오.

개인적 견해 : 나는 개정 번호 가 과대 평가 된 것으로 생각합니다 (적어도 분산 개발 및 / 또는 비선형 / 지사 기록에 대해서는). 먼저, 분산 버전 제어 시스템의 경우 저장소에 대해 로컬이거나 로컬 번호 지정 기관으로 특별한 방식으로 일부 저장소를 처리해야합니다. 둘째, 더 긴 기록을 가진 더 큰 프로젝트는 5 자리 범위의 개정 수를 가질 수 있으므로 6-7 문자 개정 식별자로 단축 된 것보다 약간의 이점 만 제공하며 개정이 부분적으로 만 주문되는 동안 엄격한 순서를 암시합니다 (여기서는 수정본 n과 n + 1은 부모와 자식 일 필요는 없습니다).

수정 범위

Git 개정판에서 범위는 토폴로지 입니다. 일반적으로 본 A..B선형 기록 수단 개정 범위 (A)에서 시작하여 (그러나 제외) (즉, 범위가 B에서 끝나는 구문, 아래에서 오픈 ) 속기가 ( "문법적")이고 ^A B역사 이송 명령은 모든 의미있는을 A에서 도달 할 수있는 것을 제외하고 B에서 도달 할 수 있습니다. 이는 A..BA가 B의 조상이 아닌 경우에도 범위 의 동작 이 완전히 예측 가능하고 매우 유용하다는 A..B것을 의미합니다. ) 개정 B.

Mercurial 개정 범위는 개정 번호 범위를 기준으로 합니다 . 범위는 A:B구문을 사용하여 지정 되며 Git 범위와 반대로 닫힌 간격으로 작동 합니다 . 또한 범위 B : A는 역순으로 범위 A : B이며, Git의 경우에는 해당되지 않습니다 (하지만 A...B구문 에 대한 아래 참고 사항 참조 ). 그러나 이러한 단순성에는 가격이 따른다. 수정 범위 A : B는 A가 B의 조상이거나 그 반대의 경우, 즉 선형 이력이있는 경우에만 의미가있다. 그렇지 않으면 (범위는 예측할 수 없으며 결과는 리포지토리에 로컬입니다 (개정 번호는 리포지토리에 로컬이기 때문에).

이것은 새로운 토폴로지 개정 범위 를 갖는 Mercurial 1.6으로 수정되었습니다 . 여기서 'A..B'(또는 'A :: B')는 X의 자손과 Y의 조상 인 변경 세트로 이해됩니다. , Git의 '--ancestry-path A..B'와 같습니다.

Git A...B은 개정의 대칭 적 차이에 대한 표기법도 가지고 있습니다 . 즉 A B --not $(git merge-base A B), A 또는 B에서 도달 할 수있는 모든 커밋을 의미하지만 둘 다에서 도달 할 수있는 모든 커밋은 제외합니다 (공통 조상에서 도달 할 수 있음).

이름 바꾸기

Mercurial은 이름 바꾸기 추적 을 사용 하여 파일 이름 바꾸기를 처리합니다. 이는 파일 이름이 변경되었다는 사실에 대한 정보가 커미트 시간에 저장됨을 의미합니다. Mercurial에서이 정보는 "향상된 diff"형식으로 filelog (파일 revlog) 메타 데이터에 저장됩니다. 결과적으로 hg rename/ hg mv... 를 사용해야 하거나 hg addremove유사성 기반의 이름 바꾸기 감지 를 수행 하기 위해 실행해야합니다 .

Git은 파일 이름 변경을 처리 하기 위해 이름 변경 감지 를 사용한다는 점에서 버전 제어 시스템에서 고유 합니다. 즉, 파일 이름이 바뀌 었다는 사실은 필요할 때, 즉 병합을 수행 할 때 또는 diff를 표시 할 때 (요청 / 구성된 경우) 감지됩니다. 이는 이름 변경 감지 알고리즘을 개선 할 수 있고 커밋시 정지되지 않는 이점이 있습니다.

Git과 Mercurial은 --follow단일 파일의 히스토리를 표시 할 때 이름 바꾸기를 수행하기 위해 옵션을 사용해야 합니다. git blame/에 파일의 행별 히스토리를 표시 할 때 이름 변경을 따를 수 있습니다 hg annotate.

Git에서 git blame명령은 코드 이동을 수행 할 수 있으며, 코드 이동이 건전한 파일 이름 바꾸기의 일부가 아니더라도 한 파일에서 다른 파일로 코드를 이동 (또는 복사) 할 수도 있습니다. 내가 아는 한이 기능은 Git (2009 년 10 월 작성 당시)에 고유합니다.

네트워크 프로토콜

Mercurial과 Git은 동일한 파일 시스템에서 리포지토리를 가져오고 푸시하는 기능을 지원합니다. 여기서 리포지토리 URL은 리포지토리에 대한 파일 시스템 경로입니다. 둘 다 번들 파일 에서 가져 오기를 지원 합니다 .

SSH 및 HTTP 프로토콜을 통한 페치 및 푸시 지원 SSH의 경우 대상 컴퓨터에 액세스 가능한 셸 계정과 설치 / 사용 가능한 hg 사본이 필요합니다. HTTP 액세스를 위해서는 hg-serveMercurial CGI 스크립트가 실행 중이어야하며 서버 시스템에 Mercurial을 설치해야합니다.

Git은 원격 저장소에 액세스하는 데 사용되는 두 가지 종류의 프로토콜을 지원합니다.

  • SSH를 통한 액세스 및 사용자 정의 git : // 프로토콜을 통한 액세스를 포함하는 "스마트"프로토콜git-daemon 은 서버에 git이 설치되어 있어야합니다. 이러한 프로토콜의 교환은 클라이언트와 서버가 공통으로 가지고있는 객체를 협상 한 다음 팩 파일을 생성 및 전송하는 클라이언트와 서버로 구성됩니다. 최신 Git은 "스마트 한"HTTP 프로토콜을 지원합니다.
  • HTTP 및 FTP (페치 전용) 및 HTTPS (WebDAV를 통한 푸시)를 포함하는 "dumb"프로토콜 은 서버에 git을 설치하지 않아도되지만 저장소에는 생성 된 추가 정보 git update-server-info(일반적으로 후크에서 실행)가 포함되어야합니다. ). 교환은 클라이언트가 커밋 체인을 걷고 필요에 따라 느슨한 오브젝트와 팩 파일을 다운로드하는 것으로 구성됩니다. 단점은 엄격하게 요구되는 것 이상을 다운로드하는 것입니다 (예를 들어 단일 팩 파일이 하나만있는 경우에는 약간의 수정본 만 가져와도 전체가 다운로드 됨). 완료하려면 많은 연결이 필요할 수 있습니다.

확장 : 스크립트 가능성과 확장 (플러그인)

Mercurial은 성능을 위해 C로 작성된 일부 핵심 코드와 함께 Python 으로 구현됩니다 . 추가 기능을 추가하는 방법으로 확장 (플러그인) 을 작성하기위한 API를 제공 합니다. "책갈피 분기"또는 서명 개정과 같은 일부 기능은 Mercurial과 함께 배포 된 확장에서 제공되며이를 켜야합니다.

Git은 C , Perl쉘 스크립트 로 구현됩니다 . Git은 스크립트에 사용하기에 적합한 많은 저수준 명령 ( 배관 )을 제공합니다 . 새로운 기능을 도입하는 일반적인 방법은이 기능을 Perl 또는 쉘 스크립트로 작성하는 것입니다. 사용자 인터페이스가 안정되면 성능, 이식성 및 쉘 스크립트를 피하기 위해 C로 다시 작성하십시오 (이 절차를 내장이라고 합니다 ).

Git은 [리포지토리] 형식과 [네트워크] 프로토콜을 기반으로하고 있습니다. 언어 바인딩 대신 다른 언어로 Git을 부분적으로 또는 전체적으로 다시 구현 합니다 (일부는 부분적으로 다시 구현하고 git 명령을 부분적으로 래퍼하는 것임) : JGit (Java, EGit에서 사용하는 Java, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #).


TL; DR


32
추가 할 수있는 것은 hg가 히스토리 재 작성을 막기 위해 열심히 노력한다는 것입니다 (mq, histedit, rebase 확장으로 만 수행 할 수 있음) .git은 기본적으로 사용되며 커뮤니티의 일부처럼 보입니다. 장려합니다).
tonfa

80
"기록 다시 작성"은 불필요하게 부정적인 소리라고 생각합니다. 어떻게 내가 자식에 격려하는 사람들이 게시 역사를 고려하는 것입니다. 다른 사람들은 그 역사를 소비해야합니다. 아무도 (당신조차도) 당신의 모든 "죄송합니다, 파일을 잊어 버렸습니다"커밋에 관심이 없습니다. 새로운 기능을 개발하는 동안 업스트림 지점을 추적하는 동안 겪은 일련의 인바운드 병합에 관심이있는 사람도 없습니다. 이런 종류의 물건은 역사 (및 관련 도구)를 이해하기 어렵게 만들고 가치를 제공하지 않습니다.
더스틴

5
@Jakub : 명명 된 브랜치는 git에는 존재하지 않는 것입니다. 그것은 단순히 cset 설명의 필드이며 기록의 일부이므로 해시 등을 변경하지 않으면 변경할 수 없습니다. 자식 분기와 같은 것은 책갈피 ( "이름이 지정된 헤드")이지만 현재 원격으로 전송할 수 없습니다 (당길 때 원격 책갈피를 가져 오지 않음). stevelosh.com/blog/entry/2009/8/30/…이 내용을 잘 설명합니다.
tonfa

28
"Mercurial은 원래 리포지토리 워크 플로 당 하나의 지점 만 지원했으며이를 보여줍니다." 아뇨 Mercurial은 처음에 지명 된 지점을 지원하지 않았지만 단일 리포지토리에서 원하는만큼의 익명의 지점을 항상 가질 수있었습니다. 익명 분기를 고통으로 만드는 git과 대조하십시오 . 당신은 꽤 많이 가지고 당신이 할 아무것도 얻을 수 (및 작업 쓰레기 수집하는 것을 피하기)하려면 모든 작은 지점의 이름을 생각.
Steve Losh

17
@SteveLosh : Mercurial에 익명의 지점이 많이있는 것이 좋은 것이라고 생각하는 것 같지만 나에게는 끔찍한 것 같습니다. 당신은 그들 모두를 어떻게 구별합니까? 그리고 Git에서 브랜치의 이름을 짓는 것은 엄청난 어려움이라고 생각하지만 브랜치를 만들려는 목적이 있다면 기성품 이름이 있습니다. 당신이 목적이 없다면, 분기하지 마십시오. Mercurial이 어떻게 이점을 제공하는지 알 수 없습니다. 나는 고통과 혼란만을 본다.
iconoclast

57

두 비디오를 틀면 그 시스템이 비슷하거나 다른 점을 느낄 수 있다고 생각합니다.

Git의 Linus Torvalds ( http://www.youtube.com/watch?v=4XpnKHJAok8 )
Mercurial의 Bryan O'Sullivan ( http://www.youtube.com/watch?v=JExtkqzEoHY )

둘 다 디자인은 매우 유사하지만 구현 방식은 매우 다릅니다.

나는 Mercurial을 사용합니다. Git을 이해하는 한 git과 다른 점은 파일 자체 대신 파일의 내용을 추적한다는 것입니다. Linus는 한 파일에서 다른 파일로 함수를 이동하면 Git은 이동 중에 해당 단일 함수의 히스토리를 알려줍니다.

또한 git은 HTTP보다 느리지 만 자체 네트워크 프로토콜과 서버가 있다고 말합니다.

Git은 Mercurial보다 SVN 씩 클라이언트로 더 잘 작동합니다. SVN 서버를 당기고 밀 수 있습니다. 이 기능은 아직 Mercurial에서 개발 중입니다

Mercurial과 Git은 모두 멋진 웹 호스팅 솔루션 (BitBucket 및 GitHub)을 제공하지만 Google Code는 Mercurial 만 지원합니다. 그건 그렇고, 그들은 지원 할 대상을 결정하기 위해 Mercurial과 Git을 매우 상세하게 비교했습니다 ( http://code.google.com/p/support/wiki/DVCSAnalysis ). 좋은 정보가 많이 있습니다.


8
해당 Google 코드 페이지에 대한 모든 의견을 읽는 것이 좋습니다. 정보가 다소 편견적이며 내 경험과 잘 맞지 않습니다. 나는 hg를 좋아 하고 1 년 정도 광범위하게 사용했습니다 . 나는 지금 거의 독점적으로 git을 사용한다. git이 쉬워지고 hg가 거의 불가능하다는 것을 달성해야 할 것들이 있습니다 (일부는 "복합"을 통해 이것을 호출하는 것을 좋아하지만) 기본 git는 기본 hg만큼 쉽습니다.
Dustin

11
더스틴, 아마도 "git easy, hg not not 많지 않은"사례 중 일부를 나열 할 수 있습니까?
Gregg Lind

1
@knittl 아니에요. git에 스마트 http 프로토콜이 없기 때문에 배포하는 데 어려움이 있기 때문에 (Google 프론트 엔드의 대부분은 http 기반입니다).
tonfa

2
@tonfa : Git 용 스마트 HTTP 프로토콜은 현재 개발 중입니다 (git 메일 링리스트에 패치가 있고 'pu'= git.git 저장소의 제안 된 업데이트 브랜치에 있음).
Jakub Narębski

4
현재 Google 코드는 Git도 지원합니다.
Andrej Kirejeŭ

30

얼마 전 Mercurial의 브랜칭 모델에 대한 블로그 항목을 작성했으며 git의 브랜칭 모델과 비교했습니다. 아마 당신은 재미있을 것입니다 : http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/


@Steve Losh :이 블로그 항목 (이름이없는 분기 일명 HEAD 분리 및 git-fetch가 모든 분기를 가져 오는 것이 아니라 하나에 대한 정보)에 대해 언급하고 싶지만 500 서버 오류가 발생했습니다.
Jakub Narębski

1
@Jakub Narębski 문제는 귀하의 이름에 ASCII가 아닌 문자라는 것입니다. 다른 사이트에서 동일한 문제가 발생했다고 확신하며 Python Askimet 바인딩이 유니 코드에서 질식합니다. 내가 볼게
Steve Losh

@Steve Losh : 정보를 보내 주셔서 감사합니다. "unidecoding"후에 내 이름으로 의견을 게시 할 수있었습니다. (하지만 난 여전히 열등하다고 생각 ;-)) 의욕에 분기의 아주 좋은 설명
야쿱 Narębski을

@SteveLosh이 답변을 확대하여 수은에 대한보다 완전한 검토를하시기 바랍니다. 현재 답변은 불행히도 git에 대한 광고입니다. 저자는 수은을 광범위하게 사용하지 않았으며 효과적으로 사용하는 방법을 이해하지 못했기 때문입니다. 다시 말해, 수은 관점을 제공하는 또 다른 대답이 좋을 것입니다.
Warren Dew

25

나는 꽤 정기적으로 사용합니다. 주요 기능상의 차이점은 Git 및 Mercurial 이름이 리포지토리 내에서 분기되는 방식에 있습니다. Mercurial을 사용하면 지사 이름이 변경 세트와 함께 복제되어 가져옵니다. Mercurial의 새 브랜치에 변경 사항을 추가하고 다른 저장소로 푸시하면 브랜치 이름이 동시에 푸시됩니다. 따라서 지점 이름은 Mercurial에서 거의 전역 적이며 책갈피 확장을 사용하여 로컬 전용 경량 이름을 사용해야합니다 (원하는 경우 Mercurial은 기본적으로 익명 경량 코드 라인을 사용함). "헤드"라고합니다. Git에서 브랜치 이름과 원격 브랜치에 대한 인젝 티브 매핑은 로컬로 저장되며이를 명시 적으로 관리해야합니다.

다른 사람들이 여기서 알 수 있듯이, 사소한 차이가 많이 있습니다. 가지가있는 것은 큰 차별화 요소입니다.


2
Mercurial의 4 가지 가지에 대한 자세한 설명은이 게시물을 참조하십시오 : stevelosh.com/blog/entry/2009/8/30/…
Martin Geisler


11

Mercurial은 거의 완전히 파이썬으로 작성되었습니다. Git의 핵심은 C로 작성되었으며 Mercurial보다 빠르며 sh, perl, tcl로 작성된 도구이며 표준 GNU 유틸리티를 사용합니다. 따라서 이러한 모든 유틸리티와 인터프리터를 포함하지 않는 시스템 (예 : Windows)으로 가져와야합니다.

Windows에서 git에 대한 AFAIK svn 지원이 중단되었지만 두 가지 지원은 SVN과 함께 작동합니다. git과 Mercurial간에 상호 운용 할 수있는 확장 기능도 있습니다.

Mercurial은 멋진 Visual Studio 통합 기능을 갖추고 있습니다. 마지막으로 확인했을 때 Git 플러그인 이 작동했지만 매우 느 렸습니다.

기본 명령 세트는 매우 유사합니다 (init, clone, add, status, commit, push, pull 등). 따라서 기본 워크 플로는 동일합니다. 또한 TortoiseSVN과 유사한 클라이언트가 있습니다.

Mercurial 용 확장 프로그램은 파이썬으로 작성 될 수 있으며 (놀랍지 않습니다!) git 용으로 모든 실행 파일 형식 (실행 가능 바이너리, 쉘 스크립트 등)으로 작성 될 수 있습니다. 일부 확장 프로그램은과 같이 강력하고 강력 git bisect합니다.


9
머큐리얼 코어는 C도 참고로 작성되었지만 아마도 git보다 작은 코어 일 것입니다.
tonfa

1
Windows에서 아무런 문제없이 git-svn을 사용합니다. Cygwin에서 (만 사용하고 그 바로 Windows에서 사용 자식에 방법 당신이 저를 요구하는 경우에)를. msysgit를 말할 수 없습니다.
Dan Molding

@ Dan Moulding : 예, msysgit에 문제가 있습니다. cygwin 포트에 시도해야 할 수도 있습니다 (cygwin을 일찍 사용한 경험이 없었기 때문에 피했습니다). 충고에 감사하다!
elder_george

나는 cygwin이 레지스트리에 침입하여 사용자 데이터를 저장하는 것을 개인적으로 싫어합니다. USB 키를 사용하고 USB 키보다 빠르게 실행하려는 경우 로컬 c : \ 드라이브 사본을 동기화 된 상태로 유지하는 것이 PITA입니다. :-/
Chris K

1
위에서 언급 한 Visual Studio 용 Git 플러그인을 사용하며 현재 버전의 성능이 좋습니다. 작업을 수행하기 위해 명령 줄 도구를 사용하므로 대규모 프로젝트에서 성능이 크게 저하되지는 않을 것이라고 생각합니다.
스튜어트 엘리스

11

우수한 Windows 지원이 필요한 경우 Mercurial을 선호 할 수 있습니다. TortoiseHg (Windows 탐색기 플러그인)는 다소 복잡한 도구에 대한 간단한 그래픽 인터페이스를 제공합니다. 여기에서 상태로 Visual Studio 플러그인도 있습니다. 그러나 마지막으로 시도했을 때 SVN 인터페이스가 Windows에서 제대로 작동하지 않았습니다.

커맨드 라인 인터페이스가 마음에 들지 않는다면 Git을 추천합니다. 기술적 이유가 아니라 전략적인 이유 때문입니다. 자식 채택률이 훨씬 높습니다. cvs / svn에서 Mercurial로 전환하는 유명한 오픈 소스 프로젝트 수와 Git으로 전환되는 프로젝트 수를 확인하십시오. Mercurial 호스팅과 비교하여 git 지원으로 찾을 수있는 코드 / 프로젝트 호스팅 제공 업체 수를 확인하십시오.


명령 행 사용이 마음에 들지 않으면 TortoiseGit도 있습니다. (그러나 msysgit을 설치해야합니다.)
Ben James

2
우리 회사는 Windows 체크 아웃 Git Extensions 에 대한 훌륭한 지원 때문에 git을 선택하게되었습니다 . 나는 지금 기고자이기 때문에 편견이 있지만 우리가 그것을 사용하기 시작하지 않았습니다.
Jacob Stanley

11

Mercurial이 더 쉽다는 것을 읽은 후 (모든 인터넷 커뮤니티가 의견을 얻은 후에도 여전히 믿습니다), Git 및 Mercurial과 작업을 시작했을 때 Git이 적응하기가 비교적 간단하다고 느꼈습니다 (시작했습니다) 명령 줄에서 작업 할 때 주로 git 명령의 이름이 적절하고 이름이 적기 때문에 Mercurial with TortoiseHg) . Mercurial은 고유 한 작업을 수행하는 각 명령마다 이름이 다르지만 Git 명령은 상황에 따라 다목적 일 수 있습니다 (예 :checkout). Git은 당시보다 더 어려웠지만 이제는 그 차이가 거의 없습니다. YMMV .. TortoiseHg와 같은 훌륭한 GUI 클라이언트를 사용하면 Mercurial을 사용하는 것이 훨씬 쉬웠으며 약간 혼란스러운 명령을 기억할 필요가 없었습니다. 동일한 작업에 대한 모든 명령이 어떻게 다른지 자세히 설명하지는 않지만 Mercurial의 자체 사이트wikivs 두 가지 포괄적 인 목록이 있습니다.

╔═════════════════════════════╦════════════════════════════════════════════════════════════════════════════════════════════════╗
║           Git               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

Git은 커밋 된 파일의 모든 버전을 내부적으로 저장하고 Hg는 설치 공간을 줄일 수있는 변경 세트 만 저장합니다. Git을 사용하면 Hg에 비해 히스토리를 쉽게 변경할 수 있지만 싫어하는 기능입니다. 나는 Hg는 전자를 좋아하고 Git은 후자를 좋아합니다.

내가 Hg에서 놓친 것은 Git의 서브 모듈 기능입니다. Hg에는 하위 리포지토리가 있지만 정확히 Git 하위 모듈은 아닙니다.

두 가지 주변의 생태계도 선택에 영향을 줄 수 있습니다 : Git은 더 인기가 있어야하지만 ( GitHub는 있지만 Mercurial은 BitBucket을 , Mercurial은 TortoiseHg를 가지고 있습니다.

각각의 장점과 단점이 있으며 둘 중 하나를 잃지 않을 것입니다.


8

Scott Chacon의 게시물 을 잠시 확인하십시오 .

git은 "더 복잡한"것으로 유명하지만 내 경험상 필요 이상으로 복잡하지는 않습니다. IMO는 자식 모델이다 방법 (태그 0 개 이상의 부모 커밋에 커밋 (및 포인터를 포함)를 포함 나무 완료 ... 모양과 다른 나무를 포함) 이해하기 쉽게.

git이 수은보다 더 혼란스럽지 않은 것은 단지 내 경험이 아닙니다. 문제에 대해 Scott Chacon의이 블로그 게시물을 다시 읽는 것이 좋습니다 .


1
머큐리얼 모델은 실제로 거의 동일합니다. 온 디스크 형식을 비교하는 경우 아마도 hg의 간단한 revlog 형식보다 설명하기 어려운 packs 파일을 고려하지 않았을 것입니다.
tonfa

글쎄, 그 단순화 된 모델은 hg에서 실제로 매우 성가신 태깅을 무시합니다 (git 태그는 기본적으로 태그 객체를 생성하지 않기 때문에 약간 혼란 스럽습니다). 온 디스크 형식은 파일 이름이 많은이 두 프로젝트 모두에서 특히 비쌌습니다.
더스틴

1
나는 모델이 태깅을 무시한다고 생각하지 않는다. 태깅은 Mercurial에서 사소한 것이다. 아시다시피, 그것은 SHA-1 해시에 이름을 부여하는 파일 일 뿐이다. 시스템에서 태그가 어떻게 이동하는지에 대한 추측은 없습니다 : 태그가 밀고 당기면서 움직입니다. 태그 충돌이있는 경우 문제를 해결하는 것도 간단합니다. 다른 충돌과 같이 문제를 해결하는 것입니다. 결국, 그것은 텍스트 파일의 한 줄에 불과합니다. 이 모델의 단순성은 매우 좋은 기능이라고 생각합니다.
Martin Geisler

더스틴 : 예, .hgtags개정판 1.0을 체크 아웃 할 때 1.0 태그를 볼 수 없다는 사실 때문에 사용자가 종종 혼란 스럽습니다 . 그러나 모양 내부에 필요하지 않습니다 .hgtags그리고 당신은 당신은 찾을 hg tags여전히 목록 모든 태그를. 또한이 동작은 버전 제어 파일에 태그를 저장하면 발생하는 간단한 결과입니다. 다시 말하면 모델을 쉽게 파악하고 예측할 수 있습니다.
Martin Geisler

1
Martin Geisler 나는 Mercurial의 태그에 대한 규칙은 태그를 버전을 지정하지 않는 특수 규칙의 레이어와 함께 전송을 위해 버전 제어 파일을 사용하기 때문에 필요하기 때문에 필요하다고 생각합니다.
Jakub Narębski

5

나는 현재 직장에서 1 년 이상 조금씩 Git을 사용했고, 그 전에는 이전 직장에서 1 년 이상 Mercurial을 사용했습니다. 사용자 관점에서 평가를 제공 할 것입니다.

첫째, 둘 다 분산 버전 제어 시스템입니다. 분산 버전 제어 시스템은 기존 버전 제어 시스템에서 사고 방식을 변경해야하지만 실제로 이해하면 여러 가지 방식으로 훨씬 효과적으로 작동합니다. 이런 이유로 나는 Git과 Mercurial이 Subversion, Perforce 등보다 훨씬 우수하다고 생각합니다. 분산 버전 제어 시스템과 기존 버전 제어 시스템의 차이는 Git와 Mercurial의 차이보다 훨씬 큽니다.

그러나 Git과 Mercurial 간에는 각각 고유 한 사용 사례 하위 집합에 더 적합하도록하는 중요한 차이점이 있습니다.

머큐리얼은 배우기가 더 간단합니다. Mercurial을 사용한 지 몇 주 후에 문서 나 메모를 거의 언급하지 않는 시점에 도달했습니다. 1 년 동안 사용한 후에도 여전히 Git에서 정기적으로 노트를 참조해야합니다. 힘내는 훨씬 더 복잡합니다.

이것은 부분적으로 Mercurial이 단순한 클리너이기 때문입니다. Mercurial에서 수동으로 분기 할 필요는 거의 없습니다. Mercurial은 필요할 때 필요할 때 자동으로 익명 지점을 만듭니다. 머큐리얼 명칭은 더 직관적입니다. Git과 마찬가지로 "fetch"와 "pull"의 차이점에 대해 걱정할 필요가 없습니다. 머큐리얼은 버그가 적습니다. Git과 Mercurial이있는 플랫폼에서 프로젝트를 푸시 할 때 문제를 일으키는 데 사용되는 파일 이름 대소 문자 구분 문제가 있습니다. 그들이 마지막으로 확인한 Git에서 수정되지 않은 동안 이것은 얼마 전에 Mercurial에서 수정되었습니다. Mercurial에 파일 이름 변경을 알려줄 수 있습니다. Git을 사용하면 이름 바꾸기가 자동으로 감지되지 않으면 내 경험에서 명중이나 누락 된 제안이 있으면 이름 바꾸기를 전혀 추적 할 수 없습니다.

그러나 Git의 추가 복잡성에 대한 다른 이유는 추가 기능과 성능을 지원하는 데 필요한 것이기 때문입니다. 그렇습니다. Git에서 분기를 처리하는 것이 더 복잡합니다. 반면에 일단 지점이 있으면 Mercurial에서는 사실상 불가능한 지점으로 작업을 수행하는 것이 어렵지 않습니다. 가지를 리베 이싱하는 것은 다음 중 하나입니다. 분기 할 때 트렁크의 상태가 아닌 기본이 트렁크의 상태가되도록 분기를 이동할 수 있습니다. 이는 동일한 코드 기반으로 작업하는 많은 사람들이있을 때 버전 기록을 크게 단순화시킵니다. 트렁크에 대한 각 푸시는 서로 꼬이지 않고 순차적으로 표시 될 수 있기 때문입니다. 마찬가지로 지점의 여러 커밋을 단일 커밋으로 축소하는 것이 훨씬 쉽습니다.

궁극적으로 Mercurial과 Git의 선택은 동시에 작업하는 사람들의 수로 측정되는 버전 제어 프로젝트의 크기에 달려 있어야한다고 생각합니다. 예를 들어 단일 모 놀리 식 웹 애플리케이션에서 작업하는 12 명 이상의 그룹이있는 경우 Git의보다 강력한 분기 관리 도구를 사용하면 프로젝트에 훨씬 더 적합합니다. 반면, 팀이 이기종 분산 시스템을 개발하는 경우 한 번에 하나 또는 두 명의 개발자 만 한 구성 요소에서 한 구성 요소로 작업하는 경우 각 구성 요소 프로젝트에 Mercurial 리포지토리를 사용하면 적은 비용으로 더 원활하게 개발을 진행할 수 있습니다. 저장소 관리 오버 헤드.

결론 : 하나의 거대한 응용 프로그램을 개발하는 큰 팀이 있다면 Git을 사용하십시오. 개별 응용 프로그램이 작고 규모가 그 응용 프로그램의 크기가 아니라 숫자에서 나오는 경우 Mercurial을 사용하십시오.


4

DVCS 자체와 전혀 관련이없는 한 가지 차이점 :

Git은 C 개발자들에게 매우 인기가있는 것 같습니다. Git은 Linux Kernel의 사실상 저장소이며 이것이 C 개발자들에게 인기가있는 이유 일 수 있습니다. 이것은 Linux / Unix 세계에서만 일하는 사치를 가진 사람들에게 특히 그렇습니다.

Java 개발자는 Git보다 Mercurial을 선호하는 것 같습니다. 두 가지 이유가있을 수 있습니다. 하나는 JDK 자체를 포함하여 수많은 대규모 Java 프로젝트가 Mercurial에서 호스팅되기 때문입니다. 다른 하나는 Mercurial의 구조와 깔끔한 문서화가 Java 캠프에서 온 사람들에게 호소하는 반면, 그러한 사람들은 Git이 일관성없는 wrt 명령 이름 지정과 문서화 부족을 발견한다는 것입니다. 나는 그것이 사실이라고 말하는 것이 아닙니다. 사람들이 평소의 서식지에서 무언가에 익숙해 졌다고 말한 후 DVCS를 선택하는 경향이 있습니다.

파이썬 개발자는 거의 독점적으로 Mercurial을 선호합니다. Mercurial이 Python을 기반으로한다는 사실 이외의 합리적인 이유는 없습니다. (나는 Mercurial도 사용하고 사람들이 DVCS의 구현 언어에 대해 소란을 일으키는 이유를 정말로 이해하지 못한다. 나는 파이썬의 단어를 이해하지 못하고 그것이 어딘가에 나열되어 있다는 사실에 대해 이해하지 못한다면 파이썬을 기반으로하지만 알지 못했을 것입니다).

하나의 DVCS가 다른 DVCS보다 언어에 더 적합하다고 말할 수는 없으므로 그 중에서 선택해서는 안됩니다. 그러나 실제로 사람들은 커뮤니티의 일부로 가장 많이 노출되는 DVCS를 기반으로 (부분적으로)를 선택합니다.

(아니요, 위의 소유권 주장을 뒷받침 할 사용 통계가 없습니다. 모두 본인의 주관성을 기반으로합니다.)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.