깔끔한 선형 자식 히스토리

많은 자식 기반 프로젝트에서 간과되는 것 중 하나는 선형 커밋 히스토리의 가치입니다. 사실,많은 도구 및 지침은 선형 역사를 목표로 자식 워크 플로우를 억제. 깔끔한 역사는 매우 가치 있고 선형 역사를 보장하는 직선적 인 워크 플로우가 있기 때문에 나는이 슬픈 것을 발견합니다.

선형 대 비선형 역사

선형 역사는 단순히 모든 커밋이 서로 뒤 따르는 힘내 역사입니다. 즉. 독립 커밋 기록을 가진 분기의 병합을 찾을 수 없습니다.

1 - 비선형 대 선형

왜 선형 역사를 원합니까?

깔끔하고 논리적 인 것 외에도 선형 역사는 다음과 같은 경우에 유용합니다.:

  • 역사를 보고. 비선형 역사는 따라하기가 매우 어려울 수 있습니다–때로는 역사가 이해할 수없는 지점까지.
  • 역 추적 변경. 예를 들어:”버그 수정 전 또는 후에 기능이 도입 되었습니까?”.
  • 버그 추적. 힘내는 버그 나 회귀를 도입 한 커밋을 빠르게 찾는 데 사용할 수있는 힘내 이등분이라는 매우 깔끔한 기능을 가지고 있습니다. 그러나,비선형 역사,힘내 이등분 하드 또는 사용 불가능하게된다.
  • 변경 되돌리기. 회귀를 일으킨 커밋을 찾았거나 특정 릴리스에서 실행되지 않아야 하는 기능을 제거하려고 한다고 가정해 보겠습니다. 운이 좋으면(코드가 너무 많이 변경되지 않은 경우)자식 되돌리기를 사용하여 원하지 않는 커밋을 간단히 되돌릴 수 있습니다. 그러나 교차 분기 병합이 많은 비선형 히스토리가있는 경우 훨씬 더 어려울 것입니다.

당신이 자식을 사용하는 방법에 따라 선형 기록이 매우 가치있는 또 다른 소수의 상황이 있습니다.

요점은:당신의 역사가 덜 선형적 일수록 가치가 떨어집니다.

비선형 히스토리의 원인

간단히 말해서 모든 병합 커밋은 비선형 히스토리의 잠재적 소스입니다. 그러나 다른 종류의 병합 커밋이 있습니다.

토픽 분기에서 마스터로 병합

토픽 분기를 완료하여 마스터에 통합하려는 경우 토픽 분기를 마스터로 병합하는 일반적인 방법이 있습니다. 아마도 선을 따라 뭔가:

git checkout mastergit pullgit merge --no-ff my-topic-branch

이 방법을 사용하는 좋은 속성은 어떤 커밋이 주제 분기의 일부인지에 대한 정보를 보존한다는 것입니다.

마스터로 병합하는 문제는 주제 분기가 마스터의 최신 팁 대신 이전 마스터를 기반으로 할 때 발생합니다. 이 경우 필연적으로 비선형 역사를 얻을 수 있습니다.

2 - 병합 이전 분기

이것이 일반적인 문제가 될지 여부는 자식 저장소가 얼마나 활성화되어 있는지,얼마나 많은 개발자가 동시에 작업하고 있는지 등에 달려 있습니다.

마스터에서 주제 분기로 병합

최신 마스터와 일치하도록 분기를 업데이트하려는 경우가 있습니다(예: 당신이 당신의 주제 분기로 얻고 싶은 마스터에 몇 가지 새로운 기능이 있습니다,또는 당신은)충돌이 있기 때문에 당신이 마스터로 주제 분기를 병합 할 수없는 것을 발견.

일부 사람들이 권장하는 일반적인 방법은 마스터 팁을 주제 분기로 병합하는 것입니다. 이 비선형 역사의 주요 소스입니다!

3 - 마스터에서 주제로의 병합

솔루션:리베이스!

힘내 리베이스는 선형 기록을 원하는 경우 사용해야하는 매우 유용한 기능입니다. 일부는 어색한 리베이스의 개념을 찾을 수 있지만 실제로는 매우 간단합니다: 새 커밋 위에 분기의 변경 사항(커밋)을 재생합니다.

예를 들어,자식 리베이스를 사용하여 주제 분기의 루트를 이전 마스터에서 최신 마스터의 팁으로 변경할 수 있습니다. 주제 분기가 체크 아웃되었다고 가정하면 다음을 수행 할 수 있습니다:

git fetch origingit rebase origin/master

4 - 리베이싱

