Skip to content

Commit 1f2eb24

Browse files
authored
doc(recipes): Add example of auto-tracking branches on checkout (#990)
Takes advantage of GIT_SPICE=1 (#989) and post-checkout hooks to automatically track git branches with git-spice on checkout.
1 parent 5cf4009 commit 1f2eb24

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

doc/src/community/recipes.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,107 @@ description: >-
77

88
# Recipes
99

10+
## Customization
11+
12+
### Auto-track branches on checkout
13+
14+
<!-- gs:version unreleased -->
15+
16+
Git's post-checkout hook can be used
17+
to invoke git-spice automatically when a branch is checked out,
18+
and track the branch with git-spice if it is not already tracked.
19+
20+
**Prerequisites:**
21+
22+
- git-spice <!-- gs:version unreleased -->
23+
- Git hooks are enabled
24+
(this is the default, but certain setups may disable them)
25+
- The repository is already initialized with git-spice ($$gs repo init$$)
26+
27+
**Steps:**
28+
29+
1. Copy this script under `.git/hooks/post-checkout` in your repository.
30+
31+
??? example ".git/hooks/post-checkout"
32+
33+
```bash
34+
#!/usr/bin/env bash
35+
set -euo pipefail
36+
37+
# post-checkout is invoked with:
38+
# $1 - ref of the previous HEAD
39+
# $2 - ref of the new HEAD
40+
# $3 - 1 for a branch checkout, 0 for a file checkout
41+
shift # old SHA
42+
shift # new SHA
43+
checkout_type=$1
44+
45+
# Ignore non-branch checkouts.
46+
if [[ "$checkout_type" -eq 0 ]]; then
47+
exit 0
48+
fi
49+
50+
# Don't do anything if this was invoked during a git-spice operation;
51+
# if git-spice runs checkout, let it do what it's doing without interference.
52+
if [[ -n "${GIT_SPICE:-}" ]]; then
53+
exit 0
54+
fi
55+
56+
# post-checkout hook does not receive the branch name,
57+
# so get it from the new HEAD.
58+
branch_name=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
59+
if [[ -z "$branch_name" ]]; then
60+
exit 0 # not a branch
61+
fi
62+
63+
# ...and verify it's actually a local branch.
64+
if ! git show-ref --verify --quiet refs/heads/"$branch_name"; then
65+
exit 0
66+
fi
67+
68+
# Don't attempt to track trunk.
69+
trunk_name=$(gs trunk -n 2>/dev/null || echo "master")
70+
if [[ "$branch_name" == "$trunk_name" ]]; then
71+
exit 0
72+
fi
73+
74+
# Check if the branch is already tracked by git-spice
75+
# by poking at the internals. (gs ls --json will be slower here.)
76+
#
77+
# Warning: This may break if git-spice's internal storage format changes.
78+
if ! git rev-parse --verify --quiet refs/spice/data:branches/"$branch_name" >/dev/null; then
79+
echo >&2 "Branch not tracked with git-spice: '$branch_name'. Tracking it now..."
80+
81+
# We use 'downstack track' so that if there are any untracked branches
82+
# downstack from this one, they get tracked too.
83+
gs downstack track "$branch_name"
84+
fi
85+
```
86+
87+
2. Make sure the script is executable.
88+
89+
```bash
90+
chmod +x .git/hooks/post-checkout
91+
```
92+
93+
3. Test it out by checking out an untracked branch.
94+
95+
```bash
96+
git checkout -b my-feature main
97+
```
98+
99+
**How this works:**
100+
101+
- The post-checkout hook is invoked by Git after a checkout operation,
102+
whether with `git checkout` or `git switch`.
103+
- The script checks `GIT_SPICE` (added in <!-- gs:version unreleased -->)
104+
to ensure it does not interfere
105+
with git-spice's own operations (e.g. $$gs branch checkout$$).
106+
- It checks whether the new branch is already tracked by git-spice
107+
by looking inside its internal storage ([Internals](../guide/internals.md)).
108+
- If the branch is not tracked, it invokes $$gs downstack track$$
109+
to track the branch and any untracked branches downstack from it.
110+
10111
## Workflows
11112
12113
### Create branches without committing

0 commit comments

Comments
 (0)