Pro git - 3.5

Updated:

Pro git - 리모트 브랜치

1. 리모트 브랜치

  • 리모트 Refs는 리모트 저장소에 있는 포인터인 레퍼런스다.
  • 리모트 저장소에 있는 브랜치, 태그, 등등을 의미한다.
  • git ls-remote [remote] 명령으로 모든 리모트 Refs를 조회할 수 있다.
  • git remote show [remote] 명령은 모든 리모트 브랜치와 그 정보를 보여준다.
  • 리모트 Refs가 있지만 보통은 리모트 트래킹 브랜치를 사용한다.
user@DESKTOP-AVTBP4I MINGW64 ~/Desktop/myBlog/sunlike0508.github.io (master)
$ git remote show origin
* remote origin
  Fetch URL: https://github.com/sunlike0508/sunlike0508.github.io.git
  Push  URL: https://github.com/sunlike0508/sunlike0508.github.io.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)
  • 리모트 트래킹 브랜치는 리모트 브랜치를 추적하는 레퍼런스이며 브랜치이다.
  • 리모트 트래킹 브랜치는 로컬에 있지만 임의로 움직일 수 없다.
  • 리모트 서버에 연결할 때마다 리모트의 브랜치 업데이트 내용에 따라서 자동으로 갱신될 뿐이다.
  • 리모트 트래킹 브랜치는 일종의 북마크라고 할 수 있다.
  • 리모트 저장소에 마지막으로 연결했던 순간에 브랜치가 무슨 커밋을 가리키고 있었는지를 나타낸다.
  • 리모트 트래킹 브랜치의 이름은 <remote>/<branch> 형식으로 되어 있다.
  • 예를 들어 리모트 저장소 originmaster 브랜치를 보고 싶다면 origin/master 라는 이름으로 브랜치를 확인하면 된다.
  • 다른 팀원과 함께 어떤 이슈를 구현할 때 그 팀원이 iss53 브랜치를 서버로 Push 했고 당신도 로컬에 iss53 브랜치가 있다고 가정하자.
  • 이때 서버의 iss53 브랜치가 가리키는 커밋은 로컬에서 origin/iss53이 가리키는 커밋이다.
1.1 자세한 예제
  • git.ourcompany.com 이라는 Git 서버가 있고 이 서버의 저장소를 하나 Clone 하면 Git은 자동으로 origin 이라는 이름을 붙인다.
  • origin 으로부터 저장소 데이터를 모두 내려받고 master 브랜치를 가리키는 포인터를 만든다.
  • 이 포인터는 origin/master 라고 부르고 멋대로 조종할 수 없다.
  • 그리고 Git은 로컬의 master 브랜치가 origin/master 를 가리키게 한다.
  • 이제 이 master 브랜치에서 작업을 시작할 수 있다.
1.2 origin의 의미
  • 브랜치 이름으로 많이 사용하는 “master” 라는 이름이 괜히 특별한 의미를 가지는 게 아닌 것처럼 “origin” 도 특별한 의미가 있는 것은 아니다.

  • “master”는 git init 명령이 자동으로 만들어주는 브랜치 이름이다.
  • “origin”는 git clone 명령이 자동으로 만들어주는 리모트 이름이다.
  • git clone -o booyah 라고 옵션을 주고 명령을 실행하면 booyah/master 라고 사용자가 정한 대로 리모트 이름을 생성해준다.
1.3 그림 예제

  • 로컬 저장소에서 어떤 작업을 하고 있는데 동시에 다른 팀원이 git.ourcompany.com 서버에 Push 하고 master 브랜치를 업데이트한다.
  • 그러면 이제 팀원 간의 히스토리는 서로 달라진다.
  • 서버 저장소로부터 어떤 데이터도 주고받지 않아서 origin/master 포인터는 그대로다.

  • 리모트 서버로부터 저장소 정보를 동기화하려면 git fetch origin 명령을 사용한다.
  • 명령을 실행하면 우선 “origin” 서버의 주소 정보(이 예에서는 git.ourcompany.com)를 찾는다.
  • 그리고 현재 로컬의 저장소가 갖고 있지 않은 새로운 정보가 있으면 모두 내려받는다.
  • 그리고 받은 데이터를 로컬 저장소에 업데이트한다.
  • 그리고 origin/master 포인터의 위치를 최신 커밋으로 이동시킨다.

  • 위 상황에서 리모트 저장소를 여러 개 운영하는 상황을 이해할 수 있도록 개발용으로 사용할 Git 저장소를 팀 내부에 하나 추가해 보자.
  • 이 저장소의 주소가 git.team1.ourcompany.com 이며 git remote add 명령으로 현재 작업 중인 프로젝트에 팀의 저장소를 추가한다.
  • 이름을 teamone 으로 짓고 긴 서버 주소 대신 사용한다.

  • 서버를 추가하고 나면 git fetch teamone 명령으로 teamone 서버의 데이터를 내려받는다.
  • 명령을 실행해도 teamone 서버의 데이터는 모두 origin 서버에도 있는 것들이라서 아무것도 내려받지 않는다.
  • 하지만, 이 명령은 리모트 트래킹 브랜치 teamone/masterteamone 서버의 master 브랜치가 가리키는 커밋을 가리키게 한다.

