rugged 0.26.0b5 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged.c +24 -0
  3. data/ext/rugged/rugged.h +2 -0
  4. data/ext/rugged/rugged_signature.c +15 -2
  5. data/lib/rugged/version.rb +1 -1
  6. data/vendor/libgit2/CMakeLists.txt +9 -8
  7. data/vendor/libgit2/include/git2/common.h +29 -0
  8. data/vendor/libgit2/include/git2/errors.h +2 -0
  9. data/vendor/libgit2/include/git2/global.h +1 -1
  10. data/vendor/libgit2/include/git2/odb.h +2 -2
  11. data/vendor/libgit2/include/git2/odb_backend.h +1 -1
  12. data/vendor/libgit2/include/git2/remote.h +3 -3
  13. data/vendor/libgit2/include/git2/repository.h +2 -2
  14. data/vendor/libgit2/include/git2/sys/filter.h +11 -0
  15. data/vendor/libgit2/include/git2/sys/merge.h +5 -5
  16. data/vendor/libgit2/include/git2/sys/transport.h +10 -0
  17. data/vendor/libgit2/include/git2/transport.h +6 -6
  18. data/vendor/libgit2/include/git2/version.h +3 -3
  19. data/vendor/libgit2/include/git2/worktree.h +69 -10
  20. data/vendor/libgit2/libgit2.pc.in +2 -2
  21. data/vendor/libgit2/src/attr_file.c +6 -2
  22. data/vendor/libgit2/src/attrcache.c +7 -5
  23. data/vendor/libgit2/src/blame_git.c +12 -8
  24. data/vendor/libgit2/src/branch.c +17 -48
  25. data/vendor/libgit2/src/buffer.c +11 -12
  26. data/vendor/libgit2/src/buffer.h +2 -2
  27. data/vendor/libgit2/src/checkout.c +3 -6
  28. data/vendor/libgit2/src/config.c +42 -35
  29. data/vendor/libgit2/src/config_cache.c +1 -0
  30. data/vendor/libgit2/src/config_file.c +19 -11
  31. data/vendor/libgit2/src/config_file.h +1 -0
  32. data/vendor/libgit2/src/diff.c +35 -0
  33. data/vendor/libgit2/src/diff_parse.c +7 -1
  34. data/vendor/libgit2/src/filebuf.c +12 -1
  35. data/vendor/libgit2/src/filebuf.h +3 -1
  36. data/vendor/libgit2/src/fileops.c +83 -22
  37. data/vendor/libgit2/src/fileops.h +25 -0
  38. data/vendor/libgit2/src/filter.c +30 -14
  39. data/vendor/libgit2/src/global.c +1 -1
  40. data/vendor/libgit2/src/hash/hash_collisiondetect.h +1 -11
  41. data/vendor/libgit2/src/hash/sha1dc/sha1.c +894 -187
  42. data/vendor/libgit2/src/hash/sha1dc/sha1.h +69 -53
  43. data/vendor/libgit2/src/hash/sha1dc/ubc_check.c +13 -2
  44. data/vendor/libgit2/src/hash/sha1dc/ubc_check.h +20 -3
  45. data/vendor/libgit2/src/idxmap.c +1 -1
  46. data/vendor/libgit2/src/idxmap.h +1 -2
  47. data/vendor/libgit2/src/index.c +75 -42
  48. data/vendor/libgit2/src/indexer.c +31 -11
  49. data/vendor/libgit2/src/indexer.h +12 -0
  50. data/vendor/libgit2/src/merge.c +20 -0
  51. data/vendor/libgit2/src/merge_driver.c +29 -0
  52. data/vendor/libgit2/src/odb.c +96 -19
  53. data/vendor/libgit2/src/odb.h +25 -0
  54. data/vendor/libgit2/src/odb_loose.c +20 -6
  55. data/vendor/libgit2/src/odb_pack.c +1 -1
  56. data/vendor/libgit2/src/offmap.c +1 -1
  57. data/vendor/libgit2/src/offmap.h +1 -2
  58. data/vendor/libgit2/src/oidmap.c +1 -1
  59. data/vendor/libgit2/src/oidmap.h +1 -2
  60. data/vendor/libgit2/src/openssl_stream.c +11 -4
  61. data/vendor/libgit2/src/pack-objects.c +4 -0
  62. data/vendor/libgit2/src/pack-objects.h +1 -0
  63. data/vendor/libgit2/src/pack.c +5 -3
  64. data/vendor/libgit2/src/patch_generate.c +8 -79
  65. data/vendor/libgit2/src/patch_parse.c +5 -4
  66. data/vendor/libgit2/src/path.c +9 -7
  67. data/vendor/libgit2/src/posix.c +2 -0
  68. data/vendor/libgit2/src/posix.h +10 -0
  69. data/vendor/libgit2/src/rebase.c +12 -10
  70. data/vendor/libgit2/src/refdb_fs.c +33 -10
  71. data/vendor/libgit2/src/refs.c +89 -8
  72. data/vendor/libgit2/src/refs.h +14 -0
  73. data/vendor/libgit2/src/remote.c +9 -10
  74. data/vendor/libgit2/src/repository.c +178 -146
  75. data/vendor/libgit2/src/repository.h +25 -0
  76. data/vendor/libgit2/src/revparse.c +22 -3
  77. data/vendor/libgit2/src/revwalk.c +6 -3
  78. data/vendor/libgit2/src/settings.c +22 -1
  79. data/vendor/libgit2/src/signature.c +4 -1
  80. data/vendor/libgit2/src/socket_stream.c +2 -4
  81. data/vendor/libgit2/src/strmap.c +1 -1
  82. data/vendor/libgit2/src/strmap.h +1 -3
  83. data/vendor/libgit2/src/submodule.c +27 -7
  84. data/vendor/libgit2/src/sysdir.c +11 -0
  85. data/vendor/libgit2/src/sysdir.h +12 -0
  86. data/vendor/libgit2/src/transports/http.c +3 -0
  87. data/vendor/libgit2/src/transports/smart.c +6 -0
  88. data/vendor/libgit2/src/transports/smart_protocol.c +2 -1
  89. data/vendor/libgit2/src/transports/ssh.c +13 -1
  90. data/vendor/libgit2/src/transports/winhttp.c +1 -2
  91. data/vendor/libgit2/src/tree.c +13 -11
  92. data/vendor/libgit2/src/unix/posix.h +6 -1
  93. data/vendor/libgit2/src/varint.c +1 -1
  94. data/vendor/libgit2/src/win32/posix.h +3 -0
  95. data/vendor/libgit2/src/win32/posix_w32.c +334 -111
  96. data/vendor/libgit2/src/worktree.c +174 -48
  97. data/vendor/libgit2/src/worktree.h +1 -1
  98. metadata +77 -76
