88
99Arguments can be URLs or paths to git-scm.com worktrees. When a worktree
1010path is given, Hugo is run to build the site and a local server is started.
11+ Use worktree@commit to checkout a specific commit before building.
1112Use worktree:/path/to/page to navigate to a specific page.
13+ Both can be combined: worktree@commit:/path/to/page
1214
1315Options:
1416 --dark Emulate dark mode (prefers-color-scheme: dark)
@@ -18,6 +20,7 @@ Options:
1820Examples:
1921 node script/compare-screenshots.js https://git-scm.com http://localhost:5000
2022 node script/compare-screenshots.js https://git-scm.com /path/to/worktree
23+ node script/compare-screenshots.js https://git-scm.com .@HEAD~2
2124 node script/compare-screenshots.js https://git-scm.com/docs/git-config /path/to/worktree:/docs/git-config
2225 node script/compare-screenshots.js --dark https://git-scm.com http://localhost:5000
2326 node script/compare-screenshots.js --clip=1280x720+0+0 https://git-scm.com http://localhost:5000` ;
@@ -27,21 +30,53 @@ const { spawn, execSync } = require('child_process');
2730const fs = require ( 'fs' ) ;
2831const path = require ( 'path' ) ;
2932
33+ /**
34+ * Parse a worktree argument to extract worktree path, commit, and page path.
35+ *
36+ * Format: worktree[@commit][:/page/path]
37+ *
38+ * Examples:
39+ * . -> { worktreePath: '.', commit: undefined, pagePath: '' }
40+ * .@HEAD~2 -> { worktreePath: '.', commit: 'HEAD~2', pagePath: '' }
41+ * /path/to/worktree:/docs/git -> { worktreePath: '/path/to/worktree', commit: undefined, pagePath: 'docs/git' }
42+ * .@main :/about -> { worktreePath: '.', commit: 'main', pagePath: 'about' }
43+ *
44+ * Returns false if the argument is a URL or not a valid worktree.
45+ */
3046function getWorktreeInfo ( arg ) {
3147 if ( arg . startsWith ( 'http://' ) || arg . startsWith ( 'https://' ) ) return false ;
3248 const colonIndex = arg . indexOf ( ':' ) ;
33- const worktreePath = colonIndex === - 1 ? arg : arg . slice ( 0 , colonIndex ) ;
49+ const beforeColon = colonIndex === - 1 ? arg : arg . slice ( 0 , colonIndex ) ;
3450 const pagePath = colonIndex === - 1 ? '' : arg . slice ( colonIndex + 1 ) . replace ( / ^ \/ + / , '' ) ;
51+ const atIndex = beforeColon . indexOf ( '@' ) ;
52+ const worktreePath = atIndex === - 1 ? beforeColon : beforeColon . slice ( 0 , atIndex ) ;
53+ const commit = atIndex === - 1 ? undefined : beforeColon . slice ( atIndex + 1 ) ;
3554 try {
3655 if ( fs . statSync ( path . join ( worktreePath , 'hugo.yml' ) ) . isFile ( ) ) {
37- return { worktreePath, pagePath } ;
56+ return { worktreePath, commit , pagePath } ;
3857 }
3958 } catch {
4059 }
4160 return false ;
4261}
4362
44- async function startServer ( worktreePath , port ) {
63+ async function startServer ( worktreePath , port , commit ) {
64+ let restoreRef ;
65+ let wasDetached = false ;
66+
67+ if ( commit ) {
68+ // Determine if we're on a branch (symbolic ref) or detached HEAD
69+ try {
70+ restoreRef = execSync ( 'git symbolic-ref --short HEAD' , { cwd : worktreePath , encoding : 'utf-8' } ) . trim ( ) ;
71+ } catch {
72+ // Not on a branch, save the commit SHA
73+ restoreRef = execSync ( 'git rev-parse HEAD' , { cwd : worktreePath , encoding : 'utf-8' } ) . trim ( ) ;
74+ wasDetached = true ;
75+ }
76+ console . log ( `Switching to ${ commit } in ${ worktreePath } ...` ) ;
77+ execSync ( `git switch -d ${ commit } ` , { cwd : worktreePath , stdio : 'inherit' } ) ;
78+ }
79+
4580 // Build Hugo site
4681 console . error ( `Building Hugo site in ${ worktreePath } ...` ) ;
4782 execSync ( 'hugo' , { cwd : worktreePath , stdio : 'inherit' } ) ;
@@ -54,6 +89,18 @@ async function startServer(worktreePath, port) {
5489 stdio : [ 'ignore' , 'pipe' , 'inherit' ] ,
5590 } ) ;
5691
92+ // Attach restore function to server
93+ server . restore = ( ) => {
94+ if ( restoreRef ) {
95+ console . log ( `Restoring ${ worktreePath } to ${ restoreRef } ...` ) ;
96+ if ( wasDetached ) {
97+ execSync ( `git switch -d ${ restoreRef } ` , { cwd : worktreePath , stdio : 'inherit' } ) ;
98+ } else {
99+ execSync ( `git switch ${ restoreRef } ` , { cwd : worktreePath , stdio : 'inherit' } ) ;
100+ }
101+ }
102+ } ;
103+
57104 // Wait for server to be ready
58105 await new Promise ( ( resolve , reject ) => {
59106 const timeout = setTimeout ( ( ) => reject ( new Error ( 'Server startup timeout' ) ) , 30000 ) ;
@@ -137,7 +184,7 @@ async function main() {
137184
138185 const worktreeInfo = getWorktreeInfo ( urlOrWorktree ) ;
139186 if ( worktreeInfo ) {
140- server = await startServer ( worktreeInfo . worktreePath , 5000 ) ;
187+ server = await startServer ( worktreeInfo . worktreePath , 5000 , worktreeInfo . commit ) ;
141188 url = `http://localhost:5000/${ worktreeInfo . pagePath } ` ;
142189 }
143190
@@ -156,6 +203,7 @@ async function main() {
156203 } finally {
157204 if ( server ) {
158205 server . kill ( ) ;
206+ server . restore ( ) ;
159207 }
160208 }
161209 }
0 commit comments