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,8 +26,6 @@
26
26
 
27
27
  bool git_reference__enable_symbolic_ref_target_validation = true;
28
28
 
29
- GIT__USE_STRMAP
30
-
31
29
  #define DEFAULT_NESTING_LEVEL 5
32
30
  #define MAX_NESTING_LEVEL 10
33
31
 
@@ -1132,6 +1130,18 @@ int git_reference__update_terminal(
1132
1130
  return error;
1133
1131
  }
1134
1132
 
1133
+ static const char *commit_type(const git_commit *commit)
1134
+ {
1135
+ unsigned int count = git_commit_parentcount(commit);
1136
+
1137
+ if (count >= 2)
1138
+ return " (merge)";
1139
+ else if (count == 0)
1140
+ return " (initial)";
1141
+ else
1142
+ return "";
1143
+ }
1144
+
1135
1145
  int git_reference__update_for_commit(
1136
1146
  git_repository *repo,
1137
1147
  git_reference *ref,
@@ -1148,7 +1158,7 @@ int git_reference__update_for_commit(
1148
1158
  if ((error = git_commit_lookup(&commit, repo, id)) < 0 ||
1149
1159
  (error = git_buf_printf(&reflog_msg, "%s%s: %s",
1150
1160
  operation ? operation : "commit",
1151
- git_commit_parentcount(commit) == 0 ? " (initial)" : "",
1161
+ commit_type(commit),
1152
1162
  git_commit_summary(commit))) < 0)
1153
1163
  goto done;
1154
1164
 
@@ -770,8 +770,12 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur
770
770
  goto found;
771
771
  }
772
772
 
773
- /* HTTP_PROXY / HTTPS_PROXY environment variables */
774
- error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
773
+ /* http_proxy / https_proxy environment variables */
774
+ error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy");
775
+
776
+ /* try uppercase environment variables */
777
+ if (error == GIT_ENOTFOUND)
778
+ error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
775
779
 
776
780
  if (error < 0) {
777
781
  if (error == GIT_ENOTFOUND) {
@@ -28,16 +28,40 @@
28
28
  #include "diff_driver.h"
29
29
  #include "annotated_commit.h"
30
30
  #include "submodule.h"
31
+ #include "worktree.h"
31
32
 
32
- GIT__USE_STRMAP
33
33
  #include "strmap.h"
34
34
 
35
35
  #ifdef GIT_WIN32
36
36
  # include "win32/w32_util.h"
37
37
  #endif
38
38
 
39
+ static const struct {
40
+ git_repository_item_t parent;
41
+ const char *name;
42
+ bool directory;
43
+ } items[] = {
44
+ { GIT_REPOSITORY_ITEM_GITDIR, NULL, true },
45
+ { GIT_REPOSITORY_ITEM_WORKDIR, NULL, true },
46
+ { GIT_REPOSITORY_ITEM_COMMONDIR, NULL, true },
47
+ { GIT_REPOSITORY_ITEM_GITDIR, "index", false },
48
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "objects", true },
49
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "refs", true },
50
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "packed-refs", false },
51
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "remotes", true },
52
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "config", false },
53
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "info", true },
54
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "hooks", true },
55
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "logs", true },
56
+ { GIT_REPOSITORY_ITEM_GITDIR, "modules", true },
57
+ { GIT_REPOSITORY_ITEM_COMMONDIR, "worktrees", true }
58
+ };
59
+
39
60
  static int check_repositoryformatversion(git_config *config);
40
61
 
62
+ #define GIT_COMMONDIR_FILE "commondir"
63
+ #define GIT_GITDIR_FILE "gitdir"
64
+
41
65
  #define GIT_FILE_CONTENT_PREFIX "gitdir:"
42
66
 
43
67
  #define GIT_BRANCH_MASTER "master"
@@ -141,8 +165,9 @@ void git_repository_free(git_repository *repo)
141
165
  git_buf_free(git_array_get(repo->reserved_names, i));
