Skip to content

Commit 8aff1a9

Browse files
pcloudsgitster
authored andcommitted
Add a place for (not) sharing stuff between worktrees
When multiple worktrees are used, we need rules to determine if something belongs to one worktree or all of them. Instead of keeping adding rules when new stuff comes (*), have a generic rule: - Inside $GIT_DIR, which is per-worktree by default, add $GIT_DIR/common which is always shared. New features that want to share stuff should put stuff under this directory. - Inside refs/, which is shared by default except refs/bisect, add refs/worktree/ which is per-worktree. We may eventually move refs/bisect to this new location and remove the exception in refs code. (*) And it may also include stuff from external commands which will have no way to modify common/per-worktree rules. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5c79f74 commit 8aff1a9

File tree

7 files changed

+76
-6
lines changed

7 files changed

+76
-6
lines changed

Documentation/git-worktree.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,22 @@ working trees, it can be used to identify worktrees. For example if
204204
you only have two working trees, at "/abc/def/ghi" and "/abc/def/ggg",
205205
then "ghi" or "def/ghi" is enough to point to the former working tree.
206206

207+
REFS
208+
----
209+
In multiple working trees, some refs may be shared between all working
210+
trees, some refs are local. One example is HEAD is different for all
211+
working trees. This section is about the sharing rules.
212+
213+
In general, all pseudo refs are per working tree and all refs starting
214+
with "refs/" are shared. Pseudo refs are ones like HEAD which are
215+
directly under GIT_DIR instead of inside GIT_DIR/refs. There are one
216+
exception to this: refs inside refs/bisect and refs/worktree is not
217+
shared.
218+
219+
To access refs, it's best not to look inside GIT_DIR directly. Instead
220+
use commands such as linkgit:git-revparse[1] or linkgit:git-update-ref[1]
221+
which will handle refs correctly.
222+
207223
DETAILS
208224
-------
209225
Each linked working tree has a private sub-directory in the repository's
@@ -228,7 +244,8 @@ linked working tree `git rev-parse --git-path HEAD` returns
228244
`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
229245
rev-parse --git-path refs/heads/master` uses
230246
$GIT_COMMON_DIR and returns `/path/main/.git/refs/heads/master`,
231-
since refs are shared across all working trees.
247+
since refs are shared across all working trees, except refs/bisect and
248+
refs/worktree.
232249

233250
See linkgit:gitrepository-layout[5] for more information. The rule of
234251
thumb is do not make any assumption about whether a path belongs to

Documentation/gitrepository-layout.txt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ refs::
9595
References are stored in subdirectories of this
9696
directory. The 'git prune' command knows to preserve
9797
objects reachable from refs found in this directory and
98-
its subdirectories. This directory is ignored if $GIT_COMMON_DIR
99-
is set and "$GIT_COMMON_DIR/refs" will be used instead.
98+
its subdirectories.
99+
This directory is ignored (except refs/bisect and
100+
refs/worktree) if $GIT_COMMON_DIR is set and
101+
"$GIT_COMMON_DIR/refs" will be used instead.
100102

101103
refs/heads/`name`::
102104
records tip-of-the-tree commit objects of branch `name`
@@ -165,6 +167,11 @@ hooks::
165167
each hook. This directory is ignored if $GIT_COMMON_DIR is set
166168
and "$GIT_COMMON_DIR/hooks" will be used instead.
167169

170+
common::
171+
When multiple working trees are used, most of files in
172+
$GIT_DIR are per-worktree with a few known exceptions. All
173+
files under 'common' however will be shared between all
174+
working trees.
168175

169176
index::
170177
The current index file for the repository. It is