@@ -62,6 +62,7 @@ typedef struct refdb_fs_backend {
62
62
  int peeling_mode;
63
63
  git_iterator_flag_t iterator_flags;
64
64
  uint32_t direach_flags;
65
+ int fsync;
65
66
  } refdb_fs_backend;
66
67
 
67
68
  static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
@@ -736,8 +737,9 @@ static int reference_path_available(
736
737
 
737
738
  static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *name)
738
739
  {
739
- int error;
740
+ int error, filebuf_flags;
740
741
  git_buf ref_path = GIT_BUF_INIT;
742
+ const char *basedir;
741
743
 
742
744
  assert(file && backend && name);
743
745
 
@@ -746,16 +748,25 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
746
748
  return GIT_EINVALIDSPEC;
747
749
  }
748
750
 
751
+ if (is_per_worktree_ref(name))
752
+ basedir = backend->gitpath;
753
+ else
754
+ basedir = backend->commonpath;
755
+
749
756
  /* Remove a possibly existing empty directory hierarchy
750
757
  * which name would collide with the reference name
751
758
  */
752
- if ((error = git_futils_rmdir_r(name, backend->gitpath, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
759
+ if ((error = git_futils_rmdir_r(name, basedir, GIT_RMDIR_SKIP_NONEMPTY)) < 0)
753
760
  return error;
754
761
 
755
- if (git_buf_joinpath(&ref_path, backend->gitpath, name) < 0)
762
+ if (git_buf_joinpath(&ref_path, basedir, name) < 0)
756
763
  return -1;
757
764
 
758
- error = git_filebuf_open(file, ref_path.ptr, GIT_FILEBUF_FORCE, GIT_REFS_FILE_MODE);
765
+ filebuf_flags = GIT_FILEBUF_FORCE;
766
+ if (backend->fsync)
767
+ filebuf_flags |= GIT_FILEBUF_FSYNC;
768
+
769
+ error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE);
759
770
 
760
771
  if (error == GIT_EDIRECTORY)
761
772
  giterr_set(GITERR_REFERENCE, "cannot lock ref '%s', there are refs beneath that folder", name);
@@ -990,15 +1001,18 @@ static int packed_write(refdb_fs_backend *backend)
990
1001
  {
991
1002
  git_sortedcache *refcache = backend->refcache;
992
1003
  git_filebuf pack_file = GIT_FILEBUF_INIT;
993
- int error;
1004
+ int error, open_flags = 0;
994
1005
  size_t i;
995
1006
 
996
1007
  /* lock the cache to updates while we do this */
997
1008
  if ((error = git_sortedcache_wlock(refcache)) < 0)
998
1009
  return error;
999
1010
 
1011
+ if (backend->fsync)
1012
+ open_flags = GIT_FILEBUF_FSYNC;
1013
+
1000
1014
  /* Open the file! */
1001
- if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), 0, GIT_PACKEDREFS_FILE_MODE)) < 0)
1015
+ if ((error = git_filebuf_open(&pack_file, git_sortedcache_path(refcache), open_flags, GIT_PACKEDREFS_FILE_MODE)) < 0)
1002
1016
  goto fail;
1003
1017
 
1004
1018
  /* Packfiles have a header... apparently
@@ -1126,7 +1140,7 @@ out:
1126
1140
  static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message)
1127
1141
  {
1128
1142
  int error;
1129
- git_oid old_id = {{0}};
1143
+ git_oid old_id;
1130
1144
  git_reference *tmp = NULL, *head = NULL, *peeled = NULL;
1131
1145
  const char *name;
1132
1146
 
@@ -1134,7 +1148,8 @@ static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref
1134
1148
  return 0;
1135
1149
 
1136
1150
  /* if we can't resolve, we use {0}*40 as old id */
