rugged 0.23.3 → 0.24.0b0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/ext/rugged/rugged.c +24 -0
  4. data/ext/rugged/rugged_config.c +65 -0
  5. data/ext/rugged/rugged_remote.c +22 -2
  6. data/ext/rugged/rugged_repo.c +10 -5
  7. data/ext/rugged/rugged_tree.c +4 -1
  8. data/lib/rugged/version.rb +1 -1
  9. data/vendor/libgit2/CMakeLists.txt +47 -2
  10. data/vendor/libgit2/include/git2/config.h +18 -0
  11. data/vendor/libgit2/include/git2/diff.h +25 -2
  12. data/vendor/libgit2/include/git2/errors.h +0 -12
  13. data/vendor/libgit2/include/git2/index.h +11 -0
  14. data/vendor/libgit2/include/git2/remote.h +12 -1
  15. data/vendor/libgit2/include/git2/sys/config.h +14 -0
  16. data/vendor/libgit2/include/git2/sys/filter.h +4 -1
  17. data/vendor/libgit2/include/git2/sys/odb_backend.h +4 -0
  18. data/vendor/libgit2/include/git2/sys/refdb_backend.h +5 -4
  19. data/vendor/libgit2/include/git2/sys/transport.h +27 -0
  20. data/vendor/libgit2/include/git2/transport.h +25 -21
  21. data/vendor/libgit2/include/git2/version.h +2 -2
  22. data/vendor/libgit2/libgit2.pc.in +3 -2
  23. data/vendor/libgit2/src/branch.c +1 -12
  24. data/vendor/libgit2/src/checkout.c +29 -20
  25. data/vendor/libgit2/src/clone.c +2 -2
  26. data/vendor/libgit2/src/common.h +13 -4
  27. data/vendor/libgit2/src/config.c +36 -0
  28. data/vendor/libgit2/src/config.h +15 -0
  29. data/vendor/libgit2/src/config_file.c +124 -20
  30. data/vendor/libgit2/src/config_file.h +10 -0
  31. data/vendor/libgit2/src/curl_stream.c +7 -7
  32. data/vendor/libgit2/src/diff.c +89 -27
  33. data/vendor/libgit2/src/diff_print.c +1 -1
  34. data/vendor/libgit2/src/errors.c +75 -40
  35. data/vendor/libgit2/src/filebuf.c +81 -3
  36. data/vendor/libgit2/src/fileops.c +176 -75
  37. data/vendor/libgit2/src/fileops.h +7 -10
  38. data/vendor/libgit2/src/filter.c +5 -2
  39. data/vendor/libgit2/src/global.c +25 -9
  40. data/vendor/libgit2/src/global.h +1 -0
  41. data/vendor/libgit2/src/idxmap.h +92 -0
  42. data/vendor/libgit2/src/ignore.c +9 -7
  43. data/vendor/libgit2/src/index.c +246 -46
  44. data/vendor/libgit2/src/index.h +2 -0
  45. data/vendor/libgit2/src/iterator.c +377 -118
  46. data/vendor/libgit2/src/iterator.h +28 -20
  47. data/vendor/libgit2/src/merge.c +26 -13
  48. data/vendor/libgit2/src/notes.c +1 -1
  49. data/vendor/libgit2/src/odb.c +1 -2
  50. data/vendor/libgit2/src/odb_loose.c +2 -2
  51. data/vendor/libgit2/src/odb_mempack.c +6 -2
  52. data/vendor/libgit2/src/oidmap.h +2 -0
  53. data/vendor/libgit2/src/openssl_stream.c +9 -3
  54. data/vendor/libgit2/src/path.c +37 -2
  55. data/vendor/libgit2/src/path.h +12 -1
  56. data/vendor/libgit2/src/pathspec.c +12 -12
  57. data/vendor/libgit2/src/push.c +2 -1
  58. data/vendor/libgit2/src/push.h +1 -0
  59. data/vendor/libgit2/src/refdb.c +2 -6
  60. data/vendor/libgit2/src/refdb_fs.c +13 -3
  61. data/vendor/libgit2/src/remote.c +44 -15
  62. data/vendor/libgit2/src/repository.c +28 -12
  63. data/vendor/libgit2/src/stash.c +17 -12
  64. data/vendor/libgit2/src/stransport_stream.c +1 -1
  65. data/vendor/libgit2/src/submodule.c +234 -152
  66. data/vendor/libgit2/src/sysdir.c +22 -8
  67. data/vendor/libgit2/src/transaction.c +41 -0
  68. data/vendor/libgit2/src/transaction.h +14 -0
  69. data/vendor/libgit2/src/transports/cred.c +8 -0
  70. data/vendor/libgit2/src/transports/http.c +6 -0
  71. data/vendor/libgit2/src/transports/smart.c +95 -0
  72. data/vendor/libgit2/src/transports/smart.h +1 -0
  73. data/vendor/libgit2/src/transports/smart_pkt.c +9 -2
  74. data/vendor/libgit2/src/transports/ssh.c +5 -3
  75. data/vendor/libgit2/src/transports/winhttp.c +19 -1
  76. data/vendor/libgit2/src/unix/posix.h +14 -1
  77. data/vendor/libgit2/src/util.c +56 -13
  78. data/vendor/libgit2/src/util.h +13 -5
  79. data/vendor/libgit2/src/win32/path_w32.c +15 -8
  80. data/vendor/libgit2/src/win32/posix_w32.c +11 -2
  81. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +343 -0
  82. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +93 -0
  83. data/vendor/libgit2/src/win32/w32_stack.c +192 -0
  84. data/vendor/libgit2/src/win32/w32_stack.h +138 -0
  85. data/vendor/libgit2/src/win32/w32_util.c +29 -5
  86. data/vendor/libgit2/src/win32/w32_util.h +13 -3
  87. metadata +11 -5
