리모트 Refs (Remote References)
일단, "Refs"란??
- Git은 모든 'history'를 'Key-Value format'으로 관리한다.
ㄴ> 'Key'는 'SHA-1로 만들어진 40자리 해시값'이나 이를 기억하기 어렵기 때문에 "쉬운 이름의 파일"에 해시값이 저장한다.
이런 파일들을 "References"라고 하며, 약자로 "Refs"라고한다.
- Git에서 "Refs"는 '.git/refs'에 저장된다.
ㄴ> '.git/refs/heads' 디렉토리 내에는 main와 branch파일들이 있다.
- Git에서 "어떤 특정한 작업을 가르키는 Refs"를 "branch"라고 한다.
리모트 Refs (Remote references) 란?
: 리모트 저장소에 있는 포인터인 레퍼런스. 리모트 저장소에 있는 브랜치, 태그, 등등을 의미한다.
<리모트 Refs 정보 조회 명령어들>
1. $ git ls-remote [remote] : 모든 리모트 Refs를 조회
- 원격 저장소의 refs/heads 와 refs/tags 목록을 표시해준다.
- ex) 커니코들린 github의 리모트 Refs 조회 시
$ git ls-remote https://github.com/kunny/kunny-kotlin-book.git
724da71f0afd8e9beb37e0acf7d60216c1a33e75 HEAD
ece20d7730ff73bdcd422906c360982a8be57107 refs/heads/arch-components-lifecycle
dcc096e0afa44af8dd78ecf8a8da137d5f715ddb refs/heads/arch-components-room
680f7b8dc0bee2b63d66c38f1801e4e09c1c2c0c refs/heads/arch-components-viewmodel
6dec6be7abcce7e0c4f877da438218b7c6b238ec refs/heads/dagger-step-1
a6bbe93de516b42ec57df5f2915447c2cf283db5 refs/heads/dagger-step-2
080897e00b236874f29051fc9054f3e1c286975d refs/heads/java
e09876c9a663b61fe1e920971523170f47e389e9 refs/heads/kotlin-step-1
d8f2dae007086272adabe4a7a53681974e25b630 refs/heads/kotlin-step-2
fa165cb2ca67012693707b8268457bacaa93116a refs/heads/kotlin-step-2_cache-on-viewholder
724da71f0afd8e9beb37e0acf7d60216c1a33e75 refs/heads/master
b562d48c40e4620de3cc97acc91afd68a2db6a34 refs/heads/rxjava
aea3c173a796f218fa6856577475ec6aa5565508 refs/heads/rxjava-rxbinding
467185d0c280332775669180ac64bf88878f4d8f refs/pull/2/head
2. $ git remote show [원격저장소명] : 모든 리모트 브랜치와 그 정보 출력
- '리모트 저장소의 URL'과 '추적하는 브랜치'들을 출력
- $ git pull 명령을 실행할 때, main 브랜치와 Merge할 브랜치가 무엇인지 보여 준다.
- ex) fork해 온 커니코들린 github의 리모트 정보 조회
$ git remote show origin
* remote origin
Fetch URL: https://github.com/sykim-ivy/kunny-kotlin-book.git
Push URL: https://github.com/sykim-ivy/kunny-kotlin-book.git
HEAD branch: master
Remote branches:
arch-components-lifecycle tracked
arch-components-room tracked
arch-components-viewmodel tracked
dagger-step-1 tracked
dagger-step-2 tracked
java tracked
kotlin-step-1 tracked
kotlin-step-2 tracked
kotlin-step-2_cache-on-viewholder tracked
master tracked
rxjava tracked
rxjava-rxbinding tracked
Local branches configured for 'git pull':
java merges with remote java
master merges with remote master
Local refs configured for 'git push':
java pushes to java (up to date)
master pushes to master (up to date)
사실, 리모트 Refs가 있지만 보통은 "리모트 트래킹 브랜치(Remote-tracking branch)"를 사용한다.
리모트 트래킹 브랜치(Remote-tracking branch)
"트래킹 브랜치(Tracking branch)"란??
: 원격 브랜치를 로컬로 가져올 때 자동으로 생성되는 '원격 브랜치와 연결된 로컬 브랜치'
- 리모트 브랜치와 직접적인 연결고리가 있는 '로컬 브랜치'이다.
- Repository를 clone하면, 일반적으로 'origin/main'를 추적하는 'main' 브랜치가 자동으로 생성됩니다.
그렇기 때문에 '$ git push'와 '$ git pull'은 별다른 매개변수 없이 바로 사용 가능함
- 트래킹 브랜치에서 $ git push 명령 시 자동으로 원격 저장소와 브랜치를 알고 연결됨
- 트래킹 브랜치에서 $ git pull 명령 시 자동으로 모든 원격 저장소가 업데이트되고 병합(merge)된다.
+) 'Upstream 브랜치'
: 트래킹하는 대상 브랜치 (=로컬 저장소와 연결된 원격 저장소) -> Q. 리모트 트래킹 브랜치가 upstream브랜치랑 같은 거 아닌가??
clone 시, 트래킹 브랜치를 직접 설정하기
: $ git clone -b <remote>/<RemoteTrackingBranchName> <RemoteURL>
(리모트를 origin 이 아닌 다른 리모트로 할 수도 있고, 브랜치도 master 가 아닌 다른 브랜치로 추적하게 할 수 있다.)
<RemoteTrackingBranchName>에 해당하는 'Upstream 브랜치'로 이동
: $ git checkout <remote>/<RemoteTrackingBranchName>
cf) $ git checkout <LocalBranchName> : 브랜치 이동 (※생성 안함!)
'트래킹(Tracking) 브랜치' 생성과 이동
: $ git checkout -b <LocalTrackingBranchName> <remote>/<RemoteTrackingBranchName>
- 생성된 로컬 브랜치의 'Upstream 브랜치'는 <RemoteTrackingBranchName>이다.
ㄴ> cf1) $ git branch <LocalBranchName> : 로컬 브랜치 생성 (※ 이동 안함!)
ㄴ> cf2) $ git push <remote> <AddingRemoteBranchName> : 원격 브랜치 생성
1) 리모트 브랜치와 다른 이름으로 로컬 브랜치를 만들려면
: $ git checkout -b <다르게 사용할 branch명> <remote>/<RemoteTrackingBranchName>
: 리모트 브랜치와 다른 이름으로 브랜치를 만들려면 로컬 브랜치의 이름을 아래와 같이 다르게 지정한다. (ex2)
ㄴ> eX) $ git checkout -b <LocalNewBranchName> master : 원격 master를 기준으로 local에 새로운 branch 만들기
2) 브랜치 이름을 짓지 않고 remote 저장소의 브랜치 이름을 그대로 로컬 브랜치로 생성
: $ git checkout --t <remote>/<RemoteTrackingBranchName>
- [-t 또는 --track 옵션]을 사용하면 된다. (ex1)
이미 로컬에 존재하는 브랜치가 리모트의 특정 브랜치를 추적하게 할 때 = upstream branch설정
: $ git branch -u <remote>/<RemoteTrackingBranchName>
또는 $ git branch --set-upstream-to <remote>/<RemoteTrackingBranchName>
- $ git branch -u 나 --set-upstream-to 옵션 사용 (ex3)
- ★ remote repository로 push할 경우 처음에는 --set-upstream 옵션이 필요하다.
그냥 push할 경우, 로컬 저장소의 브랜치와 연결된 원격 저장소의 브랜치가 없어서 아래와 같이 오류가 발생함
>> fatal: The current branch master has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin master
'트래킹(Tracking) 브랜치' 현재 설정 확인 : $ git branch -vv
※ 중요) 명령을 실행했을 때 나타나는 결과는 모두 "마지막으로 서버에서 데이터를 가져온(fetch) 시점을 바탕으로 계산한다"는 점이다.
단순히 이 명령만으로는 서버의 최신 데이터를 반영하지는 않으며 로컬에 저장된 서버의 캐시 데이터를 사용한다.
최신 데이터로 추적 상황을 알아보려면 먼저 서버로부터 최신 데이터를 받아온 후에 추적 상황을 확인해야 한다.
그러므로 아래처럼 두 명령을 이어서 사용하는 것이 적당하다
$ git fetch --all
$ git branch -vv
- (ex4)
리모트 서버로부터 로컬 저장소 정보를 동기화
: $ git fetch <Remote저장소명>
- Remote저장소의 서버 주소 정보를 찾아서,
로컬의 저장소가 갖고 있지 않은 새로운 정보가 있으면 모두 내려받고 받은 데이터를 로컬 저장소에 업데이트 후,
'<RemoteName>/<RemoteBranchName>'위치를 최신 커밋으로 이동시킨다.
- ※주의★★)
$git fetch 명령으로 "리모트 트래킹 브랜치를 내려받는다고 해서 로컬 저장소에 수정할 수 있는 브랜치가 새로 생기는 것이 아니다. "
▼ 위 주의사항을 꺽고 로컬 저장소에 수정할 수 있는 브랜치를 만들고 싶을 때
리모트 트래킹 브랜치에서 시작하는 로컬 브랜치 생성
: $ git checkout -b <LocalTrackingBranchName> <Remote저장소명>/<Remote브랜치명>
- Merge 하지 않고 리모트 트래킹 브랜치에서 시작하는 로컬 브랜치 생성를 만들려면 아래와 같은 명령을 사용한다.
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
ㄴ> 그러면 origin/serverfix 에서 시작하고 수정할 수 있는 serverfix 라는 로컬 브랜치가 만들어진다.
$git merge : 현재 브랜치와 다른 브랜치를 병합할 때
$git rebase : 현재 브랜치의 commit을 다른 브랜치에 재배치
Ex) 트래킹 브랜치 사용하기
ex1) 리모트 브랜치를 로컬에 가져오기 (checkout)
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
▼ 이 명령은 매우 자주 쓰여서 더 생략할 수 있다.
입력한 브랜치가 있는 (a) 리모트가 딱 하나 있고 (b) 로컬에는 없으면 Git은 트래킹 브랜치를 만들어 준다.
$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
ex2) 리모트 브랜치를 가져올 때 다른 이름으로 로컬 브랜치를 만들려면
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'
ㄴ> 이제 sf 브랜치에서 Push 나 Pull 하면 자동으로 origin/serverfix 로 데이터를 보내거나 가져온다.
ex3) 로컬에 존재하는 브랜치가 리모트의 특정 브랜치를 추적
$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
ex4) 추적 브랜치가 현재 어떻게 설정되어 있는지 확인
$ git branch -vv
iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets
master 1ae2a45 [origin/master] deploying index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
testing 5ea463a trying something new
ㄴ> line2 : iss53 브랜치는 origin/iss53 리모트 브랜치를 추적하고 있다.
'ahead' 표시를 통해 로컬 브랜치가 커밋 2개 앞서 있다(리모트 브랜치에는 없는 커밋이 로컬에는 존재)는 것을 알 수 있다.
ㄴ> line3 : `master 브랜치는 origin/master 브랜치를 추적하고 있으며 두 브랜치가 가리키는 커밋 내용이 같은 상태이다.
ㄴ> line4 : 로컬 브랜치 중 serverfix 브랜치는 server-fix-good 이라는 teamone 리모트 서버의 브랜치를 추적하고 있으며 커밋 3개 앞서 있으며 동시에 커밋 1개로 뒤쳐져 있다.
이 말은 serverfix 브랜치에 서버로 보내지 않은 커밋이 3개, 서버의 브랜치에서 아직 로컬 브랜치로 머지하지 않은 커밋이 1개 있다는 말이다.
ㄴ> line5 : testing 브랜치는 추적하는 브랜치가 없는 상태이다.
리모트 트래킹 브랜치(Remote-tracking branch)
: 로컬에 존재하는 리모트 브랜치를 추적하는 레퍼런스이며 브랜치.
(영어 뜻 그대로 'Remote-tracking branch'로 일종의 북마크)
- 리모트 저장소에 마지막으로 연결했던 순간에 브랜치가 무슨 커밋을 가리키고 있었는지를 나타낸다.
- 로컬에 있지만 임의로 움직일 수 없다.
리모트 서버에 연결할 때마다 리모트의 브랜치 업데이트 내용에 따라서 자동으로 갱신될 뿐이다.
- 브랜치의 이름 형식
<RemoteName>/<RemoteBranchName> |
ㄴ> ex1) 리모트 저장소 origin 의 master 브랜치를 보고 싶다면?
∴ origin/master 라는 이름으로 브랜치를 확인
ㄴ> ex2) 다른 팀원과 함께 어떤 이슈를 구현할 때 그 팀원이 iss53 브랜치를 서버로 Push 했고 당신도 로컬에 iss53 브랜치가 있다고 가정하자. 이때 서버의 iss53 브랜치가 가리키는 커밋은 로컬에서의 명칭은??
∴ origin/iss53
- Ex3) GitPro의 리모트 Ref 예제
ⓐ git.ourcompany.com 이라는 Git 서버가 있고, 이 서버의 저장소를 하나 Clone 하면 Git은 자동으로 'origin' 이라는 이름을 붙인다.
'origin' 으로부터 저장소 데이터를 모두 내려받고 'master' 브랜치를 가리키는 포인터를 만든다.
이 포인터는 origin/master 라고 부르고 멋대로 조종할 수 없다.
그리고 Git은 로컬의 master 브랜치가 origin/master 를 가리키게 한다.
그림 30. Clone 이후 서버와 로컬의 master 브랜치
ⓑ 로컬 저장소에서 어떤 작업을 하고 있는데 동시에 다른 팀원이 git.ourcompany.com 서버에 Push 하고 master 브랜치를 업데이트한다.
그러면 이제 팀원 간의 히스토리는 서로 달라진다.
서버 저장소로부터 어떤 데이터도 주고받지 않아서 origin/master 포인터는 그대로다.
그림 31. 로컬과 서버의 커밋 히스토리는 독립적임
ⓒ $ git fetch origin 명령을 사용하여 원격 저장소 반영사항을 로컬에 가져온다.
★ 그림 32. git fetch 명령은 리모트 브랜치 정보를 업데이트
ⓓ 로컬에 리모트 저장소를 하나 더 추가.
리모트 저장소를 여러 개 운영하는 상황을 이해할 수 있도록 개발용으로 사용할 Git 저장소를 팀 내부에 하나 추가해 보자.
이 저장소의 주소가 git.team1.ourcompany.com 이며 'ch2.1 Git의 기초'에서 살펴본
$ git remote add <이름> <원격 URL> 명령으로 현재 작업 중인 프로젝트에 팀의 저장소를 추가
이름을 teamone 으로 짓고 긴 서버 주소 대신 사용한다.
그림 33. 서버를 리모트 저장소로 추가 https://git-scm.com/book/en/v2/images/remote-branches-4.png
ⓔ $ git fetch teamone 명령으로 teamone 서버의 데이터를 내려받는다.
※ 이 예제의 경우, 명령을 실행해도 teamone 서버의 데이터는 모두 origin 서버에도 있는 것들이라서 아무것도 내려받지 않는다.
(teamone브랜치가 master 브랜치의 이전 커밋을 가리키므로)
하지만, 이 명령은 리모트 트래킹 브랜치 teamone/master 가 teamone 서버의 master 브랜치가 가리키는 커밋을 가리키게 한다.
그림 34. teamone/master 의 리모트 트래킹 브랜치 https://git-scm.com/book/en/v2/images/remote-branches-5.png
END!
스터디 도움 참조 블로그 (References)