142
166
  git_array_clear(repo->reserved_names);
143
167
 
144
- git__free(repo->path_gitlink);
145
- git__free(repo->path_repository);
168
+ git__free(repo->gitlink);
169
+ git__free(repo->gitdir);
170
+ git__free(repo->commondir);
146
171
  git__free(repo->workdir);
147
172
  git__free(repo->namespace);
148
173
  git__free(repo->ident_name);
@@ -157,17 +182,41 @@ void git_repository_free(git_repository *repo)
157
182
  *
158
183
  * Open a repository object from its path
159
184
  */
160
- static bool valid_repository_path(git_buf *repository_path)
185
+ static bool valid_repository_path(git_buf *repository_path, git_buf *common_path)
161
186
  {
162
- /* Check OBJECTS_DIR first, since it will generate the longest path name */
163
- if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) == false)
164
- return false;
187
+ /* Check if we have a separate commondir (e.g. we have a
188
+ * worktree) */
189
+ if (git_path_contains_file(repository_path, GIT_COMMONDIR_FILE)) {
190
+ git_buf common_link = GIT_BUF_INIT;
191
+ git_buf_joinpath(&common_link, repository_path->ptr, GIT_COMMONDIR_FILE);
192
+
193
+ git_futils_readbuffer(&common_link, common_link.ptr);
194
+ git_buf_rtrim(&common_link);
195
+
196
+ if (git_path_is_relative(common_link.ptr)) {
197
+ git_buf_joinpath(common_path, repository_path->ptr, common_link.ptr);
198
+ } else {
199
+ git_buf_swap(common_path, &common_link);
200
+ }
201
+
202
+ git_buf_free(&common_link);
203
+ }
204
+ else {
205
+ git_buf_set(common_path, repository_path->ptr, repository_path->size);
206
+ }
207
+
208
+ /* Make sure the commondir path always has a trailing * slash */
209
+ if (git_buf_rfind(common_path, '/') != (ssize_t)common_path->size - 1)
210
+ git_buf_putc(common_path, '/');
165
211
 
166
212
  /* Ensure HEAD file exists */
167
213
  if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false)
168
214
  return false;
169
215
 
170
- if (git_path_contains_dir(repository_path, GIT_REFS_DIR) == false)
216
+ /* Check files in common dir */
217
+ if (git_path_contains_dir(common_path, GIT_OBJECTS_DIR) == false)
218
+ return false;
219
+ if (git_path_contains_dir(common_path, GIT_REFS_DIR) == false)
171
220
  return false;
172
221
 
173
222
  return true;
@@ -206,6 +255,7 @@ int git_repository_new(git_repository **out)
206
255
  GITERR_CHECK_ALLOC(repo);
207
256
 
208
257
  repo->is_bare = 1;
258
+ repo->is_worktree = 0;
209
259
 
210
260
  return 0;
211
261
  }
@@ -225,9 +275,10 @@ static int load_config_data(git_repository *repo, const git_config *config)
225
275
 
226
276
  static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path)
227
277
  {
228
- int error;
278
+ int error;
229
279
  git_config_entry *ce;
230
- git_buf worktree = GIT_BUF_INIT;
280
+ git_buf worktree = GIT_BUF_INIT;
281
+ git_buf path = GIT_BUF_INIT;
231
282
 
232
283
  if (repo->is_bare)
233
284
  return 0;
@@ -236,9 +287,26 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
236
287
  &ce, config, "core.worktree", false)) < 0)
237
288
  return error;
238
289
 
