Critical

  • 원격 추적 브랜치
  • git fetch/pull

 

협업을 하지 않고 로컬 저장소만 사용할 거라면 fetch, pull은 필요없다. 하지만 협업할 계획이라면 매우 중요하다.

 

 

* 원격 추적 브랜치

로컬에서의 브랜치는 앞서 다뤄봤으므로 익숙할 것이다. 하지만 clone이나 remote를 통해 원격 저장소와 동기화를 이루고 나면 "origin/main"과 같은 새로운 브랜치가 생성된다. 이 브랜치가 원격 추적 브랜치이다.

마지막으로 원격 저장소와 통신한 시점을 기억하는 포인터라고 생각하면 된다.

 

# 원격 브랜치 목록 확인
$ git branch -r
> origin/HEAD -> origin/main
> origin/main

 

추가로 커밋 후 git status 실행 시, 로컬에서만 작업했을 때와는 다른 메시지가 출력된다.

 

$ git status
> On branch main
> Your branch is ahead of 'origin/main' by 1 commit.

 

"origin/main" 브랜치에 비해서 커밋 1개가 앞서있다는 얘기이다.

앞서 말했듯이 원격 저장소와 로컬 저장소는 자동으로 동기화되지 않기 때문에 한쪽에서 커밋하는 순간 어긋나기 때문에 그것을 알려주는 것이다.

 

로컬에는 없지만 원격에는 존재하는 브랜치에 접근하려면 어떻게 해야할까?

매우 간단하다. switch 명령어를 사용하면 된다.

로컬에는 없지만 원격에 존재하는 경우
로컬과 원격 모두 없는 경우

기본적으로 로컬 브랜치와 원격 브랜치의 이름이 같으면 서로 묶인다.

 

# 브랜치 추적 설정
$ git branch -u <remote-branch>
# 브랜치 추적 해제
$ git branch --unset-upstream <remote-branch>

 

만약 자동으로 브랜치를 추적하지 않는다면 수동으로 설정해주면 된다. 추적할 필요가 없다면 해제 할 수도 있다.

두 명령어 모두 대상 브랜치로 이동해서 실행해야 한다.

 

로컬과 원격의 워크 플로우

 

* Fetching

내가 로컬에서 작업하는 동안 다른 인원들이 작업한 것들이 원격 저장소에 올라간 경우가 있을 수 있다. 협업 과정에서는 매우 흔한 일일 것이다.

이 때, 내 작업 영역을 망치지 않으면서 변경 사항에 접근할 수 있도록 하는 명령어가 fetch이다.

 

origin/master가 업데이트 됐다. master와 별개의 브랜치이다

원격 저장소에서 변경 사항을 가져오지만 작업 파일에 통합하지는 않는다.

 

origin/food가 변경되었을 뿐 로컬에는 영향이 없다

 

 

* Pulling

Fetching과 다르게 HEAD 브랜치를 업데이트 한다. 작업 영역이 업데이트 된다는 얘기이다.

간단하게 정리하자면 fetch+merge 이다.

매우 중요한 점이 있는데, 현재 HEAD가 위치한 브랜치에 풀링이 적용 된다.

 

$ git pull origin movies

 

원격 저장소의 movies 브랜치를 풀링한다는 의미이다. 의도하는 것은 로컬 저장소의 movies 브랜치에 풀링하는 것인데 만약 HEAD가 main이라면 main 브랜치에 풀링이 되어버리므로 조심해야한다.

 

fetch와 다르게 origin/movies와 movies브랜치가 병합되었다. 위와 같은 경우는 충돌이 발생하지 않았으므로 빨리 감기 병합이 이뤄졌다.

 

로컬 브랜치와 원격 브랜치가 추적되도록 설정되었다면 명령어를 간소화 시킬 수 있다.

 

$ git pull

 

main 브랜치에서 실행했다면 원격의 main 브랜치를 풀링한다.

 

추가로 원격 저장소에 푸시하기 전에 풀다운 하여 변경 사항을 확인하는 습관을 들이는것이 좋다.

Critical

  • 깃허브가 하는 일
  • git clone
  • 깃허브 등록 및 SSH키 설정
  • 깃허브 저장소 만들기
  • 원격 작업
  • git push

 

 

* Github란?

깃 저장소를 위한 호스팅 플랫폼이다.

깃 허브에 등록한 저장소가 포트폴리오가 될 수 있다.

최신 정보를 얻기에도 매우 유용하다.

 

 

git clone <url>

로컬에 없는 저장소를 가져온다.

깃허브의 공개 저장소에 있는 것들은 모두 클론이 가능하다. 단, 푸시는 불가능하다.

그리고 거의 대부분의 경우에 깃허브가 쓰일 뿐이지 깃허브만 가능한것이 아니다. git clone 명령어도 github와 관계가 없다.

 