@@ -88,4 +88,19 @@ extern int git_config__cvar(
88
88
  */
89
89
  int git_config_lookup_map_enum(git_cvar_t *type_out, const char **str_out,
90
90
  const git_cvar_map *maps, size_t map_n, int enum_val);
91
+
92
+ /**
93
+ * Unlock the backend with the highest priority
94
+ *
95
+ * Unlocking will allow other writers to updat the configuration
96
+ * file. Optionally, any changes performed since the lock will be
97
+ * applied to the configuration.
98
+ *
99
+ * @param cfg the configuration
100
+ * @param commit boolean which indicates whether to commit any changes
101
+ * done since locking
102
+ * @return 0 or an error code
103
+ */
104
+ GIT_EXTERN(int) git_config_unlock(git_config *cfg, int commit);
105
+
91
106
  #endif
@@ -105,6 +105,10 @@ typedef struct {
105
105
 
106
106
  git_array_t(struct reader) readers;
107
107
 
108
+ bool locked;
109
+ git_filebuf locked_buf;
110
+ git_buf locked_content;
111
+
108
112
  char *file_path;
109
113
  } diskfile_backend;
110
114
 
@@ -685,6 +689,42 @@ static int config_snapshot(git_config_backend **out, git_config_backend *in)
685
689
  return git_config_file__snapshot(out, b);
686
690
  }
687
691
 
692
+ static int config_lock(git_config_backend *_cfg)
693
+ {
694
+ diskfile_backend *cfg = (diskfile_backend *) _cfg;
695
+ int error;
696
+
697
+ if ((error = git_filebuf_open(&cfg->locked_buf, cfg->file_path, 0, GIT_CONFIG_FILE_MODE)) < 0)
698
+ return error;
699
+
700
+ error = git_futils_readbuffer(&cfg->locked_content, cfg->file_path);
701
+ if (error < 0 && error != GIT_ENOTFOUND) {
702
+ git_filebuf_cleanup(&cfg->locked_buf);
703
+ return error;
704
+ }
705
+
706
+ cfg->locked = true;
707
+ return 0;
708
+
709
+ }
710
+
711
+ static int config_unlock(git_config_backend *_cfg, int success)
712
+ {
713
+ diskfile_backend *cfg = (diskfile_backend *) _cfg;
714
+ int error = 0;
715
+
716
+ if (success) {
717
+ git_filebuf_write(&cfg->locked_buf, cfg->locked_content.ptr, cfg->locked_content.size);
718
+ error = git_filebuf_commit(&cfg->locked_buf);
719
+ }
720
+
721
+ git_filebuf_cleanup(&cfg->locked_buf);
722
+ git_buf_free(&cfg->locked_content);
723
+ cfg->locked = false;
724
+
725
+ return error;
726
+ }
727
+
688
728
  int git_config_file__ondisk(git_config_backend **out, const char *path)
