오답노트

[Git] Git 사용법 정리 본문

Git

[Git] Git 사용법 정리

권멋져 2022. 7. 27. 21:24

기본적으로 git과 VS Code가 설치되어있다는 가정하에 시작한다.

 

Git

리누스 토발츠에 의해서 만들어진 버전관리 시스템이다.

버전은 디버깅, 백업, 협업과 같은 목적에 사용된다.

 

VS Code에서 사용 준비하기

VS Code를 실행 후 상단 메뉴중 터미널에서 새 터미널 클릭

1-2.1 새 터미널 열기

아래 터미널 창이 생성되고 터미널 창 우측상단에 + 옆 드롭박스(V) 버튼 클릭 후 Git Bash 선택

1-2.2 터미널 변경

커맨드 Ctrl + ,  를 통해 설정을 열어 상단 에디트 박스에 exclude 검색

Files: Exclude 항목에서 .git을 선택 후 패턴 추가 클릭

 

1-2.3 exclude 파일 항목에서 .git을 패턴 추가한 결과

바탕화면에서 git으로 관리할 폴더 생성

1-2.4 바탕화면에 생성한 git으로 관리할 파일

위에서 생성한 파일을 VS Code에 드래그 & 드롭

1-2.5 TEST 파일을 나타내는 VS Code

[그림 1-2.1] 과 같이 터미널을 열어 아래 명령어를 통해 git을 생성한다.

git init

1-2.6 TEST 폴더에 git을 생성한 결과

Git 버전 만들기 (add / commit)

먼저 Test 파일에 텍스트 파일을 하나 생성한다. 그리고 터미널에

git status

를 입력한다. 위 명령어는 현재 git의 상태를 출력한다.

입력 후 아래와 같이 새로 만든 텍스트 파일이 Untracked 라고 출력된다.

1-3.1 Untracked 된 새로 만든 파일

이 상태에서는 test.txt의 버전관리를 할 수 없다.

버전 관리를 하기 위해서는 스테이징을 해야한다.

git add 파일명.확장자 

위 명령어를 터미널에 사용하여 test.txt를 스테이징할 수 있다.

1-3.2 Untracked 파일 add후 status

test.txt는 스테이징 되어 new file이 되었다.

만약 스테이징을 취소하고 싶다면

git rm --cached 파일명.확장자

을 입력하자.

 

이렇게 스테이징된 파일들을 버전으로 만들 수 있다.

git commit -am 메세지

-am 은 옵션으로 한 번이라도 add됬던 파일들은 자동으로 commit 해준다.

1-3.3 성공적으로 commit

이전 버전으로 돌아가기 (checkout)

우선 이전에 만들었던 test.txt에 아무 내용이나 입력하고 저장을 해보자.

그렇다면 아래와 같이 test.txt 탭 옆에 M이라고 출력된다.

 

 

1.3 버전 만들기를 통해 TEST 디렉토리 내에서 버전을 하나 더 만든다.

버전이 잘 만들어졌는지 확인하는 방법은

git log --oneline --all

log 는 말 그대로 commit에 대한 log 이며 

--oneline은 커밋 ID만 나타낸다.

--all 보이지 않는 commit 까지 모두 볼 수 있도록 해준다.

 

1-4.1 commit 에 대한 log 출력

이제 checkout으로 수정 전의 test.txt.로 돌아가보자

git checkout 커밋ID

커밋 ID는 노란색으로 나오는 영문과 숫자 조합의 6자리이다.

[그림 1-4.1] 에서 9b0a8b1이 커밋ID이다

 

1-4.2 checkout에 대한 결과

checkout으로 이전 버전으로 돌아갔다.

[그림 1-4.1]과 [그림 1-4.2]를 비교해보면 HEAD가 바뀐것을 알 수 있다.

checkout을 하면 HEAD가 커밋ID 위치로 변경된다.

그리고 HEAD가 더 이상 master를 바라보지 않게 되는데, 이를 dettached state라고 한다.

 

