rugged 0.26.0b3 → 0.26.0b4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);