689
729
  {
690
730
  diskfile_backend *backend;
@@ -706,6 +746,8 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
706
746
  backend->header.parent.del_multivar = config_delete_multivar;
707
747
  backend->header.parent.iterator = config_iterator_new;
708
748
  backend->header.parent.snapshot = config_snapshot;
749
+ backend->header.parent.lock = config_lock;
750
+ backend->header.parent.unlock = config_unlock;
709
751
  backend->header.parent.free = backend_free;
710
752
 
711
753
  *out = (git_config_backend *)backend;
@@ -750,6 +792,21 @@ static int config_delete_readonly(git_config_backend *cfg, const char *name)
750
792
  return config_error_readonly();
751
793
  }
752
794
 
795
+ static int config_lock_readonly(git_config_backend *_cfg)
796
+ {
797
+ GIT_UNUSED(_cfg);
798
+
799
+ return config_error_readonly();
800
+ }
801
+
802
+ static int config_unlock_readonly(git_config_backend *_cfg, int success)
803
+ {
804
+ GIT_UNUSED(_cfg);
805
+ GIT_UNUSED(success);
806
+
807
+ return config_error_readonly();
808
+ }
809
+
753
810
  static void backend_readonly_free(git_config_backend *_backend)
754
811
  {
755
812
  diskfile_backend *backend = (diskfile_backend *)_backend;
@@ -803,6 +860,8 @@ int git_config_file__snapshot(git_config_backend **out, diskfile_backend *in)
803
860
  backend->header.parent.del = config_delete_readonly;
804
861
  backend->header.parent.del_multivar = config_delete_multivar_readonly;
805
862
  backend->header.parent.iterator = config_iterator_new;
863
+ backend->header.parent.lock = config_lock_readonly;
864
+ backend->header.parent.unlock = config_unlock_readonly;
806
865
  backend->header.parent.free = backend_readonly_free;
807
866
 
808
867
  *out = (git_config_backend *)backend;
@@ -1602,7 +1661,7 @@ static int config_read(git_strmap *values, diskfile_backend *cfg_file, struct re
1602
1661
  return config_parse(reader, NULL, read_on_variable, NULL, NULL, &parse_data);
1603
1662
  }
1604
1663
 
1605
- static int write_section(git_filebuf *file, const char *key)
1664
+ static int write_section(git_buf *fbuf, const char *key)
1606
1665
  {
1607
1666
  int result;
1608
1667
  const char *dot;
@@ -1626,7 +1685,7 @@ static int write_section(git_filebuf *file, const char *key)
1626
1685
  if (git_buf_oom(&buf))
1627
1686
  return -1;
1628
1687
 
1629
- result = git_filebuf_write(file, git_buf_cstr(&buf), buf.size);
1688
+ result = git_buf_put(fbuf, git_buf_cstr(&buf), buf.size);
1630
1689
  git_buf_free(&buf);
1631
1690
 
1632
1691
  return result;
@@ -1651,7 +1710,8 @@ static const char *quotes_for_value(const char *value)
1651
1710
  }
1652
1711
 
1653
1712
  struct write_data {
1654
- git_filebuf *file;
1713
+ git_buf *buf;
1714
+ git_buf buffered_comment;
1655
1715
  unsigned int in_section : 1,
1656
1716
  preg_replaced : 1;
1657
1717
  const char *section;
@@ -1660,23 +1720,28 @@ struct write_data {
1660
1720
  const char *value;
1661
1721
  };
1662
1722
 
1663
- static int write_line(struct write_data *write_data, const char *line, size_t line_len)
1723
+ static int write_line_to(git_buf *buf, const char *line, size_t line_len)
1664
1724
  {
1665
- int result = git_filebuf_write(write_data->file, line, line_len);
1725
+ int result = git_buf_put(buf, line, line_len);
1666
1726
 
1667
1727
  if (!result && line_len && line[line_len-1] != '\n')
1668
- result = git_filebuf_printf(write_data->file, "\n");
1728
+ result = git_buf_printf(buf, "\n");
1669
1729
 
1670
1730
  return result;
1671
1731
  }
1672
1732
 
1733
+ static int write_line(struct write_data *write_data, const char *line, size_t line_len)
1734
+ {
1735
+ return write_line_to(write_data->buf, line, line_len);
1736
+ }
1737
+
1673
1738
  static int write_value(struct write_data *write_data)
1674
1739
  {
1675
1740
  const char *q;
1676
1741
  int result;
1677
1742
 
1678
1743
  q = quotes_for_value(write_data->value);
1679
- result = git_filebuf_printf(write_data->file,
1744
+ result = git_buf_printf(write_data->buf,
1680
1745
  "\t%s = %s%s%s\n", write_data->name, q, write_data->value, q);
1681
1746
 
1682
1747
  /* If we are updating a single name/value, we're done. Setting `value`
@@ -1711,6 +1776,14 @@ static int write_on_section(
1711
1776
 
1712
1777
  write_data->in_section = strcmp(current_section, write_data->section) == 0;
1713
1778
 
1779
+ /*
1780
+ * If there were comments just before this section, dump them as well.
1781
+ */
1782
+ if (!result) {
1783
+ result = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size);
1784
+ git_buf_clear(&write_data->buffered_comment);
1785
+ }
1786
+
1714
1787
  if (!result)
1715
1788
  result = write_line(write_data, line, line_len);
1716
1789
 
@@ -1728,10 +1801,19 @@ static int write_on_variable(
1728
1801
  {
1729
1802
  struct write_data *write_data = (struct write_data *)data;
1730
1803
  bool has_matched = false;
1804
+ int error;
1731
1805
 
1732
1806
  GIT_UNUSED(reader);
1733
1807
  GIT_UNUSED(current_section);
1734
1808
 
1809
+ /*
1810
+ * If there were comments just before this variable, let's dump them as well.
1811
+ */
1812
+ if ((error = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size)) < 0)
1813
+ return error;
1814
+
1815
+ git_buf_clear(&write_data->buffered_comment);
1816
+
1735
1817
  /* See if we are to update this name/value pair; first examine name */
1736
1818
  if (write_data->in_section &&
1737
1819
  strcasecmp(write_data->name, var_name) == 0)
@@ -1766,7 +1848,7 @@ static int write_on_comment(struct reader **reader, const char *line, size_t lin
1766
1848
  GIT_UNUSED(reader);
1767
1849
 
1768
1850
  write_data = (struct write_data *)data;
1769
- return write_line(write_data, line, line_len);
1851
+ return write_line_to(&write_data->buffered_comment, line, line_len);
1770
1852
  }
1771
1853
 
1772
1854
  static int write_on_eof(struct reader **reader, void *data)
@@ -1776,13 +1858,19 @@ static int write_on_eof(struct reader **reader, void *data)
1776
1858
 
1777
1859
  GIT_UNUSED(reader);
1778
1860
 
1861
+ /*
1862
+ * If we've buffered comments when reaching EOF, make sure to dump them.
1863
+ */
1864
+ if ((result = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size)) < 0)
1865
+ return result;
1866
+
1779
1867
  /* If we are at the EOF and have not written our value (again, for a
1780
1868
  * simple name/value set, not a multivar) then we have never seen the
1781
1869
  * section in question and should create a new section and write the
1782
1870
  * value.
1783
1871
  */
1784
1872
  if ((!write_data->preg || !write_data->preg_replaced) && write_data->value) {
1785
- if ((result = write_section(write_data->file, write_data->section)) == 0)
1873
+ if ((result = write_section(write_data->buf, write_data->section)) == 0)
1786
1874
  result = write_value(write_data);
1787
1875
  }
1788
1876
 
@@ -1797,18 +1885,23 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
1797
1885
  int result;
1798
1886
  char *section, *name, *ldot;
1799
1887
  git_filebuf file = GIT_FILEBUF_INIT;
1888
+ git_buf buf = GIT_BUF_INIT;
1800
1889
  struct reader *reader = git_array_get(cfg->readers, 0);
1801
1890
  struct write_data write_data;
1802
1891
 
1803
- /* Lock the file */
1804
- if ((result = git_filebuf_open(
1805
- &file, cfg->file_path, 0, GIT_CONFIG_FILE_MODE)) < 0) {
1892
+ if (cfg->locked) {
1893
+ result = git_buf_puts(&reader->buffer, git_buf_cstr(&cfg->locked_content));
1894
+ } else {
1895
+ /* Lock the file */
1896
+ if ((result = git_filebuf_open(
1897
+ &file, cfg->file_path, 0, GIT_CONFIG_FILE_MODE)) < 0) {
1806
1898
  git_buf_free(&reader->buffer);
1807
1899
  return result;
1808
- }
1900
+ }
1809
1901
 
1810
- /* We need to read in our own config file */
1811
- result = git_futils_readbuffer(&reader->buffer, cfg->file_path);
1902
+ /* We need to read in our own config file */
1903
+ result = git_futils_readbuffer(&reader->buffer, cfg->file_path);
1904
+ }
1812
1905
 
1813
1906
  /* Initialise the reading position */
1814
1907
  if (result == GIT_ENOTFOUND) {
@@ -1827,7 +1920,8 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
1827
1920
  name = ldot + 1;
1828
1921
  section = git__strndup(key, ldot - key);
1829
1922
 
1830
- write_data.file = &file;
1923
+ write_data.buf = &buf;
1924
+ git_buf_init(&write_data.buffered_comment, 0);
1831
1925
  write_data.section = section;
1832
1926
  write_data.in_section = 0;
1833
1927
  write_data.preg_replaced = 0;
@@ -1837,19 +1931,29 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
1837
1931
 
1838
1932
  result = config_parse(reader, write_on_section, write_on_variable, write_on_comment, write_on_eof, &write_data);
1839
1933
  git__free(section);
1934
+ git_buf_free(&write_data.buffered_comment);
1840
1935
 
1841
1936
  if (result < 0) {
1842
1937
  git_filebuf_cleanup(&file);
1843
1938
  goto done;
1844
1939
  }
1845
1940
 
1846
- /* refresh stats - if this errors, then commit will error too */
1847
- (void)git_filebuf_stats(&reader->file_mtime, &reader->file_size, &file);
1941
+ if (cfg->locked) {
1942
+ size_t len = buf.asize;
1943
+ /* Update our copy with the modified contents */
1944
+ git_buf_free(&cfg->locked_content);
1945
+ git_buf_attach(&cfg->locked_content, git_buf_detach(&buf), len);
1946
+ } else {
1947
+ git_filebuf_write(&file, git_buf_cstr(&buf), git_buf_len(&buf));
1848
1948
 
1849
- result = git_filebuf_commit(&file);
1850
- git_buf_free(&reader->buffer);
1949
+ /* refresh stats - if this errors, then commit will error too */
1950
+ (void)git_filebuf_stats(&reader->file_mtime, &reader->file_size, &file);
1951
+
1952
+ result = git_filebuf_commit(&file);
1953
+ }
1851
1954
 
1852
1955
  done:
1956
+ git_buf_free(&buf);
1853
1957
  git_buf_free(&reader->buffer);
1854
1958
  return result;
1855
1959
  }
@@ -55,6 +55,16 @@ GIT_INLINE(int) git_config_file_foreach_match(
55
55
  return git_config_backend_foreach_match(cfg, regexp, fn, data);
56
56
  }
57
57
 
58
+ GIT_INLINE(int) git_config_file_lock(git_config_backend *cfg)
59
+ {
60
+ return cfg->lock(cfg);
61
+ }
62
+
63
+ GIT_INLINE(int) git_config_file_unlock(git_config_backend *cfg, int success)
64
+ {
65
+ return cfg->unlock(cfg, success);
66
+ }
67
+
58
68
  extern int git_config_file_normalize_section(char *start, char *end);
59
69
 
60
70
  #endif
@@ -67,9 +67,9 @@ static int curls_certificate(git_cert **out, git_stream *stream)
67
67
 
68
68
  /* No information is available, can happen with SecureTransport */
69
69
  if (certinfo->num_of_certs == 0) {
70
- s->cert_info.cert_type = GIT_CERT_NONE;
71
- s->cert_info.data = NULL;
72
- s->cert_info.len = 0;
70
+ s->cert_info.parent.cert_type = GIT_CERT_NONE;
71
+ s->cert_info.data = NULL;
72
+ s->cert_info.len = 0;
73
73
  return 0;
74
74
  }
75
75
 
@@ -85,11 +85,11 @@ static int curls_certificate(git_cert **out, git_stream *stream)
85
85
  s->cert_info_strings.strings = (char **) strings.contents;
86
86
  s->cert_info_strings.count = strings.length;
87
87
 
88
- s->cert_info.cert_type = GIT_CERT_STRARRAY;
89
- s->cert_info.data = &s->cert_info_strings;
90
- s->cert_info.len = strings.length;
88
+ s->cert_info.parent.cert_type = GIT_CERT_STRARRAY;
89
+ s->cert_info.data = &s->cert_info_strings;
90
+ s->cert_info.len = strings.length;
91
91
 
92
- *out = (git_cert *) &s->cert_info;
92
+ *out = &s->cert_info.parent;
93
93
 
94
94
  return 0;
95
95
  }
@@ -74,6 +74,32 @@ static int diff_insert_delta(
74
74
  return error;
75
75
  }
76
76
 
77
+ static bool diff_pathspec_match(
78
+ const char **matched_pathspec,
79
+ git_diff *diff,
80
+ const git_index_entry *entry)
81
+ {
82
+ bool disable_pathspec_match =
83
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH);
84
+
85
+ /* If we're disabling fnmatch, then the iterator has already applied
86
+ * the filters to the files for us and we don't have to do anything.
87
+ * However, this only applies to *files* - the iterator will include
88
+ * directories that we need to recurse into when not autoexpanding,
89
+ * so we still need to apply the pathspec match to directories.
90
+ */
91
+ if ((S_ISLNK(entry->mode) || S_ISREG(entry->mode)) &&
92
+ disable_pathspec_match) {
93
+ *matched_pathspec = entry->path;
94
+ return true;
95
+ }
96
+
97
+ return git_pathspec__match(
98
+ &diff->pathspec, entry->path, disable_pathspec_match,
99
+ DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE),
100
+ matched_pathspec, NULL);
101
+ }
102
+
77
103
  static int diff_delta__from_one(
78
104
  git_diff *diff,
79
105
  git_delta_t status,
@@ -110,11 +136,7 @@ static int diff_delta__from_one(
110
136
  DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNREADABLE))
