Git
버전 관리
동시 협업
repository와 commit
repository(저장소)
프로젝트를 위해 만든 디렉토리의 모습을 버전별로 담아둔다
.git이라는 디렉토리가 숨겨져있다(이것이 repository이다)
commit
지금 모습을 하나의 버전으로 남기는 것
commit을 하면 그 당시의 프로젝트 디렉토리의 모습이 사진처럼 repository에 저장된다
그 고정된 결과물 자체도 commit이라고 한다
git 내부의 3가지 종류의 작업 영역
working directory(working tree라고도 함)
작업을 하는 프로젝트 디렉토리(사용자의 작업 공간)
staging area(index라고도 함)
git add를 한 파일들이 존재하는 영역
커밋을 하면 staging area에 있는 파일들만 커밋에 반영
repository
working directory의 변경 이력들이 저장되어 있는 영역(커밋들이 저장되는 영역)
working directory에서 뭔가 작업을 하고,
작업한 파일들을 git add 해주고,
커밋을 하면 staging area에 있던 파일들의 모습이 마치 영화의 한 장면, 스냅 샷(snapshot)처럼 이 repository에 저장이 된다
git add
변경사항이 있는지 확인 git status
변경사항이 있는 모든 파일을 한번에 staging area에 추가하는 방법
(git add . ==> 현재 프로젝트 디렉토리 내에서 변경사항이 생긴 모든 파일들을 staging area에 추가)
git 파일 상태
Untracked
파일이 Git에 의해서 그 변동사항이 전혀 추적되고 있지 않는 상태를 뜻한다
파일을 새로 생성하고 그 파일을 한 번도 git add 해주지 않았다면 이 상태
Tracked
파일이 Git에 의해 그 변동사항이 추적되고 있는 상태
Staged
파일의 내용이 수정되고나서, staging area에 올라와있는 상태
새로 생성한 파일에 내용을 쓰고 git add를 해주거나
한 번이라도 커밋에 포함됐었던 파일이라도 내용을 수정하고 git add를 해주면 이 상태
Unmodified
현재 파일의 내용이 최신 커밋의 모습과 비교했을 때 전혀 바뀐 게 없는 상태면 그 파일은 Unmodified(수정되지 않은, 변한 게 없는) 상태
커밋을 하고 난 직후에는 working directory 안의 모든 파일들이 이 상태가 된다
Modified
최신 커밋의 모습과 비교했을 때 조금이라도 바뀐 내용이 있는 상태면 그 파일은 Modified(수정된) 상태
git reset(staging area에서 파일 제거)
git reset 파일명
파일 수정 수 git add를 했을때 다시 원래대로 돌리고 싶을 경우
git reset 파일명을 하면 된다
(변경된 새 모습은 그대로 working directory에 남아있다)
Git command
Git 다루기
커밋 히스토리
git log
이때까지 한 커밋들을 볼 수 있다
위에 있을 수록 최신 커밋
옵션으로 --pretty=oneline을 주게 되면 커밋당 한줄로 잘 보여준다
(git log --pretty=oneline)
git show
어떤 파일이 어떻게 변했는지 보는 방법
git show + 커밋 아이디(앞 4자리 정도만 써줘도 된다)
빨간색으로 나오는 것이 이전 커밋에 있던 README파일의 모습
초록색이 해당 커밋에서 README파일의 모습
-m 옵션 없이 git commit만으로 커밋 메시지 남기기
m옵션 없이 git commit만 입력하면 vim으로 작성할 수 있게 된다
장점: 복잡하고 긴 커밋 메시지를 쉽게 남길 수 있다
최신 커밋 수정(--amend)
vscode에서 수정 후 저장 - 터미널에서 git commit --amend 입력 - vim에서 수정
수정하면 커밋의 아이디가 바뀐다
alias
커맨드가 긴 경우 alias를 통해 설정할 수 있다
git log --pretty=oneline 이것을
git config alias.history 'log --pretty=oneline'를 통해
git history라고만 써도 작동하게 된다
두 커밋 간의 차이 보기
git diff + 비교적 오래된 커밋 아이디 + 비교적 최근 커밋 아이디
HEAD
어떤 커밋 하나를 가리킨다(보통 가장 최근에 한 커밋을 가리킴)
HEAD가 가리키는 커밋에 따라 working directory 구성
매번 더 새로운 커밋을 가리킴
git cat을 했을 때
HEAD가 가리키는 시점의 커밋의 working directory를 보여준다
Git reset
github에 push만 잘해두면 git pull을 써서 다시 되돌릴 수 있다
working directory: cat 파일명
staging area: git status
git reset
HEAD가 이전 커밋을 가리키게 하는 커맨드
(git reset --hard + 커밋의 아이디)
(git reset --hard HEAD^) 현재 HEAD가 가리키는 커밋 바로 이전
(git reset --hard HEAD~x) 현재 HEAD가 가리키는 커밋 x단계 이전
HEAD가 가리키는 커밋에 따라 working directory가 달라진다
git reset의 3가지 옵션
--soft
repository: HEAD가 이전 커밋을 가리킴
staging area: 안바뀜
working directory: 안바뀜
--mixed
(working directory는 가장 최근에 작업했던 모습 그대로이다)
repository: HEAD가 이전 커밋을 가리킴
staging area: 이전 커밋처럼 바뀜
working directory: 안바뀜
--hard (별로 권장되지 않는다)
(HEAD가 가리키는 커밋 이후로 한 작업이 전부 사라진다)
repository: HEAD가 이전 커밋을 가리킴
staging area: 이전 커밋처럼 바뀜
working directory: 이전 커밋처럼 바뀜
git reset 정리
git reset [옵션][커밋 아이디] : 옵션에 따라 하는 작업이 달라짐(옵션을 생략하면 --mixed 옵션이 적용됨)
HEAD가 특정 커밋을 가리키도록 이동시킴(--soft는 여기까지 수행)
staging area도 특정 커밋처럼 리셋(--mixed는 여기까지 수행)
working directory도 특정 커밋처럼 리셋(--hard는 여기까지 수행)
그리고 이때 커밋 아이디 대신 HEAD의 위치를 기준으로 한 표기법(예 : HEAD^, HEAD~3)을 사용해도 됨
과거의 커밋으로 git reset을 한다고 그 이후의 커밋들이 삭제되는 게 절대 아닙니다. 계속 남아있습니다.
git reset은 과거의 커밋뿐만 아니라 현재 HEAD가 가리키는 커밋 이후의 커밋으로도 할 수 있습니다.
git reset 후
git reset을 해도 그 이후 커밋들은 삭제되지 않는다
단지 헤드가 가리키던 브랜치가 새로운 커밋을 가리킬 뿐이다
다시 git reset + 가장 최근 커밋 아이디를 하면 돌아온다
git reflog(reference log)
가장 최근 커밋의 아이디를 모를 경우 사용
(헤드가 이때까지 가리키던 커밋들을 기록한 정보를 보여준다)
커밋에 tag 달기
태그(tag)
보통 프로젝트에서 주요 버전의 시작점이 되는 커밋에 Version1, Version2 같은 태그를 단다
git tag + 태그 이름 + 커밋 아이디
ex) git tag Version_1 84ab
커밋 메시지 작성 가이드라인
(1) 커밋 메시지의 제목과 상세 설명 사이에는 한 줄을 비워두세요.
(2) 커밋 메시지의 제목 뒤에 온점(.)을 붙이지 마세요.
(3) 커밋 메시지의 제목의 첫 번째 알파벳은 대문자로 작성하세요.
(4) 커밋 메시지의 제목은 명령조로 작성하세요.(Fix it / Fixed it / Fixes it)
(5) 커밋의 상세 내용에는 이런 걸 적으면 좋습니다.
왜 커밋을 했는지
어떤 문제가 있었고
적용한 해결책이 어떤 효과를 가지는지
(6) 다른 사람들이 자신의 코드를 바로 이해할 수 있다고 가정하지 말고 최대한 친절하게 작성하세요.
(7) 하나의 커밋에는 하나의 수정사항, 하나의 이슈(issue)를 해결한 내용만 남기도록 하세요.
(8) 현재 프로젝트 디렉토리의 상태가 그 내부의 전체 코드를 실행했을 때 에러가 발생하지 않는 상태인 경우에만 커밋을 하도록 하세요.
Branch
branch
하나의 코드 관리 흐름
ex) git history를 했을 때 나오는 것을 branch라고 부른다
branch 만드는 방법
git branch + 파일명
branch 이동
git checkout + 이동할 branch
이동 후 작업을 하고 commit을 하면 이동한 곳의 branch에만 반영된다
다시 main으로 돌아와서 cat 파일명을 하면 원래대로이다.
(유료버전, 무료버전 이런식으로 두개를 만들 때 branch를 만들어서 따로 작업한다)
git branch
현재 존재하는 모든 branch 확인
branch 삭제
git branch -d 파일명
-d(delete)
git checkout -b 파일명
branch 만들고 바로 그 브랜치로 이동하는 방법
-b(branch 생성 + 이동)
branch merge하기
git merge main
현재 위치인 premium branch에
main branch를 합치겠다는 뜻
merge할 때 conflict
ex) premium은 def divide_premium(a, b):
maim은 def divide_free(a, b):
두개의 이름이 다른데 merge하려고 하면 conflict가 발생한다
이를 해결하기 위해서는 conflict가 발생한 파일을 열고 merge의 결과가 되었으면 하는 모습대로 코드를 수정하고 커밋을 해주면 된다.
HEAD와 브랜치의 관계
브랜치는 하나의 커밋을 가리킨다
HEAD는 브랜치를 가리킨다
(HEAD -> branch -> commit)
git checkout primium을 하면 HEAD는 primium branch를 가리키게 되는 것이다
merge는 헤드가 가리키던 커밋에 다른 브랜치가 가리키던 커밋을 합쳐서 새로운 커밋(머지 커밋이라고 한다)을 만드는 작업이다.
merge
종류
Fast-forward 머지: 새로운 커밋이 생기는 게 아니라 단지 브랜치가 이동하게 되는 머지
커밋 히스토리에서 같은 선(line) 상에 있는 브랜치를 머지할 때 Fast-forward 머지가 이루어집니다
3-way 머지
경우 base master premium 머지 결과
case1 A A B -> B
case2 1 2 1 -> 2
case3 "hello" (공백) "hello" -> (공백)
case4 "bye" "fighting" "please" -> Conflict 발생!
3-way merge는 base때의 내용과 비교했을 때 달라진 부분이 있는 것이 우선시되고,
두 브랜치에서 둘다 변화가 일어났을 때는 Conflict를 발생시켜서 사용자가 스스로 선택하게끔 한다는 걸 기억하시면 됩니다.
3-way merge는 두갈래로 나누어지는 것을 말한다(갈라지는 곳의 커밋, 갈라지고 맨 마지막 커밋, 갈라지고 맨 마지막 커밋 이렇게 커밋 3개를 고려하기 때문)
Git pull
git push 전에 git pull을 해야 하는 경우가 많다
로컬 레포지토리와 리모트 레포지토리의 최신 커밋이 다른 경우
(다른 개발자가 리모트 레포지토리에 새로운 것을 git push 해서 내 로컬 레포지토리와 리모트 레포지토리의 최신 커밋이 다른 경우)
git push를 하면 push가 되지 않는다 이미 다른 사람이 해놓은 것이 있는데 내 것을 그냥 반영하면 덮어씌워질 수 있기 때문이다
일단 git pull을 해야한다 그러면 다른 개발자가 작업한 내용이 현재 내 브랜치에도 반영된다
이걸 하면 대부분 conflict가 발생한다
해결 후 다시 commit을 하면 된다
그러면 merge하는 커밋이 생긴다
그 후 git push를 해주면 된다
(git pull은 리모트 레포지토리에 있는 브랜치를 가져와서 현재 브랜치에 자동으로 merge하는 커맨드)
Git fetch
git fetch
git pull과 다르게 merge는 하지 않고 가져오는 단계까지만 하는 것
리모트 레포지토리에 있는 브랜치의 내용을 일단 가져와서 살펴본 후에 머지하고 싶을 때 사용
git fetch로 가져와서 git diff로 확인
Git blame
Git revert
git revert
git revert + 커밋 아이디
최신 커밋에서 한 작업을 되돌리고 다시 커밋 해주는 커맨드
되돌린 커밋이 삭제되지는 않고 revert한 커밋이 새로 생긴다
git reset을 하면 안되는 이유는 git reset을 하면 로컬 레포지토리의 헤드는 이전 커밋을 가리키게 되는데 리모트 레포지토리는 현재 커밋을 가리키고 있기 때문에 git push를 하면 우선 git pull을 하라고 에러가 뜨기 때문이다
여러 커밋 취소
git revert + 커밋 아이디..커밋 아이디
(맨 앞 커밋 아이디는 포함되지 않는다)
--graph
Git rebase
Git stash
git stash
어떤 브랜치에서 하던 작업을 아직 커밋하지 않았는데 다른 브랜치로 가야하는 상황에 사용
stash(안전한 곳에 보관하다, 넣어두다)
working directory에서 작업하던 내용을 깃이 따로 보관
보관장소(stack)
저장공간 확인 git stash list
최근 커밋 이후로 작업했던 내용은 모두 스택에 옯겨지고 working directory 내부는 다시 최근 커밋의 상태로 초기화된다
git stash apply + 작업 내용의 아이디
스택에 있는 내용을 다시 working directory로 가져와서 적용
잘못된 브랜치에서 작업했을 때
git stash로 stack에 작업 내용 저장
올바른 브랜치로 가서 다시 git stash apply를 한다
stack에 작업 내용이 계속 쌓여서 이미 적용한 작업 내용은 지워주는 것이 좋다
git stash drop + 작업 내용의 아이디( ex)stash@{0} )
Git cherry-pick
Git 정리
Git 써보기
GitHub 시작하기
Git에서 커밋 다루기
git log : 커밋 히스토리를 출력
git log --pretty=oneline : --pretty 옵션을 사용하면 커밋 히스토리를 다양한 방식으로 출력할 수 있습니다. --pretty 옵션에 oneline이라는 값을 주면 커밋 하나당 한 줄씩 출력해줍니다. --pretty 옵션에 대해 더 자세히 알고싶으면 이 링크를 참고하세요.
git show [커밋 아이디] : 특정 커밋에서 어떤 변경사항이 있었는지 확인
git commit --amend : 최신 커밋을 다시 수정해서 새로운 커밋으로 만듦
git config alias.[별명][커맨드] : 길이가 긴 커맨드에 별명을 붙여서 이후로는 별명으로도 해당 커맨드를 실행할 수 있게 설정
git diff [커밋 A의 아이디][커밋 B의 아이디] : 두 커밋 간의 차이 비교
git reset [옵션][커밋 아이디] : 옵션에 따라 하는 작업이 달라짐(옵션을 생략하면 --mixed 옵션이 적용됨)
git tag [태그 이름][커밋 아이디] : 특정 커밋에 태그를 붙임
Git에서 브랜치 사용하기
Git 실전 I
Git 실전 Ⅱ
! 그 밖에 알아야할 사실
(1) git commit이라고만 쓰고 실행하면 커밋 메시지를 입력할 수 있는 텍스트 에디터 창이 뜹니다. 거기서 커밋 메시지를 입력하고 저장하고 나면 커밋이 이루어집니다.
(2) git push와 git pull은 그 작업 단위가 브랜치입니다. 예를 들어, master 브랜치에서 git push를 하면 master 브랜치의 내용만 리모트 레포지토리의 master 브랜치로 전송되지, premium 브랜치의 내용이 전송되는 것은 아닙니다.(git push에 --all이라는 옵션을 주면 모든 브랜치의 내용을 전송할 수 있기는 합니다.)
Git 작업 순서