다시 원래 버전으로 돌아오고 싶을 때 두 가지 방법이 있다.

1. git checkout 커밋ID

2. git checkout master

 

1번은 위에서 설명한 것과 같은 결과가 나타난다. 해당 커밋ID의 test.txt로 변경되고

HEAD가 master를 바라보지 않는 dettached state 가 된다.

 

2번은 master가 위치한 test.txt로 변경되는 것은 1번과 같다. 하지만 HEAD가 master를 바라보면서 HEAD는 attached state가 된다.

 

이러한 HEAD의 상태는 나중에 reset에서 다른 결과가 나타나게 된다.

 

1번과 2번에 대한 HEAD의 변화는 아래 그림으로 확인해보자.

 

1-4.3 1번 checkout에 대한 결과
1-4.4 2번 checkout에 대한 결과

버전 삭제/복구 (reset)

reset은 HEAD의 상태에 따라 다른 결과를 나타낸다.

우선 버전을 지우기 위해선 HEAD가 attached state여야 한다.

git reset --hard 커밋ID

이때 커밋ID는 내가 지우고 싶은 커밋 직전 커밋이다.

한 마디로 reset으로 지정한 커밋 이후의 커밋은 안보고싶다는 이야기이다.

즉 commit은 지워지지 않는다. 우리가 안보이는 곳에 아직도 남아있다. (reset에 한에서)

 

1-5.1 reset에 대한 결과

이제 로그를 봐도 두번째로 만든 커밋을 찾아볼 수 없다.

하지만 우리가 안보이는 곳에 아직도 남아있다.

 

다시 복원을 해보자

git reflog

위 명령어를 입력하면 사용사가 git에 명령했던 내용을 볼 수 있다. 이 중에서 내가 reset으로 삭제한 커밋ID를 확인할 수 있다.

1-5.2 reflog를 통해 내가 지운 커밋id를 알 수 있다.

이제 checkout으로 삭제했던 커밋으로 돌아가보자

1-5.3 checkout을 통해 삭제한 커밋으로 이동한 HEAD

 

하지만 이 상태에서는 master가 HEAD보다 아래 있으므로 HEAD를 움직이면 바로 사라질 것이다.

그렇다면 master를 다시 위로 올려줘야 하는데, 이 또한 reset으로 가능하다.

 

순서는 먼저 HEAD를 attached state로 만들어야 하므로 HEAD가 master를 바라볼 수 있도록한다.

(git checkout master)

이제 HEAD는 attached state이므로 reset을 통해 master의 위치 변경이 가능하다.

(git reset --hard 커밋ID)

 

위 두 명령을 실행한 후 결과는 아래 그림과 같이 삭제한 커밋이 복구되었다.

1-5.4 복구된 커밋

위 방법에서 알 수 있는 사실은 HEAD가 attached state라면 reset을 통해 master의 위치를 변경할 수 있다는 것이다.

 

 

그렇다면 다시 [그림 1-5.3]으로 돌아가보자

[그림 1-5.3]은 HEAD가 dettached state 이다. 이 상태에서 reset으로 삭제된 커밋을 지정한다면 어떻게 될까?

결과는 checkout과 같은 결과를 나타낸다. 즉 HEAD만 이동한다는 것이다.

 

정리하면 아래와 같다.

HEAD가 attached state 라면 master의 위치를 변경하고
HEAD가 dettached state 라면 HEAD의 위치를 변경(checkout과 동일)한다.

버전 분할과 병합 (branch/merge)

git은 병렬적으로 작업을 수행할 수 있다.

예를 들면 프로그램 한 개를 만드는데 A기능과 B기능이 필요하다.

혼자 작업한다면 A기능 또는 B기능을 먼저 만들고 후에 나머지 남은 기능을 만들게 될것이다.

하지만 두 명이 작업한다면 한 명이 한개의 작업을 하는동안 다른 한 명이 남은 작업을 같이 진행할 수 있다는 것이다.

이 때 필요한것이 버전 분할과 병합이다.

 

우선 분할부터 알아보자

 

