Git 워크 플로우 및 리베이스 및 병합 질문


971

다른 개발자와 함께 프로젝트에서 몇 달 동안 Git을 사용하고 있습니다. SVN에 대해 수년간의 경험이 있으므로 관계에 많은 수하물을 가져 오는 것 같습니다.

Git이 분기 및 병합에 탁월하다고 들었습니다. 지금까지는 보지 못했습니다. 물론, 브랜치는 간단하지 않지만 병합하려고하면 모든 것이 지옥에 빠집니다. 이제 SVN에서 익숙해졌지만 한 하위 하위 버전 관리 시스템을 다른 하위 버전으로 교환 한 것 같습니다.

내 파트너는 내 문제는 willy-nilly를 병합하려는 욕구에서 비롯되며 여러 상황에서 병합 대신 rebase를 사용해야한다고 말합니다. 예를 들어, 다음은 그가 정리 한 워크 플로입니다.

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature
git checkout master
git merge my_new_feature

기본적으로 기능 분기를 작성하고 항상 마스터에서 분기로 리베이스하고 분기에서 마스터로 다시 병합하십시오. 분기가 항상 로컬에 유지된다는 점에 유의해야합니다.

여기에 내가 시작한 워크 플로우가 있습니다

clone remote repository
create my_new_feature branch on remote repository
git checkout -b --track my_new_feature origin/my_new_feature
..work, commit, push to origin/my_new_feature
git merge master (to get some changes that my partner added)
..work, commit, push to origin/my_new_feature
git merge master
..finish my_new_feature, push to origin/my_new_feature
git checkout master
git merge my_new_feature
delete remote branch
delete local branch

두 가지 근본적인 차이점이 있습니다 (제 생각에) : 리베이스 대신 항상 병합을 사용하고 기능 지점 (및 기능 지점 커밋)을 원격 저장소로 푸시합니다.

원격 지점에 대한 나의 추론은 내가 일하는 동안 내 작업을 백업하기를 원하기 때문입니다. 우리 저장소는 자동으로 백업되며 문제가 발생하면 복원 할 수 있습니다. 내 랩탑이 아니거나 철저하지 않습니다. 따라서 다른 곳에서는 미러링되지 않은 랩톱의 코드가 싫어요.

rebase 대신 병합에 대한 나의 추론은 병합이 표준으로 보이고 rebase가 고급 기능인 것 같습니다. 내 직감은 내가하려는 일이 고급 설정이 아니기 때문에 rebase가 필요하지 않다는 것입니다. 나는 심지어 Git에 관한 새로운 Pragmatic Programming 책을 꼼꼼히 살펴 보았고 그것들은 광범위하게 병합되고 거의 rebase에 대해서는 언급하지 않았다.

어쨌든, 나는 최근 지점에서 워크 플로우를 따르고 있었고 마스터로 다시 병합하려고 시도했을 때 모두 지옥에 갔다. 중요하지 않은 것들과 많은 충돌이있었습니다. 갈등은 나에게 이해가되지 않았다. 로컬 마스터가 모든 충돌을 해결했지만 원격 마스터는 여전히 행복하지 않았기 때문에 모든 것을 정리하는 데 하루가 걸렸으며 결국 원격 마스터에게 강제로 밀렸습니다.

이와 같은 "올바른"워크 플로우는 무엇입니까? 힘내는 분기와 병합을 매우 쉽게 만들어야하며, 나는 그것을 보지 못합니다.

2011-04-15 업데이트

이것은 매우 인기있는 질문 인 것 같습니다. 처음 질문 한 이후 2 년의 경험으로 업데이트 할 것이라고 생각했습니다.

적어도 우리의 경우에는 원래 워크 플로우가 올바른 것으로 판명되었습니다. 다시 말해, 이것이 우리가하는 일이며 작동합니다.

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge my_new_feature