239
- if (ce && ce->value) {
290
+ if (repo->is_worktree) {
291
+ char *gitlink = git_worktree__read_link(repo->gitdir, GIT_GITDIR_FILE);
292
+ if (!gitlink) {
293
+ error = -1;
294
+ goto cleanup;
295
+ }
296
+
297
+ git_buf_attach(&worktree, gitlink, 0);
298
+
299
+ if ((git_path_dirname_r(&worktree, worktree.ptr)) < 0 ||
300
+ git_path_to_dir(&worktree) < 0) {
301
+ error = -1;
302
+ goto cleanup;
303
+ }
304
+
305
+ repo->workdir = git_buf_detach(&worktree);
306
+ }
307
+ else if (ce && ce->value) {
240
308
  if ((error = git_path_prettify_dir(
241
- &worktree, ce->value, repo->path_repository)) < 0)
309
+ &worktree, ce->value, repo->gitdir)) < 0)
242
310
  goto cleanup;
243
311
 
244
312
  repo->workdir = git_buf_detach(&worktree);
@@ -246,7 +314,7 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
246
314
  else if (parent_path && git_path_isdir(parent_path->ptr))
247
315
  repo->workdir = git_buf_detach(parent_path);
248
316
  else {
249
- if (git_path_dirname_r(&worktree, repo->path_repository) < 0 ||
317
+ if (git_path_dirname_r(&worktree, repo->gitdir) < 0 ||
250
318
  git_path_to_dir(&worktree) < 0) {
251
319
  error = -1;
252
320
  goto cleanup;
@@ -257,6 +325,7 @@ static int load_workdir(git_repository *repo, git_config *config, git_buf *paren
257
325
 
258
326
  GITERR_CHECK_ALLOC(repo->workdir);
259
327
  cleanup:
328
+ git_buf_free(&path);
260
329
  git_config_entry_free(ce);
261
330
  return error;
262
331
  }
@@ -356,6 +425,7 @@ static int find_repo(
356
425
  git_buf *repo_path,
357
426
  git_buf *parent_path,
358
427
  git_buf *link_path,
428
+ git_buf *common_path,
359
429
  const char *start_path,
360
430
  uint32_t flags,
361
431
  const char *ceiling_dirs)
@@ -363,6 +433,7 @@ static int find_repo(
363
433
  int error;
364
434
  git_buf path = GIT_BUF_INIT;
365
435
  git_buf repo_link = GIT_BUF_INIT;
436
+ git_buf common_link = GIT_BUF_INIT;
366
437
  struct stat st;
367
438
  dev_t initial_device = 0;
368
439
  int min_iterations;
@@ -409,9 +480,16 @@ static int find_repo(
409
480
  break;
410
481
 
411
482
  if (S_ISDIR(st.st_mode)) {
412
- if (valid_repository_path(&path)) {
483
+ if (valid_repository_path(&path, &common_link)) {
413
484
  git_path_to_dir(&path);
414
485
  git_buf_set(repo_path, path.ptr, path.size);
486
+
487
+ if (link_path)
488
+ git_buf_attach(link_path,
489
+ git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0);
490
+ if (common_path)
491
+ git_buf_swap(&common_link, common_path);
492
+
415
493
  break;
416
494
  }
417
495
  }
@@ -419,11 +497,13 @@ static int find_repo(
419
497
  error = read_gitfile(&repo_link, path.ptr);
420
498
  if (error < 0)
421
499
  break;
422
- if (valid_repository_path(&repo_link)) {
500
+ if (valid_repository_path(&repo_link, &common_link)) {
423
501
  git_buf_swap(repo_path, &repo_link);
424
502
 
425
503
  if (link_path)
426
504
  error = git_buf_put(link_path, path.ptr, path.size);
505
+ if (common_path)
506
+ git_buf_swap(&common_link, common_path);
427
507
  }
428
508
  break;
429
509
  }
@@ -470,6 +550,7 @@ static int find_repo(
470
550
 
471
551
  git_buf_free(&path);
472
552
  git_buf_free(&repo_link);
553
+ git_buf_free(&common_link);
473
554
  return error;
474
555
  }
475
556
 
@@ -478,14 +559,15 @@ int git_repository_open_bare(
478
559
  const char *bare_path)
479
560
  {
480
561
  int error;
481
- git_buf path = GIT_BUF_INIT;
562
+ git_buf path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
482
563
  git_repository *repo = NULL;
483
564
 
484
565
  if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0)
485
566
  return error;
486
567
 
487
- if (!valid_repository_path(&path)) {
568
+ if (!valid_repository_path(&path, &common_path)) {
488
569
  git_buf_free(&path);
570
+ git_buf_free(&common_path);
489
571
  giterr_set(GITERR_REPOSITORY, "path is not a repository: %s", bare_path);
490
572
  return GIT_ENOTFOUND;
491
573
  }
@@ -493,11 +575,14 @@ int git_repository_open_bare(
493
575
  repo = repository_alloc();
494
576
  GITERR_CHECK_ALLOC(repo);
495
577
 
496
- repo->path_repository = git_buf_detach(&path);
497
- GITERR_CHECK_ALLOC(repo->path_repository);
578
+ repo->gitdir = git_buf_detach(&path);
579
+ GITERR_CHECK_ALLOC(repo->gitdir);
580
+ repo->commondir = git_buf_detach(&common_path);
581
+ GITERR_CHECK_ALLOC(repo->commondir);
498
582
 
499
583
  /* of course we're bare! */
500
584
  repo->is_bare = 1;
585
+ repo->is_worktree = 0;
501
586
  repo->workdir = NULL;
502
587
 
503
588
  *repo_ptr = repo;
@@ -681,7 +766,7 @@ int git_repository_open_ext(
681
766
  {
682
767
  int error;
683
768
  git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT,
684
- link_path = GIT_BUF_INIT;
769
+ link_path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
685
770
  git_repository *repo;
686
771
  git_config *config = NULL;
687
772
 
@@ -692,7 +777,7 @@ int git_repository_open_ext(
692
777
  *repo_ptr = NULL;
693
778
 
694
779
  error = find_repo(
695
- &path, &parent, &link_path, start_path, flags, ceiling_dirs);
780
+ &path, &parent, &link_path, &common_path, start_path, flags, ceiling_dirs);
696
781
 
697
782
  if (error < 0 || !repo_ptr)
698
783
  return error;
@@ -700,13 +785,24 @@ int git_repository_open_ext(
700
785
  repo = repository_alloc();
701
786
  GITERR_CHECK_ALLOC(repo);
702
787
 
703
- repo->path_repository = git_buf_detach(&path);
704
- GITERR_CHECK_ALLOC(repo->path_repository);
788
+ repo->gitdir = git_buf_detach(&path);
789
+ GITERR_CHECK_ALLOC(repo->gitdir);
705
790
 
706
791
  if (link_path.size) {
707
- repo->path_gitlink = git_buf_detach(&link_path);
708
- GITERR_CHECK_ALLOC(repo->path_gitlink);
792
+ repo->gitlink = git_buf_detach(&link_path);
793
+ GITERR_CHECK_ALLOC(repo->gitlink);
709
794
  }
795
+ if (common_path.size) {
796
+ repo->commondir = git_buf_detach(&common_path);
797
+ GITERR_CHECK_ALLOC(repo->commondir);
798
+ }
799
+
800
+ if ((error = git_buf_joinpath(&path, repo->gitdir, "gitdir")) < 0)
801
+ goto cleanup;
802
+ /* A 'gitdir' file inside a git directory is currently
803
+ * only used when the repository is a working tree. */
804
+ if (git_path_exists(path.ptr))
805
+ repo->is_worktree = 1;
710
806
 
711
807
  /*
712
808
  * We'd like to have the config, but git doesn't particularly
@@ -731,6 +827,7 @@ int git_repository_open_ext(
731
827
  }
732
828
 
733
829
  cleanup:
830
+ git_buf_free(&path);
734
831
  git_buf_free(&parent);
735
832
  git_config_free(config);
736
833
 
@@ -748,6 +845,36 @@ int git_repository_open(git_repository **repo_out, const char *path)
748
845
  repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL);
749
846
  }
750
847
 
848
+ int git_repository_open_from_worktree(git_repository **repo_out, git_worktree *wt)
849
+ {
850
+ git_buf path = GIT_BUF_INIT;
851
+ git_repository *repo = NULL;
852
+ int len, err;
853
+
854
+ assert(repo_out && wt);
855
+
856
+ *repo_out = NULL;
857
+ len = strlen(wt->gitlink_path);
858
+
859
+ if (len <= 4 || strcasecmp(wt->gitlink_path + len - 4, ".git")) {
860
+ err = -1;
861
+ goto out;
862
+ }
863
+
864
+ if ((err = git_buf_set(&path, wt->gitlink_path, len - 4)) < 0)
865
+ goto out;
866
+
867
+ if ((err = git_repository_open(&repo, path.ptr)) < 0)
868
+ goto out;
869
+
870
+ *repo_out = repo;
871
+
872
+ out:
873
+ git_buf_free(&path);
874
+
875
+ return err;
876
+ }
877
+
751
878
  int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb)
752
879
  {
753
880
  git_repository *repo;
@@ -773,7 +900,7 @@ int git_repository_discover(
773
900
 
774
901
  git_buf_sanitize(out);
775
902
 
776
- return find_repo(out, NULL, NULL, start_path, flags, ceiling_dirs);
903
+ return find_repo(out, NULL, NULL, NULL, start_path, flags, ceiling_dirs);
777
904
  }
778
905
 
779
906
  static int load_config(
@@ -793,8 +920,7 @@ static int load_config(
793
920
  if ((error = git_config_new(&cfg)) < 0)
794
921
  return error;
795
922
 
796
- error = git_buf_joinpath(
797
- &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO);
923
+ error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG);
798
924
  if (error < 0)
799
925
  goto on_error;
800
926
 
@@ -928,7 +1054,8 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
928
1054
  git_buf odb_path = GIT_BUF_INIT;
929
1055
  git_odb *odb;
930
1056
 
931
- if ((error = git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR)) < 0)
1057
+ if ((error = git_repository_item_path(&odb_path, repo,
1058
+ GIT_REPOSITORY_ITEM_OBJECTS)) < 0)
932
1059
  return error;
933
1060
 
934
1061
  error = git_odb_open(&odb, odb_path.ptr);
@@ -1014,7 +1141,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
1014
1141
  git_buf index_path = GIT_BUF_INIT;
1015
1142
  git_index *index;
1016
1143
 
1017
- if ((error = git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE)) < 0)
1144
+ if ((error = git_buf_joinpath(&index_path, repo->gitdir, GIT_INDEX_FILE)) < 0)
1018
1145
  return error;
1019
1146
 
1020
1147
  error = git_index_open(&index, index_path.ptr);
@@ -1130,13 +1257,13 @@ bool git_repository__reserved_names(
1130
1257
  prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
1131
1258
  git__prefixcmp;
1132
1259
 
1133
- if (repo->path_gitlink &&
1134
- reserved_names_add8dot3(repo, repo->path_gitlink) < 0)
1260
+ if (repo->gitlink &&
1261
+ reserved_names_add8dot3(repo, repo->gitlink) < 0)
1135
1262
  goto on_error;
1136
1263
 
1137
- if (repo->path_repository &&
1138
- prefixcmp(repo->path_repository, repo->workdir) == 0 &&
1139
- reserved_names_add8dot3(repo, repo->path_repository) < 0)
1264
+ if (repo->gitdir &&
1265
+ prefixcmp(repo->gitdir, repo->workdir) == 0 &&
1266
+ reserved_names_add8dot3(repo, repo->gitdir) < 0)
1140
1267
  goto on_error;
1141
1268
  }
1142
1269
  }
@@ -1193,7 +1320,7 @@ static int check_repositoryformatversion(git_config *config)
1193
1320
  return 0;
1194
1321
  }
1195
1322
 
1196
- static int repo_init_create_head(const char *git_dir, const char *ref_name)
1323
+ int git_repository_create_head(const char *git_dir, const char *ref_name)
1197
1324
  {
1198
1325
  git_buf ref_path = GIT_BUF_INIT;
1199
1326
  git_filebuf ref = GIT_FILEBUF_INIT;
@@ -1856,7 +1983,8 @@ int git_repository_init_ext(
1856
1983
  git_repository_init_options *opts)
1857
1984
  {
1858
1985
  int error;
1859
- git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT;
1986
+ git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT,
1987
+ common_path = GIT_BUF_INIT;
1860
1988
  const char *wd;
1861
1989
 
1862
1990
  assert(out && given_repo && opts);
@@ -1868,7 +1996,7 @@ int git_repository_init_ext(
1868
1996
  goto cleanup;
1869
1997
 
1870
1998
  wd = (opts->flags & GIT_REPOSITORY_INIT_BARE) ? NULL : git_buf_cstr(&wd_path);
1871
- if (valid_repository_path(&repo_path)) {
1999
+ if (valid_repository_path(&repo_path, &common_path)) {
1872
2000
 
1873
2001
  if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) {
1874
2002
  giterr_set(GITERR_REPOSITORY,
@@ -1889,7 +2017,7 @@ int git_repository_init_ext(
1889
2017
  repo_path.ptr, wd, opts)) &&
1890
2018
  !(error = repo_init_config(
1891
2019
  repo_path.ptr, wd, opts->flags, opts->mode)))
1892
- error = repo_init_create_head(
2020
+ error = git_repository_create_head(
1893
2021
  repo_path.ptr, opts->initial_head);
1894
2022
  }
1895
2023
  if (error < 0)
@@ -1901,6 +2029,7 @@ int git_repository_init_ext(
1901
2029
  error = repo_init_create_origin(*out, opts->origin_url);
1902
2030
 
1903
2031
  cleanup:
2032
+ git_buf_free(&common_path);
1904
2033
  git_buf_free(&repo_path);
1905
2034
  git_buf_free(&wd_path);
1906
2035
 
@@ -1930,6 +2059,49 @@ int git_repository_head_detached(git_repository *repo)
1930
2059
  return exists;
1931
2060
  }
1932
2061
 
2062
+ static int read_worktree_head(git_buf *out, git_repository *repo, const char *name)
2063
+ {
2064
+ git_buf path = GIT_BUF_INIT;
2065
+ int err;
2066
+
2067
+ assert(out && repo && name);
2068
+
2069
+ git_buf_clear(out);
2070
+
2071
+ if ((err = git_buf_printf(&path, "%s/worktrees/%s/HEAD", repo->commondir, name)) < 0)
2072
+ goto out;
2073
+ if (!git_path_exists(path.ptr))
2074
+ {
2075
+ err = -1;
2076
+ goto out;
2077
+ }
2078
+
2079
+ if ((err = git_futils_readbuffer(out, path.ptr)) < 0)
2080
+ goto out;
2081
+ git_buf_rtrim(out);
2082
+
2083
+ out:
2084
+ git_buf_free(&path);
2085
+
2086
+ return err;
2087
+ }
2088
+
2089
+ int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
2090
+ {
2091
+ git_buf buf = GIT_BUF_INIT;
2092
+ int ret;
2093
+
2094
+ assert(repo && name);
2095
+
2096
+ if (read_worktree_head(&buf, repo, name) < 0)
2097
+ return -1;
2098
+
2099
+ ret = git__strncmp(buf.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) != 0;
2100
+ git_buf_free(&buf);
2101
+
2102
+ return ret;
2103
+ }
2104
+
1933
2105
  int git_repository_head(git_reference **head_out, git_repository *repo)
1934
2106
  {
1935
2107
  git_reference *head;
@@ -1949,6 +2121,48 @@ int git_repository_head(git_reference **head_out, git_repository *repo)
1949
2121
  return error == GIT_ENOTFOUND ? GIT_EUNBORNBRANCH : error;
1950
2122
  }
1951
2123
 
2124
+ int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
2125
+ {
2126
+ git_buf buf = GIT_BUF_INIT;
2127
+ git_reference *head;
2128
+ int err;
2129
+
2130
+ assert(out && repo && name);
2131
+
2132
+ *out = NULL;
2133
+
2134
+ if (git_repository_head_detached_for_worktree(repo, name))
2135
+ return -1;
2136
+ if ((err = read_worktree_head(&buf, repo, name)) < 0)
2137
+ goto out;
2138
+
2139
+ /* We can only resolve symbolic references */
2140
+ if (git__strncmp(buf.ptr, GIT_SYMREF, strlen(GIT_SYMREF)))
2141
+ {
2142
+ err = -1;
2143
+ goto out;
2144
+ }
2145
+ git_buf_consume(&buf, buf.ptr + strlen(GIT_SYMREF));
2146
+
2147
+ if ((err = git_reference_lookup(&head, repo, buf.ptr)) < 0)
2148
+ goto out;
2149
+ if (git_reference_type(head) == GIT_REF_OID)
2150
+ {
2151
+ *out = head;
2152
+ err = 0;
2153
+ goto out;
2154
+ }
2155
+
2156
+ err = git_reference_lookup_resolved(
2157
+ out, repo, git_reference_symbolic_target(head), -1);
2158
+ git_reference_free(head);
2159
+
2160
+ out:
2161
+ git_buf_free(&buf);
2162
+
2163
+ return err;
2164
+ }
2165
+
1952
2166
  int git_repository_head_unborn(git_repository *repo)
1953
2167
  {
1954
2168
  git_reference *ref = NULL;
@@ -2007,10 +2221,50 @@ int git_repository_is_empty(git_repository *repo)
2007
2221
  return is_empty;
2008
2222
  }
2009
2223
 
2224
+ int git_repository_item_path(git_buf *out, git_repository *repo, git_repository_item_t item)
2225
+ {
2226
+ const char *parent;
2227
+
2228
+ switch (items[item].parent) {
2229
+ case GIT_REPOSITORY_ITEM_GITDIR:
2230
+ parent = git_repository_path(repo);
2231
+ break;
2232
+ case GIT_REPOSITORY_ITEM_WORKDIR:
2233
+ parent = git_repository_workdir(repo);
2234
+ break;
2235
+ case GIT_REPOSITORY_ITEM_COMMONDIR:
2236
+ parent = git_repository_commondir(repo);
2237
+ break;
2238
+ default:
2239
+ giterr_set(GITERR_INVALID, "Invalid item directory");
2240
+ return -1;
2241
+ }
2242
+
2243
+ if (parent == NULL) {
2244
+ giterr_set(GITERR_INVALID, "Path cannot exist in repository");
2245
+ return -1;
2246
+ }
2247
+
2248
+ if (git_buf_sets(out, parent) < 0)
2249
+ return -1;
2250
+
2251
+ if (items[item].name) {
2252
+ if (git_buf_joinpath(out, parent, items[item].name) < 0)
2253
+ return -1;
2254
+ }
2255
+
2256
+ if (items[item].directory) {
2257
+ if (git_path_to_dir(out) < 0)
2258
+ return -1;
2259
+ }
2260
+
2261
+ return 0;
2262
+ }
2263
+
2010
2264
  const char *git_repository_path(git_repository *repo)
2011
2265
  {
2012
2266
  assert(repo);
2013
- return repo->path_repository;
2267
+ return repo->gitdir;
2014
2268
  }
2015
2269
 
2016
2270
  const char *git_repository_workdir(git_repository *repo)
@@ -2023,6 +2277,12 @@ const char *git_repository_workdir(git_repository *repo)
2023
2277
  return repo->workdir;
2024
2278
  }
2025
2279
 
2280
+ const char *git_repository_commondir(git_repository *repo)
2281
+ {
2282
+ assert(repo);
2283
+ return repo->commondir;
2284
+ }
2285
+
2026
2286
  int git_repository_set_workdir(
2027
2287
  git_repository *repo, const char *workdir, int update_gitlink)
2028
2288
  {
@@ -2073,6 +2333,12 @@ int git_repository_is_bare(git_repository *repo)
2073
2333
  return repo->is_bare;
2074
2334
  }
2075
2335
 
2336
+ int git_repository_is_worktree(git_repository *repo)
2337
+ {
2338
+ assert(repo);
2339
+ return repo->is_worktree;
2340
+ }
2341
+
2076
2342
  int git_repository_set_bare(git_repository *repo)
2077
2343
  {
2078
2344
  int error;
@@ -2127,7 +2393,7 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head
2127
2393
 
2128
2394
  git_oid_fmt(orig_head_str, orig_head);
2129
2395
 
2130
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
2396
+ if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 &&
2131
2397
  (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
2132
2398
  (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
2133
2399
  error = git_filebuf_commit(&file);
@@ -2148,7 +2414,7 @@ int git_repository_message(git_buf *out, git_repository *repo)
2148
2414
 
2149
2415
  git_buf_sanitize(out);
2150
2416
 
2151
- if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
2417
+ if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
2152
2418
  return -1;
2153
2419
 
2154
2420
  if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
@@ -2169,7 +2435,7 @@ int git_repository_message_remove(git_repository *repo)
2169
2435
  git_buf path = GIT_BUF_INIT;
2170
2436
  int error;
2171
2437
 
2172
- if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
2438
+ if (git_buf_joinpath(&path, repo->gitdir, GIT_MERGE_MSG_FILE) < 0)
2173
2439
  return -1;
2174
2440
 
2175
2441
  error = p_unlink(git_buf_cstr(&path));
@@ -2290,6 +2556,12 @@ int git_repository_set_head(
2290
2556
  if (error < 0 && error != GIT_ENOTFOUND)
2291
2557
  goto cleanup;
2292
2558
 
2559
+ if (ref && current->type == GIT_REF_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) &&
2560
+ git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) {
2561
+ error = -1;
2562
+ goto cleanup;
2563
+ }
2564
+
2293
2565
  if (!error) {
2294
2566
  if (git_reference_is_branch(ref)) {
2295
2567
  error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
@@ -2405,7 +2677,7 @@ int git_repository_state(git_repository *repo)
2405
2677
 
2406
2678
  assert(repo);
2407
2679
 
2408
- if (git_buf_puts(&repo_path, repo->path_repository) < 0)
2680
+ if (git_buf_puts(&repo_path, repo->gitdir) < 0)
2409
2681
  return -1;
2410
2682
 
2411
2683
  if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
@@ -2447,7 +2719,7 @@ int git_repository__cleanup_files(
2447
2719
  for (error = 0, i = 0; !error && i < files_len; ++i) {
2448
2720
  const char *path;
2449
2721
 
2450
- if (git_buf_joinpath(&buf, repo->path_repository, files[i]) < 0)
2722
+ if (git_buf_joinpath(&buf, repo->gitdir, files[i]) < 0)
2451
2723
  return -1;
2452
2724
 
2453
2725
  path = git_buf_cstr(&buf);
@@ -2491,7 +2763,7 @@ int git_repository_is_shallow(git_repository *repo)
2491
2763
  struct stat st;
2492
2764
  int error;
2493
2765
 
2494
- if ((error = git_buf_joinpath(&path, repo->path_repository, "shallow")) < 0)
2766
+ if ((error = git_buf_joinpath(&path, repo->gitdir, "shallow")) < 0)
2495
2767
  return error;
2496
2768
 
2497
2769
  error = git_path_lstat(path.ptr, &st);