多个工作目录与Git?

我不确定这是Git支持的东西,但理论上它似乎应该适用于我。

我的工作流程经常涉及我同时在多个分支中编辑文件。 换句话说,我经常想在一个分支中打开几个文件,而我在另一个分支中编辑另一个文件的内容。

我的典型解决方案是做两个结账,但这是一个耻辱,我不能在他们之间分享分支和参考。 我想只有两个工作目录由相同的.git文件夹管理。

我知道本地git克隆解决方案(默认是硬链接共享对象,和 - 共享选项,它使用原始的repo设置备用对象存储),但这些解决方案仅减少磁盘空间使用,特别是在共享的情况下,似乎充满了危险。

有没有办法使用一个.git文件夹,并有两个工作目录支持它? 或者Git硬编码只是在任何时候检出一个工作目录?


Git 2.5自2015年7月起提议替换contrib/workdir/git-new-workdirgit worktree

见Junio C gitstergitster )的提交68a2e6a。

发布说明提到:

替代contrib/workdir/git-new-workdir ,它不依赖于符号链接,通过让借款人和借款人相互知道对象和分享对象和参考,从而更安全。

参见提交799767cc9(Git 2.5rc2)

这意味着你现在可以做一个git worktree add <path> [<branch>]

创建<path>并签出<branch>到其中。 新的工作目录链接到当前的存储库,共享除了工作目录特定文件(如HEAD,索引等)以外的所有内容git worktree部分添加:

一个git仓库可以支持多个工作树 ,允许你一次检出多个分支。
使用git worktree add一个新的工作树与存储库相关联。

这个新的工作树被称为“链接工作树”,而不是由“ git init ”或“ git clone ”准备的“主工作树”
存储库具有一个主工作树(如果它不是裸存储库)以及零个或多个链接的工作树。

细节:

