자식 기록에서 특정 개정을 어떻게 제거합니까?


213

git history가 다음과 같다고 가정하십시오.

12 34 5

1–5는 별도의 개정판입니다. 1, 2, 4 및 5를 계속 유지하면서 3을 제거해야합니다. 어떻게해야합니까?

삭제 후 수백 개의 개정이있을 때 효율적인 방법이 있습니까?


이 질문은 잘못 정의되어 있습니다. 저자가 1-2- (3 + 4) -5 또는 1-2-4-5를 원한다고 명시 적으로 말하지는 않는다
RandyTek

14
8 년 후, 어떤 문제를 해결하려고했는지 정확하게 말할 수 없습니다. 그러나 자식에는 항상 무언가를 할 수있는 방법이 많이 있으며, 여러 사람들이 좋아하는 많은 답변이 있으므로 모호성이 너무 많은 사람들에게 많은 어려움을 초래하지는 않는다고 생각합니다.
1800 INFORMATION

1
git rebase --onto 2 3 HEAD꽤 많은 수단 3 머리 (HEAD이 경우 선택 사항입니다, 또는 5) 사이의 커밋과, (2) 상에 리베이스
neaumusic

답변:


76

개정판 3과 4를 단일 개정판으로 결합하기 위해 git rebase를 사용할 수 있습니다. 개정 3의 변경 사항을 제거하려면 대화식 리베이스 모드에서 편집 명령을 사용해야합니다. 변경 사항을 단일 개정으로 결합하려면 squash를 사용하십시오.

이 스쿼시 기법을 성공적으로 사용했지만 이전에 개정판을 제거 할 필요는 없었습니다. "Splitting commits"아래의 git-rebase 문서는이를 이해하기에 충분한 아이디어를 제공 할 것입니다. (또는 다른 사람이 알고있을 수도 있습니다).

로부터 자식 문서 :

그대로 유지하려는 가장 오래된 커밋으로 시작하십시오.

git rebase -i <after-this-commit>

주어진 커밋 뒤에 오는 현재 분기의 모든 커밋 (병합 커밋 무시)으로 편집기가 시작됩니다. 이 목록의 커밋을 마음의 내용으로 재정렬하고 제거 할 수 있습니다. 목록은 다음과 같이 다소 비슷합니다.

deadbee를 선택하십시오이 커밋의 한 줄
다음 커밋의 한 줄
...

oneline 설명은 순전히 당신의 즐거움을위한 것입니다. git-rebase는 커밋 이름 (이 예제에서는 "deadbee"및 "fa1afe1")을 보지 않으므로 이름을 삭제하거나 편집하지 마십시오.

"pick"명령을 "edit"명령으로 대체하면 커밋을 적용한 후 git-rebase에게 중지하도록 지시하여 파일 및 / 또는 커밋 메시지를 편집하고 커밋을 수정 한 후 재베이스 작업을 계속할 수 있습니다.

둘 이상의 커밋을 하나로 묶으려면 두 번째 이후 커밋에 대해 "pick"명령을 "squash"로 바꾸십시오. 커밋에 다른 작성자가있는 경우 스쿼시 된 커밋이 첫 번째 커밋의 작성자에게 기인합니다.


42
-1 질문이 잘 정의되었지만이 답변은 명확하지 않습니다. 저자는 정확한 해결책이 무엇인지 말하지 않습니다.
Aleksandr Levchuk

1
이것은 잘못된 리드입니다. SPLITTING COMMITS 섹션이 올바르지 않습니다. 매뉴얼에서 훨씬 더 높은 내용을 읽으려면 @Rares Vernica의 답변을 참조하십시오.
Aleksandr Levchuk 8

1
@AleksandrLevchuk 질문은 잘 정의되어 있지 않습니다. 3의 변경 세트를 유지할지 또는 버릴지에 대한 질문의 표현 방식이 불분명합니다. 변경 사항을 버릴 경우 다른 답변이 더 쉬운 접근 방법을 제공한다는 데 동의합니다. 그러나 변경 사항을 유지하려면 순전히 미용 작업입니다. 두 접근법 모두 다른 사람들이 결함이있는 역사를 기반으로 작업을 수행했을 경우 위험한 방식으로 역사를 다시 작성합니다. 이 경우 미용 정리를 수행해서는 안되며 변경 삭제는 git revert를 통해 더 잘 수행됩니다.
Theodore Murdock

