使用`git init`总是在同一目录中创建具有相同名称repo的'git nude repo'

时间:2019-12-25 16:42:05

标签: git

始终使用git init在相同目录(无论我在哪里使用git init都在同一个目录中创建具有相同名称repo的'git nude repo',将其称为'A')

如果删除了仓库'A',然后再次执行git init,(删除的)仓库A 将在同一目录中再次创建(如上所述)。如果我第二次执行“ git init”,则会收到以下错误,好像我的当前文件夹中包含repo A的.git。

Reinitialized existing Git repository in path/to/repo/A

创建存储库“ A”时,它将处于未出生或未绑定状态,这意味着没有分支,将在第一次提交时创建分支。

此外,git日志,git状态,有关gits状态的所有内容都属于此存储库“ A”。

我可以使用git clone,但是git status,log,commit仍然会显示,就好像它位于repo'A'git目录中一样。

git pull,push,commit属于仓库'A'git目录

由于遇到此问题,我暂时停止在本地计算机上使用git了,但是现在我需要使用它,别无选择。

我尝试重新安装git。没有帮助。

我很难调查这个问题,因为我不太了解git init在内部如何工作。

我在这里的问题如下

  1. git init如何在内部工作?在哪种情况下可能会发生我的问题?
  2. 如何解决此问题?通过修复我的意思,我只想使用git init,即使用它的方式。

编辑:

我不知道为什么要放在前面。我修好了它。谢谢你指出这一点,它只是语法。问题的细节仍然是正确的。

1 个答案:

答案 0 :(得分:3)

基于最新编辑进行更新

我想我明白这里出了什么问题。您已经在某种环境中设置了GIT_DIR。我不知道到底是怎么做到的,但是您需要停止这样做。检查您的.bashrc和/或.profile文件;登录时检查在环境中可能设置GIT_DIR的所有系统配置文件。如果使用POSIX Shell,请测试$GIT_DIR的当前值:

$ pwd
/tmp/tmprepo1
$ echo $GIT_DIR
/tmp/tmprepo2

使用unset命令将其取消设置:

$ unset GIT_DIR
$ echo $GIT_DIR

$ git init
Initialized empty Git repository in /tmp/tmprepo1/.git/

(这些命令是在下面的复制器上设置后运行的。)

这是重现问题的一种方法:

$ cd /tmp
$ rm -rf tmprepo2                # make sure there is no /tmp/tmprepo2
$ mkdir tmprepo1                 # now make /tmp/tmprepo1...
$ cd tmprepo1                    # ...and enter it
$ GIT_DIR=/tmp/tmprepo2 git init
Initialized empty Git repository in /tmp/tmprepo2/
$ ls -A
$ ls -AF /tmp/tmprepo2
branches/       description     hooks/          objects/
config          HEAD            info/           refs/

请注意,Git创建了/tmp/tmprepo2/.git,而不是/tmp/tmprepo1/.git

为什么Git做这个奇怪的事情?

请注意,我不仅运行git init。我跑了GIT_DIR=/tmp/tmprepo2 git init。我也可以运行git --git-dir=/tmp/tmprepo2 init关键是我明确地告诉Git,它不应该使用我的 current 目录。在这里,我使用命令行标志进行此操作-{{1 }}或环境变量 --git=dir=/tmp/tmprepo2,方法是在命令前设置$GIT_DIR(使用POSIX Shell语法)。

我怀疑您没有输入GIT_DIR=...。但是,如果我更早地 export 将该变量设置为空,则发生同样的事情:

GIT_DIR=path git init

,然后在以后的任何时间运行:

$ export GIT_DIR=/tmp/tmprepo2

您已经在环境中设置了$ git init Reinitialized existing Git repository in /tmp/tmprepo2/


原始(长)响应

首先,让我们注意GIT_DIR有两个工作:

  • 创建一个新的存储库,或
  • 验证有关现有存储库的一些信息,并从任何更新的系统模板中更新任何模板(示例)挂钩。

第二项工作很少有用,但是git init的意思是:

git init

这意味着您实际上在该(完整)路径中具有一个Git存储库。 这不是错误。这只是大多数人从未真正使用过的请求。

接下来,让我们区分Reinitialized existing Git repository in path/to/repo/A git init --bare。因为有两份工作,所以这有点棘手。但是有一个相对简单的区别:

  • 常规(非裸露)存储库是具有工作树的存储库。工作树,也称为工作树或工作树或任何数量的相似名称,是您可以查看和使用文件的地方。常规存储库由以下几部分组成:

    • 您刚才提到的工作树。
    • Git的 index 。索引有些复杂,但是一个很好的简短描述是索引是您构建 next 提交的地方。
    • 正确的存储库。它主要由几个数据库组成。稍后我们会看到更多。
  • 存储库是没有工作树的存储库。没有工作树,则无法在此存储库中进行任何工作。您仍然可以做一些事情,但是这种存储库的真正意义是要驻留在服务器上,例如GitHub或GitLab或BitBucket之类的托管服务器,没有人 会做任何工作直接。

    (出于历史和兼容性的原因,裸存储库仍具有索引。如上所述,该索引的目的主要是构建 next 提交,并帮助跟踪文件在您的工作树中,并且没有工作树,在裸存储库中的索引并不是特别有用。但是它仍然有它。)

建立一个非裸仓库

让我们开始创建一个新的空目录git init并进入该目录。 (我在类似于bash的POSIX shell中,在类似Unix / Linux的系统上进行所有操作。)

/tmp/tmprepo

如果我现在没有运行$ cd /tmp $ mkdir tmprepo $ cd tmprepo $ pwd /tmp/tmprepo git init,则Git会说:

--bare

