Git은 버전관리 + 백업 + 협업의 목적으로 사용하는 툴로, 과거 리눅스 토발츠가 자신이 사용하던 버전관리 시스템이 유료화가 되자 화가나 만든 프로그램이라고 한다.
Git을 사용하기에 앞서 Git은 새로운 버전을 만들 때, 이전 버전에 대한 정보를 복사한 후 새로 저장하기 때문에 과거에 작업했던 어떠한 정보도 버리지 않는다는 것을 기억하자.
git시작 명령어
- git init
: 현재 폴더를 대상으로 git이 작동하기 때문에pwd
로 현재 폴더 확인하는 것이 중요하다
구성
- Working directory
: 현재 작업 폴더
- Stage Area
: working directory에서 바꾼 내용을 적용하고 싶은 것들을 담은 장바구니라고 생각하자
- Repository
: Stage Area에 있는 내용을 그대로 캡쳐해서 저장해 놓은 곳
- Head
: 현재 working directory를 가리킨다.
: 즉, 현재 작업하고있는 버전을 가리킨다.
- Master
: 최종 실험 완료된 버전을 가리키고 있다.
: 즉, 마지막으로 작업했던 버전을 가리킨다.
여기서는 잘 이해가 되지 않겠지만 뒤의 내용을 읽어보면 점점 이해가 될 것이다.
해당 파일의 변경사항을 Stage Area에 저장한다.
Stage Area
.git폴더 안에 index라는 폴더를 의미한다.
(index, cache라고도 불린다.)
git add로 새롭게 추가된 변경사항을 표시해 준다.
새롭게 추가된 변경사항들만 보여주므로 따로 변경되지 않은 것들은 표시되지 않는다.
(물론 Commit시에는 변경되지 않았던 것들도 함께 저장한다.)
Stage Area에 있던 작업 내용을 추적하고 있는 다른 파일들의 내용과 함께 Repository(.git)에
Commit_ID
,Parent Commit_ID
와 함께 저장하고,Head가 가리키는 Commit_ID를 새로운 Commit_ID로 변경한다.
(단, Head가 Master를 가리키고 있는 경우 Master를 변경)
Commit_ID
: USER.NAME, USER.EMAIL, Commit시간 등을 함께 고려하여 SHA1이라고 하는 Hash알고리즘을 활용해 ID를 생성한다.
Parent Commit_ID
: 현재 Head에 저장된 Commit_ID가 Parent Commit_ID가 된다.
(단, Head가 Master를 가리키고 있는 경우 Master가 가리키는 ID)
주된 컨셉은 Master에 Main작업을 저장해 놓고, Head를 움직여 가며 실험한다고 생각하면 된다.
이때, 위의 그림과 같이 Version은 3가지의 상태가 존재하게 된다는 것을 유의하자.
HEAD를 옮기는 명령어이다.
이때, 옮기고자 하는 Commit_ID가 필요한데, 이것을 확인하기 위해서는 아래의 git log부분을 통해 알 수 있다.
명령
git checkout master
: 현재로 돌아옴
git checkout [Commit_ID]
: 해당 작업으로 시간여행 시작
예시
git checkout master
의 경우
:HEAD -> MASTER -> 3
의 상태가 될 것이다.
git checkout 3
의 경우
:HEAD, MASTER -> 3
의 상태가 될 것이다.
Head에 저장된 Commit_ID로부터 시작해 Parent를 찾아 가면서 화면에 표시해 준다.
즉, 이 명령을 통해 Head의 조상 Version들에 대한 Commit_ID를 알 수 있다.
명령/옵션
git log --oneline
: 요약본으로 확인git log --oneline --all
: Master에서도 같은 작업을 하여 보여줌
참고
위의 과정을 살펴보자, 잘 생각해보면 이상한 점을 알 수 있는데, 바로 Head와 Master의 조상이 아닐 경우에는
git log
를 통해 알 수 없다는 점이다.
(위의 그림에서 5번 노드를 생각해보자)즉, 해당 Commit_ID를 알 수 없어 checkout을 할 수 없게 되는데 이 경우에는 다음의 명령을 활용해야 한다.
git reflog
![]()
git에서 reference(HEAD, Master, Tag)의 변화를 보여주도록 하는 명령어
위의 명령으로는 전체의 version graph를 확인할 수 없다.
commit ID에 새로운 이름을 붙여주는 명령어
명령
git branch [branch이름]
: 현재 HEAD가 가리키는 버젼에 새로운 이름(branch)을 만든다
주의점
이때, 위의 그림과 같이 Head가 가리키는 버젼에 새로운 이름을 붙이는 것 뿐이지 HEAD는 여전히 버전을 가리키게 된다.
![]()
즉, Detached Head State가 유지되는 것이므로 될 수 있으면 바로
git checkout [branch이름]
을 한번 더 사용해 주어 위와 같이 다시 HEAD가 브랜치를 가리키도록 해주자..!
브랜치들을 합쳐주는 명령어
명령
git merge [Commit_ID/branch 이름]
-> 현재 Head가 가리키고 있는 내용과 Commit_ID에 있는 내용을 병합한다.(이때, 3-way mege 기법을 사용한다. -자세한건 아래 conflict 내용 참조)
1. 실험이 실패한 경우
: 위에서 보았던 것처럼 그냥 해당 branch를 버리고 HEAD를 Master로 옮기면 된다.
그냥 checkout으로 Head의 위치를 옮긴다.
2. 실험이 성공한 경우
:
Master
가실험1
을 merge하면 된다.Head가 Master에 있는 상태에서 실험1에 대해 Merge를 시도한다.
3. 실험 도중 Master에서 작업한 내용이 필요한 경우
:
실험1
이Master
를 merge하면 된다.Head가 실험1에 있는 상태에서 Master에 대해 merger를 시도한다.
(이 작업을 자주 해 놓아야 나중에 합칠 때, 충돌이 매우 적어져서 편해진다.)
(자주 해놓지 않으면 나중에 지옥을 맛보게 된다고 함...)
Head가 가리키는 브랜치가 다른 커밋을 가리키도록 하는 명령어
(즉, 이것을 사용하면 Master자체를 옮길 수 있다.)
명령
git reset --hard [Commit_ID]
git checkout vs git reset
위 두 명령의 차이점에 대해 잘 생각해 보면 reset을 좀 더 이해할 수 있을 것이다.
git merge
명령시 Base-Head-대상의 3자 대면을 하고, 다음과 같은 과정을 통해 merge를 수행한다.
- Merge의 대상이 되는 공통의 조상(Base)을 찾는다.
- Base와 Merge의 대상들을 비교해 다음의 두 종류로 나눈다.
- Base에서 변경되지 않은 내용
- Base에서 수정한 내용
- Merge시 2번에서 나눈 내용들을 다음의 기준으로 합친다.
- 수정X + 수정X = 수정X
- 수정O + 수정X = 수정O
- 수정O + 수정O = Conflict
- Accept Current Change
- Accept Incoming Change
- Accept Both Change
- Compare Changes