Skip to content

Git:Bundle

앞에서 Git 데이터를 네트워크를 거쳐 전송하는 일반적인 방법(HTTP, SSH등)을 다루었었다. 일반적으로 사용하진 않지만, 꽤 유용한 방법이 하나 더 있다.

Git에는 “Bundle” 이란 것이 있다. 데이터를 한 파일에 몰아넣는 것이다. 이 방법은 다양한 경우 유용하게 사용할 수 있다. 예를 들어 네트워크가 불통인데 변경사항을 동료에게 보낼 때, 출장을 나갔는데 보안상의 이유로 로컬 네트워크에 접속하지 못할 때, 통신 인터페이스 장비가 고장났을 때, 갑자기 공용 서버에 접근하지 못할 때, 누군가에게 수정사항을 이메일로 보내야 하는데 40개 씩이나 되는 커밋을 format-patch 로 보내고 싶지 않을 때를 예로 들 수 있다.

바로 이럴 때 git bundle 이 한 줄기 빛이 되어준다. bundle 명령은 보통 git push 명령으로 올려 보낼 모든 것을 감싸서 한 바이너리 파일로 만든다. 이 파일을 이메일로 보내거나 USB로 다른 사람에게 보내서 다른 저장소에 풀어서(Unbundle) 사용한다.

 즉, 데이터를 한 파일에 몰아넣는 기능. 즉, 백업. 오프라인 환경에 리모트 변경사항을 적용할 때도 유용하다.

Usage

master 브랜치의 모든 커밋 내용을 번들로 만들기 -> 즉, 특정 브랜치 전체 백업.

git bundle create repo.bundle HEAD master

번들로 부터 클론:

git clone repo.bundle repo

특정 커밋 범위만 번들로 만들기:

git bundle create commits.bundle master ^9a466c5

번들을 현재 워크스페이스에 적용 가능한지 확인:

git bundle verify ../commits.bundle

번들에 포함된 브랜치 확인:

git bundle list-heads ../commits.bundle

번들의 master 브랜치로부터 fetch 한 내용을 other-master 브랜치로 당겨받기.

git fetch ../commits.bundle master:other-master

Examples

Offline 상태인 다른 컴퓨터에 최신 내용 커밋하는 방법

Offline 상태인 원격지 로그:

[11:55:05] aaa@aaa-desktop:~/Project/ddrm (main)
$ git log10a
* e1ffc3d (HEAD -> main, origin/main, origin/HEAD) Add algorithm v2.1
* 4cb9831 (tag: 0.0.16) Bump version
* a82cb41 Trivial commit
* 1571e7b Update ground truth
* 48240a1 Add redis-cli scripts
* a9b6f8b Raise NotFoundContours instead of ValueError in ImgprocBase.find_plate_v1
* 1a5ece7 Update NVR information
* a2fe7b9 Fix layer name conflict
* 30c113b Update README
* bf0e344 Update perspective points

현재 나의 작업공간:

[11:58:58] your@your-Desktop:~/Project/ddrm (main)
$ git log20a
* f73606f (HEAD -> main) Record release videos
* 9aaa3a4 Create count_nonzero_lines
* ab3c5d4 Upgrade requirements: cvlayer>=0.26.0
* 1699c28 (tag: 0.0.18, origin/main, origin/HEAD) Bump version
* 99b9e53 Update ko manual
* ede6632 Update DEFAULT_BREAK_OUT_COUNT value: 60 -> 100
* fd591b0 Increased readability of the Calibration Info Box
* a97a889 (tag: 0.0.17) Bump version
* c221381 Remove unused script: redis-cli-flushall
* 4cc77ea Implement plate break-out feature
* bd4ee27 Update cam4s area_filter_min: 60000 -> 50000
* c530378 Add apps: ls, rls, put, get
* b5e43f1 Update default variables
* 8129c96 Apply settings approx_epsilon
* 13b1e37 Update constant variables
* e1ffc3d Add algorithm v2.1
* 4cb9831 (tag: 0.0.16) Bump version
* a82cb41 Trivial commit
* 1571e7b Update ground truth
* 48240a1 Add redis-cli scripts

main 브랜치의 e1ffc3d 부터 f73606f (HEAD) 를 확보해야 한다.

git bundle create offline.bundle e1ffc3d..main

