Mercurial에서 역방향 병합 취소
고통으로 죽지 않고 분극화 된 가지에 대한 병합의 효과를 어떻게 되돌릴 수 있습니까?
이 문제는 몇 달 동안 나를 괴롭 혔고 마침내 포기했습니다.
2 개의 명명 된 분기 가있는 1 개의 저장소가 있습니다 . A와 B.
A에 발생하는 변경은 필연적으로 B에서 발생합니다.
B에서 직접 발생하는 변경 사항은 A에서 발생하지 않아야합니다.
이러한 구성에서 "B"를 "A"로 병합하면 B에 대한 모든 변경 사항이 A에서 변경된 것처럼 A에 나타나기 때문에 저장소에 심각한 문제가 발생합니다.
이 상황에서 복구하는 유일한 "정상적인"방법은 병합을 "백 아웃"하는 것입니다. 즉,
hg up -r A
hg backout -r BadMergeRev --parent BadMergerevBeforeOnA
나중에 올바른 방향으로 병합하기로 결정하고 모든 종류의 불쾌한 일이 일어나고 특정 분기 B에서 지워지거나 주석 처리 된 코드가 갑자기 지워지지 않거나 주석이 제거되기 전까지는 모두 멋지고 멋지게 보입니다.
지금까지 "그것의 일을하게하고 모든 문제를 손으로 고쳐라"는 것 외에는 실행 가능한 해결책이 없었으며 솔직히 말하면 약간 허풍입니다.
다음은 문제를 설명하는 이미지입니다.
[원본 이미지 손실 됨]
파일 C & E (또는 변경 C & E)는 분기 a가 아닌 분기 b에만 나타나야합니다. 여기에서 개정 A9 (branch a, revno 9)가 문제의 시작입니다.
개정판 A10 및 A11은 "백 아웃 병합"및 "백 아웃 병합"단계입니다.
그리고 개정판 B12는 수은이며, 삭제하지 않으려는 변경 사항을 잘못 반복해서 삭제합니다.
이 딜레마는 많은 좌절과 푸른 연기를 일으켰고 나는 그것을 끝내고 싶습니다.
노트
그것은 후크 또는 정책 중 하나가 발생 반대 병합을 금지하려고하는 분명한 해답이 될 수있다, 나는이 최대를 깨끗이 할 수있는 능력을 발견 오히려 높고 그것의 가능성은 매우 가능성도 대책으로, 당신은 그 일이 반드시 여전히 불가피 하게 일어날 것이라고 가정 하면 해결 될 수 있습니다.
정교하게
모델에서는 별도의 파일을 사용했습니다. 이것들은 문제를 간단하게 들립니다. 이들은 단지 별도의 줄이 될 수있는 임의의 변경 을 나타냅니다 .
또한 부상에 대한 모욕을 더하기 위해 지점 A에 상당한 변화가 있었는데 이는 문제를 남겼습니다. "A 지점의 변경 사항이 변경된 것처럼 보이는 지점 B의 변경 사항과 충돌합니다. 대신 지점 A에서 "
역사 재 작성 트릭 :
이러한 모든 소급 솔루션의 문제점은 다음과 같습니다.
- 우리는 9000 개의 커밋을 가지고 있습니다.
- 따라서 새로 복제하는 데 30 분이 걸립니다.
- 어딘가에 저장소의 잘못된 복제본이 하나라도 존재하는 경우 원래 저장소와 다시 연결되어 다시 전체적으로 충돌 할 가능성이 있습니다.
- 모든 사람이 이미이 저장소를 복제했으며 현재 진행중인 커밋으로 며칠이 지났습니다.
- 그러한 클론 중 하나는 라이브 사이트이므로 "그것을 삭제하고 처음부터 시작"= "큰 노노"
(나는 위의 많은 것들이 약간 멍청하지만 내 통제를 벗어난다는 것을 인정합니다).
실행 가능한 유일한 해결책은 사람들 이 모든 것을 잘못 할 수 있고 할 것이라고 가정하고 이러한 잘못을 '실행 취소' 할 수 있는 방법이 있다고 가정하는 것입니다 .
잘못된 병합을 영구적으로 수정하고 수동으로 diff를 확인할 필요가없는 솔루션을 찾은 것 같습니다. 트릭은 히스토리로 돌아가서 잘못된 병합과 병렬로 커밋을 생성하는 것입니다.
따라서 단일 제품의 유지 관리 버전마다 별도의 분기가있는 저장소가 있습니다. 질문에서 제기 된 상황과 마찬가지로, 이전 버전의 분기에서 이루어진 모든 변경 사항 (즉, 해당 버전의 버그 수정)은 결국 모두 이후 버전의 분기에 병합되어야합니다.
따라서 특히 BRANCH_V8에서 무언가가 체크인되면 BRANCH_V9에 병합되어야합니다.
이제 개발자 중 한 명이 다음과 같은 실수를합니다. 그는 BRANCH_V9의 모든 변경 사항을 BRANCH_V8로 병합합니다 (즉, 잘못된 방향으로 병합). 게다가, 그 나쁜 병합 후에 그는 자신의 실수를 알아 채기 전에 약간의 추가 커밋을 수행합니다.
따라서 상황은 아래 그래픽 로그에 표시된 것과 같습니다.
o BRANCH_V8-13-잘못된 병합 직후 중요한 커밋 | o BRANCH_V8-12-BRANCH_V9에서 잘못된 병합 | \ | o BRANCH_V8-11-BRANCH_V8에 주석 추가 (즉, 마지막으로 알려진 양호한 상태) | | o | BRANCH_V9-10-BRANCH_V9에 대한 마지막 커밋 | |
이 실수를 다음과 같이 수정할 수 있습니다.
- 로컬 디렉토리를 BRANCH_V8의 마지막 양호한 상태로 업데이트하십시오.
hg update 11
- 마지막 상태의 새 자식을 만듭니다.
- 일부 파일 변경
$EDITOR some/file.txt
(Mercurial이 빈 커밋을 허용하지 않기 때문에 필요함) - 이러한 변경 사항 커밋
hg commit -m "generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9"
이제 상황은 다음과 같습니다.o BRANCH_V8-14-BRANCH_V9에서 잘못된 병합을 수정하기 위해 BRANCH_V8에 커밋 생성 | | o BRANCH_V8-13-잘못된 병합 직후 중요한 커밋 | | | o BRANCH_V8-12-BRANCH_V9에서 잘못된 병합 | / | o | BRANCH_V8-11-BRANCH_V8에 주석 추가 | | | o BRANCH_V9-10-BRANCH_V9에 대한 마지막 커밋
- 일부 파일 변경
새로 생성 된 헤드를 잘못된 병합이 발생한 개정판과 병합하고 커밋하기 전에 모든 변경 사항을 버립니다. 두 개의 헤드를 단순히 병합하지 마십시오. 그러면 병합 후에 발생한 중요한 커밋도 잃게됩니다!
- merge :
hg merge 12
(충돌 무시) - 모든 변경 사항을 버리십시오.
hg revert -a --no-backup -r 14
- 변경 사항 커밋 :
hg commit -m "throwing away wrong merge from BRANCH_V9"
이제 상황은 다음과 같습니다.o BRANCH_V8-15-BRANCH_V9에서 잘못된 병합 버리기 | \ | o BRANCH_V8-14-BRANCH_V9에서 잘못된 병합을 수정하기 위해 BRANCH_V8에 커밋 생성 | | + --- o BRANCH_V8-13-잘못된 병합 직후 중요한 커밋 | | o | BRANCH_V8-12-BRANCH_V9에서 잘못된 병합 | \ | | o BRANCH_V8-11-BRANCH_V8에 주석 추가 | | o | BRANCH_V9-10-BRANCH_V9에 대한 마지막 커밋 | |
즉. BRANCH_V8에는 두 개의 헤드가 있습니다. 하나는 잘못된 병합의 수정을 포함하고 다른 하나는 병합 직후 발생한 BRANCH_V8에 남은 중요한 커밋을 포함합니다.
- merge :
- BRANCH_V8의 두 머리를 병합합니다.
- 병합 :
hg merge
- 커밋 :
hg commit -m "merged two heads used to revert from bad merge"
- 병합 :
BRANCH_V8의 마지막 상황이 이제 수정되었으며 다음과 같습니다.
o BRANCH_V8-16-잘못된 병합에서 되 돌리는 데 사용되는 두 개의 헤드 병합 | \ | o BRANCH_V8-15-BRANCH_V9에서 잘못된 병합 버리기 | | \ | | o BRANCH_V8-14-BRANCH_V9에서 잘못된 병합을 수정하기 위해 BRANCH_V8에 커밋 생성 | | | o | | BRANCH_V8-13-잘못된 병합 직후 중요한 커밋 | / / o | BRANCH_V8-12-BRANCH_V9에서 잘못된 병합 | \ | | o BRANCH_V8-11-BRANCH_V8에 주석 추가 | | o | BRANCH_V9-10-BRANCH_V9에 대한 마지막 커밋 | |
이제 BRANCH_V8의 상황이 맞습니다. 남은 유일한 문제는 BRANCH_V8에서 BRANCH_V9 로의 다음 병합이 올바르지 않다는 것입니다. BRANCH_V9에서는 원하지 않는 잘못된 병합에 대한 '수정'에서도 병합되기 때문입니다. 여기서 트릭은 BRANCH_V8에서 BRANCH_V9로 별도의 변경으로 병합하는 것입니다.
- 먼저 BRANCH_V8에서 BRANCH_V9로 병합하면 잘못된 병합 이전의 BRANCH_V8에 대한 올바른 변경 사항이 있습니다.
- 두 번째 병합 실수와 그 수정 사항을 확인하고 아무것도 확인하지 않고 모든 변경 사항을 버립니다.
- 세 번째로 BRANCH_V8의 나머지 변경 사항을 병합합니다.
상세히:
- 작업 디렉토리를 BRANCH_V9로 전환하십시오.
hg update BRANCH_V9
- BRANCH_V8의 마지막 양호한 상태 (즉, 잘못된 병합을 수정하기 위해 생성 한 커밋)에서 병합합니다. 이 병합은 일반적인 병합과 같은 병합입니다. 갈등은 평상시처럼 해결되어야하며 버릴 필요가 없습니다.
- 병합 :
hg merge 14
- 커밋 :
hg commit -m "Merging in last good state of BRANCH_V8"
지금 상황은 :@ BRANCH_V9-17-BRANCH_V8의 마지막 양호한 상태에서 병합 | \ | | o BRANCH_V8-16-잘못된 병합에서 되 돌리는 데 사용되는 두 개의 헤드 병합 | | | \ | + --- o BRANCH_V8-15-BRANCH_V9에서 잘못된 병합 버리기 | | | | | o | | BRANCH_V8-14-BRANCH_V9에서 잘못된 병합을 수정하기 위해 BRANCH_V8에서 커밋 생성 | | | | | | o | BRANCH_V8-13-잘못된 병합 직후 중요한 커밋 | | | / + --- o BRANCH_V8-12-BRANCH_V9에서 잘못된 병합 | | / | o BRANCH_V8-11-BRANCH_V8에 주석 추가 | | o | BRANCH_V9-10-BRANCH_V9에 대한 마지막 커밋 | |
- 병합 :
- BRANCH_V8 + 수정 사항의 잘못된 병합에 병합하고 모든 변경 사항을 버리십시오.
- 병합 :
hg merge 15
- 모든 변경 사항 되돌리기 :
hg revert -a --no-backup -r 17
- 병합 커밋 :
hg commit -m "Merging in bad merge from BRANCH_V8 and its fix and throwing it all away"
현재 상황 :@ BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away |\ | o BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8 | |\ +-----o BRANCH_V8 - 16 - merged two heads used to revert from bad merge | | | | o---+ | BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9 | | | | | | o | BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9 | | | | +-----o BRANCH_V8 - 13 - important commit right after the bad merge | | | o---+ BRANCH_V8 - 12 - wrong merge from BRANCH_V9 |/ / | o BRANCH_V8 - 11 - adding comment on BRANCH_V8 | | o | BRANCH_V9 - 10 - last commit on BRANCH_V9 | |
- 병합 :
- Merge in the left-over changes from BRANCH_V8 :
- merge :
hg merge BRANCH_V8
- commit :
hg commit -m "merging changes from BRANCH_V8"
- merge :
In the end the situation looks like this:
@ BRANCH_V9 - 19 - merging changes from BRANCH_V8 |\ | o BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away | |\ | | o BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8 | | |\ o | | | BRANCH_V8 - 16 - merged two heads used to revert from bad merge |\| | | | o---+ BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9 | | | | | | | o BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9 | | | | o | | | BRANCH_V8 - 13 - important commit right after the bad merge |/ / / o---+ BRANCH_V8 - 12 - wrong merge from BRANCH_V9 |/ / | o BRANCH_V8 - 11 - adding comment on BRANCH_V8 | | o | BRANCH_V9 - 10 - last commit on BRANCH_V9 | |
After all these steps, in which you do not have to check any diff manually, BRANCH_V8 and BRANCH_V9 are correct, and future merges from BRANCH_V8 to BRANCH_V9 will be correct as well.
In a pinch, you can export the repository to a bunch diffs, edit history, and then glue back together just what you want - into a new repository, so no risk of damage. Probably not too bad for your example, but I don't know what the real history looks like.
I referenced this page while performing a simpler operation:
http://strongdynamic.blogspot.com/2007/08/expunging-problem-file-from-mercurial.html
OK, start by making a new empty repository in a separate directory from the broken repository (hg init). Now, pull up to and including the last known good version into the new repository; make sure you do not pull the bad merge and do pull everything before it. In the old repository, update to the last known good version of A, and do this:
hg graft r1 r2 r3
where r1-3 are changes made after the botched merge. You may get conflicts at this point; fix them.
This should produce new changes against the last known good version of A. Pull those new changes into the new repository. Just to double check that you didn't miss anything, do an hg incoming against the old repository. If you see anything other than the botched merge and r1-3, pull it.
Throw the old repository away. You're done. The merge isn't in the new repository at all and you never had to rewrite history.
So you want to merge just some changesets from B into A? Backing out changesets like you have been doing is a really bad idea as you have already suffered.
You should either use the transplant extension or have a third branch where you make common changes to merge into both A and B.
After much discussion with some of the helpful people on #mercurial on freenode, mpm has provided a partial solution that seems to work for my test case ( I generated a fake repository trying to replicate the scenario )
However, on my actual repository, for reasons I don't quite understand, it is still less than perfect.
Here is a diagram of the currently proposed way of resolving this problem:
[Original image lost]
Its now less of a problem to fix, but I'm still having to compare diffs ( ie: b46:b11 vs b46:b8 , a43:a10 vs a43:a9 ) and hand edit some changes back in.
Not closing this question/taking an answer until I get a guaranteed way that works on any repository.
Important
Anyone trying this stuff should clone their repository and play with it like a sandbox first. As you should be doing with any merge process, because that way if it goes wrong you can just throw it out and start again.
참고URL : https://stackoverflow.com/questions/265944/backing-out-a-backwards-merge-on-mercurial
'program story' 카테고리의 다른 글
Eclipse의 패키지 탐색기 배경색은 Windows 테마를 따릅니다. (0) | 2020.10.15 |
---|---|
R, Sweave 및 LaTeX를 사용하여 출판 품질 표를 만들기위한 일반 가이드 (0) | 2020.10.15 |
최고의 크로스 플랫폼 (휴대용) 임의 정밀도 수학 라이브러리 (0) | 2020.10.15 |
계단식 섹션이있는 Razor 중첩 레이아웃 (0) | 2020.10.15 |
Android 기본 에뮬레이터의 대안 (0) | 2020.10.15 |