* SSH키 설정 및 깃허브에 등록하기 (Windows 기준)

깃허브 가입이 완료된다면 SSH키를 설정해야한다. 그래야 매번 로그인을 하지 않고도 인증할 수 있기 때문이다.

SSH키가 있으면 그걸 사용하면 되고 없다면 터미널 명령어로 생성시켜 주어야 한다.

 

$ ssh-keygen -t ed25519 -C <email>
> Generating public/private ALGORITHM key pair.

 

 

암호 설정까지 끝내고 생성을 완료했다면 SSH 에이전트를 실행시켜서 키를 추가시켜 준다.

 

$ eval "$(ssh-agent -s)"
> Agent pid ****

$ ssh-add ~/.ssh/id_ed25519
> Identity added: /c/User/../.ssh/id_ed25519 (email)

 

 

깃허브에서 SSH키를 등록하기 위해 공개키를 복사 한다.

 

$ clip < ~/.ssh/id_ed25519.pub

 

 

깃허브의 Setting - [Access] 의 SSH and GPG keys 페이지로 이동해서 "New SSH key" 를 클릭해서 복사한 키를 입력하고 제목을 정해주면 완료된다.

 

과정이 번거롭지만 디바이스별로 딱 한번만 등록해두면 다시는 할 필요가 없다.

 

* 로컬에 기존 저장소가 있는 경우

  1. 깃허브에서 새 저장소를 만든다.
  2. 로컬 저장소에서 원격을 만든다.
  3. 푸시한다.

 

* 아직 작업을 시작하지 않은 경우

  1. 깃허브에서 새 저장소를 만든다.
  2. 클론한다.
  3. 푸시한다.

 

git remote

현재 저장소에 있는 원격 목록을 보여준다

git remote -v : 저장소의 주소까지 출력해준다.

 

git remote add <remote> <url>

새로운 원격을 만들어준다. url은 깃허브의 저장소 주소이다.

 

일반적으로 원격 이름은 origin으로 만든다. 원격은 여러개 존재할 수 있다.

 

아래와 같은 명령어도 사용된다.

git remote rename <old> <new> : 원격 이름을 수정한다.

git remote remove <name> : 원격을 삭제한다.

 

remote는 깃에게 알려줄 url에 이름을 붙인것이다.

 

git push <remote> <branch>

깃에게 대상 저장소 및 푸시할 브랜치를 알려준다.

git push origin main 은 정말 흔하게 사용하는 명령어이다.

 

 

저장소를 만든 직후 아무것도 없는 상태

원격 유무를 포함한 정보를 확인한 후에 push를 실행하면 아무것도 없던 저장소에 파일들이 추가된다.

로컬에서 작업하던것을 깃허브에 올린것이기 때문에 로컬에서 작업했던 브랜치의 이력들이 모두 올라간다.

현재는 main 브랜치만 푸시했기 때문에 main 브랜치만 존재한다.

 

 

git push <remote> <local-branch>:<remote-branch>

기본적인 푸시는 로컬 브랜치가 원격 저장소에 존재하지 않으면 새로 생성하고 그 이후에는 같은 브랜치에 푸시되는 방식이다. 즉, 로컬 A브랜치를 원격 저장소의 A브랜치로 푸시하는 것이다.

여기서 로컬 브랜치와 원격 저장소의 브랜치를 다르게 설정할 수 있다. 로컬 A브랜치를 원격 저장소의 B브랜치로 푸시할 수 있다는 것이다.

일반적으로 자주 사용되는 명령어는 아니다.

 

 

git push -u <remote> <branch>

upstream의 약어이다. 로컬 브랜치를 원격 브랜치에 연결시킨다.

 

# local의 main을 origin의 main에 연결한다
$ git push -u origin main

 

연결시키고 난 뒤에는 git push 명령어 만으로도 푸시가 가능해진다.

보통은 main 브랜치를 처음 푸시할 때 사용한다.

 

로컬 브랜치와 깃허브의 브랜치는 다르다는 것을 인지해야한다.

 

 

깃허브는 로컬 저장소와 자동으로 동기화되지 않는다.

Critical

  • 커밋 체크아웃
  • 분리된 HEAD

 

Important

  • 변경사항 무시하기
  • git restore(복원)/reset(재설정)/revert(되돌리기)

 

git checkout 명령어로 브랜치를 생성하거나 이동하는것 말고도 이전 커밋을 확인할 수도 있다.

 

git checkout <commit-hash>

HEAD를 해당 커밋으로 이동시킨다. 명령어 실행 시 HEAD가 분리된 상태라는 메시지가 출력된다.

