rugged 0.21.4 → 0.22.0b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (224) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -5
  3. data/ext/rugged/extconf.rb +9 -9
  4. data/ext/rugged/rugged.c +4 -2
  5. data/ext/rugged/rugged.h +3 -7
  6. data/ext/rugged/rugged_blob.c +57 -0
  7. data/ext/rugged/rugged_cred.c +23 -0
  8. data/ext/rugged/rugged_index.c +6 -2
  9. data/ext/rugged/rugged_remote.c +65 -52
  10. data/ext/rugged/rugged_remote_collection.c +59 -10
  11. data/ext/rugged/rugged_repo.c +345 -11
  12. data/ext/rugged/rugged_revwalk.c +10 -0
  13. data/ext/rugged/rugged_submodule.c +1042 -0
  14. data/ext/rugged/rugged_submodule_collection.c +236 -0
  15. data/ext/rugged/rugged_tag_collection.c +70 -2
  16. data/ext/rugged/rugged_tree.c +29 -10
  17. data/lib/rugged.rb +3 -0
  18. data/lib/rugged/attributes.rb +41 -0
  19. data/lib/rugged/blob.rb +28 -0
  20. data/lib/rugged/diff.rb +0 -1
  21. data/lib/rugged/diff/line.rb +1 -3
  22. data/lib/rugged/patch.rb +12 -2
  23. data/lib/rugged/repository.rb +7 -0
  24. data/lib/rugged/submodule_collection.rb +48 -0
  25. data/lib/rugged/version.rb +1 -1
  26. data/vendor/libgit2/CMakeLists.txt +27 -3
  27. data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
  28. data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
  29. data/vendor/libgit2/deps/zlib/adler32.c +39 -29
  30. data/vendor/libgit2/deps/zlib/crc32.c +33 -50
  31. data/vendor/libgit2/deps/zlib/crc32.h +1 -1
  32. data/vendor/libgit2/deps/zlib/deflate.c +198 -65
  33. data/vendor/libgit2/deps/zlib/deflate.h +8 -4
  34. data/vendor/libgit2/deps/zlib/infback.c +640 -0
  35. data/vendor/libgit2/deps/zlib/inffast.c +3 -3
  36. data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
  37. data/vendor/libgit2/deps/zlib/inflate.c +84 -52
  38. data/vendor/libgit2/deps/zlib/inftrees.c +15 -39
  39. data/vendor/libgit2/deps/zlib/trees.c +18 -36
  40. data/vendor/libgit2/deps/zlib/zconf.h +4 -0
  41. data/vendor/libgit2/deps/zlib/zlib.h +250 -95
  42. data/vendor/libgit2/deps/zlib/zutil.c +13 -10
  43. data/vendor/libgit2/deps/zlib/zutil.h +41 -62
  44. data/vendor/libgit2/include/git2.h +4 -0
  45. data/vendor/libgit2/include/git2/annotated_commit.h +99 -0
  46. data/vendor/libgit2/include/git2/attr.h +16 -13
  47. data/vendor/libgit2/include/git2/branch.h +11 -0
  48. data/vendor/libgit2/include/git2/buffer.h +16 -0
  49. data/vendor/libgit2/include/git2/checkout.h +12 -12
  50. data/vendor/libgit2/include/git2/cherrypick.h +15 -15
  51. data/vendor/libgit2/include/git2/clone.h +77 -69
  52. data/vendor/libgit2/include/git2/common.h +13 -1
  53. data/vendor/libgit2/include/git2/config.h +0 -14
  54. data/vendor/libgit2/include/git2/describe.h +162 -0
  55. data/vendor/libgit2/include/git2/diff.h +13 -8
  56. data/vendor/libgit2/include/git2/errors.h +5 -0
  57. data/vendor/libgit2/include/git2/global.h +38 -0
  58. data/vendor/libgit2/include/git2/merge.h +38 -64
  59. data/vendor/libgit2/include/git2/net.h +2 -2
  60. data/vendor/libgit2/include/git2/notes.h +17 -0
  61. data/vendor/libgit2/include/git2/oid.h +8 -4
  62. data/vendor/libgit2/include/git2/oidarray.h +40 -0
  63. data/vendor/libgit2/include/git2/rebase.h +261 -0
  64. data/vendor/libgit2/include/git2/reflog.h +1 -1
  65. data/vendor/libgit2/include/git2/remote.h +25 -47
  66. data/vendor/libgit2/include/git2/repository.h +4 -1
  67. data/vendor/libgit2/include/git2/reset.h +10 -1
  68. data/vendor/libgit2/include/git2/revert.h +1 -1
  69. data/vendor/libgit2/include/git2/revwalk.h +28 -23
  70. data/vendor/libgit2/include/git2/status.h +19 -15
  71. data/vendor/libgit2/include/git2/submodule.h +18 -0
  72. data/vendor/libgit2/include/git2/sys/config.h +0 -1
  73. data/vendor/libgit2/{src → include/git2/sys}/hashsig.h +11 -7
  74. data/vendor/libgit2/include/git2/sys/refdb_backend.h +13 -0
  75. data/vendor/libgit2/include/git2/sys/refs.h +0 -11
  76. data/vendor/libgit2/include/git2/sys/repository.h +13 -0
  77. data/vendor/libgit2/include/git2/sys/transport.h +352 -0
  78. data/vendor/libgit2/include/git2/threads.h +10 -20
  79. data/vendor/libgit2/include/git2/transaction.h +111 -0
  80. data/vendor/libgit2/include/git2/transport.h +79 -313
  81. data/vendor/libgit2/include/git2/tree.h +4 -2
  82. data/vendor/libgit2/include/git2/types.h +77 -8
  83. data/vendor/libgit2/include/git2/version.h +2 -2
  84. data/vendor/libgit2/src/annotated_commit.c +121 -0
  85. data/vendor/libgit2/src/annotated_commit.h +22 -0
  86. data/vendor/libgit2/src/attr.c +8 -4
  87. data/vendor/libgit2/src/attr_file.c +24 -2
  88. data/vendor/libgit2/src/blame.c +0 -1
  89. data/vendor/libgit2/src/branch.c +32 -3
  90. data/vendor/libgit2/src/buf_text.c +9 -5
  91. data/vendor/libgit2/src/buf_text.h +3 -2
  92. data/vendor/libgit2/src/buffer.c +67 -10
  93. data/vendor/libgit2/src/buffer.h +4 -2
  94. data/vendor/libgit2/src/cache.c +9 -9
  95. data/vendor/libgit2/src/cache.h +1 -1
  96. data/vendor/libgit2/src/cc-compat.h +2 -0
  97. data/vendor/libgit2/src/checkout.c +263 -82
  98. data/vendor/libgit2/src/checkout.h +1 -0
  99. data/vendor/libgit2/src/cherrypick.c +41 -44
  100. data/vendor/libgit2/src/clone.c +96 -58
  101. data/vendor/libgit2/src/commit.c +5 -31
  102. data/vendor/libgit2/src/commit_list.h +3 -1
  103. data/vendor/libgit2/src/config.c +0 -17
  104. data/vendor/libgit2/src/config_cache.c +0 -2
  105. data/vendor/libgit2/src/config_file.c +12 -15
  106. data/vendor/libgit2/src/crlf.c +2 -1
  107. data/vendor/libgit2/src/describe.c +886 -0
  108. data/vendor/libgit2/src/diff.c +29 -3
  109. data/vendor/libgit2/src/diff_file.c +1 -0
  110. data/vendor/libgit2/src/diff_patch.c +2 -3
  111. data/vendor/libgit2/src/diff_print.c +11 -9
  112. data/vendor/libgit2/src/diff_tform.c +4 -4
  113. data/vendor/libgit2/src/errors.c +9 -7
  114. data/vendor/libgit2/src/fetch.c +6 -6
  115. data/vendor/libgit2/src/fetchhead.h +2 -4
  116. data/vendor/libgit2/src/filebuf.c +0 -2
  117. data/vendor/libgit2/src/filebuf.h +2 -3
  118. data/vendor/libgit2/src/fileops.c +9 -7
  119. data/vendor/libgit2/src/global.c +44 -35
  120. data/vendor/libgit2/src/global.h +2 -0
  121. data/vendor/libgit2/src/graph.c +2 -2
  122. data/vendor/libgit2/src/hash.h +3 -1
  123. data/vendor/libgit2/src/hash/hash_common_crypto.h +44 -0
  124. data/vendor/libgit2/src/hash/hash_win32.c +1 -1
  125. data/vendor/libgit2/src/hashsig.c +1 -1
  126. data/vendor/libgit2/src/ignore.c +5 -88
  127. data/vendor/libgit2/src/index.c +70 -57
  128. data/vendor/libgit2/src/index.h +1 -0
  129. data/vendor/libgit2/src/indexer.c +16 -5
  130. data/vendor/libgit2/src/iterator.c +70 -1
  131. data/vendor/libgit2/src/iterator.h +5 -1
  132. data/vendor/libgit2/src/map.h +0 -1
  133. data/vendor/libgit2/src/merge.c +203 -327
  134. data/vendor/libgit2/src/merge.h +3 -13
  135. data/vendor/libgit2/src/mwindow.c +119 -8
  136. data/vendor/libgit2/src/mwindow.h +9 -1
  137. data/vendor/libgit2/src/netops.c +7 -8
  138. data/vendor/libgit2/src/netops.h +6 -16
  139. data/vendor/libgit2/src/notes.c +31 -4
  140. data/vendor/libgit2/src/notes.h +3 -0
  141. data/vendor/libgit2/src/odb.c +23 -1
  142. data/vendor/libgit2/src/odb_loose.c +1 -1
  143. data/vendor/libgit2/src/odb_pack.c +6 -3
  144. data/vendor/libgit2/src/oid.c +9 -1
  145. data/vendor/libgit2/src/oid.h +11 -0
  146. data/vendor/libgit2/src/oidarray.c +21 -0
  147. data/vendor/libgit2/src/oidarray.h +18 -0
  148. data/vendor/libgit2/src/oidmap.h +16 -0
  149. data/vendor/libgit2/src/pack.c +20 -7
  150. data/vendor/libgit2/src/pack.h +3 -0
  151. data/vendor/libgit2/src/path.c +120 -293
  152. data/vendor/libgit2/src/path.h +21 -44
  153. data/vendor/libgit2/src/pathspec.c +1 -1
  154. data/vendor/libgit2/src/pool.c +5 -11
  155. data/vendor/libgit2/src/pool.h +0 -2
  156. data/vendor/libgit2/src/posix.c +6 -6
  157. data/vendor/libgit2/src/posix.h +48 -28
  158. data/vendor/libgit2/src/push.c +19 -48
  159. data/vendor/libgit2/src/push.h +2 -4
  160. data/vendor/libgit2/src/rebase.c +1125 -0
  161. data/vendor/libgit2/src/refdb.c +19 -0
  162. data/vendor/libgit2/src/refdb.h +2 -1
  163. data/vendor/libgit2/src/refdb_fs.c +101 -29
  164. data/vendor/libgit2/src/reflog.c +1 -1
  165. data/vendor/libgit2/src/refs.c +38 -3
  166. data/vendor/libgit2/src/refs.h +13 -2
  167. data/vendor/libgit2/src/refspec.c +20 -2
  168. data/vendor/libgit2/src/remote.c +288 -154
  169. data/vendor/libgit2/src/remote.h +5 -1
  170. data/vendor/libgit2/src/repository.c +75 -36
  171. data/vendor/libgit2/src/repository.h +3 -25
  172. data/vendor/libgit2/src/reset.c +5 -1
  173. data/vendor/libgit2/src/revert.c +4 -6
  174. data/vendor/libgit2/src/revparse.c +15 -18
  175. data/vendor/libgit2/src/revwalk.c +96 -22
  176. data/vendor/libgit2/src/revwalk.h +5 -4
  177. data/vendor/libgit2/src/settings.c +22 -0
  178. data/vendor/libgit2/src/signature.c +37 -2
  179. data/vendor/libgit2/src/signature.h +3 -0
  180. data/vendor/libgit2/src/stash.c +17 -12
  181. data/vendor/libgit2/src/status.c +13 -3
  182. data/vendor/libgit2/src/strnlen.h +2 -1
  183. data/vendor/libgit2/src/submodule.c +75 -35
  184. data/vendor/libgit2/src/thread-utils.h +4 -9
  185. data/vendor/libgit2/src/trace.h +9 -1
  186. data/vendor/libgit2/src/transaction.c +352 -0
  187. data/vendor/libgit2/src/transport.c +91 -97
  188. data/vendor/libgit2/src/transports/auth.c +71 -0
  189. data/vendor/libgit2/src/transports/auth.h +63 -0
  190. data/vendor/libgit2/src/transports/auth_negotiate.c +275 -0
  191. data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
  192. data/vendor/libgit2/src/transports/cred.c +58 -0
  193. data/vendor/libgit2/src/transports/cred.h +14 -0
  194. data/vendor/libgit2/src/transports/cred_helpers.c +3 -0
  195. data/vendor/libgit2/src/transports/git.c +1 -0
  196. data/vendor/libgit2/src/transports/http.c +208 -82
  197. data/vendor/libgit2/src/transports/local.c +2 -2
  198. data/vendor/libgit2/src/transports/smart.c +2 -0
  199. data/vendor/libgit2/src/transports/smart.h +2 -0
  200. data/vendor/libgit2/src/transports/smart_protocol.c +10 -10
  201. data/vendor/libgit2/src/transports/ssh.c +243 -57
  202. data/vendor/libgit2/src/transports/winhttp.c +139 -35
  203. data/vendor/libgit2/src/tree-cache.c +118 -31
  204. data/vendor/libgit2/src/tree-cache.h +12 -7
  205. data/vendor/libgit2/src/tree.c +83 -64
  206. data/vendor/libgit2/src/tree.h +2 -3
  207. data/vendor/libgit2/src/unix/map.c +8 -2
  208. data/vendor/libgit2/src/unix/posix.h +23 -9
  209. data/vendor/libgit2/src/unix/realpath.c +8 -7
  210. data/vendor/libgit2/src/userdiff.h +3 -3
  211. data/vendor/libgit2/src/util.c +2 -92
  212. data/vendor/libgit2/src/util.h +3 -15
  213. data/vendor/libgit2/src/win32/findfile.c +0 -1
  214. data/vendor/libgit2/src/win32/map.c +3 -2
  215. data/vendor/libgit2/src/win32/mingw-compat.h +5 -12
  216. data/vendor/libgit2/src/win32/msvc-compat.h +3 -32
  217. data/vendor/libgit2/src/win32/posix.h +20 -32
  218. data/vendor/libgit2/src/win32/posix_w32.c +103 -31
  219. data/vendor/libgit2/src/win32/utf-conv.c +6 -36
  220. data/vendor/libgit2/src/win32/utf-conv.h +39 -0
  221. data/vendor/libgit2/src/win32/w32_util.h +0 -1
  222. metadata +32 -7
  223. data/vendor/libgit2/src/win32/path_w32.c +0 -305
  224. data/vendor/libgit2/src/win32/path_w32.h +0 -82
