rugged 0.23.0b2 → 0.23.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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/ext/rugged/rugged_blob.c +39 -0
  3. data/ext/rugged/rugged_diff.c +7 -3
  4. data/ext/rugged/rugged_index.c +2 -2
  5. data/ext/rugged/rugged_remote.c +27 -148
  6. data/ext/rugged/rugged_remote_collection.c +134 -12
  7. data/ext/rugged/rugged_repo.c +74 -5
  8. data/ext/rugged/rugged_submodule.c +18 -208
  9. data/ext/rugged/rugged_submodule_collection.c +148 -0
  10. data/lib/rugged/version.rb +1 -1
  11. data/vendor/libgit2/AUTHORS +1 -0
  12. data/vendor/libgit2/CMakeLists.txt +33 -25
  13. data/vendor/libgit2/deps/winhttp/winhttp.def +29 -29
  14. data/vendor/libgit2/include/git2.h +1 -1
  15. data/vendor/libgit2/include/git2/blob.h +4 -6
  16. data/vendor/libgit2/include/git2/checkout.h +10 -1
  17. data/vendor/libgit2/include/git2/clone.h +6 -7
  18. data/vendor/libgit2/include/git2/commit.h +11 -0
  19. data/vendor/libgit2/include/git2/cred_helpers.h +2 -2
  20. data/vendor/libgit2/include/git2/describe.h +1 -1
  21. data/vendor/libgit2/include/git2/diff.h +68 -11
  22. data/vendor/libgit2/include/git2/errors.h +4 -1
  23. data/vendor/libgit2/include/git2/filter.h +16 -0
  24. data/vendor/libgit2/include/git2/index.h +38 -11
  25. data/vendor/libgit2/include/git2/odb.h +1 -1
  26. data/vendor/libgit2/include/git2/odb_backend.h +2 -2
  27. data/vendor/libgit2/include/git2/remote.h +300 -207
  28. data/vendor/libgit2/include/git2/reset.h +1 -0
  29. data/vendor/libgit2/include/git2/stash.h +135 -4
  30. data/vendor/libgit2/include/git2/status.h +1 -0
  31. data/vendor/libgit2/include/git2/submodule.h +46 -75
  32. data/vendor/libgit2/include/git2/sys/odb_backend.h +1 -1
  33. data/vendor/libgit2/include/git2/sys/stream.h +2 -0
  34. data/vendor/libgit2/include/git2/sys/transport.h +1 -21
  35. data/vendor/libgit2/include/git2/transport.h +27 -0
  36. data/vendor/libgit2/include/git2/types.h +20 -10
  37. data/vendor/libgit2/include/git2/version.h +3 -3
  38. data/vendor/libgit2/libgit2.pc.in +4 -2
  39. data/vendor/libgit2/src/attr.c +2 -1
  40. data/vendor/libgit2/src/attr_file.c +18 -37
  41. data/vendor/libgit2/src/blame.c +2 -2
  42. data/vendor/libgit2/src/blob.c +4 -3
  43. data/vendor/libgit2/src/branch.c +6 -3
  44. data/vendor/libgit2/src/buf_text.c +4 -6
  45. data/vendor/libgit2/src/buf_text.h +1 -2
  46. data/vendor/libgit2/src/buffer.c +8 -6
  47. data/vendor/libgit2/src/buffer.h +1 -1
  48. data/vendor/libgit2/src/cache.c +1 -0
  49. data/vendor/libgit2/src/checkout.c +34 -20
  50. data/vendor/libgit2/src/clone.c +29 -29
  51. data/vendor/libgit2/src/commit.c +65 -0
  52. data/vendor/libgit2/src/common.h +5 -0
  53. data/vendor/libgit2/src/config.c +20 -0
  54. data/vendor/libgit2/src/config.h +6 -0
  55. data/vendor/libgit2/src/config_file.c +2 -2
  56. data/vendor/libgit2/src/crlf.c +39 -17
  57. data/vendor/libgit2/src/curl_stream.c +257 -0
  58. data/vendor/libgit2/src/curl_stream.h +14 -0
  59. data/vendor/libgit2/src/diff.c +223 -88
  60. data/vendor/libgit2/src/diff.h +21 -1
  61. data/vendor/libgit2/src/diff_file.c +23 -13
  62. data/vendor/libgit2/src/diff_file.h +4 -2
  63. data/vendor/libgit2/src/diff_patch.c +266 -71
  64. data/vendor/libgit2/src/diff_patch.h +36 -0
  65. data/vendor/libgit2/src/diff_print.c +156 -126
  66. data/vendor/libgit2/src/diff_tform.c +32 -54
  67. data/vendor/libgit2/src/fetch.c +27 -10
  68. data/vendor/libgit2/src/fetch.h +2 -2
  69. data/vendor/libgit2/src/filebuf.c +1 -1
  70. data/vendor/libgit2/src/fileops.c +6 -2
  71. data/vendor/libgit2/src/filter.c +28 -7
  72. data/vendor/libgit2/src/fnmatch.c +5 -5
  73. data/vendor/libgit2/src/global.c +16 -0
  74. data/vendor/libgit2/src/ident.c +2 -2
  75. data/vendor/libgit2/src/ignore.c +1 -0
  76. data/vendor/libgit2/src/index.c +338 -80
  77. data/vendor/libgit2/src/index.h +4 -1
  78. data/vendor/libgit2/src/indexer.c +19 -5
  79. data/vendor/libgit2/src/iterator.c +118 -11
  80. data/vendor/libgit2/src/iterator.h +25 -0
  81. data/vendor/libgit2/src/merge.c +96 -106
  82. data/vendor/libgit2/src/merge.h +14 -4
  83. data/vendor/libgit2/src/netops.c +3 -3
  84. data/vendor/libgit2/src/odb.c +17 -9
  85. data/vendor/libgit2/src/odb.h +1 -1
  86. data/vendor/libgit2/src/odb_loose.c +2 -2
  87. data/vendor/libgit2/src/odb_pack.c +1 -1
  88. data/vendor/libgit2/src/openssl_stream.c +118 -27
  89. data/vendor/libgit2/src/pack-objects.c +28 -0
  90. data/vendor/libgit2/src/pack-objects.h +1 -0
  91. data/vendor/libgit2/src/pack.c +18 -10
  92. data/vendor/libgit2/src/path.c +16 -11
  93. data/vendor/libgit2/src/path.h +1 -1
  94. data/vendor/libgit2/src/push.c +26 -42
  95. data/vendor/libgit2/src/push.h +2 -34
  96. data/vendor/libgit2/src/rebase.c +1 -1
  97. data/vendor/libgit2/src/refs.c +1 -1
  98. data/vendor/libgit2/src/refspec.c +6 -0
  99. data/vendor/libgit2/src/remote.c +381 -274
  100. data/vendor/libgit2/src/remote.h +0 -4
  101. data/vendor/libgit2/src/repository.c +33 -12
  102. data/vendor/libgit2/src/repository.h +0 -1
  103. data/vendor/libgit2/src/reset.c +1 -0
  104. data/vendor/libgit2/src/stash.c +439 -17
  105. data/vendor/libgit2/src/status.c +6 -0
  106. data/vendor/libgit2/src/stransport_stream.c +58 -21
  107. data/vendor/libgit2/src/stream.h +15 -0
  108. data/vendor/libgit2/src/submodule.c +410 -664
  109. data/vendor/libgit2/src/submodule.h +0 -24
  110. data/vendor/libgit2/src/transaction.c +1 -0
  111. data/vendor/libgit2/src/transports/cred.c +55 -1
  112. data/vendor/libgit2/src/transports/http.c +18 -2
  113. data/vendor/libgit2/src/transports/local.c +60 -59
  114. data/vendor/libgit2/src/transports/smart.h +1 -1
  115. data/vendor/libgit2/src/transports/smart_protocol.c +11 -11
  116. data/vendor/libgit2/src/transports/ssh.c +46 -7
  117. data/vendor/libgit2/src/unix/posix.h +4 -0
  118. data/vendor/libgit2/src/util.c +9 -9
  119. data/vendor/libgit2/src/util.h +9 -0
  120. data/vendor/libgit2/src/win32/posix.h +3 -0
  121. data/vendor/libgit2/src/win32/posix_w32.c +38 -0
  122. data/vendor/libgit2/src/win32/w32_util.h +10 -0
  123. metadata +4 -3
  124. data/vendor/libgit2/include/git2/push.h +0 -94
