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.