실제로 는 원시 병합 대신 스쿼시 병합 을 수행하는 경향이 있으므로 워크 플로는 약간 다릅니다 . ( 참고 : 이것은 논란의 여지가 있습니다. 아래를 참조하십시오. )이를 통해 전체 기능 브랜치를 마스터의 단일 커밋으로 바꿀 수 있습니다. 그런 다음 기능 분기를 삭제합니다. 이를 통해 지점에 약간 지저분하더라도 마스터에 대한 커밋을 논리적으로 구성 할 수 있습니다. 이것이 우리가하는 일입니다.

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge --squash my_new_feature
git commit -m "added my_new_feature"
git branch -D my_new_feature

스쿼시 병합 논쟁 -여러 의견자가 지적했듯이 스쿼시 병합은 기능 분기의 모든 기록을 버립니다. 이름에서 알 수 있듯이 모든 커밋을 단일 커밋으로 축소합니다. 작은 기능의 경우 단일 패키지로 압축되기 때문에 이치에 맞습니다. 더 큰 기능의 경우, 특히 개인 커밋이 이미 원자 적 인 경우 특히 좋은 생각이 아닙니다. 그것은 실제로 개인 취향에 달려 있습니다.

Github 및 Bitbucket (기타?) 풀 요청 -병합 /베이스가 풀 요청과 어떤 관계가 있는지 궁금한 경우 마스터로 다시 병합 할 준비가 될 때까지 위의 모든 단계를 따르는 것이 좋습니다. git과 수동으로 병합하는 대신 PR 만 수락하면됩니다. 이것은 최소한 기본적으로 스쿼시 병합을 수행하지 않지만, 스쿼시가 아닌 빨리 감기는 풀 요청 커뮤니티에서 허용되는 병합 규칙입니다 (내가 아는 한). 구체적으로 다음과 같이 작동합니다.

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git push # May need to force push
...submit PR, wait for a review, make any changes requested for the PR
git rebase master
git push # Will probably need to force push (-f), due to previous rebases from master
...accept the PR, most likely also deleting the feature branch in the process
git checkout master
git branch -d my_new_feature
git remote prune origin

나는 Git을 좋아하고 SVN으로 돌아가고 싶지 않습니다. 어려움을 겪고 있다면 터널에 붙어 터널 끝에서 빛을 볼 수 있습니다.


31
불행히도 새로운 Pragmstic Programming 책은 SVN을 계속 생각하면서 Git을 사용하여 작성되었습니다.이 경우 잘못되었습니다. Git에서 rebase는 가능한 한 간단하게 유지합니다. 귀하의 경험에 따르면 Git이 작동하지 않는 것이 아니라 Git에서 워크 플로가 작동하지 않을 수 있습니다.
Paul

18
이 경우 스쿼시 병합은 병합되지 않는 것에 대한 정보를 저장하지 않기 때문에 권장하지 않습니다 (svn과 마찬가지로 병합 정보는 여기에 없음).
Marius K

7
바닥에있는 메모를 좋아합니다 .Git과 비슷한 투쟁 경험이 있었지만 지금은 그것을 사용하지 않는다고 상상하기가 어렵습니다. 최종 설명에 감사드립니다. rebase이해에 많은 도움이되었습니다
Jon Phenow

6
기능을 완료 한 후 new_feature를 마스터에 병합하기 전에 마지막으로 리베이스하지 않아야합니까?
softarn