随便看看,似乎什么都没发生,但是如果我仔细观察,告诉我的系统也显示隐藏文件(点文件),我会看到:

$ git init
Initialized empty Git repository in /tmp/tmprepo/.git/

Git已创建一个$ ls -AF .git/ 目录,正如其在输出中所示。这是一个常规的(即非裸露的)存储库。如果我再次运行.git,但没有运行git init,则会显示:

--bare

确实是这样做的:在不触摸$ git init Reinitialized existing Git repository in /tmp/tmprepo/.git/ 中的任何重要文件的情况下,它确保从我当前的Git安装中更新了所有 template 钩子文件。由于我没有更改Git的版本,因此没有此类更新。换句话说,这根本没有做任何事情。

如果愿意,我们可以窥视这个/tmp/tmprepo/.git/目录,以查看常规(非裸露)存储库包含的内容:

.git

这是此常规存储库的存储库部分。请注意,存在一个名为$ ls -F .git branches/ description hooks/ objects/ config HEAD info/ refs/ 的文件,另一个名为config的文件以及名为HEADinfo/hooks/和{{1} }。通常,您不会直接与所有这些事物进行交互,但是,由于这些文件和目录的存在,可以轻松识别内部Git目录。

目录objects/本身是此存储库的工作树。这意味着我们可以随意创建,编辑和销毁任何我们喜欢的文件,只要我们不动手即可存放实际存储库的refs/目录即可。

建立一个裸仓库

但是,如果我现在运行/tmp/tmprepo/,则会发生这种情况:

.git

由于这里没有说已重新初始化,因此确实创建了一个新的空Git存储库。让我们看一下,使用git init --bare$ git init --bare Initialized empty Git repository in /tmp/tmprepo/ 选项,以确保我们真正看到了所有文件,包括现有的-a文件:

-A

此处的.git(目录)是较早的$ ls -AF .git/ config HEAD info/ refs/ branches/ description hooks/ objects/ 留下的。此.git创建了一个 bare 存储库,其路径名为git init。也就是说,它将现有的git init --bare目录放入/tmp/tmprepo目录中的所有相同种文件。因此,我们现在有两个存储库。

如果您以其他顺序执行此操作怎么办?

只需检查一下,我们就删除这两个存储库(两个存储库中都没有任何有价值的东西):

/tmp/tmprepo

到目前为止,这看起来是一样的。我们在.git目录中创建了一个新的空存储库。没有$ cd /tmp $ rm -rf tmprepo $ mkdir tmprepo $ cd tmprepo $ git init --bare Initialized empty Git repository in /tmp/tmprepo/ $ ls -A branches description hooks objects config HEAD info refs ,因为上次是非裸存储库的/tmp/tmprepo目录。现在:

.git

这没有说已重新初始化,因此它再次创建了一个新的非裸存储库。

结论

很可能在同一个目录中同时包含一个 non-bare 存储库。这不是一个好情况,因为在这种情况下,应该使用哪个存储库不再是显而易见的。

我们可以使用tmp/tmprepo/.git/测试Git的实际功能。 rev-parse命令现在有 lot 个选项,包括$ git init Initialized empty Git repository in /tmp/tmprepo/.git/ 。在这个git rev-parse(本身是git rev-parse --is-inside-work-tree中的裸仓库和/tmp/tmprepo中的非裸仓库以及/tmp/tmprepo中的工作树)中,我们发现:

/tmp/tmprepo/.git

如果我们删除此设置的非裸仓库部分,然后重试,则会发现:

/tmp/tmprepo

我们现在只能使用 bare 仓库,因此我们不在工作树中,因为裸仓库没有工作树。

同时删除两者:

$ git rev-parse --is-inside-work-tree
true

让我们重新开始。

您的具体问题

  

创建存储库“ A”时,它将处于未出生或未绑定状态,这意味着没有分支,将在第一次提交时创建分支。

存储库本身将没有任何提交。一个新的空存储库没有提交。

任何Git存储库中的分支名称均指一(1)个现有提交。由于新的空存储库没有提交,因此分支名称将不存在。

尽管如此,Git仍然声称您在某个分支上。这就是所谓的未出生分支

  

git init如何在内部工作?在哪种情况下会发生我的问题?

目前为止您还不清楚,您的实际问题是什么。

  

如何解决此问题?通过修复我的意思,我只想使用git init,即使用它的方式。

您可能想运行一次$ rm -rf .git $ git rev-parse --is-inside-work-tree false 没有 $ cd .. $ rm -rf tmprepo ,在已经是某些树的顶层目录中创建git init目录准备成为或将成为您的工作树。如果此目录中有一些现有文件,则可以。

运行--bare后,您现在将拥有一个.git目录。 git init命令应该可以工作,并且应该告诉您尚无提交。

您现在可以.git希望在第一次提交中的每个文件。进行一次仅包含git status文件和/或其他描述性元素(例如git add文件)的第一次提交是一个不错的主意,但是您README保留了哪些文件给你。使用LICENSE将每个添加的文件复制到Git的索引中(我们在上面已经提到过);索引中的文件将是第一次提交的文件。然后运行git add对当前索引中的内容进行快照。此新快照将是存储库中的第一个(并且现在是)提交。

第一次提交后,初始分支名称(通常为git add)将存在。索引将继续包含已提交文件的副本(实际上是对已提交文件的引用)。添加更多文件,和/或更改工作树文件和git commit任何现有文件,以覆盖更新版本的索引副本,然后再次master创建新快照。新的快照-存储库中的 second 提交-将包含索引中所有文件的冻结副本,以及指向第一个提交的链接。 Git将更新您当前的分支名称git add,以记住新提交的原始哈希ID。