다시 시작하는 Git, GitHub 기초 3

Hyuno Choi·2021년 3월 16일
0
post-thumbnail

2021년 3월 15일

이제 드디어 Git/GitHub 기초 특강의 마지막 부분입니다.😄 이번에는 리포지토리와 커밋의 구체적인 내용에 대해 작성하겠습니다.

리포지토리의 정체

지난 시간에 $ git clone 명령어로 원격 저장소를 그대로 가져오는 실습을 진행해보았는데요, clone으로 만들어진 프로젝트 폴더와 저장소에서 소스 코드를 복사해와서 직접 만든 폴더는 어떻게 다를까요?🤷‍♂️

clone으로 가져온 리포지토리 폴더는 직접 만든 폴더와 다르게 리포지토리의 정보가 들어있는 .git이라는 숨김 폴더를 가지고 있습니다. $ git clone으로 프로젝트를 복사해오면 .git 폴더도 함께 가져오게 되는데요, 덕분에 클론 받은 저장소에서도 커밋을 이어서 진행할 수 있습니다.

리포지토리 로컬 환경에 만들기💾

이번에는 새 리포지토리를 직접 만드는 과정을 진행해보겠습니다.

  1. 프로젝트명으로 디렉토리를 생성합니다.
  2. 프로젝트 디렉토리에서 $ git init 명령어를 실행합니다.

init 명령어를 입력했을 때 bash 창에 뜨는 디렉토리 뒤에 master라는 글자가 생겼다면 성공입니다!

이제 .git 폴더가 생겼는지 확인해봅시다. ls 명령어에 -a 옵션을 주면 숨김 파일까지 볼 수 있습니다. $ ls -a 명령어로 확인해보면 .git 폴더가 생성된 것이 보입니다.

또한 $ git status 명령어로 저장소의 상태를 볼 수 있습니다.

status 명령어 입력 후 보이는 정보는 다음과 같습니다.📋

  • On branch master : 현재 master 브랜치에 있음.
  • Changes not staged for commit : 스테이징 영역에 추가하지 않은 변경 사항 있음.
  • Untracked files : 한 번도 커밋하지 않은 파일. 저장소에 반영되지 않은 파일.

스테이징 영역

Git에는 스테이징 영역이라는 개념이 존재합니다. 스테이징 영역은 간단히 말해서 파일을 저장소에 업데이트 하기 전에 업데이트 할 파일들을 모아놓는 중간 지점이라고 할 수 있습니다.


출처 : Git/GitHub 기초/고급 특강 PPT

이런 스테이징 영역을 사용하는 방법은

  1. 내가 원하는 파일만 스테이징 영역에 옮기고,
  2. 커밋을 통해 그 파일들만 저장소에 반영하면 됩니다.

이런 스테이징 영역은 왜 존재할까요? 저번 Git 포스팅에서 커밋은 논리적 단위로 구분되는 것이 좋다고 했는데요, 막상 버그를 수정하거나 새로운 기능을 구현하다 보면 프로젝트 내의 파일들을 이것저것 건드리는 일이 많습니다. 이럴 때 관련된 파일만 스테이징 영역으로 옮기고 커밋을 진행하면 실제 건드렸던 파일과는 상관없이 같은 논리적 변경 사항만 커밋할 수 있습니다.

스테이징 영역에 파일 추가

$ git add 파일명 명령어로 파일을 스테이징 영역에 추가할 수 있습니다.

$ git status 명령어로 확인해보면 Changes to be committed라는 글자 밑에서 추가한 파일명을 볼 수 있습니다. 저는 test 폴더에서 file1.js 파일을 스테이징 영역에 추가했습니다.

bash창에도 나와있는 것처럼 $ git rm --cached 파일명 명령어로 스테이징 영역에서 파일을 다시 내릴 수도 있습니다.

$ git add . 명령어로 감지된 변경 사항이 있는 모든 파일을 스테이징 영역으로 옮길 수 있습니다. 하지만 의도치 않은 변경사항까지 커밋에 들어가거나 커밋 단위의 논리적 구분이 흐려질 수 있기 때문에 추천하는 방법은 아닙니다.

