우리는 현재 비교적 큰 코드베이스에서 서브 버전을 사용하고 있습니다. 각 릴리스에는 자체 분기가 있으며 트렁크에 대해 수정 사항이 수행되고 다음을 사용하여 릴리스 분기로 마이그레이션됩니다.svnmerge.py
나는 더 나은 소스 컨트롤로 옮겨 갈 시간이 왔다고 생각하며 머큐리얼과 잠시 동안 놀아 왔습니다.
Mercurial을 사용하여 이러한 릴리스 구조를 관리하는 학교는 두 곳인 것 같습니다. 각 릴리스는 자체 저장소를 가지며 릴리스 분기에 대해 수정 사항이 작성되고 기본 분기 (및 기타 최신 릴리스 분기)로 푸시되거나 단일 저장소 (또는 여러 개의 일치 사본) 내에서 이름이 지정된 분기를 사용합니다.
두 경우 모두 릴리스 브랜치에 포함시키기 위해 이식과 같은 것을 체리 픽 변경에 사용하는 것 같습니다.
나는 당신에게 묻습니다. 각 접근법의 상대적인 장점은 무엇입니까?
답변
가장 큰 차이점은 분기 이름이 기록에 기록되는 방식입니다. 명명 된 분기를 사용하면 분기 이름이 각 변경 집합에 포함 되므로 이력의 불변 부분이됩니다. 복제본을 사용하면 특정 변경 세트의 출처에 대한 영구적 인 기록 이 없습니다 .
즉, 클론은 분기 이름을 기록하지 않으려는 빠른 실험에 적합하며 명명 된 분기는 장기 분기 ( “1.x”, “2.x”및 유사)에 적합합니다.
또한 단일 저장소는 Mercurial에서 여러 개의 가벼운 분기를 쉽게 수용 할 수 있습니다. 이러한 저장소 내 브랜치는 책갈피를 지정하여 쉽게 다시 찾을 수 있습니다. 다음과 같이 회사 저장소를 복제했다고 가정 해 보겠습니다.
[a] --- [b]
당신은 멀리 해킹 및 확인 [x]
과 [y]
:
[a] --- [b] --- [x] --- [y]
평균 누군가 풋 동안 [c]
및 [d]
저장소에, 그래서 당신이 당길 때이 같은 역사 그래프를 얻을 :
[x] --- [y] / [a] --- [b] --- [c] --- [d]
단일 저장소에는 두 개의 헤드가 있습니다. 작업 사본에는 항상 소위 작업 사본 상위 변경 세트 인 단일 변경 세트가 반영됩니다. 이것을 확인하십시오 :
% hg parents
그것이보고한다고 가정 해 봅시다 [y]
. 당신은 머리를 볼 수 있습니다
% hg heads
이것은보고 [y]
와 [d]
. 리포지토리를의 깔끔한 체크 아웃으로 업데이트하려면 [d]
간단히 ( [d]
의 개정 번호로 대체 [d]
)하십시오.
% hg update --clean [d]
그러면 해당 hg parents
보고서가 나타납니다 [d]
. 이것은 당신의 다음 커밋이 [d]
부모 가 될 것임을 의미합니다 . 따라서 메인 브랜치에서 발견 한 버그를 수정하고 변경 세트를 만들 수 있습니다 [e]
.
[x] --- [y] / [에이 비 씨 디이]
변경 세트 [e]
만 푸시하려면 다음을 수행해야합니다.
% hg push -r [e]
[e]
변경 세트 해시는 어디에 있습니까 ? 기본적으로 hg push
단순히 저장소를 비교하고 그 표시됩니다 [x]
, [y]
및 [e]
누락,하지만 당신이 공유하고 싶지 않을 수도 [x]
와 [y]
아직.
버그 수정이 영향을 미치는 경우이를 기능 분기와 병합하려고합니다.
% hg update [y]
% hg merge
그러면 저장소 그래프가 다음과 같이 보입니다.
[x] --- [y] ----------- [z] / / [에이 비 씨 디이]
여기서 [z]
의 병합이다 [y]
하고 [e]
. 분기를 버릴 수도 있습니다.
% hg strip [x]
이 이야기의 주요 요점은 이것입니다. 단일 클론은 여러 개발 과정을 쉽게 나타낼 수 있습니다. 이것은 확장명을 사용하지 않고 “평범한 hg”에 항상 적용되었습니다. 하지만 북마크 확장 은 큰 도움이됩니다. 변경 세트에 이름 (책갈피)을 지정할 수 있습니다. 위의 경우 개발 헤드에 북마크를, 업스트림 헤드에 북마크를 추가해야합니다. Mercurial 1.6을 사용하여 책갈피를 밀고 끌 수 있으며 Mercurial 1.8에서 기본 제공 기능이되었습니다.
두 개의 클론을하기로 선택했다면, 개발 클론 한 후이 닮은 것 [x]
과 [y]
:
[a] --- [b] --- [x] --- [y]
업스트림 클론에는 다음이 포함됩니다.
[a] --- [b] --- [c] --- [d]
이제 버그를 확인하고 수정하십시오. hg update
업스트림 클론을 사용할 준비가되었으므로 여기에 있지 않아도됩니다 . 당신은 커밋하고 만듭니다 [e]
:
[a] --- [b] --- [c] --- [d] --- [e]
개발 복제본에 버그 수정을 포함 시키려면 다음을 수행하십시오.
[a] --- [b] --- [x] --- [y] \ [c] --- [d] --- [e]
병합 :
[a] --- [b] --- [x] --- [y] --- [z] \ / [c] --- [d] --- [e]
그래프는 다르게 보일 수 있지만 구조는 동일하지만 최종 결과는 동일합니다. 클론을 사용하면 약간의 정신 부기를해야했습니다.
명명 된 지점은 실제로 선택 사항이므로 여기 그림에 나오지 않았습니다. 머큐리얼 자체는 몇 년 동안 두 개의 클론을 사용하여 개발되었으며 우리는 명명 된 분기를 사용하기로 전환했습니다. 우리는 ‘default’브랜치 외에도 ‘stable’이라는 브랜치를 유지하고 ‘stable’브랜치를 기반으로 릴리스를 만듭니다. 권장 워크 플로우에 대한 설명은 위키 의 표준 분기 페이지를 참조하십시오 .
답변
하나의 레포로 전체 역사를 원한다고 생각합니다. 단기 리포지토리를 생성하는 것은 출시와 같은 주요 이벤트가 아닌 단기 실험을위한 것입니다.
Mercurial의 실망 중 하나는 단기 지점을 만들고, 놀고, 버리고, 쓰레기를 모으는 쉬운 방법이 없다는 것입니다. 지점은 영원합니다. 나는 역사를 포기하고 싶지 않은 것에 대해 공감하지만, 매우 저렴한 일회용 브랜치는 git
내가 실제로보고 싶은 기능이다 hg
.
답변
둘 다해야 합니다 .
@Norman의 대답으로 시작하십시오. 릴리스 당 하나의 지사를 가진 하나의 저장소를 사용하십시오.
그런 다음 구축 및 테스트를 위해 릴리스 지점 당 하나의 복제본을 만듭니다.
하나의 주요 참고 사항은 여러 저장소를 사용하더라도 transplant
1) 해시가 변경되고 2) 변경 세트 사이에 충돌하는 변경이있을 때 감지하기 어려운 버그가 발생할 수 있으므로 변경 세트를 이동 하는 데 사용하지 않아야한다는 것입니다 이식과 목표 지점. 대신 일반적인 병합을 수행하려고합니다 (프리 병합없이 : 항상 시각적으로 병합을 검사하십시오).
그래프는 다르게 보일 수 있지만 구조는 동일하지만 최종 결과는 동일합니다.
더 자세하게는, 여러 저장소를 사용하는 경우 “트렁크”저장소 (또는 기본, 기본, 개발 등)는 모든 저장소의 모든 변경 세트를 포함 합니다. 각 릴리스 / 분기 저장소는 단순히 트렁크에서 하나의 브랜치이며, 이전 릴리스를 남겨두고 싶을 때까지 모두 한쪽으로 또는 다른 쪽 트렁크로 다시 병합됩니다. 따라서 명명 된 브랜치 체계에서 해당 기본 리포지토리와 단일 리포지토리의 유일한 차이점은 단순히 브랜치의 이름이 지정되는지 여부입니다.
내가 왜 “하나의 레포로 시작”이라고 말했는지 분명하게 알 수 있습니다. 이 단일 저장소는 모든 릴리스에서 변경 세트 를 찾아야하는 유일한 장소 입니다. 버전 지정을 위해 릴리스 분기에서 변경 세트에 추가로 태그를 지정할 수 있습니다. 개념적으로 명확하고 단순하며 시스템 관리자가 항상 사용 가능하고 항상 복구 할 수 있어야하는 유일한 시스템이기 때문에 더 간단합니다.
그러나 분기 / 릴리스 당 하나의 복제본을 유지 관리해야하며 빌드 및 테스트해야합니다. 당신이 할 수있는 것처럼 사소한 hg clone <main repo>#<branch> <branch repo>
일이며 hg pull
, 지점 리포지토리에서는 해당 지점의 새로운 변경 세트 (병합 된 이전 지점의 상위 변경 세트) 만 가져옵니다.
이 설정은 단일 풀러 의 Linux 커널 커밋 모델에 가장 적합합니다 ( Lith Linus처럼 행동하는 것이 좋지 않습니다. 우리 회사에서는 역할 통합 자라고 부릅니다 ). 끌어 당기는 사람이 들어와야합니다. 지점 저장소의 유지 관리는 순전히 릴리스 관리를위한 것이며 완전히 자동화 될 수 있습니다. 개발자는 지점 리포지토리로 끌어 당길 필요가 없습니다.
다음은이 설정에 대한 @mg의 예입니다. 출발점:
[a] - [b]
알파 릴리스에 도달하면 릴리스 버전의 이름 지정된 분기 (예 : “1.0”)를 작성하십시오. 그것에 대한 버그 수정을 커밋 :
[a] - [b] ------------------ [m1]
\ /
(1.0) - [x] - [y]
(1.0)
커밋 할 때까지 명명 된 분기가 없으므로 실제 변경 세트가 아닙니다. (태그 추가와 같은 사소한 커밋을 수행하여 이름이 지정된 분기를 올바르게 만들 수 있습니다.)
병합 [m1]
은이 설정의 핵심입니다. 헤드 수가 무제한 인 개발자 리포지토리와 달리 기본 리포지토리에 여러 헤드를두기를 원하지 않습니다 (이전에 언급 한 오래된 데드 릴리스 지점 제외). 따라서 릴리스 분기에 새 변경 세트가있을 때마다 즉시 기본 분기 (또는 이후 릴리스 분기)로 다시 변경해야합니다. 이렇게하면 한 릴리스의 모든 버그 수정이 모든 이후 릴리스에도 포함됩니다.
한편 기본 브랜치의 개발은 다음 릴리스로 계속 진행됩니다.
------- [c] - [d]
/
[a] - [b] ------------------ [m1]
\ /
(1.0) - [x] - [y]
평소와 같이 기본 분기에서 두 헤드를 병합해야합니다.
------- [c] - [d] -------
/ \
[a] - [b] ------------------ [m1] - [m2]
\ /
(1.0) - [x] - [y]
그리고 이것은 1.0 브랜치 클론입니다 :
[a] - [b] - (1.0) - [x] - [y]
이제 다음 릴리스 브랜치를 추가하는 연습입니다. 그것이 2.0이라면 분명히 기본값에서 분기됩니다. 1.1 인 경우 1.0 또는 기본값을 분기하도록 선택할 수 있습니다. 어쨌든 1.0의 새 변경 세트는 먼저 다음 분기로 병합 된 다음 기본값으로 병합해야합니다. 충돌이없는 경우 자동으로 수행 될 수 있으며 빈 병합 만 발생합니다.
나는 그 예가 나의 이전의 요점들을 분명히하기를 바란다. 요약하면이 방법의 장점은 다음과 같습니다.
- 완전한 변경 세트 및 버전 기록이 포함 된 단일 권한 저장소
- 명확하고 간단한 릴리스 관리.
- 개발자 및 통합자를위한 명확하고 단순화 된 워크 플로우.
- 워크 플로우 반복 (코드 검토) 및 자동화 (자동 빈 병합)를 용이하게합니다.
UPDATE hg 자체 가이 작업을 수행합니다 . 기본 리포지토리 에는 기본 및 안정적인 분기가 포함되어 있으며 안정적인 리포지토리 는 안정적인 분기 복제본입니다. 안정적인 브랜치를 따르는 버전 태그는 릴리스 관리 목적으로 충분하기 때문에 버전 브랜치를 사용하지 않습니다.
답변
내가 아는 한 가장 큰 차이점은 이미 언급 한 것입니다. branched라는 이름은 단일 저장소에 있습니다. 명명 된 지점은 한 곳에서 모든 것을 편리하게 사용할 수 있습니다. 별도의 저장소는 더 작고 이동하기 쉽습니다. 여기에 두 개의 생각 학교가있는 이유는 확실한 승자가 없기 때문입니다. 어느 쪽의 주장이 당신에게 가장 합리적일까요? 아마도 당신의 환경이 당신과 가장 비슷할 것이므로 아마도 당신이 함께 가야 할 것입니다.
답변
현재 상황 (예 : 피처 / 재 설계의 크기)에 따라 실제적인 결정이라고 생각합니다. 나는 아직 커미터가 아닌 역할을 가진 기고자들이 무시할 수없는 기술적 오버 헤드로 적성을 입증함으로써 개발자 팀에 합류하는 데 포크가 정말 좋다고 생각한다.
답변
버전에 이름이 지정된 분기를 사용하지 않는 것이 좋습니다. 그것이 실제로 태그의 목적입니다. 지명 된 지점은 stable
지점 과 같이 오래 지속되는 전환을 의미합니다 .
그렇다면 왜 태그를 사용하지 않습니까? 기본 예 :
- 단일 지점에서 개발
- 릴리스가 작성 될 때마다 그에 따라 태그를 지정합니다
- 거기서부터 개발은 계속됩니다
- 특정 릴리스에서 수정해야 할 버그가 있거나 태그로 업데이트하고 변경 한 후 커밋하기 만하면됩니다.
그러면 default
분기 에 이름없는 새 헤드가 생성됩니다 . 익명의 브랜치는 hg에서 완벽하게 좋습니다. 그러면 언제든지 버그 수정 커밋을 기본 개발 트랙으로 병합 할 수 있습니다. 명명 된 지점이 필요하지 않습니다.