Git

Git commit

Debin 2021. 10. 27.
반응형

오늘은 커밋에 관해 실습하고 공부해보겠습니다.

 

먼저 git init 명령어를 이용해 저장소를 만든다.

 

mkdir practice 
cd practice
git init

code hello.js

 

위와 같은 명령어를 이용해 워킹 디렉터리에 파일을 생성했다. git status 명령어를 통해 현재 깃의 상태를 알 수 있다.

 

git status 명령어 결과문

 

그러면 위의 이미지와 같이 출력된다. Untracket files 표시 부분을 확인할 수 있다. 추적되지 않은 파일은 git bash에서 붉은색으로 표현한다. 이렇게 깃은 워킹 디렉터리에 새 파일이 추가되면 상태를 감지하고 향후 이력을 추적할지 여부를 결정한다.

 

우리는 이전 포스팅을 통해 워킹 디렉터리와 커밋 사이에 스테이지 영역이라는 것이 존재한다는 것을 공부했다. 이 스테이징 영역을 바탕으로 커밋을 할 수 있다. 커밋을 하려면 우선 파일의 상태가 추적 가능해야 한다.

워킹 디렉터리에 새로 추가된 untracked 상태의 파일을 추적 가능 상태로 변경하는 것을 등록이라고 한다. 파일을 등록하면 워킹 디렉터리의 파일이 스테이지 영역에 추가된다! 스테이지 영역의 관리 목록에 추가된 파일만 깃에서 이력을 추적할 수 있다.

 

깃에서 정확하게 등록이란 워킹 디렉터리에 있는 파일을 스테이지 영역으로 복사하는 것이다. (복사는 이해하기 쉽게 사용한 표현이다) 워킹 디렉터리에 추가된 모든 파일을 커밋할 때는 반드시 이 과정을 거쳐야 한다, 그래야 깃에서 버전 이력을 관리할 수 있다. 스테이지에 등록되지 않은 unstage 상태의 파일들은 커밋할 수 없다. 깃은 커밋하기 전에 파일들이 stage 상태인지 unstage 상태인지를 판단한다. 스테이지 영역으로 등록된 파일들은 tracked 상태로 자동 변경된다.

 

그럼 이제 add 명령어를 이용해 우리의 파일을 등록해보자. add 명령어는 워킹 디렉터리의 파일을 스테이지 영역으로 등록한다.

 

git add hello.js

 

add 명령어를 실행하면 지정한 파일은 스테이지 영역으로 등록된다. 스테이지 영역에 파일이 등록되면 파일은 tracked 상태로 변경된다. 

파일 이름 대신 점(.)을 이용하면 전체 파일과 폴더를 모두 등록할 수 있다. 점은 리눅스와 같은 운영 체제에서 현재 디렉터리를 의미하는 기호이다.

 

스테이지 영역에 등록하지 않은 파일은 커밋 작업에 포함되지 않는다.

 

이제 git status 명령어를 사용하면 출력 결과가 이전과 다른 것을 확인할 수 있다.

 

git status 출력 화면

 

new file 메시지가 출력되면 스테이지 영역에 파일을 정상적으로 등록한 것이다.

 

tracked 상태의 파일을 untracked 상태로 변경할 수 있다. 스테이지에 등록하는 것과 반대 과정이다. 등록 취소는 워킹 디렉터리와 스테이지 영역을 서로 왔다 갔다 할 수 있는 방법이다.

unstage 상태로 변경하려면 삭제(rm)나 리셋(reset) 명령어를 사용해야 한다.

 

git rm --cached hello.js

 

스테이지의 캐시 목록에서 파일이 삭제된다. 다시 git status 명령어를 사용하면 출력 결과는 아래와 같다.

 

git status 명령 출력 결과

 

만약 한 번이라도 커밋을 했다면 reset 명령어를 사용해야 한다.

이제 다시 hello.js를 tracked 상태로 변경한다.

 

git mv 파일 이름 새 파일 이름 

위와 같은 명령어를 이용해 작업 도중 파일의 이름도 변경할 수 있다. 깃에게 알려주지 않아도 깃은 똑똑해서 알아서 변경 결과를 알고 있다. 

 

