Git 2.5从2015年7月开始提议替换contrib/workdir/ Git -new-workdir: Git工作树
参见june C Hamano (gitster)提交68a2e6a。
发布说明中提到:
代替contrib/workdir/git-new-workdir,它不依赖于符号链接,通过使借方和借方相互意识到对方,使对象和引用的共享更加安全。
参见commit 799767cc9 (Git 2.5rc2)
这意味着你现在可以做一个git工作树添加<path> [<branch>]
Create <path> and checkout <branch> into it. The new working directory
is linked to the current repository, sharing everything except working
directory specific files such as HEAD, index, etc.
The git worktree section adds:
A git repository can support multiple working trees, allowing you to check out more than one branch at a time.
With git worktree add, a new working tree is associated with the repository.
This new working tree is called a "linked working tree" as opposed to the "main working tree" prepared by "git init" or "git clone".
A repository has one main working tree (if it's not a bare repository) and zero or more linked working trees.
细节:
Each linked working tree has a private sub-directory in the repository's
$GIT_DIR/worktrees directory.
The private sub-directory's name is usually the base name of the linked working tree's path, possibly appended with a number to make it unique.
For example, when $GIT_DIR=/path/main/.git the command git worktree add /path/other/test-next next creates:
the linked working tree in /path/other/test-next and
also creates a $GIT_DIR/worktrees/test-next directory (or $GIT_DIR/worktrees/test-next1 if test-next is already taken).
Within a linked working tree:
$GIT_DIR is set to point to this private directory (e.g. /path/main/.git/worktrees/test-next in the example) and
$GIT_COMMON_DIR is set to point back to the main working tree's $GIT_DIR (e.g. /path/main/.git).
These settings are made in a .git file located at the top directory of the linked working tree.
When you are done with a linked working tree you can simply delete it.
The working tree's administrative files in the repository will eventually be removed automatically (see gc.pruneworktreesexpire in git config), or you can run git worktree prune in the main or any linked working tree to
clean up any stale administrative files.
警告:仍然有一个git工作树“BUGS”部分需要注意。
对子模块的支持不完整。
不建议对一个超级工程进行多次签出。
Note: with git 2.7rc1 (Nov 2015) you are able to list your worktrees.
See 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, commit 1ceb7f9 (08 Oct 2015), commit 1ceb7f9 (08 Oct 2015), and commit ac6c561 (02 Oct 2015) by Michael Rappazzo (rappazzo).
(Merged by Junio C Hamano -- gitster -- in commit a46dcfb, 26 Oct 2015)
工作树:添加“list”命令
'git worktree list' iterates through the worktree list, and outputs
details of the worktree including the path to the worktree, the currently
checked out revision and branch, and if the work tree is bare.
$ git worktree list
/path/to/bare-source (bare)
/path/to/linked-worktree abcd1234 [master]
/path/to/other-linked-worktree 1234abc (detached HEAD)
There is also porcelain format option available.
The porcelain format has a line per attribute.
Attributes are listed with a label and value separated by a single space.
Boolean attributes (like 'bare' and 'detached') are listed as a label only, and are only present if and only if the value is true.
An empty line indicates the end of a worktree
例如:
$ 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
注意:如果MOVE一个工作树文件夹,需要手动更新gitdir文件。
参见nguyThái ngibmc Duy (pclouds)的commit 618244e(2016年1月22日)和commit d4cddd6(2016年1月18日)。
帮助:Eric Sunshine (sunshineco)。
(由Junio C Hamano—gitster—在commit d0a1cbc中合并,2016年2月10日)
git 2.8(2016年3月)中的新文档将包括:
如果你移动一个链接的工作树,你需要更新“gitdir”文件
在条目的目录中。
例如,如果一个链接的工作树被移动到/newpath/test-next,它的.git文件指向/path/main/。Git /worktrees/test-next,然后更新
/ /主/路径。Git /worktrees/test-next/gitdir改为引用/newpath/test-next。
在删除分支时要小心:在git 2.9(2016年6月)之前,你可以在另一个工作树中删除一个正在使用的分支。
当使用“git工作树”特性时,允许使用“git branch -d”
删除在另一个工作树中签出的分支。
参见Kazuki Yamaguchi(铼)的commit f292244(2016年3月29日)。
帮助:Eric Sunshine (sunshineco)。
(由Junio C Hamano—gitster—在commit 4fca4e3中合并,2016年4月13日)
分支-d:拒绝删除当前签出的分支
当当前工作树签出分支时,删除
禁止分支。
但是,当分支只被其他工作树签出时,错误地删除成功。
使用find_shared_symref()检查分支是否正在使用,而不仅仅是
与当前工作树的HEAD进行比较。
类似地,在git 2.9(2016年6月)之前,重命名另一个工作树中签出的分支并不会调整该工作树中的符号HEAD。
参见Kazuki Yamaguchi(铼)提交18eb3a9(2016年4月8日)和提交70999e9,提交2233066(2016年3月27日)。
(由Junio C Hamano—gitster—在commit 741a694中合并,2016年4月18日)
branch -m:更新每个工作树的head
When renaming a branch, currently only the HEAD of current working tree
is updated, but it must update HEADs of all working trees which point at
the old branch.
This is the current behavior, /path/to/wt's HEAD is not updated:
% 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]
This patch fixes this issue by updating all relevant worktree HEADs
when renaming a branch.
git 2.10正式支持锁定机制(2016年第三季度)
参见nguyn Thái ngeconc Duy (pclouds)的commit 080739b、commit 6d30862、commit 58142c0、commit 346ef53、commit 346ef53、commit 58142c0、commit 346ef53、commit 346ef53(2016年6月13日)和commit 984ad9e、commit 6835314(2016年6月03日)。
建议:Eric Sunshine (sunshineco)。
(由Junio C Hamano—gitster—在提交2c608e0中合并,2016年7月28日)
git worktree lock [--reason <string>] <worktree>
git worktree unlock <worktree>
If a linked working tree is stored on a portable device or network share
which is not always mounted, you can prevent its administrative files from
being pruned by issuing the git worktree lock command, optionally
specifying --reason to explain why the working tree is locked.
<worktree>: If the last path components in the working tree's path is unique among working trees, it can be used to identify worktrees.
For example if you only have to working trees at "/abc/def/ghi" and "/abc/def/ggg", then "ghi" or "def/ghi" is enough to point to the former working tree.
Git 2.13 (2017 Q2)在提交507e6e9(2017年4月12日)中添加了一个锁定选项。
建议:David Taylor (dt)。
帮助:Jeff King (peff)。
(由Junio C Hamano—gitster—在commit e311597中合并,2017年4月26日)
允许在创建工作树后立即锁定它。
这有助于防止“git工作树添加;Git工作树锁”和
“git工作树修剪”。
所以git worktree add'——lock是等价于git worktree add后的git worktree lock,但是没有竞态条件。
Git 2.17+(2018年第二季度)增加了Git工作树移动/ Git工作树移除:参见这个答案。
Git 2.19(2018年Q3)增加了一个“——quiet”选项,以减少“Git工作树添加”
详细的。
参见Elia Pinto (devzero2000)提交的371979c(2018年8月15日)。
协助:Martin Ågren martin.agren@gmail.com, Duy Nguyen (pclouds)和Eric Sunshine (sunshineco)。
(由Junio C Hamano—gitster—在commit a988ce9中合并,2018年8月27日)
工作树:添加——静音选项
将“——quiet”选项添加到git工作树中,就像其他git命令一样。
'add'是唯一受它影响的命令,因为所有其他命令,除了'list',目前默认是沉默的。
注意,“git工作树添加”用来做一个“查找可用的名称与stat
然后是mkdir",这是有竞争倾向的。
Git 2.22(2019年第二季度)通过使用mkdir并在循环中对EEXIST进行响应来修复这一问题。
参见Michal Suchanek (hramrach)的commit 7af01f2(2019年2月20日)。
(由Junio C Hamano - gitster -在commit 20fe798, 2019年4月9日合并)
工作树:修复工作树添加种族
Git运行一个统计循环来查找可用的工作树名称和
然后在找到的名称上执行mkdir。
将其转换为mkdir循环,以避免再次调用worktree add查找相同的空闲名称并首先创建目录。
Git 2.22 (Q2 2019)修复了判断Git存储库是否有工作树的逻辑,保护“Git branch -D”不删除当前选中的分支
不小心出来了。
对于具有不寻常名称的存储库,这种逻辑的实现被破坏了,不幸的是,这是目前子模块的规范。
参见Jonathan Tan (jhowtan)提交f3534c9(2019年4月19日)。
(由Junio C Hamano—gitster—在commit ec2642a中合并,2019年5月8日)
工作树:update is_bare启发式
When "git branch -D <name>" is run, Git usually first checks if that
branch is currently checked out.
But this check is not performed if the Git directory of that repository is not at "<repo>/.git", which is the case if that repository is a submodule that has its Git directory stored as "super/.git/modules/<repo>", for example.
This results in the branch being deleted even though it is checked out.
This is because get_main_worktree() in worktree.c sets is_bare on a
worktree only using the heuristic that a repo is bare if the worktree's
path does not end in "/.git", and not bare otherwise.
This is_bare code was introduced in 92718b7 ("worktree: add details to the worktree struct", 2015-10-08, Git v2.7.0-rc0), following a pre-core.bare heuristic.
This patch does 2 things:
Teach get_main_worktree() to use is_bare_repository() instead, introduced in 7d1864c ("Introduce is_bare_repository() and core.bare configuration variable", 2007-01-07, Git v1.5.0-rc1) and updated in e90fdc3 ("Clean up work-tree handling", 2007-08-01, Git v1.5.3-rc4).
This solves the "git branch -D <name>" problem described above.
However...
If a repository has core.bare=1 but the "git" command is being run from one of its secondary worktrees, is_bare_repository() returns false (which is fine, since there is a worktree available).
And, treating the main worktree as non-bare when it is bare causes issues: for example, failure to delete a branch from a secondary worktree that is referred to by a main worktree's HEAD, even if that main worktree is bare.
In order to avoid that, also check core.bare when setting is_bare.
If core.bare=1, trust it, and otherwise, use is_bare_repository().
在Git 2.29 (Q4 2020)中,“工作树”API提供了更好的工作树路径确定。
参见Eric Sunshine (sunshineco)的commit 918d8ff, commit 1c4854e, commit 246756f, commit 62573a5(2020年7月31日)。
(由Junio C Hamano - gitster -在commit 197253e中合并,2020年8月10日)
工作树:删除虚假和不必要的路径修改
署名:Eric Sunshine
The content of .git/worktrees/<id>/gitdir must be a path of the form "/path/to/worktree/.git".
Any other content would be indicative of a corrupt "gitdir" file.
To determine the path of the worktree itself one merely strips the "/.git" suffix, and this is indeed how the worktree path was determined from inception.
However, 5193490442 ("worktree: add a function to get worktree details", 2015-10-08, Git v2.7.0-rc0 -- merge listed in batch #7) extended the path manipulation in a mysterious way.
If it is unable to strip "/.git" from the path, then it instead reports the current working directory as the linked worktree's path:
if (!strbuf_strip_suffix(&worktree_path, "/.git")) {
strbuf_reset(&worktree_path);
strbuf_add_absolute_path(&worktree_path, ".");
strbuf_strip_suffix(&worktree_path, "/.");
}
This logic is clearly bogus; it can never be generally correct behavior. It materialized out of thin air in 5193490442 with neither explanation nor tests to illustrate a case in which it would be desirable.
It's possible that this logic was introduced to somehow deal with a corrupt "gitdir" file, so that it returns some sort of meaningful value, but returning the current working directory is not helpful. In fact, it is quite misleading (except in the one specific case when the current directory is the worktree whose "gitdir" entry is corrupt).
Moreover, reporting the corrupt value to the user, rather than fibbing about it and hiding it outright, is more helpful since it may aid in diagnosing the problem.
Therefore, drop this bogus path munging and restore the logic to the original behavior of merely stripping "/.git".