如何将裸git存储库转换为普通的(就地)存储库?


81

我有一个裸露的git存储库,但需要通过ssh(在类似于用户体验的文件管理器中)访问和浏览其内容。

我想我可以克隆它:

git clone -l <path_to_bare_repo> <new_normal_repo>

但是,我的存储库大小约为20GB,我没有足够的空间来复制它。有没有一种方法可以将裸存储库原位转换为最终的工作副本?


5
未经测试,但是如果您将裸存储库的内容放入.git目录并将bareconfig中的参数设置为false,则它的行为应类似于常规存储库,您可以在其中git checkout获取文件。
努法尔·易卜拉欣

根据你所说的“浏览内容”什么,你也许可以做到使用在裸回购想要的一切git showgit cat-file
威廉Pursell

感谢您的提示,非常有用。我需要像经验一样的更多文件管理器(已编辑问题)。
nyi 2012年

如果您的文件系统支持硬链接,并且您克隆到相同的文件系统中,则clone -l不会再占用更多磁盘空间,因为它会硬链接所有对象。但是,正如其他人指出的那样,您将需要用于结帐的空间。
尼尔·梅休2014年

1
如果您的存储库占用20GB磁盘空间,那么工作树还需要多少空间?你真的有那么多空间吗?
ADTC

Answers:


113

注意:我在一个非常简单的1提交存储库中对此进行了测试。仔细检查一下,阅读手册页,在遵循在StackOverflow上找到的建议之前,总是很高兴自己已经备份了。(您要备份,对吗?)

