왜 git commit에 그들이 만든 브랜치의 이름이 포함되지 않습니까?


20

피처 브랜치를 사용하는 팀에서 git으로 작업 할 때 종종 히스토리의 브랜치 구조를 이해하기가 어렵습니다.

예:

기능 분기 기능 / make-coffee 가 있고 기능 분기 와 병렬로 마스터 에서 버그 수정이 계속 되었다고 가정 해 봅시다 .

역사는 다음과 같습니다.

*     merge feature/make-coffee
|\
| *   small bugfix
| |
* |    fix bug #1234
| |
| *    add milk and sugar
| |
* |    improve comments
| |
* |    fix bug #9434
| |
| *    make coffe (without milk or sugar)
| |
* |    improve comments
|/
*

문제

언뜻보기에, 어느 쪽이 기능 분기인지 알기가 어렵습니다. 나는 어느 쪽이 어떤 것인지 생각하기 위해 일반적으로 양쪽에서 여러 의견을 찾아야합니다. 여러 피쳐 브랜치가 병렬로 (특히 밀접하게 관련된 피쳐를 위해) 또는 피쳐 브랜치와 마스터 사이에 양방향으로 병합 된 경우 더 복잡해집니다.

반대로, Subversion에서는 브랜치 이름이 히스토리의 일부이기 때문에 훨씬 쉽습니다. 따라서 커밋이 원래 "feature / make-coffee"에 이루어 졌다는 것을 알 수 있습니다.

Git 커밋을 만들 때 (작성자, 날짜 등과 함께) 커밋 메타 데이터에 현재 브랜치 이름을 포함시켜 이것을 쉽게 만들 있습니다. 그러나 git은 이것을하지 않습니다.

이것이 수행되지 않는 근본적인 이유가 있습니까? 아니면 아무도 그 기능을 원하지 않았다는 것입니까? 후자의 경우, 이름을 보지 않고 역사적 지점의 목적을 이해하는 다른 방법이 있습니까?


1
관련 질문 : 커밋 지점에서 나온 것을 찾기 . 이것은 git이 명시 적으로 기록하지 않는다는 사실에도 불구 하고이 정보를 찾는 방법에 관한 것입니다.
sleske

1
자기주의 사항 : 흥미롭게도 Mercurial의 커밋 에는 분기 이름 포함됩니다. 따라서 Mercurial 개발자는 git 개발자와 다른 디자인 결정을 한 것으로 보입니다. 자세한 내용은 felipec.wordpress.com/2012/05/26/… 를 참조하십시오.
sleske

답변:


14

분기 이름은 하나의 저장소 내에서만 의미가 있기 때문일 수 있습니다. 내가 make-coffee팀원이고 게이트 키퍼를 통해 모든 변경 사항을 제출하면 내 master지점이 게이트 키퍼 지점으로 끌려가 중앙 지점 으로 병합 되는 지점으로 이동 하기 전에 make-coffee-gui자신의 make-coffee-backend지점과 make-coffee병합됩니다 master.

하나의 리포지토리 내에서도 워크 플로가 발전함에 따라 지사 이름이 변경 될 수 있습니다. 예를 들어 master나중에로 변경 될 수 있습니다 development.

CodeGnome이 암시 한 것처럼 git은 데이터가 필요하지 않은 경우 데이터를 굽지 않는 강력한 디자인 철학을 가지고 있습니다. 사용자가에서 옵션을 사용할 것으로 예상되는 git loggit diff그들의 사후 원하는대로 데이터를 출력합니다. 나에게 더 적합한 형식을 찾을 때까지 시험해 보는 것이 좋습니다. git log --first-parent예를 들어, 병합중인 브랜치의 커밋은 표시되지 않습니다.


2
첫 번째 부모는 대개 잘못된 것입니다. 일반적으로 하나는 마스터를 자신이 작업하는 대상으로 끌어 당기고 작업을 첫 번째 부모로 만들고 두 번째를 마스터하기 때문입니다.
Jan Hudec