1137
- git_reference_name_to_id(&old_id, backend->repo, ref->name);
1151
+ if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0)
1152
+ memset(&old_id, 0, sizeof(old_id));
1138
1153
 
1139
1154
  if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0)
1140
1155
  return error;
@@ -1786,7 +1801,7 @@ success:
1786
1801
  /* Append to the reflog, must be called under reference lock */
1787
1802
  static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, const git_oid *old, const git_oid *new, const git_signature *who, const char *message)
1788
1803
  {
1789
- int error, is_symbolic;
1804
+ int error, is_symbolic, open_flags;
1790
1805
  git_oid old_id = {{0}}, new_id = {{0}};
1791
1806
  git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
1792
1807
  git_repository *repo = backend->repo;
@@ -1854,7 +1869,12 @@ static int reflog_append(refdb_fs_backend *backend, const git_reference *ref, co
1854
1869
  goto cleanup;
1855
1870
  }
1856
1871
 
1857
- error = git_futils_writebuffer(&buf, git_buf_cstr(&path), O_WRONLY|O_CREAT|O_APPEND, GIT_REFLOG_FILE_MODE);
1872
+ open_flags = O_WRONLY | O_CREAT | O_APPEND;
1873
+
1874
+ if (backend->fsync)
1875
+ open_flags |= O_FSYNC;
1876
+
1877
+ error = git_futils_writebuffer(&buf, git_buf_cstr(&path), open_flags, GIT_REFLOG_FILE_MODE);
1858
1878
 
1859
1879
  cleanup:
1860
1880
  git_buf_free(&buf);
@@ -2011,6 +2031,9 @@ int git_refdb_backend_fs(
2011
2031
  backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE;
2012
2032
  backend->direach_flags |= GIT_PATH_DIR_PRECOMPOSE_UNICODE;
2013
2033
  }
2034
+ if ((!git_repository__cvar(&t, backend->repo, GIT_CVAR_FSYNCOBJECTFILES) && t) ||
2035
+ git_repository__fsync_gitdir)
2036
+ backend->fsync = 1;
2014
2037
 
2015
2038
  backend->parent.exists = &refdb_fs_backend__exists;
2016
2039
  backend->parent.lookup = &refdb_fs_backend__lookup;
@@ -249,6 +249,40 @@ int git_reference_lookup_resolved(
249
249
  return 0;
250
250
  }
251
251
 
252
+ int git_reference__read_head(
253
+ git_reference **out,
254
+ git_repository *repo,
255
+ const char *path)
256
+ {
257
+ git_buf reference = GIT_BUF_INIT;
258
+ char *name = NULL;
259
+ int error;
260
+
261
+ if ((error = git_futils_readbuffer(&reference, path)) < 0)
262
+ goto out;
263
+ git_buf_rtrim(&reference);
264
+
265
+ if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) == 0) {
266
+ git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
267
+
268
+ name = git_path_basename(path);
269
+
270
+ if ((*out = git_reference__alloc_symbolic(name, reference.ptr)) == NULL) {
271
+ error = -1;
272
+ goto out;
273
+ }
274
+ } else {
275
+ if ((error = git_reference_lookup(out, repo, reference.ptr)) < 0)
276
+ goto out;
277
+ }
278
+
279
+ out:
280
+ git__free(name);
281
+ git_buf_free(&reference);
282
+
283
+ return error;
284
+ }
285
+
252
286
  int git_reference_dwim(git_reference **out, git_repository *repo, const char *refname)
253
287
  {
254
288
  int error = 0, i;
@@ -580,20 +614,63 @@ int git_reference_symbolic_set_target(
580
614
  out, ref->db->repo, ref->name, target, 1, ref->target.symbolic, log_message);
581
615
  }
582
616
 
617
+ typedef struct {
618
+ const char *old_name;
619
+ git_refname_t new_name;
620
+ } rename_cb_data;
621
+
622
+ static int update_wt_heads(git_repository *repo, const char *path, void *payload)
623
+ {
624
+ rename_cb_data *data = (rename_cb_data *) payload;
625
+ git_reference *head = NULL;
626
+ char *gitdir = NULL;
627
+ int error;
628
+
629
+ if ((error = git_reference__read_head(&head, repo, path)) < 0) {
630
+ giterr_set(GITERR_REFERENCE, "could not read HEAD when renaming references");
631
+ goto out;
632
+ }
633
+
634
+ if ((gitdir = git_path_dirname(path)) == NULL) {
635
+ error = -1;
636
+ goto out;
637
+ }
638
+
639
+ if (git_reference_type(head) != GIT_REF_SYMBOLIC ||
640
+ git__strcmp(head->target.symbolic, data->old_name) != 0) {
641
+ error = 0;
642
+ goto out;
643
+ }
644
+
645
+ /* Update HEAD it was pointing to the reference being renamed */
646
+ if ((error = git_repository_create_head(gitdir, data->new_name)) < 0) {
647
+ giterr_set(GITERR_REFERENCE, "failed to update HEAD after renaming reference");
648
+ goto out;
649
+ }
650
+
651
+ out:
652
+ git_reference_free(head);
653
+ git__free(gitdir);
654
+
655
+ return error;
656
+ }
657
+
583
658
  static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force,
584
659
  const git_signature *signature, const char *message)