해당 병합 작업은 마스터 팁을 이전 그림에 표시된 대로 토픽 분기로 병합하는 것입니다. 리베이스나 병합을 수행하든 관계없이 토픽 분기에 있는 파일의 결과 내용은 동일합니다. 그러나 역사는 다릅니다(선형 대 비선형!).

이 모든 것이 잘 들립니다. 그러나 리베이스에 대해 알아야 할 몇 가지 주의 사항이 있습니다.

주의 사항 1:리베이스는 새 커밋을 만듭니다

브랜치를 리베이스하면 실제로 새 커밋이 생성됩니다. 새로운 커밋은 이전 커밋과 다른 샤를 가질 것입니다. 이것은 일반적으로 문제가되지 않지만 로컬 저장소 외부에 존재하는 브랜치(예:브랜치가 이미 원점에 존재하는 경우)를 리베이스하면 문제가 발생합니다.

리베이스된 분기를 이미 동일한 분기가 포함되어 있지만 이전 기록이 있는 원격 리포지토리로 푸시하려면:

  1. 힘내는 그렇지 않으면 기존 분기에 새로운 기록을 푸시 할 수 없기 때문에 분기(예:git push --force-with-lease)를 강제로 밀어야합니다. 이 기능은 지정된 원격 분기의 기록을 새 기록으로 효과적으로 대체합니다.
  2. 주어진 브랜치의 로컬 버전이 더 이상 리모컨의 브랜치와 일치하지 않아 모든 종류의 문제가 발생할 수 있기 때문에 다른 사람을 매우 불행하게 만들 수 있습니다.

일반적으로 리모컨에서 분기 기록을 덮어쓰지 마십시오.

원격에서 다른 사용자와 공유되는 분기를 리베이스해야 하는 경우 간단한 워크플로는 원래 분기를 리베이스하는 대신 리베이스하는 새 분기를 만드는 것입니다. my-topic-branch이 체크 아웃되었다고 가정하면 다음을 수행 할 수 있습니다:

git checkout -b my-topic-branch-2git fetch origingit rebase origin/mastergit push -u origin my-topic-branch-2

…그런 다음my-topic-branch에서 작업하는 사람들에게my-topic-branch-2에서 계속 작업하도록 지시하십시오. 그런 다음 이전 분기는 효과적으로 사용되지 않으며 마스터로 다시 병합해서는 안됩니다.

주의 2:리베이스의 충돌 해결은 병합

보다 더 많은 작업이 될 수 있습니다 병합 작업에서 충돌이 발생하면 해당 병합 커밋의 일부로 모든 충돌을 해결합니다.

그러나 리베이스 작업에서는 리베이스 한 분기의 모든 커밋에 대해 충돌이 발생할 수 있습니다.

실제로 커밋에서 충돌이 발생하면 주제 분기의 커밋이 관련되는 경향이 있기 때문에(예:코드의 동일한 부분 수정)브랜치의 후속 커밋에서 관련(매우 유사한)충돌이 발생할 수 있습니다.

충돌을 최소화하는 가장 좋은 방법은 마스터에서 일어나는 일을 추적하고 리베이스없이 토픽 분기가 너무 오래 실행되지 않도록하는 것입니다. 앞 모든 이제 다음 작은 충돌을 다루는 끝에 하나의 큰 행복 충돌 혼란에 그들 모두를 처리 하는 것 보다 쉽습니다.

깃허브 사용자에 대한 몇 가지 경고

깃허브는 많은 것들에 아주 좋습니다. 그것은 자식 호스팅에 대한 환상적이다,그것은 코드 브라우징과 멋진 웹 인터페이스를 가지고,좋은 마크 다운 기능,요지,기타.

반면 풀 요청에는 선형 자식 기록을 능동적으로 방해하는 몇 가지 기능이 있습니다. 이 응용 프로그램은 당신에게 아름다운 욕실 꾸미기의 갤러리를 보여줍니다.:

“끌어 오기 요청 병합”을 사용하면 비선형 병합이 마스터

에 병합 될 수 있습니다. 특히”이 분기는 기본 분기와 함께 최신 상태입니다. 병합은 자동으로 수행 할 수 있습니다.”

깃허브 병합 풀 요청

깃허브가 실제로 여기서 말하는 것은 브랜치가 충돌없이 마스터에 병합 될 수 있다는 것입니다. 끌어오기 요청 분기가 최신 마스터를 기반으로 하는지 여부를 확인하지 않습니다.

