* `git worktree list` when bare repository is named `.git`
@ 2024-10-11 1:12 Rebecca Turner
0 siblings, 0 replies; 8+ messages in thread
From: Rebecca Turner @ 2024-10-11 1:12 UTC (permalink / raw)
To: git
It seems that `.git` is always stripped from the `git worktree list` output (including in `--porcelain` mode). This becomes relevant with bare repositories. Here is a bare repository functioning as expected:
$ mkdir bare1
$ cd bare1
$ git init --bare
Initialized empty Git repository in /private/tmp/bare1/
$ git worktree list
/private/tmp/bare1 (bare)
But if we create a bare repository in a directory named `.git`, `git worktree list` displays the parent directory as the worktree, even though `git status` doesn't recognize it as a worktree:
$ mkdir -p bare2/.git
$ cd bare2/.git
$ git init --bare
Initialized empty Git repository in /private/tmp/bare2/.git/
$ git worktree list
/private/tmp/bare2 (bare)
$ cd /tmp/bare2
$ git status
fatal: this operation must be run in a work tree
However, Git _will_ recognize the parent directory (/tmp/bare2) as a Git repository for the purposes of commands like `git rev-parse --git-dir`. I suspect this can be fixed in `get_main_worktree` by only stripping a `.git` suffix from the path if the main worktree is not bare.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: `git worktree list` when bare repository is named `.git`
@ 2024-10-11 3:52 Caleb White
2024-10-11 4:59 ` Rebecca Turner
0 siblings, 1 reply; 8+ messages in thread
From: Caleb White @ 2024-10-11 3:52 UTC (permalink / raw)
To: rbt; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 2487 bytes --]
> It seems that `.git` is always stripped from the `git worktree list` output (including in `--porcelain` mode). This becomes relevant with bare repositories. Here is a bare repository functioning as expected:
>
> $ mkdir bare1
> $ cd bare1
> $ git init --bare
> Initialized empty Git repository in /private/tmp/bare1/
> $ git worktree list
> /private/tmp/bare1 (bare)
>
> But if we create a bare repository in a directory named `.git`, `git worktree list` displays the parent directory as the worktree, even though `git status` doesn't recognize it as a worktree:
>
> $ mkdir -p bare2/.git
> $ cd bare2/.git
> $ git init --bare
> Initialized empty Git repository in /private/tmp/bare2/.git/
> $ git worktree list
> /private/tmp/bare2 (bare)
> $ cd /tmp/bare2
> $ git status
> fatal: this operation must be run in a work tree
>
> However, Git _will_ recognize the parent directory (/tmp/bare2) as a Git repository for the purposes of commands like `git rev-parse --git-dir`. I suspect this can be fixed in `get_main_worktree` by only stripping a `.git` suffix from the path if the main worktree is not bare.
The behavior you are seeing is correct and expected (and I use bare
repositories with worktrees like this).
The actual bare repository can be the directory, in a .git directory,
or in any other directory (as long as it has a .git file that points
to the actual bare repository). The directory will still be considered a
bare repository. For example:
mkdir -p repo/.bare
cd repo/.bare
Initialized empty Git repository in /private/tmp/repo/.bare/
git init --bare
cd ..
echo 'gitdir: .bare' >.git
git worktree list
git worktree add master
/private/tmp/repo (bare)
/private/tmp/repo/master
Bare repositories by definition do not have a working tree, and therefore it is
expected that `git status` fails (can only be executed in a worktree) while
other commands succeed.
For the purposes of `git worktree list`, the `.git` suffix **should not** be
shown. You should never try to use `git worktree list` to get the actual path
of the repository, the docs give the following warning:
See gitrepository-layout[5] for more information. The rule of thumb is do
not make any assumption about whether a path belongs to $GIT_DIR or
$GIT_COMMON_DIR when you need to directly access something inside $GIT_DIR.
Use git rev-parse --git-path to get the final path.
Best,
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 509 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: `git worktree list` when bare repository is named `.git`
2024-10-11 3:52 `git worktree list` when bare repository is named `.git` Caleb White
@ 2024-10-11 4:59 ` Rebecca Turner
2024-10-11 5:36 ` Caleb White
0 siblings, 1 reply; 8+ messages in thread
From: Rebecca Turner @ 2024-10-11 4:59 UTC (permalink / raw)
To: Caleb White; +Cc: git
> The actual bare repository can be the directory, in a .git directory,
> or in any other directory (as long as it has a .git file that points
> to the actual bare repository). The directory will still be considered a
> bare repository.
Perhaps your example got scrambled, but I can't quite reproduce it:
$ mkdir -p repo/.bare
$ cd repo/.bare
$ git init --bare
Initialized empty Git repository in /private/tmp/repo/.bare/
$ git worktree list
/private/tmp/repo/.bare (bare)
$ cd ..
$ git worktree list
fatal: not a git repository (or any of the parent directories): .git
$ echo 'gitdir: .bare' >.git
$ git worktree list
/private/tmp/repo/.bare (bare)
It seems like the $GIT_DIR is shown in the worktree list here, and when I add
a `.git` file pointing to `.bare` manually, that doesn't get listed. (Which I
suppose makes sense, because it's not a `git-worktree(1)` worktree, but still
seems a little bit odd?)
> For the purposes of `git worktree list`, the `.git` suffix **should not** be
> shown. You should never try to use `git worktree list` to get the actual path
> of the repository, the docs give the following warning:
>
> See gitrepository-layout[5] for more information. The rule of thumb is do
> not make any assumption about whether a path belongs to $GIT_DIR or
> $GIT_COMMON_DIR when you need to directly access something inside $GIT_DIR.
> Use git rev-parse --git-path to get the final path.
I understood this note to be talking about paths _within_ the `$GIT_DIR` or
`$GIT_COMMON_DIR` itself; I see no reason why `git worktree list` wouldn't list
a bare repository _consistently_ as either the `$GIT_DIR` or the parent of the
`$GIT_DIR`.
What I'd like to do is get the path of the worktree so that I can move it. `git
worktree list` gives me this information _except_ for bare repositories in
directories named `.git`. I'm happy to have a special case for this, but I'd
like to understand the principle here.
Maybe I'm just not supposed to name a bare repository `.git`? The
`gitrepository-layout(5)` page does seem to imply this is mutually exclusive
with bare repositories:
> A Git repository comes in two different flavours:
>
> • a .git directory at the root of the working tree;
>
> • a <project>.git directory that is a bare repository (i.e. without its
> own working tree), that is typically used for exchanging histories with
> others by pushing into it and fetching from it.
Thanks for your help!
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: `git worktree list` when bare repository is named `.git`
2024-10-11 4:59 ` Rebecca Turner
@ 2024-10-11 5:36 ` Caleb White
2024-10-11 16:19 ` Rebecca Turner
0 siblings, 1 reply; 8+ messages in thread
From: Caleb White @ 2024-10-11 5:36 UTC (permalink / raw)
To: Rebecca Turner; +Cc: git
On Thu Oct 10, 2024 at 11:59 PM CDT, Rebecca Turner wrote:
> Perhaps your example got scrambled, but I can't quite reproduce it:
>
> $ mkdir -p repo/.bare
> $ cd repo/.bare
> $ git init --bare
> Initialized empty Git repository in /private/tmp/repo/.bare/
> $ git worktree list
> /private/tmp/repo/.bare (bare)
> $ cd ..
> $ git worktree list
> fatal: not a git repository (or any of the parent directories): .git
> $ echo 'gitdir: .bare' >.git
> $ git worktree list
> /private/tmp/repo/.bare (bare)
> It seems like the $GIT_DIR is shown in the worktree list here, and when I add
> a `.git` file pointing to `.bare` manually, that doesn't get listed. (Which I
> suppose makes sense, because it's not a `git-worktree(1)` worktree, but still
> seems a little bit odd?)
Ah, I was mistaken. It will show the actual path if the gitdir points
to a separate directory.
> I understood this note to be talking about paths _within_ the `$GIT_DIR` or
> `$GIT_COMMON_DIR` itself; I see no reason why `git worktree list` wouldn't list
> a bare repository _consistently_ as either the `$GIT_DIR` or the parent of the
> `$GIT_DIR`.
>
> What I'd like to do is get the path of the worktree so that I can move it. `git
> worktree list` gives me this information _except_ for bare repositories in
> directories named `.git`. I'm happy to have a special case for this, but I'd
> like to understand the principle here.
Why would you move the `.git` directory? If you're trying to move the
repository, then wouldn't you just move the directory that contains the
`.git` directory?
I think the main reason why the `.git` path is trimmed is because it
doesn't make sense to show it in non-bare repositories. No one wants to
see the `.git` path in a normal repository.
# global git
git worktree list
~/sources/git 3f20f8dd05 [wt_relative_paths]
# locally modified git
./git worktree list
~/sources/git/.git 3f20f8dd05 [wt_relative_paths]
I would rather not have the `.git` show even in bare repositories,
if a user has moved the bare repository to `.git`, then that would
indicate that the *intent* is for the parent directory to essentially
act as the repository (and be moved as a cohesive unit if moving).
> Maybe I'm just not supposed to name a bare repository `.git`? The
> `gitrepository-layout(5)` page does seem to imply this is mutually exclusive
> with bare repositories:
>
>> A Git repository comes in two different flavours:
>>
>> • a .git directory at the root of the working tree;
>>
>> • a <project>.git directory that is a bare repository (i.e. without its
>> own working tree), that is typically used for exchanging histories with
>> others by pushing into it and fetching from it.
There's nothing wrong with naming a bare repository `.git`. I've been
doing it for a while now and it works just fine.
I've become a big fan of using bare repositories with worktrees,
particularly in high-trafficked repositories where I'm constantly
switching between branches.
When I was first doing research on this, I found a ton of articles with
all kinds of different ways to do it. Some folks put their worktrees in
the same directory as the actual repository (intermixed with their
code), some polluted the parent directory, some created a detached
commit that removed all files from the default working tree and then
created the worktrees, some used a bare repository but then just created
the worktrees in the same directory, etc. I finally came across an
article that showed the `.bare` method above and I thought that was the
cleanest method. However, after using it for a while, I realized that
I could just move `.bare` to `.git` and it would work just fine (and
I could remove an extra file). I've been using that method ever since.
Best,
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: `git worktree list` when bare repository is named `.git`
2024-10-11 5:36 ` Caleb White
@ 2024-10-11 16:19 ` Rebecca Turner
2024-10-11 16:45 ` Caleb White
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Rebecca Turner @ 2024-10-11 16:19 UTC (permalink / raw)
To: Caleb White; +Cc: git
> Why would you move the `.git` directory? If you're trying to move the
> repository, then wouldn't you just move the directory that contains the
> `.git` directory?
Ah, I should give some context here. I'm using worktrees with the layout you
describe later in your email:
my-repo/
.git/ <- bare git directory
main/ <- worktree for main branch
feature1/ <- worktree for feature work
...
I'm writing a tool to manage these layouts for you. I want to provide two
features:
1. The ability to add a new worktree in a slightly more magical manner; in
particular, I want to be able to do `git my-tool add feature2` and add a new
worktree in the same directory as all the other worktrees.
For a non-bare main worktree, that directory is the parent of the main
worktree.
For a bare main worktree named `.git`, it's the path of the main
worktree. (Nothing in the `git worktree list` output indicates this is the
case!)
For other bare worktrees, it's the parent of the main worktree.
2. The ability to convert an existing repository in this layout.
This requires separating the `$GIT_DIR` from the worktree and then
reassociating them, in order to convert the non-bare main worktree into a
bare main worktree and a second linked worktree. (In particular, I'd like to
avoid the cost of copying all the files in a large checkout.)
> I think the main reason why the `.git` path is trimmed is because it
> doesn't make sense to show it in non-bare repositories. No one wants to
> see the `.git` path in a normal repository.
>
> # global git
> git worktree list
> ~/sources/git 3f20f8dd05 [wt_relative_paths]
>
> # locally modified git
> ./git worktree list
> ~/sources/git/.git 3f20f8dd05 [wt_relative_paths]
I definitely agree with this!
> I would rather not have the `.git` show even in bare repositories,
> if a user has moved the bare repository to `.git`, then that would
> indicate that the *intent* is for the parent directory to essentially
> act as the repository (and be moved as a cohesive unit if moving).
I suppose that makes sense? Perhaps this is an area where the documentation
needs some additional notes.
> When I was first doing research on this, I found a ton of articles with
> all kinds of different ways to do it. Some folks put their worktrees in
> the same directory as the actual repository (intermixed with their
> code), some polluted the parent directory, some created a detached
> commit that removed all files from the default working tree and then
> created the worktrees, some used a bare repository but then just created
> the worktrees in the same directory, etc. I finally came across an
> article that showed the `.bare` method above and I thought that was the
> cleanest method. However, after using it for a while, I realized that
> I could just move `.bare` to `.git` and it would work just fine (and
> I could remove an extra file). I've been using that method ever since.
Yes, exactly! My frustration with this technique is how difficult it is to use.
I have existing checkouts I'd like to convert to worktree repositories, and
`git clone --bare` doesn't create remote-tracking branches, so it's strangely
difficult to set up repositories like this. I'm hoping to ease some of this
with my new tool.
Thanks again for your help,
-- Rebecca
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: `git worktree list` when bare repository is named `.git`
2024-10-11 16:19 ` Rebecca Turner
@ 2024-10-11 16:45 ` Caleb White
2024-10-11 22:17 ` Patrick Callahan
[not found] ` <CACt=GQry+mR7fVSUEdpPjsgSoDURk4W-DRPqLkom-f9Q0KBuTQ@mail.gmail.com>
2 siblings, 0 replies; 8+ messages in thread
From: Caleb White @ 2024-10-11 16:45 UTC (permalink / raw)
To: Rebecca Turner; +Cc: git
On Fri Oct 11, 2024 at 11:19 AM CDT, Rebecca Turner wrote:
> Ah, I should give some context here. I'm using worktrees with the layout you
> describe later in your email:
>
> my-repo/
> .git/ <- bare git directory
> main/ <- worktree for main branch
> feature1/ <- worktree for feature work
> ...
>
> I'm writing a tool to manage these layouts for you. I want to provide two
> features:
>
> 1. The ability to add a new worktree in a slightly more magical manner; in
> particular, I want to be able to do `git my-tool add feature2` and add a new
> worktree in the same directory as all the other worktrees.
If your repository is already set up in the layout you describe, you can
just execute `git worktree add` (I have this aliased to `g w add`, I'm a
lazy typer haha) in the `my-repo` directory.
> For a non-bare main worktree, that directory is the parent of the main
> worktree.
I would *not* do this, you may just want to not support this case. I
imagine most folks have a common directory for all their repositories,
and polluting the parent directory with worktrees sounds like a bad idea.
>
> For a bare main worktree named `.git`, it's the path of the main
> worktree. (Nothing in the `git worktree list` output indicates this is the
> case!)
>
> For other bare worktrees, it's the parent of the main worktree.
Note that you can use `rev-parse` to get the actual directory:
git rev-parse --absolute-git-dir
~/sources/bare-repo/.git
> 2. The ability to convert an existing repository in this layout.
>
> This requires separating the `$GIT_DIR` from the worktree and then
> reassociating them, in order to convert the non-bare main worktree into a
> bare main worktree and a second linked worktree. (In particular, I'd like to
> avoid the cost of copying all the files in a large checkout.)
To convert an existing repository to this layout, all you should have to
do is:
- Add `bare = true` to the `[core]` section of the `.git/config` file
- Remove everything except the `.git` directory
- Create a new worktree for the default branch
- Profit!
>> When I was first doing research on this, I found a ton of articles with
>> all kinds of different ways to do it. Some folks put their worktrees in
>> the same directory as the actual repository (intermixed with their
>> code), some polluted the parent directory, some created a detached
>> commit that removed all files from the default working tree and then
>> created the worktrees, some used a bare repository but then just created
>> the worktrees in the same directory, etc. I finally came across an
>> article that showed the `.bare` method above and I thought that was the
>> cleanest method. However, after using it for a while, I realized that
>> I could just move `.bare` to `.git` and it would work just fine (and
>> I could remove an extra file). I've been using that method ever since.
>
> Yes, exactly! My frustration with this technique is how difficult it is to use.
> I have existing checkouts I'd like to convert to worktree repositories, and
> `git clone --bare` doesn't create remote-tracking branches, so it's strangely
> difficult to set up repositories like this. I'm hoping to ease some of this
> with my new tool.
I've created a helper script[1] that allows me to clone a bare repository
to use with worktrees. In case you don't know, any script in your PATH
that starts with `git-` can be called as `git <script-name>`. I then
have a git alias for this script and so I can run the following to set
everything up:
git cloneb https://github.com/git/git
The script also allows setting up an upstream remote at the same time
in case you've forked the repository.
git cloneb --remote=https://github.com/git/git https://github.com/<user>/git
[1]: https://github.com/calebdw/dotfiles/blob/master/scripts/git-clone-bare-for-worktrees
Best,
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: `git worktree list` when bare repository is named `.git`
2024-10-11 16:19 ` Rebecca Turner
2024-10-11 16:45 ` Caleb White
@ 2024-10-11 22:17 ` Patrick Callahan
[not found] ` <CACt=GQry+mR7fVSUEdpPjsgSoDURk4W-DRPqLkom-f9Q0KBuTQ@mail.gmail.com>
2 siblings, 0 replies; 8+ messages in thread
From: Patrick Callahan @ 2024-10-11 22:17 UTC (permalink / raw)
Cc: git
On Fri, Oct 11, 2024 at 12:21 PM Rebecca Turner <rbt@fastmail.com> wrote:
>
> > Why would you move the `.git` directory? If you're trying to move the
> > repository, then wouldn't you just move the directory that contains the
> > `.git` directory?
>
> Ah, I should give some context here. I'm using worktrees with the layout you
> describe later in your email:
>
> my-repo/
> .git/ <- bare git directory
> main/ <- worktree for main branch
> feature1/ <- worktree for feature work
> ...
>
> I'm writing a tool to manage these layouts for you. I want to provide two
> features:
>
> 1. The ability to add a new worktree in a slightly more magical manner; in
> particular, I want to be able to do `git my-tool add feature2` and add a new
> worktree in the same directory as all the other worktrees.
>
> For a non-bare main worktree, that directory is the parent of the main
> worktree.
>
> For a bare main worktree named `.git`, it's the path of the main
> worktree. (Nothing in the `git worktree list` output indicates this is the
> case!)
>
> For other bare worktrees, it's the parent of the main worktree.
Rebecca,
I'm working on a tool to manage worktrees as well. Can we compare notes?
My directory structure separates repositories and worktrees in
separate directories, but the goals seem similar.
git documentation seems to treat the bare repository concept as if one
only uses bare repositories on a server, not locally in a development
environment.
But, I've found that local worktree-based development is possible for
multiple applications, libraries, toolchains, and CI, but it isn't
very easy to maintain by hand, so tooling is a must. With some
scripting, it works well for many bare repositories, numerous branch
worktrees, and multiple build-and-run scenarios. Switching between
tasks is almost instantaneous, with no need to stash or un-stash
anything.
I've managed to come up with a bash implementation with just three
commands for starting an editor/ide, building and running. Parameters
to these commands set the context for whatever it is I'm working on at
the moment. I'm working on separate commands to maintain the
environment. I need to do such things as clone an upstream repo,
clone
-Pat Callahan
Framingham, Ma
Here's the list of requirements I'm working with:
Overview
- Use only bare repositories and worktrees
- Start an Ide, a build, a run for whatever I'm working on at the moment
- Support development work on multiple applications, libraries, or tools
- No limit to the number of working contexts.
- Instant focus on a specific context: a set of repositories,
git-references. and worktrees
- Instant switch between different working contexts within the same
application or between different applications.
Repositories
- Bare clones of a set of official and forked repositories from
Github, Gitlab, or Sourceforge
- Local Bare Repos Only
- All Repos in one directory as repo-name.git
- Worktrees as needed for building
Worktrees
- All Worktrees in another single directory as repo-name.git-reference
(git reference being a branch, tag, or commit
- Worktree synchronization by git pull upstream, or git pull upstream --rebase
- Directories
- Hierarchy as flat as possible
- Automatic setup of out-of-tree builds using symbolic links to one or
more worktrees
IDE or Code Editor support
- Automatic setup of multiple multi-root workspaces based on the list
of worktrees used to build a specific branch.
Building and Running
- A default build script and custom build scripts where appropriate
- A default application run script with custom run scripts where appropriate
- Straightforward, flexible command line syntax
Example: Build four separate cmake build types: Debug,
RelWithDebInfo for each of two branches
b app-name branch-name1 branch-name-2 d rd r m
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: `git worktree list` when bare repository is named `.git`
[not found] ` <CACt=GQry+mR7fVSUEdpPjsgSoDURk4W-DRPqLkom-f9Q0KBuTQ@mail.gmail.com>
@ 2024-10-21 19:09 ` Rebecca Turner
0 siblings, 0 replies; 8+ messages in thread
From: Rebecca Turner @ 2024-10-21 19:09 UTC (permalink / raw)
To: Patrick Callahan; +Cc: Caleb White, git
Pat,
> I'm working on a tool to manage worktrees as well. Can we compare notes?
I've mostly finished my tool. Here's the code: https://github.com/9999years/git-prole
I'm not sure the repository layout my tool creates will match your expectations, but it'll be an interesting point of comparison. Enjoy!
Best,
-- Rebecca
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-10-21 19:09 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-11 3:52 `git worktree list` when bare repository is named `.git` Caleb White
2024-10-11 4:59 ` Rebecca Turner
2024-10-11 5:36 ` Caleb White
2024-10-11 16:19 ` Rebecca Turner
2024-10-11 16:45 ` Caleb White
2024-10-11 22:17 ` Patrick Callahan
[not found] ` <CACt=GQry+mR7fVSUEdpPjsgSoDURk4W-DRPqLkom-f9Q0KBuTQ@mail.gmail.com>
2024-10-21 19:09 ` Rebecca Turner
-- strict thread matches above, loose matches on Subject: below --
2024-10-11 1:12 Rebecca Turner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).