이 게시물에서 포스팅할 주제는 개발자라면 알아두어야 할 Git 이다.
필자는 부트캠프에서 Git 에 대해서 배우긴 하였지만 단기간 안에 배워야 했기 때문에 개념을 제대로 배우지 않고 넘어갔다.
그래서 회사에서 Git 쓰다보면 헷갈릴 때가 많았다. (에러는 무조건 구글링 하는 인생을 살았다..)
그래서 주말을 이용해 아예 git 공식문서를 통해 정리를 해보려고 한다.
Git
CVS, Subversion, Perforce, Bazaar 등의 시스템은 각 파일의 변화를 시간순으로 관리하면서 파일들의 집합을 관리한다
(보통 델타 기반 버전관리 시스템이라 함).
Git은 이런 식으로 데이터를 저장하지도 취급하지도 않는다. 대신 Git은 데이터를 파일 시스템 스냅샷의 연속으로 취급하고 크기가 아주 작다. Git은 커밋하거나 프로젝트의 상태를 저장할 때마다 파일이 존재하는 그 순간을 중요하게 여긴다. 파일이 달라지지 않았으면 Git은 성능을 위해서 파일을 새로 저장하지 않는다. 단지 이전 상태의 파일에 대한 링크만 저장한다. Git은 데이터를 스냅샷의 스트림처럼 취급한다.
스냅샷 vs 백업
스냅샷과 백업의 가장 큰 차이점은 바로 ‘원본 데이터 종속성’ 이다.
스냅샷은 원본의 완벽한 복사본이 아니기 때문에 원본 데이터가 저장된 공간에 오류가 발생할 경우 복구가 불가능하다.
반면 백업의 경우 데이터 전체를 완전한 형태의 사본으로 복제해 저장하기 때문에 원본 데이터에 영구적인 손상이 가해져도 백업된 시점의 데이터 전체를 완벽하게 복구할 수 있다.
거의 모든 명령을 로컬에서 실행
거의 모든 명령이 로컬 파일과 데이터만 사용하기 때문에 네트워크에 있는 다른 컴퓨터는 필요 없다.
프로젝트의 모든 히스토리가 로컬 디스크에 있기 때문에 모든 명령이 순식간에 실행된다.
예를 들어 Git은 프로젝트의 히스토리를 조회할 때 서버 없이 조회한다. 그냥 로컬 데이터베이스에서 히스토리를 읽어서 보여 준다.
그래서 눈 깜짝할 사이에 히스토리를 조회할 수 있다. 어떤 파일의 현재 버전과 한 달 전의 상태를 비교해보고 싶을 때도 Git은 그냥 한 달 전의 파일과 지금의 파일을 로컬에서 찾는다. 파일을 비교하기 위해 리모트에 있는 서버에 접근하고 나서 예전 버전을 가져올 필요가 없다.
즉 오프라인 상태이거나 VPN에 연결하지 못해도 막힘 없이 일 할 수 있다. 비행기나 기차 등에서 작업하고 네트워크에 접속하고 있지 않아도 커밋할 수 있다(로컬 저장소라는 점이 기억나는지). 다른 VCS 시스템에서는 불가능한 일이다.
Git은 데이터를 추가할 뿐
Git으로 무얼 하든 Git 데이터베이스에 데이터가 추가 된다.
되돌리거나 데이터를 삭제할 방법이 없다.
다른 VCS처럼 Git 도 커밋하지 않으면 변경사항을 잃어버릴 수 있다. 하지만, 일단 스냅샷을 커밋하고 나면 데이터를 잃어버리기 어렵다.
세 가지 상태
이 부분은 중요하기에 집중해서 읽어야 한다. Git을 공부하기 위해 반드시 짚고 넘어가야 할 부분이다.
Git은 파일을 Committed, Modified, Staged 이렇게 세 가지 상태로 관리한다.
- Committed 란 데이터가 로컬 데이터베이스에 안전하게 저장됐다는 것을 의미한다.
- Modified 는 수정한 파일을 아직 로컬 데이터베이스에 커밋하지 않은 것을 말한다.
- Staged 란 현재 수정한 파일을 곧 커밋할 것이라고 표시한 상태를 의미한다.
이 세 가지 상태는 Git 프로젝트의 세 가지 단계와 연결돼 있다. Git 디렉토리, 워킹 디렉토리, Staging Area 이렇게 세 가지 단계를 이해하고 넘어가자.
① Git 디렉토리
Git 디렉토리는 Git이 프로젝트의 메타데이터와 객체 데이터베이스를 저장하는 곳을 말한다.
이 Git 디렉토리가 Git의 핵심이다.
다른 컴퓨터에 있는 저장소를 Clone 할 때 Git 디렉토리가 만들어진다.
② 워킹 트리
워킹 트리는 프로젝트의 특정 버전을 Checkout 한 것이다.
Git 디렉토리는 지금 작업하는 디스크에 있고 그 디렉토리 안에 압축된 데이터베이스에서 파일을 가져와서 워킹 트리를 만든다.
③ Staging Area
Staging Area는 Git 디렉토리에 있다. 단순한 파일이고 곧 커밋할 파일에 대한 정보를 저장한다.
Git에서는 기술용어로는 “Index” 라고 하지만, “Staging Area” 라는 용어를 써도 상관 없다.
Git 으로 하는 일은 기본적으로 아래와 같다.
- 워킹 트리에서 파일을 수정한다.
- Staging Area에 파일을 Stage 해서 커밋할 스냅샷을 만든다. 모든 파일을 추가할 수도 있고 선택하여 추가할 수도 있다.
- Staging Area에 있는 파일들을 커밋해서 Git 디렉토리에 영구적인 스냅샷으로 저장한다.
Git 디렉토리에 있는 파일들은 Committed 상태이다.
파일을 수정하고 Staging Area 에 추가했다면 Staged이다. 그리고 Checkout 하고 나서 수정했지만, 아직 Staging Area에 추가하지 않았으면 Modified이다. ★★★★★
Git의 기초에서 이 상태에 대해 좀 더 자세히 배운다. 특히 Staging Area를 이용하는 방법부터 아예 생략하는 방법까지도 설명한다.
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
Q. 출력이 의미하는 바가 무엇일까?
CONTRIBUTING.md파일은 "Changes not staged for commit"에 있다.
이 말인 즉 수정한 파일이 Tracked 상태이지만 아직 Staged 상태는 아니라는 것이다.
Staged 상태로 만드려면 git add 명령을 실행해야 한다.
- git add
- 파일을 새로 추적할 때 사용
- 수정한 파일을 Staged 상태로 만들 때도 사용한다.
- Merge할 때 충돌난 상태의 파일을 Resolve상태로 만들 때도 사용한다.
⇒ add 의 의미는 프로젝트에 파일을 추가한다기 보다는 다음 커밋에 추가한다고 받아들이는 게 좋다.
출처: https://deepinsight.tistory.com/79 [Steve-Lee's Deep Insight]
주로 다음 두 가지 중 한 가지 방법으로 Git 저장소를 쓰기 시작한다.
- 아직 버전관리를 하지 않는 로컬 디렉토리 하나를 선택해서 Git 저장소를 적용하는 방법
- 다른 어딘가에서 Git 저장소를 Clone 하는 방법
1. 아직 버전관리를 하지 않는 로컬 디렉토리 하나를 선택해서 Git 저장소를 적용하는 방법
$ git init
이 명령은 .git 이라는 하위 디렉토리를 만든다. .git 디렉토리에는 저장소에 필요한 뼈대 파일(Skeleton)이 들어 있다. 이 명령만으로는 아직 프로젝트의 어떤 파일도 관리하지 않는다. (.git 디렉토리가 막 만들어진 직후에 정확히 어떤 파일이 있는지에 대한 내용은 Git의 내부에서 다룬다)
Git이 파일을 관리하게 하려면 저장소에 파일을 추가하고 커밋해야 한다. git add 명령으로 파일을 추가하고 git commit 명령으로 커밋한다:
$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'
2. 기존 저장소를 Clone 하기
다른 프로젝트에 참여하려거나(Contribute) Git 저장소를 복사하고 싶을 때 git clone 명령을 사용한다. 이미 Subversion 같은 VCS에 익숙한 사용자에게는 "checkout" 이 아니라 "clone" 이라는 점이 도드라져 보일 것이다. Git이 Subversion과 다른 가장 큰 차이점은 서버에 있는 거의 모든 데이터를 복사한다는 것이다. git clone 을 실행하면 프로젝트 히스토리를 전부 받아온다. 실제로 서버의 디스크가 망가져도 클라이언트 저장소 중에서 아무거나 하나 가져다가 복구하면 된다(서버에만 적용했던 설정은 복구하지 못하지만 모든 데이터는 복구된다 - 서버에 Git 설치하기에서 좀 더 자세히 다룬다).
$ git clone https://github.com/libgit2/libgit2
이 명령은 “libgit2” 라는 디렉토리를 만들고 그 안에 .git 디렉토리를 만든다. 그리고 저장소의 데이터를 모두 가져와서 자동으로 가장 최신 버전을 Checkout 해 놓는다. libgit2 디렉토리로 이동하면 Checkout으로 생성한 파일을 볼 수 있고 당장 하고자 하는 일을 시작할 수 있다.
아래과 같은 명령을 사용하여 저장소를 Clone 하면 `libgit2`이 아니라 다른 디렉토리 이름으로 Clone 할 수 있다.
$ git clone https://github.com/libgit2/libgit2 mylibgit
Git은 다양한 프로토콜을 지원한다.
이제까지는 https:// 프로토콜을 사용했지만 git:// 를 사용할 수도 있고 user@server:path/to/repo.git 처럼 SSH 프로토콜을 사용할 수도 있다.
수정하고 저장소에 저장하기
만질 수 있는 Git 저장소를 하나 만들었고 워킹 디렉토리에 Checkout도 했다. 이제는 파일을 수정하고 파일의 스냅샷을 커밋해 보자. 파일을 수정하다가 저장하고 싶으면 스냅샷을 커밋한다.
★★★★★
워킹 디렉토리의 모든 파일은 크게 Tracked(관리대상임)와 Untracked(관리대상이 아님)로 나눈다. Tracked 파일은 이미 스냅샷에 포함돼 있던 파일이다. Tracked 파일은 또 Unmodified(수정하지 않음)와 Modified(수정함) 그리고 Staged(커밋으로 저장소에 기록할) 상태 중 하나이다. 간단히 말하자면 Git이 알고 있는 파일이라는 것이다.
★★★★★
그리고 나머지 파일은 모두 Untracked 파일이다.
Untracked 파일은 워킹 디렉토리에 있는 파일 중 스냅샷에도 Staging Area 에도 포함되지 않은 파일이다.
처음 저장소를 Clone 하면 모든 파일은 Tracked 이면서 Unmodified 상태이다. 파일을 Checkout 하고 나서 아무것도 수정하지 않았기 때문에 그렇다.
마지막 커밋 이후 아직 아무것도 수정하지 않은 상태에서 어떤 파일을 수정하면 Git은 그 파일을 Modified 상태로 인식한다. 실제로 커밋을 하기 위해서는 이 수정한 파일을 Staged 상태로 만들고, Staged 상태의 파일을 커밋한다. 이런 라이프사이클을 계속 반복한다.
git rm
작업이 완료되어 저장소에 push를 날렸다.
하지만 모르고 작업에 필요했지만 올리지 않아도 되는 private 이라는 폴더를 올려버렸다.
그래서 폴더를 삭제하고, 다시 push를 날렸다.
하지만 Github에서는 삭제되지 않았다.
폴더를 리팩토링하고 난 후에도 마찬가지이다.
삭제 및 이동을 하고 push를 할 시 Github에 있는 폴더는 유지된 채 바뀐 폴더가 새로 생성된다.
원격 저장소에 이미 파일은 저장되어있다.
로컬에서 삭제만 한다고 해서 원격 저장소에서 삭제가 이루어지지 않는다.
★★★★★★★ 이 경우 git 명령어를 통한 파일 삭제 후 push를 해줘야한다.
$ git rm <fileName>
$ git rm --cached <fileName>
위의 git 명령어를 통해 폴더나 파일을 삭제하면 된다.
--cached 는 rm 명령어의 옵션이다.
--cached의 유무에 따라 차이점을 알아보자.
정의는 아래와 같다.
git rm => 원격 저장소와 로컬 저장소에 있는 파일을 삭제한다.
git rm --cached => 원격 저장소에 있는 파일을 삭제한다. 로컬 저장소에 있는 파일은 삭제하지 않는다.
정의 그대로 --cached 옵션을 넣을 경우에는 로컬 저장소에 있는 건 삭제되지 않는다.
즉, 로컬 저장소에는 존재하지만, 원격 저장소에 올라가진 않는다.
생각해보면 어떤 경우 쓰는지 모르겠고, 필요없는 옵션이라고 볼 수 있다.
예를 들어 작업시에만 쓰는 파일이나 로그 등 작업할 땐 필요하지만 Github에 안 올려도 되는 것들이 있다고 가정하자.
그렇다는 건, 작업할 때마다 올리지 않아도 되는 것들을 항상 고려해야한다.
즉 한가지 예로, Github에는 반영되지 않기 위해 git rm 명령어를 통해 삭제 해주는 작업을 말한다.
이런 경우를 위해 --cached 옵션을 통해 이런 불필요한 과정이 필요하지 않게 할 수 있다는 것이다.
그렇기에 일반적으로 git rm 명령어를 쓸 때에는 --cached 옵션을 사용한다.
아무튼 git rm 명령어를 통해 Github 저장소에 있는 private 폴더를 삭제할 수 있게 되었다.
출처: https://mygumi.tistory.com/103 [마이구미의 HelloWorld]
파일 삭제하기
Git에서 파일을 제거하려면 git rm 명령으로 Tracked 상태의 파일을 삭제한 후에 (정확하게는 Staging Area에서 삭제하는 것) 커밋해야 한다. 이 명령은 워킹 디렉토리에 있는 파일도 삭제하기 때문에 실제로 파일도 지워진다.
(아까 말했듯이 Tracked 상태의 파일은 git 이 알고 있는 파일이다.)
Git 명령을 사용하지 않고 단순히 워킹 디렉터리에서 파일을 삭제하고 git status 명령으로 상태를 확인하면 Git은 현재 “Changes not staged for commit” (즉, Unstaged 상태) 라고 표시해준다.
$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: PROJECTS.md
no changes added to commit (use "git add" and/or "git commit -a")
그리고 git rm 명령을 실행하면 삭제한 파일은 Staged 상태가 된다.
$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: PROJECTS.md
커밋 히스토리 조회하기
새로 저장소를 만들어서 몇 번 커밋을 했을 수도 있고, 커밋 히스토리가 있는 저장소를 Clone 했을 수도 있다. 어쨌든 가끔 저장소의 히스토리를 보고 싶을 때가 있다. Git에는 히스토리를 조회하는 명령어인 git log 가 있다.
이 예제에서는 “simplegit” 이라는 매우 단순한 프로젝트를 사용한다. 아래와 같이 이 프로젝트를 Clone 한다.
$ git clone https://github.com/schacon/simplegit-progit
이 프로젝트 디렉토리에서 git log 명령을 실행하면 아래와 같이 출력된다.
$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700
removed unnecessary test
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700
first commit
특별한 아규먼트 없이 git log 명령을 실행하면 저장소의 커밋 히스토리를 시간순으로 보여준다. 즉, 가장 최근의 커밋이 가장 먼저 나온다. 그리고 이어서 각 커밋의 SHA-1 체크섬, 저자 이름, 저자 이메일, 커밋한 날짜, 커밋 메시지를 보여준다.
리모트 저장소
노트
|
원격 저장소라 하더라도 로컬 시스템에 위치할 수도 있다.
“remote” 저장소라고 이름이 붙어있어도 이 원격 저장소가 사실 같은 로컬 시스템에 존재할 수도 있다. 여기서 “remote” 라는 이름은 반드시 저장소가 네트워크나 인터넷을 통해 어딘가 멀리 떨어져 있어야만 한다는 것을 의미하지 않는다. 물론 일반적인 원격 저장소와 마찬가지로 Push, Pull 등의 기능은 동일하게 사용한다.
|
리모트 저장소 확인하기
git remote 명령으로 현재 프로젝트에 등록된 리모트 저장소를 확인할 수 있다. 이 명령은 리모트 저장소의 단축 이름을 보여준다.
저장소를 Clone 하면 `origin`이라는 리모트 저장소가 자동으로 등록되기 때문에 `origin`이라는 이름을 볼 수 있다.
$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin
리모트 저장소 추가하기
이전 절에서도 git clone 명령이 묵시적으로 origin 리모트 저장소를 어떻게 추가되는지 설명했었지만 수박 겉핥기식으로 살펴봤을 뿐이었다. 여기에서는 리모트 저장소를 추가하는 방법을 자세하게 설명한다.
기존 워킹 디렉토리에 새 리모트 저장소를 쉽게 추가할 수 있는데 git remote add <단축이름> <url> 명령을 사용한다.
$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)
리모트 저장소를 pull 하거나 fetch 하기
앞서 설명했듯이 리모트 저장소에서 데이터를 가져오려면 간단히 아래와 같이 실행한다.
$ git fetch <remote>
이 명령은 로컬에는 없지만, 리모트 저장소에는 있는 데이터를 모두 가져온다. 그러면 리모트 저장소의 모든 브랜치를 로컬에서 접근할 수 있어서 언제든지 Merge를 하거나 내용을 살펴볼 수 있다.
저장소를 Clone 하면 명령은 자동으로 리모트 저장소를 “origin” 이라는 이름으로 추가한다.
그래서 나중에 git fetch origin 명령을 실행하면 Clone 한 이후에(혹은 마지막으로 가져온 이후에) 수정된 것을 모두 가져온다. git fetch 명령은 리모트 저장소의 데이터를 모두 로컬로 가져오지만, 자동으로 Merge 하지 않는다. 그래서 당신이 로컬에서 하던 작업을 정리하고 나서 수동으로 Merge 해야 한다.
그냥 쉽게 git pull 명령으로 리모트 저장소 브랜치에서 데이터를 가져올 뿐만 아니라 자동으로 로컬 브랜치와 Merge 시킬 수 있다(다음 섹션과 Git 브랜치 에서 좀더 자세히 살펴본다).
먼저 git clone 명령은 자동으로 로컬의 master 브랜치가 리모트 저장소의 master 브랜치를 추적하도록 한다(물론 리모트 저장소에 master 브랜치가 있다는 가정에서). 그리고 git pull 명령은 Clone 한 서버에서 데이터를 가져오고 그 데이터를 자동으로 현재 작업하는 코드와 Merge 시킨다.
pull 을 실행하면, 원격 저장소의 내용을 가져와 자동으로 병합 작업을 실행하게 됩니다. 그러나 단순히 원격 저장소의 내용을 확인만 하고 로컬 데이터와 병합은 하고 싶지 않은 경우에는 fetch 명령어를 사용할 수 있습니다.
회사 작업 방법
https://seungwubaek.github.io/tools/git/contributing_using_pull_request/
브랜치
Git이 브랜치를 다루는 과정을 이해하려면 우선 Git이 데이터를 어떻게 저장하는지 알아야 한다.
Git은 데이터를 Change Set이나 변경사항(Diff)으로 기록하지 않고 일련의 스냅샷으로 기록한다는 것을 시작하기 에서 보여줬다.
커밋하면 Git 은 현 Staging Area 에 있는 데이터의 스냅샷에 대한 포인터, 저자나 커밋 메시지 같은 메타데이터, 이전 커밋에 대한 포인터 등을 포함하는 커밋 개체(커밋 Object)를 저장한다. 이전 커밋 포인터가 있어서 현재 커밋이 무엇을 기준으로 바뀌었는지를 알 수 있다. 최초 커밋을 제외한 나머지 커밋은 이전 커밋 포인터가 적어도 하나씩 있고 브랜치를 합친 Merge 커밋 같은 경우에는 이전 커밋 포인터가 여러 개 있다.
파일이 3개 있는 디렉토리가 하나 있고 이 파일을 Staging Area 에 저장하고 커밋하는 예제를 살펴 보자. 파일을 Stage 하면 Git 저장소에 파일을 저장하고 (Git은 이것을 Blob이라고 부른다) Staging Area에 해당 파일의 체크섬을 저장한다 (시작하기 에서 살펴본 SHA-1을 사용한다).
$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'
git commit 으로 커밋하면 먼저 루트 디렉토리와 각 하위 디렉토리의 트리 개체를 체크섬과 함께 저장소에 저장한다.
그다음에 커밋 개체를 만들고 메타데이터와 루트 디렉토리 트리 개체를 가리키는 포인터 정보를 커밋 개체에 넣어 저장한다. 그래서 필요하면 언제든지 스냅샷을 다시 만들 수 있다.
이 작업을 마치고 나면 Git 저장소에는 다섯 개의 데이터 개체가 생긴다. 각 파일에 대한 Blob 세 개, 파일과 디렉토리 구조가 들어 있는 트리 개체 하나, 메타데이터와 루트 트리를 가리키는 포인터가 담긴 커밋 개체 하나이다.
Git의 브랜치는 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터 같은 것이다. 기본적으로 Git은 master 브랜치를 만든다. 처음 커밋하면 이 master 브랜치가 생성된 커밋을 가리킨다. 이후 커밋을 만들면 master 브랜치는 자동으로 가장 마지막 커밋을 가리킨다.
정리: 맨 뒤가 최근 커밋이다.이들은 이전의 커밋을 가리키는 포인터의 관계를 이룬다.
"다시 파일을 수정하고 커밋하면 이전 커밋이 무엇인지도 저장한다."
현재 작업 중인 브랜치를 가리키는 HEAD
git log 명령에 --decorate 옵션을 사용하면 쉽게 브랜치가 어떤 커밋을 가리키는지 확인할 수 있다.
$ git log --oneline --decorate
f30ab (HEAD -> master, testing) add feature #32 - ability to add new formats to the central interface
34ac2 Fixed bug #1328 - stack overflow under certain conditions
98ca9 The initial commit of my project
“master” 와 “testing” 이라는 브랜치가 f30ab 커밋 옆에 위치하여 이런식으로 브랜치가 가리키는 커밋 을 확인할 수 있다.
$ vim test.rb
$ git commit -a -m 'made a change'
이 부분이 흥미롭다. 새로 커밋해서 testing 브랜치는 앞으로 이동했다. 하지만, master 브랜치는 여전히 이전 커밋을 가리킨다. master 브랜치로 되돌아가보자.
git checkout master
방금 실행한 명령이 한 일은 두 가지다. master 브랜치가 가리키는 커밋을 HEAD 가 가리키게 하고 워킹 디렉토리의 파일도 그 시점으로 되돌려 놓았다.
앞으로 커밋을 하면 다른 브랜치의 작업들과 별개로 진행되기 때문에 testing 브랜치에서 임시로 작업하고 원래 master 브랜치로 돌아와서 하던 일을 계속할 수 있다.
브랜치를 이동하면 워킹 디렉토리의 파일이 변경된다는 점을 기억해두어야 한다. 이전에 작업했던 브랜치로 이동하면 워킹 디렉토리의 파일은 그 브랜치에서 가장 마지막으로 했던 작업 내용으로 변경된다. 파일 변경시 문제가 있어 브랜치를 이동시키는게 불가능한 경우 Git은 브랜치 이동 명령을 수행하지 않는다.
자신이 어떤 작업을 하던 중에 다른 요청이 들어와 하던 작업을 멈추고 잠시 브랜치를 변경해야 할 일이 있다고 하자. 이때, 아직 완료하지 않은 일을 commit하는 것은 껄끄럽다. 어떻게 해야 될까?
https://gmlwjd9405.github.io/2018/05/18/git-stash.html
아직 마무리하지 않은 작업을 스택에 잠시 저장할 수 있도록 하는 명령어이다. 이를 통해 아직 완료하지 않은 일을 commit 하지 않고 나중에 다시 꺼내와 마무리할 수 있다.
git stash 명령을 사용하면 워킹 디렉토리에서 수정한 파일들만 저장한다.
stash 란 아래에 해당하는 파일들을 보관해두는 장소이다.
1. Modified 이면서 Tracked 상태인 파일
- Tracked 상태인 파일을 수정한 경우
- Tracked: 과거에 이미 commit하여 스냅샷에 넣어진 관리 대상 상태의 파일
2. Staging Area에 있는 파일(Staged 상태의 파일)
- git add 명령을 실행한 경우
- Staged 상태로 만들려면 git add 명령을 실행해야 한다.
- git add는 파일을 새로 추적할 때도 사용하고 수정한 파일을 Staged 상태로 만들 때도 사용한다.
다시 돌아와서 (git checkout master 명령까지 봤음)
master 브랜치가 가리키는 커밋을 HEAD가 가리키게 하고 워킹 디렉토리의 파일도 그 시점으로 되돌려 놓았다. 앞으로 커밋을 하면 다른 브랜치의 작업들과 별개로 진행되기 때문에 testing 브랜치에서 임시로 작업하고 원래 master 브랜치로 돌아와서 하던 일을 계속할 수 있다.
브랜치를 이동하면 워킹 디렉토리의 파일이 변경된다는 점을 기억해두어야 한다. 이전에 작업했던 브랜치로 이동하면 워킹 디렉토리의 파일은 그 브랜치에서 가장 마지막으로 했던 작업 내용으로 변경된다. 파일 변경시 문제가 있어 브랜치를 이동시키는게 불가능한 경우 Git은 브랜치 이동 명령을 수행하지 않는다.
정리: 커밋하고 브랜치를 이동해야 한다. 불필요한 커밋을 하고 싶지 않은 경우, git stash 명령을 이용해 잠깐 로컬 어딘가에 저장한다.
위의 그림은 이해하기 어려울 수 있다.
다음의 git log --oneline --decorate --graph --all 명령을 사용해 자세한 설명을 보자
$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
* f30ab add feature #32 - ability to add new formats to the
* 34ac2 fixed bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project
실제로 Git의 브랜치는 어떤 한 커밋을 가리키는 40글자의 SHA-1 체크섬 파일에 불과하기 때문에 만들기도 쉽고 지우기도 쉽다. 새로 브랜치를 하나 만드는 것은 41바이트 크기의 파일을(40자와 줄 바꿈 문자) 하나 만드는 것에 불과하다.
브랜치가 필요할 때 프로젝트를 통째로 복사해야 하는 다른 버전 관리 도구와 Git의 차이는 극명하다. 통째로 복사하는 작업은 프로젝트 크기에 따라 다르겠지만 수십 초에서 수십 분까지 걸린다. 그에 비해 Git은 순식간이다. 게다가 커밋을 할 때마다 이전 커밋의 정보를 저장하기 때문에 Merge 할 때 어디서부터(Merge Base) 합쳐야 하는지 안다. 이런 특징은 개발자들이 수시로 브랜치를 만들어 사용하게 한다.
이제 왜 그렇게 브랜치를 수시로 만들고 사용해야 하는지 알아보자.
'👩🏻💻 TIL' 카테고리의 다른 글
Git 커밋 없이 Checkout 하면 어떤 일이 일어날까? (0) | 2022.03.23 |
---|---|
git merge (fast-faward, 3-way Merge) (0) | 2022.03.20 |
Express / middleware / router (0) | 2022.03.17 |
JavaScript / TypeScript fundamental (0) | 2022.03.16 |
프리즈마, 그래프큐엘의 yarn codegen (0) | 2022.02.21 |