path.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ struct common_dir {
108108

109109
static struct common_dir common_list[] = {
110110
{ 0, 1, 0, "branches" },
111+
{ 0, 1, 0, "common" },
111112
{ 0, 1, 0, "hooks" },
112113
{ 0, 1, 0, "info" },
113114
{ 0, 0, 1, "info/sparse-checkout" },
@@ -118,6 +119,7 @@ static struct common_dir common_list[] = {
118119
{ 0, 1, 0, "objects" },
119120
{ 0, 1, 0, "refs" },
120121
{ 0, 1, 1, "refs/bisect" },
122+
{ 0, 1, 1, "refs/worktree" },
121123
{ 0, 1, 0, "remotes" },
122124
{ 0, 1, 0, "worktrees" },
123125
{ 0, 1, 0, "rr-cache" },

refs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
624624
static int is_per_worktree_ref(const char *refname)
625625
{
626626
return !strcmp(refname, "HEAD") ||
627+
starts_with(refname, "refs/worktree/") ||
627628
starts_with(refname, "refs/bisect/") ||
628629
starts_with(refname, "refs/rewritten/");
629630
}

refs/files-backend.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,9 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
269269
closedir(d);
270270

271271
/*
272-
* Manually add refs/bisect, which, being per-worktree, might
273-
* not appear in the directory listing for refs/ in the main
274-
* repo.
272+
* Manually add refs/bisect and refs/worktree, which, being
273+
* per-worktree, might not appear in the directory listing for
274+
* refs/ in the main repo.
275275
*/
276276
if (!strcmp(dirname, "refs/")) {
277277
int pos = search_ref_dir(dir, "refs/bisect/", 12);
@@ -281,6 +281,14 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,
281281
dir->cache, "refs/bisect/", 12, 1);
282282
add_entry_to_dir(dir, child_entry);
283283
}
284+
285+
pos = search_ref_dir(dir, "refs/worktree/", 11);
286+
287+
if (pos < 0) {
288+
struct ref_entry *child_entry = create_dir_entry(
289+
dir->cache, "refs/worktree/", 11, 1);
290+
add_entry_to_dir(dir, child_entry);
291+
}
284292
}
285293
}
286294

t/t0060-path-utils.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ test_git_path GIT_COMMON_DIR=bar hooks/me bar/hooks/me
306306
test_git_path GIT_COMMON_DIR=bar config bar/config
307307
test_git_path GIT_COMMON_DIR=bar packed-refs bar/packed-refs
308308
test_git_path GIT_COMMON_DIR=bar shallow bar/shallow
309+
test_git_path GIT_COMMON_DIR=bar common bar/common
310+
test_git_path GIT_COMMON_DIR=bar common/file bar/common/file
309311

310312
# In the tests below, $(pwd) must be used because it is a native path on
311313
# Windows and avoids MSYS's path mangling (which simplifies "foo/../bar" and

t/t1415-worktree-refs.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/sh
2+
3+
test_description='per-worktree refs'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'setup' '
8+
test_commit initial &&
9+
test_commit wt1 &&
10+
test_commit wt2 &&
11+
git worktree add wt1 wt1 &&
12+
git worktree add wt2 wt2 &&
13+
git checkout initial &&
14+
git update-ref refs/worktree/foo HEAD &&
15+
git -C wt1 update-ref refs/worktree/foo HEAD &&
16+
git -C wt2 update-ref refs/worktree/foo HEAD
17+
'
18+
19+
test_expect_success 'refs/worktree must not be packed' '
20+
git pack-refs --all &&
21+
test_path_is_missing .git/refs/tags/wt1 &&
22+
test_path_is_file .git/refs/worktree/foo &&
23+
test_path_is_file .git/worktrees/wt1/refs/worktree/foo &&
24+
test_path_is_file .git/worktrees/wt2/refs/worktree/foo
25+
'
26+
27+
test_expect_success 'refs/worktree are per-worktree' '
28+
test_cmp_rev worktree/foo initial &&
29+
( cd wt1 && test_cmp_rev worktree/foo wt1 ) &&
30+
( cd wt2 && test_cmp_rev worktree/foo wt2 )
31+
'
32+
33+
test_done

0 commit comments

Comments
 (0)