커밋 만들기

이번에는 스테이징 영역에 올라온 파일을 저장소로 커밋해보겠습니다.

$ git commit -m '커밋 메시지' 명령어로 커밋을 만들 수 있습니다. 이때 커밋 메시지 부분에 어떤 내용을 작성해야 하는지, 어떤 형식으로 작성해야 하는지는 첫 포스팅에 정리해놓았습니다.

커밋 후에 $ git status 명령어로 다시 확인해보면 스테이징 영역이 비어있는 것을 볼 수 있습니다.

잘못 만든 커밋 되돌리기⚙️

원래 이 파트를 <커밋 만들기>의 하위 항목으로 만들려고 했는데요, 양이 너무 많은 관계로 별도 항목으로 만들었습니다. 새로운 커밋을 만드는 것은 쉽지만 한 번 지나간 커밋을 되돌리는 작업은 쉽지 않습니다. 커밋을 만들 때보다 고려해야 할 사항이 많은데요, 크게 나눠서

  1. 원격 저장소 반영 여부와
  2. 커밋 이력 유지 여부에 따라 방법이 달라집니다.

로컬에서 되돌리기

일단 가장 기본적인 로컬에서 커밋을 되돌리는 방법부터 살펴보겠습니다.

reset - 커밋 이력 삭제

$ git reset 커밋 아이디 명령어로 해당 커밋 버전으로 되돌아갈 수 있습니다. 혹은 커밋 아이디 부분에 HEAD~돌아가고 싶은 커밋 수를 입력하면 HEAD부터 해당 커밋까지 되돌아가게 됩니다. 예를 들어 현재 버전의 바로 전 커밋으로 돌아가고 싶다면 $ git reset HEAD~1이라고 입력하면 됩니다.

reset 명령어는 돌아가는 길에 있는 모든 커밋 이력을 삭제합니다. 이제부터는 git 시각화 사이트를 이용해서 설명하겠습니다. git 명령어를 연습할 수 있는 유용한 사이트입니다.

사이트 : https://git-school.github.io/visualizing-git

여기 제 커밋 이력이 있습니다. 여기서 ff51e45 커밋으로 돌아가고 싶다면

  • $ git reset ff51e45 또는
  • & git reset HEAD~2 명령어를 입력하면 됩니다.

보이는 것처럼 HEAD가 해당 커밋으로 되돌아갔습니다. 앞의 두 커밋은 이력에서 삭제됩니다.

그런데 되돌아간다는 말로 끝내기에는 Git의 구조가 복잡합니다.🤔 로컬 저장소, 스테이징 영역, 워킹 디렉토리 중에 어디부터 어디까지 reset의 효과가 반영된다는 말일까요? Git은 reset 명령어의 옵션으로 반영 범위를 지정할 수 있게 해줬습니다.

soft

$ git reset --soft 커밋 아이디 명령어는 로컬 저장소에서만 커밋을 되돌립니다. 즉, commit 명령어를 입력하기 바로 전 단계로 되돌아간다고 할 수 있습니다. 스테이징 영역과 워킹 디렉토리 상에는 여전히 리셋하기 전의 파일이 남아있습니다.

mixed

$ git reset 커밋 아이디 명령어는 사실 --mixed 옵션이 디폴트로 설정되어 있습니다. 이 명령어는 로컬 저장소스테이징 영역에만 영향을 미칩니다. 즉, add 명령어를 실행하기 전 단계로 되돌아간다고 할 수 있습니다. 현재 프로젝트 폴더 내의 파일에는 변화가 없지만 두 영역의 파일은 해당 커밋 버전으로 되돌아갑니다.

hard

$ git reset --hard 커밋 아이디 명령어는 가장 조심해서 다루어야 합니다. 이름에서 유추할 수 있듯이, --hard 옵션은 모든 영역에 영향을 미칩니다. 만약 워킹 디렉토리 상의 변경 사항을 저장하지 않았다면 변경 사항을 잃어버리게 됩니다.

revert - 커밋 이력 유지

