역사에 묻힌 Git 커밋을 어떻게 분할 할 수 있습니까?


292

나는 내 역사를 흐트러 뜨리고 약간의 변화를 원합니다. 문제는 관련이없는 두 가지 변경 사항이있는 커밋이 있으며이 커밋은 로컬 (푸시되지 않은) 기록의 다른 변경 사항으로 둘러싸여 있습니다.

이 커밋을 푸시하기 전에 분할하고 싶지만, 내가보고있는 대부분의 가이드는 가장 최근의 커밋 또는 커밋되지 않은 로컬 변경을 분할하는 것과 관련이 있습니다. 그 이후로 내 커밋을 "재실행"할 필요없이 역사에 조금 묻힌 커밋 에이 작업을 수행하는 것이 가능합니까?


답변:


450

rebase 맨 페이지에 커밋 분할에 대한 안내서가 있습니다 . 빠른 요약은 다음과 같습니다.

  • 대상 커밋 (예 :)을 포함하여 대화식 리베이스를 수행하고 git rebase -i <commit-to-split>^ branch편집하도록 표시합니다.

  • 리베이스가 해당 커밋에 도달하면을 사용 git reset HEAD^하여 커밋 전에 재설정하지만 작업 트리는 그대로 유지하십시오.

  • 변경 사항을 점차적으로 추가하고 커밋하여 원하는만큼 커밋합니다. add -p지정된 파일에서 일부 변경 사항 만 추가하는 데 유용 할 수 있습니다. commit -c ORIG_HEAD특정 커밋에 대해 원래 커밋 메시지를 다시 사용하려는 경우에 사용하십시오 .

  • 커밋중인 것을 테스트하려면 (좋은 아이디어!) 커밋 git stash하지 않은 부분 (또는 stash --keep-index커밋하기 전에 ) 을 숨기고 테스트 한 다음 git stash pop나머지는 작업 트리로 되돌립니다. 모든 수정 사항이 커밋 될 때까지 계속 커밋하십시오. 즉, 깨끗한 작업 트리가 있어야합니다.

  • git rebase --continue지금 분할 커밋 후에 커밋 적용을 계속하려면 실행하십시오 .


17
...하지만 커밋이 분할 된 후 이미 기록을 푸시했다면 아무 것도하지 마십시오.
wilhelmtell

29
@wilhelmtell : OP가이 역사를 추진하지 않았다고 명시 적으로 말했기 때문에 나는 평소 "잠재적으로 위험한; 업스트림 리베이스에서 복구"보일러 플레이트를 생략했습니다.
Cascabel

2
그리고 당신은 완벽하게 읽었습니다. 나는 그것이 역사를 공유하지 않았다고 명시했을 때 'boilerplate'을 피하려고했습니다 :) 어쨌든, 나는 당신의 제안으로 성공했습니다. 그러나 사실 후에이 일을하는 것은 큰 고통입니다. 나는 여기서 교훈을 배웠으며, 그것은 커밋이 올바르게 시작되도록하는 것입니다!
Ben

2
첫 번째 단계는로 더 잘 표시 될 수 있습니다 git rebase -i <sha1_of_the_commit_to_split>^ branch. 또한 git gui분할 작업을위한 훌륭한 도구로, 파일의 다른 부분을 다른 커밋에 추가하는 데 사용할 수 있습니다.
Qiang Xu

3
@ QiangXu : 첫 번째는 합리적인 제안입니다. 두 번째는 정확하게 내가 제안한 이유 입니다.이 부서에서 할 수있는 git add -p것보다 더 많은 작업을 수행 git gui할 수 있습니다 (특히 덩어리를 편집하고 현재 덩어리에서 시작하여 모든 것을 준비하고 정규 표현식으로 덩어리를 검색합니다).
Cascabel

3

Magit으로 하는 방법은 다음과 같습니다 .

commit ed417ae가 변경하고 싶다고 가정하십시오. 여기에는 두 가지 관련없는 변경 사항이 포함되며 하나 이상의 커밋 아래에 묻 힙니다. 히트 lled417ae에 대한 로그 및 탐색을 표시 :

초기 로그

그런 다음 rrebase 팝업을 열려면 누르 십시오.

팝업을 리베이스

그리고 m커밋을 수정합니다.

@분할하려는 커밋에 어떻게 있는지 확인하십시오. 즉, HEAD가 해당 커밋에 있음을 의미합니다.