2. Push 하기

  • 로컬의 브랜치를 서버로 전송하려면 쓰기 권한이 있는 리모트 저장소에 Push 해야 한다.
  • 로컬 저장소의 브랜치는 자동으로 리모트 저장소로 전송되지 않는다.
  • 명시적으로 브랜치를 Push 해야 정보가 전송된다.
  • 따라서 리모트 저장소에 전송하지 않고 로컬 브랜치에만 두는 비공개 브랜치를 만들 수 있다.
  • 또 다른 사람과 협업하기 위해 토픽 브랜치만 전송할 수도 있다.
  • serverfix 라는 브랜치를 다른 사람과 공유할 때도 브랜치를 처음 Push 하는 것과 같은 방법으로 Push 한다. 아래와 같이 git push <remote> <branch> 명령을 사용한다.
$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
 * [new branch]      serverfix -> serverfix
  • Git은 serverfix라는 브랜치 이름을 refs/heads/serverfix:refs/heads/serverfix 로 확장한다.
  • 이것은 serverfix 라는 로컬 브랜치를 서버로 Push 하는데 리모트의 serverfix 브랜치로 업데이트한다는 것을 의미한다.
  • git push origin serverfix:serverfix 라고 Push 하는 것도 같은 의미이다.
  • 즉, “로컬의 serverfix 브랜치를 리모트 저장소의 serverfix 브랜치로 Push 하라” 라는 뜻
  • 로컬 브랜치의 이름과 리모트 서버의 브랜치 이름이 다를 때 필요하다.
  • 리모트 저장소에 serverfix 라는 이름 대신 다른 이름을 사용하려면 git push origin serverfix:awesomebranch 처럼 사용한다.
  • 나중에 누군가 저장소를 Fetch 하고 나서 서버에 있는 serverfix 브랜치에 접근할 때 origin/serverfix 라는 이름으로 접근할 수 있다.
$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
 * [new branch]      serverfix    -> origin/serverfix
  • Fetch 명령으로 리모트 트래킹 브랜치를 내려받는다고 해서 로컬 저장소에 수정할 수 있는 브랜치가 새로 생기는 것이 아니다.

  • 다시 말해서 serverfix 라는 브랜치가 생기는 것이 아니라 그저 수정 못 하는 origin/serverfix 브랜치 포인터가 생기는 것이다.
  • 새로 받은 브랜치의 내용을 Merge 하려면 git merge origin/serverfix 명령을 사용한다.
  • 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 라는 로컬 브랜치가 만들어진다.

3. 브랜치 추적

  • 리모트 트래킹 브랜치를 로컬 브랜치로 Checkout 하면 자동으로 “트래킹(Tracking) 브랜치” 가 만들어진다.
  • 트래킹 하는 대상 브랜치를 “Upstream 브랜치” 라고 부른다.
  • 트래킹 브랜치는 리모트 브랜치와 직접적인 연결고리가 있는 로컬 브랜치이다.
  • 트래킹 브랜치에서 git pull 명령을 내리면 리모트 저장소로부터 데이터를 내려받아 연결된 리모트 브랜치와 자동으로 Merge 한다.

  • 서버로부터 저장소를 Clone을 하면 Git은 자동으로 master 브랜치를 origin/master 브랜치의 트래킹 브랜치로 만든다.
  • 트래킹 브랜치를 직접 만들 수 있는데 리모트를 origin 이 아닌 다른 리모트로 할 수도 있고, 브랜치도 master 가 아닌 다른 브랜치로 추적하게 할 수 있다.
  • git checkout -b <branch> <remote>/<branch> 명령으로 간단히 트래킹 브랜치를 만들 수 있다.
  • --track 옵션을 사용하여 로컬 브랜치 이름을 자동으로 생성할 수 있다.