@@ -56,7 +56,7 @@ static int ident_insert_id(
56
56
  return GIT_PASSTHROUGH;
57
57
 
58
58
  need_size = (size_t)(id_start - from->ptr) +
59
- 5 /* "$Id: " */ + GIT_OID_HEXSZ + 1 /* "$" */ +
59
+ 5 /* "$Id: " */ + GIT_OID_HEXSZ + 2 /* " $" */ +
60
60
  (size_t)(from_end - id_end);
61
61
 
62
62
  if (git_buf_grow(to, need_size) < 0)
@@ -65,7 +65,7 @@ static int ident_insert_id(
65
65
  git_buf_set(to, from->ptr, (size_t)(id_start - from->ptr));
66
66
  git_buf_put(to, "$Id: ", 5);
67
67
  git_buf_put(to, oid, GIT_OID_HEXSZ);
68
- git_buf_putc(to, '$');
68
+ git_buf_put(to, " $", 2);
69
69
  git_buf_put(to, id_end, (size_t)(from_end - id_end));
70
70
 
71
71
  return git_buf_oom(to) ? -1 : 0;
@@ -80,6 +80,7 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
80
80
  git_vector_foreach(rules, i, rule) {
81
81
  if (!(rule->flags & GIT_ATTR_FNMATCH_HASWILD)) {
82
82
  if (does_negate_pattern(rule, match)) {
83
+ error = 0;
83
84
  *out = 1;
84
85
  goto out;
85
86
  }
@@ -24,6 +24,10 @@
24
24
  #include "git2/config.h"
25
25
  #include "git2/sys/index.h"
26
26
 
27
+ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
28
+ unsigned int flags,
29
+ git_index_matched_path_cb cb, void *payload);
30
+
27
31
  #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7)
28
32
  #define short_entry_size(len) entry_size(struct entry_short, len)
29
33
  #define long_entry_size(len) entry_size(struct entry_long, len)
@@ -112,7 +116,7 @@ static int read_header(struct index_header *dest, const void *buffer);
112
116
 
113
117
  static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
114
118
  static bool is_index_extended(git_index *index);
115
- static int write_index(git_index *index, git_filebuf *file);
119
+ static int write_index(git_oid *checksum, git_index *index, git_filebuf *file);
116
120
 
117
121
  static void index_entry_free(git_index_entry *entry);
118
122
  static void index_entry_reuc_free(git_index_reuc_entry *reuc);
@@ -594,6 +598,38 @@ int git_index_caps(const git_index *index)
594
598
  (index->no_symlinks ? GIT_INDEXCAP_NO_SYMLINKS : 0));
595
599
  }
596
600
 
601
+ const git_oid *git_index_checksum(git_index *index)
602
+ {
603
+ return &index->checksum;
604
+ }
605
+
606
+ /**
607
+ * Returns 1 for changed, 0 for not changed and <0 for errors
608
+ */
609
+ static int compare_checksum(git_index *index)
610
+ {
611
+ int fd, error;
612
+ ssize_t bytes_read;
613
+ git_oid checksum = {{ 0 }};
614
+
615
+ if ((fd = p_open(index->index_file_path, O_RDONLY)) < 0)
616
+ return fd;
617
+
618
+ if ((error = p_lseek(fd, -20, SEEK_END)) < 0) {
619
+ p_close(fd);
620
+ giterr_set(GITERR_OS, "failed to seek to end of file");
621
+ return -1;
622
+ }
623
+
624
+ bytes_read = p_read(fd, &checksum, GIT_OID_RAWSZ);
625
+ p_close(fd);
626
+
627
+ if (bytes_read < 0)
628
+ return -1;
629
+
630
+ return !!git_oid_cmp(&checksum, &index->checksum);
631
+ }
632
+
597
633
  int git_index_read(git_index *index, int force)
598
634
  {
599
635
  int error = 0, updated;
@@ -612,8 +648,8 @@ int git_index_read(git_index *index, int force)
612
648
  return 0;
613
649
  }
614
650
 
615
- updated = git_futils_filestamp_check(&stamp, index->index_file_path);
616
- if (updated < 0) {
651
+ if ((updated = git_futils_filestamp_check(&stamp, index->index_file_path) < 0) ||
652
+ ((updated = compare_checksum(index)) < 0)) {
617
653
  giterr_set(
618
654
  GITERR_INDEX,
619
655
  "Failed to read index: '%s' no longer exists",
@@ -643,15 +679,68 @@ int git_index_read(git_index *index, int force)
643
679
  }
644
680
 
645
681
  int git_index__changed_relative_to(
646
- git_index *index, const git_futils_filestamp *fs)
682
+ git_index *index, const git_oid *checksum)
647
683
  {
648
684
  /* attempt to update index (ignoring errors) */
649
685
  if (git_index_read(index, false) < 0)
650
686
  giterr_clear();
651
687
 
652
- return (index->stamp.mtime != fs->mtime ||
653
- index->stamp.size != fs->size ||
654
- index->stamp.ino != fs->ino);
688
+ return !!git_oid_cmp(&index->checksum, checksum);
689
+ }
690
+
691
+ static bool is_racy_timestamp(git_time_t stamp, git_index_entry *entry)
692
+ {
693
+ /* Git special-cases submodules in the check */
694
+ if (S_ISGITLINK(entry->mode))
695
+ return false;
696
+
697
+ /* If we never read the index, we can't have this race either */
698
+ if (stamp == 0)
699
+ return false;
700
+
701
+ /* If the timestamp is the same or newer than the index, it's racy */
702
+ return ((int32_t) stamp) <= entry->mtime.seconds;
703
+ }
704
+
705
+ /*
706
+ * Force the next diff to take a look at those entries which have the
707
+ * same timestamp as the current index.
708
+ */
709
+ static int truncate_racily_clean(git_index *index)
710
+ {
711
+ size_t i;
712
+ int error;
713
+ git_index_entry *entry;
714
+ git_time_t ts = index->stamp.mtime;
715
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
716
+ git_diff *diff;
717
+
718
+ /* Nothing to do if there's no repo to talk about */
719
+ if (!INDEX_OWNER(index))
720
+ return 0;
721
+
722
+ /* If there's no workdir, we can't know where to even check */
723
+ if (!git_repository_workdir(INDEX_OWNER(index)))
724
+ return 0;
725
+
726
+ diff_opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE | GIT_DIFF_IGNORE_SUBMODULES | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
727
+ git_vector_foreach(&index->entries, i, entry) {
728
+ if (!is_racy_timestamp(ts, entry))
729
+ continue;
730
+
731
+ diff_opts.pathspec.count = 1;
732
+ diff_opts.pathspec.strings = (char **) &entry->path;
733
+
734
+ if ((error = git_diff_index_to_workdir(&diff, INDEX_OWNER(index), index, &diff_opts)) < 0)
735
+ return error;
736
+
737
+ if (git_diff_num_deltas(diff) > 0)
738
+ entry->file_size = 0;
739
+
740
+ git_diff_free(diff);
741
+ }
742
+
743
+ return 0;
655
744
  }
656
745
 
657
746
  int git_index_write(git_index *index)
@@ -659,6 +748,8 @@ int git_index_write(git_index *index)
659
748
  git_indexwriter writer = GIT_INDEXWRITER_INIT;
660
749
  int error;
661
750
 
751
+ truncate_racily_clean(index);
752
+
662
753
  if ((error = git_indexwriter_init(&writer, index)) == 0)
663
754
  error = git_indexwriter_commit(&writer);
664
755
 
@@ -1169,6 +1260,9 @@ int git_index_remove_bypath(git_index *index, const char *path)
1169
1260
  ret != GIT_ENOTFOUND))