124

이 의견에 따르면 (그리고 이것이 사실인지 확인) rado의 대답은 매우 가깝지만 git을 분리 된 헤드 상태로 둡니다. 대신, HEAD이것을 제거 하고 사용하여 현재 <commit-id>지점에서 제거하십시오 .

git rebase --onto <commit-id>^ <commit-id>

1
commit-id를 기반으로 기록에서 commit-id를 제거하는 방법을 말해 줄 수 있다면 내 영웅이 될 것입니다.
kayleeFrye_onDeck

마술 명령이 무엇을하는지 설명에 답해 주시겠습니까? 즉, 각 매개 변수가 나타내는 것은 무엇입니까?
Alexandroid

이것은 굉장하지만 역사에서 첫 번째 커밋을 제거하려면 어떻게해야합니까? (그래서 내가 온 이유는 : P)
Sterling Camden

2
어떤 이유로 든, 이것을 실행할 때 아무 일도 일어나지 않습니다. 그러나 변경 ^하여 ~1작동 하게 만들었습니다.
안티몬

늦었지만 병합 충돌이 발생하면 리베이스를 중단 한 다음 --strategy-option theirs끝에 다시 실행하십시오 .
LastStar007

122

다음은 제거하려는 대상 <commit-id>만 알고 비 대화식으로 특정을 제거하는 방법입니다 <commit-id>.

git rebase --onto <commit-id>^ <commit-id> HEAD

2
나도 일했다. Btw, ^ 연산자는 무엇을합니까? 지정된 커밋 이후 다음 커밋을 의미합니까?
hopia

3
@hopia 지정된 커밋의 첫 번째 부모를 의미합니다. "git help 개정"참조
Emil Styrke

12
HEAD머리가 분리되지 않도록 생략하려면 @kareem의 권장 사항을 참조하십시오 .
mklement0

1
얼마나 많은 커밋을 검색해야하는지 파악하는 것보다 훨씬 쉽습니다.
Dana Woodman

1
이것은 굉장하지만 역사에서 첫 번째 커밋을 제거하려면 어떻게해야합니까? (그래서 내가 온 이유는 : P)
Sterling Camden

76

앞에서 언급했듯이 git-rebase (1) 는 친구입니다. 커밋이 master지점 에 있다고 가정하면 다음을 수행합니다.

git rebase --onto master~3 master~2 master

전에:

1---2---3---4---5  master

후:

1---2---4'---5' master

git-rebase (1)에서 :

rebase를 사용하여 커밋 범위를 제거 할 수도 있습니다. 다음과 같은 상황이 발생하면

E---F---G---H---I---J  topicA

그런 다음 명령

git rebase --onto topicA~5 topicA~3 topicA

커밋 F와 G가 제거됩니다.

E---H'---I'---J'  topicA

이것은 F와 G에 어떤 식 으로든 결함이 있거나 주제 A의 일부가되어서는 안됩니다. --onto에 대한 인수와 매개 변수는 유효한 commit-ish 일 수 있습니다.


3
이러면 안되나요 --onto master~3 master~1?
Matthias

3
마지막 커밋을 삭제하려면 --onto ~ master ~ 1 master
MikeHoss

이 솔을 가지고 가고 싶습니다. 하지만 MERGE CONFLICT오류가 발생합니다. stackoverflow.com/questions/2938301/remove-specific-commit에 언급 된 시나리오를 사용 했으며 해당 예에서 두 번째 커밋을 제거 할 수 없습니다.
maan81

22

개정 3에서 변경 한 내용을 제거하기 만하면 git revert를 사용할 수 있습니다.

힘내 되돌리기는 단순히 되 돌리는 개정의 모든 변경 사항을 취소하는 변경 사항으로 새 개정을 만듭니다.

