我可以将.git文件夹存储在要跟踪的文件之外吗?


147

我有一个不寻常的想法来使用git作为备份系统。假设我有一个目录./backup/myfiles,我想使用git对其进行备份。为了保持干净,我不想在myfiles文件夹中有一个.git目录,所以我想我可以创建./backup/git_repos/myfiles。通过查看git文档,我尝试这样做:

$ cd backup/myfiles
$ mkdir ../git_repos/myfiles
$ git --git-dir=../git_repos/myfiles init
Initialized empty Git repository in backup/git_repos/myfiles/
$ git --git-dir="../git_repos/myfiles/" add foo
fatal: pathspec 'foo' did not match any files

您会看到我到达那里的错误消息。我究竟做错了什么?


9
除了您的备份想法外,这还可以用于将“ dotfiles”(。bashrc,.vimrc等)保留在主目录中,而将.git文件夹保留在其他位置。
菲利普(Philip)

6
最直接的答案:stackoverflow.com/a/19548676/170352(由于过时的投票而被埋没)
布兰登·

1
在你没有写访问或不想做的工作目录中的任何改变(如添加git的/等)的情况下,这个答案低于狮子座(也埋葬老upvotes)是最好的。
科比约翰

1
@Philip,除非您的dotfiles存储库还包含Git子模块。Git不支持将子模块与外部工作树结合使用。
maxschlepzig

Answers:


101
git --git-dir=../repo --work-tree=. add foo

这将实现您想要的功能,但是当您必须在使用的每个git命令中指定它时,它显然会很烂。

您可以导出GIT_WORK_TREE=.GIT_DIR=../backup,Git会在每个命令中将其拾取。但是,这仅允许您在每个shell的单个存储库中工作。

我宁愿建议将.git目录符号链接到其他地方,或从主备份目录创建指向.git目录的符号链接。


1
您无需在每个命令中指定git-dir和工作树,也无需任何符号链接就可以归档它们。看我的答案。
尼克斯2012年

一个符号链接的缺点是它存在于工作树中,如果其他进程清除了工作树,则您将失去该符号链接
Jeff

此外,如果OP不想在其工作树中使用.git子目录,为什么还要使用符号链接?
杰夫

@Jeff:需要权衡。(就他的备用情况而言,清除他的工作树可能比清除任何其他目录(例如仓库本身)对他来说不是更大的问题。)
Sz。

1
我将它与direnv一起用于笔记。我的工作树在Dropbox的文件夹中,而git文件夹在外面。这样,我可以轻松地在所有计算机上进行更改,但仍然可以检查更改内容,并且仅在重要更改发生后才提交。谢谢
Paulo Phagula

170

您只需要确保存储库知道工作树在哪里,反之亦然。

要让存储库知道工作树在哪里,请设置配置值core.worktree。为了让工作树知道它的git目录在哪里,请添加一个名为.git的文件(而不是文件夹!),并添加如下一行

gitdir: /path/to/repo.git

从git 1.7.5开始,init命令为此学习了一个额外的选项。

您可以使用以下命令初始化一个新的单独存储库

git init --separate-git-dir /path/to/repo.git

这将在单独的目录中初始化git存储库,并将.git文件添加到当前目录中,该目录是新存储库的工作目录。

在1.7.5之前的版本中,您必须使用略有不同的参数并自己添加.git文件。

要初始化单独的存储库,以下命令将工作树与存储库链接:

git --git-dir=/path/to/repo.git --work-tree=. init && echo "gitdir: /path/to/repo.git" > .git

您当前的目录将是工作树,而git将使用位于的存储库/path/to/repo.git。init命令将自动设置参数core.worktree指定的值--git-dir

您甚至可以为此添加一个别名:

[alias]
    initexternal = !"f() { git --work-tree=. --git-dir=\"$1\" init && echo \"gitdir: $1\" >> .git; }; f"

在只读工作目录上使用git版本控制

有了以上知识,您甚至可以在没有写许可权的情况下为工作目录设置git版本控制。如果您--git-dir对每个git命令使用命令,或者在存储库(而不是工作目录)中执行每个命令,则可以忽略.git文件,因此不需要在工作目录中创建任何文件。另请参阅Leos答案


7
您也可以对现有存储库执行此操作:将.git文件夹移至所需位置,添加.git文件指向它,然后就可以像往常一样继续使用该存储库
joachim

请注意,您只能从存储库的根目录发出git命令。进入子文件夹会混淆它!(无论gitdir的给定值是相对的还是绝对的,都会发生这种情况)
joachim

2
解决此问题的方法是在实际的git配置文件中指定“ core.worktree”,即在.git中指向文件夹中的一个。
joachim

2
是的,这就是我在回答的第二句话中描述的内容。配置值core.worktree当然存储在.git文件夹的配置文件中,.git文件指向该文件。
尼克斯2012年

1
我发现当我使用这些指令时,生成的存储库变成了裸存储库,并且显示了错误fatal: core.worktree and core.bare do not make sense。好像只是更改配置,所以它不是光秃秃的解决。
史蒂文·卢

62

--separate-git-dir供选择git init(和git clone)可以用来实现这个对我的版本的git的(1.7.11.3)。该选项将git信息库与工作树分开,并在工作树.git的根目录中创建一个与文件系统无关的git符号链接(以名为的文件形式)。我认为结果与尼克斯的答案相同。

git init --separate-git-dir path/to/repo.git path/to/worktree

2
+1使用命令行选项init本身看起来更清晰,更清晰
goncalopp 2014年

在Windows中,repo.git是使用其hiden属性集创建的。然后,我手动更改它。您碰巧知道这是否安全吗?
PA。

+1是git在版本1.7.5中倾斜了此命令行选项,该版本当时不可用(如果我没记错的话)。我已经更新了答案,建议使用此参数。
尼克斯,2016年

