2017-10-12 6 views
1

며칠 동안 기능 지사에서 작업했으며 이제는 dev으로 병합 할 준비가되었습니다. 이 기능을 사용하면서 dev과 병합하여 패치를 받았습니다. 내 역사는 다음과 같습니다중간에 dev를 병합했을 때 커밋을 어떻게 스쿼시합니까?

* E (feature1) 
* D:merge with dev 
| \ 
* C * B:patch (dev) 
    \ | 
    * A 

내가 다음 dev 및 빨리 감기 dev와 병합 커밋 하나에 전체 분기를 납작하게하고 싶습니다. 문제는 EC으로 병합 할 수 없기 때문에 C으로 스쿼시 할 수 없다는 것입니다. 유일한 옵션은 E, BC (새로 커밋을 F이라고 함) 스쿼시 인 것 같습니다.이 경우 스쿼시 된 커밋에는 관련없는 패치의 일부인 변경 사항도 포함됩니다. dev에 병합되면 F (패치 적용 및 기능 추가)과 B (패치 만 적용)이라는 두 가지 커밋이 적용됩니다. 게다가 F은 두 가지 무관 한 변화를 일으킬 것입니다.

내 기록을 멋지게 정리하는 방법이 있습니까? 내 워크 플로를 변경해야합니까?

+0

워크 플로 권장 변경 : 절대 병합하지 마십시오. 대신 그것에 rebase. 'dev'에 리베이스하기 만하면됩니다. – o11c

+0

동의 함 (모두). 그것을 시도 할 것입니다 – lfk

+0

@ o11c - Rebasing은 당신의 분기 이력을 바꿉니다. 내가 팬이되는 동안, 때때로 위험 할 수 있습니다. 특히 자신이하는 일을 모르는 경우. 또한 rebase는 충돌이있을 때 정말로 짜증나게합니다. 왜냐하면 리베이스 할 때마다 충돌을 다시 해결해야하기 때문입니다. 병합을 사용하면 충돌을 한 번 해결 한 다음 앞으로 이동할 수 있습니다. – JDB

답변

0

자식은 커밋의 변경 내용을 추적하지 않습니다. 각 커밋에는 repo에있는 파일의 전체 복사본이 들어 있습니다. "변경"은 두 커밋을 서로 다르게하여 결정됩니다.

그래서, 짧은에, 절대적으로 F 커밋에 E, BC을 부수 다음 dev에 지점에 그 병합에 문제가 없습니다. B 커밋은 dev 브랜치에 여전히 존재합니다. git이 FB과 비교하면 CE에 의해 도입 된 변경 사항 만 F으로 표시됩니다.

물론이 문제는 git rebase을 사용하여 해결할 수 있지만 그 자체의 두통이 있습니다. 예를 들어, git rebase은 분기 히스토리를 변경하기 때문에 (커밋을 dev에서 최신 커밋의 맨 위로 이동), 충돌이있는 경우 rebase 할 때마다 이러한 충돌을 다시 해결해야합니다. 문제가 해결되는 데 시간이 오래 걸리면 dev에 최신 상태를 유지하기 위해 몇 가지 리베이스가 필요합니다.


그냥이 모든 사실이 있음을 입증하고 당신이 걱정할 필요가 없다고, 내가 설정을 예를 들어 GitHub의의의 repo했습니다 : https://github.com/cyborgx37/sandbox

시작하기를, 우리는이있는의 dev branchB 커밋

B:patch 
| 
A 

은 그 때 나는 가지고 feature1 branchC, DE 커밋 만들었습니다.

E 
| 
D:merge with dev 
|\ 
C \ 
| B 
A 

가 마지막으로 dev-with-feature1 branch있다 (D가 병합했고, 따라서이 부모님을 가지고 있기 때문에, 그 주, B 또한 커밋 역사에 표시).

F 
| 
B:patch 
| 
A 

나는 다음 dev에 떨어져이 분기를 생성, F는 하나의 커밋으로의 커밋 feature1을 모두 스쿼시
git merge --squash feature1 
git commit -m "F" 

을 사용했다.