111
137
  return 0;
112
138
 
113
- if (!git_pathspec__match(
114
- &diff->pathspec, entry->path,
115
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
116
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE),
117
- &matched_pathspec, NULL))
139
+ if (!diff_pathspec_match(&matched_pathspec, diff, entry))
118
140
  return 0;
119
141
 
120
142
  delta = diff_delta__alloc(diff, status, entry->path);
@@ -755,11 +777,7 @@ static int maybe_modified(
755
777
  const char *matched_pathspec;
756
778
  int error = 0;
757
779
 
758
- if (!git_pathspec__match(
759
- &diff->pathspec, oitem->path,
760
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH),
761
- DIFF_FLAG_IS_SET(diff, GIT_DIFF_IGNORE_CASE),
762
- &matched_pathspec, NULL))
780
+ if (!diff_pathspec_match(&matched_pathspec, diff, oitem))
763
781
  return 0;
764
782
 
765
783
  memset(&noid, 0, sizeof(noid));
@@ -1053,6 +1071,12 @@ static int handle_unmatched_new_item(
1053
1071
  &info->nitem, &untracked_state, info->new_iter)) < 0)
1054
1072
  return error;
1055
1073
 
1074
+ /* if we found nothing that matched our pathlist filter, exclude */
1075
+ if (untracked_state == GIT_ITERATOR_STATUS_FILTERED) {
1076
+ git_vector_pop(&diff->deltas);
1077
+ git__free(last);
1078
+ }
1079
+
1056
1080
  /* if we found nothing or just ignored items, update the record */
