Git에서 변경 사항 및 커밋 취소하기


항상 취소해야 할 무언가가 있습니다. 의도하지 않은 편집을 입력했거나, 상황을 더 나쁘게 만든 수정을 시도했거나, 아무도 보지 않기를 원하는 것을 커밋했을 수도 있습니다. Git은 프로젝트의 거의 모든 버전 기록을 보관하므로 대부분의 실수는 순간에 느끼는 것보다 훨씬 더 되돌릴 수 있습니다. 어느 도구를 사용할지는 실수가 얼마나 멀리 진행되었는지에 따라 달라집니다: 아직 편집기에 있는지, 이미 스테이징되었는지, 이미 커밋되었는지, 또는 팀원이 볼 수 있는 곳에 이미 푸시되었는지. 이 장은 이 순서대로 각 단계를 설명합니다.
push와 pull이란 무엇인가요?
Push는 커밋을 팀원이 함께 작업하는 저장소의 공유 사본으로 보내고, pull은 그들의 커밋을 당신에게 가져옵니다. Remotes and GitHub에서 둘 다 자세히 다룹니다. 이 장에서 "푸시됨"은 커밋이 당신의 컴퓨터를 떠났다는 뜻입니다.
커밋하기 전에 변경 사항 삭제하기
커밋 루프에서 weather-app의 styles.css를 다시 스타일링하고 있는데 새로운 레이아웃이 좋지 않은 아이디어인 것으로 판명되었다고 가정합시다. 스테이징하지 않았고, 커밋하지도 않았습니다. 파일을 마지막으로 본 그대로 돌려놓고 싶습니다. 정확히 그 작업을 위한 명령은 git restore입니다:
$ git status
On branch main
Changes not staged for commit:
modified: styles.css
$ git restore styles.css
$ git status
On branch main
nothing to commit, working tree cleangit restore <file>은 커밋하지 않은 편집을 버리고 파일을 마지막으로 저장된 상태로 돌려놓습니다. git add로 이미 변경 사항을 스테이징했었다면 마음을 바꾸면 일반 git restore은 스테이징 영역에 있는 파일이므로 건드리지 않을 것입니다. 먼저 언스테이징한 다음 복구합니다:
$ git add styles.css
$ git restore --staged styles.css
$ git restore styles.css두 개의 분리된 영역을 위한 두 개의 분리된 이동: git restore --staged는 파일을 스테이징 영역에서 꺼내고, git restore은 단독으로는 작업 디렉터리에서 편집을 버립니다. git restore은 커밋하지 않은 작업에만 도달하며, 변경 사항이 커밋되면 다른 명령이 작동합니다.
git restore <file>은 커밋하지 않은 편집을 버리고 파일을 이전의 방식대로 돌려놓습니다. 이미 git add로 변경 사항을 스테이징했다면 먼저 git restore --staged <file>로 언스테이징하고, 편집이 없어지기를 원하면 파일을 복구하세요. 이는 아직 커밋하지 않은 변경 사항에서만 작동하므로 이미 저장한 실수를 구할 수 없습니다. git stash로 작업 보관하기
때로는 수정할 실수가 없고 단지 나쁜 타이밍이 있습니다. styles.css를 편집 중이고 팀원이 지금 당신을 다른 브랜치로 필요로 하지만, 반완성된 스타일링을 커밋할 준비가 되지 않았습니다. git stash는 변경 사항을 보관하고 깨끗한 작업 디렉터리를 제공하므로 나중에 물러나서 돌아올 수 있습니다.
$ git status
On branch main
Changes not staged for commit:
modified: styles.css
$ git stash
Saved working directory and index state WIP on main: 8f3c7d1 Cache forecast responses in localStorage
$ git status
On branch main
nothing to commit, working tree cleanstyles.css에 대한 편집은 사라지지 않았으며, 보관되어 있습니다. 준비가 되면 git stash pop으로 돌려놓으세요:
$ git stash pop
On branch main
Changes not staged for commit:
modified: styles.cssgit stash는 아직 커밋할 준비가 되지 않은 변경 사항을 위한 것이며, 브랜치에 커밋을 생성하지 않습니다.
git stash는 커밋할 준비가 되지 않은 변경 사항을 보관하므로 작업 디렉터리가 깨끗해지고, git stash pop으로 나중에 돌려놓습니다. 아무것도 커밋되지 않고 아무것도 손실되지 않으며, 편집은 잠시 보관됩니다. 팀원이 지금 당신을 다른 브랜치로 필요할 때마다 이를 계속 사용합니다. git revert로 커밋 취소하기
커밋 8f3c7d1 "Cache forecast responses in localStorage"가 잘못된 것으로 판명되고 이미 푸시되었으므로 팀원이 이미 당겨갔습니다. 그 커밋을 지금 다시 작성하면 누군가가 이미 가진 것을 변경하고, 그들의 사본과 당신의 사본이 다음에 당겨갈 때 불일치합니다. git revert는 이미 존재하는 것을 변경하지 않고 이를 해결합니다: 변경 사항의 반대를 적용하는 완전히 새로운 커밋을 만듭니다.
$ git revert 8f3c7d1
[main 2b6f0d1] Revert "Cache forecast responses in localStorage"역사는 여전히 원본과 그것을 취소하는 것을 순서대로 보여줍니다. 아무도의 사본도 다시 형성할 필요가 없으며, 팀원은 다른 커밋처럼 새로운 revert 커밋을 당겨갑니다.
git revert는 다른 사람이 이미 가진 커밋에서 항상 안전합니다. 왜냐하면 오래된 것을 변경하는 대신 새로운 커밋을 추가하기 때문입니다.
git revert <commit>은 원본을 지우는 대신 이를 역으로 돌리는 완전히 새로운 커밋을 추가함으로써 커밋을 취소합니다. 이것이 커밋이 이미 공유되면 안전한 선택이 되는 이유는 저장된 것이 변경되지 않기 때문입니다. 역사는 실수와 수정 모두의 기록을 유지하므로 Git을 더 오래 사용할수록 더 좋아합니다. git reset로 되돌리기: soft, mixed, hard
커밋을 취소하는 세 번째 방법이 있습니다. git reset이며, revert와 다르게 작동합니다: 오래된 것을 취소하는 새로운 커밋을 추가하는 대신 reset은 현재 브랜치를 완전히 다른 커밋을 가리키도록 이동합니다. 이는 아무도 본 적이 없는 커밋에 빠르고 깔끔하며 공유된 커밋에 위험합니다.
Reset은 위의 restore와 revert의 더 광범위하고 사용 오류가 더 쉬운 친척입니다. 대부분의 일상적인 수정에서는 이를 필요로 하지 않으며, restore, revert, stash가 대부분의 "도와줘, 이것을 취소해"라는 순간을 다룹니다. 그러나 다른 사람의 지침에서 이를 볼 것이므로 여기 요약이 있습니다: reset은 당신의 브랜치를 역사에서 뒤로 이동하고, 그 모드 중 하나인 --hard는 확인 없이 커밋되지 않은 작업을 버립니다. 어딘가에서 복사하는 명령이 git reset --hard를 포함하면 실행하기 전에 무엇을 하는지 읽어보세요.
git reset을 사용하지 않을 것이며, restore, revert, stash는 이미 거의 모든 것을 다룹니다. 여전히 이것의 형태를 알아두세요: reset은 당신의 브랜치를 이전 커밋으로 이동하고, --hard 모드는 확인 없이 작업 디렉터리를 일치시키기 위해 지웁니다. reset --hard를 포함하는 복사하는 명령을 실제로 주의해서 다루세요. revert 또는 reset 선택하기
어떤 도구를 사용할지 결정하는 규칙: 다른 누군가가 이미 이 커밋을 당겨갔나요? 예라면 revert. 커밋이 당신의 컴퓨터에만 존재하고, 푸시하지 않은 브랜치에만 있다면 reset은 괜찮으며 종종 더 깔끔한 수정입니다. 확실하지 않을 때, revert는 항상 안전한 선택입니다. 두 경우 모두에서 작동하기 때문입니다.
git reflog로 커밋 복구하기
reset --hard, 지저분한 리베이스, 또는 실수로 브랜치 삭제는 커밋이 완전히 사라진 것처럼 보일 수 있습니다. 대부분의 경우 그렇지 않습니다. Git은 당신의 HEAD와 브랜치가 가리킨 모든 곳의 로컬 로그를 유지하며, **reflog**라고 불리며, 그 로그는 거의 항상 손실된 것처럼 보이는 커밋으로 돌아가는 방법입니다.
이를 자주 필요로 하지는 않을 것이지만 여기 요약이 있습니다: Git은 사라진 것처럼 보이는 순간 거의 아무것도 버리지 않습니다. reset --hard를 실행하고 나중에 그 커밋이 필요했다는 것을 깨닫는다면, 아마 그것을 되돌릴 수 있는 방법이 있을 것입니다. 이것은 더 깊이 들어갈 준비가 될 때마다 다룹니다.
reset --hard를 실행하고 너무 늦게 그 커밋이 필요했다는 것을 깨닫는다면, 아마 복구 가능할 것입니다. Git은 reflog라고 불리는 로컬 기록을 유지하며 당신의 작업이 가리킨 모든 곳이며, 그것은 보통 사라진 것처럼 보이는 커밋을 되돌릴 수 있기에 충분합니다. 이것은 깊은 다이브 영역이지만 거기에 있다는 것을 아는 것은 안심입니다. 