git branch 브랜치명

위 명령어를 실행하면 master가 아닌 브랜치명으로 분기가 생성된다.

1-6.1 branch로 TEST분기를 생성

현재 HEAD가 master를 가리키고 있으므로 HEAD를 TEST를 가리키도록 checkout을 하고 commit을 해보자

1-6.2 TEST로 checkout된 결과
1-6.3 TEST에서 변경 사항을 commit

지금 분기가 완전히 나눠지지 않았다. 그 이유는 master에서 TEST 브랜치를 만든것 이외에 파일에는 아무런 변화가 없기 때문이다.

현재 상태에서는 분기를 커밋ID에 이름을 부여한것과 같다. 즉 커밋 ID로 이러저러한 작업을 하는것 보다 브랜치를 만들어서 하는 것이 사람에게는 더 편한것이다.

 

이제 본격적으로 분기를 생성해보자

다시 master로 checkout 하고 파일의 변화를 주어 commit 해보자

1-6.4 분기가 생성된 모습

이제 맨 처음 설명한대로 한 프로그램에 두 개발자가 개발을 하는것과 같다.

 

다음으로는 두 분기를 합쳐보도록 한다.

git merge 브랜치명

위 명령어로 현제 HEAD가 가리치는 브랜치에 merge 명령어로 지정한 브랜치를 병합시킬 수 있다.

 

1-6.5 분기가 병합된 모습

서로 아예 다른 파일을 만들어 작업하는 것은 쉽게 병합이 가능하다.

하지만 같은 파일에서 작업을 하다보면 분명히 겹치는 부분이 생기기 마련이다.

 

이 때 병합을 시도하면 충돌이 발생하는데 이것을 confilct라고 한다.

 

다시 분기를 만들어 test.txt 파일에 의도적으로 같은 라인을 수정해보자.

 

1-6.6 merge중 conflic 발생

merge가 되지 못하고 경고문을 띄우면서 merge되지 않는다.

이 때 충돌이 발생한 파일을 찾아가서 사용자가 직접 처리를 해주고

다시 commit을 해야한다. 이 때 add를 다시 한 번 해줘야한다.

 

1-6.7 현재 git의 상태 : both modified

병합을 시도했으나 confilct 가 발생하여 발생한 상태이다.

충돌을 해결하고 test.txt 파일을 add 하면 정상적으로 commit 하여 병합을 완료할 수 있다.

 

1-6.8 병합 충돌 해결 후 병합 완료

github에 업로드/다운로드 (clone, push, pull)

github에 로그인하고 리포지토리를 생성한다. 그러면 리포지토리에 대한 url을 알 수 있다.

이 url을 이용하여 현재 로컬에 있는 git을 업로드할 수도 혹은 미리 만들어둔 리포지토리가 존재한다면 다운로드 받는 것도 가능하다.

 

우선 로컬의 리포지토리를 github에 업로드해보자.

 

github에 업로드 하는것을 push라고 한다.

push

git push 깃허브_리포지토리_URL

위 명령어를 실행하면 github 리포지토리로 로컬의 git이 push 된다.

 

만약 최초 실행이라면 에러 알림이 출력 되는데 알림에서 명령을 제시해준다.

제시되는 명령으로 실행하면 push를 실행할 수 있다.

 

pull

git pull 깃허브_리포지토리_URL

위 명령어를 실행하면 github 리포지토리에서 로컬의 git에 pull  된다.

 

rejected

충돌과 비슷한 현상이다. 같은 브랜치에서 다른 작업을 동시에 push 하려고 하면 늦게 push하는 쪽에서 rejected 된다.

이때 pull로 git의 최신 커밋을 가져오고 다시 push를 해야한다.

clone

클론은 pull과 비슷하지만 clone은 아예 로컬에 git을 생성하지 않은 상태에서, 즉 git init 명령을 실행하지 않은 상태에서 github의 git을 로컬로 복제하는것이다.

 

명령문은 아래와 같다.

git clone 깃허브_리포지토리_URL