25

我发现反转niks答案中使用的--work-treeand --git-dir目录更加简单

$ cd read_only_repos
$ git --work-tree=/some/readonly/location/foo/ --git-dir=foo init
$ cd foo
$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        .file_foo
        bar
        ...

这种方法有两个优点:

  • 它消除了具有任何命令行选项或.git文件的需要。您只需要在存储库的根目录内正常运行即可。
  • 即使您不拥有文件系统,也可以使用它对文件系统进行版本控制。Git只会写入存储库位置。

我遇到的唯一警告是.gitignore,您可以编辑而不是使用文件info/exclude

然后,read_only_repos/foo即使原始文件不受版本控制,也可以将存储库用作自己存储库中的远程数据库。


好吧,这是完全相同的命令。我看到的唯一区别是您交换了--work-tree和--git-dir参数的顺序。当然,您也没有在工作目录中创建.git文件的权限,因为您没有对该文件的写权限。不过,对目录使用版本控制而不对其具有写访问权是一个很好的用例。:-)
尼克斯,2016年

3
你说对了。关键是在工作目录之外创建仓库。
狮子座

4
我喜欢这样-它允许我在与Dropbox共享的目录上使用git,而其他参与者甚至都不知道正在使用git。
昆汀·斯塔福德·弗雷泽

19

通常,将目录命名为git存储库,该目录的工作树放在不寻常的位置,扩展名为'.git',就像裸存储库一样。

mkdir ../git_repos/myfiles.git

如果您--work-tree在初始化时提供了该选项,那么它将自动设置core.worktreeconfig变量,这意味着一旦您指定了git目录,git就会知道在哪里可以找到工作树。

git --git-dir=../git_repos/myfiles.git --work-tree=. init

但是您也可以在事实之后设置此变量。

git --git-dir=../git_repos/myfiles.git config core.worktree "$(pwd)"

完成此操作后,add命令应会按预期工作。

git --git-dir=../git_repos/myfiles.git add foo

我发现如果您先将CD刻录到../git_repos/myfiles.git中,而不是进入实际的工作树中,'git add foo'就可以了,并且您无需指定--git-dir all时间。
史蒂夫·弗利

1
是的,但是我认为大多数人倾向于在工作树中工作,而不是在存储库中工作。当然,如果您使用的是分离的工作树,则可能是在做“特殊”操作,并且很可能会使用一些宏来提供帮助。
CB Bailey 2009年

6

git在仓库内使用:

cd ./backup/git_repos/myfiles
git init --bare
git config core.worktree ../myfiles
git config core.bare false

从现在开始,您可以git./backup/git_repos/myfiles目录内部使用,而无需设置任何环境变量或其他参数。


这似乎是最好的答案,但是我得到的消息warning: core.bare and core.worktree do not make sense是否意味着它没有起作用?
hazrpg

1
我仍然认为这是可行的,但是它抱怨设置工作树时光秃秃。这就是为什么我core.bare打算false以后。
To1ne

啊! 现在这更有意义。感谢那。
hazrpg

1

您可以使用以下方式创建“ nodgit”脚本(No Dot GIT):

#!/bin/sh
gits=/usr/local/gits
    x=`pwd`
    testdir() {( cd $1; pwd; )}
    while [ "$x" != "/" ]; do
      y=`echo $x|sed -e "s/\//__/g"`
      if ([ -d "$gits/$y" ]); then
        export GIT_DIR="$gits/$y"
        export GIT_WORK_TREE="$x"
        if ([ "$1" = "nodinit" ]); then
          mkdir -p "$GIT_DIR"
          git init --bare; exit $?
        elif ([ "$1" = "shell" ]); then
          bash; exit $?
        else
          exec git "$@"
        fi
      fi
      x=`testdir "$x/.."`
    done

您可以调用nodgit代替git,它将通过查找git存储库根据需要设置变量。例如,假设您在/ usr / local / gits / __ home__foo_wibbles中有一个(裸)存储库,而在/ home / foo / wibbles / one中有一个存储库,则它将找到正确的工作目录(/ home / foo / wibbles)并存储。

哦,您也可以使用“ nodgit shell”获取具有正确vars设置的shell,以便可以使用普通的旧git命令。


0

假设您的myfiles目录已经存在并且包含一些内容,那么您可以忍受这个:

cd ~/backup
git init
git add myfiles

.git目录将位于backup,而不是myfiles


尽管这可以解决我想要的问题,但是我宁愿只将myfiles文件夹存储在git下,而别无其他。
罗里

您可以git使用文件选择要跟踪的.gitignore文件。如果要添加*和添加!myfiles到该目录,将仅跟踪该目录。但是,如果您想为另一个目录创建单独的存储库,则会遇到问题...
To1ne 2011年

0

我创建的脚本看起来像

〜/ bin / git-斜杠:

#!/usr/bin/sh

export GIT_DIR=/home/Version-Control/cygwin-root.git/
export GIT_WORK_TREE=/

git --git-dir=$GIT_DIR --work-tree=$GIT_WORK_TREE "$@"

exit $?

使用--git_dir = $ GIT_DIR是多余的,但提醒我也可以在脚本之外设置环境变量。

上面的示例用于跟踪cygwin系统文件的本地更改。

可以为任何需要此脚本的大型项目制作一个这样的脚本-但是/不带/.git是我的主要用途。

如果消除了冗余,以上内容足以构成shell别名或函数。

如果我经常这样做,我将恢复工作区到存储库的映射

"Boxes, Links, and Parallel Trees: Elements of a Configuration Management System", 
in Workshop Proceedings of the Software Management Conference. 1989.

其最接近的现代替代品是Perforce映射或视图,支持部分检出以及工作空间和存储库的非托管。

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.