1057
1081
  if (untracked_state == GIT_ITERATOR_STATUS_IGNORED ||
1058
1082
  untracked_state == GIT_ITERATOR_STATUS_EMPTY) {
@@ -1264,11 +1288,26 @@ cleanup:
1264
1288
  return error;
1265
1289
  }
1266
1290
 
1267
- #define DIFF_FROM_ITERATORS(MAKE_FIRST, MAKE_SECOND) do { \
1291
+ #define DIFF_FROM_ITERATORS(MAKE_FIRST, FLAGS_FIRST, MAKE_SECOND, FLAGS_SECOND) do { \
1268
1292
  git_iterator *a = NULL, *b = NULL; \
1269
- char *pfx = opts ? git_pathspec_prefix(&opts->pathspec) : NULL; \
1293
+ char *pfx = (opts && !(opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) ? \
1294
+ git_pathspec_prefix(&opts->pathspec) : NULL; \
1295
+ git_iterator_options a_opts = GIT_ITERATOR_OPTIONS_INIT, \
1296
+ b_opts = GIT_ITERATOR_OPTIONS_INIT; \
1297
+ a_opts.flags = FLAGS_FIRST; \
1298
+ a_opts.start = pfx; \
1299
+ a_opts.end = pfx; \
1300
+ b_opts.flags = FLAGS_SECOND; \
1301
+ b_opts.start = pfx; \
1302
+ b_opts.end = pfx; \
1270
1303
  GITERR_CHECK_VERSION(opts, GIT_DIFF_OPTIONS_VERSION, "git_diff_options"); \
1271
- if (!(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
1304
+ if (opts && (opts->flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH)) { \
1305
+ a_opts.pathlist.strings = opts->pathspec.strings; \
1306
+ a_opts.pathlist.count = opts->pathspec.count; \
1307
+ b_opts.pathlist.strings = opts->pathspec.strings; \
1308
+ b_opts.pathlist.count = opts->pathspec.count; \
1309
+ } \
1310
+ if (!error && !(error = MAKE_FIRST) && !(error = MAKE_SECOND)) \
1272
1311
  error = git_diff__from_iterators(diff, repo, a, b, opts); \
1273
1312
  git__free(pfx); git_iterator_free(a); git_iterator_free(b); \
1274
1313
  } while (0)
@@ -1280,8 +1319,8 @@ int git_diff_tree_to_tree(
1280
1319
  git_tree *new_tree,
1281
1320
  const git_diff_options *opts)
1282
1321
  {
1283
- int error = 0;
1284
1322
  git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE;
1323
+ int error = 0;
1285
1324
 
1286
1325
  assert(diff && repo);
1287
1326
 
@@ -1293,8 +1332,8 @@ int git_diff_tree_to_tree(
1293
1332
  iflag = GIT_ITERATOR_IGNORE_CASE;
1294
1333
 
1295
1334
  DIFF_FROM_ITERATORS(
1296
- git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx),
1297
- git_iterator_for_tree(&b, new_tree, iflag, pfx, pfx)
1335
+ git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
1336
+ git_iterator_for_tree(&b, new_tree, &b_opts), iflag
1298
1337
  );
1299
1338
 
1300
1339
  return error;
@@ -1318,10 +1357,10 @@ int git_diff_tree_to_index(
1318
1357
  git_index *index,
1319
1358
  const git_diff_options *opts)
1320
1359
  {
1321
- int error = 0;
1322
- bool index_ignore_case = false;
1323
1360
  git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE |
1324
1361
  GIT_ITERATOR_INCLUDE_CONFLICTS;
1362
+ bool index_ignore_case = false;
1363
+ int error = 0;
1325
1364
 
1326
1365
  assert(diff && repo);
1327
1366
 
@@ -1331,8 +1370,8 @@ int git_diff_tree_to_index(
1331
1370
  index_ignore_case = index->ignore_case;
1332
1371
 
1333
1372
  DIFF_FROM_ITERATORS(
1334
- git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx),
1335
- git_iterator_for_index(&b, index, iflag, pfx, pfx)
1373
+ git_iterator_for_tree(&a, old_tree, &a_opts), iflag,
1374
+ git_iterator_for_index(&b, index, &b_opts), iflag
1336
1375
  );
1337
1376
 
1338
1377
  /* if index is in case-insensitive order, re-sort deltas to match */
@@ -1356,10 +1395,11 @@ int git_diff_index_to_workdir(
1356
1395
  return error;
1357
1396
 
1358
1397
  DIFF_FROM_ITERATORS(
1359
- git_iterator_for_index(
1360
- &a, index, GIT_ITERATOR_INCLUDE_CONFLICTS, pfx, pfx),
1361
- git_iterator_for_workdir(
1362
- &b, repo, index, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
1398
+ git_iterator_for_index(&a, index, &a_opts),
1399
+ GIT_ITERATOR_INCLUDE_CONFLICTS,
1400
+
1401
+ git_iterator_for_workdir(&b, repo, index, NULL, &b_opts),
1402
+ GIT_ITERATOR_DONT_AUTOEXPAND
1363
1403
  );
1364
1404
 
1365
1405
  if (!error && DIFF_FLAG_IS_SET(*diff, GIT_DIFF_UPDATE_INDEX) && (*diff)->index_updated)
@@ -1383,9 +1423,8 @@ int git_diff_tree_to_workdir(
1383
1423
  return error;
1384
1424
 
1385
1425
  DIFF_FROM_ITERATORS(
1386
- git_iterator_for_tree(&a, old_tree, 0, pfx, pfx),
1387
- git_iterator_for_workdir(
1388
- &b, repo, index, old_tree, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
1426
+ git_iterator_for_tree(&a, old_tree, &a_opts), 0,
1427
+ git_iterator_for_workdir(&b, repo, index, old_tree, &b_opts), GIT_ITERATOR_DONT_AUTOEXPAND
1389
1428
  );
1390
1429
 
1391
1430
  return error;
@@ -1421,6 +1460,29 @@ int git_diff_tree_to_workdir_with_index(
1421
1460
  return error;
1422
1461
  }
1423
1462
 
1463
+ int git_diff_index_to_index(
1464
+ git_diff **diff,
1465
+ git_repository *repo,
1466
+ git_index *old_index,
1467
+ git_index *new_index,
1468
+ const git_diff_options *opts)
1469
+ {
1470
+ int error = 0;
1471
+
1472
+ assert(diff && old_index && new_index);
1473
+
1474
+ DIFF_FROM_ITERATORS(
1475
+ git_iterator_for_index(&a, old_index, &a_opts), GIT_ITERATOR_DONT_IGNORE_CASE,
1476
+ git_iterator_for_index(&b, new_index, &b_opts), GIT_ITERATOR_DONT_IGNORE_CASE
1477
+ );
1478
+
1479
+ /* if index is in case-insensitive order, re-sort deltas to match */
1480
+ if (!error && (old_index->ignore_case || new_index->ignore_case))
1481
+ diff_set_ignore_case(*diff, true);
1482
+
1483
+ return error;
1484
+ }
1485
+
1424
1486
  size_t git_diff_num_deltas(const git_diff *diff)
1425
1487
  {
1426
1488
  assert(diff);