📌  相关文章
📜  Git 中的裸仓库

📅  最后修改于: 2021-10-24 12:48:43             🧑  作者: Mango

Git 中的存储库是您正在处理项目的文件夹的快照。您可以通过提交来跟踪对项目所做的进度和更改,如果不满意也可以还原更改。
存储库可以根据在服务器上的使用情况分为两种类型。这些是:

  • 非裸存储库
  • 裸仓库

什么是非裸存储库?
非裸或默认 git 存储库有一个.git文件夹,它是存储库的支柱,用于跟踪文件夹中更改的所有重要文件都存储在该文件夹中。它存储在分支中进行的提交的哈希值和存储最新提交的哈希值的文件。
默认存储库的文件结构应如下所示:

-- Default_Repo* 
    |-- .git* 
    |          |-- hooks* 
    |          |-- info* 
    |          |-- logs* 
    |          |-- objects* 
    |          |-- refs* 
    |          |-- COMMIT_EDITMSG 
    |          |-- config 
    |          |-- description 
    |          |-- HEAD 
    |          |-- index 
    |-- example.txt 

*: Folders 

如您所见, .git文件夹包含跟踪项目文件夹所需的所有文件。默认存储库始终用于本地存储库。什么是裸仓库?
裸存储库与默认存储库相同,但不能在裸存储库中进行提交。裸仓库无法跟踪项目中所做的更改,因为它没有工作树。工作树是所有项目文件/子目录所在的目录。裸存储库本质上是一个.git文件夹,其中包含所有项目文件所在的特定文件夹。
实际上,除了 .git之外,存储库中的所有内容都是工作树的一部分。要创建裸存储库,请在 bash(对于 linux 用户)或命令提示符(对于 Windows 用户)中导航到所选目录并键入:

>mkdir FileName.git 
>cd FileName.git 
>git init –bare 

创建裸仓库

裸仓库的文件结构应如下所示:

-- BareRepo.git* 
              |-- hooks* 
              |-- info* 
              |-- logs* 
              |-- objects* 
              |-- refs* 
              |-- COMMIT_EDITMSG 
              |-- config 
              |-- description 
              |-- HEAD 
              |-- index 

*: Folders 

注意:这与非裸仓库中 .git文件夹的文件结构完全相同

重要的是要注意所有裸存储库都有.git扩展名(例如注意 BareRepo.git)。由于您无法提交或对其进行更改,因此裸存储库本身毫无用处。但那它为什么存在呢?当人们协作处理一个项目时,他们需要一个中央存储库,其中存储所有跟踪的更改并防止其他计算机上的项目版本之间发生任何冲突。中央存储库还意味着任何新贡献者都可以将存储库克隆到本地存储库,而不会获得任何未保存的更改或其他人的工作冲突(简而言之,不会造成混乱)。严格来说,中央存储库应该类似于参考存储库。

这需要使用远程存储库作为中心存储库,并且最初只能将裸存储库用作远程存储库。随着 git 的最新变化,中央存储库不必是裸露的,因此没有多少人正确地了解它。
Bare Repository 上唯一可能的操作是推送或克隆。使用裸仓库
裸仓库与本地仓库链接,因此本地仓库的.git中的文件应该与裸仓库中的文件匹配。首先,创建一个裸存储库(参见代码片段部分)。
然后,创建一个本地存储库文件夹并克隆裸存储库:

>cd C:/Users/example/repositories 
>git clone C:/Users/example/BareRepo.git 
Cloning into 'BareRepo'...
warning: You appear to have cloned an empty repository. 
done. 

不要担心警告。克隆的存储库将具有与裸存储库相同的名称,导航到该文件夹并添加项目文件并提交更改。然后将更改推送到裸存储库:

>git add * 
>git commit -m “First commit” 
[master (root-commit) ffdf43f] First Commit 
 1 file changed, 1 insertion(+) 
 create mode 100644 example.txt 
>git push c:/users/example/BareRepo.git 
Enumerating objects: 3, done. 
Counting objects: 100% (3/3), done. 
Delta compression using up to 4 threads 
Compressing objects: 100% (2/2), done. 
Writing objects: 100% (3/3), 293 bytes | 97.00 KiB/s, done. 
Total 3 (delta 0), reused 0 (delta 0) 
To c:/users/example /BareRepo.git  
 * [new branch]      master -> master 

因此,您的本地存储库已链接到裸存储库。如果项目目录中已经有一些文件,直接将项目文件夹初始化为git仓库,然后将其更改推送到裸仓库(确保裸仓库没有链接到任何其他项目或新创建的)。另一种方法是将您的工作项目存储库克隆到一个裸存储库中:

>cd “Central Repositories” 
>git clone –bare ../../…./Default_Repo 
Cloning into bare repository 'Default_Repo.git'... 
done. 

为什么只有裸存储库用作同步工作的中央存储库?
中央存储库使用裸存储库只是因为 git 不允许您推送到非裸存储库,因为工作树将变得不一致
要演示为什么不能推送到非裸存储库:

>cd C:/Users/example/repositories 
>mkdir RepoTest 
>cd RepoTest 
>git init 
Initialized empty Git repository in C:/Users/example/repositories/RepoTest/.git/ 
>cd ../BareRepo 
>git push ../RepoTest 
Enumerating objects: 3, done. 
Counting objects: 100% (3/3), done. 
Delta compression using up to 4 threads 
Compressing objects: 100% (2/2), done. 
Writing objects: 100% (3/3), 293 bytes | 146.00 KiB/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: is denied, because it will make the index and work tree inconsistent 
remote: with what you pushed, and will require 'git reset --hard' to match 
remote: the work tree to HEAD. 
remote: 
remote: You can set the 'receive.denyCurrentBranch' configuration variable 
remote: to 'ignore' or 'warn' in the remote repository to allow pushing into 
remote: its current branch; however, this is not recommended unless you 
remote: arranged to update its work tree to match what you pushed in some 
remote: other way. 
remote: 
remote: To squelch this message and still keep the default behaviour, set 
remote: 'receive.denyCurrentBranch' configuration variable to 'refuse'. 
To ../RepoTest 
 ! [remote rejected] master -> master (branch is currently checked out) 
error: failed to push some refs to '../RepoTest'

但是,如果您仍然想对此固执,您可以阅读警告并转到您希望推送的非裸存储库,并将 receive.denyCurrentBranch 设置为忽略,然后推送更改。

>cd ../RepoTest 
>git config receive.denyCurrentBranch ignore 
>cd ../Default_Repo 
>git push ../RepoTest 
Enumerating objects: 3, done. 
Counting objects: 100% (3/3), done. 
Delta compression using up to 4 threads 
Compressing objects: 100% (2/2), done. 
Writing objects: 100% (3/3), 293 bytes | 146.00 KiB/s, done. 
Total 3 (delta 0), reused 0 (delta 0) 
To ../RepoTest 
 * [new branch]      master -> master 

但是,使用它会给您带来更多问题,当您继续推送到远程存储库时,您会注意到只有提交头指向不断变化(以及 .git 中的其他文件),但您的工作树将保持不变。消除索引和工作树不一致的唯一方法是使用以下命令:

>git reset –hard 

除非您想每次将更改推送到远程存储库时都这样做,否则建议使用裸存储库。
与非裸存储库相比,裸存储库需要更少的空间来存储相同的信息以及跟踪的更改。因此,它的存储消耗是最有效的。因此,只有裸存储库适合用作远程或中央存储库。