e1ffc3d..main로 사용한 <git-rev-list-args>파라미터는 git log로 확인 가능해야 한다.

$ git log --oneline e1ffc3d..main
f73606f (HEAD -> main) Record release videos
9aaa3a4 Create count_nonzero_lines
ab3c5d4 Upgrade requirements: cvlayer>=0.26.0
1699c28 (tag: 0.0.18, origin/main, origin/HEAD) Bump version
99b9e53 Update ko manual
ede6632 Update DEFAULT_BREAK_OUT_COUNT value: 60 -> 100
fd591b0 Increased readability of the Calibration Info Box
a97a889 (tag: 0.0.17) Bump version
c221381 Remove unused script: redis-cli-flushall
4cc77ea Implement plate break-out feature
bd4ee27 Update cam4s area_filter_min: 60000 -> 50000
c530378 Add apps: ls, rls, put, get
b5e43f1 Update default variables
8129c96 Apply settings approx_epsilon
13b1e37 Update constant variables

번들 파일을 원격지에 복사한후 올바른 Git Bundle인가 검사한다.

[12:18:50] aaa@aaa-desktop:~/Project/ddrm (main)
$ git bundle verify offline.bundle
The bundle contains this ref:
f73606fea28e53770617a91db89f325b45a11d07 refs/heads/main
The bundle requires this ref:
e1ffc3d07bf14673c7639c29f5a2f03dff95417d
offline.bundle is okay

번들에 포함된 브랜치 목록을 확인하자:

[12:19:06] aaa@aaa-desktop:~/Project/ddrm (main)
$ git bundle list-heads ./offline.bundle
f73606fea28e53770617a91db89f325b45a11d07 refs/heads/main

<span style="color:red;">[에러 예제] 참고로, 현재 존재하는 브랜치에 fetch 를 하면 오류가 나더라...

[12:18:57] aaa@aaa-desktop:~/Project/ddrm (main)
$ git fetch ./offline.bundle main:main
fatal: Refusing to fetch into current branch refs/heads/main of non-bare repository

그래서 other-main라는 새로운 브랜치 만들어서 fetch 한다:

[12:20:12] aaa@aaa-desktop:~/Project/ddrm (main)
$ git fetch  ./offline.bundle  main:other-main
Receiving objects: 100% (138/138), 3.15 MiB | 44.12 MiB/s, done.
Resolving deltas: 100% (80/80), completed with 28 local objects.
From ./offline.bundle
 * [new branch]      main       -> other-main

그리고 rebase 또는 merge 한다:

[12:21:06] aaa@aaa-desktop:~/Project/ddrm (main)
$ git rebase other-main
First, rewinding head to replay your work on top of it...
Fast-forwarded main to other-main.

other-mainmain이 동일한 위치에 있는지 확인하고:

[12:21:06] aaa@aaa-desktop:~/Project/ddrm (main)
$ git log30a
* f73606f (HEAD -> main, other-main) Record release videos
* 9aaa3a4 Create count_nonzero_lines
* ab3c5d4 Upgrade requirements: cvlayer>=0.26.0
...

불필요한 other-main 브랜치 삭제:

[12:21:10] aaa@aaa-desktop:~/Project/ddrm (main)
$ git branch -d other-main
Deleted branch other-main (was f73606f).

간단히 사용할 목적의 스크립트

신규작업공간(New)과 레거시공간(Old) 가 있을 경우:

Old 와 New 의 공통: origin/HEAD이고, 신규로작업공간(New)에 추가로 커밋한 위치가 HEAD 일 때,

최신 버전이 있는 신규작업공간(New) 에서:

git bundle create offline.bundle origin/HEAD..HEAD

"offline.bundle" 파일 복사 (~/Downloads/offline.bundle로 복사했다 가정) 후 레거시공간(Old) 에서:

## [Optionsl] 확인부터 하는게 안전하긴 하다:
git bundle verify ~/Downloads/offline.bundle

## [Optionsl] 브랜치 목록 확인. 아마도 "HEAD" 가 될 것이다.
git bundle list-heads ~/Downloads/offline.bundle
## "7e00d08f73777d66077f4f20ef8331e581bb49d4 HEAD" 이런 느낌으로 출력될듯

git fetch ~/Downloads/offline.bundle HEAD:offline
git rebase offline
git branch -d offline

See also

Favorite site