자주 쓰는 Git 명령어
왜 Git을 사용하는가
원하는 시점(버전)으로 이동할 수 있기 때문이다.
중요한 역할을 하는 커밋
⭕ 커밋은 스냅사진이다.
⭕ 커밋에는 변경 사항만 부분적으로 저장되는 게 아니라 변경된 부분을 포함한 전체 코드가 담겨있다.
Git으로 관리하는 파일의 4가지 상태
파일상태 | |
---|---|
untracked | 한번도 커밋되지 않은 상태 |
tracked | 수정 없음 |
수정함 | |
스테이지됨 |
git add
에서 git push
까지 과정
- 파일 변경 / 파일 추가 ->
git add
로 스테이지에 올림. 커밋을 할 수 있는 상태됨 ->git commit
으로 하나의 스냅샷, 버전 만들기 ->git push
로 원격 저장소에 올리기
브랜치
- 브랜치 = 포인터
- [main] = Git이 제공하는 기본 브랜치
- 브랜치가 포인터이기 때문에 그저 커밋을 가리키는 것만으로도 분기를 만들 수 있다. 포인터인 브랜치가 없었더라면 프로젝트를 통째로 복사해야 해서 무겁고 시간이 많이 걸리게 된다.
- 여러 브랜치 사이를 넘나들 수 있는 이유도
HEAD
라는 포인터가 있기 때문이다. 타임머신 역할을 해주는 게 바로 이HEAD
포인터다. - 브랜치와 헤드가 떨어지는 경우는 ‘Detached HEAD’ 상태가 된다.
- 각자의 브랜치에서 개발하다가 각각 개발이 완료되면 [main] 브랜치에 작업하던 브랜치 작업물을 합치면 된다.
- [main] 브랜치에 병합된 브랜치는 지우기
브랜치 사용할 때
케이스 | |
---|---|
새로운 기능 추가 | 브랜치 생성해서 개발,코드 리뷰, 테스트 완료하면 [main]브랜치로 병합 |
버그 수정 | hoxFix, bugFix 같은 이름 사용 |
병합과 리베이스 테스트 | 임시 브랜치 만들어서 병합과 리베이스 테스트 하기 -> 잘못되면 그냥 브랜치 삭제하면 됨 |
이전 코드 개선 | 함수의 로직 등을 개선할 때 기존 코드 삭제하고 새 코드 작성하는데 유용함 |
특정 커밋으로 돌아가고 싶을 때 | 브랜치를 새로 만들어서 작업을 하고, 이후 리베이스나 병합을 사용하기 |
협업을 위한 규칙 예시
- [main] 브랜치에는 직접 커밋을 올리지 않는다.(동시 작업시 꼬일 수 있음)
- 기능 개발을 하기 전에 [main] 브랜치를 기준으로 새로운 브랜치를 만든다.
- 이 브랜치 이름은 [feature/기능이름] 형식으로 하고 한 명만 커밋을 올린다.
- [feature/기능이름] 브랜치에서 기능 개발이 끝나면 [main] 브랜치에 이를 합친다.
HEAD
- 현재 작업중인 브랜치 혹은 커밋을 가리킨다.
- 해당 브랜치에서 가장 마지막에 만들어진 커밋의 스냅샷이라고 생각하면 된다.
- 다음에 만들어질 커밋의 부모가 된다.
병합 = 두 버전의 합집합을 구하기
merge 방식 | 특이 사항 |
---|---|
merge commit | 새로운 상태니까 새롭게 저장해야함 - 두 브랜치를 합치면서 병합 커밋이 생김 |
fast-forward | 마지막 상태와 동일하니까 마지막으로 상태로 변경해주면 됨 |
conflict | 충돌 난 부분 확인하고 무엇을 남길지 수동으로 선택하기 |
자주 쓰는 Git Bash 명령어
명령어 | 설명 |
---|---|
pwd | 현재 폴더의 위치 확인 |
ls | 현재 폴더의 파일 목록 확인 |
ls -a | 숨김 파일을 포함해서 파일 목록 확인 |
cd../ | 현재 폴더의 상위 폴더로 이동 |
mkdir 새폴더이름 | 현재 폴더 아래에 새로운 폴더 만들기 |
main과 origin/main의 의미
용어 | 설명 |
---|---|
HEAD | 현재 작업중인 브랜치나 커밋을 가리킴 |
main | 로컬의 main 브랜치를 의미함 |
origin/main | 원격저장소인 GitHub의 main 브랜치를 의미함 |
Git 용어 정리
용어 | 설명 |
---|---|
워킹트리 | 일반적인 작업이 일어나는 곳 |
로컬저장소 | .git 폴더, 커밋이 들어있는 곳 |
작업 폴더 | 워킹트리 + 로컬저장소 |
Git 저장소 생성
- 현재 폴더에
.git
이라는 숨김 폴더 만든다. 이 폴더가 로컬저장소를 의미한다.
$ git init
원격저장소 등록하기
$ git remote add 원격저장소이름 원격저장소주소
원격저장소 목록 확인하기
$ git remote -v
현재 브랜치의 커밋 이력 확인하기
$ git log
원하는 커밋으로 돌아가기 = 타임머신
$ git checkout 커밋아이디(앞자리 7자리)
최신 커밋으로 가기
$ git checkout -
원격 저장소에서 프로젝트를 복제해오기
- 현재 폴더에 파일만 받을 때
$ git clone 원격저장소주소 .
- 새로운 폴더로 받을 때, 원하는 폴더이름 생략 가능
$ git clone 원격저장소주소 원하는폴더이름
- 로컬저장소도
git clone
으로 복제할 수 있다.
원격저장소의 변경사항(새로운 커밋)을 워킹트리에 반영하기
git fetch
+git merge
를 의미한다.
$ git pull origin main
원격 저장소의 브랜치와 커밋들을 로컬저장소와 동기화하기
- 새로고침 기능으로 원본저장소의 이력을 업데이트한다.
- 최신 코드를 내 코드에 반영하는 pull과 다르게 패치는 이력만 가져오기 때문에 내 코드에는 아무 영향을 주지 않는다.
$ git fetch 원격저장소별명 브랜치이름
- 옵션 생략하면 모든 원격저장소에서 모든 브랜치를 가져온다.
브랜치 만들기
- 브랜치 만들기 전에 base 브랜치로 확인하기
$ git branch 브랜치이름
브랜치 이동하기
- 충돌 피하기 위해서 브랜치 이동하기 전에 변경사항 stash하거나 커밋해서 작업트리 빈 상태 만들기
$ git checkout 브랜치이름
브랜치와 브랜치 병합하기
- 기준이 되는 브랜치(보통 main)로 체크아웃한 뒤 진행하기
$ git merge 합치고 싶은 브랜치이름
- 원격저장소에 반영하기
$ git push
충돌 해결
- 협업하다가 똑같은 코드를 고쳤을 때 발생한다.
- ⭐ 병합할 때 동료들과 같이 쓰는 [main]브랜치에 병합하지 말고 나 혼자 쓰는 [개인브랜치]에서 먼저 병합해보는 습관 들이기. 문제 생기면 나 혼자 영향받도록! ⭐
$ git checkout 개인브랜치
$ git merge main
- 병합된 커밋이 문제가 없을 때 [main]브랜치에 반영하기
- 충돌 발생
- 충돌난 파일 수정해서 병합 다시 진행하기
- 병합이 문제 없으면 [main]브랜치로 이동해서 [main]브랜치를 베이스로 다시 병합하기
브랜치를 합치는 좋은 방법 = 풀 리퀘스트
- [main] 브랜치에는 완벽한 코드만 둬야 한다.
pull request
= 협력자에게 병합을 요청하는 메세지는 보내는 것- 새로운 브랜치 만들어서 커밋 -> 원격 저장소에 푸쉬하면 GitHub 원격저장소에 [Compare & pull request] 버튼이 생성된다.
pull request
하면 원격저장소에는 병합이 된 상태다. 로컬 저장소에도 반영해야 한다.$ git checkout main
,$ git pull
을 통해 로컬 저장소와 원격 저장소가 같은 커밋을 가리키게 한다.
개발 완료! 출시하자 = 릴리즈
프로그램 버전 | 특징 |
---|---|
메이저 업그레이드 | 사용자들이 크게 느낄 변화, v2.x -> v3.x |
마이너 업그레이트 | 작은 변화의 경우. v.2.3 -> v.2.4 |
- [main]브랜치를 서버에 올려서 사용자들이 쓸 수 있게 배포하고, 버전을 태그로 기록하기
Tag
- 커밋을 참조하기 쉽도록 이름 붙이는 작업
- Annotated tag : 상세한 정보 포함하는 태그
- 원격 저장소에도 태그가 반영되도록 push 해주기
- 원하는 태그만 push하기
$ git push 원격저장소명 태그명
- 모든 태그 push하기
$ git push --tag
Fork
- 남의 원본 저장소를 내 계정의 원격 저장소에 통째로 복사해오는 작업
- 브랜치 vs 포크
의의 | 편리한 점 | 불편한 점 | |
---|---|---|---|
브랜치 | 하나의 원본저장소에서 분기를 나눔 | 하나의 원본저장소에서 코드 커밋 이력을 편하게 볼 수 있음 | 다수의 사용자가 다수의 브랜치를 만들면 관리하기가 어려움. 5인 정도가 적당함 |
포크 | 여러 원격저장소를 만들어 분기를 나눔 | 원본저장소에 영향을 미치지 않으므로 원격저장소에서 마음껏 코드를 수정할 수 있음 | 원본저장소의 이력을 보려면 따로 주소를 추가해야 함 |
풀 리퀘스트 보냈을 때 발생한 충돌 해결하는 2가지 방법
-
- 현재 커밋과 병합하고 싶은 커밋을 미리 내 브랜치에서 병합하기 -> 병합 커밋 만들기 -> 풀 리퀘스트 보내기
-
- 추천 방법 : 묵은 커밋을 방금 한 커밋처럼 이력 조작하기 = 리베이스
rebase
- A 브랜치의 베이스를 B 브랜치로 재배치한다는 의미이다.
- 재배치하길 원하는 브랜치로 체크아웃하기. 보통 뒤쳐진 브랜치를 의미한다.
$ git checkout A
$ git rebase B
- 빨리 감기가 가능한 상황에서 rebase 사용할 수 있다.
- 너무 예전 코드를 기점으로 새로운 코드 추가했을 경우 원격 저장소의 최신 코드와 충돌이 날 때 사용한다.
- 커밋의 베이스를 똑 떼서 다른 곳으로 붙이는 것
- 히스토리를 강제로 조작하기 때문에 혼자만 쓰는 브랜치에서 수행해야 한다.
- 브랜치에 재배치할 커밋이 없는경우 rebase는 아무런 동작을 하지 않는다.
원하는 커밋 하나만 떼서 지금 브랜치에 붙이기 = cherry-pick
- 상황 : 출시한 코드가 담긴 [latest] 브랜치에 당장 고쳐야 하는 버그가 생겼다. 출시 전 코드중에서 딱 그 버그를 고친 커밋 하나만 반영하고 싶을 때 사용한다.
- 특정 커밋의 변경사항을 복사해 현재 브랜치에 가져올 때 사용한다.
$ git cherry-pick 커밋해시
commit 메세지 수정하기
- 로컬 저장소만 수정하기
$ git commit --amend
- 이미 원격 저장소에 푸시한 커밋 수정하기 -> 강제 푸시하기
- ⭐ 강제 푸시는 나 혼자만 쓰고 있는 브랜치에서만 해야 한다 ⭐
$ git commit --amend
$ git push -f
git add 취소 - unstaged로 변경
- 스테이지 영역에 있는 파일들을 스테이지에서 내린다.
- 워킹트리의 내용은 변경되지 않고 남아 있다.
$ git reset 파일이름
git commit 취소하기
$ git reset HEAD^
현재 브랜치를 특정 커밋으로 되돌리기
- 현재 브랜치를 두 단계 이전으로 되돌리기
$ git reset --hard HEAD~2
checkout HEAD~2
과 reset --hard HEAD~2
의 차이
- [main]브랜치는 그 자리에 있고 HEAD만 옮겨진다 = detached HEAD 상황이 됨
$ git checkout HEAD~2
- 분리된 [main] 브랜치와 HEAD를 다시 연결하기
$ git checkout HEAD~2
$ git branch -f main
$ git checkout main
커밋의 변경사항을 되돌리기
- 잘못된 커밋이 있으면 언제든지 되돌리기. 푸시된 커밋도 가능!
$ git revert 커밋해시
변경사항을 잠시 다른 곳에 저장하고 싶을 떈
- 상황 : 기능 개발하다가 급하게 고쳐야 하는 버그가 생긴 경우
- 변경 사항 임시 저장하기
$ git stash
- stash 목록 확인하기
$ git stash list
- stash에 있던 변경사항 불러오기
$ git stash apply stash이름
- stash 제거하기
$ git stash drop stash이름
⭐ git 사용이 헷갈릴 땐 git help
에 검색하자 ⭐
$ git help cherry-pick
참고
책 - 팀 개발을 위한 Git, GitHub 시작하기
[Git] git add 취소하기, git commit 취소하기, git push 취소하기 - Heee’s Development Blog