Git 이란 분산형 관리 시스템 형태의 형상 관리 도구이다.
💡 형상 관리 도구란? 과거 작업 내역과 현재 작업 내역, 변경점을 확인할 수 있도록 만들어진 도구이다. **즉 버전 관리 도구라고도 한다.******소프트웨어 개발에 필요한 소스코드를 효과적으로 관리 할 수 있게 해주는 프레임 워크 중 하나이다.
대표적으로 SVN과 Git 이 존재하는데, SVN은 중앙 서버 저장소에서 소스 코드와 히스토리를 저장하는 형태이며, Git은 로컬 저장소와 서버 저장소를 분산해서 저장할 수 있다는 것이 차이점이다.
SVN(중앙집중식)
GIT(분산관리식)
.git/objects
blob : 텍스트, 이미지, 음악 등 다양한 형식의 파일이 저장 될 수 있다. 즉 , 파일의 내용(contents)를 담는다. git 저장의 기본 단위라고 볼 수 있다.
//해시 파일에 압축된 내용을 프린트
git cat-file -p [hash]
//해시 파일의 타입을 확인
git cat-file -t [hash]
해당 blob의 내용을 확인하고 싶으면 위에 작성된 명령어를 입력하면 된다.
tree: 디렉토리의 파일명 & 내용명에 정보를 담는 곳이다.
commit : 고유한 id를 지니고 있으며 hash 정보를 통하여 저장된다.
tag :
.git/refs
.git/logs
.git/hooks
.git/index
.git/FETCH_HEAD
local (Working Directory)
사용자 컴퓨터 내부의 폴더. 저장소로 인식되는 폴더는 .git 이라는 숨김 폴더를 가지고 있다. 로컬 저장소는 네트워크 통신이 필요하지 않다.
remote
원격 서버에 존재하는 저장소, 즉 소스 코드를 저장하고 공유할 수 있는 원격 저장소를 제공하는 대표적인 서비스로 Github, GitLab, Bitbucket 등이 있다.
upstream , downstream
fork → upstream : 오리지널 레퍼지토리 origin : fork한 레퍼지토리 downstream : orgin
clone → upstream : fork한 레퍼지토리 (origin) downstream : local
Github vs Gitlab
Github
- 공개적으로 사용 가능한 무료 서비스, 유료 서비스를 포함한 깃 저장소 호스팅을 지원하는 웹 서비스
Gitlab
- 개인 또는 조직이 Git repository의 내부 관리를 상용할 수 있다. 즉, 각 조직에서 서버를 설치하여 git 저장소를 운영할 수 있다.
**차이**
- 모두 git repository를 중심으로 개발 업무를 진행하는데 있어서 큰 차이는 없다.
- 소스코드 관리 이슈 트래킹, 모니터링 등 gitlab 하나로 많은 편의를 제공하고 있어서 github보다는 실무적으로 더 많이 사용되고 있다.
git 영역
코드가 Commit 될 때, 3가지 영역을 거친다.
1) Working Directory → 사용자가 코드를 작업하고 관리하는 프로젝트 디렉토리
2) Staging Area → git add를 통해서 수정된 코드를 올리는 영역. 바로 Repository에 올라가지 않고, Staging Area에 소스코드가 올라간다.
3) Repository → Staging Area에 올라간 코드들 중 git commit를 통해 최종 수정본을 저장소에 제출
git Status(파일 상태)
File의 관점에서는 4가지 상태가 존재한다.
untracked : Git에 add 되지 않은 상태, 즉 git으로 버전 관리가 되어 있지 않은 상태
unmodified : Git에 add 되었지만, 수정되지 않은 상태(new file과 동일).
modified : 이미 git으로 추적하고 있고, 파일이 수정되어 있는 상태(stage에 올라가 있지 않음)
staged : 파일이 수정 완료되어 commit할 준비가 되어 있는 상태, 즉 Staging Area에 반영된 상태
git HEAD
HEAD란? 현재 체크아웃된 브랜치의 이름을 가리키는 용어이다.
즉, 현재 내가 어떤 작업 공간에 머물고 있는지를 나타낸다. HEAD는 default로 master를 바라본다.
HEAD → koi.mcw_0.2 : 현재 koi.mcw_0.2 라는 브랜치의 커밋이 로컬 저장소의 최종 커밋, 즉 현재 작업 공간은 koi.mcw_0.2 브랜치임을 뜻한다.
git Branch
software 개발 시, 동일한 소스 코드 위에서 신규 개발, 버그 수정 등의 업무 협업을 할 시, 여러 개발자들이 동시에 다양한 작업을 할 수 있도록 하는 기능이다. 즉, 브랜치를 통해 하나의 프로젝트를 여러 버전으로 관리할 수 있다.
분기된 브랜치에서 수정을 한 후 커밋하면, master 브랜치에는 어떠한 영향을 끼치지 않는다. 따라서 반영하고 싶은 브랜치가 있다면 master 브랜치와 병합하고, 반영하고 싶지 않은 작업이 있는 브랜치는 삭제하면 된다.
//현재 체크아웃된 branch 확인 or branch list 확인
git branch
//branch 생성
git branch 브랜치명
//해당 브랜치로 이동
git checkout branch 이름
//master 브랜치로 이동
git checkout master
//branch 삭제 -> master 브랜치로 체크아웃 후 가능
git branch -d branch 이름
git fork vs git clone
fork
clone
git fetch vs git pull
협업 시, 다른 팀원이 원격 저장소에 먼저 변경 사항을 커밋하고 push 했을 경우 사용
fetch
pull
요약
git push
프로젝트 내에 추가되거나 수정된 소스코드를 공유하고 싶을 때, upstream 저장소로 push할 수 있다.
//git push 기본 명령어
git push <리모트 저장소 이름> <push할 브랜치 이름>
//git push 시, push할 remote 저장소의 upstream branch 설정
git push --set-upstream origin master
//원격 저장소의 브랜치와 로컬 저장소의 브랜치를 자동으로 연결
//git push or git pull 명령어 만으로 브랜치 간 연결이 가능해 진다.
git push -u <리모트 저장소 이름> <push할 브랜치 이름>
해당 명령어는 Clone 한 리모트 저장소에 쓰기 권한이 있고, Clone 하고 난 이후 아무도 Upstream 저장소에 Push 하지 않았을 때만 사용할 수 있다.
즉, 다른 사용자가 먼저 push를 했을 경우에는 곧바로 push할 수 없고, remote에 올라가 있는 데이터를 로컬로 merge한 이후에, 새롭게 push할 수 있다.
origin vs master vs origin/master
origin : remote 저장소 이름. git clone을 통해 원격 저장소를 복사하면 자동으로 origin이라는 이름의 원격 저장소가 등록된다.
master : 가장 중심이 되는 기본 브랜치
origin/master : remote의 중심이 되는 브랜치
git checkout
git checkout은 크게 두 가지 기능이 있다.
-Branch 또는 코드를 특정 커밋 시점으로 되돌릴 때 (switch 기능)
-내용 되돌리기 (restore 기능)
이때 커밋으로 시점을 되돌릴 시 , head는 detach 즉, 브랜치를 참조하지 않은 상태가 된다.
detach 상태인 head에서 커밋을 계속 생성해도, 참조하는 브랜치가 없어서 commit되지 않은 내용이라고 인식하여 삭제된다. 커밋 생성 후 내용을 유지하려면, 새로 브랜치를 생성해서 참조하던지, 기존의 브랜치를 참조하도록 하던지 선택해야 한다.
//특정 커밋으로 되돌리기
git checkout [커밋 해시값]
//특정 브랜치 생성 후 해당 브랜치로 이동
git checkout -b 새로운 브랜치 이름
//특정 커밋으로 되돌린 뒤, 특정 브랜치를 해당 커밋으로 참조하도록 하기
//브랜치를 새로 생성하거나, master 브랜치를 해당 커밋 시점에 참조하도록 하면 된다.
git checkout -B [브랜치 이름] [커밋 해시값]
//모든 변경사항을 취소
git checkout .
git merge
- 다른 Branch의 버전을 현재 Branch로 가져와서 병합 시키는 작업을 의미한다.
- fetch를 통해 변경 사항을 비교 대조 한 후, merge로 원격 저장소의 변경 사항을 로컬 저장소에 반영한다.
- 새로운 브랜치에서 개발을 완료하고 merge 하기 위해서는 master 브랜치에 checkout되어 있어야 한다.
// 병합하기 위해 master 브랜치 checkout
git checkout master
// 병합할 branch 설정
git merge 브랜치 이름
머지가 완료되었다면 다음 메시지를 확인할 수 있다.
Merge made by the 'recursive' strategy.
example.txt | 1 +
1 file changed, 1 insertion(+)
병합이 완료되었다면 작업했던 브랜치를 삭제한다.
//병합되지 않은 브랜치를 삭제하려면 -d -> -D로 쓴다.
git branch -d 브랜치 이름
1. Fast - forward 방식
분기된 브랜치(develop)는 master가 가지고 있는 모든 내용을 포함하고 있으므로, master 보다 더 최신버전이라고 할 수 있다. master에서 추가로 커밋이 이루어지지 않고 병합하게 된다면, master에는 최신화된 브랜치(develop)의 내용이 추가로 붙게 된다.
2. 3-way-merge(Recursive merge)
develop에서 기능 개발 후, 커밋을 한 뒤에 master에서 추가적인 커밋이 있었다고 가정했을 때, 분기된 branch는 master보다 최신 버전이라고 보기 어렵다. 이때 master와 develop이 서로 다른 내용을 가지고 있으므로, 내용을 합친 뒤(Fast -forward) 새로운 커밋 메시지를 만들어(Recursive) 병합한다.
즉, base(A)와 base에서 뻗어나간 브랜치가 참조하는 커밋(B,C)을 비교하여 병합 후 새로운 커밋을 생성하는 방식이다.
merge option
/* merge option */
// -ff : 두 브랜치가 fast -forward 관계일 경우,
//-ff 명령어 사용 시, merge commit을 생성하지 않고 브랜치의 참조만 변경한다.
//git merge의 default option
git checkout master
git merge -ff 분기 브랜치
/* merge option */
//--no-ff : fast-foward 관계여도, 강제로 merge commit 을 생성하고 병합
git checkout master
git merge --no-ff 분기 브랜치
Github에서 제공하는 Merge 방식에는 Merge, Squash and Merge, Rebase and Merge로 총 3가지가 있다.
1) Merge
git checkout master
git merge <분기 브랜치명>
하나의 브랜치와 다른 브랜치의 변경 이력 전체를 합치는 방식
병합하기 전, master 브랜치에 checkout이 되어 있어야 한다.
2) Squash and Merge
git merge --squash <분기 브랜치명>
master에서 병합 시, develop의 커밋 이력을 삭제하고, 해당 브랜치에서 작업했던 커밋 내역들을 새로운 커밋을 생성하여 해당 커밋에 모두 담기게 하는 병합 방식이다.
-squash 옵션을 사용하면 커밋까지 생성하지 않는다.상대 브랜치의 작업 내용이 추가되어 파일 상태만 변경된다.--squash 옵션으로 merge를 진행하면 분기 브랜치의 최신 commit이 merging commit을 참조하지 않아서 merging 정보가 표시되지 않는다. 따라서 master 브랜치 관점에서는 병합에 대한 이력이 남지 않게 되는 것이다.3) git rebase & merge
rebase란 ?
현재 브랜치의 Base를 재설정하고 합치는 것.
각각의 브랜치는 base를 가지고 있다. 해당 base로부터 코드를 수정하고 commit한다.
각각의 개발자가 merge를 하게 되면, git history가 서로 엉키게 된다. 이러한 분기 branch들의 history를 깔끔하게 재정렬 해주는 것이 rebase 기능이다.
develop 브랜치에서 이루어진 커밋 내역들을 master 브랜치에 rebase 하여 커밋 내용을 재배치하고 추가 커밋 메시지 없이 병합된다. 이때, Base가 바뀐 커밋들이 이동하는 것이 아닌, rebase될 브랜치에 복사되는 것이다.
(rebase 전 후를 살펴보면 commit message는 동일한데, commit id가 바뀐 것을 확인할 수 있다)
주의할 점은, rebase는 rebase 대상이 될 분기 브랜치에, merge는 기존의 중심 브랜치에 체크아웃된 상태에서 진행되어야 한다.
git rebase [base 브랜치명](master)
git checkout [브랜치명](master)
git merge [분기 브랜치명]
git restore
git의 파일 조작(특정 커밋으로 되돌리기, Unstaging 시키기) 의 기능을 지원하는 명령어
//특정 파일 HEAD Commit으로 복구하기
git restore [파일이름]
//특정 파일을 특정 Commit을 복구하기
//커밋 해시값에는 'HEAD'가 들어갈 수도 있다.
git restore --source [커밋 해시값] [파일 이름]
//Staging Area에 올라간 파일 다시 Unstaging 시키기(git add 이전 상태)
git restore --staged [파일이름]
git reset vs git revert
git reset
git restore은 파일 단위의 제어를 명령했다면, git reset은 전체 파일을 제어하기 위한 명령어
전체 파일들이 특정 커밋으로 돌아가기 위해 사용된다.
//취소 하고 싶은 commit : aea80d9
//현재 작업 위치인 HEAD의 포인터를 이전의 커밋으로 변경
git reset --hard/--soft/--mixed 86cd811
—soft 옵션은 작업 디렉토리와 인덱스를 보존, 즉 파일이 스테이징된 상태를 유지한다.(커밋된 코드가 리셋 이후에도 사라지지 않는다.)
커밋만 변경한다.
—mixed 옵션은 변경 이력을 모두 삭제하지만 변경 내용(소스코드)는 유지한다. 이때 파일은 unstaged 상태이기 때문에 , add 명령어로 stage에 올리고 커밋해야 한다.
커밋, 인덱스를 변경한다.
—hard 옵션은 현재 HEAD에서 추가된 변경사항을 모두 되돌려준다. 이때, git 저장소에서 관리하지 않는 파일(Untracked files)를 추가한 경우에는 reset 이후에도 그대로 유지된다. 해당 파일들 까지 삭제하고 싶은 경우에는 git clean을 따로 실행한다.
커밋,디렉토리,인덱스를 변경한다.
hard 옵션으로 인해 지워진 commit을 되돌리려면 git reflog 명령어를 사용한다.
//삭제하기 이전까지의 모든 git 내역 출력
git reflog
//--hard 옵션으로 지운 커밋을 같은 명령어로 복구
git reset --hard [되돌리고 싶은 커밋 해시값]
HEAD^는 헤드의 직전 위치를 의미, 최신 커밋의 부모 커밋을 뜻한다.
//취소 하고 싶은 commit : aea80d9
//현재 작업 위치인 HEAD의 포인터를 이전의 커밋으로 변경
git reset --soft/--mixed/--hard HEAD^
git revert
하나의 커밋에서의 변경사항을 제거하기 위한 새로운 커밋을 만드는 명령어이다. git reset을 사용하면 현재 커밋과 대상 커밋 사이의 모든 커밋이 제거되는 반면에, 하나의 커밋만 제거하기 위해서는 git revert를 사용한다.
//특정 커밋의 변경사항 제거하기
git revert [커밋 해시값]
//바로 커밋으로 올리지 않고, stage area에 머무르도록 하기
git revert --no-commit [커밋 해시값]
//이후
git commit -m "커밋 메시지"
//여러개 커밋을 되돌리기
git revert [커밋 해시값] [커밋 해시값] ...
revert는 기본적으로 가장 최근의 커밋을 되돌릴 수 있도록 되어있다. 최신 커밋보다 더 이전의 커밋에 대해 revert를 하게 되면, 이후에 새로 생성된 커밋들의 내용과 충돌이 감지될 수 있다.
Solution : 최신 버전들을 모두 역순으로 revert 해서 원하는 지점의 커밋까지 revert 되어야 한다.
git stash
워킹 디렉토리에서 수정한 파일들을 임시저장한다.
// 임시 저장할 내용 stash 등록
git stash
// stash 내역 확인
git stash list
// stash에서 내용 꺼내오기
git stash apply
// stash에서 내용 꺼내오고, 목록에서 삭제
git stash pop
// 임시 커밋 내용에 메시지 부여하기
git stash -m '임시저장1'
.gitignore
Git의 root 디렉토리에 저장되어, Git Repository나 Staging Area에 추가되지 말아야 하는 폴더나 파일을 정의하는 파일. Staging Area에 올라가지 않기 때문에, tracking 되지 않는다.
참고
fork vs clone
https://velog.io/@imacoolgirlyo/Git-fork와-clone-의-차이점-5sjuhwfzgp
github vs gitlab
https://anothel.tistory.com/159
https://ko.wikipedia.org/wiki/깃랩
.git 폴더 구조 분석
https://tecoble.techcourse.co.kr/post/2021-07-08-dot-git/
git에서 만나는 이슈 정리/명령어 정리
https://parksb.github.io/article/28.html
pull vs fetch
https://devlog-wjdrbs96.tistory.com/236
origin, upstream, downstream
https://alkhwa-113.tistory.com/entry/upstream-vs-origin
git object 내부 파해치기
https://storycompiler.tistory.com/7
git restore
git merge방식
https://mangchhe.github.io/git/2021/09/04/GitMerge/
sourcetree 에서의 git rebase
git reset
https://git-scm.com/book/ko/v2/Git-도구-Reset-명확히-알고-가기