diff options
35 files changed, 812 insertions, 165 deletions
@@ -19,7 +19,6 @@ release its source code. * Archives: <http://librelist.com/browser/libgit2/> * Website: <http://libgit2.github.com> * API documentation: <http://libgit2.github.com/libgit2> -* Usage guide: <http://libgit2.github.com/api.html> What It Can Do ================================== diff --git a/examples/general.c b/examples/general.c index 9ea264ec6..a042be011 100644 --- a/examples/general.c +++ b/examples/general.c @@ -8,7 +8,7 @@ // new functionality. // // If you're trying to write something in C using [libgit2][lg], you will also want -// to check out the generated [API documentation][ap] and the [Usage Guide][ug]. We've +// to check out the generated [API documentation][ap]. We've // tried to link to the relevant sections of the API docs in each section in this file. // // **libgit2** only implements the core plumbing functions, not really the higher @@ -17,7 +17,6 @@ // // [lg]: http://libgit2.github.com // [ap]: http://libgit2.github.com/libgit2 -// [ug]: http://libgit2.github.com/api.html // [pg]: http://progit.org/book/ch9-0.html // ### Includes diff --git a/include/git2/branch.h b/include/git2/branch.h index 54a1ab118..3c7fb443c 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -210,6 +210,31 @@ GIT_EXTERN(int) git_branch_tracking_name( GIT_EXTERN(int) git_branch_is_head( git_reference *branch); +/** + * Return the name of remote that the remote tracking branch belongs to. + * + * @param remote_name_out The user-allocated buffer which will be + * filled with the name of the remote. Pass NULL if you just want to + * get the needed size of the name of the remote as the output value. + * + * @param buffer_size Size of the `out` buffer in bytes. + * + * @param repo The repository where the branch lives. + * + * @param branch The reference to the remote tracking branch. + * + * @return Number of characters in the reference name + * including the trailing NUL byte; GIT_ENOTFOUND + * when no remote matching remote was gound, + * GIT_EAMBIGUOUS when the branch maps to several remotes, + * otherwise an error code. + */ +GIT_EXTERN(int) git_branch_remote_name( + char *remote_name_out, + size_t buffer_size, + git_repository *repo, + git_reference *branch); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/clone.h b/include/git2/clone.h index b54676874..e7205d744 100644 --- a/include/git2/clone.h +++ b/include/git2/clone.h @@ -56,7 +56,7 @@ GIT_BEGIN_DECL * - `remote_callbacks` may be used to specify custom progress callbacks for * the origin remote before the fetch is initiated. * - `remote_autotag` may be used to specify the autotag setting before the - * initial fetch. + * initial fetch. The default is GIT_REMOTE_DOWNLOAD_TAGS_ALL. * - `checkout_branch` gives the name of the branch to checkout. NULL means * use the remote's HEAD. */ diff --git a/include/git2/diff.h b/include/git2/diff.h index 81c41df04..3a88902ad 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -123,40 +123,6 @@ typedef enum { } git_diff_option_t; /** - * Structure describing options about how the diff should be executed. - * - * Setting all values of the structure to zero will yield the default - * values. Similarly, passing NULL for the options structure will - * give the defaults. The default values are marked below. - * - * - `flags` is a combination of the `git_diff_option_t` values above - * - `context_lines` is the number of unchanged lines that define the - * boundary of a hunk (and to display before and after) - * - `interhunk_lines` is the maximum number of unchanged lines between - * hunk boundaries before the hunks will be merged into a one. - * - `old_prefix` is the virtual "directory" to prefix to old file names - * in hunk headers (default "a") - * - `new_prefix` is the virtual "directory" to prefix to new file names - * in hunk headers (default "b") - * - `pathspec` is an array of paths / fnmatch patterns to constrain diff - * - `max_size` is a file size (in bytes) above which a blob will be marked - * as binary automatically; pass a negative value to disable. - */ -typedef struct { - unsigned int version; /**< version for the struct */ - uint32_t flags; /**< defaults to GIT_DIFF_NORMAL */ - uint16_t context_lines; /**< defaults to 3 */ - uint16_t interhunk_lines; /**< defaults to 0 */ - const char *old_prefix; /**< defaults to "a" */ - const char *new_prefix; /**< defaults to "b" */ - git_strarray pathspec; /**< defaults to include all paths */ - git_off_t max_size; /**< defaults to 512MB */ -} git_diff_options; - -#define GIT_DIFF_OPTIONS_VERSION 1 -#define GIT_DIFF_OPTIONS_INIT {GIT_DIFF_OPTIONS_VERSION} - -/** * The diff list object that contains all individual file deltas. * * This is an opaque structure which will be allocated by one of the diff @@ -266,6 +232,64 @@ typedef struct { } git_diff_delta; /** + * Diff notification callback function. + * + * The callback will be called for each file, just before the `git_delta_t` + * gets inserted into the diff list. + * + * When the callback: + * - returns < 0, the diff process will be aborted. + * - returns > 0, the delta will not be inserted into the diff list, but the + * diff process continues. + * - returns 0, the delta is inserted into the diff list, and the diff process + * continues. + */ +typedef int (*git_diff_notify_cb)( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload); + +/** + * Structure describing options about how the diff should be executed. + * + * Setting all values of the structure to zero will yield the default + * values. Similarly, passing NULL for the options structure will + * give the defaults. The default values are marked below. + * + * - `flags` is a combination of the `git_diff_option_t` values above + * - `context_lines` is the number of unchanged lines that define the + * boundary of a hunk (and to display before and after) + * - `interhunk_lines` is the maximum number of unchanged lines between + * hunk boundaries before the hunks will be merged into a one. + * - `old_prefix` is the virtual "directory" to prefix to old file names + * in hunk headers (default "a") + * - `new_prefix` is the virtual "directory" to prefix to new file names + * in hunk headers (default "b") + * - `pathspec` is an array of paths / fnmatch patterns to constrain diff + * - `max_size` is a file size (in bytes) above which a blob will be marked + * as binary automatically; pass a negative value to disable. + * - `notify_cb` is an optional callback function, notifying the consumer of + * which files are being examined as the diff is generated + * - `notify_payload` is the payload data to pass to the `notify_cb` function + */ +typedef struct { + unsigned int version; /**< version for the struct */ + uint32_t flags; /**< defaults to GIT_DIFF_NORMAL */ + uint16_t context_lines; /**< defaults to 3 */ + uint16_t interhunk_lines; /**< defaults to 0 */ + const char *old_prefix; /**< defaults to "a" */ + const char *new_prefix; /**< defaults to "b" */ + git_strarray pathspec; /**< defaults to include all paths */ + git_off_t max_size; /**< defaults to 512MB */ + git_diff_notify_cb notify_cb; + void *notify_payload; +} git_diff_options; + +#define GIT_DIFF_OPTIONS_VERSION 1 +#define GIT_DIFF_OPTIONS_INIT {GIT_DIFF_OPTIONS_VERSION} + +/** * When iterating over a diff, callback that will be made per file. * * @param delta A pointer to the delta data for the file diff --git a/include/git2/net.h b/include/git2/net.h index 6e3525f5d..e70ba1f71 100644 --- a/include/git2/net.h +++ b/include/git2/net.h @@ -37,7 +37,7 @@ typedef enum { * Remote head description, given out on `ls` calls. */ struct git_remote_head { - int local:1; /* available locally */ + int local; /* available locally */ git_oid oid; git_oid loid; char *name; diff --git a/include/git2/refspec.h b/include/git2/refspec.h index ee06f8eca..ec7830b7c 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -53,6 +53,15 @@ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); GIT_EXTERN(int) git_refspec_src_matches(const git_refspec *refspec, const char *refname); /** + * Check if a refspec's destination descriptor matches a reference + * + * @param refspec the refspec + * @param refname the name of the reference to check + * @return 1 if the refspec matches, 0 otherwise + */ +GIT_EXTERN(int) git_refspec_dst_matches(const git_refspec *refspec, const char *refname); + +/** * Transform a reference to its target following the refspec's rules * * @param out where to store the target name @@ -63,6 +72,17 @@ GIT_EXTERN(int) git_refspec_src_matches(const git_refspec *refspec, const char * */ GIT_EXTERN(int) git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name); +/** + * Transform a target reference to its source reference following the refspec's rules + * + * @param out where to store the source reference name + * @param outlen the size of the `out` buffer + * @param spec the refspec + * @param name the name of the reference to transform + * @return 0, GIT_EBUFS or another error + */ +GIT_EXTERN(int) git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, const char *name); + GIT_END_DECL #endif diff --git a/include/git2/transport.h b/include/git2/transport.h index 469b43f72..783ea51bf 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -300,7 +300,7 @@ typedef struct git_smart_subtransport_definition { /* True if the protocol is stateless; false otherwise. For example, * http:// is stateless, but git:// is not. */ - unsigned rpc : 1; + unsigned rpc; } git_smart_subtransport_definition; /* Smart transport subtransports that come with libgit2 */ diff --git a/src/branch.c b/src/branch.c index 975a43dbd..11ecbe9a1 100644 --- a/src/branch.c +++ b/src/branch.c @@ -319,6 +319,87 @@ cleanup: return error; } +int git_branch_remote_name( + char *remote_name_out, + size_t buffer_size, + git_repository *repo, + git_reference *branch) +{ + git_strarray remote_list = {0}; + size_t i, remote_name_size; + git_remote *remote; + const git_refspec *fetchspec; + int error = 0; + char *remote_name = NULL; + + assert(branch); + + if (remote_name_out && buffer_size) + *remote_name_out = '\0'; + + /* Verify that this is a remote branch */ + if (!git_reference_is_remote(branch)) { + giterr_set(GITERR_INVALID, + "Reference '%s' is not a remote branch.", branch->name); + error = GIT_ERROR; + goto cleanup; + } + + /* Get the remotes */ + if ((error = git_remote_list(&remote_list, repo)) < 0) + goto cleanup; + + /* Find matching remotes */ + for (i = 0; i < remote_list.count; i++) { + if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0) + goto cleanup; + + fetchspec = git_remote_fetchspec(remote); + + /* Defensivly check that we have a fetchspec */ + if (fetchspec && + git_refspec_dst_matches(fetchspec, branch->name)) { + /* If we have not already set out yet, then set + * it to the matching remote name. Otherwise + * multiple remotes match this reference, and it + * is ambiguous. */ + if (!remote_name) { + remote_name = remote_list.strings[i]; + } else { + git_remote_free(remote); + error = GIT_EAMBIGUOUS; + goto cleanup; + } + } + + git_remote_free(remote); + } + + if (remote_name) { + remote_name_size = strlen(remote_name) + 1; + error = (int) remote_name_size; + + if (remote_name_out) { + if(remote_name_size > buffer_size) { + giterr_set( + GITERR_INVALID, + "Buffer too short to hold the remote name."); + error = GIT_ERROR; + goto cleanup; + } + + memcpy(remote_name_out, remote_name, remote_name_size); + } + } else { + error = GIT_ENOTFOUND; + goto cleanup; + } + +cleanup: + git_strarray_free(&remote_list); + return error; +} + int git_branch_tracking_name( char *tracking_branch_name_out, size_t buffer_size, diff --git a/src/checkout.c b/src/checkout.c index 40f5732ed..0ce283beb 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -224,7 +224,7 @@ static int checkout_action_wd_only( if (!git_pathspec_match_path( pathspec, wd->path, (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0, - git_iterator_ignore_case(workdir))) + git_iterator_ignore_case(workdir), NULL)) return 0; /* check if item is tracked in the index but not in the checkout diff */ diff --git a/src/clone.c b/src/clone.c index 333bf2148..4b72b833c 100644 --- a/src/clone.c +++ b/src/clone.c @@ -417,6 +417,7 @@ static void normalize_options(git_clone_options *dst, const git_clone_options *s /* Provide defaults for null pointers */ if (!dst->remote_name) dst->remote_name = "origin"; + if (!dst->remote_autotag) dst->remote_autotag = GIT_REMOTE_DOWNLOAD_TAGS_ALL; } int git_clone( diff --git a/src/diff.c b/src/diff.c index 4b60935f0..d9bc32a37 100644 --- a/src/diff.c +++ b/src/diff.c @@ -41,12 +41,26 @@ static git_diff_delta *diff_delta__alloc( return delta; } +static int diff_notify( + const git_diff_list *diff, + const git_diff_delta *delta, + const char *matched_pathspec) +{ + if (!diff->opts.notify_cb) + return 0; + + return diff->opts.notify_cb( + diff, delta, matched_pathspec, diff->opts.notify_payload); +} + static int diff_delta__from_one( git_diff_list *diff, git_delta_t status, const git_index_entry *entry) { git_diff_delta *delta; + const char *matched_pathspec; + int notify_res; if (status == GIT_DELTA_IGNORED && (diff->opts.flags & GIT_DIFF_INCLUDE_IGNORED) == 0) @@ -59,7 +73,7 @@ static int diff_delta__from_one( if (!git_pathspec_match_path( &diff->pathspec, entry->path, (diff->opts.flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH) != 0, - (diff->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0)) + (diff->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0, &matched_pathspec)) return 0; delta = diff_delta__alloc(diff, status, entry->path); @@ -84,12 +98,16 @@ static int diff_delta__from_one( !git_oid_iszero(&delta->new_file.oid)) delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID; - if (git_vector_insert(&diff->deltas, delta) < 0) { + notify_res = diff_notify(diff, delta, matched_pathspec); + + if (notify_res) + git__free(delta); + else if (git_vector_insert(&diff->deltas, delta) < 0) { git__free(delta); return -1; } - return 0; + return notify_res < 0 ? GIT_EUSER : 0; } static int diff_delta__from_two( @@ -99,9 +117,11 @@ static int diff_delta__from_two( uint32_t old_mode, const git_index_entry *new_entry, uint32_t new_mode, - git_oid *new_oid) + git_oid *new_oid, + const char *matched_pathspec) { git_diff_delta *delta; + int notify_res; if (status == GIT_DELTA_UNMODIFIED && (diff->opts.flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0) @@ -138,12 +158,16 @@ static int diff_delta__from_two( if (new_oid || !git_oid_iszero(&new_entry->oid)) delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID; - if (git_vector_insert(&diff->deltas, delta) < 0) { + notify_res = diff_notify(diff, delta, matched_pathspec); + + if (notify_res) + git__free(delta); + else if (git_vector_insert(&diff->deltas, delta) < 0) { git__free(delta); return -1; } - return 0; + return notify_res < 0 ? GIT_EUSER : 0; } static git_diff_delta *diff_delta__last_for_item( @@ -419,13 +443,14 @@ static int maybe_modified( unsigned int omode = oitem->mode; unsigned int nmode = nitem->mode; bool new_is_workdir = (new_iter->type == GIT_ITERATOR_TYPE_WORKDIR); + const char *matched_pathspec; GIT_UNUSED(old_iter); if (!git_pathspec_match_path( &diff->pathspec, oitem->path, (diff->opts.flags & GIT_DIFF_DISABLE_PATHSPEC_MATCH) != 0, - (diff->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0)) + (diff->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0, &matched_pathspec)) return 0; /* on platforms with no symlinks, preserve mode of existing symlinks */ @@ -526,7 +551,7 @@ static int maybe_modified( } return diff_delta__from_two( - diff, status, oitem, omode, nitem, nmode, use_noid); + diff, status, oitem, omode, nitem, nmode, use_noid, matched_pathspec); } static bool entry_is_prefixed( @@ -747,10 +772,11 @@ int git_diff__from_iterators( else { assert(oitem && nitem && cmp == 0); - if (maybe_modified(old_iter, oitem, new_iter, nitem, diff) < 0 || - git_iterator_advance(old_iter, &oitem) < 0 || - git_iterator_advance(new_iter, &nitem) < 0) - goto fail; + if (maybe_modified( + old_iter, oitem, new_iter, nitem, diff) < 0 || + git_iterator_advance(old_iter, &oitem) < 0 || + git_iterator_advance(new_iter, &nitem) < 0) + goto fail; } } diff --git a/src/index.c b/src/index.c index 353f57c2b..25156d08f 100644 --- a/src/index.c +++ b/src/index.c @@ -1710,7 +1710,8 @@ int git_index_read_tree_match( goto cleanup; while (entry != NULL) { - if (git_pathspec_match_path(&pathspec, entry->path, false, false) && + if (git_pathspec_match_path( + &pathspec, entry->path, false, false, NULL) && (error = git_index_add(index, entry)) < 0) goto cleanup; diff --git a/src/path.c b/src/path.c index 5de58cce7..263cf9e7c 100644 --- a/src/path.c +++ b/src/path.c @@ -400,7 +400,7 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url) if (offset >= len || file_url[offset] == '/') return error_invalid_local_file_uri(file_url); -#ifndef _MSC_VER +#ifndef GIT_WIN32 offset--; /* A *nix absolute path starts with a forward slash */ #endif diff --git a/src/pathspec.c b/src/pathspec.c index 2bde3ba5f..732180248 100644 --- a/src/pathspec.c +++ b/src/pathspec.c @@ -106,14 +106,21 @@ void git_pathspec_free(git_vector *vspec) /* match a path against the vectorized pathspec */ bool git_pathspec_match_path( - git_vector *vspec, const char *path, bool disable_fnmatch, bool casefold) + git_vector *vspec, + const char *path, + bool disable_fnmatch, + bool casefold, + const char **matched_pathspec) { - unsigned int i; + size_t i; git_attr_fnmatch *match; int fnmatch_flags = 0; int (*use_strcmp)(const char *, const char *); int (*use_strncmp)(const char *, const char *, size_t); + if (matched_pathspec) + *matched_pathspec = NULL; + if (!vspec || !vspec->length) return true; @@ -143,8 +150,12 @@ bool git_pathspec_match_path( path[match->length] == '/') result = 0; - if (result == 0) + if (result == 0) { + if (matched_pathspec) + *matched_pathspec = match->pattern; + return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? false : true; + } } return false; diff --git a/src/pathspec.h b/src/pathspec.h index dde63c7d0..c44561520 100644 --- a/src/pathspec.h +++ b/src/pathspec.h @@ -25,8 +25,16 @@ extern int git_pathspec_init( /* free data from the pathspec vector */ extern void git_pathspec_free(git_vector *vspec); -/* match a path against the vectorized pathspec */ +/* + * Match a path against the vectorized pathspec. + * The matched pathspec is passed back into the `matched_pathspec` parameter, + * unless it is passed as NULL by the caller. + */ extern bool git_pathspec_match_path( - git_vector *vspec, const char *path, bool disable_fnmatch, bool casefold); + git_vector *vspec, + const char *path, + bool disable_fnmatch, + bool casefold, + const char **matched_pathspec); #endif diff --git a/src/push.c b/src/push.c index ddfe5ec07..64aaead6e 100644 --- a/src/push.c +++ b/src/push.c @@ -14,6 +14,20 @@ #include "vector.h" #include "push.h" +static int push_spec_rref_cmp(const void *a, const void *b) +{ + const push_spec *push_spec_a = a, *push_spec_b = b; + + return strcmp(push_spec_a->rref, push_spec_b->rref); +} + +static int push_status_ref_cmp(const void *a, const void *b) +{ + const push_status *push_status_a = a, *push_status_b = b; + + return strcmp(push_status_a->ref, push_status_b->ref); +} + int git_push_new(git_push **out, git_remote *remote) { git_push *p; @@ -27,12 +41,12 @@ int git_push_new(git_push **out, git_remote *remote) p->remote = remote; p->report_status = 1; - if (git_vector_init(&p->specs, 0, NULL) < 0) { + if (git_vector_init(&p->specs, 0, push_spec_rref_cmp) < 0) { git__free(p); return -1; } - if (git_vector_init(&p->status, 0, NULL) < 0) { + if (git_vector_init(&p->status, 0, push_status_ref_cmp) < 0) { git_vector_free(&p->specs); git__free(p); return -1; diff --git a/src/refspec.c b/src/refspec.c index bd69f58ae..a51b0cfab 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -159,11 +159,19 @@ int git_refspec_src_matches(const git_refspec *refspec, const char *refname) return (p_fnmatch(refspec->src, refname, 0) == 0); } -int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name) +int git_refspec_dst_matches(const git_refspec *refspec, const char *refname) +{ + if (refspec == NULL || refspec->dst == NULL) + return false; + + return (p_fnmatch(refspec->dst, refname, 0) == 0); +} + +static int refspec_transform_internal(char *out, size_t outlen, const char *from, const char *to, const char *name) { size_t baselen, namelen; - baselen = strlen(spec->dst); + baselen = strlen(to); if (outlen <= baselen) { giterr_set(GITERR_INVALID, "Reference name too long"); return GIT_EBUFS; @@ -173,8 +181,8 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con * No '*' at the end means that it's mapped to one specific local * branch, so no actual transformation is needed. */ - if (spec->dst[baselen - 1] != '*') { - memcpy(out, spec->dst, baselen + 1); /* include '\0' */ + if (to[baselen - 1] != '*') { + memcpy(out, to, baselen + 1); /* include '\0' */ return 0; } @@ -182,7 +190,7 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con baselen--; /* skip the prefix, -1 is for the '*' */ - name += strlen(spec->src) - 1; + name += strlen(from) - 1; namelen = strlen(name); @@ -191,12 +199,22 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con return GIT_EBUFS; } - memcpy(out, spec->dst, baselen); + memcpy(out, to, baselen); memcpy(out + baselen, name, namelen + 1); return 0; } +int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name) +{ + return refspec_transform_internal(out, outlen, spec->src, spec->dst, name); +} + +int git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, const char *name) +{ + return refspec_transform_internal(out, outlen, spec->dst, spec->src, name); +} + static int refspec_transform(git_buf *out, const char *from, const char *to, const char *name) { if (git_buf_sets(out, to) < 0) diff --git a/src/transports/smart.c b/src/transports/smart.c index af6fec535..e820488f6 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -294,6 +294,13 @@ static void git_smart__free(git_transport *transport) git__free(t); } +static int ref_name_cmp(const void *a, const void *b) +{ + const git_pkt_ref *ref_a = a, *ref_b = b; + + return strcmp(ref_a->head.name, ref_b->head.name); +} + int git_transport_smart(git_transport **out, git_remote *owner, void *param) { transport_smart *t; @@ -321,7 +328,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) t->owner = owner; t->rpc = definition->rpc; - if (git_vector_init(&t->refs, 16, NULL) < 0) { + if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0) { git__free(t); return -1; } diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 184b21a0b..0fae086cb 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -628,6 +628,110 @@ static int parse_report(gitno_buffer *buf, git_push *push) } } +static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec) +{ + git_pkt_ref *added = git__calloc(1, sizeof(git_pkt_ref)); + GITERR_CHECK_ALLOC(added); + + added->type = GIT_PKT_REF; + git_oid_cpy(&added->head.oid, &push_spec->loid); + added->head.name = git__strdup(push_spec->rref); + + if (!added->head.name || + git_vector_insert(refs, added) < 0) { + git_pkt_free((git_pkt *)added); + return -1; + } + + return 0; +} + +static int update_refs_from_report( + git_vector *refs, + git_vector *push_specs, + git_vector *push_report) +{ + git_pkt_ref *ref; + push_spec *push_spec; + push_status *push_status; + size_t i, j, refs_len; + int cmp; + + /* For each push spec we sent to the server, we should have + * gotten back a status packet in the push report */ + if (push_specs->length != push_report->length) { + giterr_set(GITERR_NET, "report-status: protocol error"); + return -1; + } + + /* We require that push_specs be sorted with push_spec_rref_cmp, + * and that push_report be sorted with push_status_ref_cmp */ + git_vector_sort(push_specs); + git_vector_sort(push_report); + + git_vector_foreach(push_specs, i, push_spec) { + push_status = git_vector_get(push_report, i); + + /* For each push spec we sent to the server, we should have + * gotten back a status packet in the push report which matches */ + if (strcmp(push_spec->rref, push_status->ref)) { + giterr_set(GITERR_NET, "report-status: protocol error"); + return -1; + } + } + + /* We require that refs be sorted with ref_name_cmp */ + git_vector_sort(refs); + i = j = 0; + refs_len = refs->length; + + /* Merge join push_specs with refs */ + while (i < push_specs->length && j < refs_len) { + push_spec = git_vector_get(push_specs, i); + push_status = git_vector_get(push_report, i); + ref = git_vector_get(refs, j); + + cmp = strcmp(push_spec->rref, ref->head.name); + + /* Iterate appropriately */ + if (cmp <= 0) i++; + if (cmp >= 0) j++; + + /* Add case */ + if (cmp < 0 && + !push_status->msg && + add_ref_from_push_spec(refs, push_spec) < 0) + return -1; + + /* Update case, delete case */ + if (cmp == 0 && + !push_status->msg) + git_oid_cpy(&ref->head.oid, &push_spec->loid); + } + + for (; i < push_specs->length; i++) { + push_spec = git_vector_get(push_specs, i); + push_status = git_vector_get(push_report, i); + + /* Add case */ + if (!push_status->msg && + add_ref_from_push_spec(refs, push_spec) < 0) + return -1; + } + + /* Remove any refs which we updated to have a zero OID. */ + git_vector_rforeach(refs, i, ref) { + if (git_oid_iszero(&ref->head.oid)) { + git_vector_remove(refs, i); + git_pkt_free((git_pkt *)ref); + } + } + + git_vector_sort(refs); + + return 0; +} + static int stream_thunk(void *buf, size_t size, void *data) { git_smart_subtransport_stream *s = (git_smart_subtransport_stream *)data; @@ -640,7 +744,6 @@ int git_smart__push(git_transport *transport, git_push *push) transport_smart *t = (transport_smart *)transport; git_smart_subtransport_stream *s; git_buf pktline = GIT_BUF_INIT; - char *url = NULL; int error = -1; #ifdef PUSH_DEBUG @@ -678,25 +781,13 @@ int git_smart__push(git_transport *transport, git_push *push) else if (parse_report(&t->buffer, push) < 0) goto on_error; - /* If we updated at least one ref, then we need to re-acquire the list of - * refs so the caller can call git_remote_update_tips afterward. TODO: Use - * the data from the push report to do this without another network call */ - if (push->specs.length) { - git_cred_acquire_cb cred_cb = t->cred_acquire_cb; - void *cred_payload = t->cred_acquire_payload; - int flags = t->flags; - - url = git__strdup(t->url); - - if (!url || t->parent.close(&t->parent) < 0 || - t->parent.connect(&t->parent, url, cred_cb, cred_payload, GIT_DIRECTION_PUSH, flags)) - goto on_error; - } + if (push->status.length && + update_refs_from_report(&t->refs, &push->specs, &push->status) < 0) + goto on_error; error = 0; on_error: - git__free(url); git_buf_free(&pktline); return error; diff --git a/src/vector.h b/src/vector.h index 690e4af9c..e2f729b83 100644 --- a/src/vector.h +++ b/src/vector.h @@ -64,7 +64,7 @@ GIT_INLINE(void *) git_vector_last(const git_vector *v) for ((iter) = 0; (iter) < (v)->length && ((elem) = (v)->contents[(iter)], 1); (iter)++ ) #define git_vector_rforeach(v, iter, elem) \ - for ((iter) = (v)->length; (iter) > 0 && ((elem) = (v)->contents[(iter)-1], 1); (iter)-- ) + for ((iter) = (v)->length - 1; (iter) < SIZE_MAX && ((elem) = (v)->contents[(iter)], 1); (iter)-- ) int git_vector_insert(git_vector *v, void *element); int git_vector_insert_sorted(git_vector *v, void *element, diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 0c23e2959..f533eaa5e 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -100,6 +100,21 @@ static int do_lstat( buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); + /* Windows symlinks have zero file size, call readlink to determine + * the length of the path pointed to, which we expect everywhere else + */ + if (S_ISLNK(fMode)) { + char target[GIT_WIN_PATH]; + int readlink_result; + + readlink_result = p_readlink(file_name, target, GIT_WIN_PATH); + + if (readlink_result == -1) + return -1; + + buf->st_size = strlen(target); + } + return 0; } @@ -157,10 +172,10 @@ int p_readlink(const char *link, char *target, size_t target_len) * it is not available in platforms older than Vista */ if (pGetFinalPath == NULL) { - HINSTANCE library = LoadLibrary("kernel32"); + HMODULE module = GetModuleHandle("kernel32"); - if (library != NULL) - pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleW"); + if (module != NULL) + pGetFinalPath = (fpath_func)GetProcAddress(module, "GetFinalPathNameByHandleW"); if (pGetFinalPath == NULL) { giterr_set(GITERR_OS, diff --git a/tests-clar/clar_libgit2.c b/tests-clar/clar_libgit2.c index 88ffb2bca..63efd5954 100644 --- a/tests-clar/clar_libgit2.c +++ b/tests-clar/clar_libgit2.c @@ -238,7 +238,7 @@ const char* cl_git_path_url(const char *path) cl_git_pass(git_path_prettify_dir(&path_buf, path, NULL)); cl_git_pass(git_buf_puts(&url_buf, "file://")); -#ifdef _MSC_VER +#ifdef GIT_WIN32 /* * A FILE uri matches the following format: file://[host]/path * where "host" can be empty and "path" is an absolute path to the resource. diff --git a/tests-clar/core/path.c b/tests-clar/core/path.c index 894e81f3d..407770baa 100644 --- a/tests-clar/core/path.c +++ b/tests-clar/core/path.c @@ -324,7 +324,7 @@ static void check_fromurl(const char *expected_result, const char *input, int sh git_buf_free(&buf); } -#ifdef _MSC_VER +#ifdef GIT_WIN32 #define ABS_PATH_MARKER "" #else #define ABS_PATH_MARKER "/" diff --git a/tests-clar/diff/diff_helpers.h b/tests-clar/diff/diff_helpers.h index 49c265285..a43847b79 100644 --- a/tests-clar/diff/diff_helpers.h +++ b/tests-clar/diff/diff_helpers.h @@ -20,6 +20,11 @@ typedef struct { int line_dels; } diff_expects; +typedef struct { + const char *path; + const char *matched_pathspec; +} notify_expected; + extern int diff_file_cb( const git_diff_delta *delta, float progress, diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c index 21da63954..7e8915c4b 100644 --- a/tests-clar/diff/workdir.c +++ b/tests-clar/diff/workdir.c @@ -307,6 +307,169 @@ void test_diff_workdir__to_index_with_pathspec(void) git_diff_list_free(diff); } +static int assert_called_notifications( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + bool found = false; + notify_expected *exp = (notify_expected*)payload; + notify_expected *e;; + + GIT_UNUSED(diff_so_far); + + for (e = exp; e->path != NULL; e++) { + if (strcmp(e->path, delta_to_add->new_file.path)) + continue; + + cl_assert_equal_s(e->matched_pathspec, matched_pathspec); + + found = true; + break; + } + + cl_assert(found); + return 0; +} + +void test_diff_workdir__to_index_notify(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + diff_expects exp; + + char *searched_pathspecs_solo[] = { + "*_deleted", + }; + notify_expected expected_matched_pathspecs_solo[] = { + { "file_deleted", "*_deleted" }, + { "staged_changes_file_deleted", "*_deleted" }, + { NULL, NULL } + }; + + char *searched_pathspecs_multiple[] = { + "staged_changes_cant_find_me", + "subdir/modified_cant_find_me", + "subdir/*", + "staged*" + }; + notify_expected expected_matched_pathspecs_multiple[] = { + { "staged_changes_file_deleted", "staged*" }, + { "staged_changes_modified_file", "staged*" }, + { "staged_delete_modified_file", "staged*" }, + { "staged_new_file_deleted_file", "staged*" }, + { "staged_new_file_modified_file", "staged*" }, + { "subdir/deleted_file", "subdir/*" }, + { "subdir/modified_file", "subdir/*" }, + { "subdir/new_file", "subdir/*" }, + { NULL, NULL } + }; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = assert_called_notifications; + opts.pathspec.strings = searched_pathspecs_solo; + opts.pathspec.count = 1; + + opts.notify_payload = &expected_matched_pathspecs_solo; + memset(&exp, 0, sizeof(exp)); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(2, exp.files); + + git_diff_list_free(diff); + + opts.pathspec.strings = searched_pathspecs_multiple; + opts.pathspec.count = 4; + opts.notify_payload = &expected_matched_pathspecs_multiple; + memset(&exp, 0, sizeof(exp)); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(8, exp.files); + + git_diff_list_free(diff); +} + +static int abort_diff( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + GIT_UNUSED(diff_so_far); + GIT_UNUSED(delta_to_add); + GIT_UNUSED(matched_pathspec); + GIT_UNUSED(payload); + + return -42; +} + +void test_diff_workdir__to_index_notify_can_be_aborted_by_callback(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + char *pathspec = NULL; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = abort_diff; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + pathspec = "file_deleted"; + cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + pathspec = "staged_changes_modified_file"; + cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); +} + +static int filter_all( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + GIT_UNUSED(diff_so_far); + GIT_UNUSED(delta_to_add); + GIT_UNUSED(matched_pathspec); + GIT_UNUSED(payload); + + return 42; +} + +void test_diff_workdir__to_index_notify_can_be_used_as_filtering_function(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + char *pathspec = NULL; + diff_expects exp; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = filter_all; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + pathspec = "*_deleted"; + memset(&exp, 0, sizeof(exp)); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(0, exp.files); + + git_diff_list_free(diff); +} + + void test_diff_workdir__filemode_changes(void) { git_config *cfg; diff --git a/tests-clar/fetchhead/fetchhead_data.h b/tests-clar/fetchhead/fetchhead_data.h index 71f67be25..294c9fb01 100644 --- a/tests-clar/fetchhead/fetchhead_data.h +++ b/tests-clar/fetchhead/fetchhead_data.h @@ -1,5 +1,5 @@ -#define FETCH_HEAD_WILDCARD_DATA \ +#define FETCH_HEAD_WILDCARD_DATA_LOCAL \ "49322bb17d3acc9146f98c97d078513228bbf3c0\t\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ @@ -7,13 +7,23 @@ "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" +#define FETCH_HEAD_WILDCARD_DATA \ + "49322bb17d3acc9146f98c97d078513228bbf3c0\t\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ + "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ + "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ + "d96c4e80345534eccee5ac7b07fc7603b56124cb\tnot-for-merge\ttag 'annotated_tag' of git://github.com/libgit2/TestGitRepository\n" \ + "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ + "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \ + "6e0c7bdb9b4ed93212491ee778ca1c65047cab4e\tnot-for-merge\ttag 'nearly-dangling' of git://github.com/libgit2/TestGitRepository\n" + #define FETCH_HEAD_NO_MERGE_DATA \ "0966a434eb1a025db6b71485ab63a3bfbea520b6\tnot-for-merge\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" \ "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tbranch 'master' of git://github.com/libgit2/TestGitRepository\n" \ "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1\tnot-for-merge\tbranch 'no-parent' of git://github.com/libgit2/TestGitRepository\n" \ "d96c4e80345534eccee5ac7b07fc7603b56124cb\tnot-for-merge\ttag 'annotated_tag' of git://github.com/libgit2/TestGitRepository\n" \ "55a1a760df4b86a02094a904dfa511deb5655905\tnot-for-merge\ttag 'blob' of git://github.com/libgit2/TestGitRepository\n" \ - "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" + "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \ + "6e0c7bdb9b4ed93212491ee778ca1c65047cab4e\tnot-for-merge\ttag 'nearly-dangling' of git://github.com/libgit2/TestGitRepository\n" #define FETCH_HEAD_EXPLICIT_DATA \ diff --git a/tests-clar/fetchhead/nonetwork.c b/tests-clar/fetchhead/nonetwork.c index b8cb69e68..ef30679f9 100644 --- a/tests-clar/fetchhead/nonetwork.c +++ b/tests-clar/fetchhead/nonetwork.c @@ -92,7 +92,7 @@ void test_fetchhead_nonetwork__write(void) cl_git_pass(git_futils_readbuffer(&fetchhead_buf, "./test1/.git/FETCH_HEAD")); - equals = (strcmp(fetchhead_buf.ptr, FETCH_HEAD_WILDCARD_DATA) == 0); + equals = (strcmp(fetchhead_buf.ptr, FETCH_HEAD_WILDCARD_DATA_LOCAL) == 0); git_buf_free(&fetchhead_buf); diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c index b138d8c10..51d6c946f 100644 --- a/tests-clar/network/remotes.c +++ b/tests-clar/network/remotes.c @@ -173,13 +173,20 @@ void test_network_remotes__fnmatch(void) void test_network_remotes__transform(void) { - char ref[1024]; + char ref[1024] = {0}; - memset(ref, 0x0, sizeof(ref)); cl_git_pass(git_refspec_transform(ref, sizeof(ref), _refspec, "refs/heads/master")); cl_assert_equal_s(ref, "refs/remotes/test/master"); } +void test_network_remotes__transform_destination_to_source(void) +{ + char ref[1024] = {0}; + + cl_git_pass(git_refspec_rtransform(ref, sizeof(ref), _refspec, "refs/remotes/test/master")); + cl_assert_equal_s(ref, "refs/heads/master"); +} + void test_network_remotes__transform_r(void) { git_buf buf = GIT_BUF_INIT; diff --git a/tests-clar/online/fetchhead.c b/tests-clar/online/fetchhead.c index f89270741..84a2177ea 100644 --- a/tests-clar/online/fetchhead.c +++ b/tests-clar/online/fetchhead.c @@ -81,7 +81,7 @@ void test_online_fetchhead__no_merges(void) cl_git_pass(git_repository_config(&config, g_repo)); cl_git_pass(git_config_set_string(config, "branch.master.remote", NULL)); cl_git_pass(git_config_set_string(config, "branch.master.merge", NULL)); - git_config_free(config); + git_config_free(config); fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA); } diff --git a/tests-clar/refs/branches/remote.c b/tests-clar/refs/branches/remote.c new file mode 100644 index 000000000..be355af46 --- /dev/null +++ b/tests-clar/refs/branches/remote.c @@ -0,0 +1,119 @@ +#include "clar_libgit2.h" +#include "branch.h" +#include "remote.h" + +static git_repository *g_repo; + +static const char *current_master_tip = "099fabac3a9ea935598528c27f866e34089c2eff"; + +void test_refs_branches_remote__initialize(void) +{ + git_oid id; + + g_repo = cl_git_sandbox_init("testrepo"); + git_oid_fromstr(&id, current_master_tip); + + /* Create test/master */ + git_reference_create(NULL, g_repo, "refs/remotes/test/master", &id, 1); +} + +void test_refs_branches_remote__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_refs_branches_remote__can_get_remote_for_branch(void) +{ + git_reference *ref; + const char *name; + char *expectedRemoteName = "test"; + int expectedRemoteNameLength = strlen(expectedRemoteName) + 1; + char remotename[1024] = {0}; + + cl_git_pass(git_branch_lookup(&ref, g_repo, "test/master", GIT_BRANCH_REMOTE)); + cl_git_pass(git_branch_name(&name, ref)); + cl_assert_equal_s("test/master", name); + + cl_assert_equal_i(expectedRemoteNameLength, + git_branch_remote_name(NULL, 0, g_repo, ref)); + cl_assert_equal_i(expectedRemoteNameLength, + git_branch_remote_name(remotename, expectedRemoteNameLength, g_repo, ref)); + cl_assert_equal_s("test", remotename); + + git_reference_free(ref); +} + +void test_refs_branches_remote__insufficient_buffer_returns_error(void) +{ + git_reference *ref; + const char *name; + char *expectedRemoteName = "test"; + int expectedRemoteNameLength = strlen(expectedRemoteName) + 1; + char remotename[1024] = {0}; + + cl_git_pass(git_branch_lookup(&ref, g_repo, "test/master", GIT_BRANCH_REMOTE)); + cl_git_pass(git_branch_name(&name, ref)); + cl_assert_equal_s("test/master", name); + + cl_assert_equal_i(expectedRemoteNameLength, + git_branch_remote_name(NULL, 0, g_repo, ref)); + cl_git_fail_with(GIT_ERROR, + git_branch_remote_name(remotename, expectedRemoteNameLength - 1, g_repo, ref)); + + git_reference_free(ref); +} + +void test_refs_branches_remote__no_matching_remote_returns_error(void) +{ + git_reference *ref; + const char *name; + git_oid id; + + git_oid_fromstr(&id, current_master_tip); + + /* Create nonexistent/master */ + git_reference_create(NULL, g_repo, "refs/remotes/nonexistent/master", &id, 1); + + cl_git_pass(git_branch_lookup(&ref, g_repo,"nonexistent/master", GIT_BRANCH_REMOTE)); + cl_git_pass(git_branch_name(&name, ref)); + cl_assert_equal_s("nonexistent/master", name); + + cl_git_fail_with(git_branch_remote_name(NULL, 0, g_repo, ref), GIT_ENOTFOUND); + git_reference_free(ref); +} + +void test_refs_branches_remote__local_remote_returns_error(void) +{ + git_reference *ref; + const char *name; + + cl_git_pass(git_branch_lookup(&ref,g_repo, "master", GIT_BRANCH_LOCAL)); + cl_git_pass(git_branch_name(&name, ref)); + cl_assert_equal_s("master",name); + + cl_git_fail_with(git_branch_remote_name(NULL, 0, g_repo, ref), GIT_ERROR); + git_reference_free(ref); +} + +void test_refs_branches_remote__ambiguous_remote_returns_error(void) +{ + git_reference *ref; + const char *name; + git_remote *remote; + + /* Create the remote */ + cl_git_pass(git_remote_create(&remote, g_repo, "addtest", "http://github.com/libgit2/libgit2")); + + /* Update the remote fetch spec */ + cl_git_pass(git_remote_set_fetchspec(remote, "refs/heads/*:refs/remotes/test/*")); + cl_git_pass(git_remote_save(remote)); + + git_remote_free(remote); + + cl_git_pass(git_branch_lookup(&ref,g_repo, "test/master", GIT_BRANCH_REMOTE)); + cl_git_pass(git_branch_name(&name, ref)); + cl_assert_equal_s("test/master", name); + + cl_git_fail_with(git_branch_remote_name(NULL, 0, g_repo, ref), GIT_EAMBIGUOUS); + git_reference_free(ref); +} diff --git a/tests-clar/refs/rename.c b/tests-clar/refs/rename.c index bfdef15fa..5c1e8a798 100644 --- a/tests-clar/refs/rename.c +++ b/tests-clar/refs/rename.c @@ -19,19 +19,19 @@ static git_repository *g_repo; void test_refs_rename__initialize(void) { - g_repo = cl_git_sandbox_init("testrepo"); + g_repo = cl_git_sandbox_init("testrepo"); } void test_refs_rename__cleanup(void) { - cl_git_sandbox_cleanup(); + cl_git_sandbox_cleanup(); } void test_refs_rename__loose(void) { - // rename a loose reference + // rename a loose reference git_reference *looked_up_ref, *another_looked_up_ref; git_buf temp_path = GIT_BUF_INIT; const char *new_name = "refs/tags/Nemo/knows/refs.kung-fu"; @@ -72,7 +72,7 @@ void test_refs_rename__loose(void) void test_refs_rename__packed(void) { - // rename a packed reference (should make it loose) + // rename a packed reference (should make it loose) git_reference *looked_up_ref, *another_looked_up_ref; git_buf temp_path = GIT_BUF_INIT; const char *brand_new_name = "refs/heads/brand_new_name"; @@ -113,7 +113,7 @@ void test_refs_rename__packed(void) void test_refs_rename__packed_doesnt_pack_others(void) { - // renaming a packed reference does not pack another reference which happens to be in both loose and pack state + // renaming a packed reference does not pack another reference which happens to be in both loose and pack state git_reference *looked_up_ref, *another_looked_up_ref; git_buf temp_path = GIT_BUF_INIT; const char *brand_new_name = "refs/heads/brand_new_name"; @@ -154,7 +154,7 @@ void test_refs_rename__packed_doesnt_pack_others(void) void test_refs_rename__name_collision(void) { - // can not rename a reference with the name of an existing reference + // can not rename a reference with the name of an existing reference git_reference *looked_up_ref; /* An existing reference... */ @@ -173,7 +173,7 @@ void test_refs_rename__name_collision(void) void test_refs_rename__invalid_name(void) { - // can not rename a reference with an invalid name + // can not rename a reference with an invalid name git_reference *looked_up_ref; /* An existing oid reference... */ @@ -199,7 +199,7 @@ void test_refs_rename__invalid_name(void) void test_refs_rename__force_loose_packed(void) { - // can force-rename a packed reference with the name of an existing loose and packed reference + // can force-rename a packed reference with the name of an existing loose and packed reference git_reference *looked_up_ref; git_oid oid; @@ -223,7 +223,7 @@ void test_refs_rename__force_loose_packed(void) void test_refs_rename__force_loose(void) { - // can force-rename a loose reference with the name of an existing loose reference + // can force-rename a loose reference with the name of an existing loose reference git_reference *looked_up_ref; git_oid oid; @@ -232,7 +232,7 @@ void test_refs_rename__force_loose(void) git_oid_cpy(&oid, git_reference_target(looked_up_ref)); /* Can be force-renamed to the name of another existing reference. */ - cl_git_pass(git_reference_rename(looked_up_ref, "refs/heads/test", 1)); + cl_git_pass(git_reference_rename(looked_up_ref, "refs/heads/test", 1)); git_reference_free(looked_up_ref); /* Check we actually renamed it */ @@ -250,7 +250,7 @@ void test_refs_rename__force_loose(void) void test_refs_rename__overwrite(void) { - // can not overwrite name of existing reference + // can not overwrite name of existing reference git_reference *ref, *ref_one, *ref_one_new, *ref_two; git_oid id; @@ -281,7 +281,7 @@ void test_refs_rename__overwrite(void) void test_refs_rename__prefix(void) { - // can be renamed to a new name prefixed with the old name + // can be renamed to a new name prefixed with the old name git_reference *ref, *ref_two, *looked_up_ref; git_oid id; @@ -313,33 +313,33 @@ void test_refs_rename__prefix(void) void test_refs_rename__move_up(void) { - // can move a reference to a upper reference hierarchy - git_reference *ref, *ref_two, *looked_up_ref; - git_oid id; + // can move a reference to a upper reference hierarchy + git_reference *ref, *ref_two, *looked_up_ref; + git_oid id; - cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); - cl_assert(git_reference_type(ref) & GIT_REF_OID); + cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name)); + cl_assert(git_reference_type(ref) & GIT_REF_OID); - git_oid_cpy(&id, git_reference_target(ref)); + git_oid_cpy(&id, git_reference_target(ref)); - /* Create loose references */ - cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name_new, &id, 0)); - git_reference_free(ref_two); + /* Create loose references */ + cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name_new, &id, 0)); + git_reference_free(ref_two); - /* An existing reference... */ - cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new)); + /* An existing reference... */ + cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new)); - /* Can be renamed upward the reference tree. */ - cl_git_pass(git_reference_rename(looked_up_ref, ref_two_name, 0)); - git_reference_free(looked_up_ref); + /* Can be renamed upward the reference tree. */ + cl_git_pass(git_reference_rename(looked_up_ref, ref_two_name, 0)); + git_reference_free(looked_up_ref); - /* Check we actually renamed it */ - cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name)); - cl_assert_equal_s(looked_up_ref->name, ref_two_name); - git_reference_free(looked_up_ref); - cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new)); - git_reference_free(ref); - git_reference_free(looked_up_ref); + /* Check we actually renamed it */ + cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name)); + cl_assert_equal_s(looked_up_ref->name, ref_two_name); + git_reference_free(looked_up_ref); + cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new)); + git_reference_free(ref); + git_reference_free(looked_up_ref); } void test_refs_rename__propagate_eexists(void) diff --git a/tests-clar/repo/init.c b/tests-clar/repo/init.c index 9ddb39545..97a5ff62a 100644 --- a/tests-clar/repo/init.c +++ b/tests-clar/repo/init.c @@ -263,36 +263,36 @@ void test_repo_init__reinit_doesnot_overwrite_ignorecase(void) void test_repo_init__reinit_overwrites_filemode(void) { - git_config *config; - int expected, current_value; + git_config *config; + int expected, current_value; #ifdef GIT_WIN32 - expected = false; + expected = false; #else - expected = true; + expected = true; #endif - /* Init a new repo */ - cl_set_cleanup(&cleanup_repository, "overwrite.git"); - cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); + /* Init a new repo */ + cl_set_cleanup(&cleanup_repository, "overwrite.git"); + cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); - /* Change the "core.filemode" config value to something unlikely */ - git_repository_config(&config, _repo); - git_config_set_bool(config, "core.filemode", !expected); - git_config_free(config); - git_repository_free(_repo); - _repo = NULL; + /* Change the "core.filemode" config value to something unlikely */ + git_repository_config(&config, _repo); + git_config_set_bool(config, "core.filemode", !expected); + git_config_free(config); + git_repository_free(_repo); + _repo = NULL; - /* Reinit the repository */ - cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); - git_repository_config(&config, _repo); + /* Reinit the repository */ + cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); + git_repository_config(&config, _repo); - /* Ensure the "core.filemode" config value has been reset */ - cl_git_pass(git_config_get_bool(¤t_value, config, "core.filemode")); - cl_assert_equal_i(expected, current_value); + /* Ensure the "core.filemode" config value has been reset */ + cl_git_pass(git_config_get_bool(¤t_value, config, "core.filemode")); + cl_assert_equal_i(expected, current_value); - git_config_free(config); + git_config_free(config); } void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void) diff --git a/tests-clar/repo/message.c b/tests-clar/repo/message.c index 4a6f13b9d..59487d51b 100644 --- a/tests-clar/repo/message.c +++ b/tests-clar/repo/message.c @@ -31,16 +31,16 @@ void test_repo_message__message(void) ssize_t len; cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), "MERGE_MSG")); - cl_git_mkfile(git_buf_cstr(&_path), expected); + cl_git_mkfile(git_buf_cstr(&_path), expected); - len = git_repository_message(NULL, 0, _repo); - cl_assert(len > 0); - _actual = git__malloc(len + 1); - cl_assert(_actual != NULL); + len = git_repository_message(NULL, 0, _repo); + cl_assert(len > 0); + _actual = git__malloc(len + 1); + cl_assert(_actual != NULL); - cl_assert(git_repository_message(_actual, len, _repo) > 0); - _actual[len] = '\0'; - cl_assert_equal_s(expected, _actual); + cl_assert(git_repository_message(_actual, len, _repo) > 0); + _actual[len] = '\0'; + cl_assert_equal_s(expected, _actual); cl_git_pass(p_unlink(git_buf_cstr(&_path))); cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(NULL, 0, _repo)); diff --git a/tests-clar/threads/basic.c b/tests-clar/threads/basic.c index 2b1c36808..a15c53140 100644 --- a/tests-clar/threads/basic.c +++ b/tests-clar/threads/basic.c @@ -5,16 +5,19 @@ static git_repository *g_repo; -void test_threads_basic__initialize(void) { - g_repo = cl_git_sandbox_init("testrepo"); +void test_threads_basic__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo"); } -void test_threads_basic__cleanup(void) { - cl_git_sandbox_cleanup(); +void test_threads_basic__cleanup(void) +{ + cl_git_sandbox_cleanup(); } -void test_threads_basic__cache(void) { - // run several threads polling the cache at the same time - cl_assert(1 == 1); +void test_threads_basic__cache(void) +{ + // run several threads polling the cache at the same time + cl_assert(1 == 1); } |
