git으로 커밋의 일부를 되돌리기


144

자식의 특정 커밋을 되돌리고 싶습니다. 불행히도 우리 조직은 여전히 ​​CVS를 표준으로 사용하므로 CVS에 다시 커밋하면 여러 git commit이 하나로 롤백됩니다. 이 경우 원래 git commit을 단일화하고 싶지만 불가능합니다.

git add --patch커밋의 어느 부분을 되돌릴 것인지 결정하기 위해 diff를 선택적으로 편집 할 수있는 것과 비슷한 접근법이 있습니까?


여기에 더 많은 솔루션이 있지만 특정 파일로 부분 되돌리기를 제한하는 데 중점을 둡니다.
— ntc2

답변:


226

--no-commit( -n) 옵션을 사용 git revert하여을 변경 한 다음 단계를 취소하고 다음을 사용하십시오 git add --patch.

$ git revert -n $bad_commit    # Revert the commit, but don't commit the changes
$ git reset HEAD .             # Unstage the changes
$ git add --patch .            # Add whatever changes you want
$ git commit                   # Commit those changes

참고 : git add --patch를 사용하여 추가 한 파일은 유지하려는 파일이 아니라 되돌리려는 파일입니다.


13
커밋 후 git :에 익숙하지 않은 사용자를 위해 최종 필수 명령을 추가하는 git reset --hard것이 좋습니다.
— tremby

15
git reset --hard원하는 편집 내용을 잃을 수 있으므로 초보자에게는 위험합니다. 대신에 익숙해 git status이 힌트, git checkout -- FILE..보다 안전하게 되돌리기 것들.
— Tino

무엇 과격한 누락 git; git revert그냥 --patch논쟁을 해야합니다 .
— Kaz

@Kaz : git revert전체 커밋을 되 돌리는 데 사용됩니다. git checkout -p되돌릴 비트를 대화식으로 선택 하는 데 사용할 수 있습니다 .
— mipadi

1
또한 (아마도) 명백한 내용을 추가하고 싶습니다 . 먼저 작업 내용을 저장하십시오 . 어느 commit첫째, 또는 stash다음보십시오 revert.
— Felipe Alvarez

39

나는 다음을 성공적으로 사용했다.

먼저 전체 커밋을 되돌리고 (인덱스에 넣음) 커밋하지 마십시오.

git revert -n <sha1>  # -n is short for --no-commit

그런 다음 색인에서 되 돌린 GOOD 변경 사항을 대화식으로 제거하십시오.

git reset -p          # -p is short for --patch  

그런 다음 나쁜 변경 사항을 역으로 비교하십시오.

git commit -m "Partially revert <sha1>..."

마지막으로 되 돌린 GOOD 변경 사항 (재설정 명령으로 준비되지 않은 변경 사항)은 여전히 ​​작업 트리에 있습니다. 그들은 청소해야합니다. 작업 트리에 커밋되지 않은 다른 변경 사항이없는 경우 다음을 수행 할 수 있습니다.

git reset --hard

5
이것은 reset HEAD .작업 디렉토리의 최종 정리가 필요하지 않기 때문에 허용되는 답변 (을 사용하는 )에 대한 탁월한 대안이 아닙니까?
— Steven Lu

2
이 대답은 뒤에 reset -p나오는 것보다 짧기 때문에 우수 reset HEAD합니다 add -p. 그러나 재설정 된 "양호한"덩어리는 여전히 커밋 후에 작업 디렉토리에 있기 때문에 여전히 정리가 필요합니다.
— Chiel ten Brinke

원하는 변경 사항을 대화식으로 제거하는 것이 혼동스럽고 오류가 발생하기 쉬우므로 특히 수정이 필요한 경우이 답변이 우수하지 않습니다 .
— Kaz

5

개인적으로, 나는 자동 생성 된 커밋 메시지를 재사용하고 최종 커밋하기 전에 "부분적으로"라는 단어를 편집하고 붙일 수있는 기회를 제공하는이 버전을 선호합니다.

# generate a revert commit
# note the hash printed to console on success
git revert --no-edit <hash to revert>

# undo that commit, but not its changes to the working tree
# (reset index to commit-before-last; that is, one graph entry up from HEAD)
git reset HEAD~1

# interactively add reversions
git add -p

# commit with pre-filled message
git commit -c <hash from revert commit, printed to console after first command>

# reset the rest of the current directory's working tree to match git
# this will reapply the excluded parts of the reversion to the working tree
# you may need to change the paths to be checked out
# be careful not to accidentally overwrite unsaved work
git checkout -- .

4

해결책:

git revert --no-commit <commit hash>
git reset -p        # every time choose 'y' if you want keep the change, otherwise choose 'n'
git commit -m "Revert ..."
git checkout -- .   # Don't forget to use it.

허용 된 솔루션과 다른 점을 말하면 사람들에게 도움이 될 것입니다.
— CharlesB

1
@Krzysztof 마지막에 체크 아웃이 중요한 이유와이 솔루션이 user1338062와 다른 이유는 무엇입니까?
— martin

3

또 다른 대안은 (현재 버전의 파일이 되돌리려는 버전과 너무 멀지 않은 경우) 부분적으로 되돌릴 (from ) 직전 에 커밋 의 해시를 얻는 것 git log입니다. 그러면 당신의 명령은 :

$ git checkout -p <hash_preceding_commit_to_revert> -- file/you/want/to/fix.ext

이것은 작업 트리의 파일을 변경하지만 커밋을 생성하지 않으므로 실제로 채워 넣으면 다시 시작할 수 있습니다 git reset --hard -- file/you/want/to/fix.ext.


1

git-revert -n을 사용한 다음 add --patch를 사용하여 덩어리를 선택할 수 있습니다.

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