commands
git config --global (user.name <user_name>/user.email <user_email>)
사용자가 저장소에 코드를 반영할 때 등록될 사용자 정보를 설정한다.
- 프로젝트마다 다른 사용자 정보로 지정하고 싶으면, --global 옵션을 제거한다.
- 설정 정보는 git config --list로 확인한다.
git init
현재 디렉터리를 git repository(깃 저장소)로 만든다.
- 현재 디렉터리에 .git 디렉터리가 생성되며,
.git 디렉터리 이외의 영역을 working directory라고 한다.
- git repository인 디렉터리에서는,
working directory에서 작업을 하고 그 작업 내역을 git repository에 반영하며,
commit 등에 의해 반영된 version은 모두 .git 디렉터리에 저장되어
version 관리를 할 수 있게 된다.
- .git 디렉터리 안에는 commit 등을 했을 때의 version을 비롯하여
해당 git repository에 관한 각종 데이터가 담겨있다.
git add <file_name>
working directory에서 파일을 수정한 내역을 git repository에 반영하기 전에
staging area(준비 영역)에 올린다. (staging area는 index나 cache라고도 한다.)
- 파일이름 대신 ‘*(모든 파일)’ 이나 ‘.(현재 디렉터리)’을 사용할 수 있다.
(’*’ 사용 시 .gitignore에 있는 것들도 올라갈 수 있으니, ‘.’을 사용하도록 한다.)
- 여러 개를 하려면 띄어쓰기로 구분한다.
git status
staging area에 어떤 파일이 어떻게 올라가 있는지 확인한다.
- 파일은 크게 다음과 같은 상태로 분류된다.
- untracked: 한 번도 commit 되지 않음. add부터 해야 함.
- staged: add 후 commit 되기를 기다림.
- unmodified: commit 후 수정되지 않음.
- modified: commit 후 수정됨. add를 해야 함.
git commit -m <commit_message>
staging area에 있는 수정 내역이 있는 파일들을 repository에 반영한다.
- --amend: 최근 commit과 관련하여 message에 오타 혹은 누락된 파일이 있을 때 사용.
- untracked가 아니라면, -a 옵션을 추가하여 add와 commit을 동시에 할 수 있다.
git restore <file_name>
commit 이후 working directory에서 수정한 파일을 다시 원래대로 복구할 때 쓴다.
- 즉, working directory에서 수정한 내역 중 staged가 아닌 파일들을 복구한다.
- --staged: staged인 파일들을 unstaged로 내린다.
git clean
Untracked files을 제거할 때 사용한다
- 다양한 옵션이 있는데, -fd를 사용하여 파일 및 디렉터리를 삭제한다.
git diff
현재 수정하고 있는 파일들 중 commit한 것들의 수정 내역을 확인한다.
- conflict가 발생했을 때 주로 사용한다.
- --staged: commit한 것과 staging area를 비교한다.
git log
repository의 반영 내역, 즉 commit에 따른 모든 version을 확인할 수 있다.
- <branch_name>: 특정 branch에 관계된 commit log만 확인한다.
- -p, --patch: 각 commit에 대한 수정 내역을 확인할 수 있다.
(diff 와 비슷하다.)
- --stat: 각 commit에 대해 어떤 파일이 수정되었는지 확인할 수 있다.
- --oneline: 각 commit을 한 줄로 간단하게 보여준다.
(commit id는 맨 앞 7자로 줄여 쓰곤 한다)
- --graph: 각 commit간의 연결 관계를 그래프로 확인할 수 있다.
- -S
<string>
: 각 commit의 수정 내역에서 특정 string이 포함된 것들만 골라 확인할 수 있다.
- git config --global alias.l ‘log --oneline --all’을 통해 git l 등으로 줄여 쓰곤 한다.
- (git reflog: git command log를 모두 확인할 수 있다.)
git reset <commit id>
이전 commit으로 되돌아간다.
이후의 commit 작업 내역들은 옵션에 따라 유실되거나 다른 상태가 된다.
- default는 --mixed로, 이후 commit된 것과 작업 중인 것들을 unstaged로 둔다.
- --soft: 이후의 commit들은 staged로, 작업 중이던 것들은 unstaged로 둔다.
- --hard: 이후의 commit과 작업 중인 것들을 모두 버린다.
--soft와는 달리, commit한 파일을 삭제했을 때도 복구할 수 있다.
<commit id>
대신 @~N을 사용하기도 한다.
@: HEAD를 나타낸다.
~: 이전 commit을 가리킬 때 사용한다.
^: 병합된 branch에 있는 이전 commit을 가리킬 때 사용한다.
<commit id>
대신 <file_name>을 쓴다면 git restore --staged 와 같다.
staging area에서 unstaged(untracked/modified)로 내린다.
- Untracked인 것들은 영향이 없으므로, git clean을 사용해야 한다.
git revert <commit id>
이전의 특정 commit에서 작업한 내역을 취소하고 다시 작업하고자 할 때 쓴다.
- reset과 달리, 돌아간 commit 이후의 commit들은 유실되지 않고 그대로 남아 있다.
따라서 이후의 commit들에 대한 작업 내역은 남아있다.
해당 commit에서 작업한 내역만 취소되는 것이다.
- remote와 관련하여 push한 commit이 있는 branch에서,
reset으로 인한 conflict를 방지하기 위해 reset 대신 사용한다.
- git revert
<commit id>
로 현재 commit에서 이전 commit으로 되돌아간다.
(이 때, conflict가 발생할 수도 있다.
revert한 commit에서 작업한 파일을 이후의 commit에서도 수정했기에 발생하는 것이다.
conflict를 해결하고 add, git revert --continue를 한다)
- 해당 commit에서 작업한 내역이 취소된 것으로 새로운 commit이 생성된다.
- 이후 작업을 한다.
(revert 시 --no-commit 옵션을 주어, 2에서 바로 commit이 되지 않게 할 수 있다.
즉, 해당 commit에서의 작업이 취소된 것으로 staged인 상태가 된다.)
branch
git branch <branch_name>
현재 버전에서 가지를 뻗어 독립적으로 작업을 진행한다.
이후, merge를 통해 병합하곤 한다.
- 이슈를 해결하거나 새로운 기능을 추가하고자 할 때 쓴다.
- <branch_name>을 생략하면, 현재 git repository에 있는 branch를 확인할 수 있다.
- -d: 해당 branch를 삭제한다.
git checkout <branch_name>
HEAD pointer가 가리키는 것을 변경함으로써 branch를 전환한다.
- <branch_name> 대신 snapshot hash code를 직접 가리킬 수도 있다.
하지만, 이 때는 HEAD가 detached 상태가 된다.
이 상태에서 commit하는 것은 불안정한 것으로,
보통 실험적인 것들을 시도할 목적으로 하곤 한다.
물론, 이 상태에서 commit한 것들을 저장하기 위해
새로운 branch를 생성하며 이동할 수도 있고,
혹은 이동 후에 새로운 branch를 생성하여 해당 commit들을 할당할 수도 있다.
- git의 버전이 업데이트 됨에 따라,
checkout 대신 switch을 사용하는 추세이다.
- -: 이전 branch로 이동한다.
git merge <branch_name>
해당 <branch_name>에서 작업한 commit 등의 내역을 현재 branch에 병합한다.
- 기준 branch는 지금까지의 작업 내역을 누적해서 저장할 것이고,
병합될 branch는 <branch_name>으로, 기준이 되는 branch에서 파생된 것이다.
- fast forward
- 기준이 되는 master branch 등에서 어떤 branch를 생성하여 작업을 하고
기준 branch에서는 이후 딱히 수정된 내역이 없을 때,
생성한 branch를 기준 branch에 merge하기 위해 사용하는 방법이다.
이 병합은 그저, 동일한 commit을 가리키도록 이동 시키는 것에 불과하다.
- master branch에서 A branch를 생성했다고 가정한다.
- A branch로 이동하여 commit 등 작업을 한다.
- 작업을 끝냈으면, master branch로 이동한다.
- git merge A로 A branch에서의 작업 내역들을 master branch에 병합한다.
- A branch와 master branch는 서로 동일한 commit을 가리킨다.
- 3-way merge
- 마찬가지로 기준 branch에서 어떤 branch를 생성하여 작업을 하고,
기준 branch에서도 이후 commit 등 수정 내역이 있을 때,
생성한 branch를 기준 branch에 merge하기 위해 사용하는 방법이다.
즉, 현재 branch가 가리키는 commit이
merge할 branch의 ancestor이 아닌 것이다.
그러므로 Git은, 각 branch가 가리키는 commit 2개와
common ancestor을 사용하여, 3-way merge를 한다.
이는, merge 결과를 별도의 commit으로 만들고 나서
기준 branch가 그 commit을 가리키도록 이동 시킨다.
결과적으로 그 merge commit은 부모가 여러 개가 된다.
- master branch에서 A branch를 생성했다고 가정한다. (C2)
(이 때, C2가 common ancestor인 commit이다.)
- A branch로 이동하여 commit 등 작업을 한다. (C3)
- 작업을 끝냈으면, master branch로 이동하여 작업을 한다. (C4)
- 작업을 끝내고, git merge A로 master branch에 병합한다.
- master branch는 merge 결과로, C5를 가리킨다.
A branch는 그대로, C3를 가리킨다.
- merge conflict
merge를 시도한 두 branch에서 같은 파일을 작업하여,
수정한 부분의 내용이 달라 충돌을 일으키는 것이다.
- git status를 통해 어느 파일에서 충돌이 발생했는지 확인하여, 열어본다.
- 기준 branch인 HEAD의 version과 병합할 branch의 version의 작업 내역을
살펴보아 서로 잘 반영하고, <<<, ===, >>> 행을 삭제하여 충돌을 해결한다.
- 충돌을 해결했으면 add, commit 한다.
- merge는, commit 내역이 모두 그대로 남고
3-way merge의 경우 merge commit이 새로 생긴다는 특징이 있다.
(참고로 merge commit은, 해당 remote branch에 대한 push event이다.)
이러한 불필요한 commit은 history를 지저분하게 하여 협업 시 불편하다.
그래서 rebase와 squash를 통해 merge를 하곤 한다.
- 프로젝트의 commit history를 어떤 관점으로 바라보고 관리하는 지에 따라
단순히 merge만 하거나 rebase/squash를 혼용하여 사용한다.
- 작업한 사실을 중요하게 다룰 때는 merge.
- 진행 과정을 다듬어서 보여주기 위함이면 rebase.
git rebase <branch_name>
기준 branch의 base를 다른 commit으로 재설정한다.
- 3-way merge를 해야할 때, merge commit이 발생하지 않게 하기 위해 사용한다.
여러 commits을 통합하는 squash를 할 때도 rebase를 쓰는 것이긴 하다.
- 3-way merge의 상황과 마찬가지로 common ancestor을 갖는 두 branch에서,
기준 branch의 base를 <branch_name>의 최신 commit으로 전환하는 것이다.
즉, 결과적으로 두 branch가 합쳐져 log graph 상으로 일렬이 되는데
두 branch의 common ancestor인 기준 branch의 base commit 이후에는
<branch_name>에서 작업한 commit이 뒤따라오고,
기준 branch에서 작업한 commit들은
수정 내역은 그대로 이지만 새로운 commit id를 갖게 된다.
- master branch에서 A branch를 생성했다고 가정한다. (C2)
(이 때, C2가 common ancestor인 commit이다.)
- A branch로 이동하여 commit 등 작업을 한다. (C3)
- 작업을 끝냈으면, master branch로 이동하여 작업을 한다. (C4)
- 작업을 끝내고, git rebase A로 master branch에 병합한다.
- master branch는 rebase 결과로, 작업 내역은 그대로 이지만
원래 가리키던 C4가 사라지고 새로운 C5를 생성하여 가리킨다.
A branch는 그대로, C3를 가리킨다.
log graph는 master branch와 A branch가 일렬로 되어 있다.
기준 branch의 원래 base (C2) 이후로는
우선 A branch에서 작업했던 내역(C3)이 모두 뒤따라 오고,
master branch에서 작업한 내역(C4)은 그 이후에 온다.
- squash
commit 내역을 하나로 통합하고자 할 때 사용하는 방법이다.
- 하나로 통합하게 되어 나머지 commit message가 유실된 것처럼 보이나,
따로 tracking하여 확인할 수는 있다.
- git rebase의 -i 옵션을 이용한다.
git rebase -i <commit id>
혹은 git rebase -i @~3 과 같이 사용한다.
- editor창 등이 뜨면 각 commit을 어떻게 할 것인지 결정할 수 있다.
합쳐서 없앨 commit을 pick에서 s(squash)로 수정한다.
(이 때, editor로 commit_editmsg이 뜨면 잘 되지 않으니,
git config -e --global 후, editor를 vim으로 변경해주자.)
합쳐질 때의 commit message도 변경할 수 있다.
- rebase를 이용한 것이므로, 새로운 commit id를 생성하여 가리킨다.
- remote와 관련되지 않은 local branch에서,
독립적으로 작업할 때 사용해야 안정적이다.
rebase는 새로운 commit이 생성되어 전환되는 방식이기 때문이다.
- 즉 remote에 push한 commit이 있는 branch에서는,
rebase를 사용할 때 commit id가 변경된다는 점에서
추후 push를 하고 pull을 할 때 conflict가 발생하는 문제가 있으므로
잘 사용하지 않는다.
- 따라서 local에서 작업을 하고 remote로 push하기 전,
commit을 정리하는 차원에서 이용하는 것을 목적으로 한다.
- 보통 PR(/MR) 직전까지는 rebase, 이후 PR로 merge하는 방식으로 섞어 쓴다.
git stash
현재 작업 중인 내역을 commit을 하지 않고 임시로 저장해두고 다른 branch이동할 때 사용한다.
- working directory에서 수정한 내역들만 저장한다.
즉, modified이거나 staged 상태인 파일.
- -u: untracked인 파일도 함께 임시 저장한다.
- -m <stash_message>: stash 시 message를 작성하여 저장한다.
- git stash list: 목록을 확인한다.
- stack 자료구조이므로, 0번째가 가장 최근 것이다.
- stash list는 현재 branch 위치 등에 관계없이 공유된다.
- git stash clear: stash stack을 모두 제거한다.
- git stash pop <stash_name>: stash를 적용함과 동시에 제거할 수 있다.
- stash를 생성한 브랜치로 이동해서 사용하도록 한다.
다른 브랜치에서 pop을 하면, conflict가 발생할 수 있으므로 주의한다.
- --index 옵션을 주어, staged인 것까지 복원한다.
- git stash apply는 단순히 stash의 내용을 가져온다.
- git stash drop은 단순히 stash를 제거한다.
- git stash show <stash_name>: stash에 저장된 내역을 확인할 수 있다.
remote repository
git remote add <remote_repo_name> <remote_repo_path>
local repository에서 remote repository에, 특정 이름으로 연결한다.
- git remote -v: 어떤 remote repository들이 연결됐는지 확인한다.
- git remote remove <remote_repo_name>: remote repo와의 연결을 끊는다.
git push <remote_repo_name> <local_branch_name>
local branch의 commit을 연결된 remote branch에 반영한다.
- 최초에는 --set-upstream 으로 local branch와 remote branch를 연결해야 한다.
그래야 서로 tracking이 되어, 이후 push나 pull하기 용이하다.
- 다른 사람이 먼저 push를 했다면, pull을 먼저 한 다음에 push할 수 있다.
(이럴 땐, pull대신 fetch를 사용하여 conflict가 발생하는지 미리 확인할 수 있다.)
git pull <remote_repo_name> <remote_branch_name>
remote branch의 commit을 local branch로 가져와 반영한다.
이 때, local branch는 자동으로 remote branch와 merge를 시도한다.
- 자동으로 merge하지 않고 remote branch의 내용만 가져오려면 fetch를 사용한다.
이후, 수동으로 remote branch와 merge를 해줘야 한다. (fast forward)
git clone <remote_repo_path> .
remote repo를 현재 위치한 directory인 local로 복제하는 것이다.
- ‘.’을 붙이지 않으면 현재 디렉터리에 clone한 directory가 따로 생성된다.
- clone은 init; remote add; pull 을 한 것과 같다.
- -b <branch_name> --single-branch: 특정 branch만 clone할 때 사용한다.
자주 쓰는 명령어
최근 local commit 이후로 한 작업 모두 취소
- git reset --hard
- git clean -fd (필요시)
최근 local commit 취소 (이 직전 커밋으로 돌아감)
- git reset --hard HEAD~1
- git clean -fd (필요시)