오답노트 및 하다 막힌 부분/git

특정 시점으로 git 롤백 + 깃내역 초기화

Dr.Mlem 2024. 12. 23. 21:58
Q1.
상황을 말해줄게. A라는 상태에서 오늘 git에 push 해서 B 상태가 되었어. 그런데 나는 다시 A 상태의 파일들 상태로 돌아가고 싶어. 그래서 checkout A를 했어. 그러면 파일들은 다시 A 상태로 돌아간거야?
 
 
 
A1.
ChatGPT 몇 초 동안 Thought about git checkout and file states

네, 맞습니다.
git checkout A를 실행하면 현재 작업 디렉토리(워킹 디렉토리)가 해당 A 커밋 시점의 파일 상태로 되돌아갑니다. 즉, 파일 내용은 모두 A 상태와 동일해집니다.

다만, 이 때 주의해야 할 점은 다음과 같습니다.

  • Detached HEAD 상태:
    git checkout A로 특정 커밋을 직접 가리키면, 현재 HEAD가 그 커밋을 직접 참조하고, 어떠한 브랜치도 가리키지 않는 Detached HEAD 상태가 됩니다. 이 상태에서도 파일은 A 상태로 되돌아가 있지만, 이 상태에서 작업한 뒤 커밋을 하면 별도의 브랜치 참조 없이 부유하는 커밋이 생길 수 있습니다.

따라서, A 상태에서 새로 작업을 진행하고 싶다면, 다음과 같이 A 커밋을 기반으로 새로운 브랜치를 만든 뒤 작업을 진행하는 것을 권장합니다.

git checkout -b my-branch A

이렇게 하면 A 시점의 상태를 가진 my-branch를 생성하고 그 위에서 안전하게 작업하고 커밋할 수 있습니다.



 
Q2.
o1

나의 말: 그런데 브랜치가 아니라, main에서 해당 작업을 진행했다면, 무슨 차이가 있지?

 
 
 
 

A2.

ChatGPT

4초 동안 Thought about detached HEAD vs main

 

git checkout <커밋> 명령을 통해 특정 커밋 시점으로 이동할 때, 단순히 그 커밋 해시를 checkout하면 'detached HEAD' 상태가 됩니다. 이 때 중요한 점은 현재 사용 중이던 브랜치, 예를 들어 main 브랜치의 포인터는 변경되지 않는다는 것입니다.

즉,

  • git checkout A (A가 특정 커밋 해시라 가정)
    워킹 디렉토리와 HEAD는 A 커밋 상태가 되지만, main 브랜치 포인터는 여전히 이전 커밋(B 등)을 가리키고 있습니다. 현재는 main 브랜치 위가 아니라 단순히 A 커밋만 checkout한 detached HEAD 상태입니다. 이 상태에서 커밋을 하면 main과는 전혀 연결되지 않은 고립된 커밋이 생기게 됩니다.
  • git checkout -b 새로운브랜치 A
    A 시점에서 새로운 브랜치를 만들어서 그 위로 checkout하면, 그 브랜치가 A 시점을 가리키는 공식적인 참조가 됩니다. 이렇게 하면 HEAD는 새로운 브랜치를 거치게 되므로, 여기서 커밋을 하면 해당 브랜치 히스토리에 커밋들이 누적됩니다.
  • main 브랜치에서 직접 되돌리기 (git reset --hard A)
    만약 main 브랜치에 머문 상태에서 git reset --hard A를 수행하면, main 브랜치 포인터를 강제로 A 커밋으로 이동시켜 히스토리를 재작성하게 됩니다. 이 경우 main 브랜치는 공식적으로 A 시점으로 돌아가며 B 이후의 히스토리는 사라집니다. 하지만 이는 다른 사람들과 공유된 리포지토리에 적용하면 문제를 일으킬 수 있습니다.

정리하자면, 단순히 git checkout A를 하면 main 브랜치 포인터는 옮겨지지 않으므로 main에서 작업한 것이 아닙니다. 새로운 브랜치를 만들어서 checkout하느냐, 아니면 reset으로 main을 직접 옮기느냐에 따라 결과가 다릅니다. main에서 바로 되돌리면 main 히스토리를 바꾸게 되지만, 커밋 해시를 직접 checkout하는 것은 main 브랜치를 건드리지 않고 단순히 그 커밋 시점 파일만 보는 것이기에 "브랜치 관점"에서 차이가 생기는 것입니다.

 
 
 
Q3.
o1

나의 말:

그렇다면, Main브랜치에 A 시점 이후의 내역들도 삭제하면서, 내 작업 디렉토리의 파일들 상태도 A 로 바꾸고 싶어. 그러면 어떻게 해야하지?
 
 
 
A3.
ChatGPT
1초 동안 Thought about reverting and resetting to A

그럴 경우에는 git reset --hard 명령을 사용하면 됩니다. 예를 들어, 다음과 같이 할 수 있습니다.

