깃 기본 명령어

git status
이론
들어가기 전부스트 캠프 마지막 프로젝트를 진행하는 도중 마스터 클래스에 백엔드 멘토님이신 호눅스님의 갑작스러운 깃 강의가 있었다.챌린지 때 분명이 학습한 내용인데 여러가지 질문에
hamp.tistory.com
깃 이론 포스팅에서 우리는 깃 내부 레포지토리에서 파일을 총 5단계의 상태로 구분한다.
git status는 각 파일들의 상태를 볼 수 있는 명령어다.


첫번 째는 가장 기본적인 git status의 결과고 오른쪽은 git status -s 옵션으로 short 즉 짧은 포맷으로 출력한 내용이다.
다양한 옵션은 공식문서를 참고하자.
Git - git-status Documentation
By default, git status will automatically refresh the index, updating the cached stat information from the working tree and writing out the result. Writing out the updated index is an optimization that isn’t strictly necessary (status computes the values
git-scm.com
git add

공식문서에서는 변경된 파일내용을 index에 더하는 명령어라고 한다.
이론 포스팅을 보면 index는 다음 포스팅에서 stagingArea라고 한다.
깃 디렉토리 및 객체
들어가기 전이전 학습에서는 깃의 간략한 이론을 살펴봤다.이번 포스팅은 깃 내부적으로 어떻게 관리되는 지를 중점적으로 살펴보자.Git 디렉토리 생성 git init 명력어를 입력하면 현재 디렉
hamp.tistory.com
간단한게 말하면 modified된 파일을 staged하는 명령어다.
한번이라도 add가 됐다면 그 파일은 이제 git에게 tracked되는 상태가된다.
사용은 다음과 같다.
다음과 같이 staged할 파일들을 나열하거나.
git add file1 file2 ...
현재 .을 통해서 현재 레포지토리의 모든 modified된 파일을 올릴 수 있다.
git add .
Git - git-add Documentation
Invoking git add -e or selecting e from the interactive hunk selector will open a patch in your editor; after the editor exits, the result is applied to the index. You are free to make arbitrary changes to the patch, but note that some changes may have con
git-scm.com
git diff

git diff 명령어는 단순히 파일이 변경됐다는 사실이 아니라 어떤 내용이 변경됐는지 살펴 볼 때 사용된다.
어떤 라인을 추가하고 삭제했는 지 궁금할 때 사용된다.
Git - git-diff Documentation
Show changes between the working tree and the index or a tree, changes between the index and a tree, changes between two trees, changes resulting from a merge, changes between two blob objects, or changes between two files on disk. git diff [ ] [--] [ …
git-scm.com
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 - git-commit Documentation
When recording your own work, the contents of modified files in your working tree are temporarily stored to a staging area called the "index" with git add. A file can be reverted back, only in the index but not in the working tree, to that of the last comm
git-scm.com
git fetch
git fetch는 다른 저장소로부터 커밋(오브젝트 파일과 참조)들을 다운로드하는 과정이다.
특정 이름의 저장소 또는 URL으로 다운로드 받을 수 있지만 보통은 현재 로컬브랜치에 대한 upstream(remote) 브랜치로부터 받아온다.
여기서 중요한점은 다운을 받았다고 변경사항이 로컬 레포지토리에 바로 반영되는 것이 아닌다.
왜냐하면 깃은 현재 브랜치의 가장 최근 커밋을 가르키는 HEAD라는 포인터가 있는데
fetch는 커밋 정보를 다운을 받지만 HEAD가 옮겨지지는 않습니다.
Git - git-fetch Documentation
The fetch and push protocols are not designed to prevent one side from stealing data from the other repository that was not intended to be shared. If you have private data that you need to protect from a malicious peer, your best option is to store it in a
git-scm.com
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 - git-merge Documentation
During a merge, the working tree files are updated to reflect the result of the merge. Among the changes made to the common ancestor’s version, non-overlapping ones (that is, you changed an area of the file while the other side left that area intact, or
git-scm.com
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 - git-pull Documentation
Often people use git pull without giving any parameter. Traditionally, this has been equivalent to saying git pull origin. However, when configuration branch. .remote is present while on branch , that value is used instead of origin. In order to determine
git-scm.com
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 |
| -m newBranchName | 브랜치 이름 변경 | |
| 옵션 x | 해당 브랜치 생성 | |
Git - git-branch Documentation
If --list is given, or if there are no non-option arguments, existing branches are listed; the current branch will be highlighted in green and marked with an asterisk. Any branches checked out in linked worktrees will be highlighted in cyan and marked with
git-scm.com
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 새브랜치이름 기존브랜치이름 | 기존 브랜치를 기반으로 새 브랜치를 생성 |
| -c 로컬브랜치이름 --track 리모트 브랜치 이름 | 리모트 브랜치를 트래킹 하는 로컬 브랜칫 생성 |
Git - git-switch Documentation
Switch to a specified branch. The working tree and the index are updated to match the branch. All new commits will be added to the tip of this branch. Optionally a new branch could be created with either -c, -C, automatically from a remote branch of same n
git-scm.com
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 - git-reset Documentation
In the first three forms, copy entries from to the index. In the last form, set the current branch head (HEAD) to , optionally modifying index and working tree to match. The / defaults to HEAD in all forms. git reset [-q] [ ] [--] … git reset [-q] [--
git-scm.com
git revert
기존 히스토리를 보존하며 수정된 새로운 커밋이 추가됨
git revert commit id


현재는 TT2 커밋 메시지를 revert해보자.
TT2 기록도 남아있고 revert한 커밋도 기록이 된다.
Git - git-revert Documentation
While git creates a basic commit message automatically, it is strongly recommended to explain why the original commit is being reverted. In addition, repeatedly reverting reverts will result in increasingly unwieldy subject lines, for example Reapply "Reap
git-scm.com
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 취소
Git - git-restore Documentation
The following sequence switches to the master branch, reverts the Makefile to two revisions back, deletes hello.c by mistake, and gets it back from the index. $ git switch master $ git restore --source master~2 Makefile (1) $ rm -f hello.c $ git restore he
git-scm.com
git stash
작업 현황을 잠시 stash 공간에 저장
git stash // stash에 작업 현황 저장
git stash apply // stash에서 다시 working derectory에 가져오기
git stash list // stash list 확인 (해시값도 확인 가능)
git stash drop stash@{index} // 특정 stash 제거
git stash clear // list 전체 제거
git stash show -p stash@{index} // 특정 index stash 내용 확인하기
git log -g stash // stash의 full commit hash 확인 가능
git show stash해시값 // 해시값을 통해 stash 내용확인
Git - Stashing과 Cleaning
작업하던 저장소가 완전 지저분해져서 Git에게 진짜로 강제로 정리하도록 해야 하는 경우가 생길 수 있다. 예를 들어 Git 버전관리 데이터가 포함된 디렉토리를 복사해왔거나 서브모듈 디렉토리
git-scm.com
git tag
스냅샷 만들기
git tag -a <tag_name> -m "tag message"
git tag <tag_name> // 메타 데이터 없이 태그 만들기
git tag // 모든 태그 확인
git tag -l "<pattern>" 특정 패턴 태그 확인
git tag -d <tag_name> 태그 삭제
git push origin --delete <tag_name> // 원격 태그 삭제하기, 단 반드 시로컬 태그 삭제 후 진행
git push origin <tag_name> 태그 원격에 올리기
git show <tag_name> 태그가 가리키는 커밋 확인