mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 12:57:05 +00:00
Merge remote-tracking branch 'libgit2/development' into bs/more-reflog-stuff
This commit is contained in:
commit
0de2c4e3a3
@ -87,7 +87,7 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker);
|
||||
/**
|
||||
* Mark a commit to start traversal from.
|
||||
*
|
||||
* The given OID must belong to a commit on the walked
|
||||
* The given OID must belong to a committish on the walked
|
||||
* repository.
|
||||
*
|
||||
* The given commit will be used as one of the roots
|
||||
@ -108,7 +108,10 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *id);
|
||||
* pattern will be pushed to the revision walker.
|
||||
*
|
||||
* A leading 'refs/' is implied if not present as well as a trailing
|
||||
* '/ *' if the glob lacks '?', '*' or '['.
|
||||
* '/\*' if the glob lacks '?', '\*' or '['.
|
||||
*
|
||||
* Any references matching this glob which do not point to a
|
||||
* committish will be ignored.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param glob the glob pattern references should match
|
||||
@ -127,7 +130,7 @@ GIT_EXTERN(int) git_revwalk_push_head(git_revwalk *walk);
|
||||
/**
|
||||
* Mark a commit (and its ancestors) uninteresting for the output.
|
||||
*
|
||||
* The given OID must belong to a commit on the walked
|
||||
* The given OID must belong to a committish on the walked
|
||||
* repository.
|
||||
*
|
||||
* The resolved commit and all its parents will be hidden from the
|
||||
@ -147,7 +150,10 @@ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *commit_id);
|
||||
* revision walk.
|
||||
*
|
||||
* A leading 'refs/' is implied if not present as well as a trailing
|
||||
* '/ *' if the glob lacks '?', '*' or '['.
|
||||
* '/\*' if the glob lacks '?', '\*' or '['.
|
||||
*
|
||||
* Any references matching this glob which do not point to a
|
||||
* committish will be ignored.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param glob the glob pattern references should match
|
||||
@ -166,7 +172,7 @@ GIT_EXTERN(int) git_revwalk_hide_head(git_revwalk *walk);
|
||||
/**
|
||||
* Push the OID pointed to by a reference
|
||||
*
|
||||
* The reference must point to a commit.
|
||||
* The reference must point to a committish.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param refname the reference to push
|
||||
@ -177,7 +183,7 @@ GIT_EXTERN(int) git_revwalk_push_ref(git_revwalk *walk, const char *refname);
|
||||
/**
|
||||
* Hide the OID pointed to by a reference
|
||||
*
|
||||
* The reference must point to a commit.
|
||||
* The reference must point to a committish.
|
||||
*
|
||||
* @param walk the walker being used for the traversal
|
||||
* @param refname the reference to hide
|
||||
|
40
src/commit.c
40
src/commit.c
@ -183,33 +183,15 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
|
||||
const char *buffer_start = git_odb_object_data(odb_obj), *buffer;
|
||||
const char *buffer_end = buffer_start + git_odb_object_size(odb_obj);
|
||||
git_oid parent_id;
|
||||
uint32_t parent_count = 0;
|
||||
size_t header_len;
|
||||
|
||||
/* find end-of-header (counting parents as we go) */
|
||||
for (buffer = buffer_start; buffer < buffer_end; ++buffer) {
|
||||
if (!strncmp("\n\n", buffer, 2)) {
|
||||
++buffer;
|
||||
break;
|
||||
}
|
||||
if (!strncmp("\nparent ", buffer, strlen("\nparent ")))
|
||||
++parent_count;
|
||||
}
|
||||
buffer = buffer_start;
|
||||
|
||||
header_len = buffer - buffer_start;
|
||||
commit->raw_header = git__strndup(buffer_start, header_len);
|
||||
GITERR_CHECK_ALLOC(commit->raw_header);
|
||||
|
||||
/* point "buffer" to header data */
|
||||
buffer = commit->raw_header;
|
||||
buffer_end = commit->raw_header + header_len;
|
||||
|
||||
if (parent_count < 1)
|
||||
parent_count = 1;
|
||||
|
||||
git_array_init_to_size(commit->parent_ids, parent_count);
|
||||
/* Allocate for one, which will allow not to realloc 90% of the time */
|
||||
git_array_init_to_size(commit->parent_ids, 1);
|
||||
GITERR_CHECK_ARRAY(commit->parent_ids);
|
||||
|
||||
/* The tree is always the first field */
|
||||
if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
|
||||
goto bad_buffer;
|
||||
|
||||
@ -240,6 +222,9 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
|
||||
/* Parse add'l header entries */
|
||||
while (buffer < buffer_end) {
|
||||
const char *eoln = buffer;
|
||||
if (buffer[-1] == '\n' && buffer[0] == '\n')
|
||||
break;
|
||||
|
||||
while (eoln < buffer_end && *eoln != '\n')
|
||||
++eoln;
|
||||
|
||||
@ -255,13 +240,12 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
|
||||
buffer = eoln;
|
||||
}
|
||||
|
||||
/* point "buffer" to data after header */
|
||||
buffer = git_odb_object_data(odb_obj);
|
||||
buffer_end = buffer + git_odb_object_size(odb_obj);
|
||||
header_len = buffer - buffer_start;
|
||||
commit->raw_header = git__strndup(buffer_start, header_len);
|
||||
GITERR_CHECK_ALLOC(commit->raw_header);
|
||||
|
||||
buffer += header_len;
|
||||
if (*buffer == '\n')
|
||||
++buffer;
|
||||
/* point "buffer" to data after header, +1 for the final LF */
|
||||
buffer = buffer_start + header_len + 1;
|
||||
|
||||
/* extract commit message */
|
||||
if (buffer <= buffer_end) {
|
||||
|
11
src/merge.c
11
src/merge.c
@ -2330,7 +2330,7 @@ done:
|
||||
|
||||
static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths)
|
||||
{
|
||||
git_tree *head_tree = NULL;
|
||||
git_index *index_repo = NULL;
|
||||
git_diff *wd_diff_list = NULL;
|
||||
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
||||
int error = 0;
|
||||
@ -2341,9 +2341,6 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde
|
||||
|
||||
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
|
||||
|
||||
if ((error = git_repository_head_tree(&head_tree, repo)) < 0)
|
||||
goto done;
|
||||
|
||||
/* Workdir changes may exist iff they do not conflict with changes that
|
||||
* will be applied by the merge (including conflicts). Ensure that there
|
||||
* are no changes in the workdir to these paths.
|
||||
@ -2351,13 +2348,13 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde
|
||||
opts.pathspec.count = merged_paths->length;
|
||||
opts.pathspec.strings = (char **)merged_paths->contents;
|
||||
|
||||
if ((error = git_diff_tree_to_workdir(&wd_diff_list, repo, head_tree, &opts)) < 0)
|
||||
if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, index_repo, &opts)) < 0)
|
||||
goto done;
|
||||
|
||||
*conflicts = wd_diff_list->deltas.length;
|
||||
|
||||
done:
|
||||
git_tree_free(head_tree);
|
||||
git_index_free(index_repo);
|
||||
git_diff_free(wd_diff_list);
|
||||
|
||||
return error;
|
||||
@ -2400,7 +2397,7 @@ int git_merge__indexes(git_repository *repo, git_index *index_new)
|
||||
|
||||
/* Remove removed items from the index */
|
||||
git_vector_foreach(&paths, i, path) {
|
||||
if ((e = git_index_get_bypath(index_new, path, 0)) == NULL) {
|
||||
if (git_index_get_bypath(index_new, path, 0) == NULL) {
|
||||
if ((error = git_index_remove(index_repo, path, 0)) < 0 &&
|
||||
error != GIT_ENOTFOUND)
|
||||
goto done;
|
||||
|
13
src/posix.h
13
src/posix.h
@ -89,18 +89,7 @@ extern struct tm * p_gmtime_r (const time_t *timer, struct tm *result);
|
||||
# include "unix/posix.h"
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) || defined(__sun) || defined(__APPLE__)
|
||||
# define NO_STRNLEN
|
||||
#endif
|
||||
|
||||
#ifdef NO_STRNLEN
|
||||
GIT_INLINE(size_t) p_strnlen(const char *s, size_t maxlen) {
|
||||
const char *end = memchr(s, 0, maxlen);
|
||||
return end ? (size_t)(end - s) : maxlen;
|
||||
}
|
||||
#else
|
||||
# define p_strnlen strnlen
|
||||
#endif
|
||||
#include "strnlen.h"
|
||||
|
||||
#ifdef NO_READDIR_R
|
||||
# include <dirent.h>
|
||||
|
@ -490,8 +490,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_
|
||||
git_revwalk_sorting(walk, GIT_SORT_TIME);
|
||||
|
||||
if (spec_oid == NULL) {
|
||||
// TODO: @carlosmn: The glob should be refs/* but this makes git_revwalk_next() fails
|
||||
if ((error = git_revwalk_push_glob(walk, GIT_REFS_HEADS_DIR "*")) < 0)
|
||||
if ((error = git_revwalk_push_glob(walk, "refs/*")) < 0)
|
||||
goto cleanup;
|
||||
} else if ((error = git_revwalk_push(walk, spec_oid)) < 0)
|
||||
goto cleanup;
|
||||
|
@ -110,25 +110,34 @@ static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commi
|
||||
return error;
|
||||
}
|
||||
|
||||
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
|
||||
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob)
|
||||
{
|
||||
git_oid commit_id;
|
||||
int error;
|
||||
git_object *obj;
|
||||
git_otype type;
|
||||
git_object *obj, *oobj;
|
||||
git_commit_list_node *commit;
|
||||
|
||||
if ((error = git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY)) < 0)
|
||||
if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJ_ANY)) < 0)
|
||||
return error;
|
||||
|
||||
type = git_object_type(obj);
|
||||
git_object_free(obj);
|
||||
error = git_object_peel(&obj, oobj, GIT_OBJ_COMMIT);
|
||||
git_object_free(oobj);
|
||||
|
||||
if (type != GIT_OBJ_COMMIT) {
|
||||
giterr_set(GITERR_INVALID, "Object is no commit object");
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
/* If this comes from e.g. push_glob("tags"), ignore this */
|
||||
if (from_glob)
|
||||
return 0;
|
||||
|
||||
giterr_set(GITERR_INVALID, "Object is not a committish");
|
||||
return -1;
|
||||
}
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
commit = git_revwalk__commit_lookup(walk, oid);
|
||||
git_oid_cpy(&commit_id, git_object_id(obj));
|
||||
git_object_free(obj);
|
||||
|
||||
commit = git_revwalk__commit_lookup(walk, &commit_id);
|
||||
if (commit == NULL)
|
||||
return -1; /* error already reported by failed lookup */
|
||||
|
||||
@ -146,24 +155,24 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
|
||||
int git_revwalk_push(git_revwalk *walk, const git_oid *oid)
|
||||
{
|
||||
assert(walk && oid);
|
||||
return push_commit(walk, oid, 0);
|
||||
return push_commit(walk, oid, 0, false);
|
||||
}
|
||||
|
||||
|
||||
int git_revwalk_hide(git_revwalk *walk, const git_oid *oid)
|
||||
{
|
||||
assert(walk && oid);
|
||||
return push_commit(walk, oid, 1);
|
||||
return push_commit(walk, oid, 1, false);
|
||||
}
|
||||
|
||||
static int push_ref(git_revwalk *walk, const char *refname, int hide)
|
||||
static int push_ref(git_revwalk *walk, const char *refname, int hide, int from_glob)
|
||||
{
|
||||
git_oid oid;
|
||||
|
||||
if (git_reference_name_to_id(&oid, walk->repo, refname) < 0)
|
||||
return -1;
|
||||
|
||||
return push_commit(walk, &oid, hide);
|
||||
return push_commit(walk, &oid, hide, from_glob);
|
||||
}
|
||||
|
||||
struct push_cb_data {
|
||||
@ -171,17 +180,12 @@ struct push_cb_data {
|
||||
int hide;
|
||||
};
|
||||
|
||||
static int push_glob_cb(const char *refname, void *data_)
|
||||
{
|
||||
struct push_cb_data *data = (struct push_cb_data *)data_;
|
||||
return push_ref(data->walk, refname, data->hide);
|
||||
}
|
||||
|
||||
static int push_glob(git_revwalk *walk, const char *glob, int hide)
|
||||
{
|
||||
int error = 0;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
struct push_cb_data data;
|
||||
git_reference *ref;
|
||||
git_reference_iterator *iter;
|
||||
size_t wildcard;
|
||||
|
||||
assert(walk && glob);
|
||||
@ -199,12 +203,20 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide)
|
||||
if (!glob[wildcard])
|
||||
git_buf_put(&buf, "/*", 2);
|
||||
|
||||
data.walk = walk;
|
||||
data.hide = hide;
|
||||
if ((error = git_reference_iterator_glob_new(&iter, walk->repo, buf.ptr)) < 0)
|
||||
goto out;
|
||||
|
||||
error = git_reference_foreach_glob(
|
||||
walk->repo, git_buf_cstr(&buf), push_glob_cb, &data);
|
||||
while ((error = git_reference_next(&ref, iter)) == 0) {
|
||||
error = push_ref(walk, git_reference_name(ref), hide, true);
|
||||
git_reference_free(ref);
|
||||
if (error < 0)
|
||||
break;
|
||||
}
|
||||
git_reference_iterator_free(iter);
|
||||
|
||||
if (error == GIT_ITEROVER)
|
||||
error = 0;
|
||||
out:
|
||||
git_buf_free(&buf);
|
||||
return error;
|
||||
}
|
||||
@ -224,19 +236,19 @@ int git_revwalk_hide_glob(git_revwalk *walk, const char *glob)
|
||||
int git_revwalk_push_head(git_revwalk *walk)
|
||||
{
|
||||
assert(walk);
|
||||
return push_ref(walk, GIT_HEAD_FILE, 0);
|
||||
return push_ref(walk, GIT_HEAD_FILE, 0, false);
|
||||
}
|
||||
|
||||
int git_revwalk_hide_head(git_revwalk *walk)
|
||||
{
|
||||
assert(walk);
|
||||
return push_ref(walk, GIT_HEAD_FILE, 1);
|
||||
return push_ref(walk, GIT_HEAD_FILE, 1, false);
|
||||
}
|
||||
|
||||
int git_revwalk_push_ref(git_revwalk *walk, const char *refname)
|
||||
{
|
||||
assert(walk && refname);
|
||||
return push_ref(walk, refname, 0);
|
||||
return push_ref(walk, refname, 0, false);
|
||||
}
|
||||
|
||||
int git_revwalk_push_range(git_revwalk *walk, const char *range)
|
||||
@ -253,10 +265,10 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range)
|
||||
return GIT_EINVALIDSPEC;
|
||||
}
|
||||
|
||||
if ((error = push_commit(walk, git_object_id(revspec.from), 1)))
|
||||
if ((error = push_commit(walk, git_object_id(revspec.from), 1, false)))
|
||||
goto out;
|
||||
|
||||
error = push_commit(walk, git_object_id(revspec.to), 0);
|
||||
error = push_commit(walk, git_object_id(revspec.to), 0, false);
|
||||
|
||||
out:
|
||||
git_object_free(revspec.from);
|
||||
@ -267,7 +279,7 @@ out:
|
||||
int git_revwalk_hide_ref(git_revwalk *walk, const char *refname)
|
||||
{
|
||||
assert(walk && refname);
|
||||
return push_ref(walk, refname, 1);
|
||||
return push_ref(walk, refname, 1, false);
|
||||
}
|
||||
|
||||
static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit)
|
||||
|
23
src/strnlen.h
Normal file
23
src/strnlen.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_strlen_h__
|
||||
#define INCLUDE_strlen_h__
|
||||
|
||||
#if defined(__MINGW32__) || defined(__sun) || defined(__APPLE__)
|
||||
# define NO_STRNLEN
|
||||
#endif
|
||||
|
||||
#ifdef NO_STRNLEN
|
||||
GIT_INLINE(size_t) p_strnlen(const char *s, size_t maxlen) {
|
||||
const char *end = memchr(s, 0, maxlen);
|
||||
return end ? (size_t)(end - s) : maxlen;
|
||||
}
|
||||
#else
|
||||
# define p_strnlen strnlen
|
||||
#endif
|
||||
|
||||
#endif
|
@ -8,6 +8,7 @@
|
||||
#define INCLUDE_util_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "strnlen.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
|
||||
@ -50,8 +51,7 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n)
|
||||
size_t length = 0;
|
||||
char *ptr;
|
||||
|
||||
while (length < n && str[length])
|
||||
++length;
|
||||
length = p_strnlen(str, n);
|
||||
|
||||
ptr = (char*)git__malloc(length + 1);
|
||||
|
||||
|
322
tests/merge/workdir/dirty.c
Normal file
322
tests/merge/workdir/dirty.c
Normal file
@ -0,0 +1,322 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "git2/merge.h"
|
||||
#include "buffer.h"
|
||||
#include "merge.h"
|
||||
#include "../merge_helpers.h"
|
||||
#include "posix.h"
|
||||
|
||||
#define TEST_REPO_PATH "merge-resolve"
|
||||
#define MERGE_BRANCH_OID "7cb63eed597130ba4abb87b3e544b85021905520"
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE \
|
||||
"this file is changed in master\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is changed in branch\n"
|
||||
|
||||
#define CHANGED_IN_BRANCH_FILE \
|
||||
"changed in branch\n"
|
||||
|
||||
static git_repository *repo;
|
||||
static git_index *repo_index;
|
||||
|
||||
static char *unaffected[][4] = {
|
||||
{ "added-in-master.txt", NULL },
|
||||
{ "changed-in-master.txt", NULL },
|
||||
{ "unchanged.txt", NULL },
|
||||
{ "added-in-master.txt", "changed-in-master.txt", NULL },
|
||||
{ "added-in-master.txt", "unchanged.txt", NULL },
|
||||
{ "changed-in-master.txt", "unchanged.txt", NULL },
|
||||
{ "added-in-master.txt", "changed-in-master.txt", "unchanged.txt", NULL },
|
||||
{ "new_file.txt", NULL },
|
||||
{ "new_file.txt", "unchanged.txt", NULL },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static char *affected[][5] = {
|
||||
{ "automergeable.txt", NULL },
|
||||
{ "changed-in-branch.txt", NULL },
|
||||
{ "conflicting.txt", NULL },
|
||||
{ "removed-in-branch.txt", NULL },
|
||||
{ "automergeable.txt", "changed-in-branch.txt", NULL },
|
||||
{ "automergeable.txt", "conflicting.txt", NULL },
|
||||
{ "automergeable.txt", "removed-in-branch.txt", NULL },
|
||||
{ "changed-in-branch.txt", "conflicting.txt", NULL },
|
||||
{ "changed-in-branch.txt", "removed-in-branch.txt", NULL },
|
||||
{ "conflicting.txt", "removed-in-branch.txt", NULL },
|
||||
{ "automergeable.txt", "changed-in-branch.txt", "conflicting.txt", NULL },
|
||||
{ "automergeable.txt", "changed-in-branch.txt", "removed-in-branch.txt", NULL },
|
||||
{ "automergeable.txt", "conflicting.txt", "removed-in-branch.txt", NULL },
|
||||
{ "changed-in-branch.txt", "conflicting.txt", "removed-in-branch.txt", NULL },
|
||||
{ "automergeable.txt", "changed-in-branch.txt", "conflicting.txt", "removed-in-branch.txt", NULL },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static char *result_contents[4][6] = {
|
||||
{ "automergeable.txt", AUTOMERGEABLE_MERGED_FILE, NULL, NULL },
|
||||
{ "changed-in-branch.txt", CHANGED_IN_BRANCH_FILE, NULL, NULL },
|
||||
{ "automergeable.txt", AUTOMERGEABLE_MERGED_FILE, "changed-in-branch.txt", CHANGED_IN_BRANCH_FILE, NULL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void test_merge_workdir_dirty__initialize(void)
|
||||
{
|
||||
repo = cl_git_sandbox_init(TEST_REPO_PATH);
|
||||
git_repository_index(&repo_index, repo);
|
||||
}
|
||||
|
||||
void test_merge_workdir_dirty__cleanup(void)
|
||||
{
|
||||
git_index_free(repo_index);
|
||||
cl_git_sandbox_cleanup();
|
||||
}
|
||||
|
||||
static void set_core_autocrlf_to(git_repository *repo, bool value)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, repo));
|
||||
cl_git_pass(git_config_set_bool(cfg, "core.autocrlf", value));
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int merge_branch(git_merge_result **result, int merge_file_favor, int checkout_strategy)
|
||||
{
|
||||
git_oid their_oids[1];
|
||||
git_merge_head *their_heads[1];
|
||||
git_merge_opts opts = GIT_MERGE_OPTS_INIT;
|
||||
int error;
|
||||
|
||||
cl_git_pass(git_oid_fromstr(&their_oids[0], MERGE_BRANCH_OID));
|
||||
cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0]));
|
||||
|
||||
opts.merge_tree_opts.file_favor = merge_file_favor;
|
||||
opts.checkout_opts.checkout_strategy = checkout_strategy;
|
||||
error = git_merge(result, repo, (const git_merge_head **)their_heads, 1, &opts);
|
||||
|
||||
git_merge_head_free(their_heads[0]);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void write_files(char *files[])
|
||||
{
|
||||
char *filename;
|
||||
git_buf path = GIT_BUF_INIT, content = GIT_BUF_INIT;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, filename = files[i]; filename; filename = files[++i]) {
|
||||
git_buf_clear(&path);
|
||||
git_buf_clear(&content);
|
||||
|
||||
git_buf_printf(&path, "%s/%s", TEST_REPO_PATH, filename);
|
||||
git_buf_printf(&content, "This is a dirty file in the working directory!\n\n"
|
||||
"It will not be staged! Its filename is %s.\n", filename);
|
||||
|
||||
cl_git_mkfile(path.ptr, content.ptr);
|
||||
}
|
||||
|
||||
git_buf_free(&path);
|
||||
git_buf_free(&content);
|
||||
}
|
||||
|
||||
static void hack_index(char *files[])
|
||||
{
|
||||
char *filename;
|
||||
struct stat statbuf;
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
git_index_entry *entry;
|
||||
size_t i;
|
||||
|
||||
/* Update the index to suggest that checkout placed these files on
|
||||
* disk, keeping the object id but updating the cache, which will
|
||||
* emulate a Git implementation's different filter.
|
||||
*/
|
||||
for (i = 0, filename = files[i]; filename; filename = files[++i]) {
|
||||
git_buf_clear(&path);
|
||||
|
||||
cl_assert(entry = (git_index_entry *)
|
||||
git_index_get_bypath(repo_index, filename, 0));
|
||||
|
||||
cl_git_pass(git_buf_printf(&path, "%s/%s", TEST_REPO_PATH, filename));
|
||||
cl_git_pass(p_stat(path.ptr, &statbuf));
|
||||
|
||||
entry->ctime.seconds = (git_time_t)statbuf.st_ctime;
|
||||
entry->ctime.nanoseconds = 0;
|
||||
entry->mtime.seconds = (git_time_t)statbuf.st_mtime;
|
||||
entry->mtime.nanoseconds = 0;
|
||||
entry->dev = statbuf.st_dev;
|
||||
entry->ino = statbuf.st_ino;
|
||||
entry->uid = statbuf.st_uid;
|
||||
entry->gid = statbuf.st_gid;
|
||||
entry->file_size = statbuf.st_size;
|
||||
}
|
||||
|
||||
git_buf_free(&path);
|
||||
}
|
||||
|
||||
static void stage_random_files(char *files[])
|
||||
{
|
||||
char *filename;
|
||||
size_t i;
|
||||
|
||||
write_files(files);
|
||||
|
||||
for (i = 0, filename = files[i]; filename; filename = files[++i])
|
||||
cl_git_pass(git_index_add_bypath(repo_index, filename));
|
||||
}
|
||||
|
||||
static void stage_content(char *content[])
|
||||
{
|
||||
git_reference *head;
|
||||
git_object *head_object;
|
||||
git_merge_result *result = NULL;
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
char *filename, *text;
|
||||
size_t i;
|
||||
|
||||
cl_git_pass(git_repository_head(&head, repo));
|
||||
cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT));
|
||||
cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD));
|
||||
|
||||
for (i = 0, filename = content[i], text = content[++i];
|
||||
filename && text;
|
||||
filename = content[++i], text = content[++i]) {
|
||||
|
||||
git_buf_clear(&path);
|
||||
|
||||
cl_git_pass(git_buf_printf(&path, "%s/%s", TEST_REPO_PATH, filename));
|
||||
|
||||
cl_git_mkfile(path.ptr, text);
|
||||
cl_git_pass(git_index_add_bypath(repo_index, filename));
|
||||
}
|
||||
|
||||
git_merge_result_free(result);
|
||||
git_object_free(head_object);
|
||||
git_reference_free(head);
|
||||
git_buf_free(&path);
|
||||
}
|
||||
|
||||
static int merge_dirty_files(char *dirty_files[])
|
||||
{
|
||||
git_reference *head;
|
||||
git_object *head_object;
|
||||
git_merge_result *result = NULL;
|
||||
int error;
|
||||
|
||||
cl_git_pass(git_repository_head(&head, repo));
|
||||
cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT));
|
||||
cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD));
|
||||
|
||||
write_files(dirty_files);
|
||||
|
||||
error = merge_branch(&result, 0, 0);
|
||||
|
||||
git_merge_result_free(result);
|
||||
git_object_free(head_object);
|
||||
git_reference_free(head);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int merge_differently_filtered_files(char *files[])
|
||||
{
|
||||
git_reference *head;
|
||||
git_object *head_object;
|
||||
git_merge_result *result = NULL;
|
||||
int error;
|
||||
|
||||
cl_git_pass(git_repository_head(&head, repo));
|
||||
cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT));
|
||||
cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD));
|
||||
|
||||
write_files(files);
|
||||
hack_index(files);
|
||||
|
||||
cl_git_pass(git_index_write(repo_index));
|
||||
|
||||
error = merge_branch(&result, 0, 0);
|
||||
|
||||
git_merge_result_free(result);
|
||||
git_object_free(head_object);
|
||||
git_reference_free(head);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int merge_staged_files(char *staged_files[])
|
||||
{
|
||||
git_merge_result *result = NULL;
|
||||
int error;
|
||||
|
||||
stage_random_files(staged_files);
|
||||
|
||||
error = merge_branch(&result, 0, 0);
|
||||
|
||||
git_merge_result_free(result);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void test_merge_workdir_dirty__unaffected_dirty_files_allowed(void)
|
||||
{
|
||||
char **files;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, files = unaffected[i]; files[0]; files = unaffected[++i])
|
||||
cl_git_pass(merge_dirty_files(files));
|
||||
}
|
||||
|
||||
void test_merge_workdir_dirty__affected_dirty_files_disallowed(void)
|
||||
{
|
||||
char **files;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, files = affected[i]; files[0]; files = affected[++i])
|
||||
cl_git_fail(merge_dirty_files(files));
|
||||
}
|
||||
|
||||
void test_merge_workdir_dirty__staged_files_in_index_disallowed(void)
|
||||
{
|
||||
char **files;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, files = unaffected[i]; files[0]; files = unaffected[++i])
|
||||
cl_git_fail(merge_staged_files(files));
|
||||
|
||||
for (i = 0, files = affected[i]; files[0]; files = affected[++i])
|
||||
cl_git_fail(merge_staged_files(files));
|
||||
}
|
||||
|
||||
void test_merge_workdir_dirty__identical_staged_files_allowed(void)
|
||||
{
|
||||
git_merge_result *result;
|
||||
char **content;
|
||||
size_t i;
|
||||
|
||||
set_core_autocrlf_to(repo, false);
|
||||
|
||||
for (i = 0, content = result_contents[i]; content[0]; content = result_contents[++i]) {
|
||||
stage_content(content);
|
||||
|
||||
git_index_write(repo_index);
|
||||
cl_git_pass(merge_branch(&result, 0, 0));
|
||||
|
||||
git_merge_result_free(result);
|
||||
}
|
||||
}
|
||||
|
||||
void test_merge_workdir_dirty__honors_cache(void)
|
||||
{
|
||||
char **files;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, files = affected[i]; files[0]; files = affected[++i])
|
||||
cl_git_pass(merge_differently_filtered_files(files));
|
||||
}
|
@ -9,7 +9,7 @@ static const char *third_tree = "eb86d8b81d6adbd5290a935d6c9976882de98488";
|
||||
|
||||
static git_repository *g_repo;
|
||||
|
||||
// Fixture setup and teardown
|
||||
/* Fixture setup and teardown */
|
||||
void test_object_tree_write__initialize(void)
|
||||
{
|
||||
g_repo = cl_git_sandbox_init("testrepo");
|
||||
@ -22,7 +22,7 @@ void test_object_tree_write__cleanup(void)
|
||||
|
||||
void test_object_tree_write__from_memory(void)
|
||||
{
|
||||
// write a tree from a memory
|
||||
/* write a tree from a memory */
|
||||
git_treebuilder *builder;
|
||||
git_tree *tree;
|
||||
git_oid id, bid, rid, id2;
|
||||
@ -31,7 +31,9 @@ void test_object_tree_write__from_memory(void)
|
||||
git_oid_fromstr(&id2, second_tree);
|
||||
git_oid_fromstr(&bid, blob_oid);
|
||||
|
||||
//create a second tree from first tree using `git_treebuilder_insert` on REPOSITORY_FOLDER.
|
||||
/* create a second tree from first tree using `git_treebuilder_insert`
|
||||
* on REPOSITORY_FOLDER.
|
||||
*/
|
||||
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
|
||||
cl_git_pass(git_treebuilder_create(&builder, tree));
|
||||
|
||||
@ -61,7 +63,7 @@ void test_object_tree_write__from_memory(void)
|
||||
|
||||
void test_object_tree_write__subtree(void)
|
||||
{
|
||||
// write a hierarchical tree from a memory
|
||||
/* write a hierarchical tree from a memory */
|
||||
git_treebuilder *builder;
|
||||
git_tree *tree;
|
||||
git_oid id, bid, subtree_id, id2, id3;
|
||||
@ -72,25 +74,25 @@ void test_object_tree_write__subtree(void)
|
||||
git_oid_fromstr(&id3, third_tree);
|
||||
git_oid_fromstr(&bid, blob_oid);
|
||||
|
||||
//create subtree
|
||||
/* create subtree */
|
||||
cl_git_pass(git_treebuilder_create(&builder, NULL));
|
||||
cl_git_pass(git_treebuilder_insert(
|
||||
NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); //-V536
|
||||
NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); /* -V536 */
|
||||
cl_git_pass(git_treebuilder_write(&subtree_id, g_repo, builder));
|
||||
git_treebuilder_free(builder);
|
||||
|
||||
// create parent tree
|
||||
/* create parent tree */
|
||||
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
|
||||
cl_git_pass(git_treebuilder_create(&builder, tree));
|
||||
cl_git_pass(git_treebuilder_insert(
|
||||
NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); //-V536
|
||||
NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); /* -V536 */
|
||||
cl_git_pass(git_treebuilder_write(&id_hiearar, g_repo, builder));
|
||||
git_treebuilder_free(builder);
|
||||
git_tree_free(tree);
|
||||
|
||||
cl_assert(git_oid_cmp(&id_hiearar, &id3) == 0);
|
||||
|
||||
// check data is correct
|
||||
/* check data is correct */
|
||||
cl_git_pass(git_tree_lookup(&tree, g_repo, &id_hiearar));
|
||||
cl_assert(2 == git_tree_entrycount(tree));
|
||||
git_tree_free(tree);
|
||||
@ -314,3 +316,83 @@ void test_object_tree_write__filtering(void)
|
||||
|
||||
git_tree_free(tree);
|
||||
}
|
||||
|
||||
void test_object_tree_write__cruel_paths(void)
|
||||
{
|
||||
static const char *the_paths[] = {
|
||||
"C:\\",
|
||||
" : * ? \" \n < > |",
|
||||
"a\\b",
|
||||
"\\\\b\a",
|
||||
":\\",
|
||||
"COM1",
|
||||
"foo.aux",
|
||||
REP1024("1234"), /* 4096 char string */
|
||||
REP1024("12345678"), /* 8192 char string */
|
||||
"\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD", /* Ūnĭcōde̽ */
|
||||
NULL
|
||||
};
|
||||
git_treebuilder *builder;
|
||||
git_tree *tree;
|
||||
git_oid id, bid, subid;
|
||||
const char **scan;
|
||||
int count = 0, i, j;
|
||||
git_tree_entry *te;
|
||||
|
||||
git_oid_fromstr(&bid, blob_oid);
|
||||
|
||||
/* create tree */
|
||||
cl_git_pass(git_treebuilder_create(&builder, NULL));
|
||||
for (scan = the_paths; *scan; ++scan) {
|
||||
cl_git_pass(git_treebuilder_insert(
|
||||
NULL, builder, *scan, &bid, GIT_FILEMODE_BLOB));
|
||||
count++;
|
||||
}
|
||||
cl_git_pass(git_treebuilder_write(&id, g_repo, builder));
|
||||
git_treebuilder_free(builder);
|
||||
|
||||
/* check data is correct */
|
||||
cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
|
||||
|
||||
cl_assert_equal_i(count, git_tree_entrycount(tree));
|
||||
|
||||
for (scan = the_paths; *scan; ++scan) {
|
||||
const git_tree_entry *cte = git_tree_entry_byname(tree, *scan);
|
||||
cl_assert(cte != NULL);
|
||||
cl_assert_equal_s(*scan, git_tree_entry_name(cte));
|
||||
}
|
||||
for (scan = the_paths; *scan; ++scan) {
|
||||
cl_git_pass(git_tree_entry_bypath(&te, tree, *scan));
|
||||
cl_assert_equal_s(*scan, git_tree_entry_name(te));
|
||||
git_tree_entry_free(te);
|
||||
}
|
||||
|
||||
git_tree_free(tree);
|
||||
|
||||
/* let's try longer paths */
|
||||
cl_git_pass(git_treebuilder_create(&builder, NULL));
|
||||
for (scan = the_paths; *scan; ++scan) {
|
||||
cl_git_pass(git_treebuilder_insert(
|
||||
NULL, builder, *scan, &id, GIT_FILEMODE_TREE));
|
||||
}
|
||||
cl_git_pass(git_treebuilder_write(&subid, g_repo, builder));
|
||||
git_treebuilder_free(builder);
|
||||
|
||||
/* check data is correct */
|
||||
cl_git_pass(git_tree_lookup(&tree, g_repo, &subid));
|
||||
|
||||
cl_assert_equal_i(count, git_tree_entrycount(tree));
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
for (j = 0; j < count; ++j) {
|
||||
git_buf b = GIT_BUF_INIT;
|
||||
cl_git_pass(git_buf_joinpath(&b, the_paths[i], the_paths[j]));
|
||||
cl_git_pass(git_tree_entry_bypath(&te, tree, b.ptr));
|
||||
cl_assert_equal_s(the_paths[j], git_tree_entry_name(te));
|
||||
git_tree_entry_free(te);
|
||||
git_buf_free(&b);
|
||||
}
|
||||
}
|
||||
|
||||
git_tree_free(tree);
|
||||
}
|
||||
|
@ -252,3 +252,41 @@ void test_revwalk_basic__push_range(void)
|
||||
cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e"));
|
||||
cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1));
|
||||
}
|
||||
|
||||
void test_revwalk_basic__push_mixed(void)
|
||||
{
|
||||
git_oid oid;
|
||||
int i = 0;
|
||||
|
||||
revwalk_basic_setup_walk(NULL);
|
||||
|
||||
git_revwalk_reset(_walk);
|
||||
git_revwalk_sorting(_walk, 0);
|
||||
cl_git_pass(git_revwalk_push_glob(_walk, "tags"));
|
||||
|
||||
while (git_revwalk_next(&oid, _walk) == 0) {
|
||||
i++;
|
||||
}
|
||||
|
||||
/* git rev-list --count --glob=tags #=> 9 */
|
||||
cl_assert_equal_i(9, i);
|
||||
}
|
||||
|
||||
void test_revwalk_basic__push_all(void)
|
||||
{
|
||||
git_oid oid;
|
||||
int i = 0;
|
||||
|
||||
revwalk_basic_setup_walk(NULL);
|
||||
|
||||
git_revwalk_reset(_walk);
|
||||
git_revwalk_sorting(_walk, 0);
|
||||
cl_git_pass(git_revwalk_push_glob(_walk, "*"));
|
||||
|
||||
while (git_revwalk_next(&oid, _walk) == 0) {
|
||||
i++;
|
||||
}
|
||||
|
||||
/* git rev-list --count --all #=> 15 */
|
||||
cl_assert_equal_i(15, i);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user