585
660
  {
661
+ git_repository *repo;
586
662
  git_refname_t normalized;
587
663
  bool should_head_be_updated = false;
588
664
  int error = 0;
589
665
 
590
666
  assert(ref && new_name && signature);
591
667
 
668
+ repo = git_reference_owner(ref);
669
+
592
670
  if ((error = reference_normalize_for_repo(
593
- normalized, git_reference_owner(ref), new_name, true)) < 0)
671
+ normalized, repo, new_name, true)) < 0)
594
672
  return error;
595
673
 
596
-
597
674
  /* Check if we have to update HEAD. */
598
675
  if ((error = git_branch_is_head(ref)) < 0)
599
676
  return error;
@@ -603,14 +680,18 @@ static int reference__rename(git_reference **out, git_reference *ref, const char
603
680
  if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0)
604
681
  return error;
605
682
 
606
- /* Update HEAD it was pointing to the reference being renamed */
607
- if (should_head_be_updated &&
608
- (error = git_repository_set_head(ref->db->repo, normalized)) < 0) {
609
- giterr_set(GITERR_REFERENCE, "failed to update HEAD after renaming reference");
610
- return error;
683
+ /* Update HEAD if it was pointing to the reference being renamed */
684
+ if (should_head_be_updated) {
685
+ error = git_repository_set_head(ref->db->repo, normalized);
686
+ } else {
687
+ rename_cb_data payload;
688
+ payload.old_name = ref->name;
689
+ memcpy(&payload.new_name, &normalized, sizeof(normalized));
690
+
691
+ error = git_repository_foreach_head(repo, update_wt_heads, &payload);
611
692
  }
612
693
 
613
- return 0;
694
+ return error;
614
695
  }
615
696
 
616
697
 
@@ -107,6 +107,20 @@ int git_reference_lookup_resolved(
107
107
  const char *name,
108
108
  int max_deref);
109
109
 
110
+ /**
111
+ * Read reference from a file.
112
+ *
113
+ * This function will read in the file at `path`. If it is a
114
+ * symref, it will return a new unresolved symbolic reference
115
+ * with the given name pointing to the reference pointed to by
116
+ * the file. If it is not a symbolic reference, it will return
117
+ * the resolved reference.
118
+ */
119
+ int git_reference__read_head(
120
+ git_reference **out,
121
+ git_repository *repo,
122
+ const char *path);
123
+
110
124
  int git_reference__log_signature(git_signature **out, git_repository *repo);
111
125
 
112
126
  /** Update a reference after a commit. */
@@ -192,7 +192,7 @@ static int canonicalize_url(git_buf *out, const char *in)
192
192
  static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
193
193
  {
194
194
  git_remote *remote;
195
- git_config *config = NULL;
195
+ git_config *config_ro = NULL, *config_rw;
196
196
  git_buf canonical_url = GIT_BUF_INIT;
197
197
  git_buf var = GIT_BUF_INIT;
198
198
  int error = -1;
@@ -200,7 +200,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
200
200
  /* name is optional */
201
201
  assert(out && repo && url);
202
202
 
203
- if ((error = git_repository_config__weakptr(&config, repo)) < 0)
203
+ if ((error = git_repository_config_snapshot(&config_ro, repo)) < 0)
204
204
  return error;
205
205
 
206
206
  remote = git__calloc(1, sizeof(git_remote));
@@ -212,7 +212,8 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
212
212
  (error = canonicalize_url(&canonical_url, url)) < 0)
213
213
  goto on_error;
214
214
 
215
- remote->url = apply_insteadof(repo->_config, canonical_url.ptr, GIT_DIRECTION_FETCH);
215
+ remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
216
+ GITERR_CHECK_ALLOC(remote->url);
216
217
 
217
218
  if (name != NULL) {
218
219
  remote->name = git__strdup(name);
@@ -221,7 +222,8 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
221
222
  if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0)
222
223
  goto on_error;
223
224
 
224
- if ((error = git_config_set_string(config, var.ptr, canonical_url.ptr)) < 0)
225
+ if ((error = git_repository_config__weakptr(&config_rw, repo)) < 0 ||
226
+ (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0)
225
227
  goto on_error;
226
228
  }
227
229
 
@@ -233,10 +235,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
233
235
  if (name && (error = write_add_refspec(repo, name, fetch, true)) < 0)
234
236
  goto on_error;
235
237
 
236
- if ((error = git_repository_config_snapshot(&config, repo)) < 0)
237
- goto on_error;
238
-
239
- if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
238
+ if ((error = lookup_remote_prune_config(remote, config_ro, name)) < 0)
240
239
  goto on_error;
241
240
 
242
241
  /* Move the data over to where the matching functions can find them */
@@ -260,7 +259,7 @@ on_error:
260
259
  if (error)
261
260
  git_remote_free(remote);
262
261
 
263
- git_config_free(config);
262
+ git_config_free(config_ro);
264
263
  git_buf_free(&canonical_url);
265
264
  git_buf_free(&var);
266
265
  return error;
@@ -2412,7 +2411,7 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
2412
2411
  proxy = &opts->proxy_opts;
2413
2412
  }
2414
2413
 
2415
- assert(remote && refspecs);
2414
+ assert(remote);
2416
2415
 
2417
2416
  if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
2418
2417
  return error;
