rugged 0.26.0b3 → 0.26.0b4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/ext/rugged/extconf.rb +10 -7
  4. data/ext/rugged/rugged.c +4 -6
  5. data/ext/rugged/rugged_repo.c +1 -1
  6. data/ext/rugged/rugged_revwalk.c +4 -4
  7. data/ext/rugged/rugged_tree.c +2 -2
  8. data/lib/rugged/version.rb +1 -1
  9. data/vendor/libgit2/CMakeLists.txt +13 -6
  10. data/vendor/libgit2/COPYING +33 -0
  11. data/vendor/libgit2/include/git2/branch.h +12 -0
  12. data/vendor/libgit2/include/git2/commit.h +6 -3
  13. data/vendor/libgit2/include/git2/common.h +11 -0
  14. data/vendor/libgit2/include/git2/errors.h +2 -0
  15. data/vendor/libgit2/include/git2/index.h +7 -6
  16. data/vendor/libgit2/include/git2/repository.h +91 -0
  17. data/vendor/libgit2/include/git2/stash.h +2 -2
  18. data/vendor/libgit2/include/git2/types.h +3 -0
  19. data/vendor/libgit2/include/git2/worktree.h +161 -0
  20. data/vendor/libgit2/src/attr.c +24 -16
  21. data/vendor/libgit2/src/attr_file.h +1 -1
  22. data/vendor/libgit2/src/attrcache.c +11 -10
  23. data/vendor/libgit2/src/attrcache.h +1 -4
  24. data/vendor/libgit2/src/blob.c +2 -2
  25. data/vendor/libgit2/src/branch.c +63 -0
  26. data/vendor/libgit2/src/buffer.h +2 -1
  27. data/vendor/libgit2/src/cache.c +21 -25
  28. data/vendor/libgit2/src/cache.h +1 -1
  29. data/vendor/libgit2/src/checkout.c +0 -2
  30. data/vendor/libgit2/src/cherrypick.c +2 -2
  31. data/vendor/libgit2/src/clone.c +2 -3
  32. data/vendor/libgit2/src/commit.c +8 -4
  33. data/vendor/libgit2/src/config_file.c +1 -3
  34. data/vendor/libgit2/src/describe.c +1 -3
  35. data/vendor/libgit2/src/diff_driver.c +2 -4
  36. data/vendor/libgit2/src/fetchhead.c +2 -2
  37. data/vendor/libgit2/src/fileops.c +1 -3
  38. data/vendor/libgit2/src/hash.h +5 -3
  39. data/vendor/libgit2/src/hash/hash_collisiondetect.h +57 -0
  40. data/vendor/libgit2/src/hash/sha1dc/sha1.c +1149 -0
  41. data/vendor/libgit2/src/hash/sha1dc/sha1.h +94 -0
  42. data/vendor/libgit2/src/hash/sha1dc/ubc_check.c +361 -0
  43. data/vendor/libgit2/src/hash/sha1dc/ubc_check.h +35 -0
  44. data/vendor/libgit2/src/idxmap.c +133 -0
  45. data/vendor/libgit2/src/idxmap.h +22 -60
  46. data/vendor/libgit2/src/ignore.c +7 -1
  47. data/vendor/libgit2/src/ignore.h +1 -1
  48. data/vendor/libgit2/src/index.c +11 -14
  49. data/vendor/libgit2/src/indexer.c +8 -11
  50. data/vendor/libgit2/src/merge.c +5 -5
  51. data/vendor/libgit2/src/mwindow.c +1 -3
  52. data/vendor/libgit2/src/odb.c +3 -3
  53. data/vendor/libgit2/src/odb.h +3 -0
  54. data/vendor/libgit2/src/odb_mempack.c +11 -18
  55. data/vendor/libgit2/src/offmap.c +83 -0
  56. data/vendor/libgit2/src/offmap.h +14 -34
  57. data/vendor/libgit2/src/oidmap.c +105 -0
  58. data/vendor/libgit2/src/oidmap.h +19 -22
  59. data/vendor/libgit2/src/pack-objects.c +10 -13
  60. data/vendor/libgit2/src/pack.c +17 -26
  61. data/vendor/libgit2/src/path.c +45 -24
  62. data/vendor/libgit2/src/rebase.c +3 -3
  63. data/vendor/libgit2/src/refdb_fs.c +81 -46
  64. data/vendor/libgit2/src/refs.c +13 -3
  65. data/vendor/libgit2/src/remote.c +6 -2
  66. data/vendor/libgit2/src/repository.c +318 -46
  67. data/vendor/libgit2/src/repository.h +5 -2
  68. data/vendor/libgit2/src/revert.c +2 -2
  69. data/vendor/libgit2/src/revwalk.c +6 -8
  70. data/vendor/libgit2/src/settings.c +5 -0
  71. data/vendor/libgit2/src/sortedcache.c +3 -5
  72. data/vendor/libgit2/src/strmap.c +95 -0
  73. data/vendor/libgit2/src/strmap.h +17 -37
  74. data/vendor/libgit2/src/submodule.c +12 -8
  75. data/vendor/libgit2/src/thread-utils.h +6 -0
  76. data/vendor/libgit2/src/transaction.c +5 -17
  77. data/vendor/libgit2/src/transports/local.c +2 -1
  78. data/vendor/libgit2/src/transports/smart.h +2 -0
  79. data/vendor/libgit2/src/transports/smart_protocol.c +3 -1
  80. data/vendor/libgit2/src/tree.c +2 -4
  81. data/vendor/libgit2/src/unix/posix.h +1 -1
  82. data/vendor/libgit2/src/worktree.c +432 -0
  83. data/vendor/libgit2/src/worktree.h +35 -0
  84. metadata +13 -2