17
워크 플로는 삭제 된 분기에서 모든 커밋 기록을 잃습니다. (
Max Nanasy

답변:


371

"충돌"은 "동일한 내용의 병렬 진화"를 의미합니다. 따라서 병합하는 동안 "지옥으로"이동하면 동일한 파일 세트에서 대규모로 진화 한 것입니다.

리베이스가 병합보다 나은 이유는 다음과 같습니다.

  • 마스터 중 하나를 사용하여 로컬 커밋 기록을 다시 작성한 다음 작업을 다시 적용하여 충돌을 해결하십시오.
  • 최종 병합은 마스터의 모든 커밋 히스토리와 재 적용 변경 사항 만 갖기 때문에 확실히 "빠른 전달"입니다.

이 경우 올바른 워크 플로 (공통 파일 집합의 발전)가 먼저 리베이스 된 다음 병합 합니다.

그러나 즉, 백업 이유 때문에 로컬 브랜치를 푸시하면 다른 사람이 해당 브랜치를 가져 오거나 (또는 ​​최소한 사용하지 않아야 함) 커밋 히스토리가 연속 리베이스에 의해 다시 작성되기 때문에


그 주제 (REBASE 다음 병합 워크 플로우)에서 barraponto가 에서 의견이 개 흥미로운 게시물을 모두 언급 randyfay.com :

이 기술을 사용하면 항상 current 최신 패치와 같은 퍼블릭 브랜치에서 작업을 수행 할 수 있습니다 HEAD.

( 바자에 대한 유사한 기술 이 존재합니다 )


27
리베이스 공유 를 허용하는 기술 에 대해서는 softwareswirl.blogspot.com/2009/04/…를
mhagger

2
randyfay.com/node/91randyfay.com/node/89대단 합니다. 이 기사를 통해 워크 플로에서 무엇을 입 었는지, 이상적인 워크 플로가 무엇인지 이해할 수있었습니다.
Capi Etheriel 11

마스터 브랜치에서 로컬로 리베이스하는 것은 기본적으로 로컬이 마스터가 어떤 종류의 병합 후에 알지 못했던 기록을 업데이트하는 것입니까?
heellatan

@dtan 내가 여기서 설명하는 것은 마스터 위에 로컬로 리베이스하는 것입니다. 로컬 히스토리를 정확하게 업데이트하지 않고 로컬 브랜치 내에서 충돌을 해결하기 위해 마스터 위에 로컬 히스토리를 다시 적용하십시오.
VonC

386

TL; DR

git rebase 워크 플로는 충돌 해결에 좋지 않은 사람들이나 Git Disaster 피하기 : Gory Story에 제안 된 것처럼 SVN 워크 플로에 익숙한 사람들로부터 당신을 보호하지 않습니다 . 충돌 해결이 더 지루해지고 잘못된 충돌 해결에서 복구하기가 더 어려워집니다. 대신 diff3을 사용하면 처음에는 그렇게 어렵지 않습니다.


Rebase 워크 플로우는 충돌 해결에 좋지 않습니다!

나는 역사를 정리하기 위해 매우 친근하다. 그러나 충돌이 발생하면 즉시 리베이스를 중단하고 대신 병합을 수행하십시오! 사람들이 충돌 해결을위한 병합 워크 플로에 대한 더 나은 대안으로 rebase 워크 플로를 추천하고 있다는 사실이 실제로 저를 죽입니다 (이 질문에 관한 것입니다).

병합하는 동안 "지옥으로"가면 리베이스 중에 "지옥으로"가되며 잠재적으로 훨씬 더 많은 지옥이됩니다! 이유는 다음과 같습니다.

이유 # 1 : 각 커밋마다 한 번이 아니라 한 번 충돌 해결

병합 대신 리베이스 할 때, 동일한 충돌에 대해 리베이스하려는 커밋 횟수만큼 충돌 해결을 수행해야합니다!

실제 시나리오

나는 지점에서 복잡한 방법을 리팩토링하기 위해 마스터에서 분기합니다. 리팩토링 작업은 리팩토링하고 코드 검토를 받기 위해 총 15 개의 커밋으로 구성됩니다. 리팩토링의 일부는 이전에 마스터에 있던 혼합 탭과 공백을 수정하는 것입니다. 이것은 필요하지만 불행히도 마스터 에서이 방법으로 변경 한 내용과 충돌합니다. 물론이 방법으로 작업하는 동안 누군가가 마스터 브랜치에서 내 변경 사항과 병합 해야하는 동일한 방법을 간단하고 합법적으로 변경합니다.

지점과 마스터를 다시 병합 할 때 두 가지 옵션이 있습니다.

자식 병합 : 충돌이 발생합니다. 그들이 마스터하고 변경하여 내 지점 (최종 제품)에 적용한 변경 사항을 확인했습니다. 끝난.

git rebase : 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 두 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 세 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 네 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 5 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 6 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 나는 일곱 번째 와 충돌합니다범하다. 충돌을 해결하고 리베이스를 계속합니다. 8 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 9 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 열 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 11 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 12 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 13 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다. 열네 번째 와 충돌합니다범하다. 충돌을 해결하고 리베이스를 계속합니다. 15 번째 커밋 과 충돌 합니다. 충돌을 해결하고 리베이스를 계속합니다.

이것이 당신이 선호하는 워크 플로우 라면 나를 놀려 야합니다 . 마스터에서 한 번의 변경으로 충돌하는 공백 수정 만 있으면됩니다. 모든 커밋은 충돌하므로 해결해야합니다. 그리고 이것은 공백 충돌 만있는 간단한 시나리오입니다. 하늘은 파일 간의 주요 코드 변경과 관련하여 실제 충돌이 발생 하고 여러 번 해결해야 한다는 것을 금합니다 .

추가 충돌 해결이 필요 하면 실수 가능성이 높아집니다 . 그러나 취소 할 수 있기 때문에 실수는 괜찮습니다. 물론 ...

이유 # 2 : 리베이스를 사용하면 실행 취소가 없습니다!

우리 모두는 갈등 해결이 어려울 수 있으며 일부 사람들은 그 문제에 매우 나쁘다는 것에 모두 동의 할 수 있다고 생각합니다. 실수가 발생하기 쉽기 때문에 git을 사용하면 실행 취소하기가 쉽습니다.

브랜치 를 병합 할 때 git은 충돌 해결이 제대로 수행되지 않으면 버려 지거나 수정 될 수있는 병합 커밋을 만듭니다. 잘못된 병합 커밋을 공개 / 정식 리포지토리로 이미 푸시 한 경우에도 병합에서 git revert발생한 변경 사항을 취소하고 새 병합 커밋에서 병합을 올바르게 다시 실행할 수 있습니다.

브랜치 를 리베이스 하면 충돌 해결이 잘못되었을 가능성이 있습니다. 모든 커밋에 잘못된 병합이 포함되어 있으므로 리베이스를 다시 실행할 수 없습니다 *. 기껏해야, 돌아가서 영향을받는 각 커밋을 수정해야합니다. 재미 없어.

리베이스 후에는 커밋의 원래 부분과 잘못된 충돌 해결의 결과로 무엇을 도입했는지 확인할 수 없습니다.

* git의 내부 로그에서 오래된 심판을 파낼 수 있거나 rebasing 전에 마지막 커밋을 가리키는 세 번째 분기를 만드는 경우 rebase를 취소 할 수 있습니다.

충돌 해결에서 지옥을 꺼내십시오 : diff3 사용

이 충돌을 예로 들어 보겠습니다.

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

갈등을 살펴보면 각 지점이 무엇을 변경했는지 또는 의도가 무엇인지 알 수 없습니다. 이것이 갈등 해결이 혼란스럽고 어려운 이유라고 생각합니다.

구조에 diff3!

git config --global merge.conflictstyle diff3

diff3을 사용하면 새로운 충돌마다 병합 된 공통 조상 인 세 번째 섹션이 있습니다.

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
||||||| merged common ancestor
EmailMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

먼저 병합 된 공통 조상을 검사하십시오. 그런 다음 각면을 비교하여 각 가지의 의도를 결정하십시오. HEAD가 EmailMessage를 TextMessage로 변경 한 것을 볼 수 있습니다. 그 목적은 TextMessage에 사용되는 클래스를 변경하여 동일한 매개 변수를 전달하는 것입니다. 또한 feature-branch의 의도가 : include_timestamp 옵션에 대해 true 대신 false를 전달 함을 알 수 있습니다. 이러한 변경 사항을 병합하려면 두 가지 의도를 결합하십시오.

TextMessage.send(:include_timestamp => false)

일반적으로 :

  1. 공통 조상과 각 분기를 비교하고 가장 간단한 변경을 갖는 분기를 결정하십시오.
  2. 이 간단한 변경 사항을 다른 지점의 코드 버전에 적용하면 더 간단하고 복잡한 변경 사항이 모두 포함됩니다.
  3. 변경 사항을 함께 병합 한 섹션 이외의 충돌 코드 섹션을 모두 제거하십시오.

대안 : 지점의 변경 사항을 수동으로 적용하여 해결

마지막으로 diff3에서도 일부 충돌을 이해하기가 끔찍합니다. 이것은 diff가 의미 상 공통적이지 않은 공통 라인을 발견 할 때 특히 발생합니다 (예 : 두 지점이 같은 곳에 빈 줄이 생겼습니다!). 예를 들어, 하나의 브랜치가 클래스 본문의 들여 쓰기를 변경하거나 유사한 메소드를 재정렬합니다. 이 경우 더 나은 해결 방법은 병합의 양쪽에서 변경 사항을 검사하고 diff를 다른 파일에 수동으로 적용하는 것입니다.

병합 곳에 우리가 시나리오에서 충돌을 해결하는 방법에 살펴 보자 origin/feature1어디 lib/message.rb충돌을.

  1. 현재 체크 아웃 한 지점 ( HEAD, 또는 --ours) 또는 병합중인 지점 ( origin/feature1, 또는 --theirs)이 더 간단하게 적용 되는지 결정합니다 . 트리플 도트 ( git diff a...b) 와 함께 diff를 사용하면 b마지막 분기 이후에 발생한 변경 사항 a, 즉 a와 b의 공통 조상을 b와 비교합니다.

    git diff HEAD...origin/feature1 -- lib/message.rb # show the change in feature1
    git diff origin/feature1...HEAD -- lib/message.rb # show the change in our branch
    
  2. 더 복잡한 버전의 파일을 확인하십시오. 이렇게하면 모든 충돌 마커가 제거되고 선택한면이 사용됩니다.

    git checkout --ours -- lib/message.rb   # if our branch's change is more complicated
    git checkout --theirs -- lib/message.rb # if origin/feature1's change is more complicated
    
  3. 복잡한 변경 사항을 체크 아웃 한 상태에서 간단한 변경 사항의 차이점을 확인하십시오 (1 단계 참조). 이 diff에서 충돌하는 파일에 각 변경 사항을 적용하십시오.


4
한 번에 모든 갈등을 병합하는 것이 개인 커밋보다 더 잘 작동합니까? 이미 단일 커밋을 병합하는 데 문제가 있습니다 (특히 커밋을 논리적 부분으로 나누지 않고 검증을 위해 충분한 테스트를 제공하지 않는 사람들). 또한 백업 옵션과 관련하여 rebase는 병합보다 나쁘지 않습니다. 대화식 rebase 및 tortoisegit와 같은 도구 (포함 할 커밋을 선택할 수 있음)는 지능적으로 도움이됩니다.
prusswan 2016 년

8
나는 # 1의 이유를 언급 한 것 같습니다. 개별 커밋이 논리적으로 일관성이없는 경우 논리적으로 일관된 분기를 병합해야하는 더 많은 이유 때문에 실제로 충돌을 이해할 수 있습니다. 커밋 1이 버그이고 커밋 2가 수정하면 커밋 1을 병합하는 것이 혼동됩니다. 위에서 설명한 것과 같이 15 개의 충돌이 연속적으로 발생할 수있는 합법적 인 이유가 있습니다. 또한 rebase가 더 나쁘지 않다는 당신의 주장은 다소 근거가 없습니다. Rebase는 잘못된 병합을 원래의 좋은 커밋으로 혼합하고 다시 시도하기 위해 좋은 커밋을 남겨 두지 않습니다. 병합합니다.
Edward Anderson

6
나는 당신에게 전무에 동의합니다. 그레이트 포스트; 그것은 몇 가지를 정리합니다. 그래도 rerere가 도움이 될지 궁금합니다. 또한 diff3 사용에 대한 제안에 감사드립니다. 현재이 기능을 전환 할 것입니다.
derick

45
diff3에 대해서만 이야기 +1-공통 조상이 무엇을 말하지 않았는지 책임이있는 사람을 이해할 수없는 갈등 저주를 얼마나 자주보고 있었는지. 대단히 감사합니다.
John

4
이것은 받아 들여진 대답이어야합니다. rebase 워크 플로는 특정 시점에 코드베이스에 큰 차이가 있다는 사실을 숨기고 있기 때문에 끔찍합니다.보고있는 코드가 어떻게 작성되었는지 이해하려는 경우 유용 할 수 있습니다. 충돌하지 않는 작은 지점 만 마스터를 기반으로해야합니다.
Robert Rüger

32

워크 플로에서 최대한 많이 리베이스하고 자주 시도합니다. 불일치가 누적되지 않으면 브랜치 간의 충돌 정도와 심각도가 줄어 듭니다.

그러나 대부분 리베이스 기반 워크 플로우에서도 병합 할 수있는 공간이 있습니다.

병합은 실제로 두 개의 부모가있는 노드를 만듭니다. 이제 다음 상황을 고려하십시오. 두 개의 독립적 인 피쳐 brances A와 B가 있으며 이제 A와 B에 의존하는 A 지점과 B가 검토되는 기능 지점 C에서 물건을 개발하고 싶습니다.

내가하는 일은 다음과 같습니다.

  1. A 위에 분기 C를 작성 (체크 아웃)하십시오.
  2. B와 병합

이제 분기 C에는 A와 B의 변경 사항이 포함되어 있으며 계속 개발할 수 있습니다. A로 변경하면 다음과 같이 분기 그래프를 재구성합니다.

  1. A의 새 상단에 분기 T를 만듭니다.
  2. T를 B와 병합
  3. C를 T로 리베이스
  4. 분기 T 삭제

이렇게하면 실제로 임의의 분기 그래프를 유지할 수 있지만 부모가 변경 될 때 rebasing을 수행하는 자동 도구가 없기 때문에 위에서 설명한 상황보다 복잡한 것을 수행하는 것은 이미 너무 복잡합니다.


1
리베이스만으로도 같은 결과를 얻을 수 있습니다. 여기서 병합은 실제로 필요하지 않습니다 (커밋을 복제하지 않으려는 경우는 제외하지만 인수로 거의 보지 않습니다).
odwl

1
실제로 커밋을 복제하고 싶지 않습니다. 작업의 기내 구조를 최대한 깨끗하게 유지하고 싶습니다. 그러나 그것은 개인적인 취향의 문제이며 모든 사람에게 꼭 맞는 것은 아닙니다.
Alex Gontmakher 2016 년

나는 100 %가 첫 번째 단락에 동의합니다. (@Edward의 답변은 그렇지 않은 경우 작동하지만 전 세계의 모든 프로젝트가 제안한대로 작동하고 싶습니다). 대답의 나머지 부분은 A와 B가 진행되는 동안 C 작업은 이미 위험하다고 생각 합니다 (적어도 A와 B에 의존 하는 정도까지 ). 아마도 병합을 유지하지 않을 것입니다 (C는 최신 및 가장 큰 기반을 기반으로 재조정됩니다).
Alois Mahdal

23

거의 모든 상황에서 git push origin --mirror를 사용하지 마십시오.

이 작업을 수행 할 것인지 묻는 메시지는 표시되지 않으며 로컬 상자에없는 모든 원격 브랜치가 지워 지므로 더 좋습니다.

http://twitter.com/dysinger/status/1273652486


6
또는 결과가 무엇인지 잘 모르는 일을하지 마십시오? 내가 관리하는 데 사용한 기계 Instructions to this machine may lead to unintended consequences, loss of work/data, or even death (at the hands of the sysad). Remember that you are solely responsible for the consequences of your actions 는 MOTD에있었습니다.
richo

미러 리포지토리를 사용하는 경우 사용하십시오 (내 경우에는 수신 후 후크의 소스
리포지토리

14

설명을 읽은 후에 한 가지 질문이 있습니다.

git checkout master
git pull origin
git checkout my_new_feature

기능 분기에서 'git rebase / merge master'를 수행하기 전에?

때문에 당신의 마스터 분기 친구의 저장소에서 자동으로 업데이트되지 않습니다. 와 함께해야합니다 git pull origin. 즉, 항상 변하지 않는 로컬 마스터 브랜치에서 리베이스 할 것입니까? 그런 다음 푸시 시간이 오면 보지 못한 (로컬) 커밋이있는 리포지토리를 푸시하여 푸시가 실패합니다.


13

당신의 상황에서 나는 당신의 파트너가 맞다고 생각합니다. rebasing에 대한 좋은 점은 외부인에게 변경 사항이 모두 깔끔한 순서로 일어난 것처럼 보입니다. 이것은 의미

  • 변경 사항을 매우 쉽게 검토 할 수 있습니다
  • 계속해서 작고 멋진 커밋을 할 수는 있지만 한 번에 마스터로 병합하여 커밋 세트를 공개 할 수 있습니다
  • 퍼블릭 마스터 브랜치를 보면 개발자마다 다른 기능에 대한 다양한 커밋이 표시되지만 모두 혼합되지는 않습니다.

여전히 백업을 위해 개인 개발 브랜치를 원격 저장소로 계속 푸시 할 수 있지만 다른 사용자는 재베이스 작업을하기 때문에이를 "공용"브랜치로 취급해서는 안됩니다. BTW, 쉬운 명령은 git push --mirror origin입니다.

Git을 사용한 패키징 소프트웨어 기사 는 병합과 리베 이싱의 장단점을 잘 설명합니다. 상황이 조금 다르지만 교장은 동일합니다. 기본적으로 브랜치가 퍼블릭인지 프라이빗인지, 메인 라인에 통합 할 계획인지에 따라 결정됩니다.


1
git을 사용한 패키징 소프트웨어 링크가 더 이상 작동하지 않습니다. 원래 답변을 편집 할 수있는 좋은 링크를 찾을 수 없습니다.
Chetan

에 미러링하지 말고 origin세 번째 전용 백업 저장소에 미러링해야합니다.
Miral

12

어쨌든, 나는 최근 지점에서 워크 플로우를 따르고 있었고 마스터로 다시 병합하려고 시도했을 때 모두 지옥에 갔다. 중요하지 않은 것들과 많은 충돌이있었습니다. 갈등은 나에게 이해가되지 않았다. 로컬 마스터가 모든 충돌을 해결했지만 원격 마스터는 여전히 행복하지 않았기 때문에 모든 것을 정리하는 데 하루가 걸렸으며 결국 원격 마스터에게 강제로 밀렸습니다.

파트너 나 제안 된 워크 플로 모두 이해가되지 않는 충돌을 겪어야합니다. 제안 된 워크 플로우를 따르는 경우에도 해결 후 '강제'푸시가 필요하지 않습니다. 실제로 밀고 있던 브랜치를 병합하지 않았지만 원격 팁의 자손이 아닌 브랜치를 푸시해야 함을 나타냅니다.

무슨 일이 있었는지주의해서 살펴 봐야한다고 생각합니다. 로컬 브랜치 생성과 로컬 브랜치로 다시 병합하려는 지점간에 원격 마스터 브랜치를 다른 사람이 (고의적이든 아니든) 다시 감쌀 수 있습니까?

다른 많은 버전 제어 시스템과 비교할 때 Git을 사용하면 도구와의 싸움이 줄어들고 소스 스트림의 기본 문제를 해결할 수 있습니다. 힘내는 마술을 수행하지 않으므로 충돌하는 변경으로 인해 충돌이 발생하지만 커밋 부모를 추적하여 쓰기 작업을 쉽게 수행 할 수 있어야합니다.


OP가 자신의 프로세스에서 발견되지 않은 rebase 또는 실수를 가지고 있음을 암시하고 있습니다.
krosenvold

8

"작은 지점을 보유한 단일 개발자 인 경우에도 리베이스를 사용하고 올바르게 병합하는 습관을들이는 것이 좋습니다. 기본 작업 패턴은 다음과 같습니다.

  • 기존 지점 A에서 새 지점 B 만들기

  • 지점 B의 변경 사항 추가 / 커밋

  • 지점 A의 업데이트 리베이스

  • B 지점에서 A 지점으로 변경 사항 병합

https://www.atlassian.com/git/tutorials/merging-vs-rebasing/


7

내가 관찰 한 바에 따르면, git merge는 병합 후에도 브랜치를 분리하는 경향이 있지만 rebase 다음 merge는 하나의 브랜치로 결합합니다. 후자는 훨씬 더 깔끔한 반면에 전자는 병합 후에도 어느 커밋이 어느 브랜치에 속하는지 알아내는 것이 더 쉬울 것입니다.


4

Git을 사용하면 "올바른"워크 플로우가 없습니다. 보트에 떠 다니는 것을 사용하십시오. 그러나 브랜치를 병합 할 때 끊임없이 충돌이 발생하면 동료 개발자와 더 잘 협력해야합니까? 두 사람이 같은 파일을 계속 편집하는 것처럼 들립니다. 또한 공백 및 하위 버전 키워드 (예 :“$ Id $”및 기타 키워드)도주의하십시오.


0

rebase 워크 플로는 시각적으로 더 명확하기 때문에 (GitKraken뿐만 아니라 Intellij 및에서 gitk가장 먼저 권장하지만 가장 먼저 권장합니다) : 분기가 있고 마스터에서 시작하여 마스터로 돌아갑니다. . 다이어그램이 깨끗하고 아름답다면 아무것도 지옥에 가지 않는다는 것을 알게 될 것 입니다 .

여기에 이미지 설명을 입력하십시오

내 작업 흐름은 거의 당신에서 동일하지만, 하나의 작은 차이 : 나는 squash전에 내 로컬 지점에서 하나에 저지른 rebase최신 변경 사항에에 내 지점 master, 이유는

rebase각 커밋 을 기반으로 작동

즉, 15 개의 커밋이 동일한 줄을 변경하면 master 있다면 스쿼시하지 않으면 15 번 확인해야하지만 최종 결과는 무엇입니까?

따라서 전체 워크 플로는 다음과 같습니다.

  1. 체크 아웃 master후 최신 버전인지 확인하십시오.

  2. 거기에서 새로운 지점을 만듭니다

  3. 이 때문에, 당신은 자유롭게, 원격, 걱정에 여러 번 푸시을 커밋 할 수있다 당신의 일을 당신의 지점.

  4. 누군가 "내 PR / MR이 승인되면 이제 마스터로 병합되었습니다"라고 말하면 가져 오거나 가져올 수 있습니다. 언제든지 또는 6 단계에서 수행 할 수 있습니다.

  5. 모든 작업을 수행 한 후 커밋하고 커밋이 여러 개인 경우 스쿼시하십시오 (모든 작업과 코드 라인을 몇 번 변경했는지는 중요하지 않습니다. 유일한 중요한 것은 최종 버전입니다). 밀어 넣든 말든 상관 없습니다.

  6. 체크 아웃하는 master, pull다시는 최신이 보장하는 master지역이다. 다이어그램은 다음과 유사해야합니다.

여기에 이미지 설명을 입력하십시오

보시다시피, 귀하는 로컬 지사에 있으며,이 지사에있는 오래된 상태에서 시작한 master반면 master(로컬 및 원격 모두) 동료의 변경으로 진행되었습니다.

  1. 지점으로 다시 체크 아웃하고 마스터로 리베이스하십시오. 이제 커밋이 한 번만 발생하므로 충돌을 한 번만 해결할 수 있습니다 . (GitKraken에서는 브랜치를 끌어서 master"Rebase"를 선택해야합니다. 또 다른 이유는 제가 좋아하는 이유입니다.) 처럼:

여기에 이미지 설명을 입력하십시오

  1. 이제 최신의 모든 변경 사항 master과 지점의 변경 사항이 결합되었습니다. 이제 리모컨으로 밀 수 있으며, 이전에 밀었다면 강제로 밀어야합니다. Git은 단순히 빨리 감을 수 없다는 것을 알려줄 것입니다. 리베이스로 인해 지점의 시작점이 변경되었습니다. 그러나 현명하게 힘을 사용하십시오 . 결국, 리모컨 또한 지점 이므로 master잘못된 일 을 해도 영향을 미치지 않습니다 .

  2. PR / MR을 작성하고 승인 될 때까지 기다리면 master기고하십시오. 축하합니다! 이제 master다이어그램을 정리하기 위해을 (를 ) 체크 아웃하고 변경 사항을 가져온 다음 로컬 브랜치를 삭제할 수 있습니다. 원격 브랜치를 마스터로 병합 할 때 수행하지 않으면 원격 브랜치도 삭제해야합니다.

최종 다이어그램은 깨끗하고 다시 명확합니다.

여기에 이미지 설명을 입력하십시오

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