1414#include "repository.h"
1515#include "worktree.h"
1616
17- static bool is_worktree_dir (git_buf * dir )
17+ static bool is_worktree_dir (const char * dir )
1818{
19- return git_path_contains_file (dir , "commondir" )
20- && git_path_contains_file (dir , "gitdir" )
21- && git_path_contains_file (dir , "HEAD" );
19+ git_buf buf = GIT_BUF_INIT ;
20+ int error ;
21+
22+ if (git_buf_sets (& buf , dir ) < 0 )
23+ return -1 ;
24+
25+ error = git_path_contains_file (& buf , "commondir" )
26+ && git_path_contains_file (& buf , "gitdir" )
27+ && git_path_contains_file (& buf , "HEAD" );
28+
29+ git_buf_free (& buf );
30+ return error ;
2231}
2332
2433int git_worktree_list (git_strarray * wts , git_repository * repo )
@@ -47,7 +56,7 @@ int git_worktree_list(git_strarray *wts, git_repository *repo)
4756 git_buf_truncate (& path , len );
4857 git_buf_puts (& path , worktree );
4958
50- if (!is_worktree_dir (& path )) {
59+ if (!is_worktree_dir (path . ptr )) {
5160 git_vector_remove (& worktrees , i );
5261 git__free (worktree );
5362 }
@@ -112,6 +121,46 @@ static int write_wtfile(const char *base, const char *file, const git_buf *buf)
112121 return err ;
113122}
114123
124+ static int open_worktree_dir (git_worktree * * out , const char * parent , const char * dir , const char * name )
125+ {
126+ git_buf gitdir = GIT_BUF_INIT ;
127+ git_worktree * wt = NULL ;
128+ int error = 0 ;
129+
130+ if (!is_worktree_dir (dir )) {
131+ error = -1 ;
132+ goto out ;
133+ }
134+
135+ if ((wt = git__calloc (1 , sizeof (struct git_repository ))) == NULL ) {
136+ error = -1 ;
137+ goto out ;
138+ }
139+
140+ if ((wt -> name = git__strdup (name )) == NULL
141+ || (wt -> commondir_path = git_worktree__read_link (dir , "commondir" )) == NULL
142+ || (wt -> gitlink_path = git_worktree__read_link (dir , "gitdir" )) == NULL
143+ || (wt -> parent_path = git__strdup (parent )) == NULL ) {
144+ error = -1 ;
145+ goto out ;
146+ }
147+
148+ if ((error = git_path_prettify_dir (& gitdir , dir , NULL )) < 0 )
149+ goto out ;
150+ wt -> gitdir_path = git_buf_detach (& gitdir );
151+
152+ wt -> locked = !!git_worktree_is_locked (NULL , wt );
153+
154+ * out = wt ;
155+
156+ out :
157+ if (error )
158+ git_worktree_free (wt );
159+ git_buf_free (& gitdir );
160+
161+ return error ;
162+ }
163+
115164int git_worktree_lookup (git_worktree * * out , git_repository * repo , const char * name )
116165{
117166 git_buf path = GIT_BUF_INIT ;
@@ -125,33 +174,47 @@ int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *na
125174 if ((error = git_buf_printf (& path , "%s/worktrees/%s" , repo -> commondir , name )) < 0 )
126175 goto out ;
127176
128- if (!is_worktree_dir (& path )) {
129- error = -1 ;
177+ if ((error = (open_worktree_dir (out , git_repository_workdir (repo ), path .ptr , name ))) < 0 )
130178 goto out ;
131- }
132179
133- if ((wt = git__malloc (sizeof (struct git_repository ))) == NULL ) {
180+ out :
181+ git_buf_free (& path );
182+
183+ if (error )
184+ git_worktree_free (wt );
185+
186+ return error ;
187+ }
188+
189+ int git_worktree_open_from_repository (git_worktree * * out , git_repository * repo )
190+ {
191+ git_buf parent = GIT_BUF_INIT ;
192+ const char * gitdir , * commondir ;
193+ char * name = NULL ;
194+ int error = 0 ;
195+
196+ if (!git_repository_is_worktree (repo )) {
197+ giterr_set (GITERR_WORKTREE , "cannot open worktree of a non-worktree repo" );
134198 error = -1 ;
135199 goto out ;
136200 }
137201
138- if ((wt -> name = git__strdup (name )) == NULL
139- || (wt -> commondir_path = git_worktree__read_link (path .ptr , "commondir" )) == NULL
140- || (wt -> gitlink_path = git_worktree__read_link (path .ptr , "gitdir" )) == NULL
141- || (wt -> parent_path = git__strdup (git_repository_path (repo ))) == NULL ) {
142- error = -1 ;
202+ gitdir = git_repository_path (repo );
203+ commondir = git_repository_commondir (repo );
204+
205+ if ((error = git_path_prettify_dir (& parent , ".." , commondir )) < 0 )
143206 goto out ;
144- }
145- wt -> gitdir_path = git_buf_detach (& path );
146- wt -> locked = !!git_worktree_is_locked (NULL , wt );
147207
148- (* out ) = wt ;
208+ /* The name is defined by the last component in '.git/worktree/%s' */
209+ name = git_path_basename (gitdir );
149210
150- out :
151- git_buf_free ( & path ) ;
211+ if (( error = open_worktree_dir ( out , parent . ptr , gitdir , name )) < 0 )
212+ goto out ;
152213
214+ out :
153215 if (error )
154- git_worktree_free (wt );
216+ free (name );
217+ git_buf_free (& parent );
155218
156219 return error ;
157220}
@@ -177,7 +240,7 @@ int git_worktree_validate(const git_worktree *wt)
177240 assert (wt );
178241
179242 git_buf_puts (& buf , wt -> gitdir_path );
180- if (!is_worktree_dir (& buf )) {
243+ if (!is_worktree_dir (buf . ptr )) {
181244 giterr_set (GITERR_WORKTREE ,
182245 "Worktree gitdir ('%s') is not valid" ,
183246 wt -> gitlink_path );
@@ -209,7 +272,7 @@ int git_worktree_validate(const git_worktree *wt)
209272
210273int git_worktree_add (git_worktree * * out , git_repository * repo , const char * name , const char * worktree )
211274{
212- git_buf path = GIT_BUF_INIT , buf = GIT_BUF_INIT ;
275+ git_buf gitdir = GIT_BUF_INIT , wddir = GIT_BUF_INIT , buf = GIT_BUF_INIT ;
213276 git_reference * ref = NULL , * head = NULL ;
214277 git_commit * commit = NULL ;
215278 git_repository * wt = NULL ;
@@ -220,35 +283,39 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
220283
221284 * out = NULL ;
222285
223- /* Create worktree related files in commondir */
224- if ((err = git_buf_joinpath (& path , repo -> commondir , "worktrees" )) < 0 )
286+ /* Create gitdir directory ".git/worktrees/<name>" */
287+ if ((err = git_buf_joinpath (& gitdir , repo -> commondir , "worktrees" )) < 0 )
225288 goto out ;
226- if (!git_path_exists (path .ptr ))
227- if ((err = git_futils_mkdir (path .ptr , 0755 , GIT_MKDIR_EXCL )) < 0 )
289+ if (!git_path_exists (gitdir .ptr ))
290+ if ((err = git_futils_mkdir (gitdir .ptr , 0755 , GIT_MKDIR_EXCL )) < 0 )
228291 goto out ;
229- if ((err = git_buf_joinpath (& path , path .ptr , name )) < 0 )
292+ if ((err = git_buf_joinpath (& gitdir , gitdir .ptr , name )) < 0 )
293+ goto out ;
294+ if ((err = git_futils_mkdir (gitdir .ptr , 0755 , GIT_MKDIR_EXCL )) < 0 )
230295 goto out ;
231- if ((err = git_futils_mkdir ( path .ptr , 0755 , GIT_MKDIR_EXCL )) < 0 )
296+ if ((err = git_path_prettify_dir ( & gitdir , gitdir .ptr , NULL )) < 0 )
232297 goto out ;
233298
234299 /* Create worktree work dir */
235300 if ((err = git_futils_mkdir (worktree , 0755 , GIT_MKDIR_EXCL )) < 0 )
236301 goto out ;
302+ if ((err = git_path_prettify_dir (& wddir , worktree , NULL )) < 0 )
303+ goto out ;
237304
238305 /* Create worktree .git file */
239- if ((err = git_buf_printf (& buf , "gitdir: %s\n" , path .ptr )) < 0 )
306+ if ((err = git_buf_printf (& buf , "gitdir: %s\n" , gitdir .ptr )) < 0 )
240307 goto out ;
241- if ((err = write_wtfile (worktree , ".git" , & buf )) < 0 )
308+ if ((err = write_wtfile (wddir . ptr , ".git" , & buf )) < 0 )
242309 goto out ;
243310
244- /* Create commondir files */
245- if ((err = git_buf_sets (& buf , repo -> commondir )) < 0
311+ /* Create gitdir files */
312+ if ((err = git_path_prettify_dir (& buf , repo -> commondir , NULL ) < 0 )
246313 || (err = git_buf_putc (& buf , '\n' )) < 0
247- || (err = write_wtfile (path .ptr , "commondir" , & buf )) < 0 )
314+ || (err = write_wtfile (gitdir .ptr , "commondir" , & buf )) < 0 )
248315 goto out ;
249- if ((err = git_buf_joinpath (& buf , worktree , ".git" )) < 0
316+ if ((err = git_buf_joinpath (& buf , wddir . ptr , ".git" )) < 0
250317 || (err = git_buf_putc (& buf , '\n' )) < 0
251- || (err = write_wtfile (path .ptr , "gitdir" , & buf )) < 0 )
318+ || (err = write_wtfile (gitdir .ptr , "gitdir" , & buf )) < 0 )
252319 goto out ;
253320
254321 /* Create new branch */
@@ -260,9 +327,9 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
260327 goto out ;
261328
262329 /* Set worktree's HEAD */
263- if ((err = git_repository_create_head (path .ptr , name )) < 0 )
330+ if ((err = git_repository_create_head (gitdir .ptr , git_reference_name ( ref ) )) < 0 )
264331 goto out ;
265- if ((err = git_repository_open (& wt , worktree )) < 0 )
332+ if ((err = git_repository_open (& wt , wddir . ptr )) < 0 )
266333 goto out ;
267334
268335 /* Checkout worktree's HEAD */
@@ -275,7 +342,8 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
275342 goto out ;
276343
277344out :
278- git_buf_free (& path );
345+ git_buf_free (& gitdir );
346+ git_buf_free (& wddir );
279347 git_buf_free (& buf );
280348 git_reference_free (ref );
281349 git_reference_free (head );
@@ -394,7 +462,7 @@ int git_worktree_prune(git_worktree *wt, unsigned flags)
394462 }
395463
396464 /* Delete gitdir in parent repository */
397- if ((err = git_buf_printf (& path , "%s/worktrees/%s" , wt -> parent_path , wt -> name )) < 0 )
465+ if ((err = git_buf_printf (& path , "%s/worktrees/%s" , wt -> commondir_path , wt -> name )) < 0 )
398466 goto out ;
399467 if (!git_path_exists (path .ptr ))
400468 {
0 commit comments