1
@ JanHudec : 실제로 이것은 :-)에 달려 있습니다. 일을하는 사람이 합병하면 예. 나중에 검토 후 병합이 발생하면 검토자가 마스터를 체크 아웃하고 기능 분기를 마스터에 병합하고 테스트 한 후 푸시 할 가능성이 높습니다.
sleske

5

로 지점 기록 추적 --no-ff

Git에서 커밋에는 조상이 있지만 "브랜치"는 실제로 일부 개발 라인의 현재 헤드입니다. 즉, 커밋은 특정 시점에서 작업 트리의 스냅 샷이며 한 번에 여러 개의 브랜치에 속할 수 있습니다. 이것은 다른 DVCS와 비교할 때 Git 브랜칭을 매우 가볍게 만드는 것의 일부입니다.

Git 커밋은 Git 히스토리에 필요하지 않기 때문에 지점 정보를 전달하지 않습니다. 그러나 빨리 감기되지 않는 병합은 확실히 어떤 지점이 병합되었는지에 대한 추가 정보를 전달할 수 있습니다. 항상 --no-ff플래그를 병합에 전달하여 이력에이 정보가 포함되도록 할 수 있습니다 . git-merge (1)는 다음과 같이 말합니다.

   --no-ff
       Create a merge commit even when the merge resolves as a
       fast-forward. This is the default behaviour when merging an
       annotated (and possibly signed) tag.

이렇게하면 일반적으로와 비슷한 병합 메시지가 생성 Merge branch 'foo'되므로 일반적으로 다음과 유사한 줄로 "조상 가지"에 대한 정보를 찾을 수 있습니다.

$ git log --regexp-ignore-case --grep 'merge branch'

고맙지 만, (대부분) 내 질문에 대답하지 않습니다. 원래 브랜치를 찾기 위해 다른 방법이 있는지 묻지는 않지만 정보가 일반 메타 데이터로 포함되지 않는 이유는 디자인 문제에 더 가깝습니다.
sleske

1
@ sleske 내 대답이 반응 형이라고 생각합니다. Git 기록이 필요하지 않기 때문에 Git이 추적하지 않습니다. 나는 그것이 그보다 더 근본적이라고 생각하지 않습니다. 구체적인 내용은 소스를 살펴 봐야하지만, 현재 분기의 끝에서 히스토리가 거꾸로 계산됩니다. 브랜치를 일류 객체로 취급하는 다른 DVCS와 비교하고 디자인 철학이 더 좋은지 확인할 수 있습니다. YMMV.
CodeGnome

1
마지막은이어야합니다 git log --merges.
Dan

3

가장 간단한 대답은 가지 이름이 임시라는 것입니다. 예를 들어 지점 이름을 바꾸려면 git branch -m <oldname> <newname>어떻게해야합니까 ( )? 해당 지점에 대한 모든 커밋은 어떻게됩니까? 아니면 두 사람이 다른 지역 리포지토리에 동일한 이름을 가진 지점을 가지고 있다면 어떨까요?

git에서 의미가있는 유일한 것은 커밋 자체의 체크섬입니다. 이것이 기본 추적 단위입니다.

정보가 있습니다, 당신은 단지 그것을 요구하지 않고, 정확히 거기에 없습니다 .

힘내는 각 지점의 헤드 체크섬을에 저장합니다 .git/refs/heads. 예를 들면 다음과 같습니다.

... /. git / refs / heads $ ls 테스트 
-rw-rw-r-- 1 michealt michealt 41 9 월 30 일 11:50 테스트
... /. git / refs / heads $ 고양이 테스트 
87111111111111111111111111111111111111d4

(그렇습니다. 특별한 것은 아니지만 내 자식 체크섬을 움켜 쥐고 있지만 실수로 누수가 없어야 할 순간을보고있는 개인 저장소입니다.)

이것을보고 부모 또는 부모 부모 또는 부모 부모로 이것을 가진 모든 커밋을 추적하면 주어진 커밋이 어떤 브랜치에 있는지 알 수 있습니다. 렌더링 할 큰 그래프 일뿐입니다.

