我不确定这是否受 Git 支持,但理论上它似乎应该对我有用。
我的工作流程通常涉及同时编辑多个分支中的文件。换句话说,我经常想在一个分支中打开几个文件,同时在另一个分支中编辑另一个文件的内容。
我的典型解决方案是进行两次结帐,但遗憾的是我无法在它们之间共享分支和引用。我想要的是只有两个工作目录由同一个 .git 文件夹管理。
我知道本地 git clone 解决方案(默认设置是硬链接共享对象,以及 --shared 选项,它使用原始存储库),但这些解决方案只会减少磁盘空间的使用,尤其是在 --shared
的情况下,似乎充满了危险。
有没有一种方法可以使用一个 .git 文件夹,并有两个由它支持的工作目录?或者 Git 是否被硬编码为在任何时候只检出一个工作目录?
I'm not sure if this is something supported by Git, but in theory it seems like it should work to me.
My workflow often involves my editing of files in multiple branches simultaneously. In other words, I often want to open a few files in one branch is while I edit the contents of another file in another branch.
My typical solution to this is to make two checkouts, but it's a shame I can't share branches and refs between them. What I would like is to just have two working directories managed by the same .git
folder.
I'm aware of local git clone
solutions (the default, which is to hardlink shared objects, and the --shared
option, which sets up an alternate object store with the original repo), but these solutions only cut down on disk space usage, and especially in the case of --shared
, seem fraught with peril.
Is there a way to use one .git
folder, and have two working directories backed by it? Or is Git hardcoded to have just one working directory checked out at any time?
发布评论
评论(4)
Git 2.5 自 2015 年 7 月起提议替换
contrib/workdir/git-new-workdir
:git worktree请参阅提交 68a2e6a by 朱尼奥·C·滨野(
gitster
)。发行说明提到:
请参阅 commit 799767cc9 (Git 2.5rc2)
这意味着您现在可以 执行
git 工作树添加 <路径> [<分支>]
警告:仍然存在
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 日),作者:迈克尔·拉帕佐(
拉帕佐
)。(由 Junio C Hamano --
gitster
-- 合并于 提交a46dcfb,2015 年 10 月 26 日)例如:
注意:如果您移动工作树文件夹,则需要手动更新
gitdir
文件。请参阅提交 618244e(2016 年 1 月 22 日)和提交 d4cddd6(2016 年 1 月 18 日),作者:阮泰Ngọc Duy (
pclouds
)。帮助者:Eric Sunshine (
sunshineco
)。(由 Junio C Hamano --
gitster
-- 合并于 提交d0a1cbc,2016 年 2 月 10 日)git 中的新文档 2.8(2016 年 3 月)将包括:
删除分支时要小心:在 git 2.9(2016 年 6 月)之前,您可以删除另一个工作树中正在使用的分支。
请参阅 commit f292244(2016 年 3 月 29 日),作者:山口一树(
铼
)。帮助者:Eric Sunshine (
sunshineco
)。(由 Junio C Hamano --
gitster
-- 合并于 提交4fca4e3,2016 年 4 月 13 日)同样,在 git 2.9(2016 年 6 月)之前,重命名在另一个工作树中检出的分支不会调整所述另一个工作树中的符号 HEAD。
请参阅提交 18eb3a9(2016 年 4 月 8 日)和提交 70999e9, 提交 2233066(2016 年 3 月 27 日),作者:山口一树(
铼
)。(由 Junio C Hamano --
gitster
-- 合并于 提交741a694,2016 年 4 月 18 日)git 2.10(2016 年第 3 季度)正式支持锁定机制,
请参阅 commit 080739b、提交 6d30862, 提交 58142c0, 提交 346ef53, 提交 346ef53, 提交 58142c0, 提交 346ef53, 提交 346ef53(2016 年 6 月 13 日),以及 提交 984ad9e, 提交 6835314(2016 年 6 月 3 日),作者:阮Thái Ngọc Duy (
pclouds
)。建议者:Eric Sunshine (
sunshineco
)。(由 Junio C Hamano --
gitster
-- 合并于 提交2c608e0,2016 年 7 月 28 日)Git 2.13(2017 年第 2 季度)在 提交 507e6e9(4 月 12 日2017),作者:Nguyễn Thái Ngọc Duy (
pclouds
)。建议者:David Taylor (
dt
)。帮助者:Jeff King (
peff
)。(由 Junio C Hamano --
gitster
-- 合并于 提交e311597,2017 年 4 月 26 日)因此,
git worktree add' --lock
相当于git worktree add
之后的git worktree lock
,但没有竞争条件。Git 2.17+(2018 年第 2 季度)添加了
git worktree move
/git worktree remove
:请参阅此答案。Git 2.19(2018 年第 3 季度)添加“
--quiet
”选项以减少“git worktree add
”冗长。
请参阅 提交 371979c(2018 年 8 月 15 日),作者:埃利亚·平托(
devzero2000
)。帮助者:Martin Ågren [电子邮件受保护],Duy Nguyen (
pclouds
) 和 Eric Sunshine (sunshineco
).(由 Junio C Hamano --
gitster
-- 合并于 提交a988ce9,2018 年 8 月 27 日)请注意,“
git worktree add
”用于执行“使用 stat 查找可用名称”然后是
mkdir
”,这很容易出现竞争。Git 2.22(2019 年第 2 季度)已通过使用
mkdir
并在循环中响应EEXIST
修复了此问题。请参阅 提交 7af01f2(2019 年 2 月 20 日),作者:米哈尔·苏哈内克(
hramrach
)。(由 Junio C Hamano --
gitster
-- 合并于 提交20fe798,2019 年 4 月 9 日)Git 2.22(2019 年第 2 季度)修复了判断 Git 存储库是否具有工作树的逻辑,以保护“
gitbranch-D
”不删除当前检查的分支错误地退出。
对于具有不寻常名称的存储库,此逻辑的实现被破坏,不幸的是,这已成为当今子模块的常态。
请参阅 提交 f3534c9(2019 年 4 月 19 日),作者:乔纳森·谭(
jhowtan
)。(由 Junio C Hamano --
gitster
-- 合并于 提交ec2642a,2019 年 5 月 8 日)在 Git 2.29(2020 年第 4 季度)中,“
worktree
”API 可以更好地确定工作树路径。请参阅提交918d8ff,提交 1c4854e, 提交 246756f, 提交 62573a5(2020 年 7 月 31 日),作者:埃里克·阳光(
sunshineco
)。(由 Junio C Hamano --
gitster
-- 合并于 提交197253e,2020 年 8 月 10 日)Git 2.5 proposes since July 2015 a replacement for
contrib/workdir/git-new-workdir
: git worktreeSee commit 68a2e6a by Junio C Hamano (
gitster
).The release note mentions:
See commit 799767cc9 (Git 2.5rc2)
That means you now can do a
git worktree add <path> [<branch>]
Warning: there is still a
git worktree
"BUGS" section to be aware of.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)For instance:
Note: if you MOVE a worktree folder, you need to manually update the
gitdir
file.See commit 618244e (22 Jan 2016), and commit d4cddd6 (18 Jan 2016) by Nguyễn Thái Ngọc Duy (
pclouds
).Helped-by: Eric Sunshine (
sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit d0a1cbc, 10 Feb 2016)The new doc in git 2.8 (March 2016) will include:
Be careful when deleting a branch: before git 2.9 (June 2016), you could delete one in use in another working tree.
See commit f292244 (29 Mar 2016) by Kazuki Yamaguchi (
rhenium
).Helped-by: Eric Sunshine (
sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit 4fca4e3, 13 Apr 2016)Similarly, before git 2.9 (June 2016), renaming a branch checked out in another worktree did not adjust the symbolic HEAD in said other worktree.
See commit 18eb3a9 (08 Apr 2016), and commit 70999e9, commit 2233066 (27 Mar 2016) by Kazuki Yamaguchi (
rhenium
).(Merged by Junio C Hamano --
gitster
-- in commit 741a694, 18 Apr 2016)The locking mechanism is officially supported with git 2.10 (Q3 2016)
See commit 080739b, commit 6d30862, commit 58142c0, commit 346ef53, commit 346ef53, commit 58142c0, commit 346ef53, commit 346ef53 (13 Jun 2016), and commit 984ad9e, commit 6835314 (03 Jun 2016) by Nguyễn Thái Ngọc Duy (
pclouds
).Suggested-by: Eric Sunshine (
sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit 2c608e0, 28 Jul 2016)Git 2.13 (Q2 2017) add a
lock
option in commit 507e6e9 (12 Apr 2017) by Nguyễn Thái Ngọc Duy (pclouds
).Suggested-by: David Taylor (
dt
).Helped-by: Jeff King (
peff
).(Merged by Junio C Hamano --
gitster
-- in commit e311597, 26 Apr 2017)So
git worktree add' --lock
is the equivalent ofgit worktree lock
aftergit worktree add
, but without race condition.Git 2.17+ (Q2 2018) adds
git worktree move
/git worktree remove
: see this answer.Git 2.19 (Q3 2018) add a "
--quiet
" option to make "git worktree add
" lessverbose.
See commit 371979c (15 Aug 2018) by Elia Pinto (
devzero2000
).Helped-by: Martin Ågren [email protected], Duy Nguyen (
pclouds
), and Eric Sunshine (sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit a988ce9, 27 Aug 2018)Note that "
git worktree add
" used to do a "find an available name with statand then
mkdir
", which is race-prone.This has been fixed with Git 2.22 (Q2 2019) by using
mkdir
and reacting toEEXIST
in a loop.See commit 7af01f2 (20 Feb 2019) by Michal Suchanek (
hramrach
).(Merged by Junio C Hamano --
gitster
-- in commit 20fe798, 09 Apr 2019)Git 2.22 (Q2 2019) fixes the logic to tell if a Git repository has a working tree protects "
git branch -D
" from removing the branch that is currently checkedout by mistake.
The implementation of this logic was broken for repositories with unusual name, which unfortunately is the norm for submodules these days.
See commit f3534c9 (19 Apr 2019) by Jonathan Tan (
jhowtan
).(Merged by Junio C Hamano --
gitster
-- in commit ec2642a, 08 May 2019)With Git 2.29 (Q4 2020), the "
worktree
" API offers a better determination of a worktree path.See commit 918d8ff, commit 1c4854e, commit 246756f, commit 62573a5 (31 Jul 2020) by Eric Sunshine (
sunshineco
).(Merged by Junio C Hamano --
gitster
-- in commit 197253e, 10 Aug 2020)git
发行版附带 名为 git-new-workdir 的贡献脚本。您可以按如下方式使用它:
其中 project-dir 是包含
.git
存储库的目录的名称。此脚本创建另一个 .git 目录,其中包含许多指向原始目录的符号链接,但无法共享的文件(如当前分支)除外,允许您在两个不同的分支中工作。
听起来有点脆弱,但这是一个选择。
The
git
distribution comes with a contributed script calledgit-new-workdir
.You would use it as follows:
where project-dir is the name of the directory containing your
.git
repository.This scripts creates another
.git
directory with many symlinks to the original one except for files that cannot be shared (like the current branch), allowing you to work in two different branches.It sounds a bit fragile, but it's an option.
我遇到了这个问题,希望找到我在这里找不到的解决方案。现在我确实找到了我需要的东西,我决定将其发布在这里供其他人使用。
警告:如果您需要同时编辑多个分支(例如OP状态),这可能不是一个好的解决方案。它用于签出多个分支> 同时您不打算编辑。 (多个工作目录由一个 .git 文件夹支持。)
自从我第一次遇到这个问题以来,我学到了一些东西:
What a "裸存储库”是。它本质上是
.git
目录的内容,而不位于工作树中。事实上,您可以使用
git
选项在命令行上指定您正在使用的存储库的位置(.git
目录的位置)--git-dir=
什么是“镜像存储库”。
最后一点是一个非常重要的区别。我实际上不想在存储库上工作,我只需要同时签出不同分支和/或标签的副本。事实上,我需要保证分支最终不会与我的远程分支不同。所以镜子对我来说是完美的。
因此,对于我的用例,我通过这样做得到了我需要的东西:
对此的一个重要警告是,两个副本没有单独的 HEAD。因此,在上述操作之后,运行 git --git-dir= --work-tree=firstcopy status 将从branch2到branch1的所有差异显示为未提交的更改 - 因为 HEAD 指向branch2。 (这就是为什么我使用
-f
选项来checkout
,因为我实际上根本不打算在本地进行任何更改。我可以签出任何标签或分支工作树,只要我使用-f
选项。)对于我的用例,在同一台计算机上共存多个结帐而无需编辑它们,这非常有效。我不知道是否有任何方法可以在没有其他答案中涵盖的脚本的情况下为多个工作树提供多个 HEAD,但我希望这对其他人有帮助。
I came across this question hoping for a solution I didn't find here. So now that I did find what I needed, I decided to post it here for others.
Caveat: This is probably not a good solution if you need to edit multiple branches simultaneously, like OP states. It is for having multiple branches checked out simultaneously that you don't intend to edit. (Multiple working directories backed by one .git folder.)
There were a few things I've learned since I came to this question the first time:
What a "bare repository" is. It is essentially the contents of the
.git
directory, without being located in a working tree.The fact that you can specify the location of the repo you are using (the location of your
.git
dir) on the command line with thegit
option--git-dir=
The fact that you can specify the location of your working copy with
--work-tree=
What a "mirror repo" is.
This last is a pretty important distinction. I don't actually want to work on the repo, I just need to have copies of different branches and/or tags checked out simultaneously. In actual fact, I need to guarantee that the branches don't end up different from my remote's branches. So a mirror is perfect for me.
So for my use case, I got what I needed by doing:
The big caveat about this is that there isn't a separate HEAD for the two copies. So after the above, running
git --git-dir=<localgitdir> --work-tree=firstcopy status
will show all the differences from branch2 to branch1 as uncommitted changes - because HEAD is pointing at branch2. (That's why I use the-f
option tocheckout
, because I'm not actually planning to make any changes locally at all. I can checkout any tag or branch for any work-tree, as long as I use the-f
option.)For my use case of having multiple checkouts co-existing on the same computer without needing to edit them, this works perfectly. I don't know if there is any way to have multiple HEADs for the multiple work trees without a script such as is covered in the other answers, but I hope this is helpful to someone else anyway.
我能想到的唯一解决方案是克隆两个目录并将它们添加为彼此的远程存储库。然后,您可以继续将内容从已更改的存储库提取到另一存储库,而无需实际将任何内容推送到远程存储库。
我假设您想要有两个工作目录,而不是远程的两个克隆,因为您不想将某些分支推送到远程。否则,遥控器的两个克隆就可以正常工作 - 您只需要进行一些推拉操作即可使所有三个克隆保持同步。
The only solution I can think of is to clone two directories and add them as remote repositories of each other. You can then keep pulling stuff from the changed one into the other without actually pushing anything to the remote repository.
I am assuming you want to have two working directories and not two clones of the remote because you don't want to push some branches to the remote. Otherwise, two clones of your remote would work just fine - you just need to do some pushes and pulls to keep all three in sync.