要将--bare存储库转换为非裸存储库:

  1. .git在存储库的顶层创建一个文件夹。
  2. 将存储库管理内容(HEAD branches config description hooks info objects refs等)移动到.git您刚刚创建的内容中。
  3. 运行git config --local --bool core.bare false以将本地git-repository转换为non-bare。
  4. (通过TamásPap的评论)在第3步之后,您将看到您位于分支master(或主分支所在的那个分支)中,所有文件都被删除,并进行了删除。那很正常 只需手动结帐master,或执行git reset --hard,就可以完成。
  5. (以解决Royi报告的问题)在部分之后 编辑.git/config文件添加行。否则将看不到和其他来源的分支。fetch = +refs/heads/*:refs/remotes/origin/*url = <...>[remote "origin"]git fetchorigin/master

这些步骤与该问题的方向相反,即“将普通库转换为裸仓库”(尤其是注意将答案转换为裸仓库),该步骤指出上述步骤(我认为是任一方向)与执行a的步骤不同git-clone。虽然不确定是否与您有关,但是您git clone在问题中提到了这一点。


2
我已经全部写完了,但是当我推送文件时它们仍然没有出现。可能是什么(我也将denyCurrentBranch切换为忽略)?
罗伊

谢谢!有一天,我上班了,发现我的主要仓库(从那里有几个工作树)在报告自己是“裸机”。其他所有工作树都很好。不知道如何结婚,但是找到了这个答案,效果很好。
davidbak

17

我有一个稍微不同的情况:

解:

  • .git目录中克隆该内容中的裸仓库:
    git clone --bare https://github.com/user/project .git
  • 将其标记为非裸仓库:
    git config --local --bool core.bare false
  • 复位指数(否则,它认为一切都已经被删除了,因为.git 裸露的回购协议不包含文件“ index”)
    git reset HEAD -- .
    ,恢复的.git/index

我已经有效地将裸仓库变成了非裸仓库,同时保留了以前的内容。我使用多年
完整脚本涉及以下步骤:

cd /path/to/current/worktree

# That creates a .git directly at the right place
git clone --bare /url/of/repo .git

# restore the link between the local repo and its upstream remote repo
git config --local --bool core.bare false
git config --local remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
git fetch origin
git branch -u origin/master master

# reset the index (not the working tree)
git reset HEAD -- .

但是,我确实确认接受的解决方案(通过ADTC添加有用的git reset步骤)更为简单。


还值得注意的是,如果裸存储库是在具有不同行尾的计算机上创建的,则即使执行了这些步骤,您仍可能会看到修改后的文件。我相信这很正常;git试图修复换行。不知道为什么。
朱诺·伍兹

因此,您基本上将GitHub仓库克隆为裸仓库,切换为非裸仓库,手动将“ non-repo”中的所有文件放入并重置索引?与仅将仓库回购为非裸仓库有何不同?无论如何,非裸克隆过程将检出所有文件。而且,如果您确实需要,可以将检出的文件替换为“非仓库”中的文件。
ADTC

@ADTC的目标是.git在最初由存档(非git)制成的工作树(您知道是您的仓库)中获得一个子文件夹。我无法签出非裸仓库,因为我在其中签出的文件夹不为空。git clone --no-checkout在子文件夹中执行非裸操作将迫使我将其上移.git一个级别。做一个简单的克隆使我可以.git在需要的地方直接创建子文件夹。您可以在此处查看脚本:github.com/VonC/compileEverything/blob/…–
VonC

“我不能签出非裸仓库,因为签出的文件夹不为空。” 您的意思是您有一个非git工作树,其中包含尚未提交的更改,并且您打算在将其转换为启用了Git的工作树之后提交?是的,我猜想,它适用于这种用例。就个人而言,我将克隆到一个空文件夹并首先比较两个文件夹(使用外部工具)。但这就是我。
ADTC

@ADTC否:我没有“非git工作树,其中包含尚未提交的更改”。我希望提交任何东西。我拥有的只是一个回购的确切的工作树:唯一缺少的就是它.git。我确实.git通过了一个裸克隆,然后将该.git文件夹转换为一个非裸文件夹,然后执行git resetgit以使git意识到工作树已经存在。这正是github.com/VonC/compileEverything/blob/…所做的。
VonC

11

为了简化和合并答案中的信息:

有三个区别使裸仓库与普通的.git文件夹不同:

  • 在配置文件中将core.bare设置为true
  • 索引文件和工作树不存在
  • 不会为“原始”遥控器生成默认的refspec

因此,您只需将裸仓库移到新文件夹的.git子文件夹中,

mkdir clone
mv bare.git clone/.git

更改core.bare:

cd clone
git config --local --bool core.bare false

添加默认来源refspec进行制作git fetchgit push选择与往常相同的默认值:

git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'

并生成索引文件和工作树:

git checkout master

我建议git checkout不要git reset生成文件,以防意外将其键入错误的位置。


9

原始张贴者的问题是没有足够的空间来简单地做事。对于那些确实有足够空间的人,答案要简单得多:

git clone foo.git foo

我要避免这种情况的原因是,当仓库变大时,git clone有时会死掉。我想对裸仓库进行rsync,然后将其转换。
Sridhar Sarnobat,

@SridharSarnobat,然后考虑执行公认的答案中描述的任务:stackoverflow.com/a/10637882/377270-我将这一行答案放在此处,以便具有足够可用空间的人可以轻松地完成操作。
sarnold

6

如果磁盘空间不足,则通过转换为常规存储库来扩展工作树将是一个问题,但是您可以浏览裸存储库的内容而无需对其进行转换。用于git cat-file -p <commit-sha>任何提交,以查看其引用的树。使用git cat-file -p <blob-sha>查看由BLOB引用的文件的内容。使用git show <sha>:pathsha为提交或树的位置时,可以在path处查看blob的内容。


1
没错,但我需要更方便地浏览它(在ssh上的文件管理器中)。因此,我需要忍受增加的磁盘空间。
nyi 2012年

1
实际上,这是一个实际问题(+1)。工作树通常会占用多达一半的磁盘空间。部分原因是git历史记录被积极压缩。
jpaugh

3

cd 进入裸仓库并做

  1. 要么:
git config core.bare false
git reset --hard
  1. 要么
git clone X.git X

(将为您提供名为X的常规git repo)


这是最简单的解决方案,我可以在2019年确认它有效(第一种方法)。
Sridhar Sarnobat,

只是我忘记了一些注意事项(适用于所有答案):首次按下设置远程URL时,您需要编辑配置文件。
Sridhar Sarnobat,

2

如果您不介意在其他工作树上工作,那么

git worktree add ../repo2
cd ..
git status # now works fine

请注意,这不是克隆。


这太好了,不确定为什么它不在列表中的
首位

0

一键部署

您可以使用hooks目录中的post-receive脚本来将存储库扩展到部署目录,而不是将裸机远程转换为标准存储库。

这是设置即按即用的好例子

为了便于参考,这是上面链接中的脚本内容示例。它将仅将从“ master”分支的推送部署到与存储库的父目录处于同一级别的名为“ deploy”的目录:

#!/usr/bin/env ruby
# post-receive

# 1. Read STDIN (Format: "from_commit to_commit branch_name")
from, to, branch = ARGF.read.split " "

# 2. Only deploy if master branch was pushed
if (branch =~ /master$/) == nil
    puts "Received branch #{branch}, not deploying."
    exit
end

# 3. Copy files to deploy directory
deploy_to_dir = File.expand_path('../deploy')
`GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master`
puts "DEPLOY: master(#{to}) copied to '#{deploy_to_dir}'"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.