@@ -156,10 +156,12 @@ void git_buf_rtrim(git_buf *buf);
156
156
  int git_buf_cmp(const git_buf *a, const git_buf *b);
157
157
 
158
158
  /* Write data as base64 encoded in buffer */
159
- int git_buf_put_base64(git_buf *buf, const char *data, size_t len);
159
+ int git_buf_encode_base64(git_buf *buf, const char *data, size_t len);
160
+ /* Decode the given bas64 and write the result to the buffer */
161
+ int git_buf_decode_base64(git_buf *buf, const char *base64, size_t len);
160
162
 
161
163
  /* Write data as "base85" encoded in buffer */
162
- int git_buf_put_base85(git_buf *buf, const char *data, size_t len);
164
+ int git_buf_encode_base85(git_buf *buf, const char *data, size_t len);
163
165
 
164
166
  /*
165
167
  * Insert, remove or replace a portion of the buffer.
@@ -68,8 +68,8 @@ int git_cache_init(git_cache *cache)
68
68
  {
69
69
  memset(cache, 0, sizeof(*cache));
70
70
  cache->map = git_oidmap_alloc();
71
- if (git_mutex_init(&cache->lock)) {
72
- giterr_set(GITERR_OS, "Failed to initialize cache mutex");
71
+ if (git_rwlock_init(&cache->lock)) {
72
+ giterr_set(GITERR_OS, "Failed to initialize cache rwlock");
73
73
  return -1;
74
74
  }
75
75
  return 0;
@@ -94,19 +94,19 @@ static void clear_cache(git_cache *cache)
94
94
 
95
95
  void git_cache_clear(git_cache *cache)
96
96
  {
97
- if (git_mutex_lock(&cache->lock) < 0)
97
+ if (git_rwlock_wrlock(&cache->lock) < 0)
98
98
  return;
99
99
 
100
100
  clear_cache(cache);
101
101
 
102
- git_mutex_unlock(&cache->lock);
102
+ git_rwlock_wrunlock(&cache->lock);
103
103
  }
104
104
 
105
105
  void git_cache_free(git_cache *cache)
106
106
  {
107
107
  git_cache_clear(cache);
108
108
  git_oidmap_free(cache->map);
109
- git_mutex_free(&cache->lock);
109
+ git_rwlock_free(&cache->lock);
110
110
  git__memzero(cache, sizeof(*cache));
111
111
  }
112
112
 
@@ -152,7 +152,7 @@ static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags)
152
152
  khiter_t pos;
153
153
  git_cached_obj *entry = NULL;
154
154
 
155
- if (!git_cache__enabled || git_mutex_lock(&cache->lock) < 0)
155
+ if (!git_cache__enabled || git_rwlock_rdlock(&cache->lock) < 0)
156
156
  return NULL;
157
157
 
158
158
  pos = kh_get(oid, cache->map, oid);
@@ -166,7 +166,7 @@ static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags)
166
166
  }
167
167
  }
168
168
 
169
- git_mutex_unlock(&cache->lock);
169
+ git_rwlock_rdunlock(&cache->lock);
170
170
 
171
171
  return entry;
172
172
  }
@@ -185,7 +185,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
185
185
  if (!cache_should_store(entry->type, entry->size))
186
186
  return entry;
187
187
 
188
- if (git_mutex_lock(&cache->lock) < 0)
188
+ if (git_rwlock_wrlock(&cache->lock) < 0)
189
189
  return entry;
190
190
 
191
191
  /* soften the load on the cache */
