변경 사항을 유지하면서 Git 리포지토리에서 선택된 커밋 로그 항목을 제거하는 방법은 무엇입니까?


241

항목이 커밋 로그에 표시되지 않도록 선형 커밋 트리에서 선택한 커밋 로그 항목을 제거하고 싶습니다.

내 커밋 트리는 다음과 같습니다.

R--A--B--C--D--E--HEAD

커밋 로그에 표시되지 않도록 B 및 C 항목을 제거하고 싶지만 A에서 D 로의 변경 사항은 유지해야합니다. 아마도 단일 커밋을 도입하여 B와 C가 BC가되고 나무가 보이도록 할 수 있습니다.

R--A--BC--D--E--HEAD

또는 이상적으로 A가 D를 직접 온 후에. A에서 B로, B에서 C로, C에서 D 로의 변화를 나타내는 D '.

R--A--D'--E--HEAD

이게 가능해? 그렇다면 어떻게?

이것은 상당히 새로운 프로젝트이므로 현재 지점이 없으므로 병합도 없습니다.


@ xk0der : "commits"가 올바른 용어입니다. rebase오래된 커밋을 제거하거나 새로운 커밋을 만들 수 있습니다. "커밋 로그 항목"의 의미를 모르겠습니다.
jfs

@JFSebastian "commit log"에 문제가 보이지 않습니다-모든 커밋 로그. 그리고 실제 변경 사항 (커밋)을 유지하면서 로그에서 몇 가지 항목을 삭제하고 싶었습니다.
xk0der

@ xk0der : 자식 커밋 내용으로 주소 를 변경하는 경우, 즉 어떤 커밋 예를 들어, 로그 메시지를; 새로운 커밋을 만듭니다. 당신은 수있는 자식의이 자식없이 커밋 읽고 직접 참조하십시오 .
jfs

@JFSebastian-링크 고마워요-알아요-하지만 그 기술력은 내가 직면 한 문제와 그 문제를 어떻게 변화 시키는가? 나는 그렇지 않다고 생각한다. 결국 : 나는 "커밋 로그 메시지"를 제거하고 싶다- "커밋 변경"을 제거하지 않고-내 질문을 다시 읽으십시오-특히 두 번째 단락. 더 추가하려면 git log"커밋 로그" git-scm.com/docs/git-log를 표시하십시오 . 그리고 변경 사항이 아니라 해당 로그에서 두 항목을 제거하고 싶었습니다.
xk0der

답변:


273

git-rebase (1) 은 정확히 그렇게합니다.

$ git rebase -i HEAD~5

git awsome-ness [git rebase --interactive] 는 예제를 포함합니다.

  1. git-rebase공개 (원격) 커밋에 사용하지 마십시오 .
  2. 작업 디렉토리가 깨끗해야합니다 ( commit또는 stash현재 변경 사항).
  3. 위 명령을 실행하십시오. 시작합니다 $EDITOR.
  4. pick이전 CD로 교체하십시오 squash. 커밋을 삭제하려면 해당 라인을 삭제하면됩니다.

길을 잃은 경우 다음을 입력하십시오.

$ git rebase --abort  

빠른 답변 감사합니다. A를 체크 아웃하고 리베이스를 git rebase -i D [A]합니까?
xk0der


3
원격 저장소에서 어떻게 할 수 있습니까?
Eray

6
@ 레이 : push -f변경 사항 만. 혼자 일하지 않으면하지 마십시오.
jfs

2
@ ripper234 : git-rebase블로그 게시물에 대한 수동 및 웨이 백 머신 을 가리키는 링크를 수정 했습니다.
jfs

75
# detach head and move to D commit
git checkout <SHA1-for-D>

# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>

# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>

# Re-apply everything from the old D onwards onto this new place 
git rebase --onto HEAD <SHA1-for-D> master

이것은 또한 작동하며 소프트 리셋이 무엇인지 이해하는 데 도움이되었습니다. 물론 "최상위"답변도 정확하고 짧지 만이 답변에 감사드립니다.
cgp

41

제거하려는 커밋 ID 만 알고 특정 커밋 ID를 제거하는 방법은 다음과 같습니다.

git rebase --onto commit-id^ commit-id

이렇게하면 커밋에 의해 도입 된 변경 사항이 실제로 제거됩니다.


7
이 명령의 여분의 HEAD는 리베이스가 바람직하지 않은 '분리 된 HEAD'로 마무리되도록합니다. 생략해야합니다.
Frosty

3
이것은 내 commit-id에 도입 된 변경 사항을 되돌리고 OP는 변경 사항을 유지하고 커밋을 스쿼시합니다.
CB Bailey

1
-1은 OP가 요청한 것을 수행하지 않기 때문에 (명시 적으로 보유하고자하는 것을 파괴 함).
Emil Styrke

1
OP가 요청한 것을 수행하지는 않지만 정확히 필요한 것이므로 유용한 답변을 얻으려면 +1입니다.
Edvins

20

JF Sebastian의 답변을 확장하려면 :

