@@ -6,6 +6,7 @@ export PATH := env_var('HOME') + "/bin:" + HOMEBREW_PREFIX + "/bin:" + env_var('
66@ cross + ARGS :
77 just {{ ARGS}}
88
9+ # Auto-setup environment on first use
910# Auto-setup environment on first use
1011setup :
1112 #!/usr/bin/env fish
@@ -16,6 +17,24 @@ setup:
1617 end
1718 end
1819
20+ # Show this help message
21+ help :
22+ @ echo " git-cross - Vendor parts of git repos into your project"
23+ @ echo " "
24+ @ echo " Usage:"
25+ @ echo " just <command> [options]"
26+ @ echo " ./cross <command> [options] (wrapper script)"
27+ @ echo " "
28+ @ echo " Available commands:"
29+ @ just --list --unsorted
30+ @ echo " "
31+ @ echo " Quick start:"
32+ @ echo " 1. Add upstream repo: just use <name> <url>"
33+ @ echo " 2. Patch directory: just patch <name>:<path> <local_path>"
34+ @ echo " 3. Sync from upstream: just sync"
35+ @ echo " "
36+ @ echo " For more details, see README.md"
37+
1938# Check for required dependencies
2039check-deps :
2140 #!/usr/bin/env fish
@@ -51,13 +70,18 @@ _resolve_context arg_rspec arg_lpath invocation_dir:
5170 # Check Crossfile for matching local path
5271 if test -f Crossfile
5372 while read -l line
54- # Parse: patch <remote>:<path> <local> ...
73+ # Parse: [cross] patch <remote>:<path> <local> ...
5574 set parts (string split " " $line)
56- if test " $parts[1]" = " patch"
57- set p_local $parts[3 ]
75+ set cmd_idx 1
76+ if test " $parts[1]" = " cross"
77+ set cmd_idx 2
78+ end
79+
80+ if test " $parts[$cmd_idx]" = " patch"
81+ set p_local $parts[(math $cmd_idx + 2 )] # Local path is 2 positions after command
5882 # Check if CWD is inside the patch local path
5983 if string match -q " $p_local*" " $rel_cwd"
60- set rspec $parts[2 ]
84+ set rspec $parts[(math $cmd_idx + 1 )] # Remote spec is 1 position after command
6185 set lpath $p_local
6286 echo " $rspec|$lpath"
6387 exit 0
@@ -82,117 +106,121 @@ update_crossfile cmd:
82106 echo " {{ cmd}} " >> $CROSSFILE
83107 end
84108
109+ # Execute arbitrary shell command
110+ exec + CMD :
111+ {{ CMD}}
112+
85113# Add a remote repository
86- use name url : check-deps (update_crossfile " use " + name + " " + url)
114+ use name url : check-deps (update_crossfile " cross use " + name + " " + url)
87115 echo here\
88116 @ git remote show | grep -q " ^{{ name}} $" \
89117 || { git remote add {{ name}} {{ url}} && echo " Added remote: {{ name}} -> {{ url}} " ; }
90118
91119# Patch a directory from a remote into a local path
92- patch remote_spec local_path branch = " master": check-deps (update_crossfile " patch " + remote_spec + " " + local_path + (if branch != " master" { " " + branch } else { " " }))
120+ patch remote_spec local_path branch = " master": check-deps (update_crossfile " cross patch " + remote_spec + " " + local_path + (if branch != " master" { " " + branch } else { " " }))
93121 #!/usr/bin/env fish
94122 set parts (string split -m1 : {{remote_spec}})
95123 set remote $parts[1 ]
96124 set remote_path $parts[2 ]
97-
98125 test -n " $remote" -a -n " $remote_path" || begin
99126 echo " Error: Invalid format. Use remote:path"
100127 exit 1
101128 end
102-
103129 git remote show | grep -q " ^$remote\$ " || begin
104130 echo " Error: Remote '$remote' not found. Run: just use $remote <url>"
105131 exit 1
106132 end
107-
108133 set hash (echo $remote_path | md5sum | cut -d' ' -f1)
109134 set wt " .git/cross/worktrees/$remote" _" $hash"
110-
111135 echo " Setting up hidden worktree at $wt..."
112-
113136 if not test -d $wt
114137 mkdir -p (dirname $wt)
115-
116138 echo " Fetching $remote {{ branch}} ..."
117139 git fetch $remote {{ branch}}
118-
119140 git rev-parse --verify " $remote/{{ branch}} " >/ dev/ null || begin
120141 echo " Error: $remote/{{ branch}} does not exist"
121142 exit 1
122143 end
123-
124144 git worktree add --no-checkout -B " cross/$remote/{{ branch}} /$hash" $wt " $remote/{{ branch}} " >/ dev/ null 2 >&1
125-
126145 set sparse (git -C $wt rev-parse --git-path info/ sparse-checkout)
127146 mkdir -p (dirname $sparse)
128147 echo " /$remote_path/" > $sparse
129-
130148 git -C $wt config core.sparseCheckout true
131149 git -C $wt read -tree -mu HEAD >/ dev/ null 2 >&1
132150 end
133-
134151 echo " Syncing files to {{ local_path}} ..."
135152 mkdir -p {{ local_path}}
136153 rsync -av --delete --exclude .git $wt/ $remote_path/ {{ local_path}} /
137-
138154 echo " Done. {{ local_path}} now contains files from $remote:$remote_path"
139155
156+ # Internal: sync local paths from Crossfile
157+ _ sync_from_crossfile :
158+ #!/usr/bin/env fish
159+ # Check if Crossfile exists
160+ if not test -f Crossfile
161+ echo " Note: No Crossfile found. Only worktrees were updated."
162+ exit 0
163+ end
164+ echo " Syncing changes to local paths..."
165+ while read -l line
166+ set parts (string split " " $line)
167+ # Determine if line starts with 'cross' prefix
168+ set cmd_idx 1
169+ if test " $parts[1]" = " cross"
170+ set cmd_idx 2
171+ end
172+ # Handle 'patch' command: sync worktree to local path
173+ if test " $parts[$cmd_idx]" = " patch"
174+ set rspec $parts[(math $cmd_idx + 1 )]
175+ set lpath $parts[(math $cmd_idx + 2 )]
176+ set rparts (string split -m1 : $rspec)
177+ set remote $rparts[1 ]
178+ set rpath $rparts[2 ]
179+ set hash (echo $rpath | md5sum | cut -d' ' -f1)
180+ set wt " .git/cross/worktrees/$remote" _" $hash"
181+ # Sync only if worktree exists
182+ if test -d $wt
183+ echo " $lpath ← $rspec"
184+ mkdir -p $lpath
185+ rsync -a --delete --exclude .git $wt/ $rpath/ $lpath/ >/ dev/ null 2 >&1
186+ end
187+ # Handle 'exec' command: run post-hooks or custom commands
188+ else if test " $parts[$cmd_idx]" = " exec"
189+ set cmd_str (string join " " $parts[(math $cmd_idx + 1 )..-1])
190+ echo " exec: $cmd_str"
191+ eval $cmd_str
192+ end
193+ end < Crossfile
194+ echo " ✅ Sync complete"
195+
140196# Sync all patches from upstream
141197sync : check-deps
142198 #!/usr/bin/env fish
143199 test -d .git/ cross/ worktrees || begin
144200 echo " No worktrees found."
145201 exit 0
146202 end
147-
148203 # First, update all worktrees from upstream
149204 for wt in .git/ cross/ worktrees/ *
150205 test -d $wt || continue
151206 echo " Updating $wt..."
152-
153207 # Stash local changes if any
154208 set dirty (git -C $wt status --porcelain)
155209 if test -n " $dirty"
156210 echo " Stashing local changes in $wt..."
157211 git -C $wt stash
158212 end
159-
160213 set branch (git -C $wt rev-parse --abbrev-ref HEAD)
161214 set upstream (git -C $wt rev-parse --abbrev-ref --symbolic-full-name ' @{upstream}' )
162215 git -C $wt pull --rebase >/ dev/ null 2 >&1
163-
164216 # Pop stash if we stashed
165217 if test -n " $dirty"
166218 echo " Popping stash in $wt..."
167219 git -C $wt stash pop
168220 end
169221 end
170-
171222 # Then, sync changes to local paths using Crossfile
172- if test -f Crossfile
173- echo " Syncing changes to local paths..."
174- while read -l line
175- set parts (string split " " $line)
176- if test " $parts[1]" = " patch"
177- set rspec $parts[2 ]
178- set lpath $parts[3 ]
179- set rparts (string split -m1 : $rspec)
180- set remote $rparts[1 ]
181- set rpath $rparts[2 ]
182-
183- set hash (echo $rpath | md5sum | cut -d' ' -f1)
184- set wt " .git/cross/worktrees/$remote" _" $hash"
185-
186- if test -d $wt
187- echo " $lpath ← $rspec"
188- rsync -a --delete --exclude .git $wt/ $rpath/ $lpath/ >/ dev/ null 2 >&1
189- end
190- end
191- end < Crossfile
192- echo " ✅ Sync complete"
193- else
194- echo " Note: No Crossfile found. Only worktrees were updated."
195- end
223+ just --quiet _sync_from_crossfile
196224
197225# Diff local vs upstream
198226diff arg_rspec = " " arg_lpath = " ": check-deps
@@ -289,9 +317,14 @@ list: check-deps
289317
290318 while read -l line
291319 set parts (string split " " $line)
292- if test " $parts[1]" = " patch"
293- set remote_spec $parts[2 ]
294- set local_path $parts[3 ]
320+ set cmd_idx 1
321+ if test " $parts[1]" = " cross"
322+ set cmd_idx 2
323+ end
324+
325+ if test " $parts[$cmd_idx]" = " patch"
326+ set remote_spec $parts[(math $cmd_idx + 1 )] # Remote spec
327+ set local_path $parts[(math $cmd_idx + 2 )] # Local path
295328 set rparts (string split -m1 : $remote_spec)
296329 printf " %-20s %-30s %-20s\n " $rparts[1 ] $rparts[2 ] $local_path
297330 end
@@ -310,9 +343,14 @@ status: check-deps
310343
311344 while read -l line
312345 set parts (string split " " $line)
313- if test " $parts[1]" = " patch"
314- set remote_spec $parts[2 ]
315- set local_path $parts[3 ]
346+ set cmd_idx 1
347+ if test " $parts[1]" = " cross"
348+ set cmd_idx 2
349+ end
350+
351+ if test " $parts[$cmd_idx]" = " patch"
352+ set remote_spec $parts[(math $cmd_idx + 1 )] # Remote spec
353+ set local_path $parts[(math $cmd_idx + 2 )] # Local path
316354 set rparts (string split -m1 : $remote_spec)
317355 set remote $rparts[1 ]
318356 set rpath $rparts[2 ]
@@ -370,8 +408,15 @@ replay: check-deps
370408 continue
371409 end
372410
373- echo " ▶ just $line"
374- just $line
411+ # If line starts with "cross", execute it directly via just
412+ if string match -q " cross *" $line
413+ echo " ▶ just $line"
414+ just $line
415+ else
416+ # Backward compatibility for old format (implicit "cross")
417+ echo " ▶ just cross $line"
418+ just cross $line
419+ end
375420 end < Crossfile
376421
377422 echo " ✅ Crossfile replay complete"
0 commit comments