diff for the F commit을 살펴보면 "패치 적용"이 표시되지 않습니다. B already contains those changes 이후로 F이 단지 이것을 반복하면 자식은 F과 연결되지 않습니다. 또 다른 관점에서

, here's the blame :

initial  hello! 
B:patch  patch! 
F   new feature!!! 

힘내 커밋의 변화를 추적하지 않습니다. 전체 프로젝트 상태를 저장합니다. "변경"은 커밋을 상위 (또는 전임자) 커밋과 비교하여 결정됩니다. B에 패치가 있기 때문에 git은 변경된 내용을 B과 연관시킵니다. 패치가 F에있을 것으로 예상됩니다. F에없는 유일한 방법은 패치를 삭제했는지 여부입니다.

+0

F에 대한 커밋 메시지는 feature1을 구현한다고 말합니다. 그러나 실제로, dev에서 F ^에서 F로 이동하면 패치도 얻게됩니다. 기본적으로 커밋 메시지가 거짓말입니다. – lfk

+0

아마도 나는 정확하게 이해하지 못하고 있습니다. dev 브랜치에서'B'를 제거 할 계획이십니까? 그렇지 않다면 아무런 문제가 없습니다. 'F' *는'B'를 포함해야합니다. 왜냐하면'F'는'B' 뒤에옵니다. 'F'는 모든 파일 상태의 전체 복사본을 포함 할 것이므로'F'가 어떤 변화를 가져 왔는지 알아 내려고하면 git는'F'를'B'와 비교하여 diff를줍니다. 패치가 이미'B'에 있기 때문에 자식은'F'에 속하는 것으로 간주하지 않을 것입니다. – JDB

+0

@Farshid - git이 zip 파일로 가득 찬 폴더처럼 생각하십시오.각 zip 파일에는 날짜 스탬프가 있으므로 주문을 추적 할 수 있습니다. 각 zip 파일에는 해당 날짜의 전체 소스 코드가 들어 있습니다. 특정 날짜에 무엇이 소개되었는지 알고 싶다면 그 날의 우편 번호를 이전 우편 번호와 비교하십시오. 그것은 기본적으로 자식 작동 방식입니다 ... 각 커밋은 모든 파일 상태의 전체 복사본입니다 ** ** 변경 기록이 아닙니다. – JDB

0

정확하게 이해하면 B 위의 커밋 내용 전체를 E이 단일 커밋으로 적용하려고합니다. 이것은 당신이, 당신이 git checkout E .을 사용할 수 있습니다 무엇을 달성하고자하는 경우

(잊지 않는 ".") :

여기
# go to your `dev` branch : 
git checkout dev 

# get the *content* of E (here comes the ".") : 
git checkout E . 

# all the content of E should appear as modifications staged for commit : 
git status -sb 

# you can double check that the content is to your liking : 
git diff --cached # --cached means 'compare with the index' 
gitk --cached  # as opposed to 'compare with what is on the disk' 

# commit 
git commit 
+0

그것은 매우 흥미로운 방법입니다. 적어도 하나의 문제가 있음을 알 수 있습니다. 병합 된 결과가 dev에 병합되었는지 또는 dev에 병합 (또는 리베이스)하지 않고 테스트하고 빠른 포워드하는 것과는 대조적으로 병합 된 결과가 작동하는지 여부를 알 수 있습니다. 물론 작동하지 않으면 dev에 커밋하지 않아도됩니다. 하지만 또 다른 문제는 머지 커밋을 만들 수 없기 때문에 좋은 역사를 유지하는 데 도움이됩니다. – lfk

0

내가 무슨 짓을했는지 : 나는 새에 E, BCF를 저지 숙청 , F에 대한 메시지와 함께 feature1을 구현한다고 표시합니다 (지금까지는 패치도 추가합니다). 그런 다음 dev에 리베이스되었습니다. 이제 커밋 메시지와 기록은 정확합니다 : F에는 패치가 포함되어 있지만 추가하지 않았습니다. 이전 커밋에 의해 추가되었습니다.

마지막으로 dev (병합 완료를 강제하려면 --no-ff)과 병합되었습니다.

앞으로는 dev과 병합하지 말고 리베이스해야합니다.