@@ -26,6 +26,8 @@
26
26
  #define GIT_CAP_THIN_PACK "thin-pack"
27
27
  #define GIT_CAP_SYMREF "symref"
28
28
 
29
+ extern bool git_smart__ofs_delta_enabled;
30
+
29
31
  enum git_pkt_type {
30
32
  GIT_PKT_CMD,
31
33
  GIT_PKT_FLUSH,
@@ -19,6 +19,8 @@
19
19
  /* The minimal interval between progress updates (in seconds). */
20
20
  #define MIN_PROGRESS_UPDATE_INTERVAL 0.5
21
21
 
22
+ bool git_smart__ofs_delta_enabled = true;
23
+
22
24
  int git_smart__store_refs(transport_smart *t, int flushes)
23
25
  {
24
26
  gitno_buffer *buf = &t->buffer;
@@ -138,7 +140,7 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
138
140
  if (*ptr == ' ')
139
141
  ptr++;
140
142
 
141
- if (!git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
143
+ if (git_smart__ofs_delta_enabled && !git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
142
144
  caps->common = caps->ofs_delta = 1;
143
145
  ptr += strlen(GIT_CAP_OFS_DELTA);
144
146
  continue;
@@ -20,8 +20,6 @@
20
20
  #define TREE_ENTRY_CHECK_NAMELEN(n) \
21
21
  if (n > UINT16_MAX) { giterr_set(GITERR_INVALID, "tree entry path too long"); }
22
22
 
23
- GIT__USE_STRMAP
24
-
25
23
  static bool valid_filemode(const int filemode)
26
24
  {
27
25
  return (filemode == GIT_FILEMODE_TREE
@@ -505,7 +503,7 @@ static int append_entry(
505
503
 
506
504
  entry->attr = (uint16_t)filemode;
507
505
 
508
- git_strmap_insert(bld->map, entry->filename, entry, error);
506
+ git_strmap_insert(bld->map, entry->filename, entry, &error);
509
507
  if (error < 0) {
510
508
  git_tree_entry_free(entry);
511
509
  giterr_set(GITERR_TREE, "failed to append entry %s to the tree builder", filename);
@@ -754,7 +752,7 @@ int git_treebuilder_insert(
754
752
  entry = alloc_entry(filename, strlen(filename), id);
755
753
  GITERR_CHECK_ALLOC(entry);
756
754
 
757
- git_strmap_insert(bld->map, entry->filename, entry, error);
755
+ git_strmap_insert(bld->map, entry->filename, entry, &error);
758
756
 
759
757
  if (error < 0) {
760
758
  git_tree_entry_free(entry);
@@ -50,7 +50,7 @@ extern char *p_realpath(const char *, char *);
50
50
  #define p_strcasecmp(s1, s2) strcasecmp(s1, s2)
51
51
  #define p_strncasecmp(s1, s2, c) strncasecmp(s1, s2, c)
52
52
  #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a)
53
- #define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__)
53
+ #define p_snprintf(b, c, ...) snprintf(b, c, __VA_ARGS__)
54
54
  #define p_mkstemp(p) mkstemp(p)
55
55
  #define p_chdir(p) chdir(p)
56
56
  #define p_chmod(p,m) chmod(p, m)
@@ -0,0 +1,432 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #include "common.h"
9
+
10
+ #include "git2/branch.h"
11
+ #include "git2/commit.h"
12
+ #include "git2/worktree.h"
13
+
14
+ #include "repository.h"
15
+ #include "worktree.h"
16
+
17
+ static bool is_worktree_dir(git_buf *dir)
18
+ {
19
+ return git_path_contains_file(dir, "commondir")
20
+ && git_path_contains_file(dir, "gitdir")
21
+ && git_path_contains_file(dir, "HEAD");
22
+ }
23
+
24
+ int git_worktree_list(git_strarray *wts, git_repository *repo)
25
+ {
26
+ git_vector worktrees = GIT_VECTOR_INIT;
27
+ git_buf path = GIT_BUF_INIT;
28
+ char *worktree;
29
+ unsigned i, len;
30
+ int error;
31
+
32
+ assert(wts && repo);
33
+
34
+ wts->count = 0;
35
+ wts->strings = NULL;
36
+
37
+ if ((error = git_buf_printf(&path, "%s/worktrees/", repo->commondir)) < 0)
38
+ goto exit;
39
+ if (!git_path_exists(path.ptr) || git_path_is_empty_dir(path.ptr))
40
+ goto exit;
41
+ if ((error = git_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0)
42
+ goto exit;
43
+
44
+ len = path.size;
45
+
46
+ git_vector_foreach(&worktrees, i, worktree) {
47
+ git_buf_truncate(&path, len);
48
+ git_buf_puts(&path, worktree);
49
+
50
+ if (!is_worktree_dir(&path)) {
51
+ git_vector_remove(&worktrees, i);
52
+ git__free(worktree);
53
+ }
54
+ }
55
+
56
+ wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees);
57
+
58
+ exit:
59
+ git_buf_free(&path);
60
+
61
+ return error;
62
+ }
63
+
64
+ char *git_worktree__read_link(const char *base, const char *file)
65
+ {
66
+ git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
67
+
68
+ assert(base && file);
69
+
70
+ if (git_buf_joinpath(&path, base, file) < 0)
71
+ goto err;
72
+ if (git_futils_readbuffer(&buf, path.ptr) < 0)
73
+ goto err;
74
+ git_buf_free(&path);
75
+
76
+ git_buf_rtrim(&buf);
77
+
78
+ if (!git_path_is_relative(buf.ptr))
79
+ return git_buf_detach(&buf);
80
+
81
+ if (git_buf_sets(&path, base) < 0)
82
+ goto err;
83
+ if (git_path_apply_relative(&path, buf.ptr) < 0)
84
+ goto err;
85
+ git_buf_free(&buf);
86
+
87
+ return git_buf_detach(&path);
88
+
89
+ err:
90
+ git_buf_free(&buf);
91
+ git_buf_free(&path);
92
+
93
+ return NULL;
94
+ }
95
+
96
+ static int write_wtfile(const char *base, const char *file, const git_buf *buf)
97
+ {
98
+ git_buf path = GIT_BUF_INIT;
99
+ int err;
100
+
101
+ assert(base && file && buf);
102
+
103
+ if ((err = git_buf_joinpath(&path, base, file)) < 0)
104
+ goto out;
105
+
106
+ if ((err = git_futils_writebuffer(buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
107
+ goto out;
108
+
109
+ out:
110
+ git_buf_free(&path);
111
+
112
+ return err;
113
+ }
114
+
115
+ int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name)
116
+ {
117
+ git_buf path = GIT_BUF_INIT;
118
+ git_worktree *wt = NULL;
119
+ int error;
120
+
121
+ assert(repo && name);
122
+
123
+ *out = NULL;
124
+
125
+ if ((error = git_buf_printf(&path, "%s/worktrees/%s", repo->commondir, name)) < 0)
126
+ goto out;
127
+
128
+ if (!is_worktree_dir(&path)) {
129
+ error = -1;
130
+ goto out;
131
+ }
132
+
133
+ if ((wt = git__malloc(sizeof(struct git_repository))) == NULL) {
134
+ error = -1;
135
+ goto out;
136
+ }
137
+
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;
143
+ goto out;
144
+ }
145
+ wt->gitdir_path = git_buf_detach(&path);
146
+ wt->locked = !!git_worktree_is_locked(NULL, wt);
147
+
148
+ (*out) = wt;
149
+
150
+ out:
151
+ git_buf_free(&path);
152
+
153
+ if (error)
154
+ git_worktree_free(wt);
155
+
156
+ return error;
157
+ }
158
+
159
+ void git_worktree_free(git_worktree *wt)
160
+ {
161
+ if (!wt)
162
+ return;
163
+
164
+ git__free(wt->commondir_path);
165
+ git__free(wt->gitlink_path);
166
+ git__free(wt->gitdir_path);
167
+ git__free(wt->parent_path);
168
+ git__free(wt->name);
169
+ git__free(wt);
170
+ }
171
+
172
+ int git_worktree_validate(const git_worktree *wt)
173
+ {
174
+ git_buf buf = GIT_BUF_INIT;
175
+ int err = 0;
176
+
177
+ assert(wt);
178
+
179
+ git_buf_puts(&buf, wt->gitdir_path);
180
+ if (!is_worktree_dir(&buf)) {
181
+ giterr_set(GITERR_WORKTREE,
182
+ "Worktree gitdir ('%s') is not valid",
183
+ wt->gitlink_path);
184
+ err = -1;
185
+ goto out;
186
+ }
187
+
188
+ if (!git_path_exists(wt->parent_path)) {
189
+ giterr_set(GITERR_WORKTREE,
190
+ "Worktree parent directory ('%s') does not exist ",
191
+ wt->parent_path);
192
+ err = -2;
193
+ goto out;
194
+ }
195
+
196
+ if (!git_path_exists(wt->commondir_path)) {
197
+ giterr_set(GITERR_WORKTREE,
198
+ "Worktree common directory ('%s') does not exist ",
199
+ wt->commondir_path);
200
+ err = -3;
201
+ goto out;
202
+ }
203
+
204
+ out:
205
+ git_buf_free(&buf);
206
+
207
+ return err;
208
+ }
209
+
210
+ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree)
211
+ {
212
+ git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
213
+ git_reference *ref = NULL, *head = NULL;
214
+ git_commit *commit = NULL;
215
+ git_repository *wt = NULL;
216
+ git_checkout_options coopts = GIT_CHECKOUT_OPTIONS_INIT;
217
+ int err;
218
+
219
+ assert(out && repo && name && worktree);
220
+
221
+ *out = NULL;
222
+
223
+ /* Create worktree related files in commondir */
224
+ if ((err = git_buf_joinpath(&path, repo->commondir, "worktrees")) < 0)
225
+ goto out;
226
+ if (!git_path_exists(path.ptr))
227
+ if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
228
+ goto out;
229
+ if ((err = git_buf_joinpath(&path, path.ptr, name)) < 0)
230
+ goto out;
231
+ if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
232
+ goto out;
233
+
234
+ /* Create worktree work dir */
235
+ if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0)
236
+ goto out;
237
+
238
+ /* Create worktree .git file */
239
+ if ((err = git_buf_printf(&buf, "gitdir: %s\n", path.ptr)) < 0)
240
+ goto out;
241
+ if ((err = write_wtfile(worktree, ".git", &buf)) < 0)
242
+ goto out;
243
+
244
+ /* Create commondir files */
245
+ if ((err = git_buf_sets(&buf, repo->commondir)) < 0
246
+ || (err = git_buf_putc(&buf, '\n')) < 0
247
+ || (err = write_wtfile(path.ptr, "commondir", &buf)) < 0)
248
+ goto out;
249
+ if ((err = git_buf_joinpath(&buf, worktree, ".git")) < 0
250
+ || (err = git_buf_putc(&buf, '\n')) < 0
251
+ || (err = write_wtfile(path.ptr, "gitdir", &buf)) < 0)
252
+ goto out;
253
+
254
+ /* Create new branch */
255
+ if ((err = git_repository_head(&head, repo)) < 0)
256
+ goto out;
257
+ if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0)
258
+ goto out;
259
+ if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0)
260
+ goto out;
261
+
262
+ /* Set worktree's HEAD */
263
+ if ((err = git_repository_create_head(path.ptr, name)) < 0)
264
+ goto out;
265
+ if ((err = git_repository_open(&wt, worktree)) < 0)
266
+ goto out;
267
+
268
+ /* Checkout worktree's HEAD */
269
+ coopts.checkout_strategy = GIT_CHECKOUT_FORCE;
270
+ if ((err = git_checkout_head(wt, &coopts)) < 0)
271
+ goto out;
272
+
273
+ /* Load result */
274
+ if ((err = git_worktree_lookup(out, repo, name)) < 0)
275
+ goto out;
276
+
277
+ out:
278
+ git_buf_free(&path);
279
+ git_buf_free(&buf);
280
+ git_reference_free(ref);
281
+ git_reference_free(head);
282
+ git_commit_free(commit);
283
+ git_repository_free(wt);
284
+
285
+ return err;
286
+ }
287
+
288
+ int git_worktree_lock(git_worktree *wt, char *creason)
289
+ {
290
+ git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
291
+ int err;
292
+
293
+ assert(wt);
294
+
295
+ if ((err = git_worktree_is_locked(NULL, wt)) < 0)
296
+ goto out;
297
+
298
+ if ((err = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
299
+ goto out;
300
+
301
+ if (creason)
302
+ git_buf_attach_notowned(&buf, creason, strlen(creason));
303
+
304
+ if ((err = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
305
+ goto out;
306
+
307
+ wt->locked = 1;
308
+
309
+ out:
310
+ git_buf_free(&path);
311
+
312
+ return err;
313
+ }
314
+
315
+ int git_worktree_unlock(git_worktree *wt)
316
+ {
317
+ git_buf path = GIT_BUF_INIT;
318
+
319
+ assert(wt);
320
+
321
+ if (!git_worktree_is_locked(NULL, wt))
322
+ return 0;
323
+
324
+ if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0)
325
+ return -1;
326
+
327
+ if (p_unlink(path.ptr) != 0) {
328
+ git_buf_free(&path);
329
+ return -1;
330
+ }
331
+
332
+ wt->locked = 0;
333
+
334
+ git_buf_free(&path);
335
+
336
+ return 0;
337
+ }
338
+
339
+ int git_worktree_is_locked(git_buf *reason, const git_worktree *wt)
340
+ {
341
+ git_buf path = GIT_BUF_INIT;
342
+ int ret;
343
+
344
+ assert(wt);
345
+
346
+ if (reason)
347
+ git_buf_clear(reason);
348
+
349
+ if ((ret = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
350
+ goto out;
351
+ if ((ret = git_path_exists(path.ptr)) && reason)
352
+ git_futils_readbuffer(reason, path.ptr);
353
+
354
+ out:
355
+ git_buf_free(&path);
356
+
357
+ return ret;
358
+ }
359
+
360
+ int git_worktree_is_prunable(git_worktree *wt, unsigned flags)
361
+ {
362
+ git_buf reason = GIT_BUF_INIT;
363
+
364
+ if ((flags & GIT_WORKTREE_PRUNE_LOCKED) == 0 &&
365
+ git_worktree_is_locked(&reason, wt))
366
+ {
367
+ if (!reason.size)
368
+ git_buf_attach_notowned(&reason, "no reason given", 15);
369
+ giterr_set(GITERR_WORKTREE, "Not pruning locked working tree: '%s'", reason.ptr);
370
+ git_buf_free(&reason);
371
+
372
+ return 0;
373
+ }
374
+
375
+ if ((flags & GIT_WORKTREE_PRUNE_VALID) == 0 &&
376
+ git_worktree_validate(wt) == 0)
377
+ {
378
+ giterr_set(GITERR_WORKTREE, "Not pruning valid working tree");
379
+ return 0;
380
+ }
381
+
382
+ return 1;
383
+ }
384
+
385
+ int git_worktree_prune(git_worktree *wt, unsigned flags)
386
+ {
387
+ git_buf path = GIT_BUF_INIT;
388
+ char *wtpath;
389
+ int err;
390
+
391
+ if (!git_worktree_is_prunable(wt, flags)) {
392
+ err = -1;
393
+ goto out;
394
+ }
395
+
396
+ /* Delete gitdir in parent repository */
397
+ if ((err = git_buf_printf(&path, "%s/worktrees/%s", wt->parent_path, wt->name)) < 0)
398
+ goto out;
399
+ if (!git_path_exists(path.ptr))
400
+ {
401
+ giterr_set(GITERR_WORKTREE, "Worktree gitdir '%s' does not exist", path.ptr);
402
+ err = -1;
403
+ goto out;
404
+ }
405
+ if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0)
406
+ goto out;
407
+
408
+ /* Skip deletion of the actual working tree if it does
409
+ * not exist or deletion was not requested */
410
+ if ((flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 ||
411
+ !git_path_exists(wt->gitlink_path))
412
+ {
413
+ goto out;
414
+ }
415
+
416
+ if ((wtpath = git_path_dirname(wt->gitlink_path)) == NULL)
417
+ goto out;
418
+ git_buf_attach(&path, wtpath, 0);
419
+ if (!git_path_exists(path.ptr))
420
+ {
421
+ giterr_set(GITERR_WORKTREE, "Working tree '%s' does not exist", path.ptr);
422
+ err = -1;
423
+ goto out;
424
+ }
425
+ if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0)
426
+ goto out;
427
+
428
+ out:
429
+ git_buf_free(&path);
430
+
431
+ return err;
432
+ }