@@ -227,7 +227,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
227
227
  }
228
228
  }
229
229
 
230
- git_mutex_unlock(&cache->lock);
230
+ git_rwlock_wrunlock(&cache->lock);
231
231
  return entry;
232
232
  }
233
233
 
@@ -30,7 +30,7 @@ typedef struct {
30
30
 
31
31
  typedef struct {
32
32
  git_oidmap *map;
33
- git_mutex lock;
33
+ git_rwlock lock;
34
34
  ssize_t used_memory;
35
35
  } git_cache;
36
36
 
@@ -49,9 +49,11 @@
49
49
  #if defined(_MSC_VER) || defined(__MINGW32__)
50
50
  # define PRIuZ "Iu"
51
51
  # define PRIxZ "Ix"
52
+ # define PRIdZ "Id"
52
53
  #else
53
54
  # define PRIuZ "zu"
54
55
  # define PRIxZ "zx"
56
+ # define PRIdZ "zd"
55
57
  #endif
56
58
 
57
59
  /* Micosoft Visual C/C++ */
@@ -37,15 +37,17 @@ enum {
37
37
  CHECKOUT_ACTION__UPDATE_BLOB = 2,
38
38
  CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
39
39
  CHECKOUT_ACTION__CONFLICT = 8,
40
- CHECKOUT_ACTION__UPDATE_CONFLICT = 16,
41
- CHECKOUT_ACTION__MAX = 16,
42
- CHECKOUT_ACTION__DEFER_REMOVE = 32,
40
+ CHECKOUT_ACTION__REMOVE_CONFLICT = 16,
41
+ CHECKOUT_ACTION__UPDATE_CONFLICT = 32,
42
+ CHECKOUT_ACTION__MAX = 32,
43
+ CHECKOUT_ACTION__DEFER_REMOVE = 64,
43
44
  CHECKOUT_ACTION__REMOVE_AND_UPDATE =
44
45
  (CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
45
46
  };
46
47
 
47
48
  typedef struct {
48
49
  git_repository *repo;
50
+ git_iterator *target;
49
51
  git_diff *diff;
50
52
  git_checkout_options opts;
51
53
  bool opts_free_baseline;
@@ -53,7 +55,10 @@ typedef struct {
53
55
  git_index *index;
54
56
  git_pool pool;
55
57
  git_vector removes;
56
- git_vector conflicts;
58
+ git_vector remove_conflicts;
59
+ git_vector update_conflicts;
60
+ git_vector *update_reuc;
61
+ git_vector *update_names;
57
62
  git_buf path;
58
63
  size_t workdir_len;
59
64
  git_buf tmp;
@@ -116,6 +121,7 @@ static int checkout_notify(
116
121
  case GIT_DELTA_ADDED:
117
122
  case GIT_DELTA_IGNORED:
118
123
  case GIT_DELTA_UNTRACKED:
124
+ case GIT_DELTA_UNREADABLE:
119
125
  target = &delta->new_file;
120
126
  break;
121
127
  case GIT_DELTA_DELETED:
@@ -138,6 +144,7 @@ static int checkout_notify(
138
144
  static bool checkout_is_workdir_modified(
139
145
  checkout_data *data,
140
146
  const git_diff_file *baseitem,
147
+ const git_diff_file *newitem,
141
148
  const git_index_entry *wditem)
142
149
  {
143
150
  git_oid oid;
@@ -169,13 +176,16 @@ static bool checkout_is_workdir_modified(
169
176
 
170
177
  /* Look at the cache to decide if the workdir is modified. If not,
171
178
  * we can simply compare the oid in the cache to the baseitem instead
172
- * of hashing the file.
179
+ * of hashing the file. If so, we allow the checkout to proceed if the
180
+ * oid is identical (ie, the staged item is what we're trying to check
181
+ * out.)
173
182
  */
174
183
  if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
175
184
  if (wditem->mtime.seconds == ie->mtime.seconds &&
176
185
  wditem->mtime.nanoseconds == ie->mtime.nanoseconds &&
177
186
  wditem->file_size == ie->file_size)
178
- return (git_oid__cmp(&baseitem->id, &ie->id) != 0);
187
+ return (git_oid__cmp(&baseitem->id, &ie->id) != 0 &&
188
+ git_oid_cmp(&newitem->id, &ie->id) != 0);
179
189
  }
180
190
 
181
191
  /* depending on where base is coming from, we may or may not know
@@ -401,7 +411,7 @@ static int checkout_action_with_wd(
401
411
 
402
412
  switch (delta->status) {
403
413
  case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */
404
- if (checkout_is_workdir_modified(data, &delta->old_file, wd)) {
414
+ if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) {
405
415
  GITERR_CHECK_ERROR(
406
416
  checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) );
407
417
  *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
@@ -414,13 +424,13 @@ static int checkout_action_with_wd(
414
424
  *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
415
425
  break;
416
426
  case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */
417
- if (checkout_is_workdir_modified(data, &delta->old_file, wd))
427
+ if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
418
428
  *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
419
429
  else
420
430
  *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
421
431
  break;
422
432
  case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */
423
- if (checkout_is_workdir_modified(data, &delta->old_file, wd))
433
+ if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
424
434
  *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
425
435
  else
426
436
  *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
@@ -443,7 +453,7 @@ static int checkout_action_with_wd(
443
453
  } else
444
454
  *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
445
455
  }
446
- else if (checkout_is_workdir_modified(data, &delta->old_file, wd))
456
+ else if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd))
447
457
  *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
448
458
  else
449
459
  *action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE);
@@ -785,38 +795,58 @@ done:
785
795
  return error;
786
796
  }
787
797
 
788
- static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
798
+ static int checkout_conflict_append_update(
799
+ const git_index_entry *ancestor,
800
+ const git_index_entry *ours,
801
+ const git_index_entry *theirs,
802
+ void *payload)
803
+ {
804
+ checkout_data *data = payload;
805
+ checkout_conflictdata *conflict;
806
+ int error;
807
+
808
+ conflict = git__calloc(1, sizeof(checkout_conflictdata));
809
+ GITERR_CHECK_ALLOC(conflict);
810
+
811
+ conflict->ancestor = ancestor;
812
+ conflict->ours = ours;
813
+ conflict->theirs = theirs;
814
+
815
+ if ((error = checkout_conflict_detect_submodule(conflict)) < 0 ||
816
+ (error = checkout_conflict_detect_binary(data->repo, conflict)) < 0)
817
+ {
818
+ git__free(conflict);
819
+ return error;
820
+ }
821
+
822
+ if (git_vector_insert(&data->update_conflicts, conflict))
823
+ return -1;
824
+
825
+ return 0;
826
+ }
827
+
828
+ static int checkout_conflicts_foreach(
829
+ checkout_data *data,
830
+ git_index *index,
831
+ git_iterator *workdir,
832
+ git_vector *pathspec,
833
+ int (*cb)(const git_index_entry *, const git_index_entry *, const git_index_entry *, void *),
834
+ void *payload)
789
835
  {
790
836
  git_index_conflict_iterator *iterator = NULL;
791
837
  const git_index_entry *ancestor, *ours, *theirs;
792
- checkout_conflictdata *conflict;
793
838
  int error = 0;
794
839
 
795
- if ((error = git_index_conflict_iterator_new(&iterator, data->index)) < 0)
840
+ if ((error = git_index_conflict_iterator_new(&iterator, index)) < 0)
796
841
  goto done;
797
842
 
798
- data->conflicts._cmp = checkout_conflictdata_cmp;
799
-
800
843
  /* Collect the conflicts */
801
844
  while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iterator)) == 0) {
802
845
  if (!conflict_pathspec_match(data, workdir, pathspec, ancestor, ours, theirs))
803
846
  continue;
804
847
 
805
- conflict = git__calloc(1, sizeof(checkout_conflictdata));
806
- GITERR_CHECK_ALLOC(conflict);
807
-
808
- conflict->ancestor = ancestor;
809
- conflict->ours = ours;
810
- conflict->theirs = theirs;
811
-
812
- if ((error = checkout_conflict_detect_submodule(conflict)) < 0 ||
813
- (error = checkout_conflict_detect_binary(data->repo, conflict)) < 0)
814
- {
815
- git__free(conflict);
848
+ if ((error = cb(ancestor, ours, theirs, payload)) < 0)
816
849
  goto done;
817
- }
818
-
819
- git_vector_insert(&data->conflicts, conflict);
820
850
  }
821
851
 
822
852
  if (error == GIT_ITEROVER)
@@ -828,6 +858,26 @@ done:
828
858
  return error;
829
859
  }