브랜치는 언제나 해당 브랜치의 최근 커밋을 가리키고 HEAD는 그 브랜치를 가리키게 된다. 일반적으로 HEAD는 커밋이 아닌 특정 브랜치를 참조하게 된다.

하지만 해당 명령어를 통해서 HEAD가 특정 커밋을 참조하도록 바꾼다. 원래 브랜치를 참조하던것이 커밋을 참조하게 되었으므로 분리된 상태가 된 것이다.

이를 통해 이전 커밋을 참조할 수 있다.

다시 브랜치로 돌아가려면 switch 명령어로 돌아가면 된다. "git switch -" 입력 시 현재 브랜치의 최상단으로 이동한다.

 

정상적인 상태
HEAD가 분리된 상태

HEAD가 분리된 상태에서도 브랜치를 새로 생성시킬 수 있다.

 

과거의 커밋으로 돌아가서 프로토타입 작성 등의 새로운 작업을 시작할 때 매우 유용하게 사용할 수 있을 것 같다.

 

 

git checkout HEAD <file-name>

커밋 참조를 이용해서 작업 영역의 변경 사항을 한번에 초기화 하는 방법이다.

무언가 열심히 작업을 하다가 문제가 생기거나 마음에 안들어서 초기화 할때 사용하면 된다.

파일 이름을 적어주면 해당 파일만 마지막 커밋 내용으로 덮어씌워진다.

HEAD 대신 -- 을 입력해도 된다.

 

 

git restore

 

git restore 명령어의 두 가지 목적

  • 작업 영역의 변경사항 되돌리기
  • 언스테이징

 

checkout이 너무 많은 기능을 수행하기 때문에 독립시켜 만든 명령어이다.

git checkout HEAD <file-name> == git restore <file-name> 이다.

git restore --source <commit-hash> <file-name> : 특정 커밋의 파일로 변경한다.

git restore --staged <file-name> : 스테이지에 등록된 파일을 다시 작업 영역으로 되돌린다.

git restore 명령어는 git status에서 사용법을 알려주기도 한다.

 

 

 

git reset

저장소를 특정 커밋으로 재설정한다.

일반 재설정과 하드 재설정이 존재한다.

 

일반 재설정 / git reset <commit-hash>

커밋 삭제 전
커밋 삭제 후

위와 같이 잘못된 커밋이 존재할 경우 해당 명령어로 커밋만 삭제할 수 있다.

"커밋만" 삭제한다는 점을 주의해야한다. 변경된 사항은 여전히 작업 영역에 남아있다.

HEAD부터 <commit-hash> 직전까지의 범위를 모두 삭제한다.

 

커밋된 작업이 작업 영역으로 돌아왔다

잘못된 브랜치에서 커밋을 했을 때 유용하게 사용할 수 있다.

커밋을 삭제하고 남아있는 변경사항을 정상적인 브랜치에서 다시 커밋을 하면 된다.

 

 

하드 재설정 / git reset --hard <commit-hash>

--hard 플래그 하나가 추가된 형태이다. 커밋을 삭제하는것은 동일하지만 작업의 변경사항까지 모두 삭제한다.

일반 재설정 이후 restore로 작업 영역의 변경사항을 취소한것과 마찬가지이다.

 

reset은 브랜치 기준으로 작동한다.

 

 

git revert <commit-hash>

reset과 기능이 매우 유사하다. reset은 커밋을 제거하고 브랜치 포인터를 뒤로 이동시키는 반면에 revert는 새로운 커밋을 만들어서 이전 커밋의 변경 사항을 취소한다.

결과적으로 커밋을 취소(되돌리는것)하는것은 동일하지만 커밋을 삭제하느냐 남겨두느냐의 차이가 있다.

병합 커밋을 실행할때처럼 명령어 실행 시 충돌을 처리해야 할 수도 있다.

 

reset과 다르게 커밋이 삭제되지 않고 남아있다

revert를 사용하는 이유는 협업 때문이다.

설령 잘못된 커밋이더라도 다른 사람들이 작업하고 있는 커밋이라면 reset으로 커밋을 제거했을 때, 다른 사람들이 가지고 있는 기록을 취소하는 것이기 때문에 심각한 문제가 발생될 수 있다.

커밋 실수를 했을 때 다른 사람들과 공유되지 않았다는 것이 확실할때는 reset을 사용하는 것이 좋고 다른 사람들과 공유중인것이 확인됐을 때는 revert를 사용해야 한다.

 

HEAD를 기준으로 이전 커밋들을 참조할 수도 있다.

HEAD~[N] 으로 HEAD 기준으로 N개 이전 커밋을 참조한다.

 

요약

  • git restore : 작업 영역의 수정 사항이나 스테이징을 취소한다.
  • git reset : 커밋을 취소한다. (커밋 삭제)
  • git revert : 커밋을 복구한다. (새로운 커밋 생성)

 

