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

时间:2009-02-02 23:41:54

标签: git

我有一个不寻常的想法,使用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

您可以看到我到达的错误消息。我做错了什么?

10 个答案:

答案 0 :(得分:161)

您只需要确保存储库知道工作树的位置,反之亦然。

要让存储库知道工作树的位置,请设置配置值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命令上使用--git-dir或从存储库(而不是工作目录)中执行每个命令,则可以省略.git文件,因此不需要在工作目录中创建任何文件。另请参阅Leos answer

答案 1 :(得分:92)

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

这会做你想要的,但是当你必须用你曾经使用的每个git命令指定它时,显然会很糟糕。

您可以导出GIT_WORK_TREE=.GIT_DIR=../backup,Git会在每个命令中选择它们。但是,这只会让您轻松地在每个shell的单个存储库中工作。

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

答案 2 :(得分:56)

--separate-git-dir(和git init)的git clone选项可用于在我的git版本(1.7.11.3)上完成此操作。该选项将git存储库与工作树分开,并在工作树的根目录中创建与文件系统无关的git符号链接(以名为.git的文件的形式)。我认为结果与niks' answer相同。

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

答案 3 :(得分:24)

我发现撤消niks' answer:中使用的--work-tree--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用作您自己的存储库中的远程存储库,即使原始文件不受版本控制。

答案 4 :(得分:18)

通常命名一个目录,该目录是一个git存储库,其工作树位于一个带有“.git”扩展名的不寻常的地方,就像一个裸存储库。

mkdir ../git_repos/myfiles.git

如果您在初始时提供了--work-tree选项,那么这将自动设置core.worktree配置变量,这意味着一旦指定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

答案 5 :(得分:4)

在repo中使用git

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

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

答案 6 :(得分: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 repo来设置变量。比如说你在/ usr / local / gits / __ home__foo_wibbles有一个(裸)回购,你在/ home / foo / wibbles / one然后它会找到正确的工作目录(/ home / foo / wibbles)和repo

哦,你也可以使用“nodgit shell”获取一个带有正确vars的shell,这样你就可以使用普通的旧git命令了。

答案 7 :(得分:0)

假设您的myfiles目录已经存在并且有一些内容,您能否接受这个:

cd ~/backup
git init
git add myfiles

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

答案 8 :(得分:0)

我创建了类似

的脚本

〜/斌/ 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 mappings or views,支持部分结帐以及工作区和回购的非托管。

答案 9 :(得分:0)

选项 1:core.worktree

在要跟踪的路径之外初始化一个非裸仓库,并将 core.worktree 设置为要跟踪的路径。您可以使用终端命令设置此值或直接编辑存储库配置文件以添加:

worktree = <path to files to backup>

不要将存储库文件夹设为此路径的子文件夹,否则会递归。您可以尝试这个并简单地忽略存储库文件夹,但我认为 git 不会允许这种情况。

在您的情况下,您将转到 backup/git_repos/ to run the initcommand and could use the--git-dir=./myfiles` 选项以覆盖默认存储库文件夹名称。命令看起来像这样:

cd backup/git_repos 
git init --git-dir=./myfiles
git config core.worktree backup/myfiles

注意:我最近为 Windows 测试了很多 git GUI,只有 Git 扩展支持使用 core.worktree 移动主工作树。

不支持 core.worktree 的 GUI

SourceTree、Fork、Tower、GitKraken、GitHub Desktop、GitAhead、SmartGit* 和 Git-Cola。使用 core.worktree 时,您需要坚持使用终端。

* SmartGit 将此功能与选项 2 混淆,并要求提供 .git 文件。这对于 core.worktree 不是必需的。

选项 2:--separate-git-dir

使用初始化位置中的 --separate-git-dir=<path to hold repository data>. This will use the specified path to hold the repository data and create a .git` 文件在要备份的路径上初始化存储库,其中包含如下一行:

gitdir: <path to hold repository data>

对你来说,命令看起来像这样:

cd backup/myfiles
git init --separate-git-dir=backup/git_repos/myfiles/

您在 .git 中的 backup/myfiles/ 文件将包含 gitdir: backup/git_repos/myfiles/

您现在操作 git 将 .git 文件的位置视为存储库位置。