2017-12-16 14 views
1

나는이 역사를 시작하는 경우 :rebases를 통해 동일한 기록을 공유하는 지점을 어떻게 유지합니까?

* 505421e - (HEAD -> stage4) go to stage 4 
* 307978f - (stage3) go to stage 3 
* d8ab213 - steb b 
* 49cbef9 - (stage2) step a 
* 6e4a2ed - (stage1) go to stage 1 
* 3ca2d7d - do something 
* 5ce596d - (stage0) go to stage 0 
* 0c8487b - foo 
* ccfb7c9 - bar 

그리고 나는 foo 다음 분기 stage0–stage3가 더 이상 동일 stage4 역사를 커밋이없는 것, 커밋 변경하기 위해 git rebase -i ccfb7c9 수행하고 업데이트 된 foo 커밋 필요가 없습니다 . 같은 역사를 갖게하려면 어떻게해야합니까?

+0

https://stackoverflow.com/a/45844847/6309는 유망 해 보입니다. – VonC

+0

일반적으로 구조를 유지하는 것은 불가능합니다. 예를 들어, 3ca2를 5ce5로 채우면 어떨까요? 그 다음에'stage0' 포인트가 있어야합니까? –

+0

@DavisHerring : 논리적으로 올바른 대답은'git filter-branch'와 같은 방식으로 처리하는 것입니다 : old => 새로운 커밋 해시 맵을 만들고지도 항목을 기반으로 레이블을 바꿉니다. 두 개의 커밋을 수행하면 이전 커밋과 두 개의 커밋 모두 새로운 커밋으로 매핑됩니다. 커밋을 분할하면 이전 커밋이 새로운 커밋 중 첫 번째 커밋에 매핑됩니다. 기존 리베이스 코드는 이러한 맵을 만드는 데 도움이되지 않습니다. – torek

답변

1

정확합니다. 불행히도 Git에는 "옳은 길"을 구현하기위한 어떤 것도 내장되어 있지 않습니다. 을 염두에두고 특정 시점에이를 수행하는 프로그램을 작성하기는했지만 을 "올바르게"정의하는 것이 다소 어렵습니다. 이상한 모든 경우에 너무 어려워서 버렸습니다.

여기에 근본적인 문제가 git cherry-pick 경우와 같은 복사 커밋에 의해 git rebase 작품 (대화 형 REBASE와 당신이 길을 따라 몇 가지 추가 변경시키는) 것입니다. 새 사본에는 새롭고 다른 해시 ID가 있습니다. 복사본이 만들어지면 브랜치 이름 현재 브랜치 (그 중 마지막 복사 된 커밋까지 시작한 항목)를 다시 가리 킵니다. 점에서

  • 0c8487b - foo
  • 5ce596d - (stage0) go to stage 0
  • 3ca2d7d - do something
  • ...
  • 505421e - (HEAD -> stage4) go to stage 4

: 즉

,이 경우, 당신은 망할 놈의 복사본이 주문 (가장 초기부터 최신까지) 한 번에 하나씩. 첫 번째 단계에서 일부를으로 변경하십시오. 변경 사항이있는 경우 새로운 내용이 새로운 해시 ID (예 : cccccc1)를 얻게되므로 실제로 변경 사항이 없으면 실제로 무엇이든 상관 없습니다. 우리는 이것을 "새로운 커밋 1"이라고 부른다.) 이 새로운 커밋의 부모 커밋은 bar이라고 표시된 커밋 인 ccfb7c9이므로 새 기록은 해당 시점의 이전 기록에 다시 포함됩니다.

그러면 Git은 두 번째 커밋 인 5ce596d - (stage0) go to stage 0을 복사합니다.이 커밋은 cccccc2이됩니다. cccccc2의 부모는 cccccc1이며, 이것은 다른 커밋이되도록 강제로 5ce596d과 완전히 다릅니다. 자식은 계속해서 8 개의 모든 커밋을 복사하고 마지막 커밋은 cccccc8이된다. Git은 stage4이라는 이름을 변경하여 이름이 cccccc8이되도록합니다.

따라서 Git이 발견 한 커밋 (예 : stage4)에서 시작하여 내역을 보면 새 메시지 번호이 표시됩니다. 그러나 Git은 다른 이름을 변경하지 않았습니다. 예를 들어, stage3은 여전히 ​​커밋을 확인합니다. 307978fstage0은 커밋을 확인하고 여전히 커밋을 확인합니다. 5ce596d.따라서 의 이름에서 시작하여 해당 기록을 보면이라는 이름을 사용하면 원래 일련의 커밋을 볼 수 있습니다.

필요한 것은 각 라벨을 원래 해시에서 새로운 해시로 이동시키는 것입니다. 문제는이 모든 것을 식별하는 데서 오는 것입니다 : 어떤 레이블 이되어야합니까? (일부는 이전의 커밋을 의도적으로 유지하고 일부는 이전하는 것이 바람직 할 수 있습니다.) 어떤 커밋이 올바른 커밋입니까? 대화 형 리베이스 중에 커밋을 분할하고 다른 것을 결합하는 경우 어떻게해야합니까?

간단하고 강력한 솔루션은 변경하려는 이름을 수동으로 강제 실행하여 새 커밋을 가리키는 것입니다.

git branch -f stage0 newhash0 
git branch -f stage1 newhash1 
git branch -f stage2 newhash2 
git branch -f stage3 newhash3 

을하면됩니다 : git log --all --decorate --oneline --graph를 실행하고 각각의 이름에 대한 이전 및 커밋 새로운 ID를 기록해, 다음 실행합니다. 또는 자동으로 이동하는 stage4에서 시작하여 거꾸로 작업하여 커밋을 찾을 수 있기 때문에 분기 이름 중 일부만 완전히 삭제하십시오. 이름은 그냥 "커밋 원시 포인터"보다 더 많은 의미를 가질 수 있도록


1 내가 좋아하는 정의는 구조화 지점 이름을 포함한다. 이 구조화의 양식도 어렵습니다. 이름 계층 구조를 사용해야합니까? 아니면 분기 이름을 "슈퍼 브랜치"로 그룹화하는 git config 항목이 있어야합니까?

일부 git rebase 명령은 문자 그대로 git cherry-pick으로 실행되고 일부는 실행하지 않습니다. 대화 형 리베이스는 실제로 git cherry-pickgit commit --amend 및 기타 까다로운 항목과 함께 실행되는 경우 중 하나입니다.

3 임의 힘내 오브젝트의 해시 ID 엄격 내용에 의해 결정된다 "복사"-가 동일한 동일한 해시 ID, 즉으로 바람 비트의 원래 비트에 100 % 동일한 경우 이렇게 , 당신은 단순히 원본을 다시 사용합니다. 그러나 모든 변경 작업을 수행하자마자 순서에있는 일부 커밋의 해시 ID가 변경되므로 "다운 스트림"(자식) 커밋마다 다른 부모 해시 ID가 있어야하며 이는 다운 스트림 커밋도 변경됩니다.