通常我們會用 git init
命令來將我們所在的目錄轉換為一個 Git 本地倉庫或者初始化一個新的空倉庫。
用法
-
將當前目錄轉換為一個本地倉庫
git init
這個命令執行後會在本地生成一個 .git
的資料夾,用來追蹤倉庫的所有變更。效果如下:
-
指定某個目錄成為本地倉庫
git init <repo>
這個命令執行後, 將建立一個名為repo且只包含 .git
子資料夾的空目錄。效果如下:
-
指定某個目錄成為中心倉庫(裸倉庫)
git init --bare <repo>
這個命令執行後,將在本地建立一個名為 repo 的資料夾, 裡面包含著 Git 的基本目錄, 我們一般會將這個資料夾命名為後面加 .git
的形式,如 repo.git
(這也是為什麼我們從 GitHub clone 倉庫的時候,地址都是 xxx.git 這樣的形式的原因)。效果如下:
詳細說一下使用 --bare
引數的含義,使用 --bare
引數初始化的倉庫,我們一般稱之為裸倉庫, 因為這樣建立的倉庫並不包含 工作區
, 也就是說,我們並不能在這個目錄下執行我們一般使用的 Git 命令。
對比
我們來對比一下直接使用 git init
建立的倉庫和加了 --bare
引數的兩個倉庫。 我們直接看兩個倉庫的的 config
檔案中的內容:
-
直接
git init
建立的倉庫:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
-
加了
--bare
建立的裸倉庫:
[core]
repositoryformatversion = 0
filemode = true
bare = true
ignorecase = true
precomposeunicode = true
可以看到最直觀的差異在於 bare
配置項是否為 true
, 此外不加 --bare
建立的本地倉庫配置中有一項 logallrefupdates = true
, 作用根據名字就可以看出來, 記錄所有的 ref
(引用) 更新, 關於 ref 的部分之後有時間可以再寫,這個配置可以理解為是 Git 的一道防線。
功能差異
我們可以使用最簡單的例子演示一下。
# 直接建立本地倉庫
(Tao) ➜ git init repo
# 建立裸倉庫
(Tao) ➜ git init --bare repo.git
# 分別 clone 兩個倉庫
(Tao) ➜ git clone repo c1
Cloning into `c1`...
warning: You appear to have cloned an empty repository.
done.
(Tao) ➜ git clone repo.git c2
Cloning into `c2`...
warning: You appear to have cloned an empty repository.
done.
# 進入 c1 倉庫
(Tao) ➜ cd c1
(Tao) ➜ c1 git:(master) touch test
(Tao) ➜ c1 git:(master) ✗ g add -A
(Tao) ➜ c1 git:(master) ✗ g commit -m "test commit"
[master (root-commit) b1e32ad] test commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
(Tao) ➜ c1 git:(master) git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 200 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require `git reset --hard` to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set `receive.denyCurrentBranch` configuration variable to
remote: error: `ignore` or `warn` in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: `receive.denyCurrentBranch` configuration variable to `refuse`.
To /Users/tao/repo
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to `/Users/tao/repo`
# 進入 c2 倉庫重複執行
(Tao) ➜ c1 git:(master) cd ../c2
(Tao) ➜ c2 git:(master) touch test
(Tao) ➜ c2 git:(master) ✗ git add -A
(Tao) ➜ c2 git:(master) ✗ git commit -m "test commit"
[master (root-commit) 7aacc58] test commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
(Tao) ➜ c2 git:(master) git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 201 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /Users/tao/repo.git
* [new branch] master -> master
從裸倉庫 clone 下來的本地倉庫可以進行正常的 push
操作, 但是從一般倉庫 clone 下來的本地倉庫卻不行。 這也正是裸倉庫存在的意義。 裸倉庫一般情況下是作為遠端的中心倉庫而存在的。
總結
使用 git init --bare <repo>
可以建立一個裸倉庫,並且這個倉庫是可以被正常 clone
和 push
更新的, 裸倉庫不包含工作區,所以並不會存在在裸倉庫上直接提交變更的情況。
可以通過公眾號 TheMoeLove 和我聯絡