每个链接的工作树在存储库的$GIT_DIR/worktrees目录中都有一个私有子目录。
私人子目录的名称通常是链接工作树路径的基本名称,可能附有一个数字以使其唯一。
例如,当$GIT_DIR=/path/main/.git ,命令git worktree add /path/other/test-next next创建:

  • 链接工作树在/path/other/test-next
  • 还会创建一个$GIT_DIR/worktrees/test-next目录(或者如果已经采用test-next则为$GIT_DIR/worktrees/test-next1 )。
  • 在一个链接的工作树中:

  • $GIT_DIR被设置为指向这个私有目录(例如/path/main/.git/worktrees/test-next )和
  • $GIT_COMMON_DIR被设置为指向主工作树的$GIT_DIR (例如/path/main/.git )。
  • 这些设置是在位于链接工作树顶部目录的.git文件中进行的。

    当你完成一个链接的工作树时,你可以简单地删除它。
    存储库中的工作树管理文件最终会自动删除(请参阅git config gc.pruneworktreesexpire ),或者您可以在主或任何链接的工作树中运行git worktree prune来清理任何陈旧的管理文件。


    警告:还有一个git worktree “BUGS”部分需要注意。

    子模块的支持不完整
    不建议多次签出超级项目。


    注意:使用git 2.7rc1(2015年11月),您可以列出您的工作树。
    参见提交bb9c03b,提交92718b7,提交5193490,提交1ceb7f9,提交1ceb7f9,提交5193490,提交1ceb7f9,提交1ceb7f9(2015年10月8日),提交92718b7,提交5193490,提交1ceb7f9,提交1ceb7f9(2015年10月8日),提交5193490,提交1ceb7f9(2015年10月8日),提交1ceb7f9(2015年10月8日),并提交ac6c561(2015年10月2日)作者:Michael Rappazzo( rappazzo )。
    (由Junio C gitster合并 - gitster - 于2015年10月26日提交a46dcfb)

    worktree :添加“ list ”命令

    ' git worktree list '循环遍历工作树列表,并输出工作树的详细信息,包括工作树的路径,当前检出的修订和分支,以及工作树是否裸露。

    $ git worktree list
    /path/to/bare-source            (bare)
    /path/to/linked-worktree        abcd1234 [master]
    /path/to/other-linked-worktree  1234abc  (detached HEAD)
    

    还有瓷器格式选项可用。

    瓷器格式每个属性都有一行。

  • 列出的属性具有由单个空格分隔的标签和值。
  • 布尔属性(如'bare'和'detached')仅作为标签列出,并且仅当且仅当该值为true时才存在。
  • 一条空行表示工作树的结束
  • 例如:

    $ git worktree list --porcelain
    
    worktree /path/to/bare-source
    bare
    
    worktree /path/to/linked-worktree
    HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
    branch refs/heads/master
    
    worktree /path/to/other-linked-worktree
    HEAD 1234abc1234abc1234abc1234abc1234abc1234a
    detached
    

    注意:如果您移动工作文件夹,则需要手动更新gitdir文件。

    见提交618244e(2016年1月22日),并提交d4cddd6(2016年1月18日)由阮泰玉维战( pclouds )。
    帮助:埃里克阳光( sunshineco )。
    (由Junio C gitster合并 - gitster - in commit d0a1cbc,​​2016年2月10日)

    git 2.8(2016年3月)中的新文档将包括:

    如果您移动链接的工作树,则需要更新条目目录中的' gitdir '文件。
    例如,如果链接的工作树移动到/newpath/test-next并且其.git文件指向/path/main/.git/worktrees/test-next ,则更新/path/main/.git/worktrees/test-next/gitdir来引用/newpath/test-next


    删除分支时要小心:在git 2.9(2016年6月)之前,您可以删除另一个正在使用的树。

    当“ git worktree ”功能正在使用时,“ git branch -d ”允许删除在另一个工作树中检出的分支。

    见Kazuki Yamaguchi( rhenium )提交f292244(2016年3月29日)。
    帮助:埃里克阳光( sunshineco )。
    (由Junio C gitster合并 - gitster - 于2016年4月13日提交4fca4e3)

    branch -d :拒绝删除当前检出的分支

    当一个分支被当前工作树签出时,删除该分支是被禁止的。
    但是,只有其他工作树检出分支时,删除不正确才能成功。
    使用find_shared_symref()检查分支是否正在使用,而不仅仅是与当前工作树的HEAD进行比较。


    同样,在git 2.9(2016年6月)之前,重命名在另一个工作树中检出的分支不会调整其他工作树中的符号HEAD。

    参见承诺18eb3a9(2016年4月8日),承诺70999e9,承诺2233066(2016年3月27日)Kazuki Yamaguchi( rhenium )。
    (由Junio C gitster合并 - gitster - 在承诺741a694,2016年4月18日)

    branch -m :更新所有per-worktree HEAD

    重命名分支时,当前只有当前工作树的HEAD被更新,但它必须更新指向旧分支的所有工作树的HEAD。

    这是当前行为,/ path / to / wt的HEAD未更新:

      % git worktree list
      /path/to     2c3c5f2 [master]
      /path/to/wt  2c3c5f2 [oldname]
      % git branch -m master master2
      % git worktree list
      /path/to     2c3c5f2 [master2]
      /path/to/wt  2c3c5f2 [oldname]
      % git branch -m oldname newname
      % git worktree list
      /path/to     2c3c5f2 [master2]
      /path/to/wt  0000000 [oldname]
    

    此修补程序通过在重命名分支时更新所有相关的工作头HEAD来解决此问题。


    锁定机制正式支持git 2.10(Q3 2016)

    请参阅提交080739b,提交6d30862,提交58142c0,提交346ef53,提交346ef53,提交58142c0,提交346ef53,提交346ef53(2016年6月13日),并提交NguyễnTháiNgọcDuy( pclouds )的984ad9e,提交6835314(2016年6月3日)。
    建议者:Eric Sunshine( sunshineco )。
    (由Junio C gitster合并 - gitster - 在承诺2c608e0,2016年7月28日)

    git worktree lock [--reason <string>] <worktree>
    git worktree unlock <worktree>
    

    如果链接的工作树存储在其上并不总是安装在便携式设备或网络共享,可以防止其行政文件从通过发出被修剪git worktree lock命令,可以选择指定--reason解释为什么工作树被锁定。

    <worktree> :如果工作树的路径中的最后一个路径组件在工作树中是唯一的,则它可以用于标识工作树。
    例如,如果您只需在“ /abc/def/ghi ”和“ /abc/def/ggg ”中工作树,那么“ ghi ”或“ def/ghi ”就足以指向以前的工作树。


    Git 2.13(Q2 2017)在NguyễnTháiNgọcDuy( pclouds )的提交507e6e9(2017年4月12日)中添加了一个lock选项
    建议:David Taylor( dt )。
    帮助:杰夫金( peff )。
    (由Junio C gitster合并 - gitster - 在2017年4月26日提交的e311597)

    允许在创建后立即锁定工作树。
    这有助于防止“ git worktree add; git worktree lock ”和“ git worktree prune ”之间的竞争。

    所以git worktree add' --lock git worktree lock git worktree add后的git worktree lock的等价物,但没有竞争条件。


    Git 2.17+(Q2 2018)增加了git worktree move / git worktree remove :看到这个答案。


    git发行版附带了一个名为git-new-workdir的贡献脚本。 你会使用它如下:

    git-new-workdir project-dir new-workdir branch
    

    其中project-dir是包含.git存储库的目录的名称。 这个脚本创建了另一个`.git'目录,其中包含许多符合链接的目录,除了不能共享的文件(如当前分支)外,允许您在两个不同的分支中工作。

    这听起来有点脆弱,但它是一种选择。


    我遇到了这个问题,希望能找到我在这里找不到的解决方案。 所以,现在我确实找到了我需要的东西,我决定将它发布给其他人。

    警告:如果您需要同时编辑多个分支(如OP状态),这可能不是一个好的解决方案。 这是为了同时检出多个分支,您不打算编辑。 (由一个.git文件夹支持的多个工作目录。)

    自从我第一次来到这个问题以来,我学到了一些东西:

  • 什么是“裸仓库”。 它实质上是.git目录的内容,不在工作树中。

  • 事实上,你可以在命令行中用git选项指定你正在使用的回购库的位置(你的.git目录的位置)-- git --git-dir=

  • 您可以使用--work-tree=来指定工作副本的位置

  • 什么是“镜像回购”?

  • 这最后是一个非常重要的区别。 我实际上并不想在回购协议上工作,我只需要同时签出不同分支和/或标签的副本。 实际上,我需要保证分支机构不会与我的分支机构不同。 所以一面镜子对我来说是完美的。

    所以对于我的用例,我得到了我需要做的事情:

    git clone --mirror <remoteurl> <localgitdir> # Where localgitdir doesn't exist yet
    mkdir firstcopy
    mkdir secondcopy
    git --git-dir=<localgitdir> --work-tree=firstcopy checkout -f branch1
    git --git-dir=<localgitdir> --work-tree=secondcopy checkout -f branch2
    

    关于这个的一个重要警告是,这两个副本没有单独的HEAD。 因此,在上述之后,运行git --git-dir=<localgitdir> --work-tree=firstcopy status会显示从branch2到branch1的所有不同之处,因为未提交的更改 - 因为HEAD指向branch2。 (这就是为什么我使用-f选项来checkout原因,因为我实际上并不打算在本地进行任何更改。只要使用-f选项,我就可以为任何工作树签出任何标签或分支。 )

    对于在同一台计算机上同时存在多个结帐而无需编辑它们的情况 ,此功能完美无缺。 我不知道是否有任何方法可以为多个工作树设置多个HEAD,而不需要脚本,如其他答案中所述,但我希望这对其他人有帮助。

    链接地址: http://www.djcxy.com/p/4439.html

    上一篇: Multiple working directories with Git?

    下一篇: How to download a branch with git?