使用Git的多个工作目录?

jto*_*lds 233 git

我不确定这是否是Git所支持的东西,但理论上它似乎应该对我有用.

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

我的典型解决方案是进行两次检查,但遗憾的是我不能在它们之间共享分支和引用.我想要的是只有两个工作目录由同一个.git文件夹管理.

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

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

Von*_*onC 279

Git 2.5自2015年7月开始建议更换contrib/workdir/git-new-workdir:git worktree

看看提交68a2e6a通过JUNIOÇ滨野(gitster).

发行说明中提到:

替代contrib/workdir/git-new-workdir它不依赖于符号链接,并通过使借方和借方相互了解来共享对象和更安全.

请参阅commit 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目录(或者$GIT_DIR/worktrees/test-next1如果test-next已经采用).

在链接的工作树中:

  • $GIT_DIR设置为指向此私有目录(例如/path/main/.git/worktrees/test-next在示例中)和
  • $GIT_COMMON_DIR设置为指向主工作树$GIT_DIR(例如/path/main/.git).

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

完成链接的工作树后,您只需删除它即可.
资源库中的工作树的行政文件最终会被自动删除(见gc.pruneworktreesexpiregit config),也可以运行git worktree prune在主或任何链接工作树清理任何过时的行政文件.


警告:还有一个git worktree"BUGS"部分需要注意.

对子模块的支持不完整.
建议不要对超级项目进行多次检出.


注意:使用git 2.7rc1(2015年11月),您可以列出您的工作树.
请参阅commit bb9c03b,commit 92718b7,commit 5193490,commit 1ceb7f9,commit 1ceb7f9,commit 5193490,commit 1ceb7f9,commit 1ceb7f9(08 Oct 2015),commit 92718b7,commit 5193490,commit 1ceb7f9,commit 1ceb7f9(08 Oct 2015),commit 5193490,提交1ceb7f9(2015年10月8日),提交1ceb7f9(2015年10月8日),并由Michael Rappazzo()提交ac6c561(2015年10月2日).(由Junio C Hamano合并- -承诺a46dcfb,2015年10月26日)rappazzo
gitster

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)
Run Code Online (Sandbox Code Playgroud)

还有瓷器格式可供选择.

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

  • 列出的属性标签和值由单个空格分隔.
  • 布尔属性(如'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
Run Code Online (Sandbox Code Playgroud)

注意:如果您移动了一个worktree文件夹,则需要手动更新该gitdir文件.

请参阅提交618244e(2016年1月22日),并由NguyễnTháiNgọcDuy()提交d4cddd6(2016年1月18日). 帮助:Eric Sunshine().(由Junio C Hamano合并- -提交d0a1cbc,2016年2月10日)pclouds
sunshineco
gitster

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()提交f292244(2016年3月29日). 帮助:Eric Sunshine().(由Junio C Hamano合并- -提交4fca4e3,2016年4月13日)rhenium
sunshineco
gitster

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

当前工作树检出分支时,禁止删除分支.
但是,当分支仅由其他工作树检出时,删除不正确成功.
使用find_shared_symref()来检查分支正在使用中,不仅与当前工作树的HEAD比较.


类似地,在git 2.9(2016年6月)之前,重命名在另一个工作树中检出的分支没有调整所述其他工作树中的符号HEAD.

请参阅提交18eb3a9(2016年4月8日),并由Kazuki Yamaguchi()提交70999e9,提交2233066(2016年3月27日).(由Junio C Hamano合并- -提交741a694,2016年4月18日)rhenium
gitster

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]
Run Code Online (Sandbox Code Playgroud)

此修补程序通过在重命名分支时更新所有相关的工作树HEAD来修复此问题.


锁定机制由git 2.10正式支持(2016年第3季度)

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

git worktree lock [--reason <string>] <worktree>
git worktree unlock <worktree>
Run Code Online (Sandbox Code Playgroud)

如果链接的工作树存储在并非总是挂载的便携式设备或网络共享上,则可以通过发出git worktree lock命令来阻止其管理文件被修剪,可选地指定--reason解释工作树被锁定的原因.

<worktree>:如果工作树路径中的最后一个路径组件在工作树中是唯一的,则可以使用它来识别工作树.
例如,如果您只需要在" /abc/def/ghi"和" /abc/def/ggg" 处工作树,那么" ghi"或" def/ghi"足以指向前工作树.


的git 2.13(Q2 2017)添加一个lock选项提交507e6e9由(2017年4月12日)阮泰玉维战(pclouds).
建议:大卫泰勒(dt).
帮助:杰夫金(peff).
(由Junio C gitsterHamano合并- -提交e311597,2017年4月26日)

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

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


Git 2.17 +(2018年第二季度)补充git worktree move/ git worktree remove:看到这个答案.


Git 2.19(Q8 2018)添加了一个" --quiet"选项,使" git worktree add"更简洁.

Elia Pinto()提交371979c(2018年8月15日). 帮助:MartinÅgren,Duy Nguyen()Eric Sunshine().(由Junio C Hamano合并- -提交a988ce9,2018年8月27日)devzero2000
pcloudssunshineco
gitster

worktree:添加--quiet选项

与其他命令一样,添加' --quiet'选项. ' '是唯一受其影响的命令,因为除了' ' 之外的所有其他命令默认情况下都是静默的.git worktreegit
addlist

  • 这是他们创造的最酷的东西,正是我一直在寻找的东西。感谢那! (2认同)

adl*_*adl 113

git发行版附带一个名为的贡献脚本git-new-workdir.您可以按如下方式使用它:

git-new-workdir project-dir new-workdir branch
Run Code Online (Sandbox Code Playgroud)

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

听起来有点脆弱,但这是一个选择.

  • 通常它工作得很好,但是如果你不小心在不同的位置编辑了同一个分支,那么修复这些东西并不重要. (9认同)
  • +1我纠正了,这非常棒.它似乎立即在两个不同的检出的存储库之间共享历史和分支,没有推/拉,只有符号.我完全没有意识到git可以处理这个问题.唉,它不包含在我的发行版中. (3认同)
  • 对于那些使用msysgit(windows)的人,你可以使用这个移植版本的脚本:https://github.com/joero74/git-new-workdir (2认同)

Wil*_*ard 13

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

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

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

  1. 什么是" 裸库 ".它本质上是.git目录的内容,而不是位于工作树中.

  2. 您可以.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
Run Code Online (Sandbox Code Playgroud)

关于这一点的一个重要警告是,两份副本没有单独的HEAD.因此,在上面之后,运行git --git-dir=<localgitdir> --work-tree=firstcopy status将显示从branch2到branch1的所有差异作为未提交的更改 - 因为HEAD指向branch2.(这就是我使用该-f选项的原因checkout,因为我实际上并没有计划在本地进行任何更改.只要我使用该-f选项,我就可以检查任何工作树的任何标记或分支.)

对于我在同一台计算机上共存多个签出而不需要编辑它们的用例,这非常有效.我不知道是否有任何方法可以为多个工作树提供多个HEAD而没有其他答案所涵盖的脚本,但我希望这对其他人有帮助.


归档时间:

查看次数:

79666 次

最近记录:

6 年,5 月 前