]> git.proxmox.com Git - libgit2.git/blame - src/status.c
Add GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED
[libgit2.git] / src / status.c
CommitLineData
205166d2 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
205166d2 3 *
bb742ede
VM
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
205166d2
JP
6 */
7
8#include "common.h"
9#include "git2.h"
10#include "fileops.h"
11#include "hash.h"
3af6b34a
JP
12#include "vector.h"
13#include "tree.h"
1ee2ef87 14#include "status.h"
3af6b34a 15#include "git2/status.h"
56453d34 16#include "repository.h"
df743c7d 17#include "ignore.h"
114f5a6c 18#include "index.h"
205166d2 19
a48ea31d
RB
20#include "git2/diff.h"
21#include "diff.h"
22
a1683f28 23static unsigned int index_delta2status(const git_diff_delta *head2idx)
a48ea31d 24{
a1683f28 25 git_status_t st = GIT_STATUS_CURRENT;
a48ea31d 26
a1683f28 27 switch (head2idx->status) {
a48ea31d
RB
28 case GIT_DELTA_ADDED:
29 case GIT_DELTA_COPIED:
a48ea31d
RB
30 st = GIT_STATUS_INDEX_NEW;
31 break;
32 case GIT_DELTA_DELETED:
33 st = GIT_STATUS_INDEX_DELETED;
34 break;
35 case GIT_DELTA_MODIFIED:
36 st = GIT_STATUS_INDEX_MODIFIED;
37 break;
bc16fd3e
RB
38 case GIT_DELTA_RENAMED:
39 st = GIT_STATUS_INDEX_RENAMED;
a1683f28 40
9950bb4e 41 if (!git_oid_equal(&head2idx->old_file.id, &head2idx->new_file.id))
a1683f28 42 st |= GIT_STATUS_INDEX_MODIFIED;
bc16fd3e
RB
43 break;
44 case GIT_DELTA_TYPECHANGE:
45 st = GIT_STATUS_INDEX_TYPECHANGE;
46 break;
a48ea31d
RB
47 default:
48 break;
49 }
50
51 return st;
52}
53
a1683f28 54static unsigned int workdir_delta2status(
3ff1d123 55 git_diff *diff, git_diff_delta *idx2wd)
a48ea31d 56{
a1683f28 57 git_status_t st = GIT_STATUS_CURRENT;
a48ea31d 58
a1683f28 59 switch (idx2wd->status) {
a48ea31d 60 case GIT_DELTA_ADDED:
bc16fd3e 61 case GIT_DELTA_COPIED:
a48ea31d
RB
62 case GIT_DELTA_UNTRACKED:
63 st = GIT_STATUS_WT_NEW;
64 break;
61bef72d
AR
65 case GIT_DELTA_UNREADABLE:
66 st = GIT_STATUS_WT_UNREADABLE;
67 break;
a48ea31d
RB
68 case GIT_DELTA_DELETED:
69 st = GIT_STATUS_WT_DELETED;
70 break;
71 case GIT_DELTA_MODIFIED:
72 st = GIT_STATUS_WT_MODIFIED;
73 break;
74 case GIT_DELTA_IGNORED:
75 st = GIT_STATUS_IGNORED;
76 break;
dfe8c8df
ET
77 case GIT_DELTA_RENAMED:
78 st = GIT_STATUS_WT_RENAMED;
a1683f28 79
9950bb4e 80 if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id)) {
a1683f28
RB
81 /* if OIDs don't match, we might need to calculate them now to
82 * discern between RENAMED vs RENAMED+MODIFED
83 */
9950bb4e 84 if (git_oid_iszero(&idx2wd->old_file.id) &&
a1683f28
RB
85 diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
86 !git_diff__oid_for_file(
240f4af3
RB
87 &idx2wd->old_file.id, diff, idx2wd->old_file.path,
88 idx2wd->old_file.mode, idx2wd->old_file.size))
9950bb4e 89 idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
a1683f28 90
9950bb4e 91 if (git_oid_iszero(&idx2wd->new_file.id) &&
a1683f28
RB
92 diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
93 !git_diff__oid_for_file(
240f4af3
RB
94 &idx2wd->new_file.id, diff, idx2wd->new_file.path,
95 idx2wd->new_file.mode, idx2wd->new_file.size))
9950bb4e 96 idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
a1683f28 97
9950bb4e 98 if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id))
a1683f28
RB
99 st |= GIT_STATUS_WT_MODIFIED;
100 }
dfe8c8df 101 break;
bc16fd3e
RB
102 case GIT_DELTA_TYPECHANGE:
103 st = GIT_STATUS_WT_TYPECHANGE;
104 break;
a48ea31d
RB
105 default:
106 break;
107 }
108
109 return st;
110}
111
1ee2ef87 112static bool status_is_included(
3a68d7f0 113 git_status_list *status,
1ee2ef87
ET
114 git_diff_delta *head2idx,
115 git_diff_delta *idx2wd)
55cbd05b 116{
3a68d7f0
RB
117 if (!(status->opts.flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES))
118 return 1;
119
37ee70fa 120 /* if excluding submodules and this is a submodule everywhere */
3a68d7f0
RB
121 if (head2idx) {
122 if (head2idx->status != GIT_DELTA_ADDED &&
123 head2idx->old_file.mode != GIT_FILEMODE_COMMIT)
124 return 1;
125 if (head2idx->status != GIT_DELTA_DELETED &&
126 head2idx->new_file.mode != GIT_FILEMODE_COMMIT)
127 return 1;
128 }
129 if (idx2wd) {
130 if (idx2wd->status != GIT_DELTA_ADDED &&
131 idx2wd->old_file.mode != GIT_FILEMODE_COMMIT)
132 return 1;
133 if (idx2wd->status != GIT_DELTA_DELETED &&
134 idx2wd->new_file.mode != GIT_FILEMODE_COMMIT)
135 return 1;
55cbd05b
RB
136 }
137
3a68d7f0
RB
138 /* only get here if every valid mode is GIT_FILEMODE_COMMIT */
139 return 0;
55cbd05b
RB
140}
141
1ee2ef87 142static git_status_t status_compute(
a1683f28 143 git_status_list *status,
1ee2ef87
ET
144 git_diff_delta *head2idx,
145 git_diff_delta *idx2wd)
146{
a1683f28 147 git_status_t st = GIT_STATUS_CURRENT;
1ee2ef87
ET
148
149 if (head2idx)
a1683f28 150 st |= index_delta2status(head2idx);
1ee2ef87
ET
151
152 if (idx2wd)
a1683f28 153 st |= workdir_delta2status(status->idx2wd, idx2wd);
1ee2ef87 154
a1683f28 155 return st;
1ee2ef87
ET
156}
157
158static int status_collect(
159 git_diff_delta *head2idx,
160 git_diff_delta *idx2wd,
793c4385 161 void *payload)
a48ea31d 162{
25e0b157 163 git_status_list *status = payload;
1ee2ef87 164 git_status_entry *status_entry;
351888cf 165
25e0b157 166 if (!status_is_included(status, head2idx, idx2wd))
1ee2ef87 167 return 0;
351888cf 168
1ee2ef87 169 status_entry = git__malloc(sizeof(git_status_entry));
25e0b157 170 GITERR_CHECK_ALLOC(status_entry);
1ee2ef87 171
25e0b157 172 status_entry->status = status_compute(status, head2idx, idx2wd);
1ee2ef87
ET
173 status_entry->head_to_index = head2idx;
174 status_entry->index_to_workdir = idx2wd;
175
25e0b157 176 return git_vector_insert(&status->paired, status_entry);
1ee2ef87
ET
177}
178
dfe8c8df
ET
179GIT_INLINE(int) status_entry_cmp_base(
180 const void *a,
181 const void *b,
182 int (*strcomp)(const char *a, const char *b))
183{
184 const git_status_entry *entry_a = a;
185 const git_status_entry *entry_b = b;
186 const git_diff_delta *delta_a, *delta_b;
187
188 delta_a = entry_a->index_to_workdir ? entry_a->index_to_workdir :
189 entry_a->head_to_index;
190 delta_b = entry_b->index_to_workdir ? entry_b->index_to_workdir :
191 entry_b->head_to_index;
192
193 if (!delta_a && delta_b)
194 return -1;
195 if (delta_a && !delta_b)
196 return 1;
197 if (!delta_a && !delta_b)
198 return 0;
199
200 return strcomp(delta_a->new_file.path, delta_b->new_file.path);
201}
202
203static int status_entry_icmp(const void *a, const void *b)
204{
205 return status_entry_cmp_base(a, b, git__strcasecmp);
206}
207
208static int status_entry_cmp(const void *a, const void *b)
209{
210 return status_entry_cmp_base(a, b, git__strcmp);
211}
212
213static git_status_list *git_status_list_alloc(git_index *index)
1ee2ef87 214{
351888cf 215 git_status_list *status = NULL;
dfe8c8df
ET
216 int (*entrycmp)(const void *a, const void *b);
217
351888cf
RB
218 if (!(status = git__calloc(1, sizeof(git_status_list))))
219 return NULL;
220
dfe8c8df 221 entrycmp = index->ignore_case ? status_entry_icmp : status_entry_cmp;
1ee2ef87 222
351888cf
RB
223 if (git_vector_init(&status->paired, 0, entrycmp) < 0) {
224 git__free(status);
1ee2ef87 225 return NULL;
351888cf 226 }
1ee2ef87 227
351888cf 228 return status;
1ee2ef87
ET
229}
230
cd424ad5
RB
231static int status_validate_options(const git_status_options *opts)
232{
233 if (!opts)
234 return 0;
235
236 GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options");
237
238 if (opts->show > GIT_STATUS_SHOW_WORKDIR_ONLY) {
239 giterr_set(GITERR_INVALID, "Unknown status 'show' option");
240 return -1;
241 }
242
243 if ((opts->flags & GIT_STATUS_OPT_NO_REFRESH) != 0 &&
244 (opts->flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0) {
245 giterr_set(GITERR_INVALID, "Updating index from status "
246 "is not allowed when index refresh is disabled");
247 return -1;
248 }
249
250 return 0;
251}
252
1ee2ef87
ET
253int git_status_list_new(
254 git_status_list **out,
255 git_repository *repo,
256 const git_status_options *opts)
257{
dfe8c8df 258 git_index *index = NULL;
351888cf 259 git_status_list *status = NULL;
2f8d30be 260 git_diff_options diffopt = GIT_DIFF_OPTIONS_INIT;
e38f0d69 261 git_diff_find_options findopt = GIT_DIFF_FIND_OPTIONS_INIT;
a48ea31d
RB
262 git_tree *head = NULL;
263 git_status_show_t show =
264 opts ? opts->show : GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
1ee2ef87 265 int error = 0;
351888cf 266 unsigned int flags = opts ? opts->flags : GIT_STATUS_OPT_DEFAULTS;
a48ea31d 267
1ee2ef87
ET
268 *out = NULL;
269
cd424ad5
RB
270 if (status_validate_options(opts) < 0)
271 return -1;
79cfa20d 272
dfe8c8df
ET
273 if ((error = git_repository__ensure_not_bare(repo, "status")) < 0 ||
274 (error = git_repository_index(&index, repo)) < 0)
1ee2ef87 275 return error;
52032ae5 276
5cec896a 277 /* if there is no HEAD, that's okay - we'll make an empty iterator */
4bf630b6
RB
278 if ((error = git_repository_head_tree(&head, repo)) < 0) {
279 if (error != GIT_ENOTFOUND && error != GIT_EUNBORNBRANCH)
280 goto done;
281 giterr_clear();
351888cf 282 }
1ee2ef87 283
4bf630b6
RB
284 /* refresh index from disk unless prevented */
285 if ((flags & GIT_STATUS_OPT_NO_REFRESH) == 0 &&
8e5a8ef8 286 git_index_read(index, false) < 0)
4bf630b6
RB
287 giterr_clear();
288
351888cf
RB
289 status = git_status_list_alloc(index);
290 GITERR_CHECK_ALLOC(status);
a48ea31d 291
351888cf
RB
292 if (opts) {
293 memcpy(&status->opts, opts, sizeof(git_status_options));
294 memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec));
295 }
4b136a94 296
0d64bef9 297 diffopt.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
e38f0d69 298 findopt.flags = GIT_DIFF_FIND_FOR_UNTRACKED;
bc16fd3e 299
351888cf 300 if ((flags & GIT_STATUS_OPT_INCLUDE_UNTRACKED) != 0)
66142ae0 301 diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNTRACKED;
351888cf 302 if ((flags & GIT_STATUS_OPT_INCLUDE_IGNORED) != 0)
66142ae0 303 diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_IGNORED;
351888cf 304 if ((flags & GIT_STATUS_OPT_INCLUDE_UNMODIFIED) != 0)
66142ae0 305 diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED;
351888cf 306 if ((flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0)
4b136a94 307 diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS;
351888cf 308 if ((flags & GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH) != 0)
a1773f9d 309 diffopt.flags = diffopt.flags | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
351888cf 310 if ((flags & GIT_STATUS_OPT_RECURSE_IGNORED_DIRS) != 0)
0c289dd7 311 diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_IGNORED_DIRS;
351888cf 312 if ((flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0)
37ee70fa 313 diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES;
cd424ad5
RB
314 if ((flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0)
315 diffopt.flags = diffopt.flags | GIT_DIFF_UPDATE_INDEX;
66271925
AR
316 if ((flags & GIT_STATUS_OPT_INCLUDE_UNREADABLE) != 0)
317 diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNREADABLE;
a48ea31d 318
e38f0d69 319 if ((flags & GIT_STATUS_OPT_RENAMES_FROM_REWRITES) != 0)
17c7fbf6
ET
320 findopt.flags = findopt.flags |
321 GIT_DIFF_FIND_AND_BREAK_REWRITES |
322 GIT_DIFF_FIND_RENAMES_FROM_REWRITES |
323 GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY;
dfe8c8df 324
37ee70fa 325 if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) {
351888cf 326 if ((error = git_diff_tree_to_index(
4bf630b6 327 &status->head2idx, repo, head, index, &diffopt)) < 0)
351888cf 328 goto done;
1ee2ef87 329
351888cf 330 if ((flags & GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX) != 0 &&
e38f0d69 331 (error = git_diff_find_similar(status->head2idx, &findopt)) < 0)
351888cf 332 goto done;
37ee70fa 333 }
a48ea31d 334
37ee70fa 335 if (show != GIT_STATUS_SHOW_INDEX_ONLY) {
351888cf 336 if ((error = git_diff_index_to_workdir(
f47bc8ff
AR
337 &status->idx2wd, repo, index, &diffopt)) < 0) {
338 printf("git_diff_index_to_workdir failed with error %d\n", error);
351888cf 339 goto done;
f47bc8ff 340 }
a48ea31d 341
351888cf 342 if ((flags & GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR) != 0 &&
e38f0d69 343 (error = git_diff_find_similar(status->idx2wd, &findopt)) < 0)
351888cf 344 goto done;
1ee2ef87 345 }
55cbd05b 346
25e0b157
RB
347 error = git_diff__paired_foreach(
348 status->head2idx, status->idx2wd, status_collect, status);
349 if (error < 0)
350 goto done;
dfe8c8df 351
22b6b82f
RB
352 if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY)
353 git_vector_set_cmp(&status->paired, status_entry_cmp);
354 if (flags & GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)
355 git_vector_set_cmp(&status->paired, status_entry_icmp);
356
357 if ((flags &
358 (GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
359 GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR |
360 GIT_STATUS_OPT_SORT_CASE_SENSITIVELY |
361 GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)) != 0)
351888cf 362 git_vector_sort(&status->paired);
dfe8c8df 363
351888cf
RB
364done:
365 if (error < 0) {
366 git_status_list_free(status);
367 status = NULL;
368 }
a48ea31d 369
351888cf 370 *out = status;
1ee2ef87 371
a48ea31d 372 git_tree_free(head);
dfe8c8df 373 git_index_free(index);
5dca2010 374
1ee2ef87
ET
375 return error;
376}
377
351888cf 378size_t git_status_list_entrycount(git_status_list *status)
1ee2ef87 379{
351888cf 380 assert(status);
1ee2ef87 381
351888cf 382 return status->paired.length;
1ee2ef87
ET
383}
384
351888cf 385const git_status_entry *git_status_byindex(git_status_list *status, size_t i)
1ee2ef87 386{
351888cf 387 assert(status);
1ee2ef87 388
351888cf 389 return git_vector_get(&status->paired, i);
1ee2ef87
ET
390}
391
351888cf 392void git_status_list_free(git_status_list *status)
1ee2ef87 393{
351888cf 394 if (status == NULL)
1ee2ef87
ET
395 return;
396
3ff1d123
RB
397 git_diff_free(status->head2idx);
398 git_diff_free(status->idx2wd);
1ee2ef87 399
9cfce273 400 git_vector_free_deep(&status->paired);
1ee2ef87 401
351888cf
RB
402 git__memzero(status, sizeof(*status));
403 git__free(status);
1ee2ef87
ET
404}
405
406int git_status_foreach_ext(
407 git_repository *repo,
408 const git_status_options *opts,
409 git_status_cb cb,
410 void *payload)
411{
351888cf 412 git_status_list *status;
1ee2ef87
ET
413 const git_status_entry *status_entry;
414 size_t i;
415 int error = 0;
416
f47bc8ff
AR
417 if ((error = git_status_list_new(&status, repo, opts)) < 0) {
418 printf("git_status_list_new failed with error %d\n", error);
1ee2ef87 419 return error;
f47bc8ff 420 }
1ee2ef87 421
351888cf 422 git_vector_foreach(&status->paired, i, status_entry) {
1ee2ef87
ET
423 const char *path = status_entry->head_to_index ?
424 status_entry->head_to_index->old_file.path :
425 status_entry->index_to_workdir->old_file.path;
426
c7b3e1b3 427 if ((error = cb(path, status_entry->status, payload)) != 0) {
26c1cb91 428 giterr_set_after_callback(error);
1ee2ef87 429 break;
c7b3e1b3 430 }
1ee2ef87
ET
431 }
432
351888cf 433 git_status_list_free(status);
f335ecd6 434
1ee2ef87 435 return error;
a48ea31d
RB
436}
437
351888cf 438int git_status_foreach(git_repository *repo, git_status_cb cb, void *payload)
a48ea31d 439{
351888cf 440 return git_status_foreach_ext(repo, NULL, cb, payload);
a48ea31d
RB
441}
442
41a82592 443struct status_file_info {
5dca2010 444 char *expected;
41a82592
RB
445 unsigned int count;
446 unsigned int status;
25423d03 447 int fnm_flags;
5dca2010 448 int ambiguous;
3af6b34a
JP
449};
450
41a82592 451static int get_one_status(const char *path, unsigned int status, void *data)
df743c7d 452{
41a82592 453 struct status_file_info *sfi = data;
25423d03 454 int (*strcomp)(const char *a, const char *b);
df743c7d 455
41a82592
RB
456 sfi->count++;
457 sfi->status = status;
df743c7d 458
25423d03
RB
459 strcomp = (sfi->fnm_flags & FNM_CASEFOLD) ? git__strcasecmp : git__strcmp;
460
b90500f0 461 if (sfi->count > 1 ||
25423d03
RB
462 (strcomp(sfi->expected, path) != 0 &&
463 p_fnmatch(sfi->expected, path, sfi->fnm_flags) != 0))
5c8bb98c 464 {
5dca2010 465 sfi->ambiguous = true;
2f28219c 466 return GIT_EAMBIGUOUS; /* giterr_set will be done by caller */
0d0fa7c3 467 }
d8b903da 468
41a82592 469 return 0;
d8b903da 470}
471
0d0fa7c3 472int git_status_file(
41a82592
RB
473 unsigned int *status_flags,
474 git_repository *repo,
475 const char *path)
20361b2f 476{
41a82592 477 int error;
79cfa20d
BS
478 git_status_options opts = GIT_STATUS_OPTIONS_INIT;
479 struct status_file_info sfi = {0};
25423d03 480 git_index *index;
20361b2f 481
56453d34 482 assert(status_flags && repo && path);
483
25423d03
RB
484 if ((error = git_repository_index__weakptr(&index, repo)) < 0)
485 return error;
486
41a82592 487 if ((sfi.expected = git__strdup(path)) == NULL)
722c08af 488 return -1;
25423d03
RB
489 if (index->ignore_case)
490 sfi.fnm_flags = FNM_CASEFOLD;
20361b2f 491
dfe8c8df 492 opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
41a82592 493 opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
1f9e41ee 494 GIT_STATUS_OPT_RECURSE_IGNORED_DIRS |
41a82592
RB
495 GIT_STATUS_OPT_INCLUDE_UNTRACKED |
496 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
497 GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
498 opts.pathspec.count = 1;
499 opts.pathspec.strings = &sfi.expected;
df743c7d 500
41a82592 501 error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi);
df743c7d 502
5c8bb98c
RB
503 if (error < 0 && sfi.ambiguous) {
504 giterr_set(GITERR_INVALID,
505 "Ambiguous path '%s' given to git_status_file", sfi.expected);
5dca2010 506 error = GIT_EAMBIGUOUS;
5c8bb98c 507 }
5dca2010 508
41a82592 509 if (!error && !sfi.count) {
1f9e41ee
RB
510 giterr_set(GITERR_INVALID,
511 "Attempt to get status of nonexistent file '%s'", path);
512 error = GIT_ENOTFOUND;
df743c7d
RB
513 }
514
41a82592 515 *status_flags = sfi.status;
20361b2f 516
41a82592 517 git__free(sfi.expected);
0d0fa7c3 518
56453d34 519 return error;
20361b2f 520}
d8b903da 521
dc13f1f7 522int git_status_should_ignore(
41a82592
RB
523 int *ignored,
524 git_repository *repo,
525 const char *path)
cfbc880d 526{
2fb4e9b3 527 return git_ignore_path_is_ignored(ignored, repo, path);
cfbc880d
RB
528}
529
702efc89 530int git_status_init_options(git_status_options *opts, unsigned int version)
b9f81997 531{
702efc89
RB
532 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
533 opts, version, git_status_options, GIT_STATUS_OPTIONS_INIT);
9c8ed499
RB
534 return 0;
535}
536
537int git_status_list_get_perfdata(
538 git_diff_perfdata *out, const git_status_list *status)
539{
bc91347b
RB
540 assert(out);
541 GITERR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
9c8ed499
RB
542
543 out->stat_calls = 0;
544 out->oid_calculations = 0;
545
546 if (status->head2idx) {
547 out->stat_calls += status->head2idx->perf.stat_calls;
548 out->oid_calculations += status->head2idx->perf.oid_calculations;
549 }
550 if (status->idx2wd) {
551 out->stat_calls += status->idx2wd->perf.stat_calls;
552 out->oid_calculations += status->idx2wd->perf.oid_calculations;
553 }
554
555 return 0;
b9f81997 556}
9c8ed499 557