今天在創(chuàng)建git倉庫時,想到了加不加--bare參數(shù)的問題,之前印象中知道是有區(qū)別的,具體區(qū)別在哪一時還真說不清了,這篇文章就總結(jié)一下。
差分對比
首先,這兩個命令都是初始化一個空的git倉庫,分別用這兩個命令創(chuàng)建兩個示例分析一下:
$ git init repo
$ tree -a repo
repo
└── .git
├── branches
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
10 directories, 15 files
$ git init --bare repo.git
$ tree -a repo.git
repo.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
├── readme
└── refs
├── heads
└── tags
9 directories, 16 files
可以看到,初始化后的目錄結(jié)構(gòu)是不一樣的,加了bare參數(shù)后不會在根目錄創(chuàng)建.git文件夾,而把.git下面的文件直接拿到根目錄里來了。再來看一下配置上有什么不同:
$ cd repo; git config --list | grep core
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
$ cd repo.git; git config --list | grep core
core.repositoryformatversion=0
core.filemode=true
core.bare=true
可以看到有兩項配置不一樣,從字面意思也基本能猜到代表什么意思。
功能差異
加bare參數(shù)創(chuàng)建的倉庫(repo.git)一般叫“裸倉庫”,里面沒有工作區(qū)的概念,即你不能直接在這樣的倉庫里進(jìn)行正常的git命令操作;反之,不加bare參數(shù)創(chuàng)建的倉庫(repo)就可以直接在上面進(jìn)行g(shù)it操作。如果是這樣的話,那“裸倉庫”還有什么用呢?我們先來看兩個示例,分別clone上面創(chuàng)建的兩個倉庫,然后修改、提交并push到遠(yuǎn)程倉庫:
$ git clone repo c_1
$ cd c_1; touch test.txt; git add -A; g commit -m "test commit"
$ git push origin master
對象計數(shù)中: 3, 完成.
寫入對象中: 100% (3/3), 205 bytes | 205.00 KiB/s, 完成.
Total 3 (delta 0), reused 0 (delta 0)
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: 默認(rèn)禁止更新非純倉庫的當(dāng)前分支,因為您推送的內(nèi)容將導(dǎo)致索引和工作區(qū)
remote: 不一致,并且將需要執(zhí)行 'git reset --hard' 將工作區(qū)匹配到 HEAD。
remote:
remote: 您可以在遠(yuǎn)程倉庫中設(shè)置 'receive.denyCurrentBranch' 配置變量為
remote: 'ignore' 或 'warn' 以允許推送到當(dāng)前分支。然而不推薦這么做,除非您
remote: 用某種方式將其工作區(qū)更新至您推送的狀態(tài)。
remote:
remote: 若要屏蔽此信息且保持默認(rèn)行為,設(shè)置 'receive.denyCurrentBranch'
remote: 配置變量為 'refuse'。
To /home/evan/ARM/repo
! [remote rejected] master -> master (branch is currently checked out)
error: 無法推送一些引用到 '/home/evan/ARM/repo'
可以發(fā)現(xiàn),并不能推送修改到“非裸倉庫”,提示里也給出了說明。再來試試裸倉庫的情況:
$ git clone repo.git c_2
$ cd c_2; touch test.txt; git add -A; g commit -m "test commit"
$ git push origin master
對象計數(shù)中: 3, 完成.
寫入對象中: 100% (3/3), 204 bytes | 204.00 KiB/s, 完成.
Total 3 (delta 0), reused 0 (delta 0)
To /home/evan/ARM/repo.git
* [new branch] master -> master
推送修改到“裸倉庫”就一切正常,這也正是裸倉庫存在的意義, 裸倉庫一般情況下僅作為遠(yuǎn)程倉庫使用。個人理解,這樣主要是為了維護(hù)遠(yuǎn)程倉庫的“干凈”,考慮這個場景,如果有人在遠(yuǎn)程倉庫做了git操作,而你往上提交推送的時候必然會產(chǎn)生很多不必要的沖突。而將遠(yuǎn)程倉庫賦予bare屬性,大家沿著同一個準(zhǔn)線往上提交推送,管理起來就方便多了。所以,我們在GitHub等這樣的網(wǎng)站上看到的項目都是bare倉庫。
總結(jié)
使用git init --bare “repo”可以創(chuàng)建一個裸倉庫,并且這個倉庫是可以被正常clone和push的,裸倉庫不包含工作區(qū),所以不能在裸倉庫上直接提交變更。