즉,선형 기록을 원한다면 끌어오기 요청 분기가 최신 마스터 위에 리베이스되어 있는지 확인해야 합니다. 내가 말할 수있는 한,그러한 정보는 깃허브 웹 인터페이스를 통해 사용할 수 없습니다(당신이”보호 된 지점”을 사용하지 않는 한–아래 참조),그래서 당신은 당신의 로컬 자식 클라이언트에서 그것을 할 필요가 있습니다.

끌어오기 요청이 제대로 리베이스되었더라도,깃허브 웹 인터페이스의 병합 작업이 원자성이 될 것이라는 보장은 없다(즉, 병합 작업이 진행되기 전에 누군가가 변경 사항을 마스터에 푸시 할 수 있습니다.

따라서 분기가 최신 마스터 위에 올바르게 리베이스되었는지 확인하는 유일한 방법은 병합 작업을 로컬에서 수행하고 결과 마스터를 수동으로 푸시하는 것입니다. 선을 따라 뭔가:

git checkout mastergit pullgit checkout my-pullrequest-branchgit rebase mastergit checkout mastergit merge --no-ff my-pullrequest-branchgit push origin master

당신이 불운이고 누군가가 당신의 끌어 오기 및 푸시 작업 사이에 마스터에 대한 변경 사항을 밀어 관리하는 경우,푸시 작업이 거부됩니다. 그러나 이것은 당신의 작업이 원자 적이라는 것을 보장하기 때문에 좋은 것입니다. 그냥git reset --hard origin/master이 통과 할 때까지 위의 단계를 반복합니다.

참고:코드 검토 및 테스트와 함께 프로젝트 지침을 준수하십시오. 예를 들어 풀 요청의 일부로 자동 테스트(빌드,정적 분석,단위 테스트 등)를 실행하는 경우 마스터 브랜치를 수동으로 업데이트하는 대신 리베이스된 브랜치를 다시 제출해야 합니다.

보호된 분기 기능은 마스터에서 병합을 장려합니다.

그러나…끌어 오기 요청 분기가 최신 마스터를 기반으로하지 않으면”분기 업데이트”라는 친숙한 버튼이 표시되고”이 분기는 기본 분기와 함께 오래되었습니다. 마스터의 최신 변경 사항을 이 분기로 병합합니다.”

github-update-branch

이 시점에서 가장 좋은 방법은 분기를 로컬로 리베이스하고 끌어 오기 요청에 강제로 푸시하는 것입니다. my-pullrequest-branch이 체크 아웃되었다고 가정하면 다음을 수행하십시오:

git fetch origingit rebase origin/mastergit push -f

안타깝게도 깃허브 풀 요청은 강제 푸시와 잘 작동하지 않으므로 일부 코드 검토 정보가 과정에서 손실될 수 있습니다. 허용되지 않는 경우 새 끌어 오기 요청을 만드는 것이 좋습니다(즉,리베이스된 분기를 새 원격 분기로 푸시하고 새 분기에서 끌어 오기 요청을 만드는 것).

결론

선형 역사에 관심이 있다면:

  • 마스터에 병합하기 전에 최신 마스터 위에 주제 분기를 리베이스.
  • 마스터를 주제 분기에 병합하지 마십시오. 대신 리베이스.
  • 주제 분기를 다른 사람과 공유 할 때 리베이스해야 할 때마다 새 분기를 만듭니다(my-topic-branch-2, my-topic-branch-3, …).
    • “병합”단추는 홍보 분기가 최신 마스터를 기반으로 함을 보장하지 않습니다. 필요한 경우 수동으로 리베이스.
    • 상태 확인과 함께 보호 된 분기를 사용하는 경우”분기 업데이트”버튼을 누르지 마십시오. 대신 수동으로 리베이스.

선형 자식 역사에 대해 너무 신경 쓰지 않는다면-행복한 병합!

깃허브에 대한 위시리스트

깃허브에서 일하는 훌륭한 사람들에게:풀 리퀘스트에서 리베이스 워크플로에 대한 지원을 추가하십시오(옵트인 리포지토리 옵션일 수 있음).

  • 분기(이 상태 검사의 사용을 필요로하지 않아야)최신 마스터를 기반으로하지 않는 경우 풀 요청에서 병합 버튼/작업을 비활성화 할 수있는 가능성을 추가합니다.
  • “최신 마스터에 리베이스”버튼을 추가하십시오. 많은 경우에 이것은 웹 인터페이스를 통해 쉽게 할 수있는 충돌없는 작업이어야합니다.
  • 리베이스/강제 푸시 후 풀 요청 기록(커밋,주석,…)을 유지합니다.

Leave a Reply