면책 조항 : 나는 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 bisect
Mercurial의 명령 (이전의 이등분 확장 )은 git bisect
Git의 명령에서 영감을 얻은 반면 아이디어는 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은 일치하는 브랜치를 푸시합니다 . 즉, 원격 리포지토리에 해당 항목이 이미있는 로컬 브랜치 만 푸시합니다. --all
git-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 woodyatt 와 Steve 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..B
A가 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-serve
Mercurial 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