이제 본격적인 커밋을 진행하기 전에 HEAD 개념을 알아보겠다. 깃에는 HEAD 라는 포인터 개념이 있다. HEAD는 커밋을 가리키는 묵시적 참조 포인터다. HEAD는 최종적인 커밋 작업의 위치를 가리킨다. 앞에서 새로운 커밋은 이전 부모 커밋을 기반으로 새로운 커밋을 만든다. HEAD는 바로 부모 커밋을 가리킨다. 단 깃을 설치하고 처음 커밋할 때는 HEEAD의 포인터가 없다. 최소한 한 번 이상을 커밋을 해야만 HEAD가 존재한다. HEAD는 커밋될 때마다 한 단계씩 이동한다. 그리고 마지막 커밋 위치를 가리킨다. HEAD는 커밋이 변하한 최종 시점을 의미한다.

 

커밋은 파일 변화를 깃 저장소에 영구적!으로 기록한다. 이러한 커밋은 이전에 파일을 복사하여 관리하던 방식과는 큰 차이가 없다. 깃이 다른 버전 도구와 다른 점은 스냅샷 방식을 이용한다는 것이다. 파일을 복사하는 방식으로 수정본을 관리하면 같은 내용을 반복해서 저장하기에 많은 용량을 차지한다. 또 수정된 부분들을 일일이 찾아야 하기 때문에 검색할 때도 매우 불편합니다.

깃은 이러한 시스템적인 단점을 해결하려고 변경된 파일 전체를 저장하지 않고, 파일에서 변경된 부분을 찾아 수정된 내용만 저장합니다. 마치 변화된 부분만 찾아 사진을 찍는 것과 같다고 하여 스냅샷 방식이라고 한다.

깃의 스냅샷은 HEAD가 가리키는 커밋을 기반으로 사진을 찍습니다. 그리고 이를 스테이지 영역과 비교하여 새로운 커밋으로 기록합니다. 이처럼 깃은 스냅샷 방식을 이용하여 빠르게 버전의 차이점을 처리하고, 용량을 적게 사용한다.

 

커밋은 변화된 내용을 영구적으로 깃 저장소에 기록합니다. 새롭게 생성된 파일을 커밋하려면 반드시 tracked 상태로 변경해 주어야 한다. tracked 상태로 파일이 변경됨과 동시에 스테이지 영역에 등록한다. tracked 상태인 파일을 수정하면 다시 modified 상태로 변경된다. modified 상태는 untracked 상태다. untracked 상태의 파일은 반드시 add 명령어를 이용해 스테이지 상태로 재등록해야 한다. 재등록하면 다시 tracked 상태로 변경된다.

(커밋 전에 git status 명령어로 항상 상태를 확인하는 습관이 중요하다)

 

이제 실제적인 커밋 작업을 해보겠다. 수정된 파일 이력을 커밋하려면 commit 명령어를 사용해야 한다.

 

git commit

 

깃의 커밋은 HEAD와 스테이지 영역 간 차이를 비교하여 새로운 객체를 생성한다. 생성된 객체를 깃 저장소에 저장한다.

 

커밋은 변경된 파일 차이를 깃 저장소에 기록한다. 따라서 커밋을 할 때 생성된 객체를 기록하는 것과 동시에 이를 구별할 수 있는 메시지를 같이 작성해야 한다. 변화된 각 커밋 객체에 꼬리표처럼 설명을 달아 놓는다고 생각하며 된다. 이 설명들을 커밋 메시지라고 한다.

커밋은 파일 이름을 여러 개 사용하지 않고 하나만 가진다. 기존처럼 파일 이름으로 변화된 객체를 구별할 수 없다.

그 대신 깃은 변화된 객체를 구별하고자 메시지 시스템을 도입했습니다. 파일 이름을 사용하지 않고, 별도로 작성한 메시지 문자열로 각 변경 객체들을 쉽게 구분할 수 있다. 따라서 모든 커밋은 반드시 반드시 커밋 메시지를 작성해야 한다.

 

