Local과 Remote
깃 브랜치에는 로컬과 리모트가 있습니다. 깃에서 레포지토리를 클론 혹은 포크(깃헙 데스크탑 등으로 내려받으면)하면 로컬이 생성되며 로컬에서 커밋을 남긴 후 푸시하면 리모트에 로컬의 변경 사항이 반영됩니다.
- 로컬: 내 컴퓨터에 저장되어 있는 깃
- 리모트: 깃허브에 저장되어 있는 것
리모트에 코드가 반영되는 순서는
- git add <파일 이름> or . (.일 시 모든 파일 추가)로 변경 사항 추가
- 로컬에서 커밋 생성
- 푸시
- 리모트 저장소에 반영
입니다. 내 로컬에선 맘껏 수정해도 문제가 없지만 리모트에 푸시를 할 때는 꼭 변경 사항이 있는 파일을 모두 확인해주세요. 깃 리모트에 코드가 올라가기 전 마지막 방파제입니다!
- 아무 브랜치로 이동해서 아래 명령어를 입력해주세요. 저는 dev로 이동해보겠습니다.
git checkout dev
git reset --hard HEAD~1
- 아래와 같이 실제 리모트의 origin에 올라가 있는 브랜치 아래로 로컬 브랜치를 확인할 수 있습니다.
HEAD
위와 같이 리모트, 로컬을 통틀어서 모든 브랜치에는 헤드(HEAD)가 있습니다. 헤드는 브랜치의 가장 마지막 커밋을 가르키는 flag입니다. 그러므로 로컬과 리모트 브랜치의 헤드는 같은 커밋을 가르킬 수도, 아닐 수도 있습니다. 위의 상태에서 아래 명령어를 실행해주면
git reset --hard HEAD
아무 일도 일어나지 않습니다. 당연하겠지만 로컬은 로컬의 헤드로, 리모트는 리모트의 헤드로 이동하기 때문입니다.
HEAD 에서 발생하는 문제들
리모트와 로컬의 헤드가 각각 존재하기 때문에 우리는 브랜치 이름 변경, 삭제, 헤드의 이동 등을 하고 난 후 push와 pull 등의 명령어를 사용할 때 헤드와 관련된 문제를 직면하게 됩니다.
브랜치가 분리 되었을 때
깃은 기본적으로 로컬과 리모트 브랜치를 연결해줍니다. git pull, git push 등을 했을 때 자동으로 그 브랜치의 코드를 리모트에서 가져오는 것도 로컬과 리모트가 연결되어 있기 때문에 가능한 것입니다. 그렇다면 브랜치를 강제로 분리해보겠습니다.
git checkout main
git branch -D dev
git checkout -b dev
이제 push를 하게되면 아래와 같은 화면을 볼 수 있습니다.
연결된 리모트 브랜치가 없어서 리모트에 올려달라는 이야기입니다. 리모트 브랜치와 연결된 로컬 브랜치를 upstream 이라 하며 위 대화 상자의 내용은 현재 브랜치를 origin dev의 upstream으로 설정한다는 뜻입니다.
위 상태에서 pull을 하면 아래와 같은 대화 상자를 볼 수 있습니다.
연결된 리모트 브랜치가 없어 특정 브랜치에서 풀을 받거나 upstream으로 설정하라는 뜻입니다. 브랜치를 특정 브랜치의 upstream으로 설정하는 방법은 아래와 같습니다.
git branch --set-upstream-to=origin/dev dev
이제 push와 pull이 정상적으로 작동하는 것을 볼 수 있습니다.
커밋과 브랜치는 다르다
브랜치 위에 있다 와 커밋 위에 있다는 다른 의미입니다. 아래와 같이 dev 브랜치로 체크아웃 한 후에 git branch 명령어를 입력하면 아래와 같이 보입니다.
하지만 커밋 주소를 복사한 후 체크아웃 하면
git checkout <커밋 주소> # git checkout 6a873e34dfc07122dad20e93e6bd990f43029e84
git branch
아래와 같이 분리된 헤드를 볼 수 있습니다. 이 헤드는 아직 이름이 부여되지 않아 어떠한 브랜치에도 연결되어 있지 않습니다.
위 상태로 커밋을 남기면 아래와 같이 어떠한 브랜치도 없이 커밋만 남아있는 것을 볼 수 있습니다.
연결된 브랜치가 없어 push를 하면 아래와 같은 화면을 볼 수 있습니다.
위 문제를 해결하는 방법은 아래와 같습니다.
git push origin HEAD:<브랜치 이름> # 리모트 브랜치에 푸시하기 때문에 로컬 브랜치는 그대
git checkout <브랜치 이름> # 로컬 브랜치로 이동
git pull # 풀받기
커밋으로 체크아웃 했을 땐 꼭 다시 브랜치로 돌아와 줘야 한다는 것을 명심해야 합나다!
Git Prune
Head, 브랜치와 관련된 액션을 수행한 후 git pull (fetch) 과정에서 ref lock 에러가 발생했을 때, 해결 방법 중 하나가 'git remote prune origin' 을 수행하는 것입니다.
git remote prune origin
정의는 아래와 같습니다.
- git prune 은 unreachable 한 git object 들을 "local" 에서 clean 하는 작업이다.
- unreachable 이란 git tree 에 의해 참조되지 않는 gc 대상이 되는 dangling refs 들이다.
git prune 을 수행할 때 --dry-run --verbose 옵션을 주면 실제 수행되지는 않고, 어떻게 수행될지 시뮬레이션을 볼 수 있습니다.
git remote prune --dry-run --verbose
git remote prune 과 git fetch --prune 도 git prune 이 하는 일을 똑같이 합니다.
remote 에 존재하지 않는 refs 를 지워버린 후에 fetch 나 pull 을 수행합니다.
git fetch --prune
prune 은 remote 의 것을 지우는 것이 아닌, local 에서 remote 를 참조하는 것 중 유효하지 않은 것을 제거하는 작업입니다.
여기에 --tag나 --force와 같은 옵션들을 주면, 강제로 local에서 remote의 유효하지 않은 tag도 함께 제거할 수 있습니다.
git fetch --all --prune --tags --force
'GIT > GIT 심화' 카테고리의 다른 글
Git Commit Message Convention (0) | 2023.01.29 |
---|---|
Tag를 이용한 버전 관리 (0) | 2023.01.29 |
Diff로 변경사항 확인하기 (1) | 2023.01.28 |
rm으로 Cached 관리하기 (0) | 2023.01.28 |
Checkout이 있는데 왜 Switch, Restore? (0) | 2023.01.28 |