|
Packit Service |
20376f |
/*
|
|
Packit Service |
20376f |
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
Packit Service |
20376f |
*
|
|
Packit Service |
20376f |
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
Packit Service |
20376f |
* a Linking Exception. For full terms see the included COPYING file.
|
|
Packit Service |
20376f |
*/
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
#include "common.h"
|
|
Packit Service |
20376f |
#include "git2.h"
|
|
Packit Service |
20376f |
#include "fileops.h"
|
|
Packit Service |
20376f |
#include "hash.h"
|
|
Packit Service |
20376f |
#include "vector.h"
|
|
Packit Service |
20376f |
#include "tree.h"
|
|
Packit Service |
20376f |
#include "status.h"
|
|
Packit Service |
20376f |
#include "git2/status.h"
|
|
Packit Service |
20376f |
#include "repository.h"
|
|
Packit Service |
20376f |
#include "ignore.h"
|
|
Packit Service |
20376f |
#include "index.h"
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
#include "git2/diff.h"
|
|
Packit Service |
20376f |
#include "diff.h"
|
|
Packit Service |
20376f |
#include "diff_generate.h"
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static unsigned int index_delta2status(const git_diff_delta *head2idx)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_status_t st = GIT_STATUS_CURRENT;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
switch (head2idx->status) {
|
|
Packit Service |
20376f |
case GIT_DELTA_ADDED:
|
|
Packit Service |
20376f |
case GIT_DELTA_COPIED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_INDEX_NEW;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_DELETED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_INDEX_DELETED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_MODIFIED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_INDEX_MODIFIED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_RENAMED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_INDEX_RENAMED;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!git_oid_equal(&head2idx->old_file.id, &head2idx->new_file.id))
|
|
Packit Service |
20376f |
st |= GIT_STATUS_INDEX_MODIFIED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_TYPECHANGE:
|
|
Packit Service |
20376f |
st = GIT_STATUS_INDEX_TYPECHANGE;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_CONFLICTED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_CONFLICTED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
default:
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return st;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static unsigned int workdir_delta2status(
|
|
Packit Service |
20376f |
git_diff *diff, git_diff_delta *idx2wd)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_status_t st = GIT_STATUS_CURRENT;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
switch (idx2wd->status) {
|
|
Packit Service |
20376f |
case GIT_DELTA_ADDED:
|
|
Packit Service |
20376f |
case GIT_DELTA_COPIED:
|
|
Packit Service |
20376f |
case GIT_DELTA_UNTRACKED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_WT_NEW;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_UNREADABLE:
|
|
Packit Service |
20376f |
st = GIT_STATUS_WT_UNREADABLE;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_DELETED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_WT_DELETED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_MODIFIED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_WT_MODIFIED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_IGNORED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_IGNORED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_RENAMED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_WT_RENAMED;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id)) {
|
|
Packit Service |
20376f |
/* if OIDs don't match, we might need to calculate them now to
|
|
Packit Service |
20376f |
* discern between RENAMED vs RENAMED+MODIFED
|
|
Packit Service |
20376f |
*/
|
|
Packit Service |
20376f |
if (git_oid_iszero(&idx2wd->old_file.id) &&
|
|
Packit Service |
20376f |
diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
|
|
Packit Service |
20376f |
!git_diff__oid_for_file(
|
|
Packit Service |
20376f |
&idx2wd->old_file.id, diff, idx2wd->old_file.path,
|
|
Packit Service |
20376f |
idx2wd->old_file.mode, idx2wd->old_file.size))
|
|
Packit Service |
20376f |
idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (git_oid_iszero(&idx2wd->new_file.id) &&
|
|
Packit Service |
20376f |
diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
|
|
Packit Service |
20376f |
!git_diff__oid_for_file(
|
|
Packit Service |
20376f |
&idx2wd->new_file.id, diff, idx2wd->new_file.path,
|
|
Packit Service |
20376f |
idx2wd->new_file.mode, idx2wd->new_file.size))
|
|
Packit Service |
20376f |
idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id))
|
|
Packit Service |
20376f |
st |= GIT_STATUS_WT_MODIFIED;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_TYPECHANGE:
|
|
Packit Service |
20376f |
st = GIT_STATUS_WT_TYPECHANGE;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
case GIT_DELTA_CONFLICTED:
|
|
Packit Service |
20376f |
st = GIT_STATUS_CONFLICTED;
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
default:
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return st;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static bool status_is_included(
|
|
Packit Service |
20376f |
git_status_list *status,
|
|
Packit Service |
20376f |
git_diff_delta *head2idx,
|
|
Packit Service |
20376f |
git_diff_delta *idx2wd)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
if (!(status->opts.flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES))
|
|
Packit Service |
20376f |
return 1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* if excluding submodules and this is a submodule everywhere */
|
|
Packit Service |
20376f |
if (head2idx) {
|
|
Packit Service |
20376f |
if (head2idx->status != GIT_DELTA_ADDED &&
|
|
Packit Service |
20376f |
head2idx->old_file.mode != GIT_FILEMODE_COMMIT)
|
|
Packit Service |
20376f |
return 1;
|
|
Packit Service |
20376f |
if (head2idx->status != GIT_DELTA_DELETED &&
|
|
Packit Service |
20376f |
head2idx->new_file.mode != GIT_FILEMODE_COMMIT)
|
|
Packit Service |
20376f |
return 1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
if (idx2wd) {
|
|
Packit Service |
20376f |
if (idx2wd->status != GIT_DELTA_ADDED &&
|
|
Packit Service |
20376f |
idx2wd->old_file.mode != GIT_FILEMODE_COMMIT)
|
|
Packit Service |
20376f |
return 1;
|
|
Packit Service |
20376f |
if (idx2wd->status != GIT_DELTA_DELETED &&
|
|
Packit Service |
20376f |
idx2wd->new_file.mode != GIT_FILEMODE_COMMIT)
|
|
Packit Service |
20376f |
return 1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* only get here if every valid mode is GIT_FILEMODE_COMMIT */
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static git_status_t status_compute(
|
|
Packit Service |
20376f |
git_status_list *status,
|
|
Packit Service |
20376f |
git_diff_delta *head2idx,
|
|
Packit Service |
20376f |
git_diff_delta *idx2wd)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_status_t st = GIT_STATUS_CURRENT;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (head2idx)
|
|
Packit Service |
20376f |
st |= index_delta2status(head2idx);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (idx2wd)
|
|
Packit Service |
20376f |
st |= workdir_delta2status(status->idx2wd, idx2wd);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return st;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int status_collect(
|
|
Packit Service |
20376f |
git_diff_delta *head2idx,
|
|
Packit Service |
20376f |
git_diff_delta *idx2wd,
|
|
Packit Service |
20376f |
void *payload)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_status_list *status = payload;
|
|
Packit Service |
20376f |
git_status_entry *status_entry;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!status_is_included(status, head2idx, idx2wd))
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
status_entry = git__malloc(sizeof(git_status_entry));
|
|
Packit Service |
20376f |
GITERR_CHECK_ALLOC(status_entry);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
status_entry->status = status_compute(status, head2idx, idx2wd);
|
|
Packit Service |
20376f |
status_entry->head_to_index = head2idx;
|
|
Packit Service |
20376f |
status_entry->index_to_workdir = idx2wd;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return git_vector_insert(&status->paired, status_entry);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
GIT_INLINE(int) status_entry_cmp_base(
|
|
Packit Service |
20376f |
const void *a,
|
|
Packit Service |
20376f |
const void *b,
|
|
Packit Service |
20376f |
int (*strcomp)(const char *a, const char *b))
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
const git_status_entry *entry_a = a;
|
|
Packit Service |
20376f |
const git_status_entry *entry_b = b;
|
|
Packit Service |
20376f |
const git_diff_delta *delta_a, *delta_b;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
delta_a = entry_a->index_to_workdir ? entry_a->index_to_workdir :
|
|
Packit Service |
20376f |
entry_a->head_to_index;
|
|
Packit Service |
20376f |
delta_b = entry_b->index_to_workdir ? entry_b->index_to_workdir :
|
|
Packit Service |
20376f |
entry_b->head_to_index;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!delta_a && delta_b)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
if (delta_a && !delta_b)
|
|
Packit Service |
20376f |
return 1;
|
|
Packit Service |
20376f |
if (!delta_a && !delta_b)
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return strcomp(delta_a->new_file.path, delta_b->new_file.path);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int status_entry_icmp(const void *a, const void *b)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
return status_entry_cmp_base(a, b, git__strcasecmp);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int status_entry_cmp(const void *a, const void *b)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
return status_entry_cmp_base(a, b, git__strcmp);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static git_status_list *git_status_list_alloc(git_index *index)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_status_list *status = NULL;
|
|
Packit Service |
20376f |
int (*entrycmp)(const void *a, const void *b);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!(status = git__calloc(1, sizeof(git_status_list))))
|
|
Packit Service |
20376f |
return NULL;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
entrycmp = index->ignore_case ? status_entry_icmp : status_entry_cmp;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (git_vector_init(&status->paired, 0, entrycmp) < 0) {
|
|
Packit Service |
20376f |
git__free(status);
|
|
Packit Service |
20376f |
return NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return status;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int status_validate_options(const git_status_options *opts)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
if (!opts)
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options");
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (opts->show > GIT_STATUS_SHOW_WORKDIR_ONLY) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_INVALID, "unknown status 'show' option");
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((opts->flags & GIT_STATUS_OPT_NO_REFRESH) != 0 &&
|
|
Packit Service |
20376f |
(opts->flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_INVALID, "updating index from status "
|
|
Packit Service |
20376f |
"is not allowed when index refresh is disabled");
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_status_list_new(
|
|
Packit Service |
20376f |
git_status_list **out,
|
|
Packit Service |
20376f |
git_repository *repo,
|
|
Packit Service |
20376f |
const git_status_options *opts)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_index *index = NULL;
|
|
Packit Service |
20376f |
git_status_list *status = NULL;
|
|
Packit Service |
20376f |
git_diff_options diffopt = GIT_DIFF_OPTIONS_INIT;
|
|
Packit Service |
20376f |
git_diff_find_options findopt = GIT_DIFF_FIND_OPTIONS_INIT;
|
|
Packit Service |
20376f |
git_tree *head = NULL;
|
|
Packit Service |
20376f |
git_status_show_t show =
|
|
Packit Service |
20376f |
opts ? opts->show : GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
|
Packit Service |
20376f |
int error = 0;
|
|
Packit Service |
20376f |
unsigned int flags = opts ? opts->flags : GIT_STATUS_OPT_DEFAULTS;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
*out = NULL;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (status_validate_options(opts) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = git_repository__ensure_not_bare(repo, "status")) < 0 ||
|
|
Packit Service |
20376f |
(error = git_repository_index(&index, repo)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* if there is no HEAD, that's okay - we'll make an empty iterator */
|
|
Packit Service |
20376f |
if ((error = git_repository_head_tree(&head, repo)) < 0) {
|
|
Packit Service |
20376f |
if (error != GIT_ENOTFOUND && error != GIT_EUNBORNBRANCH)
|
|
Packit Service |
20376f |
goto done;
|
|
Packit Service |
20376f |
giterr_clear();
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* refresh index from disk unless prevented */
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_NO_REFRESH) == 0 &&
|
|
Packit Service |
20376f |
git_index_read(index, false) < 0)
|
|
Packit Service |
20376f |
giterr_clear();
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
status = git_status_list_alloc(index);
|
|
Packit Service |
20376f |
GITERR_CHECK_ALLOC(status);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (opts) {
|
|
Packit Service |
20376f |
memcpy(&status->opts, opts, sizeof(git_status_options));
|
|
Packit Service |
20376f |
memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec));
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
diffopt.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
|
|
Packit Service |
20376f |
findopt.flags = GIT_DIFF_FIND_FOR_UNTRACKED;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_INCLUDE_UNTRACKED) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNTRACKED;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_INCLUDE_IGNORED) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_IGNORED;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_INCLUDE_UNMODIFIED) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNMODIFIED;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_DISABLE_PATHSPEC_MATCH;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_RECURSE_IGNORED_DIRS) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_IGNORED_DIRS;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_UPDATE_INDEX;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_INCLUDE_UNREADABLE) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNREADABLE;
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED) != 0)
|
|
Packit Service |
20376f |
diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_RENAMES_FROM_REWRITES) != 0)
|
|
Packit Service |
20376f |
findopt.flags = findopt.flags |
|
|
Packit Service |
20376f |
GIT_DIFF_FIND_AND_BREAK_REWRITES |
|
|
Packit Service |
20376f |
GIT_DIFF_FIND_RENAMES_FROM_REWRITES |
|
|
Packit Service |
20376f |
GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (show != GIT_STATUS_SHOW_WORKDIR_ONLY) {
|
|
Packit Service |
20376f |
if ((error = git_diff_tree_to_index(
|
|
Packit Service |
20376f |
&status->head2idx, repo, head, index, &diffopt)) < 0)
|
|
Packit Service |
20376f |
goto done;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX) != 0 &&
|
|
Packit Service |
20376f |
(error = git_diff_find_similar(status->head2idx, &findopt)) < 0)
|
|
Packit Service |
20376f |
goto done;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (show != GIT_STATUS_SHOW_INDEX_ONLY) {
|
|
Packit Service |
20376f |
if ((error = git_diff_index_to_workdir(
|
|
Packit Service |
20376f |
&status->idx2wd, repo, index, &diffopt)) < 0) {
|
|
Packit Service |
20376f |
goto done;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((flags & GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR) != 0 &&
|
|
Packit Service |
20376f |
(error = git_diff_find_similar(status->idx2wd, &findopt)) < 0)
|
|
Packit Service |
20376f |
goto done;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
error = git_diff__paired_foreach(
|
|
Packit Service |
20376f |
status->head2idx, status->idx2wd, status_collect, status);
|
|
Packit Service |
20376f |
if (error < 0)
|
|
Packit Service |
20376f |
goto done;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY)
|
|
Packit Service |
20376f |
git_vector_set_cmp(&status->paired, status_entry_cmp);
|
|
Packit Service |
20376f |
if (flags & GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)
|
|
Packit Service |
20376f |
git_vector_set_cmp(&status->paired, status_entry_icmp);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((flags &
|
|
Packit Service |
20376f |
(GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_SORT_CASE_SENSITIVELY |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY)) != 0)
|
|
Packit Service |
20376f |
git_vector_sort(&status->paired);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
done:
|
|
Packit Service |
20376f |
if (error < 0) {
|
|
Packit Service |
20376f |
git_status_list_free(status);
|
|
Packit Service |
20376f |
status = NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
*out = status;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_tree_free(head);
|
|
Packit Service |
20376f |
git_index_free(index);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
size_t git_status_list_entrycount(git_status_list *status)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
assert(status);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return status->paired.length;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
const git_status_entry *git_status_byindex(git_status_list *status, size_t i)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
assert(status);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return git_vector_get(&status->paired, i);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
void git_status_list_free(git_status_list *status)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
if (status == NULL)
|
|
Packit Service |
20376f |
return;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_diff_free(status->head2idx);
|
|
Packit Service |
20376f |
git_diff_free(status->idx2wd);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_free_deep(&status->paired);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git__memzero(status, sizeof(*status));
|
|
Packit Service |
20376f |
git__free(status);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_status_foreach_ext(
|
|
Packit Service |
20376f |
git_repository *repo,
|
|
Packit Service |
20376f |
const git_status_options *opts,
|
|
Packit Service |
20376f |
git_status_cb cb,
|
|
Packit Service |
20376f |
void *payload)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_status_list *status;
|
|
Packit Service |
20376f |
const git_status_entry *status_entry;
|
|
Packit Service |
20376f |
size_t i;
|
|
Packit Service |
20376f |
int error = 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = git_status_list_new(&status, repo, opts)) < 0) {
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_foreach(&status->paired, i, status_entry) {
|
|
Packit Service |
20376f |
const char *path = status_entry->head_to_index ?
|
|
Packit Service |
20376f |
status_entry->head_to_index->old_file.path :
|
|
Packit Service |
20376f |
status_entry->index_to_workdir->old_file.path;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = cb(path, status_entry->status, payload)) != 0) {
|
|
Packit Service |
20376f |
giterr_set_after_callback(error);
|
|
Packit Service |
20376f |
break;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_status_list_free(status);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_status_foreach(git_repository *repo, git_status_cb cb, void *payload)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
return git_status_foreach_ext(repo, NULL, cb, payload);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
struct status_file_info {
|
|
Packit Service |
20376f |
char *expected;
|
|
Packit Service |
20376f |
unsigned int count;
|
|
Packit Service |
20376f |
unsigned int status;
|
|
Packit Service |
20376f |
int fnm_flags;
|
|
Packit Service |
20376f |
int ambiguous;
|
|
Packit Service |
20376f |
};
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int get_one_status(const char *path, unsigned int status, void *data)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
struct status_file_info *sfi = data;
|
|
Packit Service |
20376f |
int (*strcomp)(const char *a, const char *b);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
sfi->count++;
|
|
Packit Service |
20376f |
sfi->status = status;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
strcomp = (sfi->fnm_flags & FNM_CASEFOLD) ? git__strcasecmp : git__strcmp;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (sfi->count > 1 ||
|
|
Packit Service |
20376f |
(strcomp(sfi->expected, path) != 0 &&
|
|
Packit Service |
20376f |
p_fnmatch(sfi->expected, path, sfi->fnm_flags) != 0))
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
sfi->ambiguous = true;
|
|
Packit Service |
20376f |
return GIT_EAMBIGUOUS; /* giterr_set will be done by caller */
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_status_file(
|
|
Packit Service |
20376f |
unsigned int *status_flags,
|
|
Packit Service |
20376f |
git_repository *repo,
|
|
Packit Service |
20376f |
const char *path)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
int error;
|
|
Packit Service |
20376f |
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
|
Packit Service |
20376f |
struct status_file_info sfi = {0};
|
|
Packit Service |
20376f |
git_index *index;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
assert(status_flags && repo && path);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = git_repository_index__weakptr(&index, repo)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((sfi.expected = git__strdup(path)) == NULL)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
if (index->ignore_case)
|
|
Packit Service |
20376f |
sfi.fnm_flags = FNM_CASEFOLD;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
|
Packit Service |
20376f |
opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_RECURSE_IGNORED_DIRS |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_INCLUDE_UNTRACKED |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_INCLUDE_UNMODIFIED |
|
|
Packit Service |
20376f |
GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH;
|
|
Packit Service |
20376f |
opts.pathspec.count = 1;
|
|
Packit Service |
20376f |
opts.pathspec.strings = &sfi.expected;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi;;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (error < 0 && sfi.ambiguous) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_INVALID,
|
|
Packit Service |
20376f |
"ambiguous path '%s' given to git_status_file", sfi.expected);
|
|
Packit Service |
20376f |
error = GIT_EAMBIGUOUS;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!error && !sfi.count) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_INVALID,
|
|
Packit Service |
20376f |
"attempt to get status of nonexistent file '%s'", path);
|
|
Packit Service |
20376f |
error = GIT_ENOTFOUND;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
*status_flags = sfi.status;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git__free(sfi.expected);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_status_should_ignore(
|
|
Packit Service |
20376f |
int *ignored,
|
|
Packit Service |
20376f |
git_repository *repo,
|
|
Packit Service |
20376f |
const char *path)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
return git_ignore_path_is_ignored(ignored, repo, path);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_status_init_options(git_status_options *opts, unsigned int version)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
|
|
Packit Service |
20376f |
opts, version, git_status_options, GIT_STATUS_OPTIONS_INIT);
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_status_list_get_perfdata(
|
|
Packit Service |
20376f |
git_diff_perfdata *out, const git_status_list *status)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
assert(out);
|
|
Packit Service |
20376f |
GITERR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
out->stat_calls = 0;
|
|
Packit Service |
20376f |
out->oid_calculations = 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (status->head2idx) {
|
|
Packit Service |
20376f |
out->stat_calls += status->head2idx->perf.stat_calls;
|
|
Packit Service |
20376f |
out->oid_calculations += status->head2idx->perf.oid_calculations;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
if (status->idx2wd) {
|
|
Packit Service |
20376f |
out->stat_calls += status->idx2wd->perf.stat_calls;
|
|
Packit Service |
20376f |
out->oid_calculations += status->idx2wd->perf.oid_calculations;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|