$ 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'
  • 리모트 브랜치와 다른 이름으로 브랜치를 만들려면 로컬 브랜치의 이름을 아래와 같이 다르게 지정한다.
$ 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 로 데이터를 보내거나 가져온다.

  • 이미 로컬에 존재하는 브랜치가 리모트의 특정 브랜치를 추적하게 하려면 git branch 명령에 -u--set-upstream-to 옵션을 붙여서 아래와 같이 설정한다.

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
  • 추적 브랜치가 현재 어떻게 설정되어 있는지 확인하려면 git branch 명령에 -vv 옵션을 더한다.
  • 이 명령을 실행하면 로컬 브랜치 목록과 로컬 브랜치가 추적하고 있는 리모트 브랜치도 함께 보여준다.
  • 게다가, 로컬 브랜치가 앞서가는지 뒤쳐지는지에 대한 내용도 보여준다.
$ 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
  • 위의 결과를 보면 iss53 브랜치는 origin/iss53 리모트 브랜치를 추적하고 있다는 것을 알 수 있다.
  • “ahead” 표시를 통해 로컬 브랜치가 커밋 2개 앞서 있다(리모트 브랜치에는 없는 커밋이 로컬에는 존재)는 것을 알 수 있다.
  • master 브랜치는 origin/master 브랜치를 추적하고 있으며 두 브랜치가 가리키는 커밋 내용이 같은 상태이다.
  • serverfix 브랜치는 server-fix-good 이라는 teamone 리모트 서버의 브랜치를 추적하고 있으며 커밋 3개 앞서 있으며 동시에 커밋 1개로 뒤쳐져 있다.
  • serverfix 브랜치에 서버로 보내지 않은 커밋이 3개, 서버의 브랜치에서 아직 로컬 브랜치로 머지하지 않은 커밋이 1개 있다는 말이다.
  • 마지막 testing 브랜치는 추적하는 브랜치가 없는 상태이다.
  • 여기서 중요한 점은 명령을 실행했을 때 나타나는 결과는 모두 마지막으로 서버에서 데이터를 가져온(fetch) 시점을 바탕으로 계산한다는 점이다.
  • 즉, 단순히 이 명령만으로는 서버의 최신 데이터를 반영하지는 않으며 로컬에 저장된 서버의 캐시 데이터를 사용한다.
  • 현재 시점에서 진짜 최신 데이터로 추적 상황을 알아보려면 먼저 서버로부터 최신 데이터를 받아온 후에 추적 상황을 확인해야 한다.
  • 따라서 아래와 같이 사용하는 것이 적절하다.
$ git fetch --all; git branch -vv
3.1 Upstream 별명
  • 추적 브랜치를 설정했다면 추적 브랜치 이름을 @{upstream} 이나 @{u} 로 짧게 대체하여 사용할 수 있다.
  • master 브랜치가 origin/master 브랜치를 추적하는 경우라면 git merge origin/master 명령과 git merge @{u} 명령을 똑같이 사용할 수 있다.

4. Pull 하기

  • git fetch 명령을 실행하면 서버에는 존재하지만, 로컬에는 아직 없는 데이터를 받아와서 저장한다.
  • 이 때 워킹 디렉토리의 파일 내용은 변경되지 않고 그대로 남는다.
  • 서버로부터 데이터를 가져와서 저장해두고 사용자가 Merge 하도록 준비만 해둔다.
  • 간단히 말하면 git pull 명령은 대부분 git fetch 명령을 실행하고 나서 자동으로 git merge 명령을 수행하는 것 뿐이다.

  • 바로 앞 절에서 살펴본 대로 clone 이나 checkout 명령을 실행하여 추적 브랜치가 설정되면 git pull 명령은 서버로부터 데이터를 가져와서 현재 로컬 브랜치와 서버의 추적 브랜치를 Merge 한다.
  • 일반적으로 fetchmerge 명령을 명시적으로 사용하는 것이 pull 명령으로 한번에 두 작업을 하는 것보다 낫다.

5. 리모트 브랜치 삭제

  • 협업하는 데 사용했던 그 리모트 브랜치는 이제 더 이상 필요하지 않기에 삭제할 수 있다.
  • git push 명령에 --delete 옵션을 사용하여 리모트 브랜치를 삭제할 수 있다.
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted]         serverfix