커밋이 커밋 자체에있는 분기의 이름 (위에서 언급 한대로 변경 가능)을 저장하면 커밋에 도움이되지 않는 추가 오버 헤드가 발생합니다. 커밋의 부모와 그 이익을 저장하십시오.

적절한 플래그와 함께 git log 명령을 실행하면 분기를 볼 수 있습니다.

git log --branches --source --pretty = oneline --graph
자식 로그 --all --source --pretty = oneline --graph

원하는 것을 고르는 방법은 여러 가지가 있습니다- 자식 로그 문서를 살펴보십시오 -다음 -all섹션과 몇 가지 옵션을 참조하십시오.

8787111111111111111111111111111111111111d4 테스트 분기 'test1'을 테스트에 병합
| \  
| 42111111111111111111111111111111111111e8 test1 업데이트 : 항목 추가
* | dd11111111111111111111111111111111111111159 테스트 분기 'test3'을 테스트에 병합
| \ \  

그 'test', 'test1'및 'test2'는 이들이 약속 한 지점입니다.

git log documentation은 방대 하며 원하는 거의 모든 것을 얻을 수 있습니다.


3

왜 git commits에 그들이 만든 브랜치의 이름이 포함되어 있지 않습니까?

단지 디자인 결정입니다. 해당 정보가 필요한 경우, 단일 저장소에서이를 적용하기 위해 ready-commit-msg 또는 commit-msg 후크를 추가 할 수 있습니다.

BitKeeper 재해 후 Linus Torvalds는 Linux 커널 개발 프로세스와 일치하도록 git을 개발했습니다. 패치가 수락 될 때까지 패치를 여러 번 수정하고, 편집하고, 다듬고 (메일을 통해), 사인 오프 (= 커밋 편집), 체리 피킹, 중위 지점 방황, 종종 더 많은 편집, 체리 그들이 Linus에 의해 상류로 합병 될 때까지 -picks 등등.

이러한 워크 플로에는 커밋의 특정 출처가 없을 수 있으며 종종 커밋은 git이 배포됨에 따라 재미있는 분기 이름을 가진 중요하지 않은 개인 임의 저장소의 일부 임시 디버깅 분기에서 만들어집니다.

어쩌면 그 디자인 결정은 우연히 일어 났지만 Linux 커널 개발 프로세스와 정확히 일치합니다.


2

Git에서 "커피 만들기"와 같은 커밋 은 기능 분기가 병합 될 때 분기의 일부로 간주되기 때문입니다 . 이를 확인하는 명령도 있습니다.

% git branch --contains @
  feature/make-coffee
  master

또한 지점은 저렴하고 지역적이며 미묘합니다. 서버에서 쉽게 추가, 제거, 이름 변경, 푸시 및 삭제할 수 있습니다.

Git은 모든 것을 할 수 있다는 원칙에 따라 원격 서버에서 브랜치를 쉽게 제거하고 히스토리를 쉽게 다시 작성할 수 있습니다.

내가 '마스터'지점에 있었고 '커피 만들기'와 '우유와 설탕 추가'라는 두 가지 커밋을 한 다음 새 분기를 사용하기로 결정했기 때문에 '마스터'를 다시 '원산지'로 재설정했습니다. /석사'. 문제는 아닙니다. 모든 역사는 여전히 깨끗합니다. '커피 만들기'와 '우유와 설탕 추가'는 마스터의 일부가 아니며 피처 / 메이커 전용입니다.

머큐리얼은 정반대입니다. 물건을 바꾸고 싶지 않습니다. 브랜치는 영구적이며 재기록 기록이 찌그러져 서 서버에서 브랜치를 삭제할 수는 없습니다.

간단히 말해서, Git은 모든 것을 할 수있게 해주 며, Mercurial은 일을 쉽게하기를 원합니다 (그리고 원하는 것을하기가 정말로 어렵게 만듭니다).

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