git-rebase를 사용하면 커밋 히스토리를 쉽게 변경할 수 있습니다.

git rebase --interactive를 실행하면 $ EDITOR에 다음이 표시됩니다.

pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

행을 이동하여 커밋 순서를 변경하고 행을 삭제하여 해당 커밋을 제거 할 수 있습니다. 또는 두 커밋을 단일 커밋 (이전 커밋은 위의 커밋), 커밋 편집 (변경된 내용) 또는 커밋 메시지 변경에 대한 명령을 추가 할 수 있습니다.

선택은 단지 그 커밋을 내버려두고 싶다는 것을 의미한다고 생각합니다.

(예는 여기에서 )


14

다음 을 사용하여 예제에서 B와 C를 비 대화식으로 제거 할 수 있습니다 .

git rebase --onto HEAD~5 HEAD~3 HEAD

또는 상징적으로

git rebase --onto A C HEAD

B와 C의 변경 사항 은 D에 있지 않습니다 . 그들은 사라질 것이다.


자세한 내용은 여기를 참조하십시오 : sethrobertson.github.io/GitFixUm/fixup.html#remove_deep
Max

3

한 가지 더

git rebase -i ad0389efc1a79b1f9c4dd6061dca6edc1d5bb78a (C's hash)
and
git push origin master  -f

기본으로 사용하려는 해시를 선택하면 위의 명령은 대화식으로 만들어야 모든 최상위 메시지를 스쿼시 할 수 있습니다 (가장 오래된 것을 남겨 두어야 함)


2

A의 SHA1에서 다른 브랜치를 만들고 원하는 변경 사항을 체리 피킹 하여이 프로세스가 훨씬 안전하고 이해하기 쉽다는 것을 알았습니다. 그런 다음 이전 분기를 쉽게 제거하고 새 분기의 이름을 쉽게 바꿀 수 있습니다.

git checkout <SHA1 of A>
git log #verify looks good
git checkout -b rework
git cherry-pick <SHA1 of D>
....
git log #verify looks good
git branch -D <oldbranch>
git branch -m rework <oldbranch>

이렇게하면 E 커밋도 잃어 버리지 않습니까? 내가 이해했듯이 마스터를 삭제하고 재 작업의 이름을 마스터로 바꿉니다 (ABCDE 흐름이 마스터 분기 인 것을 고려하십시오).
Renan Bandeira

1

모든 사람들의 답변을 수집했습니다. (git plz를 처음 사용하는 경우 참조 용으로 만 사용)

커밋을 삭제하는 git rebase

자식 로그

-first check from which commit you want to rebase

자식 rebase -i HEAD ~ 1

-Here i want to rebase on the second last commit- commit count starts from '1')
-this will open the command line editor (called vim editor i guess)

그러면 화면이 다음과 같이 보일 것입니다 :

pick 0c2236d 새 줄을 추가했습니다.

2a1cd65..0c2236d를 2a1cd65 (1 명령)로 리베이스

#

명령 :

p, pick = 커밋 사용

r, reword = 커밋 사용, 커밋 메시지 편집

e, 편집 = 커밋 사용, 수정을 위해 중지

s, squash = 커밋을 사용하지만 이전 커밋에 통합

f, fixup = "squash"와 같지만이 커밋의 로그 메시지를 버립니다.

x, exec = 쉘을 사용하여 명령 실행 (나머지 행)

d, 삭제 = 커밋 제거

#

이 줄은 순서를 바꿀 수 있습니다. 그것들은 위에서 아래로 실행됩니다.

#

여기에서 줄을 제거하면 커밋이 손실됩니다.

#

그러나 모든 것을 제거하면 리베이스가 중단됩니다.

#

빈 커밋은 주석 처리됩니다 ~ ~

~
~
~
~
~
~
~
~
~

필요에 따라 첫 번째 줄을 변경하십시오 (위의 명령을 사용하여 커밋 등을 제거하십시오.) 편집이 완료되면 ': x'를 눌러 편집기를 저장하고 종료하십시오 (vim 편집기 전용)

그리고

자식 푸시

문제가 나타나면 원격으로 변경 사항을 강제로 푸시해야합니다 (ITS VERY CRITICAL : 팀에서 작업하는 경우 강제로 푸시하지 마십시오)

자식 푸시 -f 원점


-1

이것을 위해 git cherry-pick을 사용할 수 있습니다. 'cherry-pick'은 지금 지점에 커밋을 적용합니다.

그런 다음

git rebase --hard <SHA1 of A>

그런 다음 D 및 E 커밋을 적용하십시오.

git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>

이것은 B와 C 커밋을 생략합니다. B없이 브랜치에 D 커밋을 적용하는 것이 불가능할 수 있다고 말 했으므로 YMMV.


2
OP는 변경 사항을 삭제하지 않고 B, C, D 커밋을 결합하려고합니다.
jfs

3
나는 당신이 의미 생각 reset --hard,하지 rebase --hard(존재하지 않는)
마우 페르에게
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.