多个工作目录与Git?

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

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

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

我知道本地git克隆解决scheme(默认,这是硬链接共享对象,和 – 共享选项,它设置了一个替代的对象存储与原始的回购),但这些解决scheme只减less磁盘空间的使用,特别是在共享的情况下,似乎充满了危险。

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

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

见Junio C gitstergitster )的 提交68a2e6a 。

发行说明提到 :

替代contrib/workdir/git-new-workdir ,它不依赖于符号链接,通过使借款人和借款人相互了解,使对象和参考资料共享更安全。

参见提交799767cc9 (Git 2.5rc2)

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

创build<path>并签出<branch> 。 新的工作目录链接到当前的存储库,除了工作目录特定的文件,如HEAD,索引等,共享一切git worktree部分添加:

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

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

细节:

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

  • 链接的工作树在/path/other/test-next
  • 还会创build一个$GIT_DIR/worktrees/test-next目录(如果test-next已经被使用,则创build$GIT_DIR/worktrees/test-next1 )。

在一个链接的工作树中:

  • $GIT_DIR被设置为指向这个私人目录(例如/path/main/.git/worktrees/test-next
  • $GIT_COMMON_DIR被设置为指向主工作树的$GIT_DIR (例如/path/main/.git )。

这些设置是在位于链接工作树顶部目录的.git文件中进行的。

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


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

子模块的支持是不完整的
不build议多次签出一个超级项目。


注意:使用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 – in commit a46dcfb ,2015年10月26日)

worktree :添加“ list ”命令

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

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

还有瓷器格式选项可用。

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

  • 属性以一个空格分隔的标签和值列出。
  • 布尔属性(比如“裸”和“分离”)仅作为标签列出,只有当值为真时才存在。
  • 空行表示工作树的结束

例如:

 $ 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日),并提交NguyễnTháiNgọcDuy ( pclouds )的d4cddd6 (2016年1月18日) 。
帮助: 埃里克阳光( 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 ”function时,“ git branch -d ”允许删除在另一个工作树中检出的分支。

见山口一木( rhenium ) 提交f292244 (2016年3月29日) 。
帮助: 埃里克阳光( sunshineco ) 。
(由Junio C gitster合并- gitster -在4fca4e3 ,2016年4月13日提交 )

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。

这是当前行为,/ 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来解决此问题。


locking机制是官方支持与git 2.10(Q3 2016)

请参阅提交080739b , 提交6d30862 , 提交58142c0 , 提交346ef53 , 提交346ef53 , 提交58142c0 , 提交346ef53 , 提交346ef53 (2016年6月13日),并提交984ad9e , 提交6835314 (2016年6月3日)由NguyễnTháiNgọcDuy( pclouds ) 。
build议: 埃里克阳光( sunshineco ) 。
(由Junio C gitster合并- gitster – in commit 2c608e0 ,2016年7月28日)

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

如果链接的工作树存储在便携式设备或networking共享上,而这些共享并不总是挂载,那么可以通过发出git worktree lock命令来防止其pipe理文件被修剪,可以指定 – 解释为什么工作树被locking。

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


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

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

所以git worktree add' --lock git worktree lock git worktree add ,但没有竞争条件git worktree lock相当于。

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

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

其中project-dir是包含.git存储库的目录的名称。 这个脚本创build另一个`.git'目录,除了不能被共享的文件(比如当前分支)之外,还有许多与原始文件相符的符号链接,允许你在两个不同的分支中工作。

这听起来有点脆弱,但它是一个选项。

我遇到了这个问题希望find一个解决scheme,我没有在这里find。 所以现在我确实find了我需要的东西,所以我决定把它发布给其他人。

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

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

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

  2. 事实上你可以在命令行中用git选项指定你正在使用的repo的位置(你的.git目录的位置)– git --git-dir=

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

  4. 什么是“镜子回购”?

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

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

 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选项,就可以签出任何工作树的标签或分支。 )

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

我能想到的唯一的解决scheme是克隆两个目录,并将它们添加为彼此的远程存储库。 然后,您可以不断将东西从已更改的东西拖到另一个中,而无需将任何东西推送到远程存储库。

我假设你想有两个工作目录,而不是两个克隆的远程,因为你不想把一些分支到远程。 否则,你的遥控器的两个克隆将工作得很好 – 你只需要做一些推动和保持所有三个同步。