Unverified Commit b55bb43d by Patrick Steinhardt Committed by GitHub

Merge pull request #4475 from pks-t/pks/v0.26.1-backports

v0.26.3 backports
parents dd2d5381 bb00842f
v0.26.3
-------
This is a bugfix release. It includes the following non-exclusive list of
improvements, which have been backported from the master branch:
* Fix cloning of the libgit2 project with `git clone --recursive` by removing an
invalid submodule from our testing data.
* Fix endianness of the port in `p_getaddrinfo()`.
* Fix handling of negative gitignore rules with wildcards.
* Fix handling of case-insensitive negative gitignore rules.
* Fix resolving references to a tag if the reference is stored with its fully
resolved OID in the packed-refs file.
* Fix checkout not treating worktree files as modified when only their mode has
changed.
* Fix rename detection with `GIT_DIFF_FIND_RENAMES_FROM_REWRITES`.
* Enable Windows 7 and earlier to use TLS 1.2.
v0.26.2
-------
......
......@@ -440,6 +440,8 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
#define WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 0x00000008
#define WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 0x00000020
#define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 0x00000080
#define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 0x00000200
#define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 0x00000800
#define WINHTTP_FLAG_SECURE_PROTOCOL_ALL (WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 | WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1)
#define WINHTTP_AUTH_SCHEME_BASIC 0x00000001
......
......@@ -62,5 +62,6 @@
#include "git2/tree.h"
#include "git2/types.h"
#include "git2/version.h"
#include "git2/worktree.h"
#endif
......@@ -11,6 +11,7 @@
#include "git2/types.h"
#include "git2/oid.h"
#include "git2/odb.h"
#include "git2/buffer.h"
/**
* @file git2/sys/mempack.h
......@@ -38,10 +39,10 @@ GIT_BEGIN_DECL
* Subsequent reads will also be served from the in-memory store
* to ensure consistency, until the memory store is dumped.
*
* @param out Poiter where to store the ODB backend
* @param out Pointer where to store the ODB backend
* @return 0 on success; error code otherwise
*/
int git_mempack_new(git_odb_backend **out);
GIT_EXTERN(int) git_mempack_new(git_odb_backend **out);
/**
* Dump all the queued in-memory writes to a packfile.
......@@ -64,7 +65,7 @@ int git_mempack_new(git_odb_backend **out);
* @param backend The mempack backend
* @return 0 on success; error code otherwise
*/
int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend);
GIT_EXTERN(int) git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend);
/**
* Reset the memory packer by clearing all the queued objects.
......@@ -78,7 +79,7 @@ int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backe
*
* @param backend The mempack backend
*/
void git_mempack_reset(git_odb_backend *backend);
GIT_EXTERN(void) git_mempack_reset(git_odb_backend *backend);
GIT_END_DECL
......
......@@ -7,10 +7,10 @@
#ifndef INCLUDE_git_version_h__
#define INCLUDE_git_version_h__
#define LIBGIT2_VERSION "0.26.2"
#define LIBGIT2_VERSION "0.26.3"
#define LIBGIT2_VER_MAJOR 0
#define LIBGIT2_VER_MINOR 26
#define LIBGIT2_VER_REVISION 2
#define LIBGIT2_VER_REVISION 3
#define LIBGIT2_VER_PATCH 0
#define LIBGIT2_SOVERSION 26
......
......@@ -159,6 +159,19 @@ GIT_INLINE(bool) is_workdir_base_or_new(
git_oid__cmp(&newitem->id, workdir_id) == 0);
}
GIT_INLINE(bool) is_file_mode_changed(git_filemode_t a, git_filemode_t b)
{
#ifdef GIT_WIN32
/*
* On Win32 we do not support the executable bit; the file will
* always be 0100644 on disk, don't bother doing a test.
*/
return false;
#else
return (S_ISREG(a) && S_ISREG(b) && a != b);
#endif
}
static bool checkout_is_workdir_modified(
checkout_data *data,
const git_diff_file *baseitem,
......@@ -192,16 +205,23 @@ static bool checkout_is_workdir_modified(
return rval;
}
/* Look at the cache to decide if the workdir is modified. If not,
* we can simply compare the oid in the cache to the baseitem instead
* of hashing the file. If so, we allow the checkout to proceed if the
* oid is identical (ie, the staged item is what we're trying to check
* out.)
/*
* Look at the cache to decide if the workdir is modified: if the
* cache contents match the workdir contents, then we do not need
* to examine the working directory directly, instead we can
* examine the cache to see if _it_ has been modified. This allows
* us to avoid touching the disk.
*/
if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
if (git_index_time_eq(&wditem->mtime, &ie->mtime) &&
wditem->file_size == ie->file_size)
return !is_workdir_base_or_new(&ie->id, baseitem, newitem);
ie = git_index_get_bypath(data->index, wditem->path, 0);
if (ie != NULL &&
git_index_time_eq(&wditem->mtime, &ie->mtime) &&
wditem->file_size == ie->file_size &&
!is_file_mode_changed(wditem->mode, ie->mode)) {
/* The workdir is modified iff the index entry is modified */
return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
is_file_mode_changed(baseitem->mode, ie->mode);
}
/* depending on where base is coming from, we may or may not know
......@@ -214,6 +234,9 @@ static bool checkout_is_workdir_modified(
if (S_ISDIR(wditem->mode))
return false;
if (is_file_mode_changed(baseitem->mode, wditem->mode))
return true;
if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
return false;
......
......@@ -12,6 +12,7 @@
#include "stream.h"
#include "git2/transport.h"
#include "buffer.h"
#include "global.h"
#include "vector.h"
#include "proxy.h"
......@@ -36,6 +37,18 @@ typedef struct {
git_cred *proxy_cred;
} curl_stream;
int git_curl_stream_global_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
giterr_set(GITERR_NET, "could not initialize curl");
return -1;
}
/* `curl_global_cleanup` is provided by libcurl */
git__on_shutdown(curl_global_cleanup);
return 0;
}
static int seterr_curl(curl_stream *s)
{
giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
......@@ -193,6 +206,7 @@ static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_op
CURLcode res;
curl_stream *s = (curl_stream *) stream;
git_proxy_options_clear(&s->proxy);
if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0)
return error;
......@@ -293,6 +307,8 @@ static void curls_free(git_stream *stream)
curls_close(stream);
git_strarray_free(&s->cert_info_strings);
git_proxy_options_clear(&s->proxy);
git_cred_free(s->proxy_cred);
git__free(s);
}
......@@ -348,6 +364,11 @@ int git_curl_stream_new(git_stream **out, const char *host, const char *port)
#include "stream.h"
int git_curl_stream_global_init(void)
{
return 0;
}
int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(out);
......
......@@ -9,6 +9,7 @@
#include "git2/sys/stream.h"
extern int git_curl_stream_global_init(void);
extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
#endif
......@@ -12,13 +12,6 @@
#include "commit.h"
#include "index.h"
#define DIFF_FLAG_IS_SET(DIFF,FLAG) \
(((DIFF)->opts.flags & (FLAG)) != 0)
#define DIFF_FLAG_ISNT_SET(DIFF,FLAG) \
(((DIFF)->opts.flags & (FLAG)) == 0)
#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \
(VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL))
GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta)
{
const char *str = delta->old_file.path;
......
......@@ -138,7 +138,6 @@ int git_diff_file_content__init_from_src(
memset(fc, 0, sizeof(*fc));
fc->repo = repo;
fc->file = as_file;
fc->blob = src->blob;
if (!src->blob && !src->buf) {
fc->flags |= GIT_DIFF_FLAG__NO_DATA;
......@@ -148,12 +147,15 @@ int git_diff_file_content__init_from_src(
fc->file->mode = GIT_FILEMODE_BLOB;
if (src->blob) {
git_blob_dup((git_blob **)&fc->blob, (git_blob *) src->blob);
fc->file->size = git_blob_rawsize(src->blob);
git_oid_cpy(&fc->file->id, git_blob_id(src->blob));
fc->file->id_abbrev = GIT_OID_HEXSZ;
fc->map.len = (size_t)fc->file->size;
fc->map.data = (char *)git_blob_rawcontent(src->blob);
fc->flags |= GIT_DIFF_FLAG__FREE_BLOB;
} else {
fc->file->size = src->buflen;
git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJ_BLOB);
......
......@@ -23,7 +23,7 @@
(((DIFF)->base.opts.flags & (FLAG)) == 0)
#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->base.opts.flags = \
(VAL) ? ((DIFF)->base.opts.flags | (FLAG)) : \
((DIFF)->base.opts.flags & ~(VAL))
((DIFF)->base.opts.flags & ~(FLAG))
typedef struct {
struct git_diff base;
......
......@@ -685,8 +685,10 @@ static bool is_rename_target(
break;
}
if (FLAG_SET(opts, GIT_DIFF_FIND_RENAMES_FROM_REWRITES) &&
delta->similarity < opts->rename_from_rewrite_threshold)
delta->similarity < opts->rename_from_rewrite_threshold) {
delta->flags |= GIT_DIFF_FLAG__TO_SPLIT;
break;
}
return false;
......
......@@ -10,6 +10,7 @@
#include "sysdir.h"
#include "filter.h"
#include "merge_driver.h"
#include "curl_stream.h"
#include "openssl_stream.h"
#include "thread-utils.h"
#include "git2/global.h"
......@@ -22,7 +23,7 @@
git_mutex git__mwindow_mutex;
#define MAX_SHUTDOWN_CB 9
#define MAX_SHUTDOWN_CB 10
static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
static git_atomic git__n_shutdown_callbacks;
......@@ -62,7 +63,8 @@ static int init_common(void)
(ret = git_filter_global_init()) == 0 &&
(ret = git_merge_driver_global_init()) == 0 &&
(ret = git_transport_ssh_global_init()) == 0 &&
(ret = git_openssl_stream_global_init()) == 0)
(ret = git_openssl_stream_global_init()) == 0 &&
(ret = git_curl_stream_global_init()) == 0)
ret = git_mwindow_global_init();
GIT_MEMORY_BARRIER;
......
......@@ -23,21 +23,36 @@ struct git_hash_ctx {
GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
SHA1_Init(&ctx->c);
if (SHA1_Init(&ctx->c) != 1) {
giterr_set(GITERR_SHA1, "hash_openssl: failed to initialize hash context");
return -1;
}
return 0;
}
GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
{
assert(ctx);
SHA1_Update(&ctx->c, data, len);
if (SHA1_Update(&ctx->c, data, len) != 1) {
giterr_set(GITERR_SHA1, "hash_openssl: failed to update hash");
return -1;
}
return 0;
}
GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
SHA1_Final(out->id, &ctx->c);
if (SHA1_Final(out->id, &ctx->c) != 1) {
giterr_set(GITERR_SHA1, "hash_openssl: failed to finalize hash");
return -1;
}
return 0;
}
......
......@@ -40,15 +40,22 @@
*/
static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
{
int (*cmp)(const char *, const char *, size_t);
git_attr_fnmatch *longer, *shorter;
char *p;
if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0
&& (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0) {
if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0
|| (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0)
return false;
if (neg->flags & GIT_ATTR_FNMATCH_ICASE)
cmp = git__strncasecmp;
else
cmp = git__strncmp;
/* If lengths match we need to have an exact match */
if (rule->length == neg->length) {
return strcmp(rule->pattern, neg->pattern) == 0;
return cmp(rule->pattern, neg->pattern, rule->length) == 0;
} else if (rule->length < neg->length) {
shorter = rule;
longer = neg;
......@@ -68,10 +75,7 @@ static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
if (memchr(shorter->pattern, '/', shorter->length) != NULL)
return false;
return memcmp(p, shorter->pattern, shorter->length) == 0;
}
return false;
return cmp(p, shorter->pattern, shorter->length) == 0;
}
/**
......@@ -89,7 +93,7 @@ static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
*/
static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match)
{
int error = 0;
int error = 0, fnflags;
size_t i;
git_attr_fnmatch *rule;
char *path;
......@@ -97,6 +101,10 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
*out = 0;
fnflags = FNM_PATHNAME;
if (match->flags & GIT_ATTR_FNMATCH_ICASE)
fnflags |= FNM_IGNORECASE;
/* path of the file relative to the workdir, so we match the rules in subdirs */
if (match->containing_dir) {
git_buf_puts(&buf, match->containing_dir);
......@@ -136,7 +144,7 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
if (error < 0)
goto out;
if ((error = p_fnmatch(git_buf_cstr(&buf), path, FNM_PATHNAME)) < 0) {
if ((error = p_fnmatch(git_buf_cstr(&buf), path, fnflags)) < 0) {
giterr_set(GITERR_INVALID, "error matching pattern");
goto out;
}
......@@ -197,10 +205,26 @@ static int parse_ignore_file(
if (ignore_case)
match->flags |= GIT_ATTR_FNMATCH_ICASE;
while (match->length > 0) {
if (match->pattern[match->length - 1] == ' ' ||
match->pattern[match->length - 1] == '\t') {
match->pattern[match->length - 1] = 0;
match->length --;
} else {
break;
}
}
scan = git__next_line(scan);
/* if a negative match doesn't actually do anything, throw it away */
if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE)
/*
* If a negative match doesn't actually do anything,
* throw it away. As we cannot always verify whether a
* rule containing wildcards negates another rule, we
* do not optimize away these rules, though.
* */
if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE
&& !(match->flags & GIT_ATTR_FNMATCH_HASWILD))
error = does_negate_rule(&valid_rule, &attrs->rules, match);
if (!error && valid_rule)
......
......@@ -843,6 +843,7 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats)
static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
{
unsigned int i;
int error;
struct delta_info *delta;
int progressed = 0, non_null = 0, progress_cb_result;
......@@ -857,8 +858,13 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
non_null = 1;
idx->off = delta->delta_off;
if (git_packfile_unpack(&obj, idx->pack, &idx->off) < 0)
if ((error = git_packfile_unpack(&obj, idx->pack, &idx->off)) < 0) {
if (error == GIT_PASSTHROUGH) {
/* We have not seen the base object, we'll try again later. */
continue;
}
return -1;
}
if (hash_and_save(idx, &obj, delta->delta_off) < 0)
continue;
......@@ -950,6 +956,10 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack");
return -1;
}
if (idx->off + 20 > idx->pack->mwf.size) {
giterr_set(GITERR_INDEXER, "missing trailer at the end of the pack");
return -1;
}
packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left);
if (packfile_trailer == NULL) {
......@@ -1118,6 +1128,9 @@ void git_indexer_free(git_indexer *idx)
if (idx == NULL)
return;
if (idx->have_stream)
git_packfile_stream_free(&idx->stream);
git_vector_free_deep(&idx->objects);
if (idx->pack->idx_cache) {
......
......@@ -2141,7 +2141,7 @@ static int compute_base(
git_oidarray bases = {0};
git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL;
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
size_t i;
size_t i, base_count;
int error;
*out = NULL;
......@@ -2149,17 +2149,27 @@ static int compute_base(
if (given_opts)
memcpy(&opts, given_opts, sizeof(git_merge_options));
if ((error = insert_head_ids(&head_ids, one)) < 0 ||
(error = insert_head_ids(&head_ids, two)) < 0)
/* With more than two commits, merge_bases_many finds the base of
* the first commit and a hypothetical merge of the others. Since
* "one" may itself be a virtual commit, which insert_head_ids
* substitutes multiple ancestors for, it needs to be added
* after "two" which is always a single real commit.
*/
if ((error = insert_head_ids(&head_ids, two)) < 0 ||
(error = insert_head_ids(&head_ids, one)) < 0 ||
(error = git_merge_bases_many(&bases, repo,
head_ids.size, head_ids.ptr)) < 0)
goto done;
if ((error = git_merge_bases_many(&bases, repo,
head_ids.size, head_ids.ptr)) < 0 ||
(error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0 ||
(opts.flags & GIT_MERGE_NO_RECURSIVE))
base_count = (opts.flags & GIT_MERGE_NO_RECURSIVE) ? 0 : bases.count;
if (base_count)
git_oidarray__reverse(&bases);
if ((error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0)
goto done;
for (i = 1; i < bases.count; i++) {
for (i = 1; i < base_count; i++) {
recursion_level++;
if (opts.recursion_limit && recursion_level > opts.recursion_limit)
......
......@@ -8,6 +8,7 @@
#include "common.h"
#include "git2/object.h"
#include "git2/sys/odb_backend.h"
#include "git2/sys/mempack.h"
#include "fileops.h"
#include "hash.h"
#include "odb.h"
......
......@@ -19,3 +19,15 @@ void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array)
arr->count = array->size;
arr->ids = array->ptr;
}
void git_oidarray__reverse(git_oidarray *arr)
{
size_t i;
git_oid tmp;
for (i = 0; i < arr->count / 2; i++) {
git_oid_cpy(&tmp, &arr->ids[i]);
git_oid_cpy(&arr->ids[i], &arr->ids[(arr->count-1)-i]);
git_oid_cpy(&arr->ids[(arr->count-1)-i], &tmp);
}
}
......@@ -13,6 +13,7 @@
typedef git_array_t(git_oid) git_array_oid_t;
extern void git_oidarray__reverse(git_oidarray *arr);
extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array);
#endif
......@@ -149,11 +149,20 @@ int git_openssl_stream_global_init(void)
return 0;
}
#if defined(GIT_THREADS)
static void threadid_cb(CRYPTO_THREADID *threadid)
{
CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid());
}
#endif
int git_openssl_set_locking(void)
{
#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
int num_locks, i;
CRYPTO_THREADID_set_callback(threadid_cb);
num_locks = CRYPTO_num_locks();
openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
GITERR_CHECK_ALLOC(openssl_locks);
......@@ -272,8 +281,9 @@ static int ssl_set_error(SSL *ssl, int error)
case SSL_ERROR_SYSCALL:
e = ERR_get_error();
if (e > 0) {
giterr_set(GITERR_NET, "SSL error: %s",
ERR_error_string(e, NULL));
char errmsg[256];
ERR_error_string_n(e, errmsg, sizeof(errmsg));
giterr_set(GITERR_NET, "SSL error: %s", errmsg);
break;
} else if (error < 0) {
giterr_set(GITERR_OS, "SSL error: syscall failure");
......@@ -283,10 +293,13 @@ static int ssl_set_error(SSL *ssl, int error)
return GIT_EEOF;
break;
case SSL_ERROR_SSL:
{
char errmsg[256];
e = ERR_get_error();
giterr_set(GITERR_NET, "SSL error: %s",
ERR_error_string(e, NULL));
ERR_error_string_n(e, errmsg, sizeof(errmsg));
giterr_set(GITERR_NET, "SSL error: %s", errmsg);
break;
}
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
default:
......
......@@ -716,8 +716,11 @@ int git_packfile_unpack(
error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, elem->size, elem->type);
git_mwindow_close(&w_curs);
if (error < 0)
if (error < 0) {
/* We have transferred ownership of the data to the cache. */
obj->data = NULL;
break;
}
/* the current object becomes the new base, on which we apply the delta */
base = *obj;
......@@ -934,19 +937,19 @@ git_off_t get_delta_base(
if (type == GIT_OBJ_OFS_DELTA) {
unsigned used = 0;
unsigned char c = base_info[used++];
base_offset = c & 127;
size_t unsigned_base_offset = c & 127;
while (c & 128) {
if (left <= used)
return GIT_EBUFS;
base_offset += 1;
if (!base_offset || MSB(base_offset, 7))
unsigned_base_offset += 1;
if (!unsigned_base_offset || MSB(unsigned_base_offset, 7))
return 0; /* overflow */
c = base_info[used++];
base_offset = (base_offset << 7) + (c & 127);
unsigned_base_offset = (unsigned_base_offset << 7) + (c & 127);
}
base_offset = delta_obj_offset - base_offset;
if (base_offset <= 0 || base_offset >= delta_obj_offset)
if (unsigned_base_offset == 0 || (size_t)delta_obj_offset <= unsigned_base_offset)
return 0; /* out of bound */
base_offset = delta_obj_offset - unsigned_base_offset;
*curpos += used;
} else if (type == GIT_OBJ_REF_DELTA) {
/* If we have the cooperative cache, search in it first */
......
......@@ -40,7 +40,7 @@ int p_getaddrinfo(
if (ainfo->ai_servent)
ainfo->ai_port = ainfo->ai_servent->s_port;
else
ainfo->ai_port = atol(port);
ainfo->ai_port = htons(atol(port));
memcpy(&ainfo->ai_addr_in.sin_addr,
ainfo->ai_hostent->h_addr_list[0],
......
......@@ -59,6 +59,9 @@
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif
/* access() mode parameter #defines */
#ifndef F_OK
......
......@@ -30,3 +30,9 @@ int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src)
return 0;
}
void git_proxy_options_clear(git_proxy_options *opts)
{
git__free((char *) opts->url);
opts->url = NULL;
}
......@@ -10,5 +10,6 @@
#include "git2/proxy.h"
extern int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src);
extern void git_proxy_options_clear(git_proxy_options *opts);
#endif
\ No newline at end of file
......@@ -178,6 +178,9 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks)
if (!fetch_spec)
continue;
/* Clear the buffer which can be dirty from previous iteration */
git_buf_clear(&remote_ref_name);
if ((error = git_refspec_transform(&remote_ref_name, fetch_spec, status->ref)) < 0)
goto on_error;
......
......@@ -1359,7 +1359,13 @@ int git_reference_peel(
return peel_error(error, ref, "Cannot resolve reference");
}
if (!git_oid_iszero(&resolved->peel)) {
/*
* If we try to peel an object to a tag, we cannot use
* the fully peeled object, as that will always resolve
* to a commit. So we only want to use the peeled value
* if it is not zero and the target is not a tag.
*/
if (target_type != GIT_OBJ_TAG && !git_oid_iszero(&resolved->peel)) {
error = git_object_lookup(&target,
git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY);
} else {
......
......@@ -1784,7 +1784,13 @@ static int repo_init_structure(
default_template = true;
}
if (tdir) {
/*
* If tdir was the empty string, treat it like tdir was a path to an
* empty directory (so, don't do any copying). This is the behavior
* that git(1) exhibits, although it doesn't seem to be officially
* documented.
*/
if (tdir && git__strcmp(tdir, "") != 0) {
uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS |
GIT_CPDIR_SIMPLE_TO_MODE |
GIT_CPDIR_COPY_DOTFILES;
......
......@@ -232,7 +232,7 @@ int sha1_position(const void *table,
{
const unsigned char *base = table;
do {
while (lo < hi) {
unsigned mi = (lo + hi) / 2;
int cmp = git_oid__hashcmp(base + mi * stride, key);
......@@ -243,7 +243,7 @@ int sha1_position(const void *table,
hi = mi;
else
lo = mi+1;
} while (lo < hi);
}
return -((int)lo)-1;
}
......@@ -231,6 +231,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) {
git__free(sig->name);
git__free(sig->email);
sig->name = sig->email = NULL;
return signature_error("invalid Unix timestamp");
}
......
......@@ -104,7 +104,7 @@ int socket_connect(git_stream *stream)
}
for (p = info; p != NULL; p = p->ai_next) {
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
s = socket(p->ai_family, p->ai_socktype | SOCK_CLOEXEC, p->ai_protocol);
if (s == INVALID_SOCKET)
continue;
......
......@@ -81,8 +81,10 @@ static int stransport_connect(git_stream *stream)
}
if (sec_res == kSecTrustResultDeny || sec_res == kSecTrustResultRecoverableTrustFailure ||
sec_res == kSecTrustResultFatalTrustFailure)
sec_res == kSecTrustResultFatalTrustFailure) {
giterr_set(GITERR_SSL, "untrusted connection error");
return GIT_ECERTIFICATE;
}
return 0;
......
......@@ -270,7 +270,7 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
git_revwalk *walk = NULL;
git_strarray refs;
unsigned int i;
git_reference *ref;
git_reference *ref = NULL;
int error;
if ((error = git_reference_list(&refs, repo)) < 0)
......@@ -282,6 +282,9 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
git_revwalk_sorting(walk, GIT_SORT_TIME);
for (i = 0; i < refs.count; ++i) {
git_reference_free(ref);
ref = NULL;
/* No tags */
if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))
continue;
......@@ -294,15 +297,12 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
if ((error = git_revwalk_push(walk, git_reference_target(ref))) < 0)
goto on_error;
git_reference_free(ref);
}
git_strarray_free(&refs);
*out = walk;
return 0;
on_error:
if (error)
git_revwalk_free(walk);
git_reference_free(ref);
git_strarray_free(&refs);
......
......@@ -37,6 +37,14 @@
#define WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH 0
#endif
#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS_1_1
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 0x00000200
#endif
#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS_1_2
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 0x00000800
#endif
static const char *prefix_https = "https://";
static const char *upload_pack_service = "upload-pack";
static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
......@@ -747,6 +755,10 @@ static int winhttp_connect(
int error = -1;
int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
DWORD protocols =
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
t->session = NULL;
t->connection = NULL;
......@@ -788,6 +800,16 @@ static int winhttp_connect(
goto on_error;
}
/*
* Do a best-effort attempt to enable TLS 1.2 but allow this to
* fail; if TLS 1.2 support is not available for some reason,
* ignore the failure (it will keep the default protocols).
*/
WinHttpSetOption(t->session,
WINHTTP_OPTION_SECURE_PROTOCOLS,
&protocols,
sizeof(protocols));
if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
goto on_error;
......
......@@ -51,6 +51,16 @@ void test_attr_ignore__allow_root(void)
assert_is_ignored(false, "NewFolder/NewFolder/File.txt");
}
void test_attr_ignore__ignore_space(void)
{
cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder \n/NewFolder/NewFolder");
assert_is_ignored(false, "File.txt");
assert_is_ignored(true, "NewFolder");
assert_is_ignored(true, "NewFolder/NewFolder");
assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
}
void test_attr_ignore__ignore_root(void)
{
cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder");
......@@ -303,3 +313,46 @@ void test_attr_ignore__test(void)
assert_is_ignored(true, "dist/foo.o");
assert_is_ignored(true, "bin/foo");
}
void test_attr_ignore__unignore_dir_succeeds(void)
{
cl_git_rewritefile("attr/.gitignore",
"*.c\n"
"!src/*.c\n");
assert_is_ignored(false, "src/foo.c");
assert_is_ignored(true, "src/foo/foo.c");
}
void test_attr_ignore__case_insensitive_unignores_previous_rule(void)
{
git_config *cfg;
cl_git_rewritefile("attr/.gitignore",
"/case\n"
"!/Case/\n");
cl_git_pass(git_repository_config(&cfg, g_repo));
cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", true));
cl_must_pass(p_mkdir("attr/case", 0755));
cl_git_mkfile("attr/case/file", "content");
assert_is_ignored(false, "case/file");
}
void test_attr_ignore__case_sensitive_unignore_does_nothing(void)
{
git_config *cfg;
cl_git_rewritefile("attr/.gitignore",
"/case\n"
"!/Case/\n");
cl_git_pass(git_repository_config(&cfg, g_repo));
cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", false));
cl_must_pass(p_mkdir("attr/case", 0755));
cl_git_mkfile("attr/case/file", "content");
assert_is_ignored(true, "case/file");
}
......@@ -136,3 +136,48 @@ void test_checkout_head__do_remove_tracked_subdir(void)
cl_assert(!git_path_isfile("testrepo/subdir/tracked-file"));
cl_assert(git_path_isfile("testrepo/subdir/untracked-file"));
}
void test_checkout_head__typechange_workdir(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_object *target;
struct stat st;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
cl_must_pass(p_chmod("testrepo/new.txt", 0755));
cl_git_pass(git_checkout_head(g_repo, &opts));
cl_git_pass(p_stat("testrepo/new.txt", &st));
cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
git_object_free(target);
}
void test_checkout_head__typechange_index_and_workdir(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_object *target;
git_index *index;
struct stat st;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
cl_must_pass(p_chmod("testrepo/new.txt", 0755));
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_add_bypath(index, "new.txt"));
cl_git_pass(git_index_write(index));
cl_git_pass(git_checkout_head(g_repo, &opts));
cl_git_pass(p_stat("testrepo/new.txt", &st));
cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
git_object_free(target);
git_index_free(index);
}
......@@ -1514,6 +1514,51 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void)
git_reference_free(head);
}
void test_checkout_tree__mode_change_is_force_updated(void)
{
git_index *index;
git_reference *head;
git_object *obj;
git_status_list *status;
if (!cl_is_chmod_supported())
clar__skip();
assert_on_branch(g_repo, "master");
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_repository_head(&head, g_repo));
cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT));
cl_git_pass(git_reset(g_repo, obj, GIT_RESET_HARD, NULL));
cl_git_pass(git_status_list_new(&status, g_repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status));
git_status_list_free(status);
/* update the mode on-disk */
cl_must_pass(p_chmod("testrepo/README", 0755));
cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts));
cl_git_pass(git_status_list_new(&status, g_repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status));
git_status_list_free(status);
/* update the mode on-disk and in the index */
cl_must_pass(p_chmod("testrepo/README", 0755));
cl_must_pass(git_index_add_bypath(index, "README"));
cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts));
cl_git_pass(git_status_list_new(&status, g_repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status));
git_status_list_free(status);
git_object_free(obj);
git_reference_free(head);
git_index_free(index);
}
void test_checkout_tree__nullopts(void)
{
cl_git_pass(git_checkout_tree(g_repo, NULL, NULL));
......
#include "clar_libgit2.h"
#include "diff_helpers.h"
#define BLOB_DIFF \
"diff --git a/file b/file\n" \
"index 45141a7..4d713dc 100644\n" \
"--- a/file\n" \
"+++ b/file\n" \
"@@ -1 +1,6 @@\n" \
" Hello from the root\n" \
"+\n" \
"+Some additional lines\n" \
"+\n" \
"+Down here below\n" \
"+\n"
static git_repository *g_repo = NULL;
static diff_expects expected;
static git_diff_options opts;
......@@ -65,6 +78,32 @@ static void assert_one_modified(
cl_assert_equal_i(dels, exp->line_dels);
}
void test_diff_blob__patch_with_freed_blobs(void)
{
git_oid a_oid, b_oid;
git_blob *a, *b;
git_patch *p;
git_buf buf = GIT_BUF_INIT;
/* tests/resources/attr/root_test1 */
cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
/* tests/resources/attr/root_test2 */
cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));
cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, NULL));
git_blob_free(a);
git_blob_free(b);
cl_git_pass(git_patch_to_buf(&buf, p));
cl_assert_equal_s(buf.ptr, BLOB_DIFF);
git_patch_free(p);
git_buf_free(&buf);
}
void test_diff_blob__can_compare_text_blobs(void)
{
git_blob *a, *b, *c;
......
......@@ -16,6 +16,13 @@ void test_diff_rename__cleanup(void)
cl_git_sandbox_cleanup();
}
#define INITIAL_COMMIT "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2"
#define COPY_RENAME_COMMIT "2bc7f351d20b53f1c72c16c4b036e491c478c49a"
#define REWRITE_COPY_COMMIT "1c068dee5790ef1580cfc4cd670915b48d790084"
#define RENAME_MODIFICATION_COMMIT "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13"
#define REWRITE_DELETE_COMMIT "84d8efa38af7ace2b302de0adbda16b1f1cd2e1b"
#define DELETE_RENAME_COMMIT "be053a189b0bbde545e0a3f59ce00b46ad29ce0d"
/*
* Renames repo has:
*
......@@ -36,12 +43,22 @@ void test_diff_rename__cleanup(void)
* ikeepsix.txt -> ikeepsix.txt (reorder sections in file)
* sixserving.txt -> sixserving.txt (whitespace change - not just indent)
* sevencities.txt -> songof7cities.txt (rename, small text changes)
* commit 84d8efa38af7ace2b302de0adbda16b1f1cd2e1b
* songof7cities.txt -> songof7citie.txt (major rewrite, <20% match)
* ikeepsix.txt -> (deleted)
* untimely.txt (no change)
* sixserving.txt (no change)
* commit be053a189b0bbde545e0a3f59ce00b46ad29ce0d
* ikeepsix.txt -> (deleted)
* songof7cities.txt -> ikeepsix.txt (rename, 100% match)
* untimely.txt (no change)
* sixserving.txt (no change)
*/
void test_diff_rename__match_oid(void)
{
const char *old_sha = "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2";
const char *new_sha = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *old_sha = INITIAL_COMMIT;
const char *new_sha = COPY_RENAME_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
......@@ -139,8 +156,8 @@ void test_diff_rename__match_oid(void)
void test_diff_rename__checks_options_version(void)
{
const char *old_sha = "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2";
const char *new_sha = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *old_sha = INITIAL_COMMIT;
const char *new_sha = COPY_RENAME_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
......@@ -171,9 +188,9 @@ void test_diff_rename__checks_options_version(void)
void test_diff_rename__not_exact_match(void)
{
const char *sha0 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *sha1 = "1c068dee5790ef1580cfc4cd670915b48d790084";
const char *sha2 = "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13";
const char *sha0 = COPY_RENAME_COMMIT;
const char *sha1 = REWRITE_COPY_COMMIT;
const char *sha2 = RENAME_MODIFICATION_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
......@@ -433,7 +450,7 @@ void test_diff_rename__test_small_files(void)
void test_diff_rename__working_directory_changes(void)
{
const char *sha0 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *sha0 = COPY_RENAME_COMMIT;
const char *blobsha = "66311f5cfbe7836c27510a3ba2f43e282e2c8bba";
git_oid id;
git_tree *tree;
......@@ -592,8 +609,8 @@ void test_diff_rename__working_directory_changes(void)
void test_diff_rename__patch(void)
{
const char *sha0 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *sha1 = "1c068dee5790ef1580cfc4cd670915b48d790084";
const char *sha0 = COPY_RENAME_COMMIT;
const char *sha1 = REWRITE_COPY_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
......@@ -1425,9 +1442,9 @@ void test_diff_rename__can_delete_unmodified_deltas(void)
void test_diff_rename__matches_config_behavior(void)
{
const char *sha0 = "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2";
const char *sha1 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *sha2 = "1c068dee5790ef1580cfc4cd670915b48d790084";
const char *sha0 = INITIAL_COMMIT;
const char *sha1 = COPY_RENAME_COMMIT;
const char *sha2 = REWRITE_COPY_COMMIT;
git_tree *tree0, *tree1, *tree2;
git_config *cfg;
......@@ -1508,8 +1525,8 @@ void test_diff_rename__matches_config_behavior(void)
void test_diff_rename__can_override_thresholds_when_obeying_config(void)
{
const char *sha1 = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *sha2 = "1c068dee5790ef1580cfc4cd670915b48d790084";
const char *sha1 = COPY_RENAME_COMMIT;
const char *sha2 = REWRITE_COPY_COMMIT;
git_tree *tree1, *tree2;
git_config *cfg;
......@@ -1563,8 +1580,8 @@ void test_diff_rename__can_override_thresholds_when_obeying_config(void)
void test_diff_rename__by_config_doesnt_mess_with_whitespace_settings(void)
{
const char *sha1 = "1c068dee5790ef1580cfc4cd670915b48d790084";
const char *sha2 = "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13";
const char *sha1 = REWRITE_COPY_COMMIT;
const char *sha2 = RENAME_MODIFICATION_COMMIT;
git_tree *tree1, *tree2;
git_config *cfg;
......@@ -1710,8 +1727,8 @@ void test_diff_rename__blank_files_not_renamed_when_not_ignoring_whitespace(void
*/
void test_diff_rename__identical(void)
{
const char *old_sha = "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2";
const char *new_sha = "2bc7f351d20b53f1c72c16c4b036e491c478c49a";
const char *old_sha = INITIAL_COMMIT;
const char *new_sha = COPY_RENAME_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
......@@ -1748,3 +1765,216 @@ void test_diff_rename__identical(void)
git_tree_free(new_tree);
}
void test_diff_rename__rewrite_and_delete(void)
{
const char *old_sha = RENAME_MODIFICATION_COMMIT;
const char *new_sha = REWRITE_DELETE_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_find_options find_opts = GIT_DIFF_FIND_OPTIONS_INIT;
git_buf diff_buf = GIT_BUF_INIT;
const char *expected =
"diff --git a/ikeepsix.txt b/ikeepsix.txt\n"
"deleted file mode 100644\n"
"index eaf4a3e..0000000\n"
"--- a/ikeepsix.txt\n"
"+++ /dev/null\n"
"@@ -1,27 +0,0 @@\n"
"-I Keep Six Honest Serving-Men\n"
"-=============================\n"
"-\n"
"-She sends'em abroad on her own affairs,\n"
"- From the second she opens her eyes—\n"
"-One million Hows, two million Wheres,\n"
"-And seven million Whys!\n"
"-\n"
"-I let them rest from nine till five,\n"
"- For I am busy then,\n"
"-As well as breakfast, lunch, and tea,\n"
"- For they are hungry men.\n"
"-But different folk have different views;\n"
"-I know a person small—\n"
"-She keeps ten million serving-men,\n"
"-Who get no rest at all!\n"
"-\n"
"- -- Rudyard Kipling\n"
"-\n"
"-I KEEP six honest serving-men\n"
"- (They taught me all I knew);\n"
"-Their names are What and Why and When\n"
"- And How and Where and Who.\n"
"-I send them over land and sea,\n"
"- I send them east and west;\n"
"-But after they have worked for me,\n"
"- I give them all a rest.\n"
"diff --git a/songof7cities.txt b/songof7cities.txt\n"
"index 4210ffd..95ceb12 100644\n"
"--- a/songof7cities.txt\n"
"+++ b/songof7cities.txt\n"
"@@ -1,45 +1,45 @@\n"
"-The Song of Seven Cities\n"
"+THE SONG OF SEVEN CITIES\n"
" ------------------------\n"
" \n"
"-I WAS Lord of Cities very sumptuously builded.\n"
"-Seven roaring Cities paid me tribute from afar.\n"
"-Ivory their outposts were--the guardrooms of them gilded,\n"
"-And garrisoned with Amazons invincible in war.\n"
"-\n"
"-All the world went softly when it walked before my Cities--\n"
"-Neither King nor Army vexed my peoples at their toil,\n"
"-Never horse nor chariot irked or overbore my Cities,\n"
"-Never Mob nor Ruler questioned whence they drew their spoil.\n"
"-\n"
"-Banded, mailed and arrogant from sunrise unto sunset;\n"
"-Singing while they sacked it, they possessed the land at large.\n"
"-Yet when men would rob them, they resisted, they made onset\n"
"-And pierced the smoke of battle with a thousand-sabred charge.\n"
"-\n"
"-So they warred and trafficked only yesterday, my Cities.\n"
"-To-day there is no mark or mound of where my Cities stood.\n"
"-For the River rose at midnight and it washed away my Cities.\n"
"-They are evened with Atlantis and the towns before the Flood.\n"
"-\n"
"-Rain on rain-gorged channels raised the water-levels round them,\n"
"-Freshet backed on freshet swelled and swept their world from sight,\n"
"-Till the emboldened floods linked arms and, flashing forward, drowned them--\n"
"-Drowned my Seven Cities and their peoples in one night!\n"
"-\n"
"-Low among the alders lie their derelict foundations,\n"
"-The beams wherein they trusted and the plinths whereon they built--\n"
"-My rulers and their treasure and their unborn populations,\n"
"-Dead, destroyed, aborted, and defiled with mud and silt!\n"
"-\n"
"-The Daughters of the Palace whom they cherished in my Cities,\n"
"-My silver-tongued Princesses, and the promise of their May--\n"
"-Their bridegrooms of the June-tide--all have perished in my Cities,\n"
"-With the harsh envenomed virgins that can neither love nor play.\n"
"-\n"
"-I was Lord of Cities--I will build anew my Cities,\n"
"-Seven, set on rocks, above the wrath of any flood.\n"
"-Nor will I rest from search till I have filled anew my Cities\n"
"-With peoples undefeated of the dark, enduring blood.\n"
"+I WAS LORD OF CITIES VERY SUMPTUOUSLY BUILDED.\n"
"+SEVEN ROARING CITIES PAID ME TRIBUTE FROM AFAR.\n"
"+IVORY THEIR OUTPOSTS WERE--THE GUARDROOMS OF THEM GILDED,\n"
"+AND GARRISONED WITH AMAZONS INVINCIBLE IN WAR.\n"
"+\n"
"+ALL THE WORLD WENT SOFTLY WHEN IT WALKED BEFORE MY CITIES--\n"
"+NEITHER KING NOR ARMY VEXED MY PEOPLES AT THEIR TOIL,\n"
"+NEVER HORSE NOR CHARIOT IRKED OR OVERBORE MY CITIES,\n"
"+NEVER MOB NOR RULER QUESTIONED WHENCE THEY DREW THEIR SPOIL.\n"
"+\n"
"+BANDED, MAILED AND ARROGANT FROM SUNRISE UNTO SUNSET;\n"
"+SINGING WHILE THEY SACKED IT, THEY POSSESSED THE LAND AT LARGE.\n"
"+YET WHEN MEN WOULD ROB THEM, THEY RESISTED, THEY MADE ONSET\n"
"+AND PIERCED THE SMOKE OF BATTLE WITH A THOUSAND-SABRED CHARGE.\n"
"+\n"
"+SO THEY WARRED AND TRAFFICKED ONLY YESTERDAY, MY CITIES.\n"
"+TO-DAY THERE IS NO MARK OR MOUND OF WHERE MY CITIES STOOD.\n"
"+FOR THE RIVER ROSE AT MIDNIGHT AND IT WASHED AWAY MY CITIES.\n"
"+THEY ARE EVENED WITH ATLANTIS AND THE TOWNS BEFORE THE FLOOD.\n"
"+\n"
"+RAIN ON RAIN-GORGED CHANNELS RAISED THE WATER-LEVELS ROUND THEM,\n"
"+FRESHET BACKED ON FRESHET SWELLED AND SWEPT THEIR WORLD FROM SIGHT,\n"
"+TILL THE EMBOLDENED FLOODS LINKED ARMS AND, FLASHING FORWARD, DROWNED THEM--\n"
"+DROWNED MY SEVEN CITIES AND THEIR PEOPLES IN ONE NIGHT!\n"
"+\n"
"+LOW AMONG THE ALDERS LIE THEIR DERELICT FOUNDATIONS,\n"
"+THE BEAMS WHEREIN THEY TRUSTED AND THE PLINTHS WHEREON THEY BUILT--\n"
"+MY RULERS AND THEIR TREASURE AND THEIR UNBORN POPULATIONS,\n"
"+DEAD, DESTROYED, ABORTED, AND DEFILED WITH MUD AND SILT!\n"
"+\n"
"+THE DAUGHTERS OF THE PALACE WHOM THEY CHERISHED IN MY CITIES,\n"
"+MY SILVER-TONGUED PRINCESSES, AND THE PROMISE OF THEIR MAY--\n"
"+THEIR BRIDEGROOMS OF THE JUNE-TIDE--ALL HAVE PERISHED IN MY CITIES,\n"
"+WITH THE HARSH ENVENOMED VIRGINS THAT CAN NEITHER LOVE NOR PLAY.\n"
"+\n"
"+I WAS LORD OF CITIES--I WILL BUILD ANEW MY CITIES,\n"
"+SEVEN, SET ON ROCKS, ABOVE THE WRATH OF ANY FLOOD.\n"
"+NOR WILL I REST FROM SEARCH TILL I HAVE FILLED ANEW MY CITIES\n"
"+WITH PEOPLES UNDEFEATED OF THE DARK, ENDURING BLOOD.\n"
" \n"
" To the sound of trumpets shall their seed restore my Cities\n"
" Wealthy and well-weaponed, that once more may I behold\n";
old_tree = resolve_commit_oid_to_tree(g_repo, old_sha);
new_tree = resolve_commit_oid_to_tree(g_repo, new_sha);
find_opts.flags = GIT_DIFF_FIND_RENAMES_FROM_REWRITES;
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, old_tree, new_tree, NULL));
cl_git_pass(git_diff_find_similar(diff, &find_opts));
cl_git_pass(git_diff_to_buf(&diff_buf, diff, GIT_DIFF_FORMAT_PATCH));
cl_assert_equal_s(expected, diff_buf.ptr);
git_buf_free(&diff_buf);
git_diff_free(diff);
git_tree_free(old_tree);
git_tree_free(new_tree);
}
void test_diff_rename__delete_and_rename(void)
{
const char *old_sha = RENAME_MODIFICATION_COMMIT;
const char *new_sha = DELETE_RENAME_COMMIT;
git_tree *old_tree, *new_tree;
git_diff *diff;
git_diff_find_options find_opts = GIT_DIFF_FIND_OPTIONS_INIT;
git_buf diff_buf = GIT_BUF_INIT;
const char *expected =
"diff --git a/sixserving.txt b/sixserving.txt\n"
"deleted file mode 100644\n"
"index f90d4fc..0000000\n"
"--- a/sixserving.txt\n"
"+++ /dev/null\n"
"@@ -1,25 +0,0 @@\n"
"-I KEEP six honest serving-men\n"
"- (They taught me all I knew);\n"
"-Their names are What and Why and When\n"
"- And How and Where and Who.\n"
"-I send them over land and sea,\n"
"- I send them east and west;\n"
"-But after they have worked for me,\n"
"- I give them all a rest.\n"
"-\n"
"-I let them rest from nine till five,\n"
"- For I am busy then,\n"
"-As well as breakfast, lunch, and tea,\n"
"- For they are hungry men.\n"
"-But different folk have different views;\n"
"-I know a person small—\n"
"-She keeps ten million serving-men,\n"
"-Who get no rest at all!\n"
"-\n"
"-She sends'em abroad on her own affairs,\n"
"- From the second she opens her eyes—\n"
"-One million Hows, two million Wheres,\n"
"-And seven million Whys!\n"
"-\n"
"- -- Rudyard Kipling\n"
"-\n"
"diff --git a/songof7cities.txt b/sixserving.txt\n"
"similarity index 100%\n"
"rename from songof7cities.txt\n"
"rename to sixserving.txt\n";
old_tree = resolve_commit_oid_to_tree(g_repo, old_sha);
new_tree = resolve_commit_oid_to_tree(g_repo, new_sha);
find_opts.flags = GIT_DIFF_FIND_RENAMES_FROM_REWRITES;
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, old_tree, new_tree, NULL));
cl_git_pass(git_diff_find_similar(diff, &find_opts));
cl_git_pass(git_diff_to_buf(&diff_buf, diff, GIT_DIFF_FORMAT_PATCH));
cl_assert_equal_s(expected, diff_buf.ptr);
git_buf_free(&diff_buf);
git_diff_free(diff);
git_tree_free(old_tree);
git_tree_free(new_tree);
}
......@@ -70,22 +70,22 @@
"This is a mighty fine recipe!\n" \
">>>>>>> branchF-2\n"
#define CONFLICTING_RECURSIVE_H1_TO_H2_WITH_DIFF3 \
#define CONFLICTING_RECURSIVE_H2_TO_H1_WITH_DIFF3 \
"VEAL SOUP.\n" \
"\n" \
"<<<<<<< HEAD\n" \
"put into a pot three quarts of water, three onions cut small, one\n" \
"Put Into A Pot Three Quarts of Water, Three Onions Cut Small, One\n" \
"||||||| merged common ancestors\n" \
"<<<<<<< Temporary merge branch 1\n" \
"Put into a pot three quarts of water, THREE ONIONS CUT SMALL, one\n" \
"PUT INTO A POT three quarts of water, three onions cut small, one\n" \
"||||||| merged common ancestors\n" \
"Put into a pot three quarts of water, three onions cut small, one\n" \
"=======\n" \
"PUT INTO A POT three quarts of water, three onions cut small, one\n" \
"Put into a pot three quarts of water, THREE ONIONS CUT SMALL, one\n" \
">>>>>>> Temporary merge branch 2\n" \
"=======\n" \
"Put Into A Pot Three Quarts of Water, Three Onions Cut Small, One\n" \
">>>>>>> branchH-2\n" \
"put into a pot three quarts of water, three onions cut small, one\n" \
">>>>>>> branchH-1\n" \
"spoonful of black pepper pounded, and two of salt, with two or three\n" \
"slices of lean ham; let it boil steadily two hours; skim it\n" \
"occasionally, then put into it a shin of veal, let it boil two hours\n" \
......
......@@ -312,7 +312,7 @@ void test_merge_trees_recursive__conflicting_merge_base(void)
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "3a66812fed1e03ea4a6a7ee28d8a57aec1ca6537", 1, "veal.txt" },
{ 0100644, "a13c307108cd1ac9d10a23bd2e8072c298570592", 1, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" },
};
......@@ -339,14 +339,14 @@ void test_merge_trees_recursive__conflicting_merge_base_with_diff3(void)
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "cd17a91513f3aee9e44114d1ede67932dd41d2fc", 1, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" },
{ 0100644, "43b17b0ba58cbf2ffd3a048c1d4c7bbbcb0b987e", 1, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 2, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 3, "veal.txt" },
};
opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3;
cl_git_pass(merge_commits_from_branches(&index, repo, "branchH-1", "branchH-2", &opts));
cl_git_pass(merge_commits_from_branches(&index, repo, "branchH-2", "branchH-1", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 8));
......@@ -392,19 +392,67 @@ void test_merge_trees_recursive__recursionlimit(void)
{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "ce7e553c6feb6e5f3bd67e3c3be04182fe3094b4", 1, "gravy.txt" },
{ 0100644, "d8dd349b78f19a4ebe3357bacb8138f00bf5ed41", 2, "gravy.txt" },
{ 0100644, "e50fbbd701458757bdfe9815f58ed717c588d1b5", 3, "gravy.txt" },
{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
{ 0100644, "59bdc2a0bfc74c6d4f911e04bab6aa081efe40d1", 1, "veal.txt" },
{ 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 2, "veal.txt" },
{ 0100644, "68a2e1ee61a23a4728fe6b35580fbbbf729df370", 3, "veal.txt" },
};
opts.recursion_limit = 1;
cl_git_pass(merge_commits_from_branches(&index, repo, "branchE-1", "branchE-2", &opts));
cl_git_pass(merge_commits_from_branches(&index, repo, "branchC-1", "branchC-2", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 8));
git_index_free(index);
}
/* There are multiple levels of criss-cross merges. This ensures
* that the virtual merge base parents are compared in the same
* order as git. If the base parents are created in the order as
* git does, then the file `targetfile.txt` is automerged. If not,
* `targetfile.txt` will be in conflict due to the virtual merge
* base.
*/
void test_merge_trees_recursive__merge_base_for_virtual_commit(void)
{
git_index *index;
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
struct merge_index_entry merge_index_entries[] = {
{ 0100644, "1bde1883de4977ea3e664b315da951d1f614c3b1", 0, "targetfile.txt" },
{ 0100644, "f66647f02d6779e119bd435fe2908867c64c265f", 1, "version.txt" },
{ 0100644, "358efd6f589384fa8baf92234db9c7899a53916e", 2, "version.txt" },
{ 0100644, "a664873b1c0b9a1ed300f8644dde536fdaa3a34f", 3, "version.txt" },
};
cl_git_pass(merge_commits_from_branches(&index, repo, "branchJ-1", "branchJ-2", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 4));
git_index_free(index);
}
/* This test is the same as above, but the graph is constructed such
* that the 1st-recursion merge bases of the two heads are
* in a different order.
*/
void test_merge_trees_recursive__merge_base_for_virtual_commit_2(void)
{
git_index *index;
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
struct merge_index_entry merge_index_entries[] = {
{ 0100644, "4a06b258fed8a4d15967ec4253ae7366b70f727d", 0, "targetfile.txt" },
{ 0100644, "16c5a7810777e1181709833cfe6931949259f802", 1, "version.txt" },
{ 0100644, "f0856993e005c0d8ed2dc7cdc222cc1d89fb3c77", 2, "version.txt" },
{ 0100644, "2cba583804a4a6fad1baf97c959be447238d1489", 3, "version.txt" },
};
cl_git_pass(merge_commits_from_branches(&index, repo, "branchK-1", "branchK-2", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 4));
git_index_free(index);
}
......@@ -62,22 +62,22 @@ void test_merge_workdir_recursive__conflicting_merge_base_with_diff3(void)
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "cd17a91513f3aee9e44114d1ede67932dd41d2fc", 1, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" },
{ 0100644, "43b17b0ba58cbf2ffd3a048c1d4c7bbbcb0b987e", 1, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 2, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 3, "veal.txt" },
};
opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3;
checkout_opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR "branchH-1", GIT_REFS_HEADS_DIR "branchH-2", &opts, &checkout_opts));
cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR "branchH-2", GIT_REFS_HEADS_DIR "branchH-1", &opts, &checkout_opts));
cl_git_pass(git_repository_index(&index, repo));
cl_assert(merge_test_index(index, merge_index_entries, 8));
cl_git_pass(git_futils_readbuffer(&conflicting_buf, "merge-recursive/veal.txt"));
cl_assert_equal_s(CONFLICTING_RECURSIVE_H1_TO_H2_WITH_DIFF3, conflicting_buf.ptr);
cl_assert_equal_s(CONFLICTING_RECURSIVE_H2_TO_H1_WITH_DIFF3, conflicting_buf.ptr);
git_index_free(index);
git_buf_free(&conflicting_buf);
......
......@@ -495,6 +495,7 @@ static void test_inserting_submodule(void)
git_treebuilder *bld;
git_oid sm_id;
cl_git_pass(git_oid_fromstr(&sm_id, "da39a3ee5e6b4b0d3255bfef95601890afd80709"));
cl_git_pass(git_treebuilder_new(&bld, g_repo, NULL));
cl_git_pass(git_treebuilder_insert(NULL, bld, "sm", &sm_id, GIT_FILEMODE_COMMIT));
git_treebuilder_free(bld);
......
......@@ -40,6 +40,40 @@ static const unsigned char thin_pack[] = {
};
static const unsigned int thin_pack_len = 78;
/*
* Packfile with one object. It references an object which is not in the
* packfile and has a corrupt length (states the deltified stream is 1 byte
* long, where it is actually 6).
*/
static const unsigned char corrupt_thin_pack[] = {
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x71, 0xe6, 0x8f, 0xe8, 0x12, 0x9b, 0x54, 0x6b, 0x10, 0x1a, 0xee, 0x95,
0x10, 0xc5, 0x32, 0x8e, 0x7f, 0x21, 0xca, 0x1d, 0x18, 0x78, 0x9c, 0x63,
0x62, 0x66, 0x4e, 0xcb, 0xcf, 0x07, 0x00, 0x02, 0xac, 0x01, 0x4d, 0x07,
0x67, 0x03, 0xc5, 0x40, 0x99, 0x49, 0xb1, 0x3b, 0x7d, 0xae, 0x9b, 0x0e,
0xdd, 0xde, 0xc6, 0x76, 0x43, 0x24, 0x64
};
static const unsigned int corrupt_thin_pack_len = 67;
/*
* Packfile with a missing trailer.
*/
static const unsigned char missing_trailer_pack[] = {
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x50, 0xf4, 0x3b,
};
static const unsigned int missing_trailer_pack_len = 12;
/*
* Packfile that causes the packfile stream to open in a way in which it leaks
* the stream reader.
*/
static const unsigned char leaky_pack[] = {
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,
0xf4, 0xbd, 0x51, 0x51, 0x51, 0x51, 0x51, 0x72, 0x65, 0x41, 0x4b, 0x63,
0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0xbd, 0x41, 0x4b
};
static const unsigned int leaky_pack_len = 33;
static const unsigned char base_obj[] = { 07, 076 };
static const unsigned int base_obj_len = 2;
......@@ -60,6 +94,38 @@ void test_pack_indexer__out_of_order(void)
git_indexer_free(idx);
}
void test_pack_indexer__missing_trailer(void)
{
git_indexer *idx = 0;
git_transfer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL));
cl_git_pass(git_indexer_append(
idx, missing_trailer_pack, missing_trailer_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
cl_assert(giterr_last() != NULL);
cl_assert_equal_i(giterr_last()->klass, GITERR_INDEXER);
git_indexer_free(idx);
}
void test_pack_indexer__leaky(void)
{
git_indexer *idx = 0;
git_transfer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL));
cl_git_pass(git_indexer_append(
idx, leaky_pack, leaky_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
cl_assert(giterr_last() != NULL);
cl_assert_equal_i(giterr_last()->klass, GITERR_INDEXER);
git_indexer_free(idx);
}
void test_pack_indexer__fix_thin(void)
{
git_indexer *idx = NULL;
......@@ -126,6 +192,35 @@ void test_pack_indexer__fix_thin(void)
}
}
void test_pack_indexer__corrupt_length(void)
{
git_indexer *idx = NULL;
git_transfer_progress stats = { 0 };
git_repository *repo;
git_odb *odb;
git_oid id, should_id;
cl_git_pass(git_repository_init(&repo, "thin.git", true));
cl_git_pass(git_repository_odb(&odb, repo));
/* Store the missing base into your ODB so the indexer can fix the pack */
cl_git_pass(git_odb_write(&id, odb, base_obj, base_obj_len, GIT_OBJ_BLOB));
git_oid_fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18");
cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL, NULL));
cl_git_pass(git_indexer_append(
idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
cl_assert(giterr_last() != NULL);
cl_assert_equal_i(giterr_last()->klass, GITERR_ZLIB);
git_indexer_free(idx);
git_odb_free(odb);
git_repository_free(repo);
}
static int find_tmp_file_recurs(void *opaque, git_buf *path)
{
int error = 0;
......
......@@ -3,6 +3,7 @@
#include "git2/rebase.h"
#include "posix.h"
#include "signature.h"
#include "../submodule/submodule_helpers.h"
#include <fcntl.h>
......@@ -12,9 +13,44 @@ static git_signature *signature;
// Fixture setup and teardown
void test_rebase_submodule__initialize(void)
{
git_index *index;
git_oid tree_oid, commit_id;
git_tree *tree;
git_commit *parent;
git_object *obj;
git_reference *master_ref;
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
repo = cl_git_sandbox_init("rebase-submodule");
cl_git_pass(git_signature_new(&signature,
"Rebaser", "rebaser@rebaser.rb", 1405694510, 0));
rewrite_gitmodules(git_repository_workdir(repo));
git_submodule_set_url(repo, "my-submodule", git_repository_path(repo));
/* We have to commit the rewritten .gitmodules file */
git_repository_index(&index, repo);
git_index_add_bypath(index, ".gitmodules");
git_index_write_tree(&tree_oid, index);
git_index_free(index);
cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid));
git_repository_head(&master_ref, repo);
cl_git_pass(git_commit_lookup(&parent, repo, git_reference_target(master_ref)));
cl_git_pass(git_commit_create_v(&commit_id, repo, git_reference_name(master_ref), signature, signature, NULL, "Fixup .gitmodules", tree, 1, parent));
/* And a final reset, for good measure */
git_object_lookup(&obj, repo, &commit_id, GIT_OBJ_COMMIT);
cl_git_pass(git_reset(repo, obj, GIT_RESET_HARD, &opts));
git_object_free(obj);
git_commit_free(parent);
git_reference_free(master_ref);
git_tree_free(tree);
}
void test_rebase_submodule__cleanup(void)
......@@ -31,7 +67,6 @@ void test_rebase_submodule__init_untracked(void)
git_buf untracked_path = GIT_BUF_INIT;
FILE *fp;
git_submodule *submodule;
git_config *config;
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
......@@ -39,12 +74,6 @@ void test_rebase_submodule__init_untracked(void)
cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
git_repository_config(&config, repo);
cl_git_pass(git_config_set_string(config, "submodule.my-submodule.url", git_repository_path(repo)));
git_config_free(config);
cl_git_pass(git_submodule_lookup(&submodule, repo, "my-submodule"));
cl_git_pass(git_submodule_update(submodule, 1, NULL));
......
......@@ -117,3 +117,15 @@ void test_refs_peel__can_peel_fully_peeled_packed_refs(void)
"0df1a5865c8abfc09f1f2182e6a31be550e99f07",
GIT_OBJ_COMMIT);
}
void test_refs_peel__can_peel_fully_peeled_tag_to_tag(void)
{
assert_peel_generic(g_peel_repo,
"refs/tags/tag-inside-tags", GIT_OBJ_TAG,
"c2596aa0151888587ec5c0187f261e63412d9e11",
GIT_OBJ_TAG);
assert_peel_generic(g_peel_repo,
"refs/foo/tag-outside-tags", GIT_OBJ_TAG,
"c2596aa0151888587ec5c0187f261e63412d9e11",
GIT_OBJ_TAG);
}
......@@ -320,6 +320,17 @@ void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void)
assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
}
void test_repo_init__empty_template_path(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.template_path = "";
cl_git_pass(git_futils_mkdir("foo", 0755, 0));
cl_git_pass(git_repository_init_ext(&_repo, "foo", &opts));
cleanup_repository("foo");
}
void test_repo_init__extended_0(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
......
my-submodule @ efad0b11
Subproject commit efad0b11c47cb2f0220cbd6f5b0f93bb99064b00
......@@ -1155,3 +1155,30 @@ void test_status_ignore__subdir_ignore_everything_except_certain_files(void)
refute_is_ignored("project/src/foo.c");
refute_is_ignored("project/src/foo/foo.c");
}
void test_status_ignore__deeper(void)
{
int ignored;
g_repo = cl_git_sandbox_init("empty_standard_repo");
cl_git_mkfile("empty_standard_repo/.gitignore",
"*.data\n"
"!dont_ignore/*.data\n");
cl_git_pass(p_mkdir("empty_standard_repo/dont_ignore", 0777));
cl_git_mkfile("empty_standard_repo/foo.data", "");
cl_git_mkfile("empty_standard_repo/bar.data", "");
cl_git_mkfile("empty_standard_repo/dont_ignore/foo.data", "");
cl_git_mkfile("empty_standard_repo/dont_ignore/bar.data", "");
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "foo.data"));
cl_assert_equal_i(1, ignored);
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "bar.data"));
cl_assert_equal_i(1, ignored);
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "dont_ignore/foo.data"));
cl_assert_equal_i(0, ignored);
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "dont_ignore/bar.data"));
cl_assert_equal_i(0, ignored);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment