git status
깃 이론 포스팅에서 우리는 깃 내부 레포지토리에서 파일을 총 5단계의 상태로 구분한다.
git status는 각 파일들의 상태를 볼 수 있는 명령어다.
첫번 째는 가장 기본적인 git status의 결과고 오른쪽은 git status -s 옵션으로 short 즉 짧은 포맷으로 출력한 내용이다.
다양한 옵션은 공식문서를 참고하자.
git add
공식문서에서는 변경된 파일내용을 index에 더하는 명령어라고 한다.
이론 포스팅을 보면 index는 다음 포스팅에서 stagingArea라고 한다.
간단한게 말하면 modified된 파일을 staged하는 명령어다.
한번이라도 add가 됐다면 그 파일은 이제 git에게 tracked되는 상태가된다.
사용은 다음과 같다.
다음과 같이 staged할 파일들을 나열하거나.
git add file1 file2 ...
현재 .을 통해서 현재 레포지토리의 모든 modified된 파일을 올릴 수 있다.
git add .
git diff
git diff 명령어는 단순히 파일이 변경됐다는 사실이 아니라 어떤 내용이 변경됐는지 살펴 볼 때 사용된다.
어떤 라인을 추가하고 삭제했는 지 궁금할 때 사용된다.
git commit
staged 된 파일들을 커밋 메시지라는 Label을 붙혀 로컬 데이터베이스에 안전하게 저장하는 명렁어다.
우리는 데이터 객체를 배울 때 commit이라는 객체를 배웠다.
바로 그 객체가 git commit 명령어를 통해 생성된다.
커밋 객체는 현재 내부 레포지토리 상태인 트리에 대한 정보와 바로 직전의 커밋(부모 커밋)을 갖고 있다.
learnig git 홈페이지를 통해 한번 자세히 봐보자.
현재 c1이 가장 최신 커밋 객체였는데 git commit을 하니 C2가 C1을 부모 커밋으로 가르키고
또한 C3도 C2를 부모 커밋으로 가르키고 있다.
여기서 보면 C1, C2, C3는 commit ID를 의미하는데 실제로는 어떤 형태일까??
우리는 이미 배웠다. 바로 오브젝트 파일은 생성할 때 총 40글자의 체크섬(해시값)을 만들어낸다.
여기서 두 글자는 디렉토리 , 38글자는 오브젝트 파일 이름이된다.
커밋 역시 오브젝트 파일의 종류기 때문에 commit ID는 바로 40글자의 체크섬이된다.
만약 commit iD를 명령어를 매개변수로 쓰면 이 40글자를 매일입력해야할까??
사실 그렇지 않다 우리는 앞 6글자 또는 7글자만 써도된다.
실제로 내가 쓰는 깃 크라켄에서도 아래와 같이 6글자 또는 7글자만 써도 충분히 commit ID를 이용할 수 있다.
하지만 명심해야할 것은 본질적인 commit ID는 40글자라는 것을 잊지말자.
git fetch
git fetch는 다른 저장소로부터 커밋(오브젝트 파일과 참조)들을 다운로드하는 과정이다.
특정 이름의 저장소 또는 URL으로 다운로드 받을 수 있지만 보통은 현재 로컬브랜치에 대한 upstream(remote) 브랜치로부터 받아온다.
여기서 중요한점은 다운을 받았다고 변경사항이 로컬 레포지토리에 바로 반영되는 것이 아닌다.
왜냐하면 깃은 현재 브랜치의 가장 최근 커밋을 가르키는 HEAD라는 포인터가 있는데
fetch는 커밋 정보를 다운을 받지만 HEAD가 옮겨지지는 않습니다.
git merge
merge는 2개 이상의 기록을 합치는 명령어다.
현재 상태가 다음과 같을 때 4가지 형태의 merge 차이를 알아보자.
1. 3 way merge
또 다른 이름은 커밋 머지라고 부르며 대표적인 특징은 두 브랜치의 변경 사항(history)을 모두 유지하며
메인 브랜치에 다른 브랜치를 병합(merge)한다.
이 경우 각 브랜치의 변경 사항들이 과거의 커밋으로 보존되며, 병합 시 메인 브랜치에
새로운 'merge commit'이 추가되며 병합된다.
새로 생긴 커밋 M1 = C2 (공통부모 커밋) + C4(가장 최근 자식 커밋) + D2(분기된 브랜치 가장 최근 커밋)
특징은 다음과 같다.
장점
- 진행 상황을 명확히 추적할 수 있다.
- 브랜치 별 변경 사항이 유지되므로 커밋 아이디가 바뀌지 않는다.
단점
- 병합일 될 때마다 커밋이 생기므로 인원이 많고 병합이 많이 될 수록 그래프가 복잡해진다.
2. Squash Merge
병합할 브랜치의 모든 변경 사항을 하나의 커밋으로 합쳐 메인 브랜치에 병합한다.
이 경우 병합되는 브랜치의 변경 사항들은 사라지며, 모든 변경 사항이 합쳐진 한 개의 커밋이 새로운 아이디를 가지고
메인 브랜치에 추가되며 병합된다.
git merge --squash [병합할 브랜치]
git commit -m "스쿼시 머지용 커밋"
M1 = C4 +D1 + D2
여기서 병합되는 브랜치 feat1 의 커밋 D1,D2가 사라지고 M1에 모두 반영된다.
장점
- 커밋 히스토리를 간단하게 유지 내용이 하나의 커밋에 압축되어 반영된다.
단점
- 병합되는 브랜치의 로컬 커밋 히스토리를 잃버린다.
3. Rebase Merge
현재 위치한 브랜치를, 병합시킬 타겟 브랜치에 재위치(rebase)시킨 뒤 병합한다.
기준이 되는 베이스 브랜치를 타겟 브랜치로 변경(re-base)한다고 생각하면 된다.
현재 위치한 브랜치의 모든 커밋을 타겟 브랜치로 옮기기 때문에 커밋 아이디가 변경된다.
사실은 커밋을 옮기는 것이 아니라 커밋 내용을 복사한 새로운 커밋을 만드는 것이라 커밋 아이디가 달라질 수 밖에 없다.
⚠️ 주의할 점은 원격 저장소에 있는 커밋은 절대 rebase를 금지한다.
실제 커밋이 사라지고 복사본이 남은 특징이 있기때문에 히스토리 추적이 힘들다.
git rebase [타겟 브랜치]
장점
- 커밋 히스토리가 선형적으로 깔끔하게 유지됨
단점
- 기존에 존재하던 커밋 아이디들이 각각 새로운 아이디로 생성되므로 기존 브랜치를 기반으로 한 작업에 문제가 생길 수 있음
- 선형적이라는 특징으로 인해 특정 기능이 어디부터 어디까지의 커밋으로 구현되었는지 알 수 없음
4. Fast-forwad Merge (ff merge)
fast-forward란, 영상이나 소리를 빨리감기(앞으로 감기)한다는 의미한다.
따라서 병합 시 새로운 merge commit을 생성하지 않고,
현재 위치한 브랜치의 최신 커밋 = HEAD가 가리키고 있는 커밋이 병합할 브랜치의 최신 커밋으로 이동하며 병합된다.
메인 브랜치에서 다른 브랜치가 분기되었지만, 다른 브랜치에서만 새로운 커밋이 생기고 메인 브랜치에서는 아무런 변화가 없는 경우 fast-forward merge가 발생합니다.
장점
- 기존의 커밋이 유지되고 HEAD만 옮겨준다.
단점
- fast-forward merge는 항상 발생할 수 없다.
- 특정 조건인 분기된 다른 브랜치만 새로운 커밋이 생기고, 메인 브랜치는 변화가 없어야 사용할 수 있다.
git pull
위에서 git fetch는 commit을 원격 저장소에서 다운로드는 받지만 병합까지 이루워지지 않는다 것을 학습했다.
pull은 다운로드와 동시에 merge가 진행된다.
pull = fetch + merge
좀 더 구체적으로 설명하면, git pull은 제공된 파라미터로 git fetch를 실행한 뒤, 설정 옵션이나 명령어에 포함된 플래그에 따라
분기된 브랜치를 해결하기 위해 git rebase 또는 git merge를 실행한다.
그렇다면 어땐 merge를 진행할까 ?? 우리는 위에서 merge의 4가지 종류를 학습했다.
git pull은 merge하기 전에 어떤 merge를 할 지 정해줄 수 있다.
1. git config pull.rebase false
- 가장 기본적인 3 way merge
- 수정 내용과 conflict 해결 내용 2개의 커밋이 올라간다.
2. git config pull.rebase true
- 충돌이 일어난 코드를 비교하여 수정한 뒤 git rebase --continue를 수행한다.
- false와 결과는 동일하지만, 커밋은 최신 커밋 1개만 올라간다.
3. git config pull.ff only
- ff 관계면 ff를 진행하고 그렇지 않으면 commit을 생성하는 merge를 진행한다.
git branch
깃에서 브랜치란 커밋 사이를 이동할 수 있는 포인터 역할(참조)을 하는 개념이다.
앞에서 배운 HEAD는 이 브랜치를 참조하는 객체다.
정리하면, 브랜치는 특별한 개념이아닌 단순히 커밋을 참조하는 역할을 하며, HEAD는 그 브랜치를 참조하는 객체이다.
또한 보통 브랜치는 그 브랜치의 마지막 커밋을 참조한다.
git branch 명령어는 뒤에 옵션에 따라 생성 / 삭제 / 복사 / 수정 등 .. 다양한 동작을 한다.
대표적인 옵션은 다음과 같다.
옵션 | 설명 | -f 버전 |
-f | 현재 저장하지 않은 상태에서 같이 사용된 명령어들을 강제로 실행함 결과는 보증 못함 |
X |
-m oldBranch newBranch | old branch를 new branch로 이동 또는 rename |
-M = -m + -f |
-c oldBranch newBranch | old branch를 new branch에 복사 | -C = -c + -f |
-d branchName | 해당 브랜치를 삭제 | -D = -d + -f |
옵션 x | 해당 브랜치 생성 |
git switch
현재 위치를 나타내는 HEAD를 특정 위치로 옮기는 옮기는 명령어
HEAD를 옮길 때 필요한 정보는 크게 2가지다.
커밋 id 또는 브랜치다.
여기서 눈치챌만한 사람은 느꼈을 것이다. 사실 필요한 정보는 1개다.
왜나면 브랜치는 가장 최근 커밋을 을 참조하는 역할이므로, 커밋id와 같은 개념이다.
그러면 git switch에 필요한 정보는 커밋만 있으면된다는 뜻
다음 gif를 살펴보자.
main과 b1은 브랜치다.
처음 HEAD는 main에 있다. main*의 뜻은 HEAD가 main과 같다는 뜻이다.
이때 git switch C2 (커밋 id)를 입력하면 HEAD가 분리되어 C2에 가있는 것을 볼 수 있고
다시 git switch main (브랜치 이름)을 입력하여 main과 HEAD가 합쳐진 것을 볼 수 있다.
switch도 많이 사용하는 옵션을 간단하게 정리해보자.
옵션 | 설명 |
커밋 id or 브랜치명 | 해당 커밋 id 또는 브랜치로 이동 |
-c 브랜치명 | 해당 브랜치가 없으면 생성하고 HEAD를 이동 |
-c 새브랜치이름 기존브랜치이름 | 기존 브랜치를 기반으로 새 브랜치를 생성 |
git reset
커밋 기록을 되돌리거나, HEAD를 특정 상태로 작업을 초기화하는 강력한 명렁어
현재 이력을 남기지 않는다.
이 명령어는 사용할 때 명시적으로 option을 지정하는데 한번 차이점을 느껴보자.
git reset [optipn] commit id
--soft
- HEAD 포인터만 이동하며, 스테이징 영역과 작업 디렉토리는 변경하지 않는다.
- 최근 커밋을 되돌리고 싶지만, 해당 커밋의 변경 사항은 스테이징 상태로 남겨두고 싶은 경우 사용한다.
- 커밋된 파일들을 staging area로 될돌려 놓는다.
현재 로컬 main은 TTTTT라는 commit 메시지에 위치했지만
만약 squash commit 메시지의 커밋id로 soft reset을 하면 어떻게 변할까??
이전 TTTTT라는 commit이 사라지고 해당 commit이 그대로 staged Area에 있는 것을 볼 수 있다.
--mixed (default)
- HEAD 포인터를 이동시키고 스테이징 영역을 초기화하지만, 작업 디렉토리의 파일은 그대로 유지한다.
- 커밋을 되돌리고, 변경 사항을 스테이징 해제하여 작업 디렉토리에 반영하고 싶은 경우에 사용한다.
- commit된 파일들을 working directory로 돌려놓는다. (add 전)
이번에는 TT2 커밋을 sqush commit쪽으로 --mixed reset을 해보자.
이번 결과는 똑같이 커밋이 사라졌지만 변경사항이 unstaged된 working directory에 존재한다.
--hard
- HEAD 포인터를 이동시키고, 스테이징 영역과 작업 디렉토리 모두 지정한 커밋 상태로 초기화한다.
- 모든 변경 사항을 완전히 삭제하고 지정한 커밋 상태로 되돌리고 싶은 경우에 사용되며, 주의가 필요
- commit된 파일들 중 tracked 파일들을 working directory에서 삭제한다.
커밋 내용자체가 사라진걸 볼 수 있다. 어떤 기록도 찾을 수 없음.
여기서 중요한 점은 어떤 옵션을 사용하더라도 현재 커밋은 절대 살아남지 못한다는 점이다.
git revert
기존 히스토리를 보존하며 수정된 새로운 커밋이 추가됨
git revert commit id
현재는 TT2 커밋 메시지를 revert해보자.
TT2 기록도 남아있고 revert한 커밋도 기록이 된다.
reset vs revert
1. 현재상태
2. reset을 통해 C4 기록 사라짐
3. revert를 통해 C4 기록은 남아있고 C4'로 revert 된 후 커밋이 생김
reset | revet | |
히스토리 잔여 여부 | X | O |
주요 기능 | 커밋 기록 삭제 or 되돌림 | 커밋을 취소 |
새로운 커밋 추가됨 | X | O |
권장 사항 | 로컬 작업 수정 | 리모트 쪽 수정 |
git restore
특정 파일을 특정 시점으로 변경한다.
git restore 파일명 // 최근 커밋으로 해당 파일 되돌리기
git restore --source 커밋 id 파일명 // 특정 커밋으로 해당 파일 되돌리기
git restore --staged 파일명 // 특정 파일 staged 취소
'깃 > 명령어' 카테고리의 다른 글
깃 커밋 관련 명령어 (2) | 2024.11.17 |
---|---|
프로젝트 생성 (2) | 2024.11.07 |