830
860
 
861
+ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
862
+ {
863
+ git_index *index;
864
+
865
+ /* Only write conficts from sources that have them: indexes. */
866
+ if ((index = git_iterator_get_index(data->target)) == NULL)
867
+ return 0;
868
+
869
+ data->update_conflicts._cmp = checkout_conflictdata_cmp;
870
+
871
+ if (checkout_conflicts_foreach(data, index, workdir, pathspec, checkout_conflict_append_update, data) < 0)
872
+ return -1;
873
+
874
+ /* Collect the REUC and NAME entries */
875
+ data->update_reuc = &index->reuc;
876
+ data->update_names = &index->names;
877
+
878
+ return 0;
879
+ }
880
+
831
881
  GIT_INLINE(int) checkout_conflicts_cmp_entry(
832
882
  const char *path,
833
883
  const git_index_entry *entry)
@@ -852,10 +902,10 @@ static checkout_conflictdata *checkout_conflicts_search_ancestor(
852
902
  {
853
903
  size_t pos;
854
904
 
855
- if (git_vector_bsearch2(&pos, &data->conflicts, checkout_conflicts_cmp_ancestor, path) < 0)
905
+ if (git_vector_bsearch2(&pos, &data->update_conflicts, checkout_conflicts_cmp_ancestor, path) < 0)
856
906
  return NULL;
857
907
 
858
- return git_vector_get(&data->conflicts, pos);
908
+ return git_vector_get(&data->update_conflicts, pos);
859
909
  }
860
910
 
861
911
  static checkout_conflictdata *checkout_conflicts_search_branch(
@@ -865,7 +915,7 @@ static checkout_conflictdata *checkout_conflicts_search_branch(
865
915
  checkout_conflictdata *conflict;
866
916
  size_t i;
867
917
 
868
- git_vector_foreach(&data->conflicts, i, conflict) {
918
+ git_vector_foreach(&data->update_conflicts, i, conflict) {
869
919
  int cmp = -1;
870
920
 
871
921
  if (conflict->ancestor)
@@ -957,16 +1007,20 @@ done:
957
1007
  static int checkout_conflicts_coalesce_renames(
958
1008
  checkout_data *data)
959
1009
  {
1010
+ git_index *index;
960
1011
  const git_index_name_entry *name_entry;
961
1012
  checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict;
962
1013
  size_t i, names;
963
1014
  int error = 0;
964
1015
 
1016
+ if ((index = git_iterator_get_index(data->target)) == NULL)
1017
+ return 0;
1018
+
965
1019
  /* Juggle entries based on renames */
966
- names = git_index_name_entrycount(data->index);
1020
+ names = git_index_name_entrycount(index);
967
1021
 
968
1022
  for (i = 0; i < names; i++) {
969
- name_entry = git_index_name_get_byindex(data->index, i);
1023
+ name_entry = git_index_name_get_byindex(index, i);
970
1024
 
971
1025
  if ((error = checkout_conflicts_load_byname_entry(
972
1026
  &ancestor_conflict, &our_conflict, &their_conflict,
@@ -1001,7 +1055,7 @@ static int checkout_conflicts_coalesce_renames(
1001
1055
  }
1002
1056
 
1003
1057
  git_vector_remove_matching(
1004
- &data->conflicts, checkout_conflictdata_empty, NULL);
1058
+ &data->update_conflicts, checkout_conflictdata_empty, NULL);
1005
1059
 
1006
1060
  done:
1007
1061
  return error;
@@ -1010,16 +1064,20 @@ done:
1010
1064
  static int checkout_conflicts_mark_directoryfile(
1011
1065
  checkout_data *data)
1012
1066
  {
1067
+ git_index *index;
1013
1068
  checkout_conflictdata *conflict;
1014
1069
  const git_index_entry *entry;
1015
1070
  size_t i, j, len;
1016
1071
  const char *path;
1017
1072
  int prefixed, error = 0;
1018
1073
 
1019
- len = git_index_entrycount(data->index);
1074
+ if ((index = git_iterator_get_index(data->target)) == NULL)
1075
+ return 0;
1076
+
1077
+ len = git_index_entrycount(index);
1020
1078
 
1021
1079
  /* Find d/f conflicts */
1022
- git_vector_foreach(&data->conflicts, i, conflict) {
1080
+ git_vector_foreach(&data->update_conflicts, i, conflict) {
1023
1081
  if ((conflict->ours && conflict->theirs) ||
1024
1082
  (!conflict->ours && !conflict->theirs))
1025
1083
  continue;
@@ -1027,7 +1085,7 @@ static int checkout_conflicts_mark_directoryfile(
1027
1085
  path = conflict->ours ?
1028
1086
  conflict->ours->path : conflict->theirs->path;
1029
1087
 
1030
- if ((error = git_index_find(&j, data->index, path)) < 0) {
1088
+ if ((error = git_index_find(&j, index, path)) < 0) {
1031
1089
  if (error == GIT_ENOTFOUND)
1032
1090
  giterr_set(GITERR_INDEX,
1033
1091
  "Index inconsistency, could not find entry for expected conflict '%s'", path);
@@ -1036,7 +1094,7 @@ static int checkout_conflicts_mark_directoryfile(
1036
1094
  }
1037
1095
 
1038
1096
  for (; j < len; j++) {
1039
- if ((entry = git_index_get_byindex(data->index, j)) == NULL) {
1097
+ if ((entry = git_index_get_byindex(index, j)) == NULL) {
1040
1098
  giterr_set(GITERR_INDEX,
1041
1099
  "Index inconsistency, truncated index while loading expected conflict '%s'", path);
1042
1100
  error = -1;
@@ -1059,7 +1117,7 @@ done:
1059
1117
  return error;
1060
1118
  }
1061
1119
 
1062
- static int checkout_get_conflicts(
1120
+ static int checkout_get_update_conflicts(
1063
1121
  checkout_data *data,
1064
1122
  git_iterator *workdir,
1065
1123
  git_vector *pathspec)
@@ -1078,28 +1136,40 @@ done:
1078
1136
  return error;
1079
1137
  }
1080
1138
 
1081
- static int checkout_verify_paths(
1082
- git_repository *repo,
1083
- int action,
1084
- git_diff_delta *delta)
1139
+ static int checkout_conflict_append_remove(
1140
+ const git_index_entry *ancestor,
1141
+ const git_index_entry *ours,
1142
+ const git_index_entry *theirs,
1143
+ void *payload)
1085
1144
  {
1086
- unsigned int flags = GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT;
1145
+ checkout_data *data = payload;
1146
+ const char *name;
1087
1147
 
1088
- if (action & CHECKOUT_ACTION__REMOVE) {
1089
- if (!git_path_isvalid(repo, delta->old_file.path, flags)) {
1090
- giterr_set(GITERR_CHECKOUT, "Cannot remove invalid path '%s'", delta->old_file.path);
1091
- return -1;
1092
- }
1093
- }
1148
+ assert(ancestor || ours || theirs);
1094
1149
 
1095
- if (action & ~CHECKOUT_ACTION__REMOVE) {
1096
- if (!git_path_isvalid(repo, delta->new_file.path, flags)) {
1097
- giterr_set(GITERR_CHECKOUT, "Cannot checkout to invalid path '%s'", delta->old_file.path);
1098
- return -1;
1099
- }
1100
- }
1150
+ if (ancestor)
1151
+ name = git__strdup(ancestor->path);
1152
+ else if (ours)
1153
+ name = git__strdup(ours->path);
1154
+ else if (theirs)
1155
+ name = git__strdup(theirs->path);
1156
+ else
1157
+ abort();
1101
1158
 
1102
- return 0;
1159
+ GITERR_CHECK_ALLOC(name);
1160
+
1161
+ return git_vector_insert(&data->remove_conflicts, (char *)name);
1162
+ }
1163
+
1164
+ static int checkout_get_remove_conflicts(
1165
+ checkout_data *data,
1166
+ git_iterator *workdir,
1167
+ git_vector *pathspec)
1168
+ {
1169
+ if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0)
1170
+ return 0;
1171
+
1172
+ return checkout_conflicts_foreach(data, data->index, workdir, pathspec, checkout_conflict_append_remove, data);
1103
1173
  }
1104
1174
 
1105
1175
  static int checkout_get_actions(
@@ -1135,9 +1205,7 @@ static int checkout_get_actions(
1135
1205
  }
1136
1206
 
1137
1207
  git_vector_foreach(deltas, i, delta) {
1138
- if ((error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec)) == 0)
1139
- error = checkout_verify_paths(data->repo, act, delta);
1140
-
1208
+ error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec);
1141
1209
  if (error != 0)
1142
1210
  goto fail;
1143
1211
 
@@ -1171,10 +1239,12 @@ static int checkout_get_actions(
1171
1239
  }
1172
1240
 
1173
1241
 
1174
- if ((error = checkout_get_conflicts(data, workdir, &pathspec)) < 0)
1242
+ if ((error = checkout_get_remove_conflicts(data, workdir, &pathspec)) < 0 ||
1243
+ (error = checkout_get_update_conflicts(data, workdir, &pathspec)) < 0)
1175
1244
  goto fail;
1176
1245
 
1177
- counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->conflicts);
1246
+ counts[CHECKOUT_ACTION__REMOVE_CONFLICT] = git_vector_length(&data->remove_conflicts);
1247
+ counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->update_conflicts);
1178
1248
 
1179
1249
  git_pathspec__vfree(&pathspec);
1180
1250
  git_pool_clear(&pathpool);
@@ -1846,13 +1916,45 @@ done:
1846
1916
  return error;
1847
1917
  }
1848
1918
 
1919
+ static int checkout_conflict_add(
1920
+ checkout_data *data,
1921
+ const git_index_entry *conflict)
1922
+ {
1923
+ int error = git_index_remove(data->index, conflict->path, 0);
1924
+
1925
+ if (error == GIT_ENOTFOUND)
1926
+ giterr_clear();
1927
+ else if (error < 0)
1928
+ return error;
1929
+
1930
+ return git_index_add(data->index, conflict);
1931
+ }
1932
+
1933
+ static int checkout_conflict_update_index(
1934
+ checkout_data *data,
1935
+ checkout_conflictdata *conflict)
1936
+ {
1937
+ int error = 0;
1938
+
1939
+ if (conflict->ancestor)
1940
+ error = checkout_conflict_add(data, conflict->ancestor);
1941
+
1942
+ if (!error && conflict->ours)
1943
+ error = checkout_conflict_add(data, conflict->ours);
1944
+
1945
+ if (!error && conflict->theirs)
1946
+ error = checkout_conflict_add(data, conflict->theirs);
1947
+
1948
+ return error;
1949
+ }
1950
+
1849
1951
  static int checkout_create_conflicts(checkout_data *data)
1850
1952
  {
1851
1953
  checkout_conflictdata *conflict;
1852
1954
  size_t i;
1853
1955
  int error = 0;
1854
1956
 
1855
- git_vector_foreach(&data->conflicts, i, conflict) {
1957
+ git_vector_foreach(&data->update_conflicts, i, conflict) {
1856
1958
 
1857
1959
  /* Both deleted: nothing to do */
1858
1960
  if (conflict->ours == NULL && conflict->theirs == NULL)
@@ -1908,6 +2010,12 @@ static int checkout_create_conflicts(checkout_data *data)
1908
2010
  else if (!error)
1909
2011
  error = checkout_write_merge(data, conflict);
1910
2012
 
2013
+ /* Update the index extensions (REUC and NAME) if we're checking
2014
+ * out a different index. (Otherwise just leave them there.)
2015
+ */
2016
+ if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
2017
+ error = checkout_conflict_update_index(data, conflict);
2018
+
1911
2019
  if (error)
1912
2020
  break;
1913
2021
 
@@ -1920,6 +2028,52 @@ static int checkout_create_conflicts(checkout_data *data)
1920
2028
  return error;
1921
2029
  }
1922
2030
 
2031
+ static int checkout_remove_conflicts(checkout_data *data)
2032
+ {
2033
+ const char *conflict;
2034
+ size_t i;
2035
+
2036
+ git_vector_foreach(&data->remove_conflicts, i, conflict) {
2037
+ if (git_index_conflict_remove(data->index, conflict) < 0)
2038
+ return -1;
2039
+
2040
+ data->completed_steps++;
2041
+ }
2042
+
2043
+ return 0;
2044
+ }
2045
+
2046
+ static int checkout_extensions_update_index(checkout_data *data)
2047
+ {
2048
+ const git_index_reuc_entry *reuc_entry;
2049
+ const git_index_name_entry *name_entry;
2050
+ size_t i;
2051
+ int error = 0;
2052
+
2053
+ if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
2054
+ return 0;
2055
+
2056
+ if (data->update_reuc) {
2057
+ git_vector_foreach(data->update_reuc, i, reuc_entry) {
2058
+ if ((error = git_index_reuc_add(data->index, reuc_entry->path,
2059
+ reuc_entry->mode[0], &reuc_entry->oid[0],
2060
+ reuc_entry->mode[1], &reuc_entry->oid[1],
2061
+ reuc_entry->mode[2], &reuc_entry->oid[2])) < 0)
2062
+ goto done;
2063
+ }
2064
+ }
2065
+
2066
+ if (data->update_names) {
2067
+ git_vector_foreach(data->update_names, i, name_entry) {
2068
+ if ((error = git_index_name_add(data->index, name_entry->ancestor,
2069
+ name_entry->ours, name_entry->theirs)) < 0)
2070
+ goto done;
2071
+ }
2072
+ }
2073
+
2074
+ done:
2075
+ return error;
2076
+ }
1923
2077
 
1924
2078
  static void checkout_data_clear(checkout_data *data)
1925
2079
  {
@@ -1931,7 +2085,8 @@ static void checkout_data_clear(checkout_data *data)
1931
2085
  git_vector_free(&data->removes);
1932
2086
  git_pool_clear(&data->pool);
1933
2087
 
1934
- git_vector_free_deep(&data->conflicts);
2088
+ git_vector_free_deep(&data->remove_conflicts);
2089
+ git_vector_free_deep(&data->update_conflicts);
1935
2090
 
1936
2091
  git__free(data->pfx);
1937
2092
  data->pfx = NULL;
@@ -1963,6 +2118,7 @@ static int checkout_data_init(
1963
2118
  return error;
1964
2119
 
1965
2120
  data->repo = repo;
2121
+ data->target = target;
1966
2122
 
1967
2123
  GITERR_CHECK_VERSION(
1968
2124
  proposed, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options");
@@ -1983,19 +2139,18 @@ static int checkout_data_init(
1983
2139
  if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
1984
2140
  git_config *cfg;
1985
2141
 
1986
- if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
1987
- (error = git_config_refresh(cfg)) < 0)
2142
+ if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1988
2143
  goto cleanup;
1989
2144
 
1990
- /* if we are checking out the index, don't reload,
1991
- * otherwise get index and force reload
2145
+ /* Get the repository index and reload it (unless we're checking
2146
+ * out the index; then it has the changes we're trying to check
2147
+ * out and those should not be overwritten.)
1992
2148
  */
1993
- if ((data->index = git_iterator_get_index(target)) != NULL) {
1994
- GIT_REFCOUNT_INC(data->index);
1995
- } else {
1996
- /* otherwise, grab and reload the index */
1997
- if ((error = git_repository_index(&data->index, data->repo)) < 0 ||
1998
- (error = git_index_read(data->index, true)) < 0)
2149
+ if ((error = git_repository_index(&data->index, data->repo)) < 0)
2150
+ goto cleanup;
2151
+
2152
+ if (data->index != git_iterator_get_index(target)) {
2153
+ if ((error = git_index_read(data->index, true)) < 0)
1999
2154
  goto cleanup;
2000
2155
 
2001
2156
  /* cannot checkout if unresolved conflicts exist */
@@ -2007,7 +2162,7 @@ static int checkout_data_init(
2007
2162
  goto cleanup;
2008
2163
  }
2009
2164
 
2010
- /* clean conflict data when doing a tree or commit checkout */
2165
+ /* clean conflict data in the current index */
2011
2166
  git_index_name_clear(data->index);
2012
2167
  git_index_reuc_clear(data->index);
2013
2168
  }
@@ -2073,7 +2228,8 @@ static int checkout_data_init(
2073
2228
  }
2074
2229
 
2075
2230
  if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
2076
- (error = git_vector_init(&data->conflicts, 0, NULL)) < 0 ||
2231
+ (error = git_vector_init(&data->remove_conflicts, 0, NULL)) < 0 ||
2232
+ (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 ||
2077
2233
  (error = git_pool_init(&data->pool, 1, 0)) < 0 ||
2078
2234
  (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
2079
2235
  (error = git_path_to_dir(&data->path)) < 0)
@@ -2090,6 +2246,7 @@ cleanup:
2090
2246
 
2091
2247
  int git_checkout_iterator(
2092
2248
  git_iterator *target,
2249
+ git_index *index,
2093
2250
  const git_checkout_options *opts)
2094
2251
  {
2095
2252
  int error = 0;
@@ -2107,6 +2264,7 @@ int git_checkout_iterator(
2107
2264
 
2108
2265
  diff_opts.flags =
2109
2266
  GIT_DIFF_INCLUDE_UNMODIFIED |
2267
+ GIT_DIFF_INCLUDE_UNREADABLE |
2110
2268
  GIT_DIFF_INCLUDE_UNTRACKED |
2111
2269
  GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */
2112
2270
  GIT_DIFF_INCLUDE_IGNORED |
@@ -2125,7 +2283,7 @@ int git_checkout_iterator(
2125
2283
 
2126
2284
  if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
2127
2285
  (error = git_iterator_for_workdir_ext(
2128
- &workdir, data.repo, data.opts.target_directory,
2286
+ &workdir, data.repo, data.opts.target_directory, index, NULL,
2129
2287
  iterflags | GIT_ITERATOR_DONT_AUTOEXPAND,
2130
2288
  data.pfx, data.pfx)) < 0 ||
2131
2289
  (error = git_iterator_for_tree(
@@ -2151,6 +2309,7 @@ int git_checkout_iterator(
2151
2309
  goto cleanup;
2152
2310
 
2153
2311
  data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
2312
+ counts[CHECKOUT_ACTION__REMOVE_CONFLICT] +
2154
2313
  counts[CHECKOUT_ACTION__UPDATE_BLOB] +
2155
2314
  counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] +
2156
2315
  counts[CHECKOUT_ACTION__UPDATE_CONFLICT];
@@ -2164,6 +2323,10 @@ int git_checkout_iterator(
2164
2323
  (error = checkout_remove_the_old(actions, &data)) < 0)
2165
2324
  goto cleanup;
2166
2325
 
2326
+ if (counts[CHECKOUT_ACTION__REMOVE_CONFLICT] > 0 &&
2327
+ (error = checkout_remove_conflicts(&data)) < 0)
2328
+ goto cleanup;
2329
+
2167
2330
  if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 &&
2168
2331
  (error = checkout_create_the_new(actions, &data)) < 0)
2169
2332
  goto cleanup;
@@ -2176,6 +2339,10 @@ int git_checkout_iterator(
2176
2339
  (error = checkout_create_conflicts(&data)) < 0)
2177
2340
  goto cleanup;
2178
2341
 
2342
+ if (data.index != git_iterator_get_index(target) &&
2343
+ (error = checkout_extensions_update_index(&data)) < 0)
2344
+ goto cleanup;
2345
+
2179
2346
  assert(data.completed_steps == data.total_steps);
2180
2347
 
2181
2348
  cleanup:
@@ -2198,7 +2365,7 @@ int git_checkout_index(
2198
2365
  git_index *index,
2199
2366
  const git_checkout_options *opts)
2200
2367
  {
2201
- int error;
2368
+ int error, owned = 0;
2202
2369
  git_iterator *index_i;
2203
2370
 
2204
2371
  if (!index && !repo) {
@@ -2206,10 +2373,16 @@ int git_checkout_index(
2206
2373
  "Must provide either repository or index to checkout");
2207
2374
  return -1;
2208
2375
  }
2209
- if (index && repo && git_index_owner(index) != repo) {
2376
+
2377
+ if (index && repo &&
2378
+ git_index_owner(index) &&
2379
+ git_index_owner(index) != repo) {
2210
2380
  giterr_set(GITERR_CHECKOUT,
2211
2381
  "Index to checkout does not match repository");
2212
2382
  return -1;
2383
+ } else if(index && repo && !git_index_owner(index)) {
2384
+ GIT_REFCOUNT_OWN(index, repo);
2385
+ owned = 1;
2213
2386
  }
2214
2387
 
2215
2388
  if (!repo)
@@ -2220,7 +2393,10 @@ int git_checkout_index(
2220
2393
  GIT_REFCOUNT_INC(index);
2221
2394
 
2222
2395
  if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL)))
2223
- error = git_checkout_iterator(index_i, opts);
2396
+ error = git_checkout_iterator(index_i, index, opts);
2397
+
2398
+ if (owned)
2399
+ GIT_REFCOUNT_OWN(index, NULL);
2224
2400
 
2225
2401
  git_iterator_free(index_i);
2226
2402
  git_index_free(index);
@@ -2234,6 +2410,7 @@ int git_checkout_tree(
2234
2410
  const git_checkout_options *opts)
2235
2411
  {
2236
2412
  int error;
2413
+ git_index *index;
2237
2414
  git_tree *tree = NULL;
2238
2415
  git_iterator *tree_i = NULL;
2239
2416
 
@@ -2268,10 +2445,14 @@ int git_checkout_tree(
2268
2445
  }
2269
2446
  }
2270
2447
 
2448
+ if ((error = git_repository_index(&index, repo)) < 0)
2449
+ return error;
2450
+
2271
2451
  if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL)))
2272
- error = git_checkout_iterator(tree_i, opts);
2452
+ error = git_checkout_iterator(tree_i, index, opts);
2273
2453
 
2274
2454
  git_iterator_free(tree_i);
2455
+ git_index_free(index);
2275
2456
  git_tree_free(tree);
2276
2457
 
2277
2458
  return error;