【问题标题】:Can I store the .git folder outside the files I want tracked?我可以将 .git 文件夹存储在我想要跟踪的文件之外吗?
【发布时间】:2010-10-05 01:31:30
【问题描述】:

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

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

【问题讨论】:

  • 除了你的备份想法外,这也可以用来将你的“dotfiles”(.bashrc、.vimrc 等)保存在主目录中,同时将 .git 文件夹保存在其他地方。
  • 最直截了当的回答:stackoverflow.com/a/19548676/170352(因旧票而被埋葬)
  • 如果您没有写入权限或不想对工作目录进行任何更改(如添加 .git/ 等),this 下面由 Leo 回答(也由旧的赞成票)是最好的。
  • @Philip,除非您的 dotfiles 存储库还包含 Git 子模块。 Git 不支持子模块与外部工作树的结合。

标签: git


【解决方案1】:

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

cd ~/backup
git init
git add myfiles

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

【讨论】:

  • 虽然这样可以解决我想要的问题,但我宁愿只将 myfiles 文件夹存储在 git 下,别无其他。
  • 您可以使用.gitignore 文件选择您希望git 跟踪的文件。如果您将*!myfiles 添加到其中,则只会跟踪该目录。但是如果你想为另一个目录创建一个单独的 repo,你就会遇到问题......
【解决方案2】:
git --git-dir=../repo --work-tree=. add foo

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

您可以导出GIT_WORK_TREE=.GIT_DIR=../backup,Git 会在每个命令中提取它们。不过,这只会让您轻松地在每个 shell 中使用一个存储库。

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

【讨论】:

  • 您可以归档相同的内容,而无需在每个命令中指定 git-dir 和工作树,也无需任何符号链接。看我的回答。
  • 符号链接的缺点是它存在于工作树中,如果其他进程清除了工作树,那么您就丢失了符号链接
  • 此外,如果 OP 不想在他的工作树中添加一个 .git 子目录,他为什么要一个符号链接?
  • @Jeff:进行权衡。 (在他的备用案例中,清除他的工作树可能并不比清除任何其他目录(例如 repo 本身)更重要。)
  • 我将它与direnv 一起用于我的笔记。我的工作树在 Dropbox 的一个文件夹中,而我的 git 文件夹在外面的某个地方。这样,我可以轻松地在所有计算机上进行更改,但仍然能够检查更改的内容,并且仅在重大更改时才提交。谢谢
【解决方案3】:

通常将目录命名为 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)"

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

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

【讨论】:

  • 我发现如果你先 cd 到 ../git_repos/myfiles.git,而不是在真正的工作树中,'git add foo' 就可以工作,你不需要一直指定 --git-dir。
  • 确实如此,但我认为大多数人倾向于在他们的工作树中工作,而不是在他们的存储库中工作。当然,如果您使用的是分离的工作树,您可能正在做一些“特殊”的事情,并且很可能会使用一些宏来提供帮助。
【解决方案4】:

你可以用 somet like 创建一个“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 中有一个(裸)repo,并且您在 /home/foo/wibbles/one 中,那么它将找到正确的工作目录(/home/foo/wibbles)和 repo .

哦,你也可以使用“nodgit shell”来获得一个设置了正确变量的 shell,这样你就可以使用普通的旧 git 命令了。

【讨论】:

    【解决方案5】:

    在 repo 中使用git

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

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

    【讨论】:

    • 这似乎是最好的答案,但我收到了warning: core.bare and core.worktree do not make sense 的消息,这是否意味着它没有工作?
    • 我仍然认为是可行的,但它抱怨设置工作树时是裸露的。这就是为什么我之后将core.bare 设置为false
    • 啊!这现在更有意义了。谢谢你。
    【解决方案6】:

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

    要让存储库知道工作树的位置,请设置配置值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

    【讨论】:

    • 您也可以对现有仓库执行此操作:将 .git 文件夹移动到您想要的任何位置,添加 .git 文件以指向它,然后您可以继续使用仓库作为你通常会
    • 请注意,您只能从 repo 的根目录发出 git 命令。进入子文件夹会混淆它! (无论 gitdir 的给定值是相对的还是绝对的,都会发生这种情况。)
    • 解决这个问题的方法是在实际的 git 配置文件中指定 'core.worktree',即您在 .git 中指向的文件夹中的那个。
    • 是的,这就是我在回答的第二句话中所描述的。配置值core.worktree当然存放在.git文件夹的config文件中,.git文件指向的地方。
    • 我发现当我使用这些说明时,生成的 repo 变成了一个裸存储库,它给出了错误 fatal: core.worktree and core.bare do not make sense。似乎只是更改配置,所以它不是裸解决的。
    【解决方案7】:

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

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

    【讨论】:

    • +1 为init 使用命令行选项本身看起来更清晰
    • 在 windows 中,repo.git 是使用其隐藏属性集创建的。然后我手动更改它。你知道这是否安全吗?
    • +1 是的 git 在 1.7.5 版本中使用了这个命令行选项,当时不可用(如果我没记错的话)。我已更新我的答案以建议使用此参数。
    【解决方案8】:

    我发现反转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 只会写入存储库位置。

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

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

    【讨论】:

    • 嗯,这是完全相同的命令。我看到的唯一区别是您交换了 --work-tree 和 --git-dir 参数的顺序。当然,您不会在工作目录中创建 .git 文件,因为您没有对它的写入权限。尽管如此,对没有写访问权限的目录使用版本控制是一个很好的用例。 :-)
    • 你明白了。关键是在工作目录之外创建 repo。
    • 我喜欢这个 - 它允许我在与 Dropbox 共享的目录上使用 git,而其他参与者甚至不知道 git 正在使用中。
    【解决方案9】:

    我创建的脚本看起来像

    ~/bin/git-slash:

    #!/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,支持部分结帐以及非托管工作区和存储库。

    【讨论】:

      【解决方案10】:

      选项 1:core.worktree

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

      worktree = &lt;path to files to backup&gt;

      不要使存储库文件夹成为此路径的子文件夹,这将是递归的。您可以尝试这个并简单地忽略存储库文件夹,但我认为 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=&lt;path to hold repository data&gt;. This will use the specified path to hold the repository data and create a .git`文件在您要备份的路径初始化存储库,该文件包含如下行:

      gitdir: &lt;path to hold repository data&gt;

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

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

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

      您现在运行 git,将 .git 文件的位置视为存储库位置。

      【讨论】:

        猜你喜欢
        • 2019-07-13
        • 2019-02-16
        • 2010-10-25
        • 1970-01-01
        • 1970-01-01
        • 2011-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多