커밋 수정

HEAD를 부모로 옮기고 자하므로 부모 (47e18b3)로 이동하여 x( magit-reset-quickly, o사용중인 경우 바인딩 됨 evil-magit)을 누르고 "예, 커밋을 의미했습니다"라고 입력하십시오. 이제 로그는 다음과 같아야합니다.

재설정 후 로그

이제, 충돌 q후 일반 unstage 사용, 일반 Magit 상태로 이동 u, 첫 번째 커밋에 가서 범하지 않는 것을 unstage에 명령을 c평소와 같이 나머지 다음 s다케와 commit에가는 것을 두 번째 커밋 할 때 : rrebase 팝업을 열려면 누르 십시오

팝업을 리베이스

그리고 다른 하나 r는 계속하면 끝입니다! ll이제 보여줍니다 :

모든 완료 로그


1

커밋을 분할 하고이 커밋 앞에 새 커밋을<commit> 추가 하고 작성자 날짜를 저장하려면 다음 단계를 따르십시오.<commit>

  1. 커밋을 편집 하기 전에 <commit>

    git rebase -i <commit>^^
    

    NB : 아마도 편집해야 할 수도 <commit>있습니다.

  2. 체리 <commit>인덱스로 선택

    git cherry-pick -n <commit>
    
  3. 색인에서 불필요한 변경 사항을 대화식으로 재설정하고 작업 트리를 재설정

    git reset -p && git checkout-index -f -a
    

    대안으로, 불필요한 변경 사항을 대화식으로 숨기십시오. git stash push -p -m "tmp other changes"

  4. 다른 사항을 변경하고 (있는 경우) 새 커밋을 만듭니다.

    git commit -m "upd something" .
    

    선택적으로 중간 커밋을 더 추가하려면 항목 2-4를 반복하십시오.

  5. 계속 rebasing

    git rebase --continue
    

0

하나의 파일에서만 컨텐츠를 추출하려는 경우 더 빠른 버전이 있습니다. 대화식 rebase가 더 이상 대화식이 아니기 때문에 더 빠릅니다 (마지막 커밋에서 추출한 다음 전혀 rebase 할 필요가 없음)

  1. 편집기를 사용하여에서 추출하려는 행을 삭제하십시오 the_file. 닫기 the_file. 그것은 당신이 필요한 유일한 판이며, 나머지는 모두 git 명령입니다.
  2. 색인에서 삭제를 준비하십시오.

    git  add  the_file
    
  3. 색인에 영향을주지 않고 방금 삭제 한 행을 파일로 다시 복원하십시오 !

    git show HEAD:./the_file > the_file
    
  4. "SHA1"은 라인을 추출하려는 커밋입니다.

    git commit -m 'fixup! SHA1' 
    
  5. 3 단계에서 복원 한 컨텐츠로 새로운 커밋을 만듭니다.

    git commit -m 'second and new commit' the_file 
    
  6. 편집하지 말고 중지 / 계속하지 말고 모든 것을 수락하십시오.

    git rebase --autosquash -i SHA1~1
    

물론 추출 할 커밋이 마지막 커밋 일 때 더 빠릅니다.

4. git commit -C HEAD --amend
5. git commit -m 'second and new commit' thefile
6. no rebase, nothing

사용하는 경우 magit4, 5 및 6 단계는 단일 조치입니다. 확약, 즉시 수정


-2

아직 푸시하지 않은 경우을 사용하십시오 git rebase. 또한 git rebase -i대화식으로 커밋을 이동 하는 데 사용하십시오 . 문제가되는 커밋을 맨 앞으로 옮긴 다음 원하는대로 분할하고 패치를 다시 옮길 수 있습니다 (필요한 경우).


14
어디로 든 이동할 필요가 없습니다. 있는 곳으로 나눕니다.
Cascabel

1
불행히도 커밋 후의 역사 중 일부가 그것에 의존하기 때문에 이것은 효과가 없습니다. 그래서 나는 조금 제한적입니다. 그러나 이것이 나의 첫번째 선택이었을 것입니다.
Ben

@Ben : 괜찮습니다-나중에 커밋을 변경할 필요가 없습니다 (변경 사항 중 일부를 버리지 않고 모든 변경 사항을 유지한다고 가정). 자세한 내용은 여기 -stackoverflow.com/questions/1440050/…
Ether
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.