git commit 명령어만 이용해 커밋을 한다. 이 명령어를 입력하면 지정된 에디터가 열린다. 보통 처음에는 vi 에디터를 이용해 커밋메시지를 작성한다. 만약 커밋 메시지를 작성하지 않아 커밋이 거부되었다는 메시지입니다. 이처럼 vi 에디터에 아무 내용도 넣지 않고 종료하면 커밋 명령은 취소됩니다.

 

git commit -a 은 커밋을 하기 전에 자동으로 모든 파일을 등록하는 과정을 미리 수행한다. 따라서 파일 등록과 커밋을 동시에 실행하는 것이다.

 

git status 명령 출력 결과

 

이전과 달리 working tree clean 메시지를 볼 수 있다. 커밋을 하면 스테이지 영역은 초기화됩니다. 더 이상 추가된 새로운 파일과 수정된 파일이 없다는 것이다. 

 

git log 명령어를 이용해 커밋 기록을 확인할 수 있다. log 명령어는 시간 순으로 커밋 기록을 출력한다.

 

git log 명령 출력 결과

 

만약 파일을 변경하고 다시 커밋을 한다고 가정하자. 그러면 파일을 변경하는 순간 unstage 상태가 되면서 modified상태가 된다. 그러면 다시 git add 명령어를 이용해 stage 상태로 만들어야 한다. 그러면 이제 다시 git commit 명령어를 이용해 git 메시지를 작성하고 커밋을 진행한다. 다음으로 git log 명령어를 이용하면 커밋 상황을 확인할 수 있다.

 

git log 명령 출력 결과

 

총 2개의 커밋을 확인할 수 있다.

 

(git checkout 명령어를 이용하면 수정한 파일을 커밋 전 마지막 내용으로 쉽게 되돌릴 수 있다. 바로 이전 커밋으로 되돌리는 명령어이다.)

 

-m 옵션을 사용해 git commit -m "커밋메시지"로 간편하게 커밋 메시지를 작성할 수 있다.

-am 옵션을 사용하면 파일 등록과 한 줄짜리 커밋 메시지 등록을 동시에 처리한다. 

터미널에서 메시지가 없는 빈 커밋을 작성하려면 --allow-empty-message 옵션을 사용하면 빈 커밋을 만들 수 있다.

 

 

다음은 커밋아이디에 대해 알아보겠다.

fa311dbab5c167e9baa4354d13a9d44e8ddce00f 같은 길고 이상한 문자열을 커밋 아이디라고 한다. 절대적 이름이며 명시적 참조 값이다. 커밋 아이디가 이렇게 복잡한 영어와 숫자로 된 이유는 깃이 SHA1이라는 해시 알고리즘을 사용하기 때문이다. 이 알고리즘을 이용해 중복되지 않는 고유의 키를 생성할 수 있는 장점이 있다. 깃이 이 해시 알고리즘을 이용하는 것은 콘텐츠 추적과 분산형 저장 관리를 운영하면서 충돌을 방지하기 위해서이다.

 

로그 옵션 중에서 --pretty=short를 사용하면 로그를 출력할 때 첫 번째 줄의 커밋 메시지만 출력합니다.

git log --pretty=short

특정 커밋의 상세 정보도 확인할 수 있다. 특정 커밋의 상세 정보를 확인하고 싶다면 show 명령어를 사용한다.

git show 커밋ID

git log hello.js 명령어를 이용해 특정 파일의 로그만 볼 수도 있다.

 

아직 add 명령어로 파일을 추가하지 않은 경우, 워킹 디렉터리와 스테이지 영역 간 변경 사항을 비교할 수 있다.

스테이지 영역에 있는 수정된 파일을 아직 커밋하지 않았다면 최신 커밋과 변경 내용을 비교하여 볼 수 있다. HEAD는 마지막 커밋을 가지고 있는 포인터다. 명령어는 바로 diff 이다.

커밋 메시지를 작성할 때 -v 옵션을 사용하면 vi 에디터에서 diff 내용을 추가할 수 있다.

git commit -v

 

이상입니다.

반응형

댓글