본문 바로가기
개발 관련/Git

[Git] git 실수로 변경한 파일의 변경사항을 되돌리는 방법

by domo7304 2022. 8. 20.

필요한 부분에 따라 링크를 해두었으니 '이동' 을 통해 확인하면 좋을 것 같다.

  1. 문제상황설명 (이동)
  2. 내가 생각한 문제 해결 방식 2가지 (이동)
  3. 첫 번째 방식이 부적절하다고 생각하는 이유 (이동)
  4. 해결한 방법 (이동)
  5. 두 번째 방식이 적절하다고 생각하는 이유 (이동)

 

1. 문제상황설명

좌: 레포지토리, 우: PR 변경사항에 나타난 backend 폴더

하나의 repository 안에 backend 와 frontend 파일을 위치시키고 버전을 관리하고 있었는데, 다른 프론트엔드 팀원에게 backend 폴더가 PR 변경사항에 잡혔다고 연락이 왔다.

프론트엔드에서 backend 폴더에 작업 내용이 있을 리 없으니 당연히 변경사항으로 잡힐 일이 없는데, 뭔가 실수가 있었던 것 같아 원래대로 되돌려야 하는 상황이었다.

 

2. 내가 생각한 문제 해결 방식 2가지

이 때 생각난 방식은 2가지가 있었다.

  1. git reset HEAD^ 로 commit 을 하나하나 내릴 때마다 git status 로 변경사항을 살펴보며 backend 폴더의 변경사항이 잡히는 지점까지 내려간 후, 변경이 발생한 파일을 원래대로 되돌리기
  2. 변경이 발생한 파일의 최신 버전 commit hash 를 확인한 후, git restore --source [commit hash] [file name] 을 이용하여 해당 파일만 원래 상태로 되돌리기

지금 생각하기에 올바른 방법은 2번이지만, 그동안 귀찮아서 1번 방식으로 하던 본인을 반성하며 1번 방식이 왜 부적절하다고 생각하게 되었는지, 2번 방식이 왜 적절하다고 생각하는지 남기려한다.

1번 방식이 왜 부적절하다고 생각하는지 필요하지 않다면, 2번 방식으로 바로 이동 (이동)

 

3. 첫 번째 방식이 부적절하다고 생각하는 이유

일단 첫 번째 방식의 흐름을 살펴보자

git reset HEAD^
git status
# modified 로 backend 폴더가 잡힐 때까지 반복
# 변경된 backend 폴더의 파일을 원상복구
# 적절히 commit 메시지를 남긴 후
git push --force  
# 로컬에서 commit 을 reset 한 후 remote 로 올리는 것이기 때문에 강제로 push 를 해주어야한다.

 

1. git reset HEAD^ 와 git status 를 반복, backend 폴더가 아래 이미지와 같이 modified 로 잡힐 때까지 commit 을 내린다.

modified 로 나타난 backend 폴더

2. 변경된 backend 폴더의 파일을 원래대로 돌리기
3. 다시 add / commit 을 한 후 git push --force 를 이용하여 remote 에 강제로 push 하기

이미 remote 로 모든 변경사항이 전부 올라간 상황인데, 로컬에서 commit 을 내린 후 그것을 remote 에 적용하려 하는 상황이다. 때문에 로컬의 commit 히스토리를 remote 에 강제로 push 해야 하므로 --force 를 붙여야 한다.

- 위 방식대로 해왔던 이유

commit 실수가 발생했을 때, 잘못 다룬 파일에 대한 수정사항이 git 에 아예 올라가지 않았으면 하는 강박증이 있었다.
위 방식대로 수동으로 commit 을 내린 후 수정사항을 취소해주면, commit 을 눌렀을 때 변경사항이 전혀 잡히지 않으므로 그동안 위 방식대로 해왔다.

 

하지만 이번 문제상황에서는 위 방식대로 할 수가 없었다.

backend 폴더가 변경사항에 잡힌 것을 뒤늦게 PR File Changes 에서 발견하였으며, git reset HEAD^ 로 commit 을 내려가며 찾기에는 쌓여있는 commit 이 너무 많았다.
(PR convention 을 생각한다면 작업단위를 최소화하며 1기능 1PR 이 되도록 노력해야 하는 것은 알지만, 일단은 번외로 하자. 모든 개발 상황이 꼭 best practice 대로 흘러가리라는 법은 없으니)

이 상황을 맞닥뜨리고 나니, 그동안의 방식이 부적절했다는 것을 깨달을 수 있었다.

- 그동안 해오던 방식이 부적절하다고 생각하게 된 이유

1. 버전관리가 무의미해진다.

git 은 버전관리를 위해 존재하며, 위 이미지와 같은 commit history 또한 언젠가는 필요할지도 모르는 기록들이다. git reset 을 통해 commit 을 내린 후 history 를 지워버리는 행위는 버전관리가 무의미해지는 행위라는 생각이 들었다.

2. 수동으로 무언가를 한다는 것은 비효율적이며, 관련 없는 파일들에 대해서도 영향을 끼친다.

지금 해결하고자 하는 문제는 '실수로 변경이 발생한 파일을 찾아가, 원래대로 되돌리기' 일 뿐이다. 하지만 git reset 을 통해 commit 을 일일히 내리며 변경을 확인하는 경우에는 변경한 파일이 언제 modified 로 나타날 지 모르며, commit history 로 남아야 할 파일들도 계속해서 unstaged 되게 된다.

 

그동안 왜 그렇게 했을까 부끄럽지만, 지금이라도 깨달았으니 앞으로는 그러지 말아야겠다.

 

4. 해결한 방법

실수로 변경된 파일

1. 어떤 파일이 실수로 변경되었는지 찾는다.

 

해당 파일의 last commit 확인하기

2. 해당 파일의 last commit hash 를 찾는다.

 

변경된 파일 되돌리기

# cd 를 통해 변경된 파일의 폴더 디렉토리로 이동
git restore --source [commit hash] [file name]

3. 변경된 파일을 포함하는 폴더까지 이동한 후, git restore 명령어를 통해 현재 remote 에 있는 last commit 으로 파일을 변경해준다.

 

4. 그리고 다시 add / commit / push 를 하여 remote 에(PR 에) 반영해준다.

 

이렇게 할 경우 PR 의 commit history 에는 남을지라도, PR 전체의 File Changes 에서는 다시 사라지게 된다. (하나의 PR 안에서 수정을 했다가, 원상복구의 과정을 거친것...)

 

5. 두 번째 방식이 적절하다고 생각하는 이유

위에 적은 두 번째 방식이 적절하다고 생각하는 이유는 그동안 해오던 방식이 부적절하다고 생각하게 된 이유 (이동) 에 정확히 반대로 대응하여 설명할 수 있을 것 같다.

1. 버전관리에 문제가 생기지 않는다.

git reset HEAD^ 를 사용한 방법은 git commit history 를 내리며 파일이 수정된 시점을 찾는다. 하지만 다시 생각한 방법은 기존의 git commit history 를 건드리지 않으므로 다른 history 에 영향을 주지 않는다.

2. 수작업이 아니라 남겨진 commit history 를 활용하여 파일을 되돌리며, 우리의 관심사에만 집중하게 된다.

git reset HEAD^ 를 통해 commit 을 내리며, 관련 없는 파일들도 모두 unstaged 하는 것과 다르게, remote 에 남아있는 commit hash 를 통해 필요한 파일에만 영향을 끼치게 된다.

댓글