$ git revert 커밋 아이디 혹은 $ git revert HEAD~ 명령어로 해당 커밋 버전과 정확히 반대되는 커밋을 새로 만들 수 있습니다. 이 revert를 단순히 해당 커밋 버전으로 돌아간다고 잘못 이해하는 경우가 많은데요, 간단한 예시를 통해 알아보겠습니다.

텍스트 파일을 새로 만들고 다음과 같이 작성하고 커밋합니다.

1. Hello World

그리고 두 번째 줄을 추가하고 다시 커밋합니다.

1. Hello World
2. Hello Hello World

여기까지의 과정을 시각화하면 다음과 같이 보입니다. 파일을 만들고 첫 번째 줄을 만든 것이 first commit이고 현재 버전이 두 번째 줄을 추가한 두 번째 커밋입니다.

여기서 두 번째 줄을 추가한 커밋이 만약 잘못된 커밋이라면 $ git revert HEAD 명령어를 통해 직전 커밋을 되돌리는 커밋을 생성할 수 있습니다.

이런 식으로 해당 커밋과 반대되는 새로운 커밋이 생성됩니다. revert 이후 파일의 상태는

1. Hello World

과 같이 첫 번째 커밋 버전으로 돌아가 있을 것입니다. revert로 만든 커밋이 두 번째 줄을 삭제하는 역할을 했기 때문입니다.

만약 파일 생성 자체를 없었던 일로 하고 싶다면 단순히 $ git revert HEAD~1 명령어를 사용해서 첫 번째 커밋을 되돌리면 될까요? 이렇게 revert를 사용하면 충돌이 발생합니다. 첫 번째 커밋을 되돌려야 하는데 그 이후에 생긴 두 번째 커밋의 변경 사항을 어떻게 처리해야 할 지 Git이 알 수 없기 때문입니다. 따라서 revert는 최신 커밋부터 하나하나 거치며 신중하게 진행해야 합니다.

원격 저장소 커밋 되돌리기

이번에는 원격 저장소까지 올라가버린 커밋을 되돌리는 방법에 대해 알아보겠습니다. 다음 강의의 예습이라고도 할 수 있는데요, 미래에 같은 문제로 고민할 자신을 위해 커밋 되돌리는 방법을 한 번에 요약해놓으려고 합니다.

reset - 강제 push

앞서 reset으로 커밋을 되돌리는 방법이 목표 커밋 이후에 만들어진 커밋들을 삭제한다고 했습니다. 이 말은 로컬 저장소의 커밋 버전이 원격 저장소의 커밋 버전보다 낮아진다는 것을 뜻하므로 해당 변경 사항을 원격 저장소에 반영하기 위해서는 강제로 push하는 작업이 필요합니다.

세 개의 커밋을 만들고 모두 원격 저장소에 push로 반영한 모습입니다. 여기서 바로 전 커밋으로 reset 작업을 진행하겠습니다.

보이는 것처럼 원격 저장소의 커밋 버전은 최신이지만, 로컬 저장소의 커밋 버전은 한 단계 낮아진 것을 볼 수 있습니다. 이 상태에서 push를 하게되면 당연히 거부되는데요, 원격 저장소의 커밋보다 낮은 단계의 커밋을 이어서 붙일 수는 없기 때문입니다.

따라서 $ git push -f origin master 명령어를 통해 강제로 push를 진행해야 합니다.

강제로 push를 진행하면 원격 저장소의 커밋도 사라지게 됩니다. 이 방법은 협업 시 충돌이 발생할 수 있는 매우 위험한 방법으로 사전 협의 없이 독단적으로 사용해서는 안 됩니다.

revert - 커밋 이력 유지

revert 명령어는 해당 커밋 버전과 반대 역할을 하는 새로운 커밋을 만든다고 했습니다. 따라서 원격 저장소에 해당 변경 사항을 반영하고 싶다면, push를 해주기만 하면 됩니다. 그러면 새 커밋으로 원격 저장소에 추가됩니다.

이것으로 Git/GitHub 특강 기초편을 모두 마쳤습니다. 다음 포스팅부터는 고급편을 이어서 적겠습니다.


<참고 문서>

profile
프론트엔드 웹 개발자를 목표로 하고 있습니다.

0개의 댓글