1170
1261
  return ret;
1171
1262
 
1263
+ if (ret == GIT_ENOTFOUND)
1264
+ giterr_clear();
1265
+
1172
1266
  return 0;
1173
1267
  }
1174
1268
 
@@ -1310,6 +1404,30 @@ int git_index_conflict_add(git_index *index,
1310
1404
  (ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
1311
1405
  goto on_error;
1312
1406
 
1407
+ /* Validate entries */
1408
+ for (i = 0; i < 3; i++) {
1409
+ if (entries[i] && !valid_filemode(entries[i]->mode)) {
1410
+ giterr_set(GITERR_INDEX, "invalid filemode for stage %d entry",
1411
+ i);
1412
+ return -1;
1413
+ }
1414
+ }
1415
+
1416
+ /* Remove existing index entries for each path */
1417
+ for (i = 0; i < 3; i++) {
1418
+ if (entries[i] == NULL)
1419
+ continue;
1420
+
1421
+ if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) {
1422
+ if (ret != GIT_ENOTFOUND)
1423
+ goto on_error;
1424
+
1425
+ giterr_clear();
1426
+ ret = 0;
1427
+ }
1428
+ }
1429
+
1430
+ /* Add the conflict entries */
1313
1431
  for (i = 0; i < 3; i++) {
1314
1432
  if (entries[i] == NULL)
1315
1433
  continue;
@@ -1317,7 +1435,7 @@ int git_index_conflict_add(git_index *index,
1317
1435
  /* Make sure stage is correct */
1318
1436
  GIT_IDXENTRY_STAGE_SET(entries[i], i + 1);
1319
1437
 
1320
- if ((ret = index_insert(index, &entries[i], 1, true)) < 0)
1438
+ if ((ret = index_insert(index, &entries[i], 0, true)) < 0)
1321
1439
  goto on_error;
1322
1440
 
1323
1441
  entries[i] = NULL; /* don't free if later entry fails */
@@ -1506,7 +1624,7 @@ int git_index_conflict_next(
1506
1624
  while (iterator->cur < iterator->index->entries.length) {
1507
1625
  entry = git_index_get_byindex(iterator->index, iterator->cur);
1508
1626
 
1509
- if (git_index_entry_stage(entry) > 0) {
1627
+ if (git_index_entry_is_conflict(entry)) {
1510
1628
  if ((len = index_conflict__get_byindex(
1511
1629
  ancestor_out,
1512
1630
  our_out,
@@ -2043,6 +2161,8 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
2043
2161
  goto done;
2044
2162
  }
2045
2163
 
2164
+ git_oid_cpy(&index->checksum, &checksum_calculated);
2165
+
2046
2166
  #undef seek_forward
2047
2167
 
2048
2168
  /* Entries are stored case-sensitively on disk, so re-sort now if
@@ -2306,7 +2426,7 @@ static int write_tree_extension(git_index *index, git_filebuf *file)
2306
2426
  return error;
2307
2427
  }
2308
2428
 
2309
- static int write_index(git_index *index, git_filebuf *file)
2429
+ static int write_index(git_oid *checksum, git_index *index, git_filebuf *file)
2310
2430
  {
2311
2431
  git_oid hash_final;
2312
2432
  struct index_header header;
@@ -2342,6 +2462,7 @@ static int write_index(git_index *index, git_filebuf *file)
2342
2462
 
2343
2463
  /* get out the hash for all the contents we've appended to the file */
2344
2464
  git_filebuf_hash(&hash_final, file);
2465
+ git_oid_cpy(checksum, &hash_final);
2345
2466
 
2346
2467
  /* write it at the end of the file */
2347
2468
  return git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ);
@@ -2352,6 +2473,11 @@ int git_index_entry_stage(const git_index_entry *entry)
2352
2473
  return GIT_IDXENTRY_STAGE(entry);
2353
2474
  }
2354
2475
 
2476
+ int git_index_entry_is_conflict(const git_index_entry *entry)
2477
+ {
2478
+ return (GIT_IDXENTRY_STAGE(entry) > 0);
2479
+ }
2480
+
2355
2481
  typedef struct read_tree_data {
2356
2482
  git_index *index;
2357
2483
  git_vector *old_entries;
@@ -2451,11 +2577,116 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
2451
2577
  return error;
2452
2578
  }
2453
2579
 
2580
+ int git_index_read_index(
2581
+ git_index *index,
2582
+ const git_index *new_index)
2583
+ {
2584
+ git_vector new_entries = GIT_VECTOR_INIT,
2585
+ remove_entries = GIT_VECTOR_INIT;
2586
+ git_iterator *index_iterator = NULL;
2587
+ git_iterator *new_iterator = NULL;
2588
+ const git_index_entry *old_entry, *new_entry;
2589
+ git_index_entry *entry;
2590
+ size_t i;
2591
+ int error;
2592
+
2593
+ if ((error = git_vector_init(&new_entries, new_index->entries.length, index->entries._cmp)) < 0 ||
2594
+ (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0)
2595
+ goto done;
2596
+
2597
+ if ((error = git_iterator_for_index(&index_iterator,
2598
+ index, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 ||
2599
+ (error = git_iterator_for_index(&new_iterator,
2600
+ (git_index *)new_index, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0)
2601
+ goto done;
2602
+
2603
+ if (((error = git_iterator_current(&old_entry, index_iterator)) < 0 &&
2604
+ error != GIT_ITEROVER) ||
2605
+ ((error = git_iterator_current(&new_entry, new_iterator)) < 0 &&
2606
+ error != GIT_ITEROVER))
2607
+ goto done;
2608
+
2609
+ while (true) {
2610
+ int diff;
2611
+
2612
+ if (old_entry && new_entry)
2613
+ diff = git_index_entry_cmp(old_entry, new_entry);
2614
+ else if (!old_entry && new_entry)
2615
+ diff = 1;
2616
+ else if (old_entry && !new_entry)
2617
+ diff = -1;
2618
+ else
2619
+ break;
2620
+
2621
+ if (diff < 0) {
2622
+ git_vector_insert(&remove_entries, (git_index_entry *)old_entry);
2623
+ } else if (diff > 0) {
2624
+ if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
2625
+ goto done;
2626
+
2627
+ git_vector_insert(&new_entries, entry);
2628
+ } else {
2629
+ /* Path and stage are equal, if the OID is equal, keep it to
2630
+ * keep the stat cache data.
2631
+ */
2632
+ if (git_oid_equal(&old_entry->id, &new_entry->id)) {
2633
+ git_vector_insert(&new_entries, (git_index_entry *)old_entry);
2634
+ } else {
2635
+ if ((error = index_entry_dup(&entry, git_index_owner(index), new_entry)) < 0)
2636
+ goto done;
2637
+
2638
+ git_vector_insert(&new_entries, entry);
2639
+ git_vector_insert(&remove_entries, (git_index_entry *)old_entry);
2640
+ }
2641
+ }
2642
+
2643
+ if (diff <= 0) {
2644
+ if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 &&
2645
+ error != GIT_ITEROVER)
2646
+ goto done;
2647
+ }
2648
+
2649
+ if (diff >= 0) {
2650
+ if ((error = git_iterator_advance(&new_entry, new_iterator)) < 0 &&
2651
+ error != GIT_ITEROVER)
2652
+ goto done;
2653
+ }
2654
+ }
2655
+
2656
+ git_index_name_clear(index);
2657
+ git_index_reuc_clear(index);
2658
+
2659
+ git_vector_swap(&new_entries, &index->entries);
2660
+
2661
+ git_vector_foreach(&remove_entries, i, entry) {
2662
+ if (index->tree)
2663
+ git_tree_cache_invalidate_path(index->tree, entry->path);
2664
+
2665
+ index_entry_free(entry);
2666
+ }
2667
+
2668
+ error = 0;
2669
+
2670
+ done:
2671
+ git_vector_free(&new_entries);
2672
+ git_vector_free(&remove_entries);
2673
+ git_iterator_free(index_iterator);
2674
+ git_iterator_free(new_iterator);
2675
+ return error;
2676
+ }
2677
+
2454
2678
  git_repository *git_index_owner(const git_index *index)
2455
2679
  {
2456
2680
  return INDEX_OWNER(index);
2457
2681
  }
2458
2682
 
2683
+ enum {
2684
+ INDEX_ACTION_NONE = 0,
2685
+ INDEX_ACTION_UPDATE = 1,
2686
+ INDEX_ACTION_REMOVE = 2,
2687
+ INDEX_ACTION_ADDALL = 3,
2688
+ };
2689
+
2459
2690
  int git_index_add_all(
2460
2691
  git_index *index,
2461
2692
  const git_strarray *paths,
@@ -2466,29 +2697,15 @@ int git_index_add_all(
2466
2697
  int error;
2467
2698
  git_repository *repo;
2468
2699
  git_iterator *wditer = NULL;
2469
- const git_index_entry *wd = NULL;
2470
- git_index_entry *entry;
2471
2700
  git_pathspec ps;
2472
- const char *match;
2473
- size_t existing;
2474
2701
  bool no_fnmatch = (flags & GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH) != 0;
2475
- int ignorecase;
2476
- git_oid blobid;
2477
2702
 
2478
2703
  assert(index);
2479
2704
 
2480
- if (INDEX_OWNER(index) == NULL)
2481
- return create_index_error(-1,
2482
- "Could not add paths to index. "
2483
- "Index is not backed up by an existing repository.");
2484
-
2485
2705
  repo = INDEX_OWNER(index);
2486
2706
  if ((error = git_repository__ensure_not_bare(repo, "index add all")) < 0)
2487
2707
  return error;
2488
2708
 
2489
- if (git_repository__cvar(&ignorecase, repo, GIT_CVAR_IGNORECASE) < 0)
2490
- return -1;
2491
-
2492
2709
  if ((error = git_pathspec__init(&ps, paths)) < 0)
2493
2710
  return error;
2494
2711
 
@@ -2499,77 +2716,118 @@ int git_index_add_all(
2499
2716
  repo, &ps.pathspec, no_fnmatch)) < 0)
2500
2717
  goto cleanup;
2501
2718
 
2502
- if ((error = git_iterator_for_workdir(
2503
- &wditer, repo, NULL, NULL, 0, ps.prefix, ps.prefix)) < 0)
2504
- goto cleanup;
2719
+ error = index_apply_to_wd_diff(index, INDEX_ACTION_ADDALL, paths, flags, cb, payload);
2505
2720
 
2506
- while (!(error = git_iterator_advance(&wd, wditer))) {
2721
+ if (error)
2722
+ giterr_set_after_callback(error);
2507
2723
 
2508
- /* check if path actually matches */
2509
- if (!git_pathspec__match(
2510
- &ps.pathspec, wd->path, no_fnmatch, (bool)ignorecase, &match, NULL))
2511
- continue;
2724
+ cleanup:
2725
+ git_iterator_free(wditer);
2726
+ git_pathspec__clear(&ps);
2512
2727
 
2513
- /* skip ignored items that are not already in the index */
2514
- if ((flags & GIT_INDEX_ADD_FORCE) == 0 &&
2515
- git_iterator_current_is_ignored(wditer) &&
2516
- index_find(&existing, index, wd->path, 0, 0, true) < 0)
2517
- continue;
2728
+ return error;
2729
+ }
2518
2730
 
2519
- /* issue notification callback if requested */
2520
- if (cb && (error = cb(wd->path, match, payload)) != 0) {
2521
- if (error > 0) /* return > 0 means skip this one */
2522
- continue;
2523
- if (error < 0) { /* return < 0 means abort */
2524
- giterr_set_after_callback(error);
2525
- break;
2526
- }
2527
- }
2731
+ struct foreach_diff_data {
2732
+ git_index *index;
2733
+ const git_pathspec *pathspec;
2734
+ unsigned int flags;
2735
+ git_index_matched_path_cb cb;
2736
+ void *payload;
2737
+ };
2528
2738
 
2529
- /* TODO: Should we check if the file on disk is already an exact
2530
- * match to the file in the index and skip this work if it is?
2531
- */
2739
+ static int apply_each_file(const git_diff_delta *delta, float progress, void *payload)
2740
+ {
2741
+ struct foreach_diff_data *data = payload;
2742
+ const char *match, *path;
2743
+ int error = 0;
2532
2744
 
2533
- /* write the blob to disk and get the oid */
2534
- if ((error = git_blob_create_fromworkdir(&blobid, repo, wd->path)) < 0)
2535
- break;
2745
+ GIT_UNUSED(progress);
2536
2746
 
2537
- /* make the new entry to insert */
2538
- if ((error = index_entry_dup(&entry, INDEX_OWNER(index), wd)) < 0)
2539
- break;
2747
+ path = delta->old_file.path;
2748
+
2749
+ /* We only want those which match the pathspecs */
2750
+ if (!git_pathspec__match(
2751
+ &data->pathspec->pathspec, path, false, (bool)data->index->ignore_case,
2752
+ &match, NULL))
2753
+ return 0;
2540
2754
 
2541
- entry->id = blobid;
2755
+ if (data->cb)
2756
+ error = data->cb(path, match, data->payload);
2542
2757
 
2543
- /* add working directory item to index */
2544
- if ((error = index_insert(index, &entry, 1, false)) < 0)
2545
- break;
2758
+ if (error > 0) /* skip this entry */
2759
+ return 0;
2760
+ if (error < 0) /* actual error */
2761
+ return error;
2546
2762
 
2547
- git_tree_cache_invalidate_path(index->tree, wd->path);
2763
+ /* If the workdir item does not exist, remove it from the index. */
2764
+ if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0)
2765
+ error = git_index_remove_bypath(data->index, path);
2766
+ else
2767
+ error = git_index_add_bypath(data->index, delta->new_file.path);
2548
2768
 
2549
- /* add implies conflict resolved, move conflict entries to REUC */
2550
- if ((error = index_conflict_to_reuc(index, wd->path)) < 0) {
2551
- if (error != GIT_ENOTFOUND)
2552
- break;
2553
- giterr_clear();
2554
- }
2769
+ return error;
2770
+ }
2771
+
2772
+ static int index_apply_to_wd_diff(git_index *index, int action, const git_strarray *paths,
2773
+ unsigned int flags,
2774
+ git_index_matched_path_cb cb, void *payload)
2775
+ {
2776
+ int error;
2777
+ git_diff *diff;
2778
+ git_pathspec ps;
2779
+ git_repository *repo;
2780
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
2781
+ struct foreach_diff_data data = {
2782
+ index,
2783
+ NULL,
2784
+ flags,
2785
+ cb,
2786
+ payload,
2787
+ };
2788
+
2789
+ assert(index);
2790
+ assert(action == INDEX_ACTION_UPDATE || action == INDEX_ACTION_ADDALL);
2791
+
2792
+ repo = INDEX_OWNER(index);
2793
+
2794
+ if (!repo) {
2795
+ return create_index_error(-1,
2796
+ "cannot run update; the index is not backed up by a repository.");
2797
+ }
2798
+
2799
+ /*
2800
+ * We do the matching ourselves intead of passing the list to
2801
+ * diff because we want to tell the callback which one
2802
+ * matched, which we do not know if we ask diff to filter for us.
2803
+ */
2804
+ if ((error = git_pathspec__init(&ps, paths)) < 0)
2805
+ return error;
2806
+
2807
+ opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
2808
+ if (action == INDEX_ACTION_ADDALL) {
2809
+ opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED |
2810
+ GIT_DIFF_RECURSE_UNTRACKED_DIRS;
2811
+
2812
+ if (flags == GIT_INDEX_ADD_FORCE)
2813
+ opts.flags |= GIT_DIFF_INCLUDE_IGNORED;
2555
2814
  }
2556
2815
 
2557
- if (error == GIT_ITEROVER)
2558
- error = 0;
2816
+ if ((error = git_diff_index_to_workdir(&diff, repo, index, &opts)) < 0)
2817
+ goto cleanup;
2818
+
2819
+ data.pathspec = &ps;
2820
+ error = git_diff_foreach(diff, apply_each_file, NULL, NULL, NULL, &data);
2821
+ git_diff_free(diff);
2822
+
2823
+ if (error) /* make sure error is set if callback stopped iteration */
2824
+ giterr_set_after_callback(error);
2559
2825
 
2560
2826
  cleanup:
2561
- git_iterator_free(wditer);
2562
2827
  git_pathspec__clear(&ps);
2563
-
2564
2828
  return error;
2565
2829
  }
2566
2830
 
2567
- enum {
2568
- INDEX_ACTION_NONE = 0,
2569
- INDEX_ACTION_UPDATE = 1,
2570
- INDEX_ACTION_REMOVE = 2,
2571
- };
2572
-
2573
2831
  static int index_apply_to_all(
2574
2832
  git_index *index,
2575
2833
  int action,
@@ -2666,9 +2924,7 @@ int git_index_update_all(
2666
2924
  git_index_matched_path_cb cb,
2667
2925
  void *payload)
2668
2926
  {
2669
- int error = index_apply_to_all(
2670
- index, INDEX_ACTION_UPDATE, pathspec, cb, payload);
2671
-
2927
+ int error = index_apply_to_wd_diff(index, INDEX_ACTION_UPDATE, pathspec, 0, cb, payload);
2672
2928
  if (error) /* make sure error is set if callback stopped iteration */
2673
2929
  giterr_set_after_callback(error);
2674
2930
 
@@ -2769,6 +3025,7 @@ int git_indexwriter_init_for_operation(
2769
3025
  int git_indexwriter_commit(git_indexwriter *writer)
2770
3026
  {
2771
3027
  int error;
3028
+ git_oid checksum = {{ 0 }};
2772
3029
 
2773
3030
  if (!writer->should_write)
2774
3031
  return 0;
@@ -2778,7 +3035,7 @@ int git_indexwriter_commit(git_indexwriter *writer)
2778
3035
 
2779
3036
  git_vector_sort(&writer->index->reuc);
2780
3037
 
2781
- if ((error = write_index(writer->index, &writer->file)) < 0) {
3038
+ if ((error = write_index(&checksum, writer->index, &writer->file)) < 0) {
2782
3039
  git_indexwriter_cleanup(writer);
2783
3040
  return error;
2784
3041
  }
@@ -2793,6 +3050,7 @@ int git_indexwriter_commit(git_indexwriter *writer)
2793
3050
  }
2794
3051
 
2795
3052
  writer->index->on_disk = 1;
3053
+ git_oid_cpy(&writer->index->checksum, &checksum);
2796
3054
 
2797
3055
  git_index_free(writer->index);
2798
3056
  writer->index = NULL;