Miyeon

자주 쓰는 Git 명령어

2022-01-10Git

왜 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가지 방법

    1. 현재 커밋과 병합하고 싶은 커밋을 미리 내 브랜치에서 병합하기 -> 병합 커밋 만들기 -> 풀 리퀘스트 보내기
    1. 추천 방법 : 묵은 커밋을 방금 한 커밋처럼 이력 조작하기 = 리베이스

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~2reset --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

Git - Reset Demystified

git에서 원격저장소에 branch와 tag를 push하기 :: Outsider’s Dev Story