이는 원하지 않는 커밋과 해당 변경 사항을 제거하는 커밋에 대한 정보를 유지한다는 의미입니다.

되돌리기는 기본적으로 표준 커밋이기 때문에 누군가가 저장소에서 가져 온 것이 가능하다면 훨씬 더 친숙 할 것입니다.


4
불행히도 누군가가 실수로 저장소에 100MB의 쓰레기를 커밋하여 크기를 늘리고 웹 인터페이스를 느리게 만들기 때문에 좋은 해결책이 아닙니다.
Stephen Smith

18

지금까지의 모든 답변은 후행 문제를 해결하지 못합니다.

삭제 후 수백 개의 개정이있을 때 효율적인 방법이 있습니까?

단계는 다음과 같지만 참조 용으로 다음과 같은 기록을 가정합니다.

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C : 커밋이 제거 된 직후 커밋 (깨끗한)

R : 제거 할 커밋

B : 커밋을 제거하기 직전에 커밋을 제거하십시오 (기본)

"수백 개의 개정"제약 때문에 다음과 같은 전제 조건을 가정합니다.

  1. 당신이 존재하기를 원하지 않는 당혹스러운 커밋이 있습니다.
  2. 그 난처한 커밋에 실제로 의존하는 ZERO 후속 커밋이 있습니다 (복귀시 충돌 없음)
  3. 당신은 당신이 수백 개의 중재 커밋의 '커미터 (Committer)'로 등록 될 것을 신경 쓰지 않습니다 ( 'Author'는 보존 될 것입니다)
  4. 당신은 저장소를 공유하지 않았습니다
    • 또는 실제로 역사를 복제 한 모든 사람들에게 새로운 역사를 사용하도록 설득하기 위해 그 영향력을 충분히 발휘할 수 있습니다.
    • 그리고 당신 역사다시 쓰는 것에 신경 쓰지 않습니다

이것은 매우 제한적인 제약 조건이지만 실제로이 코너 사례에서 작동하는 흥미로운 답변이 있습니다.

단계는 다음과 같습니다.

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

실제로 충돌이 없으면 더 이상 중단하지 않아도됩니다. 갈등이있는 경우 갈등을 해결 rebase --continue하거나 당황 스러움으로 살기로 결정할 수 있습니다.rebase --abort .

이제 master더 이상 커밋 R 이 없습니다. save이전에 어디 있었는지에 분기점이 경우에 당신은 화해하고 싶다.

다른 사람이 새로운 역사로 이체하는 방법은 귀하에게 달려 있습니다. 당신은 알게 될 필요가있을 것이다 stash, reset --hard하고 cherry-pick. 그리고 당신은 삭제할 수 있습니다 base, remove-mesave지점을


이 150000 번을 어떻게 좋아합니까?
Gena Moroz

누군가가 150MB 파일을 커밋 한 지점의 기록 중간에서 3 개의 커밋을 순서대로 제거하도록 일했습니다.
Marcos

3

나도 비슷한 상황에 처했다. 아래 명령을 사용하고 3 차 커밋을 선택하는 동안 대화식 리베이스를 사용하십시오.

git rebase -i remote/branch

2

여기 제가 직면 한 시나리오와 그 해결 방법이 있습니다.

[branch-a]

[Hundreds of commits] -> [R] -> [I]

여기 R에 내가 제거해야 할 I커밋이 있으며 그 뒤에 오는 단일 커밋입니다R

나는 되돌리기 커밋을 만들어 함께 뭉쳤다

git revert [commit id of R]
git rebase -i HEAD~3

대화식 리베이스 스쿼시 동안 마지막 2 개의 커밋.


0

rado와 kareem의 답변은 나를 위해 아무 것도하지 않습니다 ( "현재 지점이 최신입니다."메시지 만 나타남). 아마도 이것은 '^'기호가 Windows 콘솔에서 작동하지 않기 때문에 발생합니다. 그러나에있어서 '~ 1'로 해결할 문제의 주석 치환 '^'.

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