reset과 revert는 결과는 동일하지만 과정이 다르다.

Important

  • 스태시의 기초
  • git status save/pop

 

Nice To Have

  • git stash 적용
  • 스태시 삭제
  • 여러개의 스태시로 작업하기

 

스태시는 유용한 기능이지만 반드시 사용해야 하는 상황은 발생하지 않는다.

대부분 save와 pop을 사용한다.

 

브랜치에서 작업을 하다가 완료되지 않은 상태라서 커밋을 하지 않고 다른 브랜치로 이동해야 하는 경우에는 상황에 따라 해당 작업이 이동하는 브랜치로 따라오거나 깃에서 브랜치를 이동하지 못하도록 막는(병합 커밋 발생 예상시) 두가지 옵션이 존재한다.

이 때 스태시를 사용한다.

 

 

git stash (=git stash save)

커밋되지 않은 변경사항을 저장하고 변경사항들을 모두 초기화시킨다.

내용이 삭제되는것이 아니라 스태시에 저장된 상태이다.

 

 

git stash pop

스태시에 저장된 가장 최근 목록을 가져오고 삭제한다.

 

 

git stash apply

방식은 pop과 동일하다. 단, 스태시가 삭제되지 않고 남기때문에 여러 브랜치에서 동일한 내용을 적용할 수 있다.

 

 

git stash list

스태시는 여러개 등록이 가능하다.

 

한 브랜치에서 여러번의 스태시는 흔한 일은 아니다

스태시 아이디를 통해서 특정 스태시를 적용시킬 수 있다.

 

스태시를 적용하고 바로 다른 스태시를 적용하려고 하면 위와 같이 에러가 발생한다.

작업 내용이 덮어씌워지기 때문에 에러가 발생하고 병합 되기전에 커밋이나 스태시를 하라고 한다.

 

 

git stash drop

특정 스태시를 삭제시킬 수 있다.

 

 

git stash clear

모든 스태시를 삭제한다.

Critical

  • git diff 명령어 실행 결과 읽기
  • git diff 명령어의 기본적인 사용 방법

 

Important

  • 브랜치, 커밋, 특정 파일의 비교
  • git diff --stage

 

git diff는 깃에서의 변경 사항들을 보여주는 명령어이다.

git status나 git log처럼 저장소에 아무런 영향을 미치지 않는 명령어이다.

 

git diff

스테이지에 등록되지 않은 작업 영역의 변경사항을 모두 나열한다.

 

아직 스테이지에 올라가지 않은 상태
작업 영역 파일의 변경사항을 알려준다
각 라인을 해석하면 위와 같다

a는 커밋된 파일, b는 작업 영역의 파일이다.

 

 

git diff HEAD

마지막 커밋이 실행된 이후의 변경사항을 모두 나열한다.

마지막 커밋 이후 변경 사항을 스테이지에 올리지 않은 상태라면 git diff, git diff HEAD 둘다 같은 결과를 출력한다.

하지만 변경 사항을 스테이지에 올린다면 git diff는 아무것도 출력되지 않지만 git diff HEAD는 결과가 출력된다.

 

 

git diff --staged (--cached)

스테이지에 등록된 변경사항만을 나열한다.

 

 

git diff branch1 branch2 (branch1..branch2)

두 브랜치를 비교하여 변경사항을 모두 나열한다.

a, b는 브랜치 입력 순서에 따라 매칭된다. 위와 같은 경우는 a는 branch1, b는 branch2이다.

 

 

git diff commit1 commit2 (commit1..commit2)

두 커밋을 비교하여 변경사항을 모두 나열한다.

마찬가지로 a, b는 커밋 입력 순서에 따라 매칭된다.

* HEAD는 단순히 마지막 커밋을 가리키는 레퍼런스이다. 그래서 git diff HEAD HEAD~1 실행시 마지막 커밋과 그 부모커밋을 비교하는 명령어가 된다.

 

git log --oneline
커밋 해시값을 입력한다

 

git diff <file-name1> <file-name2> <..>
git diff --staged <file-name>
git diff HEAD <file-name>
git diff branch1..branch2 <file-name>
git diff commit1..commit2 <file-name>

 

위와 같이 특정 파일에 대한 변경사항만 확인할 수도 있다. 동시에 여러 개의 파일도 가능하다.

 

-, +를 b에 비교해서 없는 내용, 있는 내용으로 구분지어서 생각하기 보다는 -는 a에만 있는 내용, +는 b에만 있는 내용이라고 생각하는게 이해하기 조금 더 쉽다.

 

 

GUI 툴을 사용하면 매번 상황에 따라 명령어를 작성하던것을 원클릭으로 볼 수 있어서 훨씬 편하다.

+ Recent posts