-
1. 시작하기
-
2. Git의 기초
- 2.1 Git 저장소 만들기
- 2.2 수정하고 저장소에 저장하기
- 2.3 커밋 히스토리 조회하기
- 2.4 되돌리기
- 2.5 리모트 저장소
- 2.6 태그
- 2.7 Git Alias
- 2.8 요약
-
3. Git 브랜치
-
4. Git 서버
- 4.1 프로토콜
- 4.2 서버에 Git 설치하기
- 4.3 SSH 공개키 만들기
- 4.4 서버 설정하기
- 4.5 Git 데몬
- 4.6 스마트 HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 또 다른 선택지, 호스팅
- 4.10 요약
-
5. 분산 환경에서의 Git
- 5.1 분산 환경에서의 워크플로
- 5.2 프로젝트에 기여하기
- 5.3 프로젝트 관리하기
- 5.4 요약
-
6. GitHub
- 6.1 계정 만들고 설정하기
- 6.2 GitHub 프로젝트에 기여하기
- 6.3 GitHub 프로젝트 관리하기
- 6.4 Organization 관리하기
- 6.5 GitHub 스크립팅
- 6.6 요약
-
7. Git 도구
- 7.1 리비전 조회하기
- 7.2 대화형 명령
- 7.3 Stashing과 Cleaning
- 7.4 내 작업에 서명하기
- 7.5 검색
- 7.6 히스토리 단장하기
- 7.7 Reset 명확히 알고 가기
- 7.8 고급 Merge
- 7.9 Rerere
- 7.10 Git으로 버그 찾기
- 7.11 서브모듈
- 7.12 Bundle
- 7.13 Replace
- 7.14 Credential 저장소
- 7.15 요약
-
8. Git맞춤
- 8.1 Git 설정하기
- 8.2 Git Attributes
- 8.3 Git Hooks
- 8.4 정책 구현하기
- 8.5 요약
-
9. Git과 여타 버전 관리 시스템
- 9.1 Git: 범용 Client
- 9.2 Git으로 옮기기
- 9.3 요약
-
10. Git의 내부
- 10.1 Plumbing 명령과 Porcelain 명령
- 10.2 Git 개체
- 10.3 Git Refs
- 10.4 Packfile
- 10.5 Refspec
- 10.6 데이터 전송 프로토콜
- 10.7 운영 및 데이터 복구
- 10.8 환경변수
- 10.9 요약
-
A1. 부록 A: 다양한 환경에서 Git 사용하기
- A1.1 GUI
- A1.2 Visual Studio
- A1.3 Eclipse
- A1.4 Bash
- A1.5 Zsh
- A1.6 Git in Powershell
- A1.7 요약
-
A2. 부록 B: 애플리케이션에 Git 넣기
-
A3. 부록 C: Git 명령어
- A3.1 설치와 설정
- A3.2 프로젝트 가져오기와 생성하기
- A3.3 스냅샷 다루기
- A3.4 Branch와 Merge
- A3.5 공유하고 업데이트하기
- A3.6 보기와 비교
- A3.7 Debugging
- A3.8 Patch 하기
- A3.9 Email
- A3.10 다른 버전 관리 시스템
- A3.11 관리
- A3.12 Plumbing 명령어
3.5 Git 브랜치 - 리모트 브랜치
리모트 브랜치
리모트 Refs는 리모트 저장소에 있는 포인터인 레퍼런스다. 리모트 저장소에 있는 브랜치, 태그, 등등을 의미한다.
git ls-remote [remote]
명령으로 모든 리모트 Refs를 조회할 수 있다. git remote show [remote]
명령은 모든 리모트 브랜치와 그 정보를 보여준다.
리모트 Refs가 있지만 보통은 리모트 트래킹 브랜치를 사용한다.
리모트 트래킹 브랜치는 리모트 브랜치를 추적하는 레퍼런스이며 브랜치다. 리모트 트래킹 브랜치는 로컬에 있지만 임의로 움직일 수 없다. 리모트 서버에 연결할 때마다 리모트의 브랜치 업데이트 내용에 따라서 자동으로 갱신될 뿐이다. 리모트 트래킹 브랜치는 일종의 북마크라고 할 수 있다. 리모트 저장소에 마지막으로 연결했던 순간에 브랜치가 무슨 커밋을 가리키고 있었는지를 나타낸다.
리모트 트래킹 브랜치의 이름은 <remote>/<branch>
형식으로 되어 있다.
예를 들어 리모트 저장소 origin
의 master
브랜치를 보고 싶다면 origin/master
라는 이름으로 브랜치를 확인하면 된다.
다른 팀원과 함께 어떤 이슈를 구현할 때 그 팀원이 iss53
브랜치를 서버로 Push 했고 당신도 로컬에 iss53
브랜치가 있다고 가정하자. 이때 서버의 iss53
브랜치가 가리키는 커밋은 로컬에서 origin/iss53
이 가리키는 커밋이다.
다소 헷갈릴 수 있으니 예제를 좀 더 살펴보자.
git.ourcompany.com
이라는 Git 서버가 있고 이 서버의 저장소를 하나 Clone 하면 Git은 자동으로 origin
이라는 이름을 붙인다.
origin
으로부터 저장소 데이터를 모두 내려받고 master
브랜치를 가리키는 포인터를 만든다. 이 포인터는 origin/master
라고 부르고 멋대로 조종할 수 없다.
그리고 Git은 로컬의 master
브랜치가 origin/master
를 가리키게 한다. 이제 이 master
브랜치에서 작업을 시작할 수 있다.
노트
|
“origin” 의 의미
브랜치 이름으로 많이 사용하는 “master” 라는 이름이 괜히 특별한 의미를 가지는 게 아닌 것처럼 “origin” 도 특별한 의미가 있는 것은 아니다.
|
![Clone 이후 서버와 로컬의 master 브랜치](png/remote-branches-1.png)
로컬 저장소에서 어떤 작업을 하고 있는데 동시에 다른 팀원이 git.ourcompany.com
서버에 Push 하고 master
브랜치를 업데이트한다. 그러면 이제 팀원 간의 히스토리는 서로 달라진다.
서버 저장소로부터 어떤 데이터도 주고받지 않아서 origin/master
포인터는 그대로다.
![로컬과 서버의 커밋 히스토리는 독립적임](png/remote-branches-2.png)
리모트 서버로부터 저장소 정보를 동기화하려면 git fetch origin
명령을 사용한다.
명령을 실행하면 우선 “origin” 서버의 주소 정보(이 예에서는 git.ourcompany.com
)를 찾아서, 현재 로컬의 저장소가 갖고 있지 않은 새로운 정보가 있으면 모두 내려받고, 받은 데이터를 로컬 저장소에 업데이트하고 나서, origin/master 포인터의 위치를 최신 커밋으로 이동시킨다.
![`git fetch` 명령은 리모트 브랜치 정보를 업데이트](png/remote-branches-3.png)
git fetch
명령은 리모트 브랜치 정보를 업데이트리모트 저장소를 여러 개 운영하는 상황을 이해할 수 있도록 개발용으로 사용할 Git 저장소를 팀 내부에 하나 추가해 보자.
이 저장소의 주소가 git.team1.ourcompany.com
이며
Git의 기초에서 살펴본 git remote add
명령으로 현재 작업 중인 프로젝트에 팀의 저장소를 추가한다.
이름을 teamone
으로 짓고 긴 서버 주소 대신 사용한다.
![서버를 리모트 저장소로 추가](png/remote-branches-4.png)
서버를 추가하고 나면 git fetch teamone
명령으로 teamone
서버의 데이터를 내려받는다.
명령을 실행해도 teamone
서버의 데이터는 모두 origin
서버에도 있는 것들이라서 아무것도 내려받지 않는다. 하지만, 이 명령은 리모트 트래킹 브랜치 teamone/master
가 teamone
서버의 master
브랜치가 가리키는 커밋을 가리키게 한다.
![`teamone/master` 의 리모트 트래킹 브랜치](png/remote-branches-5.png)
teamone/master
의 리모트 트래킹 브랜치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의 내부에서 refs/heads/
의 뜻을 자세히 알아볼 것이기 때문에 일단 넘어가도록 한다.
git push origin serverfix:serverfix
라고 Push 하는 것도 같은 의미인데 이것은 “로컬의 serverfix 브랜치를 리모트 저장소의 serverfix 브랜치로 Push 하라” 라는 뜻이다.
로컬 브랜치의 이름과 리모트 서버의 브랜치 이름이 다를 때 필요하다.
리모트 저장소에 serverfix
라는 이름 대신 다른 이름을 사용하려면 git push origin serverfix:awesomebranch
처럼 사용한다.
노트
|
암호를 매번 입력하지 않아도 된다
HTTPS URL로 시작하는 리모트 저장소를 사용한다면 아마도 Push 나 Pull을 할 때 인증을 위한 사용자이름이나 암호를 묻는 것을 볼 수 있다. 보통 터미널에서 작업하는 경우 Git이 이 정보를 사용자로부터 받기 위해 사용자이름이나 암호를 입력받아 서버로 전달해서 권한을 확인한다. 이 리모트에 접근할 때마다 매번 사용자이름나 암호를 입력하지 않도록 “credential cache” 기능을 이용할 수 있다.
이 기능을 활성화하면 Git은 몇 분 동안 입력한 사용자이름이나 암호를 저장해둔다. 이 기능을 활성화하려면 이 기능이 제공하는 다른 옵션에 대한 자세한 설명은 Credential 저장소를 참고한다. |
나중에 누군가 저장소를 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
라는 로컬 브랜치가 만들어진다.
브랜치 추적
리모트 트래킹 브랜치를 로컬 브랜치로 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.
노트
|
Upstream 별명
추적 브랜치를 설정했다면 추적 브랜치 이름을 |
추적 브랜치가 현재 어떻게 설정되어 있는지 확인하려면 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
Pull 하기
git fetch
명령을 실행하면 서버에는 존재하지만, 로컬에는 아직 없는 데이터를 받아와서 저장한다. 이 때 워킹 디렉토리의 파일 내용은 변경되지 않고 그대로 남는다.
서버로부터 데이터를 가져와서 저장해두고 사용자가 Merge 하도록 준비만 해둔다.
간단히 말하면 git pull
명령은 대부분 git fetch
명령을 실행하고 나서 자동으로 git merge
명령을 수행하는 것 뿐이다.
바로 앞 절에서 살펴본 대로 clone
이나 checkout
명령을 실행하여 추적 브랜치가 설정되면 git pull
명령은 서버로부터 데이터를 가져와서 현재 로컬 브랜치와 서버의 추적 브랜치를 Merge 한다.
일반적으로 fetch
와 merge
명령을 명시적으로 사용하는 것이 pull
명령으로 한번에 두 작업을 하는 것보다 낫다.
리모트 브랜치 삭제
동료와 협업하기 위해 리모트 브랜치를 만들었다가 작업을 마치고 master
브랜치로 Merge 했다. 협업하는 데 사용했던 그 리모트 브랜치는 이제 더 이상 필요하지 않기에 삭제할 수 있다.
git push
명령에 --delete
옵션을 사용하여 리모트 브랜치를 삭제할 수 있다.
serverfix
라는 리모트 브랜치를 삭제하려면 아래와 같이 실행한다.
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
- [deleted] serverfix
위 명령을 실행하면 서버에서 브랜치(즉 커밋을 가리키는 포인터) 하나가 사라진다. 서버에서 가비지 컬렉터가 동작하지 않는 한 데이터는 사라지지 않기 때문에 종종 의도치 않게 삭제한 경우에도 커밋한 데이터를 살릴 수 있다.