실수로 이미 해버린 커밋을 이전의 커밋으로 돌리려면 어떻게 할 수 있을까?
git commit -am "실수 커밋 ㅠㅠ"
실수로 위와 같은 커밋을 하였다고 가정했을 때 git reset 을 사용하여 해결이 가능하다. 하나 이전의 커밋으로 돌리고 싶을 때 사용 가능한 명령어는
git reset HEAD~1
여기서 HEAD 란 현재 작업 중인 브랜치의 가장 최신 커밋을 가리키는 포인터 이다, "실수 커밋 ㅠㅠ" 는 더이상 없는 커밋이 되는것이다.
HEAD는 다음과 같은 역할을 하며 Git 에서 작업을 하거나 커밋을 관리할 때 사용 되는 중요한 개념이 된다.
현재 작업 중인 브랜치, 브랜치가 변경되면 HEAD 또한 변경
커밋 히스토리 탐색: "HEAD"를 사용하여 현재 작업 중인 브랜치의 커밋 히스토리를 탐색, "HEAD~1"과 같은 표현을 사용하여 이전 커밋을 가리키거나, "HEAD^"를 사용하여 두 번째 이전 커밋을 가리킬 수 있음.
커밋 생성: "HEAD"를 기준으로 변경 사항을 스테이징하고(git add) 커밋(git commit)을 생성.
작업 디렉토리와 스테이징 영역 변경: "HEAD"를 기반으로 작업 디렉토리와 스테이징 영역이 초기화된다. 이를 통해 현재 브랜치의 상태와 일치하게 되는 것.
git reset을 사용할 때는 "실수 커밋"을 커밋 하였던 기록 조차 사라지기 때문에 reset 을 사용할 때는 주의해서 사용하여야 한다.
reset 옵션에 대해서 알아봅시다.
기존에 커밋의 단계가 위와 같은 4 단계 였다고 할 때, 4 단계 에서 2단계로 돌아가는 법을 위에서 알아보았다. 바로 git reset 이었는데, 아래 코드를 한번 살펴보자.
git reset || git reset HEAD~1 ||git reset --mixed
git reset --mixed 라는 것이 추가 되었는데 git reset 은 기본적으로 git reset --mixed 와 같은 효과이다.(기본 값으로 적용 됨) 위 3가지는 동일한 효과이며 새 커밋 상태에서 modifeid 상태로 돌아가기 위해 사용된다.
그렇다면 4 단계 에서 3단계로의 이동은 어떻게 할 수 있을까?
git reset --soft
그 다음인 이름에서 유추할 수 있듯 4에서 1단계는
git reset --hard
를 사용한다.
또한 git rest qw12345 와 같이 log 코드를 통해 자신이 원하는 커밋으로 수정도 가능하다.
git revert 또한 이전 커밋으로 되돌아가기 위한 명령어인데 reset 과는 결과가 약간 다르다.
reset 은 이전 커밋으로 돌아가는 것에 반해 revert 는 새로 돌아가는 과정 또한 새로운 커밋으로 만들어 버린다.
git am -m "첫 커밋"
git am -m "마지막 커밋 실수 ㅠㅠ"
위와 같은 커밋을 진행하였다고 하자. 마지막으로 커밋 실수가 있었으니, git revert HEAD~1 (reset 과 동일) 을 입력 하였을 때 커밋 상태가 어떻게 되는지 살펴보자.
revert "마지막 커밋 실수 ㅠㅠ"
"마지막 커밋 실수 ㅠㅠ"
"첫 커밋"
실수로 작성한 "마지막 커밋 실수 ㅠㅠ"가 사라지지 않고 revert 라는 이름으로 새로운 커밋이 하나 더 생긴 것을 확인 할 수 있다. reset 과는 다르게 돌아가는 과정 또한 커밋이 추가 된 것을 확인할 수 있다...
reset 과 revert 는 언제 사용할 수 있을까?
쉽게 말해보자면 reset 은 혼자 작업을 진행할 때
revert 는 다른 사람과의 협업을 할 때로 나눌 수 있을 것이다.
혼자서 작업을 하게 되면 자신만이 코드를 사용하게 되므로 커밋에 대한 기록을 나만 알아볼 수 있으면 된다. 그러나 협업 과정에서 자신이 실수로 작성한 코드를 커밋했다고 하였을 때 예를 들어보자
커밋 실수한거 그대로 push => 협업 하는 동료가 코드 가져옴 => 나중에 깨달음 => 혼나는게 무서워서 몰래 reset => 코드가 동료랑 안맞음 -=> 멸망
예시가 극단적이지만 잘못 커밋한 코드를 이미 push 하였다고 할 때 revert 를 사용할 수 있을 것이다.
branch는 가지치기를 생각하면 된다.
초록색의 main 나뭇가지에서 가지를 뻗어서 작업 하는 것을 branch 라고 한다.
// main 나뭇가지는 보통 고객에게 보여지는 서비스 branch를 신기능 개발 과정을 생각하면 된다고 함. 이것을 다시 main 나뭇가지로 합치는 과정에서 충돌이 일어나기도 함 ㅠㅠ
branch는 어떻게 생성 할 수 있을까? 먼저 다음과 같이 입력해보자
git branch
git branch 를 입력하면 현재 branch 상황을 표시해주는데, 따로 만들어 준 적은 없으니 main만 존재 하는 것을 확인 가능하다.
git branch "branchname"
다음과 같이 development 라는 branch 를 생성해주었고 development 가 생성 된 것을 확인 할 수 있다.
branch 변경은 다음과 같이 할 수 있다.
git checkout "branchname" 으로 변경 가능
이제 development branch 에서 내용을 추가하여보자.
"development" 에 내용을 추가하기 전에 main 에 있는 내용을 모두 받아오기 위하여, "git pull origin main" 을 사용해 준다.
기존 main 의 내용은 test.txt 라는 파일에 프로젝트라는 텍스트가 존재한다. 프로젝트 뒤에 "development" 라는 텍스트를 추가,커밋 해준 뒤 다시 main 으로 돌아가보자.
이제 test.txt 의 내용은 "프로젝트" 와 "프로젝트 development" 라는 두 개의 branch 를 가지게 되었다.
이제 main 에서 development 브랜치의 내용을 받아와 보자.
git merge "branchname"
을 사용하여 작업 할 수 있다.
그러나 이런 식으로 충돌이 발생할 것이다. 같은 파일의 같은 줄의 내용을 수정 하였을 때, git 의 어떤 것이 맞는지 판단을 하지 않는다 .
git status 명령어을 사용해 보았을 때
test.txt 는 동시에 수정이 되었다고 나오게 된다.
충돌이 일어나는 것을 막기 위해 text.txt 파일의 내용을 아래와 같이 수정 해준뒤
다음과 같이 커밋 해주면 끝이다.
다시 한번 요약 해보자면 위 과정은
development 브랜치를 생성
development 브랜치에서 main 의 내용을 가져온 뒤 변경
main 에서 development 브랜치를 병합하기 (merge)
//이 과정에서 의도적으로 충돌 발생 시키기(같은 줄 같은파일 내용 수정)
를 진행하는 일련의 과정 이었다. git merge 를 하는 과정에서 오류가 날 수 있다. git 은 어떤 것이 맞는지 우선순위를 두지 않기 때문이다. 그러나 git 에서 자체적으로 틀린 부분이 있다면 친절하게 표시를 해주기 때문에 수정 하는데 큰 어려움을 겪지 않고 브랜치를 병합 할 수 있을 것이다.