@@ -36,6 +36,8 @@
36
36
  # include "win32/w32_util.h"
37
37
  #endif
38
38
 
39
+ bool git_repository__fsync_gitdir = false;
40
+
39
41
  static const struct {
40
42
  git_repository_item_t parent;
41
43
  const char *name;
@@ -422,10 +424,10 @@ static int read_gitfile(git_buf *path_out, const char *file_path)
422
424
  }
423
425
 
424
426
  static int find_repo(
425
- git_buf *repo_path,
426
- git_buf *parent_path,
427
- git_buf *link_path,
428
- git_buf *common_path,
427
+ git_buf *gitdir_path,
428
+ git_buf *workdir_path,
429
+ git_buf *gitlink_path,
430
+ git_buf *commondir_path,
429
431
  const char *start_path,
430
432
  uint32_t flags,
431
433
  const char *ceiling_dirs)
@@ -440,7 +442,7 @@ static int find_repo(
440
442
  bool in_dot_git;
441
443
  size_t ceiling_offset = 0;
442
444
 
443
- git_buf_free(repo_path);
445
+ git_buf_clear(gitdir_path);
444
446
 
445
447
  error = git_path_prettify(&path, start_path, NULL);
446
448
  if (error < 0)
@@ -482,13 +484,13 @@ static int find_repo(
482
484
  if (S_ISDIR(st.st_mode)) {
483
485
  if (valid_repository_path(&path, &common_link)) {
484
486
  git_path_to_dir(&path);
485
- git_buf_set(repo_path, path.ptr, path.size);
487
+ git_buf_set(gitdir_path, path.ptr, path.size);
486
488
 
487
- if (link_path)
488
- git_buf_attach(link_path,
489
+ if (gitlink_path)
490
+ git_buf_attach(gitlink_path,
489
491
  git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0);
490
- if (common_path)
491
- git_buf_swap(&common_link, common_path);
492
+ if (commondir_path)
493
+ git_buf_swap(&common_link, commondir_path);
492
494
 
493
495
  break;
494
496
  }
@@ -498,12 +500,12 @@ static int find_repo(
498
500
  if (error < 0)
499
501
  break;
500
502
  if (valid_repository_path(&repo_link, &common_link)) {
501
- git_buf_swap(repo_path, &repo_link);
503
+ git_buf_swap(gitdir_path, &repo_link);
502
504
 
503
- if (link_path)
504
- error = git_buf_put(link_path, path.ptr, path.size);
505
- if (common_path)
506
- git_buf_swap(&common_link, common_path);
505
+ if (gitlink_path)
506
+ error = git_buf_put(gitlink_path, path.ptr, path.size);
507
+ if (commondir_path)
508
+ git_buf_swap(&common_link, commondir_path);
507
509
  }
508
510
  break;
509
511
  }
@@ -529,20 +531,20 @@ static int find_repo(
529
531
  break;
530
532
  }
531
533
 
532
- if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
533
- if (!git_buf_len(repo_path))
534
- git_buf_clear(parent_path);
534
+ if (!error && workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
535
+ if (!git_buf_len(gitdir_path))
536
+ git_buf_clear(workdir_path);
535
537
  else {
536
- git_path_dirname_r(parent_path, path.ptr);
537
- git_path_to_dir(parent_path);
538
+ git_path_dirname_r(workdir_path, path.ptr);
539
+ git_path_to_dir(workdir_path);
538
540
  }
539
- if (git_buf_oom(parent_path))
541
+ if (git_buf_oom(workdir_path))
540
542
  return -1;
541
543
  }
542
544
 
543
545
  /* If we didn't find the repository, and we don't have any other error
544
546
  * to report, report that. */
545
- if (!git_buf_len(repo_path) && !error) {
547
+ if (!git_buf_len(gitdir_path) && !error) {
546
548
  giterr_set(GITERR_REPOSITORY,
547
549
  "could not find repository from '%s'", start_path);
548
550
  error = GIT_ENOTFOUND;
@@ -758,6 +760,29 @@ success:
758
760
  return error;
759
761
  }
760
762
 
763
+ static int repo_is_worktree(unsigned *out, const git_repository *repo)
764
+ {
765
+ git_buf gitdir_link = GIT_BUF_INIT;
766
+ int error;
767
+
768
+ /* Worktrees cannot have the same commondir and gitdir */
769
+ if (repo->commondir && repo->gitdir
770
+ && !strcmp(repo->commondir, repo->gitdir)) {
771
+ *out = 0;
772
+ return 0;
773
+ }
774
+
775
+ if ((error = git_buf_joinpath(&gitdir_link, repo->gitdir, "gitdir")) < 0)
776
+ return -1;
777
+
778
+ /* A 'gitdir' file inside a git directory is currently
779
+ * only used when the repository is a working tree. */
780
+ *out = !!git_path_exists(gitdir_link.ptr);
781
+
782
+ git_buf_free(&gitdir_link);
783
+ return error;
784
+ }
785
+
761
786
  int git_repository_open_ext(
762
787
  git_repository **repo_ptr,
763
788
  const char *start_path,
@@ -765,8 +790,9 @@ int git_repository_open_ext(
765
790
  const char *ceiling_dirs)
766
791
  {
767
792
  int error;
768
- git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT,
769
- link_path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
793
+ unsigned is_worktree;
794
+ git_buf gitdir = GIT_BUF_INIT, workdir = GIT_BUF_INIT,
795
+ gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
770
796
  git_repository *repo;
771
797
  git_config *config = NULL;
772
798
 
@@ -777,7 +803,7 @@ int git_repository_open_ext(
777
803
  *repo_ptr = NULL;
778
804
 
779
805
  error = find_repo(
780
- &path, &parent, &link_path, &common_path, start_path, flags, ceiling_dirs);
806
+ &gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs);
781
807
 
782
808
  if (error < 0 || !repo_ptr)
783
809
  return error;
@@ -785,24 +811,21 @@ int git_repository_open_ext(
785
811
  repo = repository_alloc();
786
812
  GITERR_CHECK_ALLOC(repo);
787
813
 
788
- repo->gitdir = git_buf_detach(&path);
814
+ repo->gitdir = git_buf_detach(&gitdir);
789
815
  GITERR_CHECK_ALLOC(repo->gitdir);
790
816
 
791
- if (link_path.size) {
792
- repo->gitlink = git_buf_detach(&link_path);
817
+ if (gitlink.size) {
818
+ repo->gitlink = git_buf_detach(&gitlink);
793
819
  GITERR_CHECK_ALLOC(repo->gitlink);
794
820
  }
795
- if (common_path.size) {
796
- repo->commondir = git_buf_detach(&common_path);
821
+ if (commondir.size) {
822
+ repo->commondir = git_buf_detach(&commondir);
797
823
  GITERR_CHECK_ALLOC(repo->commondir);
798
824
  }
799
825
 
800
- if ((error = git_buf_joinpath(&path, repo->gitdir, "gitdir")) < 0)
826
+ if ((error = repo_is_worktree(&is_worktree, repo)) < 0)
801
827
  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;
828
+ repo->is_worktree = is_worktree;
806
829
 
807
830
  /*
808
831
  * We'd like to have the config, but git doesn't particularly
@@ -822,13 +845,13 @@ int git_repository_open_ext(
822
845
 
823
846
  if (config &&
824
847
  ((error = load_config_data(repo, config)) < 0 ||
825
- (error = load_workdir(repo, config, &parent)) < 0))
848
+ (error = load_workdir(repo, config, &workdir)) < 0))
826
849
  goto cleanup;
827
850
  }
828
851
 
829
852
  cleanup:
830
- git_buf_free(&path);
831
- git_buf_free(&parent);
853
+ git_buf_free(&gitdir);
854
+ git_buf_free(&workdir);
832
855
  git_config_free(config);
833
856
 
834
857
  if (error < 0)
@@ -920,13 +943,10 @@ static int load_config(
920
943
  if ((error = git_config_new(&cfg)) < 0)
921
944
  return error;
922
945
 
923
- error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG);
924
- if (error < 0)
925
- goto on_error;
946
+ if ((error = git_repository_item_path(&config_path, repo, GIT_REPOSITORY_ITEM_CONFIG)) == 0)
947
+ error = git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0);
926
948
 
927
- if ((error = git_config_add_file_ondisk(
928
- cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 &&
929
- error != GIT_ENOTFOUND)
949
+ if (error && error != GIT_ENOTFOUND)
930
950
  goto on_error;
931
951
 
932
952
  git_buf_free(&config_path);
@@ -1055,18 +1075,22 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo)
1055
1075
  git_odb *odb;
1056
1076
 
1057
1077
  if ((error = git_repository_item_path(&odb_path, repo,
1058
- GIT_REPOSITORY_ITEM_OBJECTS)) < 0)
1078
+ GIT_REPOSITORY_ITEM_OBJECTS)) < 0 ||
1079
+ (error = git_odb_new(&odb)) < 0)
1059
1080
  return error;
1060
1081
 
1061
- error = git_odb_open(&odb, odb_path.ptr);
1062
- if (!error) {
1063
- GIT_REFCOUNT_OWN(odb, repo);
1082
+ GIT_REFCOUNT_OWN(odb, repo);
1064
1083
 
1065
- odb = git__compare_and_swap(&repo->_odb, NULL, odb);
1066
- if (odb != NULL) {
1067
- GIT_REFCOUNT_OWN(odb, NULL);
1068
- git_odb_free(odb);
1069
- }
1084
+ if ((error = git_odb__set_caps(odb, GIT_ODB_CAP_FROM_OWNER)) < 0 ||
1085
+ (error = git_odb__add_default_backends(odb, odb_path.ptr, 0, 0)) < 0) {
1086
+ git_odb_free(odb);
1087
+ return error;
1088
+ }
1089
+
1090
+ odb = git__compare_and_swap(&repo->_odb, NULL, odb);
1091
+ if (odb != NULL) {
1092
+ GIT_REFCOUNT_OWN(odb, NULL);
1093
+ git_odb_free(odb);
1070
1094
  }
1071
1095
 
1072
1096
  git_buf_free(&odb_path);
@@ -2059,47 +2083,27 @@ int git_repository_head_detached(git_repository *repo)
2059
2083
  return exists;
2060
2084
  }
2061
2085
 
2062
- static int read_worktree_head(git_buf *out, git_repository *repo, const char *name)
2086
+ static int get_worktree_file_path(git_buf *out, git_repository *repo, const char *worktree, const char *file)
2063
2087
  {
2064
- git_buf path = GIT_BUF_INIT;
2065
- int err;
2066
-
2067
- assert(out && repo && name);
2068
-
2069
2088
  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;
2089
+ return git_buf_printf(out, "%s/worktrees/%s/%s", repo->commondir, worktree, file);
2087
2090
  }
2088
2091
 
2089
2092
  int git_repository_head_detached_for_worktree(git_repository *repo, const char *name)
2090
2093
  {
2091
- git_buf buf = GIT_BUF_INIT;
2092
- int ret;
2094
+ git_reference *ref = NULL;
2095
+ int error;
2093
2096
 
2094
2097
  assert(repo && name);
2095
2098
 
2096
- if (read_worktree_head(&buf, repo, name) < 0)
2097
- return -1;
2099
+ if ((error = git_repository_head_for_worktree(&ref, repo, name)) < 0)
2100
+ goto out;
2098
2101
 
2099
- ret = git__strncmp(buf.ptr, GIT_SYMREF, strlen(GIT_SYMREF)) != 0;
2100
- git_buf_free(&buf);
2102
+ error = (git_reference_type(ref) != GIT_REF_SYMBOLIC);
2103
+ out:
2104
+ git_reference_free(ref);
2101
2105
 
2102
- return ret;
2106
+ return error;
2103
2107
  }
2104
2108
 
2105
2109
  int git_repository_head(git_reference **head_out, git_repository *repo)
@@ -2123,44 +2127,67 @@ int git_repository_head(git_reference **head_out, git_repository *repo)
2123
2127
 
2124
2128
  int git_repository_head_for_worktree(git_reference **out, git_repository *repo, const char *name)
2125
2129
  {
2126
- git_buf buf = GIT_BUF_INIT;
2127
- git_reference *head;
2128
- int err;
2130
+ git_buf path = GIT_BUF_INIT;
2131
+ git_reference *head = NULL;
2132
+ int error;
2129
2133
 
2130
2134
  assert(out && repo && name);
2131
2135
 
2132
2136
  *out = NULL;
2133
2137
 
2134
- if (git_repository_head_detached_for_worktree(repo, name))
2135
- return -1;
2136
- if ((err = read_worktree_head(&buf, repo, name)) < 0)
2138
+ if ((error = get_worktree_file_path(&path, repo, name, GIT_HEAD_FILE)) < 0 ||
2139
+ (error = git_reference__read_head(&head, repo, path.ptr)) < 0)
2137
2140
  goto out;
2138
2141
 
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;
2142
+ if (git_reference_type(head) != GIT_REF_OID) {
2143
+ git_reference *resolved;
2144
+
2145
+ error = git_reference_lookup_resolved(&resolved, repo, git_reference_symbolic_target(head), -1);
2146
+ git_reference_free(head);
2147
+ head = resolved;
2144
2148
  }
2145
- git_buf_consume(&buf, buf.ptr + strlen(GIT_SYMREF));
2146
2149
 
2147
- if ((err = git_reference_lookup(&head, repo, buf.ptr)) < 0)
2150
+ *out = head;
2151
+
2152
+ out:
2153
+ if (error)
2154
+ git_reference_free(head);
2155
+
2156
+ git_buf_free(&path);
2157
+
2158
+ return error;
2159
+ }
2160
+
2161
+ int git_repository_foreach_head(git_repository *repo, git_repository_foreach_head_cb cb, void *payload)
2162
+ {
2163
+ git_strarray worktrees = GIT_VECTOR_INIT;
2164
+ git_buf path = GIT_BUF_INIT;
2165
+ int error;
2166
+ size_t i;
2167
+
2168
+ /* Execute callback for HEAD of commondir */
2169
+ if ((error = git_buf_joinpath(&path, repo->commondir, GIT_HEAD_FILE)) < 0 ||
2170
+ (error = cb(repo, path.ptr, payload) != 0))
2148
2171
  goto out;
2149
- if (git_reference_type(head) == GIT_REF_OID)
2150
- {
2151
- *out = head;
2152
- err = 0;
2172
+
2173
+ if ((error = git_worktree_list(&worktrees, repo)) < 0) {
2174
+ error = 0;
2153
2175
  goto out;
2154
2176
  }
2155
2177
 
2156
- err = git_reference_lookup_resolved(
2157
- out, repo, git_reference_symbolic_target(head), -1);
2158
- git_reference_free(head);
2178
+ /* Execute callback for all worktree HEADs */
2179
+ for (i = 0; i < worktrees.count; i++) {
2180
+ if (get_worktree_file_path(&path, repo, worktrees.strings[i], GIT_HEAD_FILE) < 0)
2181
+ continue;
2159
2182
 
2160
- out:
2161
- git_buf_free(&buf);
2183
+ if ((error = cb(repo, path.ptr, payload)) != 0)
2184
+ goto out;
2185
+ }
2162
2186
 
2163
- return err;
2187
+ out:
2188
+ git_buf_free(&path);
2189
+ git_strarray_free(&worktrees);
2190
+ return error;
2164
2191
  }
2165
2192
 
2166
2193
  int git_repository_head_unborn(git_repository *repo)
@@ -2236,13 +2263,13 @@ int git_repository_item_path(git_buf *out, git_repository *repo, git_repository_
2236
2263
  parent = git_repository_commondir(repo);
2237
2264
  break;
2238
2265
  default:
2239
- giterr_set(GITERR_INVALID, "Invalid item directory");
2266
+ giterr_set(GITERR_INVALID, "invalid item directory");
2240
2267
  return -1;
2241
2268
  }
2242
2269
 
2243
2270
  if (parent == NULL) {
2244
- giterr_set(GITERR_INVALID, "Path cannot exist in repository");
2245
- return -1;
2271
+ giterr_set(GITERR_INVALID, "path cannot exist in repository");
2272
+ return GIT_ENOTFOUND;
2246
2273
  }
2247
2274
 
2248
2275
  if (git_buf_sets(out, parent) < 0)
@@ -2525,7 +2552,9 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new)
2525
2552
 
2526
2553
  git_buf_puts(out, " to ");
2527
2554
 
2528
- if (git_reference__is_branch(new))
2555
+ if (git_reference__is_branch(new) ||
2556
+ git_reference__is_tag(new) ||
2557
+ git_reference__is_remote(new))
2529
2558
  git_buf_puts(out, git_reference__shorthand(new));
2530
2559
  else
2531
2560
  git_buf_puts(out, new);
@@ -2536,6 +2565,41 @@ static int checkout_message(git_buf *out, git_reference *old, const char *new)
2536
2565
  return 0;
2537
2566
  }
2538
2567
 
2568
+ static int detach(git_repository *repo, const git_oid *id, const char *new)
2569
+ {
2570
+ int error;
2571
+ git_buf log_message = GIT_BUF_INIT;
2572
+ git_object *object = NULL, *peeled = NULL;
2573
+ git_reference *new_head = NULL, *current = NULL;
2574
+
2575
+ assert(repo && id);
2576
+
2577
+ if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
2578
+ return error;
2579
+
2580
+ if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
2581
+ goto cleanup;
2582
+
2583
+ if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
2584
+ goto cleanup;
2585
+
2586
+ if (new == NULL)
2587
+ new = git_oid_tostr_s(git_object_id(peeled));
2588
+
2589
+ if ((error = checkout_message(&log_message, current, new)) < 0)
2590
+ goto cleanup;
2591
+
2592
+ error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
2593
+
2594
+ cleanup:
2595
+ git_buf_free(&log_message);
2596
+ git_object_free(object);
2597
+ git_object_free(peeled);
2598
+ git_reference_free(current);
2599
+ git_reference_free(new_head);
2600
+ return error;
2601
+ }
2602
+
2539
2603
  int git_repository_set_head(
2540
2604
  git_repository* repo,
2541
2605
  const char* refname)
@@ -2558,6 +2622,8 @@ int git_repository_set_head(
2558
2622
 
2559
2623
  if (ref && current->type == GIT_REF_SYMBOLIC && git__strcmp(current->target.symbolic, ref->name) &&
2560
2624
  git_reference_is_branch(ref) && git_branch_is_checked_out(ref)) {
2625
+ giterr_set(GITERR_REPOSITORY, "cannot set HEAD to reference '%s' as it is the current HEAD "
2626
+ "of a linked repository.", git_reference_name(ref));
2561
2627
  error = -1;
2562
2628
  goto cleanup;
2563
2629
  }
@@ -2567,7 +2633,8 @@ int git_repository_set_head(
2567
2633
  error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE,
2568
2634
  git_reference_name(ref), true, git_buf_cstr(&log_message));
2569
2635
  } else {
2570
- error = git_repository_set_head_detached(repo, git_reference_target(ref));
2636
+ error = detach(repo, git_reference_target(ref),
2637
+ git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL);
2571
2638
  }
2572
2639
  } else if (git_reference__is_branch(refname)) {
2573
2640
  error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname,
@@ -2582,41 +2649,6 @@ cleanup:
2582
2649
  return error;
2583
2650
  }
2584
2651
 
2585
- static int detach(git_repository *repo, const git_oid *id, const char *from)
2586
- {
2587
- int error;
2588
- git_buf log_message = GIT_BUF_INIT;
2589
- git_object *object = NULL, *peeled = NULL;
2590
- git_reference *new_head = NULL, *current = NULL;
2591
-
2592
- assert(repo && id);
2593
-
2594
- if ((error = git_reference_lookup(&current, repo, GIT_HEAD_FILE)) < 0)
2595
- return error;
2596
-
2597
- if ((error = git_object_lookup(&object, repo, id, GIT_OBJ_ANY)) < 0)
2598
- goto cleanup;
2599
-
2600
- if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0)
2601
- goto cleanup;
2602
-
2603
- if (from == NULL)
2604
- from = git_oid_tostr_s(git_object_id(peeled));
2605
-
2606
- if ((error = checkout_message(&log_message, current, from)) < 0)
2607
- goto cleanup;
2608
-
2609
- error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_buf_cstr(&log_message));
2610
-
2611
- cleanup:
2612
- git_buf_free(&log_message);
2613
- git_object_free(object);
2614
- git_object_free(peeled);
2615
- git_reference_free(current);
2616
- git_reference_free(new_head);
2617
- return error;
2618
- }
2619
-
2620
2652
  int git_repository_set_head_detached(
2621
2653
  git_repository* repo,
2622
2654
  const git_oid* commitish)