1. main 브랜치로 이동

git checkout main

2. main 브랜치의 HEAD를 A 커밋으로 강제 이동

git reset --hard A

위 명령을 실행하면 다음과 같은 효과를 얻습니다.

  • main 브랜치 포인터가 A 커밋을 가리키게 됩니다.
    즉, A 이후에 있었던 모든 커밋들이 main 브랜치 히스토리에서 사라집니다.
  • 로컬 작업 디렉토리의 파일 상태가 A 커밋 시점과 동일하게 변경됩니다.
    --hard 옵션은 워킹 디렉토리와 스테이징 영역까지 지정한 커밋 시점으로 되돌리기 때문에, 파일 상태도 완전히 A로 돌아갑니다.

단, 이미 원격에 A 이후의 커밋들을 push한 상태라면, 다른 팀원들과 히스토리가 달라질 수 있습니다. 이 경우 git push --force 명령을 사용해야 할 수 있으며, 이는 협업 상황에서 신중하게 검토해야 합니다.

 
 
 
Q4.
o1

나의 말:

이미 main에서만 사용하고 있었다면, git checkout main을 쓸 필요는 없는건가?

 

A4.

ChatGPT

1초 동안 Thought about git reset usage

이미 main 브랜치 위에서 작업 중이었다면, 굳이 git checkout main 명령어를 다시 사용할 필요는 없습니다. 현재 브랜치가 main임을 확신하고 있다면 바로 다음과 같이 실행할 수 있습니다.

git reset --hard A

이렇게 하면 main 브랜치는 즉시 A 커밋을 가리키며, 워킹 디렉토리의 파일 상태도 A 시점으로 돌아갑니다.

 
 
 
Q5.
o1

나의 말:

혹시나 해서 메인인데도 git checkout main을 쓰는건 상관없나?

 
 
 
A5.
ChatGPT
1초 동안 Thought about using `git checkout main`

네, 이미 main 브랜치에 있다면 git checkout main 명령어를 실행해도 큰 변화는 없습니다. 현재 브랜치가 main과 동일하다면 해당 명령어는 단순히 현재 상태를 유지할 뿐, 추가적인 작업을 수행하지 않습니다. 즉, "확실하게 main 브랜치 위에 있다"는 것을 확인하는 차원에서 실행하는 정도로 생각할 수 있으며, 실질적인 문제는 없습니다.

 
 
 
Q6.
o1

나의 말:

git reset --hard 96580aa627dae1e226f3e671c73fcc3b7b635617 라고 명령어를 쓰니,

HEAD is now at 96580aa SteveK 2024-12-04 22:20:26.42 라고 나오고 있어.

그런데도 여전히, github에는 24/12/13 오늘 올린 깃 내역이 존재해.

24/12/04 이후의 내역들을 싹 지우고 싶은데, 어떻게 해야하지?

 
 

 

A6.
ChatGPT
1초 동안 Thought about Git reset and history deletion
 

로컬에서는 git reset --hard를 통해 히스토리를 특정 커밋까지 되돌렸지만, 이미 GitHub(원격 저장소)에 더 최근 커밋들이 푸시된 상태라면 원격 저장소는 여전히 그 커밋들을 가지고 있습니다. 즉, 현재 상태는 다음과 같습니다:

  • 로컬: A 커밋 시점(예: 2024-12-04)으로 되돌아간 상태
  • 원격(GitHub): 2024-12-13에 올린 최신 커밋들까지 포함된 상태

원격 저장소의 히스토리를 로컬 상태와 동일하게 되돌리려면 강제 푸시(Force Push)가 필요합니다.

강제 푸시 방법

git push --force

또는 원격 브랜치 명을 명시적으로 적어줄 수도 있습니다. 보통 main 브랜치라면:

git push origin main --force

이 명령을 실행하면 로컬 저장소와 동일한 히스토리로 원격 저장소의 기록이 덮어씌워집니다. 결과적으로 2024-12-13 이후 추가했던 커밋들이 원격 저장소에서도 사라지게 됩니다.

주의사항

  • 협업 환경에서 주의: 다른 팀원이 이미 해당 히스토리를 받은 상태라면 혼란이 생길 수 있습니다. Force push로 과거 시점으로 되돌리면, 다른 팀원들의 로컬 저장소와 충돌이 발생할 수 있습니다. 팀원들에게 사전에 공지하거나 사유를 설명하고 진행하는 것이 좋습니다.
  • 복구 가능성: GitHub에서는 force push 이전에 존재하던 커밋들의 복구가 어렵습니다. 잘못 된 변경이라면 revert를 고려하거나, 상황에 맞게 진행해야 합니다.

정리하자면, 원격 저장소의 히스토리까지 특정 시점으로 되돌리기 위해서는 git reset --hard <커밋>으로 로컬 상태를 되돌린 뒤 git push --force를 사용해 원격 히스토리를 재작성해야 합니다.