diff options
188 files changed, 3963 insertions, 786 deletions
diff --git a/.travis.yml b/.travis.yml index 362b88224..589edfa36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,8 +31,14 @@ matrix: - compiler: gcc env: COVERITY=1 os: linux + - compiler: gcc + env: + - VALGRIND=1 + OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Debug" + os: linux allow_failures: - env: COVERITY=1 + - env: VALGRIND=1 install: - ./script/install-deps-${TRAVIS_OS_NAME}.sh @@ -43,8 +49,8 @@ script: # Run Tests after_success: - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install valgrind; fi - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then valgrind --leak-check=full --show-reachable=yes --suppressions=./libgit2_clar.supp _build/libgit2_clar -ionline; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a -n "$VALGRIND" ]; then sudo apt-get -qq install valgrind; fi + - if [ "$TRAVIS_OS_NAME" = "linux" -a -n "$VALGRIND" ]; then valgrind --leak-check=full --show-reachable=yes --suppressions=./libgit2_clar.supp _build/libgit2_clar -ionline; fi # Only watch the development and master branches branches: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4664c4d41..82733f653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ v0.21 + 1 * Use a map for the treebuilder, making insertion O(1) +* Introduce reference transactions, which allow multiple references to + be locked at the same time and updates be queued. This also allows + us to safely update a reflog with arbitrary contents, as we need to + do for stash. + * LF -> CRLF filter refuses to handle mixed-EOL files * LF -> CRLF filter now runs when * text = auto (with Git for Windows 1.9.4) @@ -21,6 +26,10 @@ v0.21 + 1 as, so this introduces the USERNAME credential type which the ssh transport will use to ask for the username. +* The build system now accepts an option EMBED_SSH_PATH which when set + tells it to include a copy of libssh2 at the given location. This is + enabled for MSVC. + * The git_transport_register function no longer takes a priority and takes a URL scheme name (eg "http") instead of a prefix like "http://" @@ -46,11 +55,24 @@ v0.21 + 1 repository_cb_payload to allow the user to create a repository with custom options. +* The option to ignore certificate errors via git_remote_cert_check() + is no longer present. Instead, git_remote_callbacks has gained a new + entry which lets the user perform their own certificate checks. + * git_clone_into and git_clone_local_into have been removed from the public API in favour of git_clone callbacks * Add support for refspecs with the asterisk in the middle of a pattern. +* Fetching now performs opportunistic updates. To achieve this, we + introduce a difference between active and passive refspecs, which + make git_remote_download and git_remote_fetch to take a list of + resfpecs to be the active list, similarly to how git fetch accepts a + list on the command-line. + * Introduce git_merge_bases() and the git_oidarray type to expose all merge bases between two commits. + +* Introduce git_merge_bases_many() to expose all merge bases between + multiple commits. diff --git a/CMakeLists.txt b/CMakeLists.txt index 76cca4f22..7da4a8963 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,10 @@ IF(MSVC) # HTTP transport, invoke CMake with the "-DWINHTTP=OFF" argument. OPTION( WINHTTP "Use Win32 WinHTTP routines" ON ) + # If you want to embed a copy of libssh2 into libgit2, pass a + # path to libssh2 + OPTION( EMBED_SSH_PATH "Path to libssh2 to embed (Windows)" OFF ) + ADD_DEFINITIONS(-D_SCL_SECURE_NO_WARNINGS) ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE) ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE) @@ -134,6 +138,13 @@ STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION ([0-9]+)$" "\\1" LIBGIT2_SOVERSION "$ # Find required dependencies INCLUDE_DIRECTORIES(src include) +IF (WIN32 AND EMBED_SSH_PATH) + FILE(GLOB SRC_SSH "${EMBED_SSH_PATH}/src/*.c") + INCLUDE_DIRECTORIES("${EMBED_SSH_PATH}/include") + FILE(WRITE "${EMBED_SSH_PATH}/src/libssh2_config.h" "#define HAVE_WINCNG\n#define LIBSSH2_WINCNG\n#include \"../win32/libssh2_config.h\"") + ADD_DEFINITIONS(-DGIT_SSH) +ENDIF() + IF (WIN32 AND WINHTTP AND NOT MINGW) ADD_DEFINITIONS(-DGIT_WINHTTP) INCLUDE_DIRECTORIES(deps/http-parser) @@ -393,7 +404,7 @@ ELSE() ENDIF() # Compile and link libgit2 -ADD_LIBRARY(git2 ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC}) +ADD_LIBRARY(git2 ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SSH} ${SRC_SHA1} ${WIN_RC}) TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES}) TARGET_LINK_LIBRARIES(git2 ${SSH_LIBRARIES}) TARGET_LINK_LIBRARIES(git2 ${GSSAPI_LIBRARIES}) @@ -459,7 +470,7 @@ IF (BUILD_CLAR) ${CLAR_PATH}/clar.c PROPERTIES OBJECT_DEPENDS ${CLAR_PATH}/clar.suite) - ADD_EXECUTABLE(libgit2_clar ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_CLAR} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1}) + ADD_EXECUTABLE(libgit2_clar ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_CLAR} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SSH} ${SRC_SHA1}) TARGET_LINK_LIBRARIES(libgit2_clar ${SSL_LIBRARIES}) TARGET_LINK_LIBRARIES(libgit2_clar ${SSH_LIBRARIES}) @@ -55,7 +55,7 @@ dependencies, it can make use of a few libraries to add to it: - pthreads (non-Windows) to enable threadsafe access as well as multi-threaded pack generation - OpenSSL (non-Windows) to talk over HTTPS and provide the SHA-1 functions -- LibSSH2 to enable the ssh transport +- LibSSH2 to enable the SSH transport - iconv (OSX) to handle the HFS+ path encoding peculiarities Building libgit2 - Using CMake @@ -119,8 +119,7 @@ You need to run the CMake commands from the Visual Studio command prompt, not the regular or Windows SDK one. Select the right generator for your version with the `-G "Visual Studio X" option. -See [the wiki] -(https://github.com/libgit2/libgit2/wiki/Building-libgit2-on-Windows) +See [the website](https://libgit2.github.com/docs/guides/build-and-link) for more detailed instructions. Android @@ -195,6 +194,8 @@ Here are the bindings to libgit2 that are currently available: * git2r <https://github.com/ropensci/git2r> * Ruby * Rugged <https://github.com/libgit2/rugged> +* Rust + * git2-rs <https://github.com/alexcrichton/git2-rs> * Vala * libgit2.vapi <https://github.com/apmasell/vapis/blob/master/libgit2.vapi> @@ -211,7 +212,7 @@ workflow, the libgit2 [coding conventions](CONVENTIONS.md), and out list of License ================================== -`libgit2` is under GPL2 **with linking exemption**. This means you can link to +`libgit2` is under GPL2 **with linking exception**. This means you can link to and use the library from any program, proprietary or open source; paid or gratis. However, you cannot modify libgit2 and distribute it without supplying the source. diff --git a/examples/general.c b/examples/general.c index ae8756338..051d69380 100644 --- a/examples/general.c +++ b/examples/general.c @@ -94,8 +94,8 @@ int main (int argc, char** argv) // Next we will convert the 20 byte raw SHA1 value to a human readable 40 // char hex value. printf("\n*Raw to Hex*\n"); - char out[41]; - out[40] = '\0'; + char out[GIT_OID_HEXSZ+1]; + out[GIT_OID_HEXSZ] = '\0'; // If you have a oid, you can easily get the hex value of the SHA as well. git_oid_fmt(out, &oid); diff --git a/examples/network/fetch.c b/examples/network/fetch.c index 03f1541a4..ab78fc9bd 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -36,7 +36,7 @@ static void *download(void *ptr) // Download the packfile and index it. This function updates the // amount of received data and the indexer stats which lets you // inform the user about progress. - if (git_remote_download(data->remote) < 0) { + if (git_remote_download(data->remote, NULL) < 0) { data->ret = -1; goto exit; } @@ -155,7 +155,7 @@ int fetch(git_repository *repo, int argc, char **argv) // Update the references in the remote's namespace to point to the // right commits. This may be needed even if there was no packfile // to download, which can happen e.g. when the branches have been - // changed but all the neede objects are available locally. + // changed but all the needed objects are available locally. if (git_remote_update_tips(remote, NULL, NULL) < 0) return -1; diff --git a/examples/rev-list.c b/examples/rev-list.c index 5c0d751a3..940a01136 100644 --- a/examples/rev-list.c +++ b/examples/rev-list.c @@ -22,7 +22,7 @@ int main (int argc, char **argv) git_repository *repo; git_revwalk *walk; git_oid oid; - char buf[41]; + char buf[GIT_OID_HEXSZ+1]; git_threads_init(); @@ -32,7 +32,7 @@ int main (int argc, char **argv) while (!git_revwalk_next(&oid, walk)) { git_oid_fmt(buf, &oid); - buf[40] = '\0'; + buf[GIT_OID_HEXSZ] = '\0'; printf("%s\n", buf); } diff --git a/examples/showindex.c b/examples/showindex.c index ad4a16e8e..604124f12 100644 --- a/examples/showindex.c +++ b/examples/showindex.c @@ -20,8 +20,8 @@ int main (int argc, char** argv) unsigned int i, ecount; char *dir = "."; size_t dirlen; - char out[41]; - out[40] = '\0'; + char out[GIT_OID_HEXSZ+1]; + out[GIT_OID_HEXSZ] = '\0'; git_threads_init(); diff --git a/include/git2.h b/include/git2.h index f74976061..baa7fcaf8 100644 --- a/include/git2.h +++ b/include/git2.h @@ -19,6 +19,7 @@ #include "git2/commit.h" #include "git2/common.h" #include "git2/config.h" +#include "git2/describe.h" #include "git2/diff.h" #include "git2/errors.h" #include "git2/filter.h" @@ -32,6 +33,7 @@ #include "git2/notes.h" #include "git2/object.h" #include "git2/odb.h" +#include "git2/odb_backend.h" #include "git2/oid.h" #include "git2/pack.h" #include "git2/patch.h" diff --git a/include/git2/common.h b/include/git2/common.h index 32237efed..ddeaf77a2 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -83,6 +83,8 @@ GIT_BEGIN_DECL */ #define GIT_OID_HEX_ZERO "0000000000000000000000000000000000000000" +#define FLAG_BITS 27 + /** * Return the version of the libgit2 library * being currently used. @@ -136,7 +138,8 @@ typedef enum { GIT_OPT_ENABLE_CACHING, GIT_OPT_GET_CACHED_MEMORY, GIT_OPT_GET_TEMPLATE_PATH, - GIT_OPT_SET_TEMPLATE_PATH + GIT_OPT_SET_TEMPLATE_PATH, + GIT_OPT_SET_SSL_CERT_LOCATIONS, } git_libgit2_opt_t; /** @@ -221,6 +224,17 @@ typedef enum { * > * > - `path` directory of template. * + * * opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, const char *file, const char *path) + * + * > Set the SSL certificate-authority locations. + * > + * > - `file` is the location of a file containing several + * > certificates concatenated together. + * > - `path` is the location of a directory holding several + * > certificates, one per file. + * > + * > Either parameter may be `NULL`, but not both. + * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure diff --git a/include/git2/describe.h b/include/git2/describe.h new file mode 100644 index 000000000..66b88c4fa --- /dev/null +++ b/include/git2/describe.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_describe_h__ +#define INCLUDE_git_describe_h__ + +#include "common.h" +#include "types.h" +#include "buffer.h" + +/** + * @file git2/describe.h + * @brief Git describing routines + * @defgroup git_describe Git describing routines + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Reference lookup strategy + * + * These behave like the --tags and --all optios to git-describe, + * namely they say to look for any reference in either refs/tags/ or + * refs/ respectively. + */ +typedef enum { + GIT_DESCRIBE_DEFAULT, + GIT_DESCRIBE_TAGS, + GIT_DESCRIBE_ALL, +} git_describe_strategy_t; + +/** + * Describe options structure + * + * Initialize with `GIT_DESCRIBE_OPTIONS_INIT` macro to correctly set + * the `version` field. E.g. + * + * git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + */ +typedef struct git_describe_options { + unsigned int version; + + unsigned int max_candidates_tags; /** default: 10 */ + unsigned int describe_strategy; /** default: GIT_DESCRIBE_DEFAULT */ + const char *pattern; + /** + * When calculating the distance from the matching tag or + * reference, only walk down the first-parent ancestry. + */ + int only_follow_first_parent; + /** + * If no matching tag or reference is found, the describe + * operation would normally fail. If this option is set, it + * will instead fall back to showing the full id of the + * commit. + */ + int show_commit_oid_as_fallback; +} git_describe_options; + +#define GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS 10 +#define GIT_DESCRIBE_DEFAULT_ABBREVIATED_SIZE 7 + +#define GIT_DESCRIBE_OPTIONS_VERSION 1 +#define GIT_DESCRIBE_OPTIONS_INIT { \ + GIT_DESCRIBE_OPTIONS_VERSION, \ + GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS, \ +} + +GIT_EXTERN(int) git_describe_init_options(git_describe_options *opts, unsigned int version); + +/** + * Options for formatting the describe string + */ +typedef struct { + unsigned int version; + + /** + * Size of the abbreviated commit id to use. This value is the + * lower bound for the length of the abbreviated string. The + * default is 7. + */ + unsigned int abbreviated_size; + + /** + * Set to use the long format even when a shorter name could be used. + */ + int always_use_long_format; + + /** + * If the workdir is dirty and this is set, this string will + * be appended to the description string. + */ + char *dirty_suffix; +} git_describe_format_options; + +#define GIT_DESCRIBE_FORMAT_OPTIONS_VERSION 1 +#define GIT_DESCRIBE_FORMAT_OPTIONS_INIT { \ + GIT_DESCRIBE_FORMAT_OPTIONS_VERSION, \ + GIT_DESCRIBE_DEFAULT_ABBREVIATED_SIZE, \ + } + +GIT_EXTERN(int) git_describe_init_format_options(git_describe_format_options *opts, unsigned int version); + +typedef struct git_describe_result git_describe_result; + +/** + * Describe a commit + * + * Perform the describe operation on the given committish object. + * + * @param result pointer to store the result. You must free this once + * you're done with it. + * @param committish a committish to describe + * @param opts the lookup options + */ +GIT_EXTERN(int) git_describe_commit( + git_describe_result **result, + git_object *committish, + git_describe_options *opts); + +/** + * Describe a commit + * + * Perform the describe operation on the current commit and the + * worktree. After peforming describe on HEAD, a status is run and the + * description is considered to be dirty if there are. + * + * @param result pointer to store the result. You must free this once + * you're done with it. + * @param repo the repository in which to perform the describe + * @param opts the lookup options + */ +GIT_EXTERN(int) git_describe_workdir( + git_describe_result **out, + git_repository *repo, + git_describe_options *opts); + +/** + * Print the describe result to a buffer + * + * @param result the result from `git_describe_commit()` or + * `git_describe_workdir()`. + * @param opt the formatting options + */ +GIT_EXTERN(int) git_describe_format( + git_buf *out, + const git_describe_result *result, + const git_describe_format_options *opts); + +/** + * Free the describe result. + */ +GIT_EXTERN(void) git_describe_result_free(git_describe_result *result); + +/** @} */ +GIT_END_DECL + +#endif diff --git a/include/git2/errors.h b/include/git2/errors.h index b91560631..1e3ed3acb 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -42,6 +42,7 @@ typedef enum { GIT_ELOCKED = -14, /**< Lock file prevented operation */ GIT_EMODIFIED = -15, /**< Reference value does not match expected */ GIT_EAUTH = -16, /**< Authentication error */ + GIT_ECERTIFICATE = -17, /**< Server certificate is invalid */ GIT_PASSTHROUGH = -30, /**< Internal only */ GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */ @@ -88,6 +89,7 @@ typedef enum { GITERR_REVERT, GITERR_CALLBACK, GITERR_CHERRYPICK, + GITERR_DESCRIBE, } git_error_t; /** diff --git a/include/git2/merge.h b/include/git2/merge.h index bd5ebc1bd..ed1b9a30f 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -352,6 +352,21 @@ GIT_EXTERN(int) git_merge_base_many( const git_oid input_array[]); /** + * Find all merge bases given a list of commits + * + * @param out array in which to store the resulting ids + * @param repo the repository where the commits exist + * @param length The number of commits in the provided `input_array` + * @param input_array oids of the commits + * @return Zero on success; GIT_ENOTFOUND or -1 on failure. + */ +GIT_EXTERN(int) git_merge_bases_many( + git_oidarray *out, + git_repository *repo, + size_t length, + const git_oid input_array[]); + +/** * Find a merge base in preparation for an octopus merge * * @param out the OID of a merge base considering all the commits diff --git a/include/git2/reflog.h b/include/git2/reflog.h index ac42a231c..c949a28f0 100644 --- a/include/git2/reflog.h +++ b/include/git2/reflog.h @@ -102,7 +102,7 @@ GIT_EXTERN(size_t) git_reflog_entrycount(git_reflog *reflog); * equal to 0 (zero) and less than `git_reflog_entrycount()`. * @return the entry; NULL if not found */ -GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(git_reflog *reflog, size_t idx); +GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(const git_reflog *reflog, size_t idx); /** * Remove an entry from the reflog by its index diff --git a/include/git2/remote.h b/include/git2/remote.h index de5823e6d..422c93d38 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -306,9 +306,12 @@ GIT_EXTERN(int) git_remote_ls(const git_remote_head ***out, size_t *size, git_r * The .idx file will be created and both it and the packfile with be * renamed to their final name. * + * @param remote the remote + * @param refspecs the refspecs to use for this negotiation and + * download. Use NULL or an empty array to use the base refspecs * @return 0 or an error code */ -GIT_EXTERN(int) git_remote_download(git_remote *remote); +GIT_EXTERN(int) git_remote_download(git_remote *remote, const git_strarray *refspecs); /** * Check whether the remote is connected @@ -373,6 +376,8 @@ GIT_EXTERN(int) git_remote_update_tips( * disconnect and update the remote-tracking branches. * * @param remote the remote to fetch from + * @param refspecs the refspecs to use for this fetch. Pass NULL or an + * empty array to use the base refspecs. * @param signature The identity to use when updating reflogs * @param reflog_message The message to insert into the reflogs. If NULL, the * default is "fetch" @@ -380,6 +385,7 @@ GIT_EXTERN(int) git_remote_update_tips( */ GIT_EXTERN(int) git_remote_fetch( git_remote *remote, + const git_strarray *refspecs, const git_signature *signature, const char *reflog_message); @@ -408,14 +414,6 @@ GIT_EXTERN(int) git_remote_supported_url(const char* url); GIT_EXTERN(int) git_remote_list(git_strarray *out, git_repository *repo); /** - * Choose whether to check the server's certificate (applies to HTTPS only) - * - * @param remote the remote to configure - * @param check whether to check the server's certificate (defaults to yes) - */ -GIT_EXTERN(void) git_remote_check_cert(git_remote *remote, int check); - -/** * Argument to the completion callback which tells it which operation * finished. */ @@ -456,6 +454,14 @@ struct git_remote_callbacks { git_cred_acquire_cb credentials; /** + * If cert verification fails, this will be called to let the + * user make the final decision of whether to allow the + * connection to proceed. Returns 1 to allow the connection, 0 + * to disallow it or a negative value to indicate an error. + */ + git_transport_certificate_check_cb certificate_check; + + /** * During the download of new data, this will be regularly * called with the current count of progress done by the * indexer. diff --git a/include/git2/reset.h b/include/git2/reset.h index ea7217efe..5f2ba572d 100644 --- a/include/git2/reset.h +++ b/include/git2/reset.h @@ -52,6 +52,10 @@ typedef enum { * * @param reset_type Kind of reset operation to perform. * + * @param checkout_opts Checkout options to be used for a HARD reset. + * The checkout_strategy field will be overridden (based on reset_type). + * This parameter can be used to propagate notify and progress callbacks. + * * @param signature The identity that will used to populate the reflog entry * * @param log_message The one line long message to be appended to the reflog. @@ -65,6 +69,7 @@ GIT_EXTERN(int) git_reset( git_repository *repo, git_object *target, git_reset_t reset_type, + git_checkout_options *checkout_opts, git_signature *signature, const char *log_message); diff --git a/src/hashsig.h b/include/git2/sys/hashsig.h index 8c920cbf1..cd735e1b5 100644 --- a/src/hashsig.h +++ b/include/git2/sys/hashsig.h @@ -4,10 +4,12 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef INCLUDE_hashsig_h__ -#define INCLUDE_hashsig_h__ +#ifndef INCLUDE_sys_hashsig_h__ +#define INCLUDE_sys_hashsig_h__ -#include "common.h" +#include "git2/common.h" + +GIT_BEGIN_DECL /** * Similarity signature of line hashes for a buffer @@ -35,7 +37,7 @@ typedef enum { * @param buflen The length of the data at `buf` * @param generate_pairwise_hashes Should pairwise runs be hashed */ -extern int git_hashsig_create( +GIT_EXTERN(int) git_hashsig_create( git_hashsig **out, const char *buf, size_t buflen, @@ -50,7 +52,7 @@ extern int git_hashsig_create( * This will return an error if the file doesn't contain enough data to * compute a valid signature. */ -extern int git_hashsig_create_fromfile( +GIT_EXTERN(int) git_hashsig_create_fromfile( git_hashsig **out, const char *path, git_hashsig_option_t opts); @@ -58,15 +60,17 @@ extern int git_hashsig_create_fromfile( /** * Release memory for a content similarity signature */ -extern void git_hashsig_free(git_hashsig *sig); +GIT_EXTERN(void) git_hashsig_free(git_hashsig *sig); /** * Measure similarity between two files * * @return <0 for error, [0 to 100] as similarity score */ -extern int git_hashsig_compare( +GIT_EXTERN(int) git_hashsig_compare( const git_hashsig *a, const git_hashsig *b); +GIT_END_DECL + #endif diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index 3b216a287..d943e550f 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -153,6 +153,19 @@ struct git_refdb_backend { * Remove a reflog. */ int (*reflog_delete)(git_refdb_backend *backend, const char *name); + + /** + * Lock a reference. The opaque parameter will be passed to the unlock function + */ + int (*lock)(void **payload_out, git_refdb_backend *backend, const char *refname); + + /** + * Unlock a reference. Only one of target or symbolic_target + * will be set. success indicates whether to update the + * reference or discard the lock (if it's false) + */ + int (*unlock)(git_refdb_backend *backend, void *payload, int success, int update_reflog, + const git_reference *ref, const git_signature *sig, const char *message); }; #define GIT_REFDB_BACKEND_VERSION 1 diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h index 36f8b5836..dd7b22e06 100644 --- a/include/git2/sys/repository.h +++ b/include/git2/sys/repository.h @@ -119,6 +119,19 @@ GIT_EXTERN(void) git_repository_set_refdb(git_repository *repo, git_refdb *refdb */ GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); +/** + * Set a repository to be bare. + * + * Clear the working directory and set core.bare to true. You may also + * want to call `git_repository_set_index(repo, NULL)` since a bare repo + * typically does not have an index, but this function will not do that + * for you. + * + * @param repo Repo to make bare + * @return 0 on success, <0 on failure + */ +GIT_EXTERN(int) git_repository_set_bare(git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index 62ac455d3..1e8f4e4ed 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -23,9 +23,6 @@ GIT_BEGIN_DECL typedef enum { GIT_TRANSPORTFLAGS_NONE = 0, - /* If the connection is secured with SSL/TLS, the authenticity - * of the server certificate should not be verified. */ - GIT_TRANSPORTFLAGS_NO_CHECK_CERT = 1 } git_transport_flags_t; typedef struct git_transport git_transport; @@ -37,6 +34,7 @@ struct git_transport { git_transport *transport, git_transport_message_cb progress_cb, git_transport_message_cb error_cb, + git_transport_certificate_check_cb certificate_check_cb, void *payload); /* Connect the transport to the remote repository, using the given diff --git a/include/git2/transaction.h b/include/git2/transaction.h new file mode 100644 index 000000000..64abb0c69 --- /dev/null +++ b/include/git2/transaction.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_transaction_h__ +#define INCLUDE_git_transaction_h__ + +#include "common.h" +GIT_BEGIN_DECL + +/** + * Create a new transaction object + * + * This does not lock anything, but sets up the transaction object to + * know from which repository to lock. + * + * @param out the resulting transaction + * @param repo the repository in which to lock + * @return 0 or an error code + */ +GIT_EXTERN(int) git_transaction_new(git_transaction **out, git_repository *repo); + +/** + * Lock a reference + * + * Lock the specified reference. This is the first step to updating a + * reference. + * + * @param tx the transaction + * @param refname the reference to lock + * @return 0 or an error message + */ +GIT_EXTERN(int) git_transaction_lock_ref(git_transaction *tx, const char *refname); + +/** + * Set the target of a reference + * + * Set the target of the specified reference. This reference must be + * locked. + * + * @param tx the transaction + * @param refname reference to update + * @param target target to set the reference to + * @param sig signature to use in the reflog; pass NULL to read the identity from the config + * @param msg message to use in the reflog + * @return 0, GIT_ENOTFOUND if the reference is not among the locked ones, or an error code + */ +GIT_EXTERN(int) git_transaction_set_target(git_transaction *tx, const char *refname, const git_oid *target, const git_signature *sig, const char *msg); + +/** + * Set the target of a reference + * + * Set the target of the specified reference. This reference must be + * locked. + * + * @param tx the transaction + * @param refname reference to update + * @param target target to set the reference to + * @param sig signature to use in the reflog; pass NULL to read the identity from the config + * @param msg message to use in the reflog + * @return 0, GIT_ENOTFOUND if the reference is not among the locked ones, or an error code + */ +GIT_EXTERN(int) git_transaction_set_symbolic_target(git_transaction *tx, const char *refname, const char *target, const git_signature *sig, const char *msg); + +/** + * Set the reflog of a reference + * + * Set the specified reference's reflog. If this is combined with + * setting the target, that update won't be written to the reflog. + * + * @param tx the transaction + * @param refname the reference whose reflog to set + * @param reflog the reflog as it should be written out + * @return 0, GIT_ENOTFOUND if the reference is not among the locked ones, or an error code + */ +GIT_EXTERN(int) git_transaction_set_reflog(git_transaction *tx, const char *refname, const git_reflog *reflog); + +/** + * Remove a reference + * + * @param tx the transaction + * @param refname the reference to remove + * @return 0, GIT_ENOTFOUND if the reference is not among the locked ones, or an error code + */ +GIT_EXTERN(int) git_transaction_remove(git_transaction *tx, const char *refname); + +/** + * Commit the changes from the transaction + * + * Perform the changes that have been queued. The updates will be made + * one by one, and the first failure will stop the processing. + * + * @param tx the transaction + * @return 0 or an error code + */ +GIT_EXTERN(int) git_transaction_commit(git_transaction *tx); + +/** + * Free the resources allocated by this transaction + * + * If any references remain locked, they will be unlocked without any + * changes made to them. + * + * @param tx the transaction + */ +GIT_EXTERN(void) git_transaction_free(git_transaction *tx); + +GIT_END_DECL +#endif diff --git a/include/git2/transport.h b/include/git2/transport.h index 7090698ac..39df479c7 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -20,6 +20,67 @@ */ GIT_BEGIN_DECL +/** + * Type of SSH host fingerprint + */ +typedef enum { + /** MD5 is available */ + GIT_CERT_SSH_MD5 = (1 << 0), + /** SHA-1 is available */ + GIT_CERT_SSH_SHA1 = (1 << 1), +} git_cert_ssh_t; + +/** + * Hostkey information taken from libssh2 + */ +typedef struct { + /** + * Type of certificate. Here to share the header with + * `git_cert`. + */ + git_cert_t cert_type; + /** + * A hostkey type from libssh2, either + * `GIT_CERT_SSH_MD5` or `GIT_CERT_SSH_SHA1` + */ + git_cert_ssh_t type; + + /** + * Hostkey hash. If type has `GIT_CERT_SSH_MD5` set, this will + * have the MD5 hash of the hostkey. + */ + unsigned char hash_md5[16]; + + /** + * Hostkey hash. If type has `GIT_CERT_SSH_SHA1` set, this will + * have the SHA-1 hash of the hostkey. + */ + unsigned char hash_sha1[20]; +} git_cert_hostkey; + +/** + * X.509 certificate information + */ +typedef struct { + /** + * Type of certificate. Here to share the header with + * `git_cert`. + */ + git_cert_t cert_type; + /** + * Pointer to the X.509 certificate data + */ + void *data; + /** + * Length of the memory block pointed to by `data`. + */ + size_t len; +} git_cert_x509; + +/* + *** Begin interface for credentials acquisition *** + */ + /** Authentication type requested */ typedef enum { /* git_cred_userpass_plaintext */ diff --git a/include/git2/types.h b/include/git2/types.h index 7ed1bcd4c..64cdfcdda 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -171,6 +171,9 @@ typedef struct git_reference git_reference; /** Iterator for references */ typedef struct git_reference_iterator git_reference_iterator; +/** Transactional interface to references */ +typedef struct git_transaction git_transaction; + /** Merge heads, the input to merge */ typedef struct git_merge_head git_merge_head; @@ -254,6 +257,45 @@ typedef int (*git_transfer_progress_cb)(const git_transfer_progress *stats, void typedef int (*git_transport_message_cb)(const char *str, int len, void *payload); /** + * Type of host certificate structure that is passed to the check callback + */ +typedef enum git_cert_t { + /** + * The `data` argument to the callback will be a pointer to + * the DER-encoded data. + */ + GIT_CERT_X509, + /** + * The `data` argument to the callback will be a pointer to a + * `git_cert_hostkey` structure. + */ + GIT_CERT_HOSTKEY_LIBSSH2, +} git_cert_t; + +/** + * Parent type for `git_cert_hostkey` and `git_cert_x509`. + */ +typedef struct { + /** + * Type of certificate. A `GIT_CERT_` value. + */ + git_cert_t cert_type; +} git_cert; + +/** + * Callback for the user's custom certificate checks. + * + * @param type The type of certificate or host info, SSH or X.509 + * @param data The data for the certificate or host info + * @param len The size of the certificate or host info + * @param valid Whether the libgit2 checks (OpenSSL or WinHTTP) think + * this certificate is valid + * @param host Hostname of the host libgit2 connected to + * @param payload Payload provided by the caller + */ +typedef int (*git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload); + +/** * Opaque structure representing a submodule. */ typedef struct git_submodule git_submodule; diff --git a/script/cibuild.sh b/script/cibuild.sh index e58c0849c..abe31d0dc 100755 --- a/script/cibuild.sh +++ b/script/cibuild.sh @@ -15,7 +15,7 @@ export GITTEST_REMOTE_URL="git://localhost/test.git" mkdir _build cd _build cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS || exit $? -cmake --build . --target install || exit $? +make -j2 install || exit $? ctest -V . || exit $? # Now that we've tested the raw git protocol, let's set up ssh to we @@ -33,6 +33,9 @@ ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q cat ~/.ssh/id_rsa.pub >>~/.ssh/authorized_keys ssh-keyscan -t rsa localhost >>~/.ssh/known_hosts +# Get the fingerprint for localhost and remove the colons so we can parse it as a hex number +export GITTEST_REMOTE_SSH_FINGERPRINT=$(ssh-keygen -F localhost -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':') + export GITTEST_REMOTE_URL="ssh://localhost/$HOME/_temp/test.git" export GITTEST_REMOTE_USER=$USER export GITTEST_REMOTE_SSH_KEY="$HOME/.ssh/id_rsa" @@ -40,6 +43,6 @@ export GITTEST_REMOTE_SSH_PUBKEY="$HOME/.ssh/id_rsa.pub" export GITTEST_REMOTE_SSH_PASSPHRASE="" if [ -e ./libgit2_clar ]; then - ./libgit2_clar -sonline::push -sonline::clone::cred_callback && + ./libgit2_clar -sonline::push -sonline::clone::cred_callback -sonline::clone::ssh_cert && ./libgit2_clar -sonline::clone::ssh_with_paths fi diff --git a/src/attr.c b/src/attr.c index 05b0c1b3c..a02172689 100644 --- a/src/attr.c +++ b/src/attr.c @@ -377,7 +377,7 @@ static int push_attr_file( return error; } -static int push_one_attr(void *ref, git_buf *path) +static int push_one_attr(void *ref, const char *path) { int error = 0, n_src, i; attr_walk_up_info *info = (attr_walk_up_info *)ref; @@ -388,7 +388,7 @@ static int push_one_attr(void *ref, git_buf *path) for (i = 0; !error && i < n_src; ++i) error = push_attr_file( - info->repo, info->files, src[i], path->ptr, GIT_ATTR_FILE); + info->repo, info->files, src[i], path, GIT_ATTR_FILE); return error; } @@ -411,7 +411,7 @@ static int collect_attr_files( const char *path, git_vector *files) { - int error; + int error = 0; git_buf dir = GIT_BUF_INIT; const char *workdir = git_repository_workdir(repo); attr_walk_up_info info = { NULL }; @@ -447,7 +447,11 @@ static int collect_attr_files( giterr_clear(); /* no error even if there is no index */ info.files = files; - error = git_path_walk_up(&dir, workdir, push_one_attr, &info); + if (!strcmp(dir.ptr, ".")) + error = push_one_attr(&info, ""); + else + error = git_path_walk_up(&dir, workdir, push_one_attr, &info); + if (error < 0) goto cleanup; diff --git a/src/cc-compat.h b/src/cc-compat.h index e73cb6de8..0b66d8ba1 100644 --- a/src/cc-compat.h +++ b/src/cc-compat.h @@ -35,6 +35,14 @@ # define GIT_TYPEOF(x) #endif +#if defined(__GNUC__) +# define GIT_ALIGN(x,size) x __attribute__ ((aligned(size))) +#elif defined(_MSC_VER) +# define GIT_ALIGN(x,size) __declspec(align(size)) x +#else +# define GIT_ALIGN(x,size) x +#endif + #define GIT_UNUSED(x) ((void)(x)) /* Define the printf format specifer to use for size_t output */ diff --git a/src/clone.c b/src/clone.c index 43b839003..f18f07611 100644 --- a/src/clone.c +++ b/src/clone.c @@ -358,7 +358,7 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_check git_remote_set_update_fetchhead(remote, 0); git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); - if ((error = git_remote_fetch(remote, signature, git_buf_cstr(&reflog_message))) != 0) + if ((error = git_remote_fetch(remote, NULL, signature, git_buf_cstr(&reflog_message))) != 0) goto cleanup; error = checkout_branch(repo, remote, co_opts, branch, signature, git_buf_cstr(&reflog_message)); @@ -553,7 +553,7 @@ static int clone_local_into(git_repository *repo, git_remote *remote, const git_ git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); - if ((error = git_remote_fetch(remote, signature, git_buf_cstr(&reflog_message))) != 0) + if ((error = git_remote_fetch(remote, NULL, signature, git_buf_cstr(&reflog_message))) != 0) goto cleanup; error = checkout_branch(repo, remote, co_opts, branch, signature, git_buf_cstr(&reflog_message)); diff --git a/src/commit_list.h b/src/commit_list.h index 490d841be..7cd3945ae 100644 --- a/src/commit_list.h +++ b/src/commit_list.h @@ -25,7 +25,7 @@ typedef struct git_commit_list_node { uninteresting:1, topo_delay:1, parsed:1, - flags : 4; + flags : FLAG_BITS; unsigned short in_degree; unsigned short out_degree; diff --git a/src/config_file.c b/src/config_file.c index 7106f18db..8f55c42f3 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1163,7 +1163,7 @@ static int strip_comments(char *line, int in_quotes) } /* skip any space at the end */ - if (ptr > line && git__isspace(ptr[-1])) { + while (ptr > line && git__isspace(ptr[-1])) { ptr--; } ptr[0] = '\0'; diff --git a/src/describe.c b/src/describe.c new file mode 100644 index 000000000..08c99a7d2 --- /dev/null +++ b/src/describe.c @@ -0,0 +1,871 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include "git2/describe.h" +#include "git2/strarray.h" +#include "git2/diff.h" +#include "git2/status.h" + +#include "common.h" +#include "commit.h" +#include "commit_list.h" +#include "oidmap.h" +#include "refs.h" +#include "revwalk.h" +#include "tag.h" +#include "vector.h" +#include "repository.h" + +/* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */ + +struct commit_name { + git_tag *tag; + unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */ + unsigned name_checked:1; + git_oid sha1; + char *path; + + /* Khash workaround. They original key has to still be reachable */ + git_oid peeled; +}; + +static void *oidmap_value_bykey(git_oidmap *map, const git_oid *key) +{ + khint_t pos = git_oidmap_lookup_index(map, key); + + if (!git_oidmap_valid_index(map, pos)) + return NULL; + + return git_oidmap_value_at(map, pos); +} + +static struct commit_name *find_commit_name( + git_oidmap *names, + const git_oid *peeled) +{ + return (struct commit_name *)(oidmap_value_bykey(names, peeled)); +} + +static int replace_name( + git_tag **tag, + git_repository *repo, + struct commit_name *e, + unsigned int prio, + const git_oid *sha1) +{ + git_time_t e_time = 0, t_time = 0; + + if (!e || e->prio < prio) + return 1; + + if (e->prio == 2 && prio == 2) { + /* Multiple annotated tags point to the same commit. + * Select one to keep based upon their tagger date. + */ + git_tag *t = NULL; + + if (!e->tag) { + if (git_tag_lookup(&t, repo, &e->sha1) < 0) + return 1; + e->tag = t; + } + + if (git_tag_lookup(&t, repo, sha1) < 0) + return 0; + + *tag = t; + + if (e->tag->tagger) + e_time = e->tag->tagger->when.time; + + if (t->tagger) + t_time = t->tagger->when.time; + + if (e_time < t_time) + return 1; + } + + return 0; +} + +static int add_to_known_names( + git_repository *repo, + git_oidmap *names, + const char *path, + const git_oid *peeled, + unsigned int prio, + const git_oid *sha1) +{ + struct commit_name *e = find_commit_name(names, peeled); + bool found = (e != NULL); + + git_tag *tag = NULL; + if (replace_name(&tag, repo, e, prio, sha1)) { + if (!found) { + e = git__malloc(sizeof(struct commit_name)); + GITERR_CHECK_ALLOC(e); + + e->path = NULL; + e->tag = NULL; + } + + if (e->tag) + git_tag_free(e->tag); + e->tag = tag; + e->prio = prio; + e->name_checked = 0; + git_oid_cpy(&e->sha1, sha1); + git__free(e->path); + e->path = git__strdup(path); + git_oid_cpy(&e->peeled, peeled); + + if (!found) { + int ret; + + git_oidmap_insert(names, &e->peeled, e, ret); + if (ret < 0) + return -1; + } + } + else + git_tag_free(tag); + + return 0; +} + +static int retrieve_peeled_tag_or_object_oid( + git_oid *peeled_out, + git_oid *ref_target_out, + git_repository *repo, + const char *refname) +{ + git_reference *ref; + git_object *peeled = NULL; + int error; + + if ((error = git_reference_lookup_resolved(&ref, repo, refname, -1)) < 0) + return error; + + if ((error = git_reference_peel(&peeled, ref, GIT_OBJ_ANY)) < 0) + goto cleanup; + + git_oid_cpy(ref_target_out, git_reference_target(ref)); + git_oid_cpy(peeled_out, git_object_id(peeled)); + + if (git_oid_cmp(ref_target_out, peeled_out) != 0) + error = 1; /* The reference was pointing to a annotated tag */ + else + error = 0; /* Any other object */ + +cleanup: + git_reference_free(ref); + git_object_free(peeled); + return error; +} + +struct git_describe_result { + int dirty; + int exact_match; + int fallback_to_id; + git_oid commit_id; + git_repository *repo; + struct commit_name *name; + struct possible_tag *tag; +}; + +struct get_name_data +{ + git_describe_options *opts; + git_repository *repo; + git_oidmap *names; + git_describe_result *result; +}; + +static int commit_name_dup(struct commit_name **out, struct commit_name *in) +{ + struct commit_name *name; + + name = git__malloc(sizeof(struct commit_name)); + GITERR_CHECK_ALLOC(name); + + memcpy(name, in, sizeof(struct commit_name)); + name->tag = NULL; + name->path = NULL; + + if (in->tag && git_object_dup((git_object **) &name->tag, (git_object *) in->tag) < 0) + return -1; + + name->path = git__strdup(in->path); + GITERR_CHECK_ALLOC(name->path); + + *out = name; + return 0; +} + +static int get_name(const char *refname, void *payload) +{ + struct get_name_data *data; + bool is_tag, is_annotated, all; + git_oid peeled, sha1; + unsigned int prio; + int error = 0; + + data = (struct get_name_data *)payload; + is_tag = !git__prefixcmp(refname, GIT_REFS_TAGS_DIR); + all = data->opts->describe_strategy == GIT_DESCRIBE_ALL; + + /* Reject anything outside refs/tags/ unless --all */ + if (!all && !is_tag) + return 0; + + /* Accept only tags that match the pattern, if given */ + if (data->opts->pattern && (!is_tag || p_fnmatch(data->opts->pattern, + refname + strlen(GIT_REFS_TAGS_DIR), 0))) + return 0; + + /* Is it annotated? */ + if ((error = retrieve_peeled_tag_or_object_oid( + &peeled, &sha1, data->repo, refname)) < 0) + return error; + + is_annotated = error; + + /* + * By default, we only use annotated tags, but with --tags + * we fall back to lightweight ones (even without --tags, + * we still remember lightweight ones, only to give hints + * in an error message). --all allows any refs to be used. + */ + if (is_annotated) + prio = 2; + else if (is_tag) + prio = 1; + else + prio = 0; + + add_to_known_names(data->repo, data->names, + all ? refname + strlen(GIT_REFS_DIR) : refname + strlen(GIT_REFS_TAGS_DIR), + &peeled, prio, &sha1); + return 0; +} + +struct possible_tag { + struct commit_name *name; + int depth; + int found_order; + unsigned flag_within; +}; + +static int possible_tag_dup(struct possible_tag **out, struct possible_tag *in) +{ + struct possible_tag *tag; + + tag = git__malloc(sizeof(struct possible_tag)); + GITERR_CHECK_ALLOC(tag); + + memcpy(tag, in, sizeof(struct possible_tag)); + tag->name = NULL; + + if (commit_name_dup(&tag->name, in->name) < 0) + return -1; + + *out = tag; + return 0; +} + +static int compare_pt(const void *a_, const void *b_) +{ + struct possible_tag *a = (struct possible_tag *)a_; + struct possible_tag *b = (struct possible_tag *)b_; + if (a->depth != b->depth) + return a->depth - b->depth; + if (a->found_order != b->found_order) + return a->found_order - b->found_order; + return 0; +} + +#define SEEN (1u << 0) + +static unsigned long finish_depth_computation( + git_pqueue *list, + git_revwalk *walk, + struct possible_tag *best) +{ + unsigned long seen_commits = 0; + int error, i; + + while (git_pqueue_size(list) > 0) { + git_commit_list_node *c = git_pqueue_pop(list); + seen_commits++; + if (c->flags & best->flag_within) { + size_t index = 0; + while (git_pqueue_size(list) > index) { + git_commit_list_node *i = git_pqueue_get(list, index); + if (!(i->flags & best->flag_within)) + break; + index++; + } + if (index > git_pqueue_size(list)) + break; + } else + best->depth++; + for (i = 0; i < c->out_degree; i++) { + git_commit_list_node *p = c->parents[i]; + if ((error = git_commit_list_parse(walk, p)) < 0) + return error; + if (!(p->flags & SEEN)) + if ((error = git_pqueue_insert(list, p)) < 0) + return error; + p->flags |= c->flags; + } + } + return seen_commits; +} + +static int display_name(git_buf *buf, git_repository *repo, struct commit_name *n) +{ + if (n->prio == 2 && !n->tag) { + if (git_tag_lookup(&n->tag, repo, &n->sha1) < 0) { + giterr_set(GITERR_TAG, "Annotated tag '%s' not available", n->path); + return -1; + } + } + + if (n->tag && !n->name_checked) { + if (!git_tag_name(n->tag)) { + giterr_set(GITERR_TAG, "Annotated tag '%s' has no embedded name", n->path); + return -1; + } + + /* TODO: Cope with warnings + if (strcmp(n->tag->tag, all ? n->path + 5 : n->path)) + warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path); + */ + + n->name_checked = 1; + } + + if (n->tag) + git_buf_printf(buf, "%s", git_tag_name(n->tag)); + else + git_buf_printf(buf, "%s", n->path); + + return 0; +} + +static int find_unique_abbrev_size( + int *out, + git_repository *repo, + const git_oid *oid_in, + int abbreviated_size) +{ + size_t size = abbreviated_size; + git_odb *odb; + git_oid dummy; + int error; + + if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) + return error; + + while (size < GIT_OID_HEXSZ) { + if ((error = git_odb_exists_prefix(&dummy, odb, oid_in, size)) == 0) { + *out = (int) size; + return 0; + } + + /* If the error wasn't that it's not unique, then it's a proper error */ + if (error != GIT_EAMBIGUOUS) + return error; + + /* Try again with a larger size */ + size++; + } + + /* If we didn't find any shorter prefix, we have to do the whole thing */ + *out = GIT_OID_HEXSZ; + + return 0; +} + +static int show_suffix( + git_buf *buf, + int depth, + git_repository *repo, + const git_oid* id, + size_t abbrev_size) +{ + int error, size; + + char hex_oid[GIT_OID_HEXSZ]; + + if ((error = find_unique_abbrev_size(&size, repo, id, abbrev_size)) < 0) + return error; + + git_oid_fmt(hex_oid, id); + + git_buf_printf(buf, "-%d-g", depth); + + git_buf_put(buf, hex_oid, size); + + return git_buf_oom(buf) ? -1 : 0; +} + +#define MAX_CANDIDATES_TAGS FLAG_BITS - 1 + +static int describe_not_found(const git_oid *oid, const char *message_format) { + char oid_str[GIT_OID_HEXSZ + 1]; + git_oid_tostr(oid_str, sizeof(oid_str), oid); + + giterr_set(GITERR_DESCRIBE, message_format, oid_str); + return GIT_ENOTFOUND; +} + +static int describe( + struct get_name_data *data, + git_commit *commit) +{ + struct commit_name *n; + struct possible_tag *best; + bool all, tags; + git_revwalk *walk = NULL; + git_pqueue list; + git_commit_list_node *cmit, *gave_up_on = NULL; + git_vector all_matches = GIT_VECTOR_INIT; + unsigned int match_cnt = 0, annotated_cnt = 0, cur_match; + unsigned long seen_commits = 0; /* TODO: Check long */ + unsigned int unannotated_cnt = 0; + int error; + + if (git_vector_init(&all_matches, MAX_CANDIDATES_TAGS, compare_pt) < 0) + return -1; + + if ((error = git_pqueue_init(&list, 0, 2, git_commit_list_time_cmp)) < 0) + goto cleanup; + + all = data->opts->describe_strategy == GIT_DESCRIBE_ALL; + tags = data->opts->describe_strategy == GIT_DESCRIBE_TAGS; + + git_oid_cpy(&data->result->commit_id, git_commit_id(commit)); + + n = find_commit_name(data->names, git_commit_id(commit)); + if (n && (tags || all || n->prio == 2)) { + /* + * Exact match to an existing ref. + */ + data->result->exact_match = 1; + if ((error = commit_name_dup(&data->result->name, n)) < 0) + goto cleanup; + + goto cleanup; + } + + if (!data->opts->max_candidates_tags) { + error = describe_not_found( + git_commit_id(commit), + "Cannot describe - no tag exactly matches '%s'"); + + goto cleanup; + } + + if ((error = git_revwalk_new(&walk, git_commit_owner(commit))) < 0) + goto cleanup; + + if ((cmit = git_revwalk__commit_lookup(walk, git_commit_id(commit))) == NULL) + goto cleanup; + + if ((error = git_commit_list_parse(walk, cmit)) < 0) + goto cleanup; + + cmit->flags = SEEN; + + if ((error = git_pqueue_insert(&list, cmit)) < 0) + goto cleanup; + + while (git_pqueue_size(&list) > 0) + { + int i; + + git_commit_list_node *c = (git_commit_list_node *)git_pqueue_pop(&list); + seen_commits++; + + n = find_commit_name(data->names, &c->oid); + + if (n) { + if (!tags && !all && n->prio < 2) { + unannotated_cnt++; + } else if (match_cnt < data->opts->max_candidates_tags) { + struct possible_tag *t = git__malloc(sizeof(struct commit_name)); + GITERR_CHECK_ALLOC(t); + if ((error = git_vector_insert(&all_matches, t)) < 0) + goto cleanup; + + match_cnt++; + + t->name = n; + t->depth = seen_commits - 1; + t->flag_within = 1u << match_cnt; + t->found_order = match_cnt; + c->flags |= t->flag_within; + if (n->prio == 2) + annotated_cnt++; + } + else { + gave_up_on = c; + break; + } + } + + for (cur_match = 0; cur_match < match_cnt; cur_match++) { + struct possible_tag *t = git_vector_get(&all_matches, cur_match); + if (!(c->flags & t->flag_within)) + t->depth++; + } + + if (annotated_cnt && (git_pqueue_size(&list) == 0)) { + /* + if (debug) { + char oid_str[GIT_OID_HEXSZ + 1]; + git_oid_tostr(oid_str, sizeof(oid_str), &c->oid); + + fprintf(stderr, "finished search at %s\n", oid_str); + } + */ + break; + } + for (i = 0; i < c->out_degree; i++) { + git_commit_list_node *p = c->parents[i]; + if ((error = git_commit_list_parse(walk, p)) < 0) + goto cleanup; + if (!(p->flags & SEEN)) + if ((error = git_pqueue_insert(&list, p)) < 0) + goto cleanup; + p->flags |= c->flags; + + if (data->opts->only_follow_first_parent) + break; + } + } + + if (!match_cnt) { + if (data->opts->show_commit_oid_as_fallback) { + data->result->fallback_to_id = 1; + git_oid_cpy(&data->result->commit_id, &cmit->oid); + + goto cleanup; + } + if (unannotated_cnt) { + error = describe_not_found(git_commit_id(commit), + "Cannot describe - " + "No annotated tags can describe '%s'." + "However, there were unannotated tags."); + goto cleanup; + } + else { + error = describe_not_found(git_commit_id(commit), + "Cannot describe - " + "No tags can describe '%s'."); + goto cleanup; + } + } + + best = (struct possible_tag *)git_vector_get(&all_matches, 0); + + git_vector_sort(&all_matches); + + best = (struct possible_tag *)git_vector_get(&all_matches, 0); + + if (gave_up_on) { + git_pqueue_insert(&list, gave_up_on); + seen_commits--; + } + if ((error = finish_depth_computation( + &list, walk, best)) < 0) + goto cleanup; + + seen_commits += error; + if ((error = possible_tag_dup(&data->result->tag, best)) < 0) + goto cleanup; + + /* + { + static const char *prio_names[] = { + "head", "lightweight", "annotated", + }; + + char oid_str[GIT_OID_HEXSZ + 1]; + + if (debug) { + for (cur_match = 0; cur_match < match_cnt; cur_match++) { + struct possible_tag *t = (struct possible_tag *)git_vector_get(&all_matches, cur_match); + fprintf(stderr, " %-11s %8d %s\n", + prio_names[t->name->prio], + t->depth, t->name->path); + } + fprintf(stderr, "traversed %lu commits\n", seen_commits); + if (gave_up_on) { + git_oid_tostr(oid_str, sizeof(oid_str), &gave_up_on->oid); + fprintf(stderr, + "more than %i tags found; listed %i most recent\n" + "gave up search at %s\n", + data->opts->max_candidates_tags, data->opts->max_candidates_tags, + oid_str); + } + } + } + */ + + git_oid_cpy(&data->result->commit_id, &cmit->oid); + +cleanup: + { + size_t i; + struct possible_tag *match; + git_vector_foreach(&all_matches, i, match) { + git__free(match); + } + } + git_vector_free(&all_matches); + git_pqueue_free(&list); + git_revwalk_free(walk); + return error; +} + +static int normalize_options( + git_describe_options *dst, + const git_describe_options *src) +{ + git_describe_options default_options = GIT_DESCRIBE_OPTIONS_INIT; + if (!src) src = &default_options; + + *dst = *src; + + if (dst->max_candidates_tags > GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS) + dst->max_candidates_tags = GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS; + + return 0; +} + +int git_describe_commit( + git_describe_result **result, + git_object *committish, + git_describe_options *opts) +{ + struct get_name_data data; + struct commit_name *name; + git_commit *commit; + int error = -1; + git_describe_options normalized; + + assert(committish); + + data.result = git__calloc(1, sizeof(git_describe_result)); + GITERR_CHECK_ALLOC(data.result); + data.result->repo = git_object_owner(committish); + + data.opts = opts; + data.repo = git_object_owner(committish); + + if ((error = normalize_options(&normalized, opts)) < 0) + return error; + + GITERR_CHECK_VERSION( + &normalized, + GIT_DESCRIBE_OPTIONS_VERSION, + "git_describe_options"); + + data.names = git_oidmap_alloc(); + GITERR_CHECK_ALLOC(data.names); + + /** TODO: contains to be implemented */ + + if ((error = git_object_peel((git_object **)(&commit), committish, GIT_OBJ_COMMIT)) < 0) + goto cleanup; + + if (git_reference_foreach_name( + git_object_owner(committish), + get_name, &data) < 0) + goto cleanup; + + if (git_oidmap_size(data.names) == 0) { + giterr_set(GITERR_DESCRIBE, "Cannot describe - " + "No reference found, cannot describe anything."); + error = -1; + goto cleanup; + } + + if ((error = describe(&data, commit)) < 0) + goto cleanup; + +cleanup: + git_commit_free(commit); + + git_oidmap_foreach_value(data.names, name, { + git_tag_free(name->tag); + git__free(name->path); + git__free(name); + }); + + git_oidmap_free(data.names); + + if (error < 0) + git_describe_result_free(data.result); + else + *result = data.result; + + return error; +} + +int git_describe_workdir( + git_describe_result **out, + git_repository *repo, + git_describe_options *opts) +{ + int error; + git_oid current_id; + git_status_list *status = NULL; + git_status_options status_opts = GIT_STATUS_OPTIONS_INIT; + git_describe_result *result; + git_object *commit; + + if ((error = git_reference_name_to_id(¤t_id, repo, GIT_HEAD_FILE)) < 0) + return error; + + if ((error = git_object_lookup(&commit, repo, ¤t_id, GIT_OBJ_COMMIT)) < 0) + return error; + + /* The first step is to perform a describe of HEAD, so we can leverage this */ + if ((error = git_describe_commit(&result, commit, opts)) < 0) + goto out; + + if ((error = git_status_list_new(&status, repo, &status_opts)) < 0) + goto out; + + + if (git_status_list_entrycount(status) > 0) + result->dirty = 1; + +out: + git_object_free(commit); + git_status_list_free(status); + + if (error < 0) + git_describe_result_free(result); + else + *out = result; + + return error; +} + +int git_describe_format(git_buf *out, const git_describe_result *result, const git_describe_format_options *opts) +{ + int error; + git_repository *repo; + struct commit_name *name; + + assert(out && result); + + GITERR_CHECK_VERSION(opts, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION, "git_describe_format_options"); + git_buf_sanitize(out); + + + if (opts->always_use_long_format && opts->abbreviated_size == 0) { + giterr_set(GITERR_DESCRIBE, "Cannot describe - " + "'always_use_long_format' is incompatible with a zero" + "'abbreviated_size'"); + return -1; + } + + + repo = result->repo; + + /* If we did find an exact match, then it's the easier method */ + if (result->exact_match) { + name = result->name; + if ((error = display_name(out, repo, name)) < 0) + return error; + + if (opts->always_use_long_format) { + const git_oid *id = name->tag ? git_tag_target_id(name->tag) : &result->commit_id; + if ((error = show_suffix(out, 0, repo, id, opts->abbreviated_size)) < 0) + return error; + } + + if (result->dirty && opts->dirty_suffix) + git_buf_puts(out, opts->dirty_suffix); + + return git_buf_oom(out) ? -1 : 0; + } + + /* If we didn't find *any* tags, we fall back to the commit's id */ + if (result->fallback_to_id) { + char hex_oid[GIT_OID_HEXSZ + 1] = {0}; + int size; + if ((error = find_unique_abbrev_size( + &size, repo, &result->commit_id, opts->abbreviated_size)) < 0) + return -1; + + git_oid_fmt(hex_oid, &result->commit_id); + git_buf_put(out, hex_oid, size); + + if (result->dirty && opts->dirty_suffix) + git_buf_puts(out, opts->dirty_suffix); + + return git_buf_oom(out) ? -1 : 0; + } + + /* Lastly, if we found a matching tag, we show that */ + name = result->tag->name; + + if ((error = display_name(out, repo, name)) < 0) + return error; + + if (opts->abbreviated_size) { + if ((error = show_suffix(out, result->tag->depth, repo, + &result->commit_id, opts->abbreviated_size)) < 0) + return error; + } + + if (result->dirty && opts->dirty_suffix) { + git_buf_puts(out, opts->dirty_suffix); + } + + return git_buf_oom(out) ? -1 : 0; +} + +void git_describe_result_free(git_describe_result *result) +{ + if (result == NULL) + return; + + if (result->name) { + git_tag_free(result->name->tag); + git__free(result->name->path); + git__free(result->name); + } + + if (result->tag) { + git_tag_free(result->tag->name->tag); + git__free(result->tag->name->path); + git__free(result->tag->name); + git__free(result->tag); + } + + git__free(result); +} + +int git_describe_init_options(git_describe_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_describe_options, GIT_DESCRIBE_OPTIONS_INIT); + return 0; +} + +int git_describe_init_format_options(git_describe_format_options *opts, unsigned int version) +{ + GIT_INIT_STRUCTURE_FROM_TEMPLATE( + opts, version, git_describe_format_options, GIT_DESCRIBE_FORMAT_OPTIONS_INIT); + return 0; +} diff --git a/src/diff_patch.c b/src/diff_patch.c index 8e90efceb..317dbeabb 100644 --- a/src/diff_patch.c +++ b/src/diff_patch.c @@ -273,6 +273,7 @@ int git_diff_foreach( return error; memset(&xo, 0, sizeof(xo)); + memset(&patch, 0, sizeof(patch)); diff_output_init( &xo.output, &diff->opts, file_cb, hunk_cb, data_cb, payload); git_xdiff_init(&xo, &diff->opts); diff --git a/src/diff_tform.c b/src/diff_tform.c index 423a0ca33..9ebce06a0 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -8,9 +8,9 @@ #include "git2/config.h" #include "git2/blob.h" +#include "git2/sys/hashsig.h" #include "diff.h" -#include "hashsig.h" #include "path.h" #include "fileops.h" #include "config.h" diff --git a/src/fileops.c b/src/fileops.c index 34659ad3b..bd9d27c7a 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -505,15 +505,15 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) return error; } -static int futils__rmdir_empty_parent(void *opaque, git_buf *path) +static int futils__rmdir_empty_parent(void *opaque, const char *path) { futils__rmdir_data *data = opaque; int error = 0; - if (git_buf_len(path) <= data->baselen) + if (strlen(path) <= data->baselen) error = GIT_ITEROVER; - else if (p_rmdir(git_buf_cstr(path)) < 0) { + else if (p_rmdir(path) < 0) { int en = errno; if (en == ENOENT || en == ENOTDIR) { @@ -521,7 +521,7 @@ static int futils__rmdir_empty_parent(void *opaque, git_buf *path) } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { error = GIT_ITEROVER; } else { - error = git_path_set_error(errno, git_buf_cstr(path), "rmdir"); + error = git_path_set_error(errno, path, "rmdir"); } } diff --git a/src/filter.c b/src/filter.c index b9e4f9ec8..b5a8bdd66 100644 --- a/src/filter.c +++ b/src/filter.c @@ -38,7 +38,7 @@ struct git_filter_list { }; typedef struct { - const char *filter_name; + char *filter_name; git_filter *filter; int priority; int initialized; @@ -75,6 +75,7 @@ static void filter_registry_shutdown(void) fdef->initialized = false; } + git__free(fdef->filter_name); git__free(fdef->attrdata); git__free(fdef); } @@ -230,6 +231,8 @@ int git_filter_register( size_t nattr = 0, nmatch = 0; git_buf attrs = GIT_BUF_INIT; + assert(name && filter); + if (filter_registry_initialize() < 0) return -1; @@ -246,7 +249,9 @@ int git_filter_register( sizeof(git_filter_def) + 2 * nattr * sizeof(char *), 1); GITERR_CHECK_ALLOC(fdef); - fdef->filter_name = name; + fdef->filter_name = git__strdup(name); + GITERR_CHECK_ALLOC(fdef->filter_name); + fdef->filter = filter; fdef->priority = priority; fdef->nattrs = nattr; @@ -256,6 +261,7 @@ int git_filter_register( filter_def_set_attrs(fdef); if (git_vector_insert(&git__filter_registry->filters, fdef) < 0) { + git__free(fdef->filter_name); git__free(fdef->attrdata); git__free(fdef); return -1; @@ -270,6 +276,8 @@ int git_filter_unregister(const char *name) size_t pos; git_filter_def *fdef; + assert(name); + /* cannot unregister default filters */ if (!strcmp(GIT_FILTER_CRLF, name) || !strcmp(GIT_FILTER_IDENT, name)) { giterr_set(GITERR_FILTER, "Cannot unregister filter '%s'", name); @@ -288,6 +296,7 @@ int git_filter_unregister(const char *name) fdef->initialized = false; } + git__free(fdef->filter_name); git__free(fdef->attrdata); git__free(fdef); diff --git a/src/global.c b/src/global.c index f89c73256..4a0b680ef 100644 --- a/src/global.c +++ b/src/global.c @@ -223,6 +223,9 @@ int init_error = 0; static void cb__free_status(void *st) { + git_global_st *state = (git_global_st *) st; + git__free(state->error_t.message); + git__free(st); } diff --git a/src/global.h b/src/global.h index 106504628..a89a8d6ab 100644 --- a/src/global.h +++ b/src/global.h @@ -7,13 +7,14 @@ #ifndef INCLUDE_global_h__ #define INCLUDE_global_h__ +#include "common.h" #include "mwindow.h" #include "hash.h" typedef struct { git_error *last_error; git_error error_t; - char oid_fmt[41]; + char oid_fmt[GIT_OID_HEXSZ+1]; } git_global_st; #ifdef GIT_SSL diff --git a/src/hashsig.c b/src/hashsig.c index 109f966ba..a6d5f2041 100644 --- a/src/hashsig.c +++ b/src/hashsig.c @@ -4,7 +4,7 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ -#include "hashsig.h" +#include "git2/sys/hashsig.h" #include "fileops.h" #include "util.h" diff --git a/src/ignore.c b/src/ignore.c index 78f01ac44..520bcfe41 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -91,11 +91,11 @@ static int push_ignore_file( return error; } -static int push_one_ignore(void *payload, git_buf *path) +static int push_one_ignore(void *payload, const char *path) { git_ignores *ign = payload; ign->depth++; - return push_ignore_file(ign, &ign->ign_path, path->ptr, GIT_IGNORE_FILE); + return push_ignore_file(ign, &ign->ign_path, path, GIT_IGNORE_FILE); } static int get_internal_ignores(git_attr_file **out, git_repository *repo) diff --git a/src/index.c b/src/index.c index b63a0bec6..8b757f269 100644 --- a/src/index.c +++ b/src/index.c @@ -1767,35 +1767,42 @@ static size_t read_entry( git_index_entry **out, const void *buffer, size_t buffer_size) { size_t path_length, entry_size; - uint16_t flags_raw; const char *path_ptr; - const struct entry_short *source = buffer; + struct entry_short source; git_index_entry entry = {{0}}; if (INDEX_FOOTER_SIZE + minimal_entry_size > buffer_size) return 0; - entry.ctime.seconds = (git_time_t)ntohl(source->ctime.seconds); - entry.ctime.nanoseconds = ntohl(source->ctime.nanoseconds); - entry.mtime.seconds = (git_time_t)ntohl(source->mtime.seconds); - entry.mtime.nanoseconds = ntohl(source->mtime.nanoseconds); - entry.dev = ntohl(source->dev); - entry.ino = ntohl(source->ino); - entry.mode = ntohl(source->mode); - entry.uid = ntohl(source->uid); - entry.gid = ntohl(source->gid); - entry.file_size = ntohl(source->file_size); - git_oid_cpy(&entry.id, &source->oid); - entry.flags = ntohs(source->flags); + /* buffer is not guaranteed to be aligned */ + memcpy(&source, buffer, sizeof(struct entry_short)); + + entry.ctime.seconds = (git_time_t)ntohl(source.ctime.seconds); + entry.ctime.nanoseconds = ntohl(source.ctime.nanoseconds); + entry.mtime.seconds = (git_time_t)ntohl(source.mtime.seconds); + entry.mtime.nanoseconds = ntohl(source.mtime.nanoseconds); + entry.dev = ntohl(source.dev); + entry.ino = ntohl(source.ino); + entry.mode = ntohl(source.mode); + entry.uid = ntohl(source.uid); + entry.gid = ntohl(source.gid); + entry.file_size = ntohl(source.file_size); + git_oid_cpy(&entry.id, &source.oid); + entry.flags = ntohs(source.flags); if (entry.flags & GIT_IDXENTRY_EXTENDED) { - const struct entry_long *source_l = (const struct entry_long *)source; - path_ptr = source_l->path; + uint16_t flags_raw; + size_t flags_offset; - flags_raw = ntohs(source_l->flags_extended); - memcpy(&entry.flags_extended, &flags_raw, 2); + flags_offset = offsetof(struct entry_long, flags_extended); + memcpy(&flags_raw, (const char *) buffer + flags_offset, + sizeof(flags_raw)); + flags_raw = ntohs(flags_raw); + + memcpy(&entry.flags_extended, &flags_raw, sizeof(flags_raw)); + path_ptr = (const char *) buffer + offsetof(struct entry_long, path); } else - path_ptr = source->path; + path_ptr = (const char *) buffer + offsetof(struct entry_short, path); path_length = entry.flags & GIT_IDXENTRY_NAMEMASK; @@ -1846,14 +1853,12 @@ static int read_header(struct index_header *dest, const void *buffer) static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size) { - const struct index_extension *source; struct index_extension dest; size_t total_size; - source = (const struct index_extension *)(buffer); - - memcpy(dest.signature, source->signature, 4); - dest.extension_size = ntohl(source->extension_size); + /* buffer is not guaranteed to be aligned */ + memcpy(&dest, buffer, sizeof(struct index_extension)); + dest.extension_size = ntohl(dest.extension_size); total_size = dest.extension_size + sizeof(struct index_extension); diff --git a/src/merge.c b/src/merge.c index 926a600cc..8252f6767 100644 --- a/src/merge.c +++ b/src/merge.c @@ -22,7 +22,6 @@ #include "tree.h" #include "merge_file.h" #include "blob.h" -#include "hashsig.h" #include "oid.h" #include "index.h" #include "filebuf.h" @@ -42,6 +41,7 @@ #include "git2/tree.h" #include "git2/oidarray.h" #include "git2/sys/index.h" +#include "git2/sys/hashsig.h" #define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) #define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode) @@ -62,16 +62,14 @@ struct merge_diff_df_data { /* Merge base computation */ -int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]) +int merge_bases_many(git_commit_list **out, git_revwalk **walk_out, git_repository *repo, size_t length, const git_oid input_array[]) { - git_revwalk *walk; + git_revwalk *walk = NULL; git_vector list; git_commit_list *result = NULL; + git_commit_list_node *commit; int error = -1; unsigned int i; - git_commit_list_node *commit; - - assert(out && repo && input_array); if (length < 2) { giterr_set(GITERR_INVALID, "At least two commits are required to find an ancestor. Provided 'length' was %u.", length); @@ -82,37 +80,92 @@ int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const return -1; if (git_revwalk_new(&walk, repo) < 0) - goto cleanup; + goto on_error; for (i = 1; i < length; i++) { commit = git_revwalk__commit_lookup(walk, &input_array[i]); if (commit == NULL) - goto cleanup; + goto on_error; git_vector_insert(&list, commit); } commit = git_revwalk__commit_lookup(walk, &input_array[0]); if (commit == NULL) - goto cleanup; + goto on_error; if (git_merge__bases_many(&result, walk, commit, &list) < 0) - goto cleanup; + goto on_error; if (!result) { giterr_set(GITERR_MERGE, "No merge base found"); error = GIT_ENOTFOUND; - goto cleanup; + goto on_error; } + *out = result; + *walk_out = walk; + + git_vector_free(&list); + return 0; + +on_error: + git_vector_free(&list); + git_revwalk_free(walk); + return error; +} + +int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]) +{ + git_revwalk *walk; + git_commit_list *result = NULL; + int error = 0; + + assert(out && repo && input_array); + + if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0) + return error; + git_oid_cpy(out, &result->item->oid); - error = 0; + git_commit_list_free(&result); + git_revwalk_free(walk); + + return 0; +} + +int git_merge_bases_many(git_oidarray *out, git_repository *repo, size_t length, const git_oid input_array[]) +{ + git_revwalk *walk; + git_commit_list *list, *result = NULL; + int error = 0; + git_array_oid_t array; + + assert(out && repo && input_array); + + if ((error = merge_bases_many(&result, &walk, repo, length, input_array)) < 0) + return error; + + git_array_init(array); + + list = result; + while (list) { + git_oid *id = git_array_alloc(array); + if (id == NULL) { + error = -1; + goto cleanup; + } + + git_oid_cpy(id, &list->item->oid); + list = list->next; + } + + git_oidarray__from_array(out, &array); cleanup: git_commit_list_free(&result); git_revwalk_free(walk); - git_vector_free(&list); + return error; } @@ -2338,7 +2391,6 @@ done: static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths) { - git_index *index_repo = NULL; git_diff *wd_diff_list = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; int error = 0; @@ -2347,6 +2399,16 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde *conflicts = 0; + /* We need to have merged at least 1 file for the possibility to exist to + * have conflicts with the workdir. Passing 0 as the pathspec count paramter + * will consider all files in the working directory, that is, we may detect + * a conflict if there were untracked files in the workdir prior to starting + * the merge. This typically happens when cherry-picking a commmit whose + * changes have already been applied. + */ + if (merged_paths->length == 0) + return 0; + opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; /* Workdir changes may exist iff they do not conflict with changes that @@ -2356,13 +2418,12 @@ static int merge_check_workdir(size_t *conflicts, git_repository *repo, git_inde opts.pathspec.count = merged_paths->length; opts.pathspec.strings = (char **)merged_paths->contents; - if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, index_repo, &opts)) < 0) + if ((error = git_diff_index_to_workdir(&wd_diff_list, repo, NULL, &opts)) < 0) goto done; *conflicts = wd_diff_list->deltas.length; done: - git_index_free(index_repo); git_diff_free(wd_diff_list); return error; diff --git a/src/netops.c b/src/netops.c index fceb4fb74..adbae61c4 100644 --- a/src/netops.c +++ b/src/netops.c @@ -384,10 +384,10 @@ on_error: cert_fail_name: OPENSSL_free(peer_cn); giterr_set(GITERR_SSL, "hostname does not match certificate"); - return -1; + return GIT_ECERTIFICATE; } -static int ssl_setup(gitno_socket *socket, const char *host, int flags) +static int ssl_setup(gitno_socket *socket, const char *host) { int ret; @@ -406,9 +406,6 @@ static int ssl_setup(gitno_socket *socket, const char *host, int flags) if ((ret = SSL_connect(socket->ssl.ssl)) <= 0) return ssl_set_error(&socket->ssl, ret); - if (GITNO_CONNECT_SSL_NO_CHECK_CERT & flags) - return 0; - return verify_server_cert(&socket->ssl, host); } #endif @@ -461,7 +458,7 @@ int gitno_connect(gitno_socket *s_out, const char *host, const char *port, int f hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; - if ((ret = p_getaddrinfo(host, port, &hints, &info)) < 0) { + if ((ret = p_getaddrinfo(host, port, &hints, &info)) != 0) { giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, p_gai_strerror(ret)); return -1; @@ -494,8 +491,9 @@ int gitno_connect(gitno_socket *s_out, const char *host, const char *port, int f p_freeaddrinfo(info); #ifdef GIT_SSL - if ((flags & GITNO_CONNECT_SSL) && ssl_setup(s_out, host, flags) < 0) - return -1; + if ((flags & GITNO_CONNECT_SSL) && + (ret = ssl_setup(s_out, host)) < 0) + return ret; #else /* SSL is not supported */ if (flags & GITNO_CONNECT_SSL) { diff --git a/src/netops.h b/src/netops.h index 75113fc7f..8ad915301 100644 --- a/src/netops.h +++ b/src/netops.h @@ -41,10 +41,6 @@ typedef struct gitno_buffer { enum { /* Attempt to create an SSL connection. */ GITNO_CONNECT_SSL = 1, - - /* Valid only when GITNO_CONNECT_SSL is also specified. - * Indicates that the server certificate should not be validated. */ - GITNO_CONNECT_SSL_NO_CHECK_CERT = 2, }; /** diff --git a/src/odb_loose.c b/src/odb_loose.c index b2e8bed4d..ef6de41a9 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -714,7 +714,7 @@ struct foreach_state { GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) { int v, i = 0; - if (strlen(ptr) != 41) + if (strlen(ptr) != GIT_OID_HEXSZ+1) return -1; if (ptr[2] != '/') { diff --git a/src/oidmap.h b/src/oidmap.h index a29c7cd35..b871a7926 100644 --- a/src/oidmap.h +++ b/src/oidmap.h @@ -32,4 +32,20 @@ GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) #define git_oidmap_alloc() kh_init(oid) #define git_oidmap_free(h) kh_destroy(oid,h), h = NULL +#define git_oidmap_lookup_index(h, k) kh_get(oid, h, k) +#define git_oidmap_valid_index(h, idx) (idx != kh_end(h)) + +#define git_oidmap_value_at(h, idx) kh_val(h, idx) + +#define git_oidmap_insert(h, key, val, rval) do { \ + khiter_t __pos = kh_put(oid, h, key, &rval); \ + if (rval >= 0) { \ + if (rval == 0) kh_key(h, __pos) = key; \ + kh_val(h, __pos) = val; \ + } } while (0) + +#define git_oidmap_foreach_value kh_foreach_value + +#define git_oidmap_size(h) kh_size(h) + #endif diff --git a/src/pack.c b/src/pack.c index 7c1cfe03e..516e0f3ca 100644 --- a/src/pack.c +++ b/src/pack.c @@ -620,7 +620,7 @@ int git_packfile_unpack( struct pack_chain_elem *elem = NULL, *stack; git_pack_cache_entry *cached = NULL; struct pack_chain_elem small_stack[SMALL_STACK_SIZE]; - size_t stack_size, elem_pos; + size_t stack_size = 0, elem_pos; git_otype base_type; /* diff --git a/src/path.c b/src/path.c index d29b992fe..21b6e18d6 100644 --- a/src/path.c +++ b/src/path.c @@ -417,7 +417,7 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url) int git_path_walk_up( git_buf *path, const char *ceiling, - int (*cb)(void *data, git_buf *), + int (*cb)(void *data, const char *), void *data) { int error = 0; @@ -435,12 +435,20 @@ int git_path_walk_up( } scan = git_buf_len(path); + /* empty path: yield only once */ + if (!scan) { + error = cb(data, ""); + if (error) + giterr_set_after_callback(error); + return error; + } + iter.ptr = path->ptr; iter.size = git_buf_len(path); iter.asize = path->asize; while (scan >= stop) { - error = cb(data, &iter); + error = cb(data, iter.ptr); iter.ptr[scan] = oldc; if (error) { @@ -460,6 +468,13 @@ int git_path_walk_up( if (scan >= 0) iter.ptr[scan] = oldc; + /* relative path: yield for the last component */ + if (!error && stop == 0 && iter.ptr[0] != '/') { + error = cb(data, ""); + if (error) + giterr_set_after_callback(error); + } + return error; } @@ -753,7 +768,7 @@ int git_path_cmp( int git_path_make_relative(git_buf *path, const char *parent) { const char *p, *q, *p_dirsep, *q_dirsep; - size_t plen = path->size, newlen, depth = 1, i; + size_t plen = path->size, newlen, depth = 1, i, offset; for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) { if (*p == '/' && *q == '/') { @@ -793,8 +808,11 @@ int git_path_make_relative(git_buf *path, const char *parent) newlen = (depth * 3) + plen; + /* save the offset as we might realllocate the pointer */ + offset = p - path->ptr; if (git_buf_try_grow(path, newlen + 1, 1, 0) < 0) return -1; + p = path->ptr + offset; memmove(path->ptr + (depth * 3), p, plen + 1); @@ -965,7 +983,7 @@ int git_path_direach( path_dirent_data de_data; struct dirent *de, *de_buf = (struct dirent *)&de_data; - (void)flags; + GIT_UNUSED(flags); #ifdef GIT_USE_ICONV git_path_iconv_t ic = GIT_PATH_ICONV_INIT; @@ -1036,7 +1054,7 @@ int git_path_dirload( path_dirent_data de_data; struct dirent *de, *de_buf = (struct dirent *)&de_data; - (void)flags; + GIT_UNUSED(flags); #ifdef GIT_USE_ICONV git_path_iconv_t ic = GIT_PATH_ICONV_INIT; @@ -1088,8 +1106,10 @@ int git_path_dirload( entry_path[path_len] = '/'; memcpy(&entry_path[path_len + need_slash], de_path, de_len); - if ((error = git_vector_insert(contents, entry_path)) < 0) + if ((error = git_vector_insert(contents, entry_path)) < 0) { + git__free(entry_path); break; + } } closedir(dir); diff --git a/src/path.h b/src/path.h index d0a9de707..11bb6d173 100644 --- a/src/path.h +++ b/src/path.h @@ -323,7 +323,7 @@ extern int git_path_cmp( extern int git_path_walk_up( git_buf *pathbuf, const char *ceiling, - int (*callback)(void *payload, git_buf *path), + int (*callback)(void *payload, const char *path), void *payload); /** diff --git a/src/pool.c b/src/pool.c index a516ff9eb..30555273e 100644 --- a/src/pool.c +++ b/src/pool.c @@ -7,7 +7,7 @@ struct git_pool_page { git_pool_page *next; uint32_t size; uint32_t avail; - char data[GIT_FLEX_ARRAY]; + GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8); }; struct pool_freelist { diff --git a/src/posix.c b/src/posix.c index 7aeb0e6c1..21b049e1b 100644 --- a/src/posix.c +++ b/src/posix.c @@ -151,15 +151,14 @@ int p_rename(const char *from, const char *to) #endif /* GIT_WIN32 */ -int p_read(git_file fd, void *buf, size_t cnt) +ssize_t p_read(git_file fd, void *buf, size_t cnt) { char *b = buf; while (cnt) { ssize_t r; #ifdef GIT_WIN32 - assert((size_t)((unsigned int)cnt) == cnt); - r = read(fd, b, (unsigned int)cnt); + r = read(fd, b, cnt > INT_MAX ? INT_MAX : (unsigned int)cnt); #else r = read(fd, b, cnt); #endif @@ -173,7 +172,7 @@ int p_read(git_file fd, void *buf, size_t cnt) cnt -= r; b += r; } - return (int)(b - (char *)buf); + return (b - (char *)buf); } int p_write(git_file fd, const void *buf, size_t cnt) diff --git a/src/posix.h b/src/posix.h index 9ef348739..71c403c2f 100644 --- a/src/posix.h +++ b/src/posix.h @@ -97,7 +97,7 @@ typedef int git_file; * Use your manpages to check the docs on these. */ -extern int p_read(git_file fd, void *buf, size_t cnt); +extern ssize_t p_read(git_file fd, void *buf, size_t cnt); extern int p_write(git_file fd, const void *buf, size_t cnt); #define p_close(fd) close(fd) diff --git a/src/refdb.c b/src/refdb.c index 69bf74734..16fb519a6 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -242,3 +242,22 @@ int git_refdb_init_backend(git_refdb_backend *backend, unsigned int version) backend, version, git_refdb_backend, GIT_REFDB_BACKEND_INIT); return 0; } + +int git_refdb_lock(void **payload, git_refdb *db, const char *refname) +{ + assert(payload && db && refname); + + if (!db->backend->lock) { + giterr_set(GITERR_REFERENCE, "backend does not support locking"); + return -1; + } + + return db->backend->lock(payload, db->backend, refname); +} + +int git_refdb_unlock(git_refdb *db, void *payload, int success, int update_reflog, const git_reference *ref, const git_signature *sig, const char *message) +{ + assert(db); + + return db->backend->unlock(db->backend, payload, success, update_reflog, ref, sig, message); +} diff --git a/src/refdb.h b/src/refdb.h index cbad86faf..4ee3b8065 100644 --- a/src/refdb.h +++ b/src/refdb.h @@ -51,6 +51,7 @@ int git_refdb_reflog_write(git_reflog *reflog); int git_refdb_has_log(git_refdb *db, const char *refname); int git_refdb_ensure_log(git_refdb *refdb, const char *refname); - +int git_refdb_lock(void **payload, git_refdb *db, const char *refname); +int git_refdb_unlock(git_refdb *db, void *payload, int success, int update_reflog, const git_reference *ref, const git_signature *sig, const char *message); #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 0e36ca8ac..f39ba4f9c 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -745,6 +745,57 @@ static int loose_commit(git_filebuf *file, const git_reference *ref) return git_filebuf_commit(file); } +static int refdb_fs_backend__lock(void **out, git_refdb_backend *_backend, const char *refname) +{ + int error; + git_filebuf *lock; + refdb_fs_backend *backend = (refdb_fs_backend *) _backend; + + lock = git__calloc(1, sizeof(git_filebuf)); + GITERR_CHECK_ALLOC(lock); + + if ((error = loose_lock(lock, backend, refname)) < 0) { + git__free(lock); + return error; + } + + *out = lock; + return 0; +} + +static int refdb_fs_backend__write_tail( + git_refdb_backend *_backend, + const git_reference *ref, + git_filebuf *file, + int update_reflog, + const git_signature *who, + const char *message, + const git_oid *old_id, + const char *old_target); + +static int refdb_fs_backend__delete_tail( + git_refdb_backend *_backend, + git_filebuf *file, + const char *ref_name, + const git_oid *old_id, const char *old_target); + +static int refdb_fs_backend__unlock(git_refdb_backend *backend, void *payload, int success, int update_reflog, + const git_reference *ref, const git_signature *sig, const char *message) +{ + git_filebuf *lock = (git_filebuf *) payload; + int error = 0; + + if (success == 2) + error = refdb_fs_backend__delete_tail(backend, lock, ref->name, NULL, NULL); + else if (success) + error = refdb_fs_backend__write_tail(backend, ref, lock, update_reflog, sig, message, NULL, NULL); + else + git_filebuf_cleanup(lock); + + git__free(lock); + return error; +} + /* * Find out what object this reference resolves to. * @@ -1063,7 +1114,6 @@ cleanup: return error; } - static int refdb_fs_backend__write( git_refdb_backend *_backend, const git_reference *ref, @@ -1075,9 +1125,7 @@ static int refdb_fs_backend__write( { refdb_fs_backend *backend = (refdb_fs_backend *)_backend; git_filebuf file = GIT_FILEBUF_INIT; - int error = 0, cmp = 0, should_write; - const char *new_target = NULL; - const git_oid *new_id = NULL; + int error = 0; assert(backend); @@ -1089,6 +1137,24 @@ static int refdb_fs_backend__write( if ((error = loose_lock(&file, backend, ref->name)) < 0) return error; + return refdb_fs_backend__write_tail(_backend, ref, &file, true, who, message, old_id, old_target); +} + +static int refdb_fs_backend__write_tail( + git_refdb_backend *_backend, + const git_reference *ref, + git_filebuf *file, + int update_reflog, + const git_signature *who, + const char *message, + const git_oid *old_id, + const char *old_target) +{ + refdb_fs_backend *backend = (refdb_fs_backend *)_backend; + int error = 0, cmp = 0, should_write; + const char *new_target = NULL; + const git_oid *new_id = NULL; + if ((error = cmp_old_ref(&cmp, _backend, ref->name, old_id, old_target)) < 0) goto on_error; @@ -1113,20 +1179,22 @@ static int refdb_fs_backend__write( goto on_error; /* not really error */ } - if ((error = should_write_reflog(&should_write, backend->repo, ref->name)) < 0) - goto on_error; - - if (should_write) { - if ((error = reflog_append(backend, ref, NULL, NULL, who, message)) < 0) - goto on_error; - if ((error = maybe_append_head(backend, ref, who, message)) < 0) + if (update_reflog) { + if ((error = should_write_reflog(&should_write, backend->repo, ref->name)) < 0) goto on_error; + + if (should_write) { + if ((error = reflog_append(backend, ref, NULL, NULL, who, message)) < 0) + goto on_error; + if ((error = maybe_append_head(backend, ref, who, message)) < 0) + goto on_error; + } } - return loose_commit(&file, ref); + return loose_commit(file, ref); on_error: - git_filebuf_cleanup(&file); + git_filebuf_cleanup(file); return error; } @@ -1136,17 +1204,29 @@ static int refdb_fs_backend__delete( const git_oid *old_id, const char *old_target) { refdb_fs_backend *backend = (refdb_fs_backend *)_backend; - git_buf loose_path = GIT_BUF_INIT; - size_t pack_pos; git_filebuf file = GIT_FILEBUF_INIT; - int error = 0, cmp = 0; - bool loose_deleted = 0; + int error = 0; assert(backend && ref_name); if ((error = loose_lock(&file, backend, ref_name)) < 0) return error; + return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target); +} + +static int refdb_fs_backend__delete_tail( + git_refdb_backend *_backend, + git_filebuf *file, + const char *ref_name, + const git_oid *old_id, const char *old_target) +{ + refdb_fs_backend *backend = (refdb_fs_backend *)_backend; + git_buf loose_path = GIT_BUF_INIT; + size_t pack_pos; + int error = 0, cmp = 0; + bool loose_deleted = 0; + error = cmp_old_ref(&cmp, _backend, ref_name, old_id, old_target); if (error < 0) goto cleanup; @@ -1192,7 +1272,7 @@ static int refdb_fs_backend__delete( error = packed_write(backend); cleanup: - git_filebuf_cleanup(&file); + git_filebuf_cleanup(file); return error; } @@ -1837,6 +1917,8 @@ int git_refdb_backend_fs( backend->parent.del = &refdb_fs_backend__delete; backend->parent.rename = &refdb_fs_backend__rename; backend->parent.compress = &refdb_fs_backend__compress; + backend->parent.lock = &refdb_fs_backend__lock; + backend->parent.unlock = &refdb_fs_backend__unlock; backend->parent.has_log = &refdb_reflog_fs__has_log; backend->parent.ensure_log = &refdb_reflog_fs__ensure_log; backend->parent.free = &refdb_fs_backend__free; diff --git a/src/reflog.c b/src/reflog.c index 8e41621ea..22aa7d8ed 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -148,7 +148,7 @@ size_t git_reflog_entrycount(git_reflog *reflog) return reflog->entries.length; } -const git_reflog_entry * git_reflog_entry_byindex(git_reflog *reflog, size_t idx) +const git_reflog_entry * git_reflog_entry_byindex(const git_reflog *reflog, size_t idx) { assert(reflog); diff --git a/src/refs.c b/src/refs.c index 1603876da..08e407e48 100644 --- a/src/refs.c +++ b/src/refs.c @@ -411,7 +411,7 @@ static int reference__create( return 0; } -static int log_signature(git_signature **out, git_repository *repo) +int git_reference__log_signature(git_signature **out, git_repository *repo) { int error; git_signature *who; @@ -441,7 +441,7 @@ int git_reference_create_matching( assert(id); if (!signature) { - if ((error = log_signature(&who, repo)) < 0) + if ((error = git_reference__log_signature(&who, repo)) < 0) return error; else signature = who; @@ -482,7 +482,7 @@ int git_reference_symbolic_create_matching( assert(target); if (!signature) { - if ((error = log_signature(&who, repo)) < 0) + if ((error = git_reference__log_signature(&who, repo)) < 0) return error; else signature = who; diff --git a/src/refs.h b/src/refs.h index 2e79bdfca..c6ec429a5 100644 --- a/src/refs.h +++ b/src/refs.h @@ -98,4 +98,6 @@ int git_reference_lookup_resolved( const char *name, int max_deref); +int git_reference__log_signature(git_signature **out, git_repository *repo); + #endif diff --git a/src/remote.c b/src/remote.c index fa5ec8b4c..10b56243f 100644 --- a/src/remote.c +++ b/src/remote.c @@ -21,7 +21,7 @@ static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs); -static int add_refspec(git_remote *remote, const char *string, bool is_fetch) +static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch) { git_refspec *spec; @@ -34,7 +34,7 @@ static int add_refspec(git_remote *remote, const char *string, bool is_fetch) } spec->push = !is_fetch; - if (git_vector_insert(&remote->refspecs, spec) < 0) { + if (git_vector_insert(vector, spec) < 0) { git_refspec__free(spec); git__free(spec); return -1; @@ -43,6 +43,11 @@ static int add_refspec(git_remote *remote, const char *string, bool is_fetch) return 0; } +static int add_refspec(git_remote *remote, const char *string, bool is_fetch) +{ + return add_refspec_to(&remote->refspecs, string, is_fetch); +} + static int download_tags_value(git_remote *remote, git_config *cfg) { const git_config_entry *ce; @@ -80,6 +85,8 @@ static int ensure_remote_name_is_valid(const char *name) return error; } +#if 0 +/* We could export this as a helper */ static int get_check_cert(int *out, git_repository *repo) { git_config *cfg; @@ -105,6 +112,7 @@ static int get_check_cert(int *out, git_repository *repo) *out = git_config__get_bool_force(cfg, "http.sslverify", 1); return 0; } +#endif static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch) { @@ -121,9 +129,6 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n remote->repo = repo; remote->update_fetchhead = 1; - if (get_check_cert(&remote->check_cert, repo) < 0) - goto on_error; - if (git_vector_init(&remote->refs, 32, NULL) < 0) goto on_error; @@ -274,7 +279,6 @@ int git_remote_dup(git_remote **dest, git_remote *source) remote->transport_cb_payload = source->transport_cb_payload; remote->repo = source->repo; remote->download_tags = source->download_tags; - remote->check_cert = source->check_cert; remote->update_fetchhead = source->update_fetchhead; if (git_vector_init(&remote->refs, 32, NULL) < 0 || @@ -369,11 +373,9 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); - if ((error = get_check_cert(&remote->check_cert, repo)) < 0) - goto cleanup; - if (git_vector_init(&remote->refs, 32, NULL) < 0 || git_vector_init(&remote->refspecs, 2, NULL) < 0 || + git_vector_init(&remote->passive_refspecs, 2, NULL) < 0 || git_vector_init(&remote->active_refspecs, 2, NULL) < 0) { error = -1; goto cleanup; @@ -673,12 +675,9 @@ int git_remote_connect(git_remote *remote, git_direction direction) return error; if (t->set_callbacks && - (error = t->set_callbacks(t, remote->callbacks.sideband_progress, NULL, remote->callbacks.payload)) < 0) + (error = t->set_callbacks(t, remote->callbacks.sideband_progress, NULL, remote->callbacks.certificate_check, remote->callbacks.payload)) < 0) goto on_error; - if (!remote->check_cert) - flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT; - if ((error = t->connect(t, url, remote->callbacks.credentials, remote->callbacks.payload, direction, flags)) != 0) goto on_error; @@ -820,20 +819,43 @@ static int ls_to_vector(git_vector *out, git_remote *remote) return 0; } -int git_remote_download(git_remote *remote) +int git_remote_download(git_remote *remote, const git_strarray *refspecs) { - int error; - git_vector refs; + int error = -1; + size_t i; + git_vector refs, specs, *to_active; assert(remote); if (ls_to_vector(&refs, remote) < 0) return -1; + if ((git_vector_init(&specs, 0, NULL)) < 0) + goto on_error; + + remote->passed_refspecs = 0; + if (!refspecs || !refspecs->count) { + to_active = &remote->refspecs; + } else { + for (i = 0; i < refspecs->count; i++) { + if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0) + goto on_error; + } + + to_active = &specs; + remote->passed_refspecs = 1; + } + + free_refspecs(&remote->passive_refspecs); + if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0) + goto on_error; + free_refspecs(&remote->active_refspecs); + error = dwim_refspecs(&remote->active_refspecs, to_active, &refs); - error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &refs); git_vector_free(&refs); + free_refspecs(&specs); + git_vector_free(&specs); if (error < 0) return error; @@ -842,10 +864,17 @@ int git_remote_download(git_remote *remote) return error; return git_fetch_download_pack(remote); + +on_error: + git_vector_free(&refs); + free_refspecs(&specs); + git_vector_free(&specs); + return error; } int git_remote_fetch( git_remote *remote, + const git_strarray *refspecs, const git_signature *signature, const char *reflog_message) { @@ -856,7 +885,7 @@ int git_remote_fetch( if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH)) != 0) return error; - error = git_remote_download(remote); + error = git_remote_download(remote, refspecs); /* We don't need to be connected anymore */ git_remote_disconnect(remote); @@ -898,13 +927,15 @@ static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *upda return 0; } -static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref) +static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref) { git_reference *resolved_ref = NULL; git_buf remote_name = GIT_BUF_INIT; git_buf upstream_name = GIT_BUF_INIT; + git_buf config_key = GIT_BUF_INIT; git_repository *repo; - const char *ref_name; + git_config *config = NULL; + const char *ref_name, *branch_remote; int error = 0; assert(out && spec && ref); @@ -924,6 +955,11 @@ static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vec } if ((!git_reference__is_branch(ref_name)) || + (error = git_repository_config_snapshot(&config, repo)) < 0 || + (error = git_buf_printf(&config_key, "branch.%s.remote", + ref_name + strlen(GIT_REFS_HEADS_DIR))) < 0 || + (error = git_config_get_string(&branch_remote, config, git_buf_cstr(&config_key))) < 0 || + git__strcmp(git_remote_name(remote), branch_remote) || (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 || (error = git_refspec_rtransform(&remote_name, spec, upstream_name.ptr)) < 0) { /* Not an error if there is no upstream */ @@ -939,6 +975,8 @@ cleanup: git_reference_free(resolved_ref); git_buf_free(&remote_name); git_buf_free(&upstream_name); + git_buf_free(&config_key); + git_config_free(config); return error; } @@ -967,7 +1005,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git /* Determine what to merge: if refspec was a wildcard, just use HEAD */ if (git_refspec_is_wildcard(spec)) { if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 || - (error = remote_head_for_ref(&merge_remote_ref, spec, update_heads, head_ref)) < 0) + (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0) goto cleanup; } else { /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */ @@ -1065,16 +1103,20 @@ static int update_tips_for_spec( if (autotag && !git_odb_exists(odb, &head->oid)) continue; - if (git_vector_insert(&update_heads, head) < 0) + if (!autotag && git_vector_insert(&update_heads, head) < 0) goto on_error; error = git_reference_name_to_id(&old, remote->repo, refname.ptr); if (error < 0 && error != GIT_ENOTFOUND) goto on_error; - if (error == GIT_ENOTFOUND) + if (error == GIT_ENOTFOUND) { memset(&old, 0, GIT_OID_RAWSZ); + if (autotag && git_vector_insert(&update_heads, head) < 0) + goto on_error; + } + if (!git_oid__cmp(&old, &head->oid)) continue; @@ -1109,6 +1151,96 @@ on_error: } +/** + * Iteration over the three vectors, with a pause whenever we find a match + * + * On each stop, we store the iteration stat in the inout i,j,k + * parameters, and return the currently matching passive refspec as + * well as the head which we matched. + */ +static int next_head(const git_remote *remote, git_vector *refs, + git_refspec **out_spec, git_remote_head **out_head, + size_t *out_i, size_t *out_j, size_t *out_k) +{ + const git_vector *active, *passive; + git_remote_head *head; + git_refspec *spec, *passive_spec; + size_t i, j, k; + + active = &remote->active_refspecs; + passive = &remote->passive_refspecs; + + i = *out_i; + j = *out_j; + k = *out_k; + + for (; i < refs->length; i++) { + head = git_vector_get(refs, i); + + if (!git_reference_is_valid_name(head->name)) + continue; + + for (; j < active->length; j++) { + spec = git_vector_get(active, j); + + if (!git_refspec_src_matches(spec, head->name)) + continue; + + for (; k < passive->length; k++) { + passive_spec = git_vector_get(passive, k); + + if (!git_refspec_src_matches(passive_spec, head->name)) + continue; + + *out_spec = passive_spec; + *out_head = head; + *out_i = i; + *out_j = j; + *out_k = k + 1; + return 0; + + } + k = 0; + } + j = 0; + } + + return GIT_ITEROVER; +} + +static int opportunistic_updates(const git_remote *remote, git_vector *refs, const git_signature *sig, const char *msg) +{ + size_t i, j, k; + git_refspec *spec; + git_remote_head *head; + git_reference *ref; + git_buf refname = GIT_BUF_INIT; + int error; + + i = j = k = 0; + + while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) { + /* + * If we got here, there is a refspec which was used + * for fetching which matches the source of one of the + * passive refspecs, so we should update that + * remote-tracking branch, but not add it to + * FETCH_HEAD + */ + + if ((error = git_refspec_transform(&refname, spec, head->name)) < 0) + return error; + + error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, sig, msg); + git_buf_free(&refname); + + if (error < 0) + return error; + } + + return 0; +} + int git_remote_update_tips( git_remote *remote, const git_signature *signature, @@ -1139,6 +1271,10 @@ int git_remote_update_tips( goto out; } + /* only try to do opportunisitic updates if the refpec lists differ */ + if (remote->passed_refspecs) + error = opportunistic_updates(remote, &refs, signature, reflog_message); + out: git_vector_free(&refs); git_refspec__free(&tagspec); @@ -1192,6 +1328,9 @@ void git_remote_free(git_remote *remote) free_refspecs(&remote->active_refspecs); git_vector_free(&remote->active_refspecs); + free_refspecs(&remote->passive_refspecs); + git_vector_free(&remote->passive_refspecs); + git__free(remote->url); git__free(remote->pushurl); git__free(remote->name); @@ -1244,13 +1383,6 @@ int git_remote_list(git_strarray *remotes_list, git_repository *repo) return 0; } -void git_remote_check_cert(git_remote *remote, int check) -{ - assert(remote); - - remote->check_cert = check; -} - int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks) { assert(remote && callbacks); @@ -1263,6 +1395,7 @@ int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *cal return remote->transport->set_callbacks(remote->transport, remote->callbacks.sideband_progress, NULL, + remote->callbacks.certificate_check, remote->callbacks.payload); return 0; @@ -1649,27 +1782,14 @@ void git_remote_clear_refspecs(git_remote *remote) git_vector_clear(&remote->refspecs); } -static int add_and_dwim(git_remote *remote, const char *str, int push) -{ - git_refspec *spec; - git_vector *vec; - - if (add_refspec(remote, str, !push) < 0) - return -1; - - vec = &remote->refspecs; - spec = git_vector_get(vec, vec->length - 1); - return git_refspec__dwim_one(&remote->active_refspecs, spec, &remote->refs); -} - int git_remote_add_fetch(git_remote *remote, const char *refspec) { - return add_and_dwim(remote, refspec, false); + return add_refspec(remote, refspec, true); } int git_remote_add_push(git_remote *remote, const char *refspec) { - return add_and_dwim(remote, refspec, true); + return add_refspec(remote, refspec, false); } static int set_refspecs(git_remote *remote, git_strarray *array, int push) @@ -1697,10 +1817,7 @@ static int set_refspecs(git_remote *remote, git_strarray *array, int push) return -1; } - free_refspecs(&remote->active_refspecs); - git_vector_clear(&remote->active_refspecs); - - return dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs); + return 0; } int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array) diff --git a/src/remote.h b/src/remote.h index c471756b8..b79ace438 100644 --- a/src/remote.h +++ b/src/remote.h @@ -23,6 +23,7 @@ struct git_remote { git_vector refs; git_vector refspecs; git_vector active_refspecs; + git_vector passive_refspecs; git_transport_cb transport_cb; void *transport_cb_payload; git_transport *transport; @@ -31,8 +32,8 @@ struct git_remote { git_transfer_progress stats; unsigned int need_pack; git_remote_autotag_option_t download_tags; - int check_cert; int update_fetchhead; + int passed_refspecs; }; const char* git_remote__urlfordirection(struct git_remote *remote, int direction); diff --git a/src/repository.c b/src/repository.c index d86d8905a..f032c899d 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1567,8 +1567,10 @@ int git_repository_head_unborn(git_repository *repo) error = git_repository_head(&ref, repo); git_reference_free(ref); - if (error == GIT_EUNBORNBRANCH) + if (error == GIT_EUNBORNBRANCH) { + giterr_clear(); return 1; + } if (error < 0) return -1; @@ -1681,6 +1683,32 @@ int git_repository_is_bare(git_repository *repo) return repo->is_bare; } +int git_repository_set_bare(git_repository *repo) +{ + int error; + git_config *config; + + assert(repo); + + if (repo->is_bare) + return 0; + + if ((error = git_repository_config__weakptr(&config, repo)) < 0) + return error; + + if ((error = git_config_set_bool(config, "core.bare", false)) < 0) + return error; + + if ((error = git_config__update_entry(config, "core.worktree", NULL, true, true)) < 0) + return error; + + git__free(repo->workdir); + repo->workdir = NULL; + repo->is_bare = 1; + + return 0; +} + int git_repository_head_tree(git_tree **tree, git_repository *repo) { git_reference *head; diff --git a/src/reset.c b/src/reset.c index 248c91d3a..d063abe25 100644 --- a/src/reset.c +++ b/src/reset.c @@ -100,6 +100,7 @@ int git_reset( git_repository *repo, git_object *target, git_reset_t reset_type, + git_checkout_options *checkout_opts, git_signature *signature, const char *log_message) { @@ -112,6 +113,9 @@ int git_reset( assert(repo && target); + if (checkout_opts) + opts = *checkout_opts; + if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s - The given target does not belong to this repository.", ERROR_MSG); diff --git a/src/revwalk.c b/src/revwalk.c index bd07d02cb..4dca7599a 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -116,6 +116,7 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int error; git_object *obj, *oobj; git_commit_list_node *commit; + git_commit_list *list; if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJ_ANY)) < 0) return error; @@ -141,14 +142,20 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, if (commit == NULL) return -1; /* error already reported by failed lookup */ + if (uninteresting) + walk->did_hide = 1; + else + walk->did_push = 1; + commit->uninteresting = uninteresting; - if (walk->one == NULL && !uninteresting) { - walk->one = commit; - } else { - if (git_vector_insert(&walk->twos, commit) < 0) - return -1; + list = walk->user_input; + if (git_commit_list_insert(commit, &list) == NULL) { + giterr_set_oom(); + return -1; } + walk->user_input = list; + return 0; } @@ -367,29 +374,97 @@ static int revwalk_next_reverse(git_commit_list_node **object_out, git_revwalk * } +static int interesting(git_pqueue *list) +{ + size_t i; + + for (i = 0; i < git_pqueue_size(list); i++) { + git_commit_list_node *commit = git_pqueue_get(list, i); + if (!commit->uninteresting) + return 1; + } + + return 0; +} + +static int contains(git_pqueue *list, git_commit_list_node *node) +{ + size_t i; + + for (i = 0; i < git_pqueue_size(list); i++) { + git_commit_list_node *commit = git_pqueue_get(list, i); + if (commit == node) + return 1; + } + + return 0; +} + +static int premark_uninteresting(git_revwalk *walk) +{ + int error = 0; + unsigned short i; + git_pqueue q; + git_commit_list *list; + git_commit_list_node *commit, *parent; + + if ((error = git_pqueue_init(&q, 0, 8, git_commit_list_time_cmp)) < 0) + return error; + + for (list = walk->user_input; list; list = list->next) { + if ((error = git_commit_list_parse(walk, list->item)) < 0) + goto cleanup; + + if ((error = git_pqueue_insert(&q, list->item)) < 0) + goto cleanup; + } + + while (interesting(&q)) { + commit = git_pqueue_pop(&q); + + for (i = 0; i < commit->out_degree; i++) { + parent = commit->parents[i]; + + if ((error = git_commit_list_parse(walk, parent)) < 0) + goto cleanup; + + if (commit->uninteresting) + parent->uninteresting = 1; + + if (contains(&q, parent)) + continue; + + if ((error = git_pqueue_insert(&q, parent)) < 0) + goto cleanup; + } + } + +cleanup: + git_pqueue_free(&q); + return error; +} + static int prepare_walk(git_revwalk *walk) { int error; - unsigned int i; - git_commit_list_node *next, *two; - - /* - * If walk->one is NULL, there were no positive references, - * so we know that the walk is already over. - */ - if (walk->one == NULL) { + git_commit_list *list; + git_commit_list_node *next; + + /* If there were no pushes, we know that the walk is already over */ + if (!walk->did_push) { giterr_clear(); return GIT_ITEROVER; } - if (process_commit(walk, walk->one, walk->one->uninteresting) < 0) - return -1; + if (walk->did_hide && (error = premark_uninteresting(walk)) < 0) + return error; - git_vector_foreach(&walk->twos, i, two) { - if (process_commit(walk, two, two->uninteresting) < 0) + for (list = walk->user_input; list; list = list->next) { + if (process_commit(walk, list->item, list->item->uninteresting) < 0) return -1; } + if (walk->sorting & GIT_SORT_TOPOLOGICAL) { unsigned short i; @@ -440,7 +515,6 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) if (git_pqueue_init( &walk->iterator_time, 0, 8, git_commit_list_time_cmp) < 0 || - git_vector_init(&walk->twos, 4, NULL) < 0 || git_pool_init(&walk->commit_pool, 1, git_pool__suggest_items_per_page(COMMIT_ALLOC) * COMMIT_ALLOC) < 0) return -1; @@ -470,7 +544,6 @@ void git_revwalk_free(git_revwalk *walk) git_oidmap_free(walk->commits); git_pool_clear(&walk->commit_pool); git_pqueue_free(&walk->iterator_time); - git_vector_free(&walk->twos); git__free(walk); } @@ -540,16 +613,17 @@ void git_revwalk_reset(git_revwalk *walk) commit->in_degree = 0; commit->topo_delay = 0; commit->uninteresting = 0; + commit->flags = 0; }); git_pqueue_clear(&walk->iterator_time); git_commit_list_free(&walk->iterator_topo); git_commit_list_free(&walk->iterator_rand); git_commit_list_free(&walk->iterator_reverse); + git_commit_list_free(&walk->user_input); + walk->first_parent = 0; walk->walking = 0; - - walk->one = NULL; - git_vector_clear(&walk->twos); + walk->did_push = walk->did_hide = 0; } int git_revwalk_add_hide_cb( diff --git a/src/revwalk.h b/src/revwalk.h index d81f97c01..72ddedc75 100644 --- a/src/revwalk.h +++ b/src/revwalk.h @@ -32,12 +32,13 @@ struct git_revwalk { int (*enqueue)(git_revwalk *, git_commit_list_node *); unsigned walking:1, - first_parent: 1; + first_parent: 1, + did_hide: 1, + did_push: 1; unsigned int sorting; - /* merge base calculation */ - git_commit_list_node *one; - git_vector twos; + /* the pushes and hides */ + git_commit_list *user_input; /* hide callback */ git_revwalk_hide_cb hide_cb; diff --git a/src/settings.c b/src/settings.c index 1a21ea024..971b50935 100644 --- a/src/settings.c +++ b/src/settings.c @@ -5,10 +5,15 @@ * a Linking Exception. For full terms see the included COPYING file. */ +#ifdef GIT_SSL +# include <openssl/err.h> +#endif + #include <git2.h> #include "common.h" #include "sysdir.h" #include "cache.h" +#include "global.h" void git_libgit2_version(int *major, int *minor, int *rev) { @@ -131,6 +136,23 @@ int git_libgit2_opts(int key, ...) case GIT_OPT_SET_TEMPLATE_PATH: error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *)); break; + + case GIT_OPT_SET_SSL_CERT_LOCATIONS: +#ifdef GIT_SSL + { + const char *file = va_arg(ap, const char *); + const char *path = va_arg(ap, const char *); + if (!SSL_CTX_load_verify_locations(git__ssl_ctx, file, path)) { + giterr_set(GITERR_NET, "SSL error: %s", + ERR_error_string(ERR_get_error(), NULL)); + error = -1; + } + } +#else + giterr_set(GITERR_NET, "Cannot set certificate locations: OpenSSL is not enabled"); + error = -1; +#endif + break; } va_end(ap); diff --git a/src/signature.c b/src/signature.c index 2a16b484a..514b153ac 100644 --- a/src/signature.c +++ b/src/signature.c @@ -106,6 +106,30 @@ int git_signature_dup(git_signature **dest, const git_signature *source) return 0; } +int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool) +{ + git_signature *signature; + + if (source == NULL) + return 0; + + signature = git_pool_mallocz(pool, sizeof(git_signature)); + GITERR_CHECK_ALLOC(signature); + + signature->name = git_pool_strdup(pool, source->name); + GITERR_CHECK_ALLOC(signature->name); + + signature->email = git_pool_strdup(pool, source->email); + GITERR_CHECK_ALLOC(signature->email); + + signature->when.time = source->when.time; + signature->when.offset = source->when.offset; + + *dest = signature; + + return 0; +} + int git_signature_now(git_signature **sig_out, const char *name, const char *email) { time_t now; diff --git a/src/signature.h b/src/signature.h index 24655cbf5..eb71db7db 100644 --- a/src/signature.h +++ b/src/signature.h @@ -15,4 +15,6 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header, char ender); void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig); +int git_signature__pdup(git_signature **dest, const git_signature *source, git_pool *pool); + #endif diff --git a/src/stash.c b/src/stash.c index 22f756e35..cad87d120 100644 --- a/src/stash.c +++ b/src/stash.c @@ -15,6 +15,7 @@ #include "git2/status.h" #include "git2/checkout.h" #include "git2/index.h" +#include "git2/transaction.h" #include "signature.h" static int create_error(int error, const char *msg) @@ -232,7 +233,8 @@ static int build_untracked_tree( } if (flags & GIT_STASH_INCLUDE_IGNORED) { - opts.flags |= GIT_DIFF_INCLUDE_IGNORED; + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | + GIT_DIFF_RECURSE_IGNORED_DIRS; data.include_ignored = true; } @@ -447,10 +449,11 @@ static int ensure_there_are_changes_to_stash( if (include_untracked_files) opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED | - GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; + GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS; if (include_ignored_files) - opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED; + opts.flags |= GIT_STATUS_OPT_INCLUDE_IGNORED | + GIT_STATUS_OPT_RECURSE_IGNORED_DIRS; error = git_status_foreach_ext(repo, &opts, is_dirty_cb, NULL); @@ -599,14 +602,21 @@ int git_stash_drop( git_repository *repo, size_t index) { - git_reference *stash; + git_transaction *tx; + git_reference *stash = NULL; git_reflog *reflog = NULL; size_t max; int error; - if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_transaction_new(&tx, repo)) < 0) return error; + if ((error = git_transaction_lock_ref(tx, GIT_REFS_STASH_FILE)) < 0) + goto cleanup; + + if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0) + goto cleanup; + if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0) goto cleanup; @@ -621,29 +631,25 @@ int git_stash_drop( if ((error = git_reflog_drop(reflog, index, true)) < 0) goto cleanup; - if ((error = git_reflog_write(reflog)) < 0) + if ((error = git_transaction_set_reflog(tx, GIT_REFS_STASH_FILE, reflog)) < 0) goto cleanup; if (max == 1) { - error = git_reference_delete(stash); - git_reference_free(stash); - stash = NULL; + if ((error = git_transaction_remove(tx, GIT_REFS_STASH_FILE)) < 0) + goto cleanup; } else if (index == 0) { const git_reflog_entry *entry; entry = git_reflog_entry_byindex(reflog, 0); - - git_reference_free(stash); - error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, &entry->oid_cur, 1, NULL, NULL); - if (error < 0) + if ((error = git_transaction_set_target(tx, GIT_REFS_STASH_FILE, &entry->oid_cur, NULL, NULL)) < 0) goto cleanup; - - /* We need to undo the writing that we just did */ - error = git_reflog_write(reflog); } + error = git_transaction_commit(tx); + cleanup: git_reference_free(stash); + git_transaction_free(tx); git_reflog_free(reflog); return error; } diff --git a/src/thread-utils.h b/src/thread-utils.h index 5511a5117..8deedce81 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -183,8 +183,8 @@ GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) /* Pthreads Mutex */ #define git_mutex unsigned int -#define git_mutex_init(a) 0 -#define git_mutex_lock(a) 0 +static int git_mutex_init(git_mutex* mutex) { GIT_UNUSED(mutex); return 0; } +static int git_mutex_lock(git_mutex* mutex) { GIT_UNUSED(mutex); return 0; } #define git_mutex_unlock(a) (void)0 #define git_mutex_free(a) (void)0 diff --git a/src/transaction.c b/src/transaction.c new file mode 100644 index 000000000..ebb943cea --- /dev/null +++ b/src/transaction.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "repository.h" +#include "strmap.h" +#include "refdb.h" +#include "pool.h" +#include "reflog.h" +#include "signature.h" + +#include "git2/signature.h" +#include "git2/sys/refs.h" +#include "git2/sys/refdb_backend.h" + +GIT__USE_STRMAP; + +typedef struct { + const char *name; + void *payload; + + git_ref_t ref_type; + union { + git_oid id; + char *symbolic; + } target; + git_reflog *reflog; + + const char *message; + git_signature *sig; + + unsigned int committed :1, + remove :1; +} transaction_node; + +struct git_transaction { + git_repository *repo; + git_refdb *db; + + git_strmap *locks; + git_pool pool; +}; + +int git_transaction_new(git_transaction **out, git_repository *repo) +{ + int error; + git_pool pool; + git_transaction *tx = NULL; + + assert(out && repo); + + if ((error = git_pool_init(&pool, 1, 0)) < 0) + return error; + + tx = git_pool_mallocz(&pool, sizeof(git_transaction)); + if (!tx) { + error = -1; + goto on_error; + } + + if ((error = git_strmap_alloc(&tx->locks)) < 0) { + error = -1; + goto on_error; + } + + if ((error = git_repository_refdb(&tx->db, repo)) < 0) + goto on_error; + + memcpy(&tx->pool, &pool, sizeof(git_pool)); + tx->repo = repo; + *out = tx; + return 0; + +on_error: + git_pool_clear(&pool); + return error; +} + +int git_transaction_lock_ref(git_transaction *tx, const char *refname) +{ + int error; + transaction_node *node; + + assert(tx && refname); + + node = git_pool_mallocz(&tx->pool, sizeof(transaction_node)); + GITERR_CHECK_ALLOC(node); + + node->name = git_pool_strdup(&tx->pool, refname); + GITERR_CHECK_ALLOC(node->name); + + if ((error = git_refdb_lock(&node->payload, tx->db, refname)) < 0) + return error; + + git_strmap_insert(tx->locks, node->name, node, error); + if (error < 0) + goto cleanup; + + return 0; + +cleanup: + git_refdb_unlock(tx->db, node->payload, false, false, NULL, NULL, NULL); + + return error; +} + +static int find_locked(transaction_node **out, git_transaction *tx, const char *refname) +{ + git_strmap_iter pos; + transaction_node *node; + + pos = git_strmap_lookup_index(tx->locks, refname); + if (!git_strmap_valid_index(tx->locks, pos)) { + giterr_set(GITERR_REFERENCE, "the specified reference is not locked"); + return GIT_ENOTFOUND; + } + + node = git_strmap_value_at(tx->locks, pos); + + *out = node; + return 0; +} + +static int copy_common(transaction_node *node, git_transaction *tx, const git_signature *sig, const char *msg) +{ + if (sig && git_signature__pdup(&node->sig, sig, &tx->pool) < 0) + return -1; + + if (!node->sig) { + git_signature *tmp; + int error; + + if (git_reference__log_signature(&tmp, tx->repo) < 0) + return -1; + + /* make sure the sig we use is in our pool */ + error = git_signature__pdup(&node->sig, tmp, &tx->pool); + git_signature_free(tmp); + if (error < 0) + return error; + } + + if (msg) { + node->message = git_pool_strdup(&tx->pool, msg); + GITERR_CHECK_ALLOC(node->message); + } + + return 0; +} + +int git_transaction_set_target(git_transaction *tx, const char *refname, const git_oid *target, const git_signature *sig, const char *msg) +{ + int error; + transaction_node *node; + + assert(tx && refname && target); + + if ((error = find_locked(&node, tx, refname)) < 0) + return error; + + if ((error = copy_common(node, tx, sig, msg)) < 0) + return error; + + git_oid_cpy(&node->target.id, target); + node->ref_type = GIT_REF_OID; + + return 0; +} + +int git_transaction_set_symbolic_target(git_transaction *tx, const char *refname, const char *target, const git_signature *sig, const char *msg) +{ + int error; + transaction_node *node; + + assert(tx && refname && target); + + if ((error = find_locked(&node, tx, refname)) < 0) + return error; + + if ((error = copy_common(node, tx, sig, msg)) < 0) + return error; + + node->target.symbolic = git_pool_strdup(&tx->pool, target); + GITERR_CHECK_ALLOC(node->target.symbolic); + node->ref_type = GIT_REF_SYMBOLIC; + + return 0; +} + +int git_transaction_remove(git_transaction *tx, const char *refname) +{ + int error; + transaction_node *node; + + if ((error = find_locked(&node, tx, refname)) < 0) + return error; + + node->remove = true; + node->ref_type = GIT_REF_OID; /* the id will be ignored */ + + return 0; +} + +static int dup_reflog(git_reflog **out, const git_reflog *in, git_pool *pool) +{ + git_reflog *reflog; + git_reflog_entry *entries; + size_t len, i; + + reflog = git_pool_mallocz(pool, sizeof(git_reflog)); + GITERR_CHECK_ALLOC(reflog); + + reflog->ref_name = git_pool_strdup(pool, in->ref_name); + GITERR_CHECK_ALLOC(reflog->ref_name); + + len = in->entries.length; + reflog->entries.length = len; + reflog->entries.contents = git_pool_mallocz(pool, len * sizeof(void *)); + GITERR_CHECK_ALLOC(reflog->entries.contents); + + entries = git_pool_mallocz(pool, len * sizeof(git_reflog_entry)); + GITERR_CHECK_ALLOC(entries); + + for (i = 0; i < len; i++) { + const git_reflog_entry *src; + git_reflog_entry *tgt; + + tgt = &entries[i]; + reflog->entries.contents[i] = tgt; + + src = git_vector_get(&in->entries, i); + git_oid_cpy(&tgt->oid_old, &src->oid_old); + git_oid_cpy(&tgt->oid_cur, &src->oid_cur); + + tgt->msg = git_pool_strdup(pool, src->msg); + GITERR_CHECK_ALLOC(tgt->msg); + + if (git_signature__pdup(&tgt->committer, src->committer, pool) < 0) + return -1; + } + + + *out = reflog; + return 0; +} + +int git_transaction_set_reflog(git_transaction *tx, const char *refname, const git_reflog *reflog) +{ + int error; + transaction_node *node; + + assert(tx && refname && reflog); + + if ((error = find_locked(&node, tx, refname)) < 0) + return error; + + if ((error = dup_reflog(&node->reflog, reflog, &tx->pool)) < 0) + return error; + + return 0; +} + +static int update_target(git_refdb *db, transaction_node *node) +{ + git_reference *ref; + int error, update_reflog; + + if (node->ref_type == GIT_REF_OID) { + ref = git_reference__alloc(node->name, &node->target.id, NULL); + } else if (node->ref_type == GIT_REF_SYMBOLIC) { + ref = git_reference__alloc_symbolic(node->name, node->target.symbolic); + } else { + assert(0); + } + + GITERR_CHECK_ALLOC(ref); + update_reflog = node->reflog == NULL; + + if (node->remove) { + error = git_refdb_unlock(db, node->payload, 2, false, ref, NULL, NULL); + } else if (node->ref_type == GIT_REF_OID) { + error = git_refdb_unlock(db, node->payload, true, update_reflog, ref, node->sig, node->message); + } else if (node->ref_type == GIT_REF_SYMBOLIC) { + error = git_refdb_unlock(db, node->payload, true, update_reflog, ref, node->sig, node->message); + } else { + assert(0); + } + + git_reference_free(ref); + node->committed = true; + + return error; +} + +int git_transaction_commit(git_transaction *tx) +{ + transaction_node *node; + git_strmap_iter pos; + int error; + + assert(tx); + + for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) { + if (!git_strmap_has_data(tx->locks, pos)) + continue; + + node = git_strmap_value_at(tx->locks, pos); + if (node->reflog) { + if ((error = tx->db->backend->reflog_write(tx->db->backend, node->reflog)) < 0) + return error; + } + + if (node->ref_type != GIT_REF_INVALID) { + if ((error = update_target(tx->db, node)) < 0) + return error; + } + } + + return 0; +} + +void git_transaction_free(git_transaction *tx) +{ + transaction_node *node; + git_pool pool; + git_strmap_iter pos; + + assert(tx); + + /* start by unlocking the ones we've left hanging, if any */ + for (pos = kh_begin(tx->locks); pos < kh_end(tx->locks); pos++) { + if (!git_strmap_has_data(tx->locks, pos)) + continue; + + node = git_strmap_value_at(tx->locks, pos); + if (node->committed) + continue; + + git_refdb_unlock(tx->db, node->payload, false, false, NULL, NULL, NULL); + } + + git_refdb_free(tx->db); + git_strmap_free(tx->locks); + + /* tx is inside the pool, so we need to extract the data */ + memcpy(&pool, &tx->pool, sizeof(git_pool)); + git_pool_clear(&pool); +} diff --git a/src/transports/http.c b/src/transports/http.c index f9df53b71..bcfeaee7f 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -19,6 +19,10 @@ git_http_auth_scheme auth_schemes[] = { { GIT_AUTHTYPE_BASIC, "Basic", GIT_CREDTYPE_USERPASS_PLAINTEXT, git_http_auth_basic }, }; +#ifdef GIT_SSL +# include <openssl/x509v3.h> +#endif + static const char *upload_pack_service = "upload-pack"; static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack"; static const char *upload_pack_service_url = "/git-upload-pack"; @@ -524,7 +528,7 @@ static int write_chunk(gitno_socket *socket, const char *buffer, size_t len) static int http_connect(http_subtransport *t) { - int flags = 0; + int flags = 0, error; if (t->connected && http_should_keep_alive(&t->parser) && @@ -541,13 +545,55 @@ static int http_connect(http_subtransport *t) return -1; flags |= GITNO_CONNECT_SSL; - - if (GIT_TRANSPORTFLAGS_NO_CHECK_CERT & tflags) - flags |= GITNO_CONNECT_SSL_NO_CHECK_CERT; } - if (gitno_connect(&t->socket, t->connection_data.host, t->connection_data.port, flags) < 0) - return -1; + error = gitno_connect(&t->socket, t->connection_data.host, t->connection_data.port, flags); + +#ifdef GIT_SSL + if ((!error || error == GIT_ECERTIFICATE) && t->owner->certificate_check_cb != NULL) { + X509 *cert = SSL_get_peer_certificate(t->socket.ssl.ssl); + git_cert_x509 cert_info; + int len, is_valid; + unsigned char *guard, *encoded_cert; + + /* Retrieve the length of the certificate first */ + len = i2d_X509(cert, NULL); + if (len < 0) { + giterr_set(GITERR_NET, "failed to retrieve certificate information"); + return -1; + } + + + encoded_cert = git__malloc(len); + GITERR_CHECK_ALLOC(encoded_cert); + /* i2d_X509 makes 'copy' point to just after the data */ + guard = encoded_cert; + + len = i2d_X509(cert, &guard); + if (len < 0) { + git__free(encoded_cert); + giterr_set(GITERR_NET, "failed to retrieve certificate information"); + return -1; + } + + giterr_clear(); + is_valid = error != GIT_ECERTIFICATE; + cert_info.cert_type = GIT_CERT_X509; + cert_info.data = encoded_cert; + cert_info.len = len; + error = t->owner->certificate_check_cb((git_cert *) &cert_info, is_valid, t->connection_data.host, t->owner->message_cb_payload); + git__free(encoded_cert); + + if (error < 0) { + if (!giterr_last()) + giterr_set(GITERR_NET, "user cancelled certificate check"); + + return error; + } + } +#endif + if (error < 0) + return error; t->connected = 1; return 0; @@ -608,6 +654,7 @@ replay: while (!*bytes_read && !t->parse_finished) { size_t data_offset; + int error; /* * Make the parse_buffer think it's as full of data as @@ -654,8 +701,8 @@ replay: if (PARSE_ERROR_REPLAY == t->parse_error) { s->sent_request = 0; - if (http_connect(t) < 0) - return -1; + if ((error = http_connect(t)) < 0) + return error; goto replay; } @@ -907,8 +954,8 @@ static int http_action( (ret = gitno_connection_data_from_url(&t->connection_data, url, NULL)) < 0) return ret; - if (http_connect(t) < 0) - return -1; + if ((ret = http_connect(t)) < 0) + return ret; switch (action) { case GIT_SERVICE_UPLOADPACK_LS: diff --git a/src/transports/smart.c b/src/transports/smart.c index a5c3e82dc..d0f9c90e8 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -53,12 +53,14 @@ static int git_smart__set_callbacks( git_transport *transport, git_transport_message_cb progress_cb, git_transport_message_cb error_cb, + git_transport_certificate_check_cb certificate_check_cb, void *message_cb_payload) { transport_smart *t = (transport_smart *)transport; t->progress_cb = progress_cb; t->error_cb = error_cb; + t->certificate_check_cb = certificate_check_cb; t->message_cb_payload = message_cb_payload; return 0; diff --git a/src/transports/smart.h b/src/transports/smart.h index b29faae44..44e241adc 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -137,6 +137,7 @@ typedef struct { int flags; git_transport_message_cb progress_cb; git_transport_message_cb error_cb; + git_transport_certificate_check_cb certificate_check_cb; void *message_cb_payload; git_smart_subtransport *wrapped; git_smart_subtransport_stream *current_stream; diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 5ca5065ac..7c20382dc 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -640,9 +640,9 @@ static int gen_pktline(git_buf *buf, git_push *push) { push_spec *spec; size_t i, len; - char old_id[41], new_id[41]; + char old_id[GIT_OID_HEXSZ+1], new_id[GIT_OID_HEXSZ+1]; - old_id[40] = '\0'; new_id[40] = '\0'; + old_id[GIT_OID_HEXSZ] = '\0'; new_id[GIT_OID_HEXSZ] = '\0'; git_vector_foreach(&push->specs, i, spec) { len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->rref); @@ -963,7 +963,7 @@ int git_smart__push(git_transport *transport, git_push *push) #ifdef PUSH_DEBUG { git_remote_head *head; - char hex[41]; hex[40] = '\0'; + char hex[GIT_OID_HEXSZ+1]; hex[GIT_OID_HEXSZ] = '\0'; git_vector_foreach(&push->remote->refs, i, head) { git_oid_fmt(hex, &head->oid); diff --git a/src/transports/ssh.c b/src/transports/ssh.c index a57d27d31..3868a529a 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -473,6 +473,46 @@ static int _git_ssh_setup_conn( GITERR_CHECK_ALLOC(port); } + if ((error = gitno_connect(&s->socket, host, port, 0)) < 0) + goto on_error; + + if ((error = _git_ssh_session_create(&session, s->socket)) < 0) + goto on_error; + + if (t->owner->certificate_check_cb != NULL) { + git_cert_hostkey cert = { 0 }; + const char *key; + + cert.cert_type = GIT_CERT_HOSTKEY_LIBSSH2; + + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_SHA1; + memcpy(&cert.hash_sha1, key, 20); + } + + key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); + if (key != NULL) { + cert.type |= GIT_CERT_SSH_MD5; + memcpy(&cert.hash_md5, key, 16); + } + + if (cert.type == 0) { + giterr_set(GITERR_SSH, "unable to get the host key"); + return -1; + } + + /* We don't currently trust any hostkeys */ + giterr_clear(); + error = t->owner->certificate_check_cb((git_cert *) &cert, 0, host, t->owner->message_cb_payload); + if (error < 0) { + if (!giterr_last()) + giterr_set(GITERR_NET, "user cancelled hostkey check"); + + goto on_error; + } + } + /* we need the username to ask for auth methods */ if (!user) { if ((error = request_creds(&cred, t, NULL, GIT_CREDTYPE_USERNAME)) < 0) @@ -488,12 +528,6 @@ static int _git_ssh_setup_conn( goto on_error; } - if ((error = gitno_connect(&s->socket, host, port, 0)) < 0) - goto on_error; - - if ((error = _git_ssh_session_create(&session, s->socket)) < 0) - goto on_error; - if ((error = list_auth_methods(&auth_methods, session, user)) < 0) goto on_error; @@ -602,10 +636,8 @@ static int ssh_receivepack_ls( { const char *cmd = t->cmd_receivepack ? t->cmd_receivepack : cmd_receivepack; - if (_git_ssh_setup_conn(t, url, cmd, stream) < 0) - return -1; - return 0; + return _git_ssh_setup_conn(t, url, cmd, stream); } static int ssh_receivepack( diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 6523086da..5a59dafad 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -16,6 +16,8 @@ #include "remote.h" #include "repository.h" +#include <wincrypt.h> +#pragma comment(lib, "crypt32") #include <winhttp.h> #pragma comment(lib, "winhttp") @@ -203,6 +205,39 @@ static int fallback_cred_acquire_cb( return error; } +static int certificate_check(winhttp_stream *s, int valid) +{ + int error; + winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); + PCERT_CONTEXT cert_ctx; + DWORD cert_ctx_size = sizeof(cert_ctx); + git_cert_x509 cert; + + /* If there is no override, we should fail if WinHTTP doesn't think it's fine */ + if (t->owner->certificate_check_cb == NULL && !valid) + return GIT_ECERTIFICATE; + + if (t->owner->certificate_check_cb == NULL || !t->connection_data.use_ssl) + return 0; + + if (!WinHttpQueryOption(s->request, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert_ctx, &cert_ctx_size)) { + giterr_set(GITERR_OS, "failed to get server certificate"); + return -1; + } + + giterr_clear(); + cert.cert_type = GIT_CERT_X509; + cert.data = cert_ctx->pbCertEncoded; + cert.len = cert_ctx->cbCertEncoded; + error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->connection_data.host, t->owner->cred_acquire_payload); + CertFreeCertificateContext(cert_ctx); + + if (error < 0 && !giterr_last()) + giterr_set(GITERR_NET, "user cancelled certificate check"); + + return error; +} + static int winhttp_stream_connect(winhttp_stream *s) { winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); @@ -353,13 +388,6 @@ static int winhttp_stream_connect(winhttp_stream *s) if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0) goto on_error; - - if ((GIT_TRANSPORTFLAGS_NO_CHECK_CERT & flags) && - !WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, - (LPVOID)&no_check_cert_flags, sizeof(no_check_cert_flags))) { - giterr_set(GITERR_OS, "Failed to set options to ignore cert errors"); - goto on_error; - } } /* If we have a credential on the subtransport, apply it to the request */ @@ -527,6 +555,74 @@ on_error: return error; } +static int do_send_request(winhttp_stream *s, size_t len, int ignore_length) +{ + int request_failed = 0, cert_valid = 1, error = 0; + + if (ignore_length) { + if (!WinHttpSendRequest(s->request, + WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0)) { + return -1; + } + } else { + if (!WinHttpSendRequest(s->request, + WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, + len, 0)) { + return -1; + } + } + + return 0; +} + +static int send_request(winhttp_stream *s, size_t len, int ignore_length) +{ + int request_failed = 0, cert_valid = 1, error = 0; + DWORD ignore_flags; + + if ((error = do_send_request(s, len, ignore_length)) < 0) + request_failed = 1; + + if (request_failed) { + if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) { + giterr_set(GITERR_OS, "failed to send request"); + return -1; + } else { + cert_valid = 0; + } + } + + giterr_clear(); + if ((error = certificate_check(s, cert_valid)) < 0) { + if (!giterr_last()) + giterr_set(GITERR_OS, "user cancelled certificate check"); + + return error; + } + + /* if neither the request nor the certificate check returned errors, we're done */ + if (!request_failed) + return 0; + + ignore_flags = + SECURITY_FLAG_IGNORE_CERT_CN_INVALID | + SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | + SECURITY_FLAG_IGNORE_UNKNOWN_CA; + + if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) { + giterr_set(GITERR_OS, "failed to set security options"); + return -1; + } + + if ((error = do_send_request(s, len, ignore_length)) < 0) + giterr_set(GITERR_OS, "failed to send request"); + + return error; +} + static int winhttp_stream_read( git_smart_subtransport_stream *stream, char *buffer, @@ -537,6 +633,7 @@ static int winhttp_stream_read( winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD dw_bytes_read; char replay_count = 0; + int error; replay: /* Enforce a reasonable cap on the number of replays */ @@ -553,15 +650,12 @@ replay: DWORD status_code, status_code_length, content_type_length, bytes_written; char expected_content_type_8[MAX_CONTENT_TYPE_LEN]; wchar_t expected_content_type[MAX_CONTENT_TYPE_LEN], content_type[MAX_CONTENT_TYPE_LEN]; + int request_failed = 0, cert_valid = 1; if (!s->sent_request) { - if (!WinHttpSendRequest(s->request, - WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, - s->post_body_len, 0)) { - giterr_set(GITERR_OS, "Failed to send request"); - return -1; - } + + if ((error = send_request(s, s->post_body_len, 0)) < 0) + return error; s->sent_request = 1; } @@ -815,6 +909,7 @@ static int winhttp_stream_write_single( winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); DWORD bytes_written; + int error; if (!s->request && winhttp_stream_connect(s) < 0) return -1; @@ -825,13 +920,8 @@ static int winhttp_stream_write_single( return -1; } - if (!WinHttpSendRequest(s->request, - WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, - (DWORD)len, 0)) { - giterr_set(GITERR_OS, "Failed to send request"); - return -1; - } + if ((error = send_request(s, len, 0)) < 0) + return error; s->sent_request = 1; @@ -954,6 +1044,7 @@ static int winhttp_stream_write_chunked( { winhttp_stream *s = (winhttp_stream *)stream; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); + int error; if (!s->request && winhttp_stream_connect(s) < 0) return -1; @@ -967,13 +1058,8 @@ static int winhttp_stream_write_chunked( return -1; } - if (!WinHttpSendRequest(s->request, - WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0)) { - giterr_set(GITERR_OS, "Failed to send request"); - return -1; - } + if ((error = send_request(s, 0, 1)) < 0) + return error; s->sent_request = 1; } diff --git a/src/userdiff.h b/src/userdiff.h index 523f2f8d4..91c1f42dc 100644 --- a/src/userdiff.h +++ b/src/userdiff.h @@ -191,9 +191,9 @@ PATTERNS("php", "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), PATTERNS("javascript", - "^[ \t]*(function[ \t][a-zA-Z_][^\\{]*)\n" - "^[ \t]*(var[ \t]+[a-zA-Z_][a-zA-Z0-9_]*[ \t]*=[ \t]*function[ \t\\(][^\\{]*)\n" - "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*[ \t]*:[ \t]*function[ \t\\(][^\\{]*)", + "([a-zA-Z_$][a-zA-Z0-9_$]*(\\.[a-zA-Z0-9_$]+)*[ \t]*=[ \t]*function([ \t][a-zA-Z_$][a-zA-Z0-9_$]*)?[^\\{]*)\n" + "([a-zA-Z_$][a-zA-Z0-9_$]*[ \t]*:[ \t]*function([ \t][a-zA-Z_$][a-zA-Z0-9_$]*)?[^\\{]*)\n" + "[^a-zA-Z0-9_\\$](function([ \t][a-zA-Z_$][a-zA-Z0-9_$]*)?[^\\{]*)", /* -- */ "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[fFlL]?|0[xX]?[0-9a-fA-F]+[lL]?" diff --git a/tests/attr/repo.c b/tests/attr/repo.c index 5e812a72b..8baf50622 100644 --- a/tests/attr/repo.c +++ b/tests/attr/repo.c @@ -4,6 +4,7 @@ #include "attr.h" #include "attr_expect.h" +#include "git2/sys/repository.h" static git_repository *g_repo = NULL; @@ -333,3 +334,45 @@ void test_attr_repo__staging_properly_normalizes_line_endings_according_to_gitat git_index_free(index); } + +void test_attr_repo__bare_repo_with_index(void) +{ + const char *names[4] = { "test1", "test2", "test3", "test4" }; + const char *values[4]; + git_index *index; + + cl_git_pass(git_repository_index(&index, g_repo)); + + cl_git_mkfile( + "attr/.gitattributes", + "*.txt test1 test2=foobar -test3\n" + "trial.txt -test1 test2=barfoo !test3 test4\n"); + cl_git_pass(git_index_add_bypath(index, ".gitattributes")); + git_index_free(index); + + cl_must_pass(p_unlink("attr/.gitattributes")); + cl_assert(!git_path_exists("attr/.gitattributes")); + + cl_git_pass(git_repository_set_bare(g_repo)); + + cl_git_pass(git_attr_get_many(values, g_repo, 0, "file.txt", 4, names)); + + cl_assert(GIT_ATTR_TRUE(values[0])); + cl_assert_equal_s("foobar", values[1]); + cl_assert(GIT_ATTR_FALSE(values[2])); + cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); + + cl_git_pass(git_attr_get_many(values, g_repo, 0, "trial.txt", 4, names)); + + cl_assert(GIT_ATTR_FALSE(values[0])); + cl_assert_equal_s("barfoo", values[1]); + cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); + cl_assert(GIT_ATTR_TRUE(values[3])); + + cl_git_pass(git_attr_get_many(values, g_repo, 0, "sub/sub/subdir.txt", 4, names)); + + cl_assert(GIT_ATTR_TRUE(values[0])); + cl_assert_equal_s("foobar", values[1]); + cl_assert(GIT_ATTR_FALSE(values[2])); + cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); +} diff --git a/tests/blame/blame_helpers.c b/tests/blame/blame_helpers.c index 9bb77a52d..21cd1a615 100644 --- a/tests/blame/blame_helpers.c +++ b/tests/blame/blame_helpers.c @@ -17,7 +17,7 @@ void hunk_message(size_t idx, const git_blame_hunk *hunk, const char *fmt, ...) void check_blame_hunk_index(git_repository *repo, git_blame *blame, int idx, int start_line, int len, char boundary, const char *commit_id, const char *orig_path) { - char expected[41] = {0}, actual[41] = {0}; + char expected[GIT_OID_HEXSZ+1] = {0}, actual[GIT_OID_HEXSZ+1] = {0}; const git_blame_hunk *hunk = git_blame_get_hunk_byindex(blame, idx); cl_assert(hunk); diff --git a/tests/checkout/conflict.c b/tests/checkout/conflict.c index b8ae80576..3d763af12 100644 --- a/tests/checkout/conflict.c +++ b/tests/checkout/conflict.c @@ -48,7 +48,7 @@ static git_index *g_index; struct checkout_index_entry { uint16_t mode; - char oid_str[41]; + char oid_str[GIT_OID_HEXSZ+1]; int stage; char path[128]; }; @@ -1078,8 +1078,8 @@ static void collect_progress( { git_vector *paths = payload; - (void)completed_steps; - (void)total_steps; + GIT_UNUSED(completed_steps); + GIT_UNUSED(total_steps); if (path == NULL) return; diff --git a/tests/checkout/tree.c b/tests/checkout/tree.c index b61ef2dfc..0933f64f7 100644 --- a/tests/checkout/tree.c +++ b/tests/checkout/tree.c @@ -571,7 +571,7 @@ void test_checkout_tree__donot_update_deleted_file_by_default(void) cl_git_pass(git_oid_fromstr(&old_id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_commit_lookup(&old_commit, g_repo, &old_id)); - cl_git_pass(git_reset(g_repo, (git_object *)old_commit, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(g_repo, (git_object *)old_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(p_unlink("testrepo/branch_file.txt")); cl_git_pass(git_index_remove_bypath(index ,"branch_file.txt")); diff --git a/tests/cherrypick/workdir.c b/tests/cherrypick/workdir.c index f41d47833..86a385d16 100644 --- a/tests/cherrypick/workdir.c +++ b/tests/cherrypick/workdir.c @@ -66,7 +66,7 @@ void test_cherrypick_workdir__automerge(void) git_tree *cherrypicked_tree = NULL; cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, cherrypick_oids[i]); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); @@ -92,6 +92,47 @@ void test_cherrypick_workdir__automerge(void) git_signature_free(signature); } +/* git reset --hard cfc4f0999a8367568e049af4f72e452d40828a15 + * git cherry-pick a43a050c588d4e92f11a6b139680923e9728477d*/ +void test_cherrypick_workdir__empty_result(void) +{ + git_oid head_oid; + git_signature *signature = NULL; + git_commit *head = NULL, *commit = NULL; + git_oid cherry_oid; + + const char *cherrypick_oid = "a43a050c588d4e92f11a6b139680923e9728477d"; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "19c5c7207054604b69c84d08a7571ef9672bb5c2", 0, "file1.txt" }, + { 0100644, "a58ca3fee5eb68b11adc2703e5843f968c9dad1e", 0, "file2.txt" }, + { 0100644, "28d9eb4208074ad1cc84e71ccc908b34573f05d2", 0, "file3.txt" }, + }; + + cl_git_pass(git_signature_new(&signature, "Picker", "picker@example.org", time(NULL), 0)); + + git_oid_fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15"); + + /* Create an untracked file that should not conflict */ + cl_git_mkfile(TEST_REPO_PATH "/file4.txt", ""); + cl_assert(git_path_exists(TEST_REPO_PATH "/file4.txt")); + + cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); + + git_oid_fromstr(&cherry_oid, cherrypick_oid); + cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); + cl_git_pass(git_cherrypick(repo, commit, NULL)); + + /* The resulting tree should not have changed, the change was already on HEAD */ + cl_assert(merge_test_index(repo_index, merge_index_entries, 3)); + + git_commit_free(head); + git_commit_free(commit); + + git_signature_free(signature); +} + /* git reset --hard bafbf6912c09505ac60575cd43d3f2aba3bd84d8 * git cherry-pick e9b63f3655b2ad80c0ff587389b5a9589a3a7110 */ @@ -114,7 +155,7 @@ void test_cherrypick_workdir__conflicts(void) git_oid_fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110"); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); @@ -222,7 +263,7 @@ void test_cherrypick_workdir__conflict_use_ours(void) git_oid_fromstr(&head_oid, "bafbf6912c09505ac60575cd43d3f2aba3bd84d8"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, "e9b63f3655b2ad80c0ff587389b5a9589a3a7110"); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); @@ -234,7 +275,7 @@ void test_cherrypick_workdir__conflict_use_ours(void) /* resolve conflicts in the index by taking "ours" */ opts.merge_opts.file_favor = GIT_MERGE_FILE_FAVOR_OURS; - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_cherrypick(repo, commit, &opts)); cl_assert(merge_test_index(repo_index, merge_filesystem_entries, 3)); @@ -264,7 +305,7 @@ void test_cherrypick_workdir__rename(void) git_oid_fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, "2a26c7e88b285613b302ba76712bc998863f3cbc"); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); @@ -299,7 +340,7 @@ void test_cherrypick_workdir__both_renamed(void) git_oid_fromstr(&head_oid, "44cd2ed2052c9c68f9a439d208e9614dc2a55c70"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, "2a26c7e88b285613b302ba76712bc998863f3cbc"); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); @@ -350,7 +391,7 @@ void test_cherrypick_workdir__merge_fails_without_mainline_specified(void) git_oid_fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff"); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); @@ -382,7 +423,7 @@ void test_cherrypick_workdir__merge_first_parent(void) git_oid_fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff"); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); @@ -414,7 +455,7 @@ void test_cherrypick_workdir__merge_second_parent(void) git_oid_fromstr(&head_oid, "cfc4f0999a8367568e049af4f72e452d40828a15"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&cherry_oid, "abe4603bc7cd5b8167a267e0e2418fd2348f8cff"); cl_git_pass(git_commit_lookup(&commit, repo, &cherry_oid)); diff --git a/tests/config/stress.c b/tests/config/stress.c index 488915e79..e8e9d2b61 100644 --- a/tests/config/stress.c +++ b/tests/config/stress.c @@ -44,12 +44,24 @@ void test_config_stress__comments(void) cl_git_pass(git_config_open_ondisk(&config, cl_fixture("config/config12"))); + cl_git_pass(git_config_get_string(&str, config, "some.section.test2")); + cl_assert_equal_s("hello", str); + + cl_git_pass(git_config_get_string(&str, config, "some.section.test3")); + cl_assert_equal_s("welcome", str); + cl_git_pass(git_config_get_string(&str, config, "some.section.other")); cl_assert_equal_s("hello! \" ; ; ; ", str); + cl_git_pass(git_config_get_string(&str, config, "some.section.other2")); + cl_assert_equal_s("cool! \" # # # ", str); + cl_git_pass(git_config_get_string(&str, config, "some.section.multi")); cl_assert_equal_s("hi, this is a ; multiline comment # with ;\n special chars and other stuff !@#", str); + cl_git_pass(git_config_get_string(&str, config, "some.section.multi2")); + cl_assert_equal_s("good, this is a ; multiline comment # with ;\n special chars and other stuff !@#", str); + cl_git_pass(git_config_get_string(&str, config, "some.section.back")); cl_assert_equal_s("this is \ba phrase", str); diff --git a/tests/core/buffer.c b/tests/core/buffer.c index 7482dadbe..641fed630 100644 --- a/tests/core/buffer.c +++ b/tests/core/buffer.c @@ -1,7 +1,7 @@ #include "clar_libgit2.h" #include "buffer.h" #include "buf_text.h" -#include "hashsig.h" +#include "git2/sys/hashsig.h" #include "fileops.h" #define TESTSTR "Have you seen that? Have you seeeen that??" diff --git a/tests/core/path.c b/tests/core/path.c index 471491b87..7d3e4938f 100644 --- a/tests/core/path.c +++ b/tests/core/path.c @@ -356,7 +356,7 @@ typedef struct { #define CANCEL_VALUE 1234 -static int check_one_walkup_step(void *ref, git_buf *path) +static int check_one_walkup_step(void *ref, const char *path) { check_walkup_info *info = (check_walkup_info *)ref; @@ -367,7 +367,7 @@ static int check_one_walkup_step(void *ref, git_buf *path) info->cancel_after--; cl_assert(info->expect[info->expect_idx] != NULL); - cl_assert_equal_s(info->expect[info->expect_idx], path->ptr); + cl_assert_equal_s(info->expect[info->expect_idx], path); info->expect_idx++; return 0; @@ -376,18 +376,42 @@ static int check_one_walkup_step(void *ref, git_buf *path) void test_core_path__11_walkup(void) { git_buf p = GIT_BUF_INIT; + char *expect[] = { - "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, - "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, - "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, - "this is a path", NULL, - "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL, - NULL + /* 1 */ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 2 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 3 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 4 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL, + /* 5 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, + /* 6 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL, + /* 7 */ "this_is_a_path", "", NULL, + /* 8 */ "this_is_a_path/", "", NULL, + /* 9 */ "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL, + /* 10 */ "a/b/c/", "a/b/", "a/", "", NULL, + /* 11 */ "a/b/c", "a/b/", "a/", "", NULL, + /* 12 */ "a/b/c/", "a/b/", "a/", NULL, + /* 13 */ "", NULL, + /* 14 */ "/", NULL, + /* 15 */ NULL + }; + + char *root[] = { + /* 1 */ NULL, + /* 2 */ NULL, + /* 3 */ "/", + /* 4 */ "", + /* 5 */ "/a/b", + /* 6 */ "/a/b/", + /* 7 */ NULL, + /* 8 */ NULL, + /* 9 */ NULL, + /* 10 */ NULL, + /* 11 */ NULL, + /* 12 */ "a/", + /* 13 */ NULL, + /* 14 */ NULL, }; - char *root[] = { NULL, NULL, "/", "", "/a/b", "/a/b/", NULL, NULL, NULL }; + int i, j; check_walkup_info info; @@ -404,9 +428,8 @@ void test_core_path__11_walkup(void) ); cl_assert_equal_s(p.ptr, expect[i]); - - /* skip to next run of expectations */ - while (expect[i] != NULL) i++; + cl_assert(expect[info.expect_idx] == NULL); + i = info.expect_idx; } git_buf_free(&p); diff --git a/tests/describe/describe.c b/tests/describe/describe.c new file mode 100644 index 000000000..9a523a169 --- /dev/null +++ b/tests/describe/describe.c @@ -0,0 +1,50 @@ +#include "clar_libgit2.h" +#include "describe_helpers.h" + +void test_describe_describe__can_describe_against_a_bare_repo(void) +{ + git_repository *repo; + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + + assert_describe("hard_tag", "HEAD", repo, &opts, &fmt_opts); + + opts.show_commit_oid_as_fallback = 1; + + assert_describe("be3563a*", "HEAD^", repo, &opts, &fmt_opts); + + git_repository_free(repo); +} + +static int delete_cb(git_reference *ref, void *payload) +{ + GIT_UNUSED(payload); + + cl_git_pass(git_reference_delete(ref)); + git_reference_free(ref); + + return 0; +} + +void test_describe_describe__cannot_describe_against_a_repo_with_no_ref(void) +{ + git_repository *repo; + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_buf buf = GIT_BUF_INIT; + git_object *object; + git_describe_result *result = NULL; + + repo = cl_git_sandbox_init("testrepo.git"); + cl_git_pass(git_revparse_single(&object, repo, "HEAD")); + + cl_git_pass(git_reference_foreach(repo, delete_cb, NULL)); + + cl_git_fail(git_describe_commit(&result, object, &opts)); + + git_describe_result_free(result); + git_object_free(object); + git_buf_free(&buf); + cl_git_sandbox_cleanup(); +} diff --git a/tests/describe/describe_helpers.c b/tests/describe/describe_helpers.c new file mode 100644 index 000000000..7a6a73cb8 --- /dev/null +++ b/tests/describe/describe_helpers.c @@ -0,0 +1,42 @@ +#include "describe_helpers.h" + +void assert_describe( + const char *expected_output, + const char *revparse_spec, + git_repository *repo, + git_describe_options *opts, + git_describe_format_options *fmt_opts) +{ + git_object *object; + git_buf label = GIT_BUF_INIT; + git_describe_result *result; + + cl_git_pass(git_revparse_single(&object, repo, revparse_spec)); + + cl_git_pass(git_describe_commit(&result, object, opts)); + cl_git_pass(git_describe_format(&label, result, fmt_opts)); + + cl_git_pass(p_fnmatch(expected_output, git_buf_cstr(&label), 0)); + + git_describe_result_free(result); + git_object_free(object); + git_buf_free(&label); +} + +void assert_describe_workdir( + const char *expected_output, + git_repository *repo, + git_describe_options *opts, + git_describe_format_options *fmt_opts) +{ + git_buf label = GIT_BUF_INIT; + git_describe_result *result; + + cl_git_pass(git_describe_workdir(&result, repo, opts)); + cl_git_pass(git_describe_format(&label, result, fmt_opts)); + + cl_git_pass(p_fnmatch(expected_output, git_buf_cstr(&label), 0)); + + git_describe_result_free(result); + git_buf_free(&label); +} diff --git a/tests/describe/describe_helpers.h b/tests/describe/describe_helpers.h new file mode 100644 index 000000000..16a0638e3 --- /dev/null +++ b/tests/describe/describe_helpers.h @@ -0,0 +1,15 @@ +#include "clar_libgit2.h" +#include "buffer.h" + +extern void assert_describe( + const char *expected_output, + const char *revparse_spec, + git_repository *repo, + git_describe_options *opts, + git_describe_format_options *fmt_opts); + +extern void assert_describe_workdir( + const char *expected_output, + git_repository *repo, + git_describe_options *opts, + git_describe_format_options *fmt_opts); diff --git a/tests/describe/t6120.c b/tests/describe/t6120.c new file mode 100644 index 000000000..2377335a5 --- /dev/null +++ b/tests/describe/t6120.c @@ -0,0 +1,156 @@ +#include "clar_libgit2.h" +#include "describe_helpers.h" +#include "repository.h" + +// Ported from https://github.com/git/git/blob/adfc1857bdb090786fd9d22c1acec39371c76048/t/t6120-describe.sh + +static git_repository *repo; + +void test_describe_t6120__initialize(void) +{ + repo = cl_git_sandbox_init("describe"); +} + +void test_describe_t6120__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_describe_t6120__default(void) +{ + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + + assert_describe("A-*", "HEAD", repo, &opts, &fmt_opts); + assert_describe("A-*", "HEAD^", repo, &opts, &fmt_opts); + assert_describe("R-*", "HEAD^^", repo, &opts, &fmt_opts); + assert_describe("A-*", "HEAD^^2", repo, &opts, &fmt_opts); + assert_describe("B", "HEAD^^2^", repo, &opts, &fmt_opts); + assert_describe("R-*", "HEAD^^^", repo, &opts, &fmt_opts); +} + +void test_describe_t6120__tags(void) +{ + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + opts.describe_strategy = GIT_DESCRIBE_TAGS; + + assert_describe("c-*", "HEAD", repo, &opts, &fmt_opts); + assert_describe("c-*", "HEAD^", repo, &opts, &fmt_opts); + assert_describe("e-*", "HEAD^^", repo, &opts, &fmt_opts); + assert_describe("c-*", "HEAD^^2", repo, &opts, &fmt_opts); + assert_describe("B", "HEAD^^2^", repo, &opts, &fmt_opts); + assert_describe("e", "HEAD^^^", repo, &opts, &fmt_opts); +} + +void test_describe_t6120__all(void) +{ + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + opts.describe_strategy = GIT_DESCRIBE_ALL; + + assert_describe("heads/master", "HEAD", repo, &opts, &fmt_opts); + assert_describe("tags/c-*", "HEAD^", repo, &opts, &fmt_opts); + assert_describe("tags/e", "HEAD^^^", repo, &opts, &fmt_opts); +} + +void test_describe_t6120__longformat(void) +{ + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + + fmt_opts.always_use_long_format = 1; + + assert_describe("B-0-*", "HEAD^^2^", repo, &opts, &fmt_opts); + assert_describe("A-3-*", "HEAD^^2", repo, &opts, &fmt_opts); +} + +void test_describe_t6120__firstparent(void) +{ + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + opts.describe_strategy = GIT_DESCRIBE_TAGS; + + assert_describe("c-7-*", "HEAD", repo, &opts, &fmt_opts); + + opts.only_follow_first_parent = 1; + assert_describe("e-3-*", "HEAD", repo, &opts, &fmt_opts); +} + +void test_describe_t6120__workdir(void) +{ + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + + assert_describe_workdir("A-*[0-9a-f]", repo, &opts, &fmt_opts); + cl_git_mkfile("describe/file", "something different"); + + fmt_opts.dirty_suffix = "-dirty"; + assert_describe_workdir("A-*[0-9a-f]-dirty", repo, &opts, &fmt_opts); + fmt_opts.dirty_suffix = ".mod"; + assert_describe_workdir("A-*[0-9a-f].mod", repo, &opts, &fmt_opts); +} + +static void commit_and_tag( + git_time_t *time, + const char *commit_msg, + const char *tag_name) +{ + git_index *index; + git_oid commit_id; + git_reference *ref; + + cl_git_pass(git_repository_index__weakptr(&index, repo)); + + cl_git_append2file("describe/file", "\n"); + + git_index_add_bypath(index, "describe/file"); + git_index_write(index); + + *time += 10; + cl_repo_commit_from_index(&commit_id, repo, NULL, *time, commit_msg); + + if (tag_name == NULL) + return; + + cl_git_pass(git_reference_create(&ref, repo, tag_name, &commit_id, 0, NULL, NULL)); + git_reference_free(ref); +} + +void test_describe_t6120__pattern(void) +{ + git_describe_options opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + git_oid tag_id; + git_object *head; + git_signature *tagger; + git_time_t time; + + /* set-up matching pattern tests */ + cl_git_pass(git_revparse_single(&head, repo, "HEAD")); + + time = 1380553019; + cl_git_pass(git_signature_new(&tagger, "tagger", "tagger@libgit2.org", time, 0)); + cl_git_pass(git_tag_create(&tag_id, repo, "test-annotated", head, tagger, "test-annotated", 0)); + git_signature_free(tagger); + git_object_free(head); + + commit_and_tag(&time, "one more", "refs/tags/test1-lightweight"); + commit_and_tag(&time, "yet another", "refs/tags/test2-lightweight"); + commit_and_tag(&time, "even more", NULL); + + + /* Exercize */ + opts.pattern = "test-*"; + assert_describe("test-annotated-*", "HEAD", repo, &opts, &fmt_opts); + + opts.describe_strategy = GIT_DESCRIBE_TAGS; + opts.pattern = "test1-*"; + assert_describe("test1-lightweight-*", "HEAD", repo, &opts, &fmt_opts); + + opts.pattern = "test2-*"; + assert_describe("test2-lightweight-*", "HEAD", repo, &opts, &fmt_opts); + + fmt_opts.always_use_long_format = 1; + assert_describe("test2-lightweight-*", "HEAD^", repo, &opts, &fmt_opts); +} diff --git a/tests/fetchhead/fetchhead_data.h b/tests/fetchhead/fetchhead_data.h index 94402abd5..c75b65b90 100644 --- a/tests/fetchhead/fetchhead_data.h +++ b/tests/fetchhead/fetchhead_data.h @@ -16,6 +16,11 @@ "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_WILDCARD_DATA2 \ + "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" \ + #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" \ @@ -25,6 +30,16 @@ "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_DATA2 \ + "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" \ + +#define FETCH_HEAD_NO_MERGE_DATA3 \ + "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" \ + "8f50ba15d49353813cc6e20298002c0d17b0a9ee\tnot-for-merge\ttag 'commit_tree' of git://github.com/libgit2/TestGitRepository\n" \ #define FETCH_HEAD_EXPLICIT_DATA \ "0966a434eb1a025db6b71485ab63a3bfbea520b6\t\tbranch 'first-merge' of git://github.com/libgit2/TestGitRepository\n" diff --git a/tests/fetchhead/nonetwork.c b/tests/fetchhead/nonetwork.c index 7b64a6339..c8191c5f5 100644 --- a/tests/fetchhead/nonetwork.c +++ b/tests/fetchhead/nonetwork.c @@ -335,7 +335,7 @@ void test_fetchhead_nonetwork__unborn_with_upstream(void) cl_git_pass(git_remote_set_url(remote, cl_fixture("testrepo.git"))); cl_git_pass(git_remote_save(remote)); - cl_git_pass(git_remote_fetch(remote, NULL, NULL)); + cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL)); git_remote_free(remote); cl_git_pass(git_repository_fetchhead_foreach(repo, assert_master_for_merge, NULL)); diff --git a/tests/index/names.c b/tests/index/names.c index 52922e9f1..c7619ed13 100644 --- a/tests/index/names.c +++ b/tests/index/names.c @@ -89,7 +89,7 @@ void test_index_names__cleaned_on_reset_hard(void) cl_git_pass(git_revparse_single(&target, repo, "3a34580")); test_index_names__add(); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL)); cl_assert(git_index_name_entrycount(repo_index) == 0); git_object_free(target); @@ -102,7 +102,7 @@ void test_index_names__cleaned_on_reset_mixed(void) cl_git_pass(git_revparse_single(&target, repo, "3a34580")); test_index_names__add(); - cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL, NULL)); cl_assert(git_index_name_entrycount(repo_index) == 0); git_object_free(target); diff --git a/tests/index/reuc.c b/tests/index/reuc.c index 0b4d71a6a..0b948a29e 100644 --- a/tests/index/reuc.c +++ b/tests/index/reuc.c @@ -298,7 +298,7 @@ void test_index_reuc__cleaned_on_reset_hard(void) cl_git_pass(git_revparse_single(&target, repo, "3a34580")); test_index_reuc__add(); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL)); cl_assert(reuc_entry_exists() == false); git_object_free(target); @@ -311,7 +311,7 @@ void test_index_reuc__cleaned_on_reset_mixed(void) cl_git_pass(git_revparse_single(&target, repo, "3a34580")); test_index_reuc__add(); - cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL, NULL)); cl_assert(reuc_entry_exists() == false); git_object_free(target); @@ -323,10 +323,10 @@ void test_index_reuc__retained_on_reset_soft(void) cl_git_pass(git_revparse_single(&target, repo, "3a34580")); - git_reset(repo, target, GIT_RESET_HARD, NULL, NULL); + git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL); test_index_reuc__add(); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); cl_assert(reuc_entry_exists() == true); git_object_free(target); diff --git a/tests/merge/merge_helpers.c b/tests/merge/merge_helpers.c index 154985f11..e3e703943 100644 --- a/tests/merge/merge_helpers.c +++ b/tests/merge/merge_helpers.c @@ -327,7 +327,7 @@ int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], int dircount(void *payload, git_buf *pathbuf) { - int *entries = payload; + size_t *entries = payload; size_t len = git_buf_len(pathbuf); if (len < 5 || strcmp(pathbuf->ptr + (git_buf_len(pathbuf) - 5), "/.git") != 0) diff --git a/tests/merge/merge_helpers.h b/tests/merge/merge_helpers.h index fddf8fab1..554c24b7c 100644 --- a/tests/merge/merge_helpers.h +++ b/tests/merge/merge_helpers.h @@ -49,7 +49,7 @@ struct merge_index_entry { uint16_t mode; - char oid_str[41]; + char oid_str[GIT_OID_HEXSZ+1]; int stage; char path[128]; }; @@ -70,9 +70,9 @@ struct merge_reuc_entry { unsigned int ancestor_mode; unsigned int our_mode; unsigned int their_mode; - char ancestor_oid_str[41]; - char our_oid_str[41]; - char their_oid_str[41]; + char ancestor_oid_str[GIT_OID_HEXSZ+1]; + char our_oid_str[GIT_OID_HEXSZ+1]; + char their_oid_str[GIT_OID_HEXSZ+1]; }; struct merge_index_conflict_data { diff --git a/tests/merge/trees/treediff.c b/tests/merge/trees/treediff.c index 2298a302b..8b47f7dee 100644 --- a/tests/merge/trees/treediff.c +++ b/tests/merge/trees/treediff.c @@ -3,7 +3,7 @@ #include "merge.h" #include "../merge_helpers.h" #include "diff.h" -#include "hashsig.h" +#include "git2/sys/hashsig.h" static git_repository *repo; diff --git a/tests/merge/workdir/dirty.c b/tests/merge/workdir/dirty.c index 2f776853e..0549b06b3 100644 --- a/tests/merge/workdir/dirty.c +++ b/tests/merge/workdir/dirty.c @@ -182,7 +182,7 @@ static void stage_content(char *content[]) cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT)); - cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL, NULL)); for (i = 0, filename = content[i], text = content[++i]; filename && text; @@ -209,7 +209,7 @@ static int merge_dirty_files(char *dirty_files[]) cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT)); - cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL, NULL)); write_files(dirty_files); @@ -229,7 +229,7 @@ static int merge_differently_filtered_files(char *files[]) cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT)); - cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL, NULL)); write_files(files); hack_index(files); @@ -266,7 +266,7 @@ void test_merge_workdir_dirty__unstaged_deletes_maintained(void) cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel(&head_object, head, GIT_OBJ_COMMIT)); - cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, head_object, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(p_unlink("merge-resolve/unchanged.txt")); diff --git a/tests/merge/workdir/simple.c b/tests/merge/workdir/simple.c index 327408dc9..fcd84dcd1 100644 --- a/tests/merge/workdir/simple.c +++ b/tests/merge/workdir/simple.c @@ -516,7 +516,7 @@ void test_merge_workdir_simple__directory_file(void) cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_DIR OURS_DIRECTORY_FILE, 1, NULL, NULL)); cl_git_pass(git_reference_name_to_id(&head_commit_id, repo, GIT_HEAD_FILE)); cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_id)); - cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_DIRECTORY_FILE)); cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0])); @@ -608,7 +608,7 @@ void test_merge_workdir_simple__binary(void) cl_git_pass(git_oid_fromstr(&their_oid, "ad01aebfdf2ac13145efafe3f9fcf798882f1730")); cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); - cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_merge_head_from_id(&their_head, repo, &their_oid)); diff --git a/tests/merge/workdir/submodules.c b/tests/merge/workdir/submodules.c index e093e77ab..eec9f14a9 100644 --- a/tests/merge/workdir/submodules.c +++ b/tests/merge/workdir/submodules.c @@ -44,7 +44,7 @@ void test_merge_workdir_submodules__automerge(void) cl_git_pass(git_reference_lookup(&our_ref, repo, "refs/heads/" SUBMODULE_MAIN_BRANCH)); cl_git_pass(git_commit_lookup(&our_commit, repo, git_reference_target(our_ref))); - cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref)); @@ -77,7 +77,7 @@ void test_merge_workdir_submodules__take_changed(void) cl_git_pass(git_reference_lookup(&our_ref, repo, "refs/heads/" SUBMODULE_MAIN_BRANCH)); cl_git_pass(git_commit_lookup(&our_commit, repo, git_reference_target(our_ref))); - cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER2_BRANCH)); cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref)); diff --git a/tests/network/fetchlocal.c b/tests/network/fetchlocal.c index 8809f427d..eb9a1087a 100644 --- a/tests/network/fetchlocal.c +++ b/tests/network/fetchlocal.c @@ -36,7 +36,7 @@ void test_network_fetchlocal__complete(void) cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); git_remote_set_callbacks(origin, &callbacks); cl_git_pass(git_remote_connect(origin, GIT_DIRECTION_FETCH)); - cl_git_pass(git_remote_download(origin)); + cl_git_pass(git_remote_download(origin, NULL)); cl_git_pass(git_remote_update_tips(origin, NULL, NULL)); cl_git_pass(git_reference_list(&refnames, repo)); @@ -74,7 +74,7 @@ void test_network_fetchlocal__partial(void) cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); git_remote_set_callbacks(origin, &callbacks); cl_git_pass(git_remote_connect(origin, GIT_DIRECTION_FETCH)); - cl_git_pass(git_remote_download(origin)); + cl_git_pass(git_remote_download(origin, NULL)); cl_git_pass(git_remote_update_tips(origin, NULL, NULL)); git_strarray_free(&refnames); @@ -127,3 +127,37 @@ void test_network_fetchlocal__clone_into_mirror(void) git_repository_free(repo); cl_fixture_cleanup("./foo.git"); } + +void test_network_fetchlocal__multi_remotes(void) +{ + git_repository *repo = cl_git_sandbox_init("testrepo.git"); + git_remote *test, *test2; + git_strarray refnames = {0}; + git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; + + callbacks.transfer_progress = transfer_cb; + cl_git_pass(git_remote_load(&test, repo, "test")); + cl_git_pass(git_remote_set_url(test, cl_git_fixture_url("testrepo.git"))); + git_remote_set_callbacks(test, &callbacks); + cl_git_pass(git_remote_connect(test, GIT_DIRECTION_FETCH)); + cl_git_pass(git_remote_download(test, NULL)); + cl_git_pass(git_remote_update_tips(test, NULL, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(32, (int)refnames.count); + + cl_git_pass(git_remote_load(&test2, repo, "test_with_pushurl")); + cl_git_pass(git_remote_set_url(test2, cl_git_fixture_url("testrepo.git"))); + git_remote_set_callbacks(test2, &callbacks); + cl_git_pass(git_remote_connect(test2, GIT_DIRECTION_FETCH)); + cl_git_pass(git_remote_download(test2, NULL)); + cl_git_pass(git_remote_update_tips(test2, NULL, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(44, (int)refnames.count); + + git_strarray_free(&refnames); + git_remote_free(test); + git_remote_free(test2); + git_repository_free(repo); +} diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c index f1084fc38..c6c9e4ca9 100644 --- a/tests/network/remote/local.c +++ b/tests/network/remote/local.c @@ -116,16 +116,20 @@ void test_network_remote_local__nested_tags_are_completely_peeled(void) void test_network_remote_local__shorthand_fetch_refspec0(void) { - const char *refspec = "master:remotes/sloppy/master"; - const char *refspec2 = "master:boh/sloppy/master"; + char *refspec_strings[] = { + "master:remotes/sloppy/master", + "master:boh/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 2, + }; git_reference *ref; connect_to_local_repository(cl_fixture("testrepo.git")); - cl_git_pass(git_remote_add_fetch(remote, refspec)); - cl_git_pass(git_remote_add_fetch(remote, refspec2)); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, &array)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master")); @@ -137,17 +141,21 @@ void test_network_remote_local__shorthand_fetch_refspec0(void) void test_network_remote_local__shorthand_fetch_refspec1(void) { - const char *refspec = "master"; - const char *refspec2 = "hard_tag"; + char *refspec_strings[] = { + "master", + "hard_tag", + }; + git_strarray array = { + refspec_strings, + 2, + }; git_reference *ref; connect_to_local_repository(cl_fixture("testrepo.git")); git_remote_clear_refspecs(remote); - cl_git_pass(git_remote_add_fetch(remote, refspec)); - cl_git_pass(git_remote_add_fetch(remote, refspec2)); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, &array)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); cl_git_fail(git_reference_lookup(&ref, repo, "refs/remotes/master")); @@ -162,7 +170,7 @@ void test_network_remote_local__tagopt(void) connect_to_local_repository(cl_fixture("testrepo.git")); git_remote_set_autotag(remote, GIT_REMOTE_DOWNLOAD_TAGS_ALL); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, NULL)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); @@ -174,14 +182,20 @@ void test_network_remote_local__tagopt(void) void test_network_remote_local__push_to_bare_remote(void) { + char *refspec_strings[] = { + "master:master", + }; + git_strarray array = { + refspec_strings, + 1, + }; /* Should be able to push to a bare remote */ git_remote *localremote; git_push *push; /* Get some commits */ connect_to_local_repository(cl_fixture("testrepo.git")); - cl_git_pass(git_remote_add_fetch(remote, "master:master")); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, &array)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); git_remote_disconnect(remote); @@ -210,6 +224,13 @@ void test_network_remote_local__push_to_bare_remote(void) void test_network_remote_local__push_to_bare_remote_with_file_url(void) { + char *refspec_strings[] = { + "master:master", + }; + git_strarray array = { + refspec_strings, + 1, + }; /* Should be able to push to a bare remote */ git_remote *localremote; git_push *push; @@ -217,8 +238,7 @@ void test_network_remote_local__push_to_bare_remote_with_file_url(void) /* Get some commits */ connect_to_local_repository(cl_fixture("testrepo.git")); - cl_git_pass(git_remote_add_fetch(remote, "master:master")); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, &array)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); git_remote_disconnect(remote); @@ -251,14 +271,20 @@ void test_network_remote_local__push_to_bare_remote_with_file_url(void) void test_network_remote_local__push_to_non_bare_remote(void) { + char *refspec_strings[] = { + "master:master", + }; + git_strarray array = { + refspec_strings, + 1, + }; /* Shouldn't be able to push to a non-bare remote */ git_remote *localremote; git_push *push; /* Get some commits */ connect_to_local_repository(cl_fixture("testrepo.git")); - cl_git_pass(git_remote_add_fetch(remote, "master:master")); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, &array)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); git_remote_disconnect(remote); @@ -287,7 +313,13 @@ void test_network_remote_local__push_to_non_bare_remote(void) void test_network_remote_local__fetch(void) { - const char *refspec = "master:remotes/sloppy/master"; + char *refspec_strings[] = { + "master:remotes/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 1, + }; git_reflog *log; const git_reflog_entry *entry; @@ -297,9 +329,8 @@ void test_network_remote_local__fetch(void) cl_git_pass(git_signature_now(&sig, "Foo Bar", "foo@example.com")); connect_to_local_repository(cl_fixture("testrepo.git")); - cl_git_pass(git_remote_add_fetch(remote, refspec)); - cl_git_pass(git_remote_fetch(remote, sig, "UPDAAAAAATE!!")); + cl_git_pass(git_remote_fetch(remote, &array, sig, "UPDAAAAAATE!!")); cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master")); git_reference_free(ref); @@ -316,7 +347,13 @@ void test_network_remote_local__fetch(void) void test_network_remote_local__reflog(void) { - const char *refspec = "master:remotes/sloppy/master"; + char *refspec_strings[] = { + "master:remotes/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 1, + }; git_reflog *log; const git_reflog_entry *entry; @@ -325,9 +362,8 @@ void test_network_remote_local__reflog(void) cl_git_pass(git_signature_now(&sig, "Foo Bar", "foo@example.com")); connect_to_local_repository(cl_fixture("testrepo.git")); - cl_git_pass(git_remote_add_fetch(remote, refspec)); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, &array)); cl_git_pass(git_remote_update_tips(remote, sig, "UPDAAAAAATE!!")); cl_git_pass(git_reflog_read(&log, repo, "refs/remotes/sloppy/master")); @@ -342,7 +378,13 @@ void test_network_remote_local__reflog(void) void test_network_remote_local__fetch_default_reflog_message(void) { - const char *refspec = "master:remotes/sloppy/master"; + char *refspec_strings[] = { + "master:remotes/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 1, + }; git_reflog *log; const git_reflog_entry *entry; @@ -352,9 +394,8 @@ void test_network_remote_local__fetch_default_reflog_message(void) cl_git_pass(git_signature_now(&sig, "Foo Bar", "foo@example.com")); connect_to_local_repository(cl_fixture("testrepo.git")); - cl_git_pass(git_remote_add_fetch(remote, refspec)); - cl_git_pass(git_remote_fetch(remote, sig, NULL)); + cl_git_pass(git_remote_fetch(remote, &array, sig, NULL)); cl_git_pass(git_reflog_read(&log, repo, "refs/remotes/sloppy/master")); cl_assert_equal_i(1, git_reflog_entrycount(log)); @@ -367,3 +408,24 @@ void test_network_remote_local__fetch_default_reflog_message(void) git_reflog_free(log); git_signature_free(sig); } + +void test_network_remote_local__opportunistic_update(void) +{ + git_reference *ref; + char *refspec_strings[] = { + "master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + + /* this remote has a passive refspec of "refs/heads/<star>:refs/remotes/origin/<star>" */ + cl_git_pass(git_remote_create(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"))); + /* and we pass the active refspec "master" */ + cl_git_pass(git_remote_fetch(remote, &array, NULL, NULL)); + + /* and we expect that to update our copy of origin's master */ + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/origin/master")); + git_reference_free(ref); +} diff --git a/tests/network/remote/remotes.c b/tests/network/remote/remotes.c index d176774ea..df424e961 100644 --- a/tests/network/remote/remotes.c +++ b/tests/network/remote/remotes.c @@ -547,6 +547,7 @@ void test_network_remote_remotes__single_branch(void) } cl_assert_equal_i(1, count); + git_strarray_free(&refs); git_repository_free(repo); } diff --git a/tests/object/raw/chars.c b/tests/object/raw/chars.c index 206bf7119..cde0bdbf6 100644 --- a/tests/object/raw/chars.c +++ b/tests/object/raw/chars.c @@ -12,7 +12,7 @@ void test_object_raw_chars__find_invalid_chars_in_oid(void) 0xb7, 0x75, 0x21, 0x3c, 0x23, 0xa8, 0xbd, 0x74, 0xf5, 0xe0, }; - char in[41] = "16a67770b7d8d72317c4b775213c23a8bd74f5e0"; + char in[] = "16a67770b7d8d72317c4b775213c23a8bd74f5e0"; unsigned int i; for (i = 0; i < 256; i++) { diff --git a/tests/odb/foreach.c b/tests/odb/foreach.c index 56daf7574..75448a2f7 100644 --- a/tests/odb/foreach.c +++ b/tests/odb/foreach.c @@ -87,7 +87,7 @@ void test_odb_foreach__files_in_objects_dir(void) git_repository *repo; git_odb *odb; git_buf buf = GIT_BUF_INIT; - size_t nobj = 0; + int nobj = 0; cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); diff --git a/tests/online/clone.c b/tests/online/clone.c index 6a6c049f8..13abd39bd 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -473,8 +473,95 @@ void test_online_clone__ssh_cannot_change_username(void) cl_git_fail(git_clone(&g_repo, "ssh://git@github.com/libgit2/TestGitRepository", "./foo", &g_options)); } +int ssh_certificate_check(git_cert *cert, int valid, const char *host, void *payload) +{ + git_cert_hostkey *key; + git_oid expected = {{0}}, actual = {{0}}; + const char *expected_str; + + GIT_UNUSED(valid); + GIT_UNUSED(payload); + + expected_str = cl_getenv("GITTEST_REMOTE_SSH_FINGERPRINT"); + cl_assert(expected_str); + + cl_git_pass(git_oid_fromstrp(&expected, expected_str)); + cl_assert_equal_i(GIT_CERT_HOSTKEY_LIBSSH2, cert->cert_type); + key = (git_cert_hostkey *) cert; + + /* + * We need to figure out how long our input was to check for + * the type. Here we abuse the fact that both hashes fit into + * our git_oid type. + */ + if (strlen(expected_str) == 32 && key->type & GIT_CERT_SSH_MD5) { + memcpy(&actual.id, key->hash_md5, 16); + } else if (strlen(expected_str) == 40 && key->type & GIT_CERT_SSH_SHA1) { + memcpy(&actual, key->hash_sha1, 20); + } else { + cl_fail("Cannot find a usable SSH hash"); + } + + cl_assert(!memcmp(&expected, &actual, 20)); + + cl_assert_equal_s("localhost", host); + + return GIT_EUSER; +} + +void test_online_clone__ssh_cert(void) +{ + g_options.remote_callbacks.certificate_check = ssh_certificate_check; + + if (!cl_getenv("GITTEST_REMOTE_SSH_FINGERPRINT")) + cl_skip(); + + cl_git_fail_with(GIT_EUSER, git_clone(&g_repo, "ssh://localhost/foo", "./foo", &g_options)); +} + void test_online_clone__url_with_no_path_returns_EINVALIDSPEC(void) { cl_git_fail_with(git_clone(&g_repo, "http://github.com", "./foo", &g_options), GIT_EINVALIDSPEC); } + +static int fail_certificate_check(git_cert *cert, int valid, const char *host, void *payload) +{ + GIT_UNUSED(cert); + GIT_UNUSED(valid); + GIT_UNUSED(host); + GIT_UNUSED(payload); + + return GIT_ECERTIFICATE; +} + +void test_online_clone__certificate_invalid(void) +{ + g_options.remote_callbacks.certificate_check = fail_certificate_check; + + cl_git_fail_with(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options), + GIT_ECERTIFICATE); + +#ifdef GIT_SSH + cl_git_fail_with(git_clone(&g_repo, "ssh://github.com/libgit2/TestGitRepository", "./foo", &g_options), + GIT_ECERTIFICATE); +#endif +} + +static int succeed_certificate_check(git_cert *cert, int valid, const char *host, void *payload) +{ + GIT_UNUSED(cert); + GIT_UNUSED(valid); + GIT_UNUSED(payload); + + cl_assert_equal_s("github.com", host); + + return 0; +} + +void test_online_clone__certificate_valid(void) +{ + g_options.remote_callbacks.certificate_check = succeed_certificate_check; + + cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options)); +} diff --git a/tests/online/fetch.c b/tests/online/fetch.c index f03a6faa6..ce92ee82b 100644 --- a/tests/online/fetch.c +++ b/tests/online/fetch.c @@ -47,7 +47,7 @@ static void do_fetch(const char *url, git_remote_autotag_option_t flag, int n) git_remote_set_callbacks(remote, &callbacks); git_remote_set_autotag(remote, flag); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, NULL)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); git_remote_disconnect(remote); cl_assert_equal_i(counter, n); @@ -86,11 +86,11 @@ void test_online_fetch__fetch_twice(void) git_remote *remote; cl_git_pass(git_remote_create(&remote, _repo, "test", "git://github.com/libgit2/TestGitRepository.git")); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, NULL)); git_remote_disconnect(remote); git_remote_connect(remote, GIT_DIRECTION_FETCH); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, NULL)); git_remote_disconnect(remote); git_remote_free(remote); @@ -128,7 +128,7 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date callbacks.transfer_progress = &transferProgressCallback; callbacks.payload = &invoked; git_remote_set_callbacks(remote, &callbacks); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, NULL)); cl_assert_equal_i(false, invoked); @@ -162,7 +162,7 @@ void test_online_fetch__can_cancel(void) git_remote_set_callbacks(remote, &callbacks); cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); - cl_git_fail_with(git_remote_download(remote), -4321); + cl_git_fail_with(git_remote_download(remote, NULL), -4321); git_remote_disconnect(remote); git_remote_free(remote); } diff --git a/tests/online/fetchhead.c b/tests/online/fetchhead.c index 0b3f20db1..bd423bbb0 100644 --- a/tests/online/fetchhead.c +++ b/tests/online/fetchhead.c @@ -40,17 +40,19 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet git_remote *remote; git_buf fetchhead_buf = GIT_BUF_INIT; int equals = 0; + git_strarray array, *active_refs = NULL; cl_git_pass(git_remote_load(&remote, g_repo, "origin")); git_remote_set_autotag(remote, GIT_REMOTE_DOWNLOAD_TAGS_AUTO); if(fetchspec != NULL) { - git_remote_clear_refspecs(remote); - git_remote_add_fetch(remote, fetchspec); + array.count = 1; + array.strings = (char **) &fetchspec; + active_refs = &array; } cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); - cl_git_pass(git_remote_download(remote)); + cl_git_pass(git_remote_download(remote, active_refs)); cl_git_pass(git_remote_update_tips(remote, NULL, NULL)); git_remote_disconnect(remote); git_remote_free(remote); @@ -67,6 +69,11 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet void test_online_fetchhead__wildcard_spec(void) { fetchhead_test_clone(); + fetchhead_test_fetch(NULL, FETCH_HEAD_WILDCARD_DATA2); + cl_git_pass(git_tag_delete(g_repo, "annotated_tag")); + cl_git_pass(git_tag_delete(g_repo, "blob")); + cl_git_pass(git_tag_delete(g_repo, "commit_tree")); + cl_git_pass(git_tag_delete(g_repo, "nearly-dangling")); fetchhead_test_fetch(NULL, FETCH_HEAD_WILDCARD_DATA); } @@ -87,5 +94,12 @@ void test_online_fetchhead__no_merges(void) cl_git_pass(git_config_delete_entry(config, "branch.master.merge")); git_config_free(config); + fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA2); + cl_git_pass(git_tag_delete(g_repo, "annotated_tag")); + cl_git_pass(git_tag_delete(g_repo, "blob")); + cl_git_pass(git_tag_delete(g_repo, "commit_tree")); + cl_git_pass(git_tag_delete(g_repo, "nearly-dangling")); fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA); + cl_git_pass(git_tag_delete(g_repo, "commit_tree")); + fetchhead_test_fetch(NULL, FETCH_HEAD_NO_MERGE_DATA3); } diff --git a/tests/online/push.c b/tests/online/push.c index 70ec705fe..b09c7ad1f 100644 --- a/tests/online/push.c +++ b/tests/online/push.c @@ -408,7 +408,7 @@ void test_online_push__initialize(void) /* Now that we've deleted everything, fetch from the remote */ cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_FETCH)); - cl_git_pass(git_remote_download(_remote)); + cl_git_pass(git_remote_download(_remote, NULL)); cl_git_pass(git_remote_update_tips(_remote, NULL, NULL)); git_remote_disconnect(_remote); } diff --git a/tests/online/push_util.h b/tests/online/push_util.h index a7207c49e..7736912d6 100644 --- a/tests/online/push_util.h +++ b/tests/online/push_util.h @@ -12,7 +12,7 @@ extern const git_oid OID_ZERO; * @param data pointer to a record_callbacks_data instance */ #define RECORD_CALLBACKS_INIT(data) \ - { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, record_update_tips_cb, data } + { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, data } typedef struct { char *name; diff --git a/tests/pack/packbuilder.c b/tests/pack/packbuilder.c index 1059424ed..29f3e2d64 100644 --- a/tests/pack/packbuilder.c +++ b/tests/pack/packbuilder.c @@ -47,7 +47,7 @@ void test_pack_packbuilder__cleanup(void) git_indexer_free(_indexer); _indexer = NULL; - p_chdir(".."); + cl_git_pass(p_chdir("..")); cl_git_sandbox_cleanup(); _repo = NULL; } @@ -93,7 +93,7 @@ void test_pack_packbuilder__create_pack(void) git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; git_hash_ctx ctx; git_oid hash; - char hex[41]; hex[40] = '\0'; + char hex[GIT_OID_HEXSZ+1]; hex[GIT_OID_HEXSZ] = '\0'; seed_packbuilder(); @@ -135,7 +135,7 @@ void test_pack_packbuilder__create_pack(void) void test_pack_packbuilder__get_hash(void) { - char hex[41]; hex[40] = '\0'; + char hex[GIT_OID_HEXSZ+1]; hex[GIT_OID_HEXSZ] = '\0'; seed_packbuilder(); diff --git a/tests/path/core.c b/tests/path/core.c index be63e309b..45f54df29 100644 --- a/tests/path/core.c +++ b/tests/path/core.c @@ -16,8 +16,6 @@ static void test_make_relative( void test_path_core__make_relative(void) { - git_buf buf = GIT_BUF_INIT; - test_make_relative("foo.c", "/path/to/foo.c", "/path/to", 0); test_make_relative("bar/foo.c", "/path/to/bar/foo.c", "/path/to", 0); test_make_relative("foo.c", "/path/to/foo.c", "/path/to/", 0); diff --git a/tests/refs/transactions.c b/tests/refs/transactions.c new file mode 100644 index 000000000..39ea1cae5 --- /dev/null +++ b/tests/refs/transactions.c @@ -0,0 +1,110 @@ +#include "clar_libgit2.h" +#include "git2/transaction.h" + +static git_repository *g_repo; +static git_transaction *g_tx; + +void test_refs_transactions__initialize(void) +{ + g_repo = cl_git_sandbox_init("testrepo"); + cl_git_pass(git_transaction_new(&g_tx, g_repo)); +} + +void test_refs_transactions__cleanup(void) +{ + git_transaction_free(g_tx); + cl_git_sandbox_cleanup(); +} + +void test_refs_transactions__single_ref_oid(void) +{ + git_reference *ref; + git_oid id; + + git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + + cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master")); + cl_git_pass(git_transaction_set_target(g_tx, "refs/heads/master", &id, NULL, NULL)); + cl_git_pass(git_transaction_commit(g_tx)); + + cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master")); + + cl_assert(!git_oid_cmp(&id, git_reference_target(ref))); + git_reference_free(ref); +} + +void test_refs_transactions__single_ref_symbolic(void) +{ + git_reference *ref; + + cl_git_pass(git_transaction_lock_ref(g_tx, "HEAD")); + cl_git_pass(git_transaction_set_symbolic_target(g_tx, "HEAD", "refs/heads/foo", NULL, NULL)); + cl_git_pass(git_transaction_commit(g_tx)); + + cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD")); + + cl_assert_equal_s("refs/heads/foo", git_reference_symbolic_target(ref)); + git_reference_free(ref); +} + +void test_refs_transactions__single_ref_mix_types(void) +{ + git_reference *ref; + git_oid id; + + git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + + cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master")); + cl_git_pass(git_transaction_lock_ref(g_tx, "HEAD")); + cl_git_pass(git_transaction_set_symbolic_target(g_tx, "refs/heads/master", "refs/heads/foo", NULL, NULL)); + cl_git_pass(git_transaction_set_target(g_tx, "HEAD", &id, NULL, NULL)); + cl_git_pass(git_transaction_commit(g_tx)); + + cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master")); + cl_assert_equal_s("refs/heads/foo", git_reference_symbolic_target(ref)); + git_reference_free(ref); + + cl_git_pass(git_reference_lookup(&ref, g_repo, "HEAD")); + cl_assert(!git_oid_cmp(&id, git_reference_target(ref))); + git_reference_free(ref); +} + +void test_refs_transactions__single_ref_delete(void) +{ + git_reference *ref; + + cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master")); + cl_git_pass(git_transaction_remove(g_tx, "refs/heads/master")); + cl_git_pass(git_transaction_commit(g_tx)); + + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, g_repo, "refs/heads/master")); +} + +void test_refs_transactions__single_create(void) +{ + git_reference *ref; + const char *name = "refs/heads/new-branch"; + git_oid id; + + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, g_repo, name)); + + cl_git_pass(git_transaction_lock_ref(g_tx, name)); + + git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + cl_git_pass(git_transaction_set_target(g_tx, name, &id, NULL, NULL)); + cl_git_pass(git_transaction_commit(g_tx)); + + cl_git_pass(git_reference_lookup(&ref, g_repo, name)); + cl_assert(!git_oid_cmp(&id, git_reference_target(ref))); + git_reference_free(ref); +} + +void test_refs_transactions__unlocked_set(void) +{ + git_oid id; + + cl_git_pass(git_transaction_lock_ref(g_tx, "refs/heads/master")); + git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + cl_git_fail_with(GIT_ENOTFOUND, git_transaction_set_target(g_tx, "refs/heads/foo", &id, NULL, NULL)); + cl_git_pass(git_transaction_commit(g_tx)); +} diff --git a/tests/repo/init.c b/tests/repo/init.c index 999afd625..189b0894a 100644 --- a/tests/repo/init.c +++ b/tests/repo/init.c @@ -423,6 +423,7 @@ void test_repo_init__relative_gitdir_2(void) /* make the directory first, then it should succeed */ cl_git_pass(git_repository_init_ext(&_repo, "root/b/my_repository", &opts)); + git_buf_free(&full_path); cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "root/b/c_wd/")); cl_assert(!git__suffixcmp(git_repository_path(_repo), "root/b/my_repository/")); diff --git a/tests/reset/hard.c b/tests/reset/hard.c index c6bf7a8ac..e8cf10071 100644 --- a/tests/reset/hard.c +++ b/tests/reset/hard.c @@ -71,7 +71,7 @@ void test_reset_hard__resetting_reverts_modified_files(void) cl_git_pass(git_revparse_single(&target, repo, "26a125e")); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL)); for (i = 0; i < 4; ++i) { cl_git_pass(git_buf_joinpath(&path, wd, files[i])); @@ -96,7 +96,7 @@ void test_reset_hard__cannot_reset_in_a_bare_repository(void) cl_git_pass(git_revparse_single(&target, bare, KNOWN_COMMIT_IN_BARE_REPO)); - cl_assert_equal_i(GIT_EBAREREPO, git_reset(bare, target, GIT_RESET_HARD, NULL, NULL)); + cl_assert_equal_i(GIT_EBAREREPO, git_reset(bare, target, GIT_RESET_HARD, NULL, NULL, NULL)); git_repository_free(bare); } @@ -152,7 +152,7 @@ void test_reset_hard__resetting_reverts_unmerged(void) cl_git_pass(git_index_write(index)); cl_git_pass(git_revparse_single(&target, repo, "26a125e")); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL)); cl_assert(git_path_exists("status/conflicting_file") == 0); @@ -183,7 +183,7 @@ void test_reset_hard__cleans_up_merge(void) cl_git_mkfile(git_buf_cstr(&orig_head_path), "0017bd4ab1ec30440b17bae1680cff124ab5f1f6"); cl_git_pass(git_revparse_single(&target, repo, "0017bd4")); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL)); cl_assert(!git_path_exists(git_buf_cstr(&merge_head_path))); cl_assert(!git_path_exists(git_buf_cstr(&merge_msg_path))); @@ -208,7 +208,7 @@ void test_reset_hard__reflog_is_correct(void) /* Branch not moving, no reflog entry */ cl_git_pass(git_revparse_single(&target, repo, "HEAD^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL)); reflog_check(repo, "HEAD", 3, "emeric.fermas@gmail.com", exp_msg); reflog_check(repo, "refs/heads/master", 3, "emeric.fermas@gmail.com", exp_msg); @@ -217,7 +217,7 @@ void test_reset_hard__reflog_is_correct(void) /* Moved branch, expect default message */ exp_msg = "reset: moving"; cl_git_pass(git_revparse_single(&target, repo, "HEAD~^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, NULL)); reflog_check(repo, "HEAD", 4, NULL, exp_msg); reflog_check(repo, "refs/heads/master", 4, NULL, exp_msg); @@ -226,7 +226,7 @@ void test_reset_hard__reflog_is_correct(void) /* Moved branch, expect custom message */ exp_msg = "message1"; cl_git_pass(git_revparse_single(&target, repo, "HEAD~^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, "message1")); + cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL, NULL, "message1")); reflog_check(repo, "HEAD", 5, NULL, exp_msg); reflog_check(repo, "refs/heads/master", 5, NULL, exp_msg); } diff --git a/tests/reset/mixed.c b/tests/reset/mixed.c index 55b8a2f88..cb7a44d5f 100644 --- a/tests/reset/mixed.c +++ b/tests/reset/mixed.c @@ -29,7 +29,7 @@ void test_reset_mixed__cannot_reset_in_a_bare_repository(void) cl_git_pass(git_revparse_single(&target, bare, KNOWN_COMMIT_IN_BARE_REPO)); - cl_assert_equal_i(GIT_EBAREREPO, git_reset(bare, target, GIT_RESET_MIXED, NULL, NULL)); + cl_assert_equal_i(GIT_EBAREREPO, git_reset(bare, target, GIT_RESET_MIXED, NULL, NULL, NULL)); git_repository_free(bare); } @@ -42,7 +42,7 @@ void test_reset_mixed__resetting_refreshes_the_index_to_the_commit_tree(void) cl_assert(status == GIT_STATUS_CURRENT); cl_git_pass(git_revparse_single(&target, repo, "605812a")); - cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL, NULL)); cl_git_pass(git_status_file(&status, repo, "macro_bad")); cl_assert(status == GIT_STATUS_WT_NEW); @@ -57,7 +57,7 @@ void test_reset_mixed__reflog_is_correct(void) /* Branch not moving, no reflog entry */ cl_git_pass(git_revparse_single(&target, repo, "HEAD^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL, NULL)); reflog_check(repo, "HEAD", 9, "yoram.harmelin@gmail.com", exp_msg); reflog_check(repo, "refs/heads/master", 9, "yoram.harmelin@gmail.com", exp_msg); @@ -67,7 +67,7 @@ void test_reset_mixed__reflog_is_correct(void) /* Moved branch, expect default message */ exp_msg = "reset: moving"; cl_git_pass(git_revparse_single(&target, repo, "HEAD~^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL, NULL)); reflog_check(repo, "HEAD", 10, NULL, exp_msg); reflog_check(repo, "refs/heads/master", 10, NULL, exp_msg); @@ -77,7 +77,7 @@ void test_reset_mixed__reflog_is_correct(void) /* Moved branch, expect custom message */ exp_msg = "message1"; cl_git_pass(git_revparse_single(&target, repo, "HEAD~^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, "message1")); + cl_git_pass(git_reset(repo, target, GIT_RESET_MIXED, NULL, NULL, "message1")); reflog_check(repo, "HEAD", 11, NULL, exp_msg); reflog_check(repo, "refs/heads/master", 11, NULL, exp_msg); } diff --git a/tests/reset/soft.c b/tests/reset/soft.c index c889c0355..95b86683a 100644 --- a/tests/reset/soft.c +++ b/tests/reset/soft.c @@ -30,7 +30,7 @@ static void assert_reset_soft(bool should_be_detached) cl_assert(git_repository_head_detached(repo) == should_be_detached); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); cl_assert(git_repository_head_detached(repo) == should_be_detached); @@ -61,7 +61,7 @@ void test_reset_soft__resetting_to_the_commit_pointed_at_by_the_Head_does_not_ch cl_git_pass(git_revparse_single(&target, repo, raw_head_oid)); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); cl_git_pass(git_oid_streq(&oid, raw_head_oid)); @@ -74,7 +74,7 @@ void test_reset_soft__resetting_to_a_tag_sets_the_Head_to_the_peeled_commit(void /* b25fa35 is a tag, pointing to another tag which points to commit e90810b */ cl_git_pass(git_revparse_single(&target, repo, "b25fa35")); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); cl_assert(git_repository_head_detached(repo) == false); cl_git_pass(git_reference_name_to_id(&oid, repo, "HEAD")); @@ -86,12 +86,12 @@ void test_reset_soft__cannot_reset_to_a_tag_not_pointing_at_a_commit(void) /* 53fc32d is the tree of commit e90810b */ cl_git_pass(git_revparse_single(&target, repo, "53fc32d")); - cl_git_fail(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_fail(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); git_object_free(target); /* 521d87c is an annotated tag pointing to a blob */ cl_git_pass(git_revparse_single(&target, repo, "521d87c")); - cl_git_fail(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_fail(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); } void test_reset_soft__resetting_against_an_unborn_head_repo_makes_the_head_no_longer_unborn(void) @@ -104,7 +104,7 @@ void test_reset_soft__resetting_against_an_unborn_head_repo_makes_the_head_no_lo cl_assert_equal_i(true, git_repository_head_unborn(repo)); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); cl_assert_equal_i(false, git_repository_head_unborn(repo)); @@ -124,7 +124,7 @@ void test_reset_soft__fails_when_merging(void) cl_git_pass(git_revparse_single(&target, repo, KNOWN_COMMIT_IN_BARE_REPO)); - cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path))); git_buf_free(&merge_head_path); @@ -152,7 +152,7 @@ void test_reset_soft__fails_when_index_contains_conflicts_independently_of_MERGE cl_git_pass(git_reference_peel(&target, head, GIT_OBJ_COMMIT)); git_reference_free(head); - cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); } void test_reset_soft_reflog_is_correct(void) @@ -164,19 +164,19 @@ void test_reset_soft_reflog_is_correct(void) /* Branch not moving, no reflog entry */ cl_git_pass(git_revparse_single(&target, repo, "HEAD^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); reflog_check(repo, "HEAD", 9, "yoram.harmelin@gmail.com", exp_msg); reflog_check(repo, "refs/heads/master", 9, "yoram.harmelin@gmail.com", exp_msg); /* Moved branch, expect default message */ cl_git_pass(git_revparse_single(&target, repo, "HEAD~^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL)); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, NULL)); reflog_check(repo, "HEAD", 9, "yoram.harmelin@gmail.com", exp_msg); reflog_check(repo, "refs/heads/master", 10, NULL, "reset: moving"); /* Moved branch, expect custom message */ cl_git_pass(git_revparse_single(&target, repo, "HEAD~^{commit}")); - cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, "message1")); + cl_git_pass(git_reset(repo, target, GIT_RESET_SOFT, NULL, NULL, "message1")); reflog_check(repo, "HEAD", 9, "yoram.harmelin@gmail.com", exp_msg); reflog_check(repo, "refs/heads/master", 11, NULL, "message1"); } diff --git a/tests/resources/config/config12 b/tests/resources/config/config12 index b57a81b08..6917880b5 100644 --- a/tests/resources/config/config12 +++ b/tests/resources/config/config12 @@ -1,7 +1,13 @@ [some "section"] test = hi ; comment + test2 = hello ; comment + test3 = welcome #comment other = "hello! \" ; ; ; " ; more test + other2 = "cool! \" # # # " # more test multi = "hi, this is a ; \ multiline comment # with ;\n special chars \ and other stuff !@#" + multi2 = "good, this is a ; \ +multiline comment # with ;\n special chars \ +and other stuff !@#" #^^^ back = "this is \ba phrase" diff --git a/tests/resources/describe/.gitted/HEAD b/tests/resources/describe/.gitted/HEAD new file mode 100644 index 000000000..cb4380516 --- /dev/null +++ b/tests/resources/describe/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master
diff --git a/tests/resources/describe/.gitted/config b/tests/resources/describe/.gitted/config new file mode 100644 index 000000000..454e576b9 --- /dev/null +++ b/tests/resources/describe/.gitted/config @@ -0,0 +1,8 @@ +[core]
+ repositoryformatversion = 0
+ filemode = false
+ bare = false
+ logallrefupdates = true
+ symlinks = false
+ ignorecase = true
+ hideDotFiles = dotGitOnly
diff --git a/tests/resources/describe/.gitted/index b/tests/resources/describe/.gitted/index Binary files differnew file mode 100644 index 000000000..f5f35e26b --- /dev/null +++ b/tests/resources/describe/.gitted/index diff --git a/tests/resources/describe/.gitted/logs/HEAD b/tests/resources/describe/.gitted/logs/HEAD new file mode 100644 index 000000000..fc49c6fa3 --- /dev/null +++ b/tests/resources/describe/.gitted/logs/HEAD @@ -0,0 +1,14 @@ +0000000000000000000000000000000000000000 108b485d8268ea595df8ffea74f0f4b186577d32 nulltoken <emeric.fermas@gmail.com> 1380209394 +0200 commit (initial): initial
+108b485d8268ea595df8ffea74f0f4b186577d32 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f nulltoken <emeric.fermas@gmail.com> 1380209404 +0200 commit: second
+4d6558b8fa764baeb0f19c1e857df91e0eda5a0f b240c0fb88c5a629e00ebc1275fa1f33e364a705 nulltoken <emeric.fermas@gmail.com> 1380209414 +0200 commit: third
+b240c0fb88c5a629e00ebc1275fa1f33e364a705 81f4b1aac643e6983fab370eae8aefccecbf3a4c nulltoken <emeric.fermas@gmail.com> 1380209425 +0200 commit: A
+81f4b1aac643e6983fab370eae8aefccecbf3a4c 6126a5f9c57ebc81e64370ec3095184ad92dab1c nulltoken <emeric.fermas@gmail.com> 1380209445 +0200 commit: c
+6126a5f9c57ebc81e64370ec3095184ad92dab1c 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f nulltoken <emeric.fermas@gmail.com> 1380209455 +0200 reset: moving to 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f
+4d6558b8fa764baeb0f19c1e857df91e0eda5a0f 31fc9136820b507e938a9c6b88bf2c567a9f6f4b nulltoken <emeric.fermas@gmail.com> 1380209465 +0200 commit: B
+31fc9136820b507e938a9c6b88bf2c567a9f6f4b ce1c4f8b6120122e23d4442925d98c56c41917d8 nulltoken <emeric.fermas@gmail.com> 1380209486 +0200 merge c: Merge made by the 'recursive' strategy.
+ce1c4f8b6120122e23d4442925d98c56c41917d8 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f nulltoken <emeric.fermas@gmail.com> 1380209486 +0200 reset: moving to 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f
+4d6558b8fa764baeb0f19c1e857df91e0eda5a0f 6a12b56088706aa6c39ccd23b7c7ce60f3a0b9a1 nulltoken <emeric.fermas@gmail.com> 1380209496 +0200 commit: D
+6a12b56088706aa6c39ccd23b7c7ce60f3a0b9a1 1e016431ec7b22dd3e23f3e6f5f68f358f9227cf nulltoken <emeric.fermas@gmail.com> 1380209527 +0200 commit: another
+1e016431ec7b22dd3e23f3e6f5f68f358f9227cf a9eb02af13df030159e39f70330d5c8a47655691 nulltoken <emeric.fermas@gmail.com> 1380209547 +0200 commit: yet another
+a9eb02af13df030159e39f70330d5c8a47655691 949b98e208015bfc0e2f573debc34ae2f97a7f0e nulltoken <emeric.fermas@gmail.com> 1380209557 +0200 merge ce1c4f8b6120122e23d4442925d98c56c41917d8: Merge made by the 'recursive' strategy.
+949b98e208015bfc0e2f573debc34ae2f97a7f0e a6095f816e81f64651595d488badc42399837d6a nulltoken <emeric.fermas@gmail.com> 1380209567 +0200 commit: x
diff --git a/tests/resources/describe/.gitted/logs/refs/heads/master b/tests/resources/describe/.gitted/logs/refs/heads/master new file mode 100644 index 000000000..fc49c6fa3 --- /dev/null +++ b/tests/resources/describe/.gitted/logs/refs/heads/master @@ -0,0 +1,14 @@ +0000000000000000000000000000000000000000 108b485d8268ea595df8ffea74f0f4b186577d32 nulltoken <emeric.fermas@gmail.com> 1380209394 +0200 commit (initial): initial
+108b485d8268ea595df8ffea74f0f4b186577d32 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f nulltoken <emeric.fermas@gmail.com> 1380209404 +0200 commit: second
+4d6558b8fa764baeb0f19c1e857df91e0eda5a0f b240c0fb88c5a629e00ebc1275fa1f33e364a705 nulltoken <emeric.fermas@gmail.com> 1380209414 +0200 commit: third
+b240c0fb88c5a629e00ebc1275fa1f33e364a705 81f4b1aac643e6983fab370eae8aefccecbf3a4c nulltoken <emeric.fermas@gmail.com> 1380209425 +0200 commit: A
+81f4b1aac643e6983fab370eae8aefccecbf3a4c 6126a5f9c57ebc81e64370ec3095184ad92dab1c nulltoken <emeric.fermas@gmail.com> 1380209445 +0200 commit: c
+6126a5f9c57ebc81e64370ec3095184ad92dab1c 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f nulltoken <emeric.fermas@gmail.com> 1380209455 +0200 reset: moving to 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f
+4d6558b8fa764baeb0f19c1e857df91e0eda5a0f 31fc9136820b507e938a9c6b88bf2c567a9f6f4b nulltoken <emeric.fermas@gmail.com> 1380209465 +0200 commit: B
+31fc9136820b507e938a9c6b88bf2c567a9f6f4b ce1c4f8b6120122e23d4442925d98c56c41917d8 nulltoken <emeric.fermas@gmail.com> 1380209486 +0200 merge c: Merge made by the 'recursive' strategy.
+ce1c4f8b6120122e23d4442925d98c56c41917d8 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f nulltoken <emeric.fermas@gmail.com> 1380209486 +0200 reset: moving to 4d6558b8fa764baeb0f19c1e857df91e0eda5a0f
+4d6558b8fa764baeb0f19c1e857df91e0eda5a0f 6a12b56088706aa6c39ccd23b7c7ce60f3a0b9a1 nulltoken <emeric.fermas@gmail.com> 1380209496 +0200 commit: D
+6a12b56088706aa6c39ccd23b7c7ce60f3a0b9a1 1e016431ec7b22dd3e23f3e6f5f68f358f9227cf nulltoken <emeric.fermas@gmail.com> 1380209527 +0200 commit: another
+1e016431ec7b22dd3e23f3e6f5f68f358f9227cf a9eb02af13df030159e39f70330d5c8a47655691 nulltoken <emeric.fermas@gmail.com> 1380209547 +0200 commit: yet another
+a9eb02af13df030159e39f70330d5c8a47655691 949b98e208015bfc0e2f573debc34ae2f97a7f0e nulltoken <emeric.fermas@gmail.com> 1380209557 +0200 merge ce1c4f8b6120122e23d4442925d98c56c41917d8: Merge made by the 'recursive' strategy.
+949b98e208015bfc0e2f573debc34ae2f97a7f0e a6095f816e81f64651595d488badc42399837d6a nulltoken <emeric.fermas@gmail.com> 1380209567 +0200 commit: x
diff --git a/tests/resources/describe/.gitted/objects/03/00021985931292d0611b9232e757035fefc04d b/tests/resources/describe/.gitted/objects/03/00021985931292d0611b9232e757035fefc04d Binary files differnew file mode 100644 index 000000000..4b98de8fb --- /dev/null +++ b/tests/resources/describe/.gitted/objects/03/00021985931292d0611b9232e757035fefc04d diff --git a/tests/resources/describe/.gitted/objects/10/8b485d8268ea595df8ffea74f0f4b186577d32 b/tests/resources/describe/.gitted/objects/10/8b485d8268ea595df8ffea74f0f4b186577d32 Binary files differnew file mode 100644 index 000000000..0d6187b10 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/10/8b485d8268ea595df8ffea74f0f4b186577d32 diff --git a/tests/resources/describe/.gitted/objects/10/bd08b099ecb79184c60183f5c94ca915f427ad b/tests/resources/describe/.gitted/objects/10/bd08b099ecb79184c60183f5c94ca915f427ad Binary files differnew file mode 100644 index 000000000..3540cfae0 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/10/bd08b099ecb79184c60183f5c94ca915f427ad diff --git a/tests/resources/describe/.gitted/objects/17/8481050188cf00d7d9cd5a11e43ab8fab9294f b/tests/resources/describe/.gitted/objects/17/8481050188cf00d7d9cd5a11e43ab8fab9294f Binary files differnew file mode 100644 index 000000000..f2eaf83e5 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/17/8481050188cf00d7d9cd5a11e43ab8fab9294f diff --git a/tests/resources/describe/.gitted/objects/19/1faf88a5826a99f475baaf8b13652c4e40bfe6 b/tests/resources/describe/.gitted/objects/19/1faf88a5826a99f475baaf8b13652c4e40bfe6 Binary files differnew file mode 100644 index 000000000..e44246b17 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/19/1faf88a5826a99f475baaf8b13652c4e40bfe6 diff --git a/tests/resources/describe/.gitted/objects/1e/016431ec7b22dd3e23f3e6f5f68f358f9227cf b/tests/resources/describe/.gitted/objects/1e/016431ec7b22dd3e23f3e6f5f68f358f9227cf Binary files differnew file mode 100644 index 000000000..a8769814b --- /dev/null +++ b/tests/resources/describe/.gitted/objects/1e/016431ec7b22dd3e23f3e6f5f68f358f9227cf diff --git a/tests/resources/describe/.gitted/objects/22/3b7836fb19fdf64ba2d3cd6173c6a283141f78 b/tests/resources/describe/.gitted/objects/22/3b7836fb19fdf64ba2d3cd6173c6a283141f78 Binary files differnew file mode 100644 index 000000000..faf1fbe7c --- /dev/null +++ b/tests/resources/describe/.gitted/objects/22/3b7836fb19fdf64ba2d3cd6173c6a283141f78 diff --git a/tests/resources/describe/.gitted/objects/25/d5edf8c0ef17e8a13b8da75913dcec4ea7afc1 b/tests/resources/describe/.gitted/objects/25/d5edf8c0ef17e8a13b8da75913dcec4ea7afc1 Binary files differnew file mode 100644 index 000000000..3353bf9ea --- /dev/null +++ b/tests/resources/describe/.gitted/objects/25/d5edf8c0ef17e8a13b8da75913dcec4ea7afc1 diff --git a/tests/resources/describe/.gitted/objects/2b/df67abb163a4ffb2d7f3f0880c9fe5068ce782 b/tests/resources/describe/.gitted/objects/2b/df67abb163a4ffb2d7f3f0880c9fe5068ce782 Binary files differnew file mode 100644 index 000000000..d0398e6e3 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/2b/df67abb163a4ffb2d7f3f0880c9fe5068ce782 diff --git a/tests/resources/describe/.gitted/objects/31/fc9136820b507e938a9c6b88bf2c567a9f6f4b b/tests/resources/describe/.gitted/objects/31/fc9136820b507e938a9c6b88bf2c567a9f6f4b Binary files differnew file mode 100644 index 000000000..7752a9558 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/31/fc9136820b507e938a9c6b88bf2c567a9f6f4b diff --git a/tests/resources/describe/.gitted/objects/42/8f9554a2eec22de29898819b579466af7c1583 b/tests/resources/describe/.gitted/objects/42/8f9554a2eec22de29898819b579466af7c1583 Binary files differnew file mode 100644 index 000000000..f27d552fd --- /dev/null +++ b/tests/resources/describe/.gitted/objects/42/8f9554a2eec22de29898819b579466af7c1583 diff --git a/tests/resources/describe/.gitted/objects/4d/6558b8fa764baeb0f19c1e857df91e0eda5a0f b/tests/resources/describe/.gitted/objects/4d/6558b8fa764baeb0f19c1e857df91e0eda5a0f Binary files differnew file mode 100644 index 000000000..311ee2fad --- /dev/null +++ b/tests/resources/describe/.gitted/objects/4d/6558b8fa764baeb0f19c1e857df91e0eda5a0f diff --git a/tests/resources/describe/.gitted/objects/4f/2d9ce01ad5249cabdc6565366af8aff85b1525 b/tests/resources/describe/.gitted/objects/4f/2d9ce01ad5249cabdc6565366af8aff85b1525 Binary files differnew file mode 100644 index 000000000..f04379f35 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/4f/2d9ce01ad5249cabdc6565366af8aff85b1525 diff --git a/tests/resources/describe/.gitted/objects/52/912fbab0715dec53d43053966e78ad213ba359 b/tests/resources/describe/.gitted/objects/52/912fbab0715dec53d43053966e78ad213ba359 Binary files differnew file mode 100644 index 000000000..5deb7ec06 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/52/912fbab0715dec53d43053966e78ad213ba359 diff --git a/tests/resources/describe/.gitted/objects/56/26abf0f72e58d7a153368ba57db4c673c0e171 b/tests/resources/describe/.gitted/objects/56/26abf0f72e58d7a153368ba57db4c673c0e171 Binary files differnew file mode 100644 index 000000000..4d5447467 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/56/26abf0f72e58d7a153368ba57db4c673c0e171 diff --git a/tests/resources/describe/.gitted/objects/61/26a5f9c57ebc81e64370ec3095184ad92dab1c b/tests/resources/describe/.gitted/objects/61/26a5f9c57ebc81e64370ec3095184ad92dab1c Binary files differnew file mode 100644 index 000000000..e71707f4b --- /dev/null +++ b/tests/resources/describe/.gitted/objects/61/26a5f9c57ebc81e64370ec3095184ad92dab1c diff --git a/tests/resources/describe/.gitted/objects/62/d8fe9f6db631bd3a19140699101c9e281c9f9d b/tests/resources/describe/.gitted/objects/62/d8fe9f6db631bd3a19140699101c9e281c9f9d Binary files differnew file mode 100644 index 000000000..734f7dc42 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/62/d8fe9f6db631bd3a19140699101c9e281c9f9d diff --git a/tests/resources/describe/.gitted/objects/65/a91bc2262480dce4c5979519aae6668368eb4e b/tests/resources/describe/.gitted/objects/65/a91bc2262480dce4c5979519aae6668368eb4e Binary files differnew file mode 100644 index 000000000..ef9f53a39 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/65/a91bc2262480dce4c5979519aae6668368eb4e diff --git a/tests/resources/describe/.gitted/objects/68/0166b6cd31f76354fee2572618e6b0142d05e6 b/tests/resources/describe/.gitted/objects/68/0166b6cd31f76354fee2572618e6b0142d05e6 new file mode 100644 index 000000000..36f198686 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/68/0166b6cd31f76354fee2572618e6b0142d05e6 @@ -0,0 +1,2 @@ +xŒK @]sŠÙ›4¤|c<Co0ŒS‚–Ö .¼½¸yy›÷:eÐ&žŽôîàH›4;Á£#rl#óÝØäÙ³8\-aŠ¤Uÿ¾ø¨µtÕÇcù3Kƒý³mýxÊ©Ò +O«´Jï[®T¶i$WÐ6 Á8kç!¨Ô¢~U<)a
\ No newline at end of file diff --git a/tests/resources/describe/.gitted/objects/69/3a3de402bb23897ed5c931273e53c78eff0495 b/tests/resources/describe/.gitted/objects/69/3a3de402bb23897ed5c931273e53c78eff0495 Binary files differnew file mode 100644 index 000000000..80a08fc3a --- /dev/null +++ b/tests/resources/describe/.gitted/objects/69/3a3de402bb23897ed5c931273e53c78eff0495 diff --git a/tests/resources/describe/.gitted/objects/6a/12b56088706aa6c39ccd23b7c7ce60f3a0b9a1 b/tests/resources/describe/.gitted/objects/6a/12b56088706aa6c39ccd23b7c7ce60f3a0b9a1 Binary files differnew file mode 100644 index 000000000..9c773e4b5 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/6a/12b56088706aa6c39ccd23b7c7ce60f3a0b9a1 diff --git a/tests/resources/describe/.gitted/objects/6d/218e42592043041c4da016ff298cf241b86c3c b/tests/resources/describe/.gitted/objects/6d/218e42592043041c4da016ff298cf241b86c3c Binary files differnew file mode 100644 index 000000000..59fc7095c --- /dev/null +++ b/tests/resources/describe/.gitted/objects/6d/218e42592043041c4da016ff298cf241b86c3c diff --git a/tests/resources/describe/.gitted/objects/75/bb152c600647586c226d98411b1d2f9861af5a b/tests/resources/describe/.gitted/objects/75/bb152c600647586c226d98411b1d2f9861af5a Binary files differnew file mode 100644 index 000000000..a2016f45f --- /dev/null +++ b/tests/resources/describe/.gitted/objects/75/bb152c600647586c226d98411b1d2f9861af5a diff --git a/tests/resources/describe/.gitted/objects/81/f4b1aac643e6983fab370eae8aefccecbf3a4c b/tests/resources/describe/.gitted/objects/81/f4b1aac643e6983fab370eae8aefccecbf3a4c Binary files differnew file mode 100644 index 000000000..e47f3fb85 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/81/f4b1aac643e6983fab370eae8aefccecbf3a4c diff --git a/tests/resources/describe/.gitted/objects/8e/c1d96451ff05451720e4e8968812c46b35e5e4 b/tests/resources/describe/.gitted/objects/8e/c1d96451ff05451720e4e8968812c46b35e5e4 Binary files differnew file mode 100644 index 000000000..432b2c193 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/8e/c1d96451ff05451720e4e8968812c46b35e5e4 diff --git a/tests/resources/describe/.gitted/objects/94/9b98e208015bfc0e2f573debc34ae2f97a7f0e b/tests/resources/describe/.gitted/objects/94/9b98e208015bfc0e2f573debc34ae2f97a7f0e Binary files differnew file mode 100644 index 000000000..2c7aafab5 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/94/9b98e208015bfc0e2f573debc34ae2f97a7f0e diff --git a/tests/resources/describe/.gitted/objects/9c/06d71b8406ab97537e3acdc39a2c4ade7a9411 b/tests/resources/describe/.gitted/objects/9c/06d71b8406ab97537e3acdc39a2c4ade7a9411 Binary files differnew file mode 100644 index 000000000..5fff6fa1f --- /dev/null +++ b/tests/resources/describe/.gitted/objects/9c/06d71b8406ab97537e3acdc39a2c4ade7a9411 diff --git a/tests/resources/describe/.gitted/objects/a6/095f816e81f64651595d488badc42399837d6a b/tests/resources/describe/.gitted/objects/a6/095f816e81f64651595d488badc42399837d6a Binary files differnew file mode 100644 index 000000000..eb9ab148a --- /dev/null +++ b/tests/resources/describe/.gitted/objects/a6/095f816e81f64651595d488badc42399837d6a diff --git a/tests/resources/describe/.gitted/objects/a9/e3325a07117aa5381e044a8d96c26eb30d729d b/tests/resources/describe/.gitted/objects/a9/e3325a07117aa5381e044a8d96c26eb30d729d Binary files differnew file mode 100644 index 000000000..ee45b7650 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/a9/e3325a07117aa5381e044a8d96c26eb30d729d diff --git a/tests/resources/describe/.gitted/objects/a9/eb02af13df030159e39f70330d5c8a47655691 b/tests/resources/describe/.gitted/objects/a9/eb02af13df030159e39f70330d5c8a47655691 new file mode 100644 index 000000000..320161a55 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/a9/eb02af13df030159e39f70330d5c8a47655691 @@ -0,0 +1,2 @@ +xŽA +à »öîAý&1PJ¯òÕgc±fÑÛ×3t÷˜aà…’óÖ¤!uiqdöF/ì´ÑÃzbFLŠBÛEwé¬xsÅѤ†Ò“%0{cb$J„)ir‰F—cæŸm-Uç¾·òÂ!oȨ[jæÏã™yÛ‡Pò]jrʨe´³¼ö¡D§ýdß¹ø¢I>J[QÅhK%
\ No newline at end of file diff --git a/tests/resources/describe/.gitted/objects/aa/d8d5cef3915ab78b3227abaaac99b62db9eb54 b/tests/resources/describe/.gitted/objects/aa/d8d5cef3915ab78b3227abaaac99b62db9eb54 Binary files differnew file mode 100644 index 000000000..4cbaff192 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/aa/d8d5cef3915ab78b3227abaaac99b62db9eb54 diff --git a/tests/resources/describe/.gitted/objects/aa/ddd4f14847e0e323924ec262c2343249a84f8b b/tests/resources/describe/.gitted/objects/aa/ddd4f14847e0e323924ec262c2343249a84f8b Binary files differnew file mode 100644 index 000000000..651ec782e --- /dev/null +++ b/tests/resources/describe/.gitted/objects/aa/ddd4f14847e0e323924ec262c2343249a84f8b diff --git a/tests/resources/describe/.gitted/objects/b2/40c0fb88c5a629e00ebc1275fa1f33e364a705 b/tests/resources/describe/.gitted/objects/b2/40c0fb88c5a629e00ebc1275fa1f33e364a705 new file mode 100644 index 000000000..fe86e7c7c --- /dev/null +++ b/tests/resources/describe/.gitted/objects/b2/40c0fb88c5a629e00ebc1275fa1f33e364a705 @@ -0,0 +1,3 @@ +xŽM +à »öîAͧQ(¥WñçÙJc,ÖÜ¿ž¡«7¼Øj-ƒ+E—Ñner†´ÌYè9› Xg¬•*’ «†±ï8§d´¶Áf¿ +Ad预Õ[ÊNB yíEfþ¯Öùqîûhoü†Š^â’Ñ«ÿ>žÕ—}‰Þ¹\P‘$~ Ø´óäÀŸ9¯ÒûµGG¬
\ No newline at end of file diff --git a/tests/resources/describe/.gitted/objects/ce/1c4f8b6120122e23d4442925d98c56c41917d8 b/tests/resources/describe/.gitted/objects/ce/1c4f8b6120122e23d4442925d98c56c41917d8 Binary files differnew file mode 100644 index 000000000..408c5da33 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/ce/1c4f8b6120122e23d4442925d98c56c41917d8 diff --git a/tests/resources/describe/.gitted/objects/d5/aab219a814ddbe4b3aaedf03cdea491b218ec4 b/tests/resources/describe/.gitted/objects/d5/aab219a814ddbe4b3aaedf03cdea491b218ec4 Binary files differnew file mode 100644 index 000000000..4512d16d6 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/d5/aab219a814ddbe4b3aaedf03cdea491b218ec4 diff --git a/tests/resources/describe/.gitted/objects/f2/ad6c76f0115a6ba5b00456a849810e7ec0af20 b/tests/resources/describe/.gitted/objects/f2/ad6c76f0115a6ba5b00456a849810e7ec0af20 Binary files differnew file mode 100644 index 000000000..a36463115 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/f2/ad6c76f0115a6ba5b00456a849810e7ec0af20 diff --git a/tests/resources/describe/.gitted/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 b/tests/resources/describe/.gitted/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 Binary files differnew file mode 100644 index 000000000..2e15b4fb0 --- /dev/null +++ b/tests/resources/describe/.gitted/objects/f7/0f10e4db19068f79bc43844b49f3eece45c4e8 diff --git a/tests/resources/describe/.gitted/objects/f7/19efd430d52bcfc8566a43b2eb655688d38871 b/tests/resources/describe/.gitted/objects/f7/19efd430d52bcfc8566a43b2eb655688d38871 Binary files differnew file mode 100644 index 000000000..b2d51d93b --- /dev/null +++ b/tests/resources/describe/.gitted/objects/f7/19efd430d52bcfc8566a43b2eb655688d38871 diff --git a/tests/resources/describe/.gitted/refs/heads/master b/tests/resources/describe/.gitted/refs/heads/master new file mode 100644 index 000000000..0b2a54130 --- /dev/null +++ b/tests/resources/describe/.gitted/refs/heads/master @@ -0,0 +1 @@ +a6095f816e81f64651595d488badc42399837d6a
diff --git a/tests/resources/describe/.gitted/refs/tags/A b/tests/resources/describe/.gitted/refs/tags/A new file mode 100644 index 000000000..aced4fd0f --- /dev/null +++ b/tests/resources/describe/.gitted/refs/tags/A @@ -0,0 +1 @@ +aaddd4f14847e0e323924ec262c2343249a84f8b
diff --git a/tests/resources/describe/.gitted/refs/tags/B b/tests/resources/describe/.gitted/refs/tags/B new file mode 100644 index 000000000..ab1a5e69a --- /dev/null +++ b/tests/resources/describe/.gitted/refs/tags/B @@ -0,0 +1 @@ +52912fbab0715dec53d43053966e78ad213ba359
diff --git a/tests/resources/describe/.gitted/refs/tags/D b/tests/resources/describe/.gitted/refs/tags/D new file mode 100644 index 000000000..90f420854 --- /dev/null +++ b/tests/resources/describe/.gitted/refs/tags/D @@ -0,0 +1 @@ +10bd08b099ecb79184c60183f5c94ca915f427ad
diff --git a/tests/resources/describe/.gitted/refs/tags/R b/tests/resources/describe/.gitted/refs/tags/R new file mode 100644 index 000000000..ef04b7c9f --- /dev/null +++ b/tests/resources/describe/.gitted/refs/tags/R @@ -0,0 +1 @@ +680166b6cd31f76354fee2572618e6b0142d05e6
diff --git a/tests/resources/describe/.gitted/refs/tags/c b/tests/resources/describe/.gitted/refs/tags/c new file mode 100644 index 000000000..650d82fdb --- /dev/null +++ b/tests/resources/describe/.gitted/refs/tags/c @@ -0,0 +1 @@ +6126a5f9c57ebc81e64370ec3095184ad92dab1c
diff --git a/tests/resources/describe/.gitted/refs/tags/e b/tests/resources/describe/.gitted/refs/tags/e new file mode 100644 index 000000000..5e88d6f13 --- /dev/null +++ b/tests/resources/describe/.gitted/refs/tags/e @@ -0,0 +1 @@ +1e016431ec7b22dd3e23f3e6f5f68f358f9227cf
diff --git a/tests/resources/describe/another b/tests/resources/describe/another new file mode 100644 index 000000000..a3d00fa8a --- /dev/null +++ b/tests/resources/describe/another @@ -0,0 +1 @@ +DDD
diff --git a/tests/resources/describe/file b/tests/resources/describe/file new file mode 100644 index 000000000..fd66be08d --- /dev/null +++ b/tests/resources/describe/file @@ -0,0 +1 @@ +X
diff --git a/tests/resources/describe/side b/tests/resources/describe/side new file mode 100644 index 000000000..fd66be08d --- /dev/null +++ b/tests/resources/describe/side @@ -0,0 +1 @@ +X
diff --git a/tests/resources/userdiff/.gitted/index b/tests/resources/userdiff/.gitted/index Binary files differindex b69d5cfb1..548dc7bfd 100644 --- a/tests/resources/userdiff/.gitted/index +++ b/tests/resources/userdiff/.gitted/index diff --git a/tests/resources/userdiff/.gitted/objects/09/65b377c214bbe5e0d18fcdaf556df7fa7ed7c8 b/tests/resources/userdiff/.gitted/objects/09/65b377c214bbe5e0d18fcdaf556df7fa7ed7c8 Binary files differnew file mode 100644 index 000000000..cbaf4c1bc --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/09/65b377c214bbe5e0d18fcdaf556df7fa7ed7c8 diff --git a/tests/resources/userdiff/.gitted/objects/0c/20ef1409ae1df4d5a76cdbd98d5c33ccdb6bcc b/tests/resources/userdiff/.gitted/objects/0c/20ef1409ae1df4d5a76cdbd98d5c33ccdb6bcc Binary files differnew file mode 100644 index 000000000..fa149da98 --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/0c/20ef1409ae1df4d5a76cdbd98d5c33ccdb6bcc diff --git a/tests/resources/userdiff/.gitted/objects/39/ea75107a09091ba54ff86fcc780b59477e42cd b/tests/resources/userdiff/.gitted/objects/39/ea75107a09091ba54ff86fcc780b59477e42cd Binary files differnew file mode 100644 index 000000000..748373621 --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/39/ea75107a09091ba54ff86fcc780b59477e42cd diff --git a/tests/resources/userdiff/.gitted/objects/3c/c08384deae5957247bc36776ab626cc9e0582b b/tests/resources/userdiff/.gitted/objects/3c/c08384deae5957247bc36776ab626cc9e0582b Binary files differnew file mode 100644 index 000000000..29b72fbbc --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/3c/c08384deae5957247bc36776ab626cc9e0582b diff --git a/tests/resources/userdiff/.gitted/objects/46/8d6f2afc940e14c76347fa9af26e429a3c9044 b/tests/resources/userdiff/.gitted/objects/46/8d6f2afc940e14c76347fa9af26e429a3c9044 Binary files differnew file mode 100644 index 000000000..5fc839170 --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/46/8d6f2afc940e14c76347fa9af26e429a3c9044 diff --git a/tests/resources/userdiff/.gitted/objects/53/917973acfe0111f93c2cfaacf854be245880e8 b/tests/resources/userdiff/.gitted/objects/53/917973acfe0111f93c2cfaacf854be245880e8 Binary files differnew file mode 100644 index 000000000..debf7e40f --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/53/917973acfe0111f93c2cfaacf854be245880e8 diff --git a/tests/resources/userdiff/.gitted/objects/63/1d44e0c72e8cd1b594fa11d7d1ee8a6d67ff67 b/tests/resources/userdiff/.gitted/objects/63/1d44e0c72e8cd1b594fa11d7d1ee8a6d67ff67 Binary files differnew file mode 100644 index 000000000..e8b884cd5 --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/63/1d44e0c72e8cd1b594fa11d7d1ee8a6d67ff67 diff --git a/tests/resources/userdiff/.gitted/objects/f3/be389d351e4bcc6dcc4b5fe22134ef0f63f8bd b/tests/resources/userdiff/.gitted/objects/f3/be389d351e4bcc6dcc4b5fe22134ef0f63f8bd Binary files differnew file mode 100644 index 000000000..cfbef992d --- /dev/null +++ b/tests/resources/userdiff/.gitted/objects/f3/be389d351e4bcc6dcc4b5fe22134ef0f63f8bd diff --git a/tests/resources/userdiff/after/file.javascript b/tests/resources/userdiff/after/file.javascript index 7cd3c5a8a..53917973a 100644 --- a/tests/resources/userdiff/after/file.javascript +++ b/tests/resources/userdiff/after/file.javascript @@ -1,108 +1,108 @@ -/* - Some code extracted from https://github.com/julianlloyd/scrollReveal.js - which happens to be a trending Javascript repo with an MIT license at - the time I was working on Javascript userdiff support in libgit2 +define(function(require, exports, module) { + module.exports = Player; - I extracted just some of the code, so I suspect this is no longer valid - Javascript code, but it contains enough example patterns to work. -*/ -;(function (window) { + var Key = require("./key") + , Direction = require("./direction"); - 'use strict'; + function Player(game) { + this.game = game; - var docElem = window.document.documentElement; + this.image = new Image("./assets/fighter.png"); + this.game.resources.add(this.image); - function getViewportH () { - var client = docElem['clientHeight'], - inner = window['innerHeight'], - sample = window['otherProperty']; + this.x = 0; + this.y = 0; - return (client < inner) ? inner : client; - } - - function getOffset (el) { - var offsetTop = 0, - offsetLeft = 0; + this.pixelX = 10; + this.pixelY = 10; - do { - if (!isNaN(el.offsetTop)) { - offsetTop += el.offsetTop + 1; - } - if (!isNaN(el.offsetLeft)) { - offsetLeft += el.offsetLeft; - } - } while (el = el.offsetParent) - - return { - top: offsetTop, - left: offsetLeft - } + this.animationStep = 0; } - function isElementInViewport (el, h) { - var scrolled = window.pageYOffset, - viewed = scrolled + getViewportH(), - elTop = getOffset(el).top, - elBottom = elTop + el.offsetHeight, - h = h || 0; - - return (elTop + el.offsetHeight * h) <= viewed && (elBottom) >= scrolled; - } - - scrollReveal.prototype = { - - _init: function () { - - var self = this; - - this.elems = Array.prototype.slice.call(docElem.querySelectorAll('[data-scrollReveal]')); - this.scrolled = false; + Player.prototype.update = function() { + if (!this.isWalking()) { + this.handleInput(); + } - this.elems.forEach(function (el, i) { - self.animate(el); - }); + if (this.isWalking()) { + // Increase the animation step. + this.animationStep = ++this.animationStep % 60; - var scrollHandler = function () { - if (!self.scrolled) { - self.scrolled = true; - setTimeout(function () { - self._scrollPage(); - }, 61); - } - }; + if (this.x * 32 > this.pixelX) { + this.pixelX++; + } else if (this.x * 32 < this.pixelX) { + this.pixelX--; + } - var resizeHandler = function () { - function delayed() { - self._scrollPage(); - self.resizeTimeout = null; - } - if (self.resizeTimeout) { - clearTimeout(self.resizeTimeout); + if (this.y * 32 > this.pixelY) { + this.pixelY++; + } else if (this.y * 32 < this.pixelY) { + this.pixelY--; + } + } else { + // Reset the animation step. + this.animationStep = 0; + } + }; + + Player.prototype.handleInput = function() { + var keyboard = this.game.keyboard, finalAction, action, inputs = { + 'moveDown': keyboard.isDown(Key.DOWN), + 'moveUp': keyboard.isDown(Key.UP), + 'moveLeft': keyboard.isDown(Key.LEFT), + 'moveRight': keyboard.isDown(Key.RIGHT) + }; + + for (action in inputs) { + if (inputs[action]) { + if (!finalAction || inputs[finalAction] < inputs[action]) { + finalAction = action; } - self.resizeTimeout = setTimeout(delayed, 200); - }; - - window.addEventListener('scroll', scrollHandler, false); - window.addEventListener('resize', resizeHandler, false); - }, - - /*=============================================================================*/ - - _scrollPage: function () { - var self = this; - - this.elems.forEach(function (el, i) { - if (isElementInViewport(el, self.options.viewportFactor)) { - self.animate(el); - } - }); - this.scrolled = false; - this.tested = true; - }, - }; // end scrollReveal.prototype + } + } - document.addEventListener("DOMContentLoaded", function (evt) { - window.scrollReveal = new scrollReveal(); - }); + this[finalAction] && this[finalAction](); + }; + + Player.prototype.isWalking = function() { + return this.x * 32 != this.pixelX || this.y * 32 != this.pixelY; + }; + + Player.prototype.moveDown = function() { + this.y += 1; + this.direction = Direction.DOWN; + }; + + Player.prototype.moveUp = function() { + this.y -= 1; + this.direction = Direction.UP; + }; + + Player.prototype.moveLeft = function() { + this.x -= 5; + this.direction = Direction.LEFT; + }; + + Player.prototype.moveRight = function() { + this.x += 1; + this.direction = Direction.RIGHT; + }; + + Player.prototype.draw = function(context) { + var offsetX = Math.floor(this.animationStep / 15) * 32, offsetY = 0; + + switch(this.direction) { + case Direction.UP: + offsetY = 48 * 3; + break; + case Direction.RIGHT: + offsetY = 48 * 2; + break; + case Direction.LEFT: + offsetY = 48; + break; + } -})(window); + context.drawImage(this.image.data, offsetX, offsetY, 32, 48, this.pixelX, this.pixelY, 32, 48); + }; +}); diff --git a/tests/resources/userdiff/before/file.javascript b/tests/resources/userdiff/before/file.javascript index b9f1286e5..0965b377c 100644 --- a/tests/resources/userdiff/before/file.javascript +++ b/tests/resources/userdiff/before/file.javascript @@ -1,109 +1,109 @@ -/* - Some code extracted from https://github.com/julianlloyd/scrollReveal.js - which happens to be a trending Javascript repo with an MIT license at - the time I was working on Javascript userdiff support in libgit2 +define(function(require, exports, module) { + module.exports = Player; - I extracted just some of the code, so I suspect this is no longer valid - Javascript code, but it contains enough example patterns to work. -*/ -;(function (window) { + var Key = require("./key") + , Direction = require("./direction") + , Image = require("./image"); - 'use strict'; + function Player(game) { + this.game = game; - var docElem = window.document.documentElement; + this.image = new Image("./assets/fighter.png"); + this.game.resources.add(this.image); - function getViewportH () { - var client = docElem['clientHeight'], - inner = window['innerHeight']; + this.x = 0; + this.y = 0; - return (client < inner) ? inner : client; - } - - function getOffset (el) { - var offsetTop = 0, - offsetLeft = 0; + this.pixelX = 0; + this.pixelY = 0; - do { - if (!isNaN(el.offsetTop)) { - offsetTop += el.offsetTop; - } - if (!isNaN(el.offsetLeft)) { - offsetLeft += el.offsetLeft; - } - } while (el = el.offsetParent) - - return { - top: offsetTop, - left: offsetLeft - } + this.animationStep = 0; } - function isElementInViewport (el, h) { - var scrolled = window.pageYOffset, - viewed = scrolled + getViewportH(), - elH = el.offsetHeight, - elTop = getOffset(el).top, - elBottom = elTop + elH, - h = h || 0; - - return (elTop + elH * h) <= viewed && (elBottom) >= scrolled; - } - - scrollReveal.prototype = { - - _init: function () { - - var self = this; - - this.elems = Array.prototype.slice.call(docElem.querySelectorAll('[data-scrollReveal]')); - this.scrolled = false; + Player.prototype.update = function() { + if (!this.isWalking()) { + this.handleInput(); + } - // Initialize all scrollreveals, triggering all - // reveals on visible elements. - this.elems.forEach(function (el, i) { - self.animate(el); - }); + if (this.isWalking()) { + // Increase the animation step. + this.animationStep = ++this.animationStep % 60; - var scrollHandler = function () { - if (!self.scrolled) { - self.scrolled = true; - setTimeout(function () { - self._scrollPage(); - }, 60); - } - }; + if (this.x * 32 > this.pixelX) { + this.pixelX++; + } else if (this.x * 32 < this.pixelX) { + this.pixelX--; + } - var resizeHandler = function () { - function delayed() { - self._scrollPage(); - self.resizeTimeout = null; - } - if (self.resizeTimeout) { - clearTimeout(self.resizeTimeout); + if (this.y * 32 > this.pixelY) { + this.pixelY++; + } else if (this.y * 32 < this.pixelY) { + this.pixelY--; + } + } else { + // Reset the animation step. + this.animationStep = 0; + } + }; + + Player.prototype.handleInput = function() { + var keyboard = this.game.keyboard, finalAction, action, inputs = { + 'moveDown': keyboard.isDown(Key.DOWN), + 'moveUp': keyboard.isDown(Key.UP), + 'moveLeft': keyboard.isDown(Key.LEFT), + 'moveRight': keyboard.isDown(Key.RIGHT) + }; + + for (action in inputs) { + if (inputs[action]) { + if (!finalAction || inputs[finalAction] < inputs[action]) { + finalAction = action; } - self.resizeTimeout = setTimeout(delayed, 200); - }; - - window.addEventListener('scroll', scrollHandler, false); - window.addEventListener('resize', resizeHandler, false); - }, - - /*=============================================================================*/ - - _scrollPage: function () { - var self = this; - - this.elems.forEach(function (el, i) { - if (isElementInViewport(el, self.options.viewportFactor)) { - self.animate(el); - } - }); - this.scrolled = false; - }, - }; // end scrollReveal.prototype + } + } - document.addEventListener("DOMContentLoaded", function (evt) { - window.scrollReveal = new scrollReveal(); - }); + this[finalAction] && this[finalAction](); + }; + + Player.prototype.isWalking = function() { + return this.x * 32 != this.pixelX || this.y * 32 != this.pixelY; + }; + + Player.prototype.moveDown = function() { + this.y += 1; + this.direction = Direction.DOWN; + }; + + Player.prototype.moveUp = function() { + this.y -= 1; + this.direction = Direction.UP; + }; + + Player.prototype.moveLeft = function() { + this.x -= 1; + this.direction = Direction.LEFT; + }; + + Player.prototype.moveRight = function() { + this.x += 1; + this.direction = Direction.RIGHT; + }; + + Player.prototype.draw = function(context) { + var offsetX = Math.floor(this.animationStep / 15) * 32, offsetY = 0; + + switch(this.direction) { + case Direction.UP: + offsetY = 48 * 3; + break; + case Direction.RIGHT: + offsetY = 48 * 2; + break; + case Direction.LEFT: + offsetY = 48; + break; + } -})(window); + context.drawImage(this.image.data, offsetX, offsetY, 32, 48, this.pixelX, this.pixelY - 16, 32, 48); + }; +}); diff --git a/tests/resources/userdiff/expected/driver/diff.javascript b/tests/resources/userdiff/expected/driver/diff.javascript index 4e65d0746..4cefe5cff 100644 --- a/tests/resources/userdiff/expected/driver/diff.javascript +++ b/tests/resources/userdiff/expected/driver/diff.javascript @@ -1,40 +1,27 @@ diff --git a/files/file.javascript b/files/file.javascript -index b9f1286..7cd3c5a 100644 +index 0965b37..5391797 100644 --- a/files/file.javascript +++ b/files/file.javascript -@@ -16,3 +16,4 @@ function getViewportH () - var client = docElem['clientHeight'], -- inner = window['innerHeight']; -+ inner = window['innerHeight'], -+ sample = window['otherProperty']; +@@ -4,4 +4,3 @@ function(require, exports, module) + var Key = require("./key") +- , Direction = require("./direction") +- , Image = require("./image"); ++ , Direction = require("./direction"); -@@ -27,3 +28,3 @@ function getOffset (el) - if (!isNaN(el.offsetTop)) { -- offsetTop += el.offsetTop; -+ offsetTop += el.offsetTop + 1; - } -@@ -43,8 +44,7 @@ function isElementInViewport (el, h) - viewed = scrolled + getViewportH(), -- elH = el.offsetHeight, - elTop = getOffset(el).top, -- elBottom = elTop + elH, -+ elBottom = elTop + el.offsetHeight, - h = h || 0; +@@ -16,4 +15,4 @@ function Player(game) -- return (elTop + elH * h) <= viewed && (elBottom) >= scrolled; -+ return (elTop + el.offsetHeight * h) <= viewed && (elBottom) >= scrolled; - } -@@ -60,4 +60,2 @@ _init: function () +- this.pixelX = 0; +- this.pixelY = 0; ++ this.pixelX = 10; ++ this.pixelY = 10; -- // Initialize all scrollreveals, triggering all -- // reveals on visible elements. - this.elems.forEach(function (el, i) { -@@ -71,3 +69,3 @@ var scrollHandler = function () - self._scrollPage(); -- }, 60); -+ }, 61); - } -@@ -101,2 +99,3 @@ _scrollPage: function () - this.scrolled = false; -+ this.tested = true; - }, +@@ -82,3 +81,3 @@ Player.prototype.moveUp = function() + Player.prototype.moveLeft = function() { +- this.x -= 1; ++ this.x -= 5; + this.direction = Direction.LEFT; +@@ -106,3 +105,3 @@ Player.prototype.draw = function(context) + +- context.drawImage(this.image.data, offsetX, offsetY, 32, 48, this.pixelX, this.pixelY - 16, 32, 48); ++ context.drawImage(this.image.data, offsetX, offsetY, 32, 48, this.pixelX, this.pixelY, 32, 48); + }; diff --git a/tests/resources/userdiff/expected/nodriver/diff.javascript b/tests/resources/userdiff/expected/nodriver/diff.javascript index 69afe4fd8..4bbd54764 100644 --- a/tests/resources/userdiff/expected/nodriver/diff.javascript +++ b/tests/resources/userdiff/expected/nodriver/diff.javascript @@ -1,40 +1,27 @@ diff --git a/files/file.javascript b/files/file.javascript -index b9f1286..7cd3c5a 100644 +index 0965b37..5391797 100644 --- a/files/file.javascript +++ b/files/file.javascript -@@ -16,3 +16,4 @@ - var client = docElem['clientHeight'], -- inner = window['innerHeight']; -+ inner = window['innerHeight'], -+ sample = window['otherProperty']; +@@ -4,4 +4,3 @@ define(function(require, exports, module) { + var Key = require("./key") +- , Direction = require("./direction") +- , Image = require("./image"); ++ , Direction = require("./direction"); -@@ -27,3 +28,3 @@ - if (!isNaN(el.offsetTop)) { -- offsetTop += el.offsetTop; -+ offsetTop += el.offsetTop + 1; - } -@@ -43,8 +44,7 @@ - viewed = scrolled + getViewportH(), -- elH = el.offsetHeight, - elTop = getOffset(el).top, -- elBottom = elTop + elH, -+ elBottom = elTop + el.offsetHeight, - h = h || 0; +@@ -16,4 +15,4 @@ define(function(require, exports, module) { -- return (elTop + elH * h) <= viewed && (elBottom) >= scrolled; -+ return (elTop + el.offsetHeight * h) <= viewed && (elBottom) >= scrolled; - } -@@ -60,4 +60,2 @@ +- this.pixelX = 0; +- this.pixelY = 0; ++ this.pixelX = 10; ++ this.pixelY = 10; -- // Initialize all scrollreveals, triggering all -- // reveals on visible elements. - this.elems.forEach(function (el, i) { -@@ -71,3 +69,3 @@ - self._scrollPage(); -- }, 60); -+ }, 61); - } -@@ -101,2 +99,3 @@ - this.scrolled = false; -+ this.tested = true; - }, +@@ -82,3 +81,3 @@ define(function(require, exports, module) { + Player.prototype.moveLeft = function() { +- this.x -= 1; ++ this.x -= 5; + this.direction = Direction.LEFT; +@@ -106,3 +105,3 @@ define(function(require, exports, module) { + +- context.drawImage(this.image.data, offsetX, offsetY, 32, 48, this.pixelX, this.pixelY - 16, 32, 48); ++ context.drawImage(this.image.data, offsetX, offsetY, 32, 48, this.pixelX, this.pixelY, 32, 48); + }; diff --git a/tests/resources/userdiff/files/file.javascript b/tests/resources/userdiff/files/file.javascript index 7cd3c5a8a..53917973a 100644 --- a/tests/resources/userdiff/files/file.javascript +++ b/tests/resources/userdiff/files/file.javascript @@ -1,108 +1,108 @@ -/* - Some code extracted from https://github.com/julianlloyd/scrollReveal.js - which happens to be a trending Javascript repo with an MIT license at - the time I was working on Javascript userdiff support in libgit2 +define(function(require, exports, module) { + module.exports = Player; - I extracted just some of the code, so I suspect this is no longer valid - Javascript code, but it contains enough example patterns to work. -*/ -;(function (window) { + var Key = require("./key") + , Direction = require("./direction"); - 'use strict'; + function Player(game) { + this.game = game; - var docElem = window.document.documentElement; + this.image = new Image("./assets/fighter.png"); + this.game.resources.add(this.image); - function getViewportH () { - var client = docElem['clientHeight'], - inner = window['innerHeight'], - sample = window['otherProperty']; + this.x = 0; + this.y = 0; - return (client < inner) ? inner : client; - } - - function getOffset (el) { - var offsetTop = 0, - offsetLeft = 0; + this.pixelX = 10; + this.pixelY = 10; - do { - if (!isNaN(el.offsetTop)) { - offsetTop += el.offsetTop + 1; - } - if (!isNaN(el.offsetLeft)) { - offsetLeft += el.offsetLeft; - } - } while (el = el.offsetParent) - - return { - top: offsetTop, - left: offsetLeft - } + this.animationStep = 0; } - function isElementInViewport (el, h) { - var scrolled = window.pageYOffset, - viewed = scrolled + getViewportH(), - elTop = getOffset(el).top, - elBottom = elTop + el.offsetHeight, - h = h || 0; - - return (elTop + el.offsetHeight * h) <= viewed && (elBottom) >= scrolled; - } - - scrollReveal.prototype = { - - _init: function () { - - var self = this; - - this.elems = Array.prototype.slice.call(docElem.querySelectorAll('[data-scrollReveal]')); - this.scrolled = false; + Player.prototype.update = function() { + if (!this.isWalking()) { + this.handleInput(); + } - this.elems.forEach(function (el, i) { - self.animate(el); - }); + if (this.isWalking()) { + // Increase the animation step. + this.animationStep = ++this.animationStep % 60; - var scrollHandler = function () { - if (!self.scrolled) { - self.scrolled = true; - setTimeout(function () { - self._scrollPage(); - }, 61); - } - }; + if (this.x * 32 > this.pixelX) { + this.pixelX++; + } else if (this.x * 32 < this.pixelX) { + this.pixelX--; + } - var resizeHandler = function () { - function delayed() { - self._scrollPage(); - self.resizeTimeout = null; - } - if (self.resizeTimeout) { - clearTimeout(self.resizeTimeout); + if (this.y * 32 > this.pixelY) { + this.pixelY++; + } else if (this.y * 32 < this.pixelY) { + this.pixelY--; + } + } else { + // Reset the animation step. + this.animationStep = 0; + } + }; + + Player.prototype.handleInput = function() { + var keyboard = this.game.keyboard, finalAction, action, inputs = { + 'moveDown': keyboard.isDown(Key.DOWN), + 'moveUp': keyboard.isDown(Key.UP), + 'moveLeft': keyboard.isDown(Key.LEFT), + 'moveRight': keyboard.isDown(Key.RIGHT) + }; + + for (action in inputs) { + if (inputs[action]) { + if (!finalAction || inputs[finalAction] < inputs[action]) { + finalAction = action; } - self.resizeTimeout = setTimeout(delayed, 200); - }; - - window.addEventListener('scroll', scrollHandler, false); - window.addEventListener('resize', resizeHandler, false); - }, - - /*=============================================================================*/ - - _scrollPage: function () { - var self = this; - - this.elems.forEach(function (el, i) { - if (isElementInViewport(el, self.options.viewportFactor)) { - self.animate(el); - } - }); - this.scrolled = false; - this.tested = true; - }, - }; // end scrollReveal.prototype + } + } - document.addEventListener("DOMContentLoaded", function (evt) { - window.scrollReveal = new scrollReveal(); - }); + this[finalAction] && this[finalAction](); + }; + + Player.prototype.isWalking = function() { + return this.x * 32 != this.pixelX || this.y * 32 != this.pixelY; + }; + + Player.prototype.moveDown = function() { + this.y += 1; + this.direction = Direction.DOWN; + }; + + Player.prototype.moveUp = function() { + this.y -= 1; + this.direction = Direction.UP; + }; + + Player.prototype.moveLeft = function() { + this.x -= 5; + this.direction = Direction.LEFT; + }; + + Player.prototype.moveRight = function() { + this.x += 1; + this.direction = Direction.RIGHT; + }; + + Player.prototype.draw = function(context) { + var offsetX = Math.floor(this.animationStep / 15) * 32, offsetY = 0; + + switch(this.direction) { + case Direction.UP: + offsetY = 48 * 3; + break; + case Direction.RIGHT: + offsetY = 48 * 2; + break; + case Direction.LEFT: + offsetY = 48; + break; + } -})(window); + context.drawImage(this.image.data, offsetX, offsetY, 32, 48, this.pixelX, this.pixelY, 32, 48); + }; +}); diff --git a/tests/revert/workdir.c b/tests/revert/workdir.c index e3d7e968a..0121429d8 100644 --- a/tests/revert/workdir.c +++ b/tests/revert/workdir.c @@ -48,7 +48,7 @@ void test_revert_workdir__automerge(void) git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac"); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); @@ -81,7 +81,7 @@ void test_revert_workdir__conflicts(void) cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&head, head_ref, GIT_OBJ_COMMIT)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); cl_git_pass(git_revert(repo, commit, NULL)); @@ -144,7 +144,7 @@ void test_revert_workdir__orphan(void) git_oid_fromstr(&head_oid, "39467716290f6df775a91cdb9a4eb39295018145"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&revert_oid, "ebb03002cee5d66c7732dd06241119fe72ab96a5"); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); @@ -179,7 +179,7 @@ void test_revert_workdir__again(void) cl_git_pass(git_repository_head(&head_ref, repo)); cl_git_pass(git_reference_peel((git_object **)&orig_head, head_ref, GIT_OBJ_COMMIT)); - cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_revert(repo, orig_head, NULL)); @@ -227,7 +227,7 @@ void test_revert_workdir__again_after_automerge(void) git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac"); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); @@ -275,7 +275,7 @@ void test_revert_workdir__again_after_edit(void) cl_git_pass(git_oid_fromstr(&orig_head_oid, "399fb3aba3d9d13f7d40a9254ce4402067ef3149")); cl_git_pass(git_commit_lookup(&orig_head, repo, &orig_head_oid)); - cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_oid_fromstr(&revert_oid, "2d440f2b3147d3dc7ad1085813478d6d869d5a4d")); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); @@ -326,7 +326,7 @@ void test_revert_workdir__again_after_edit_two(void) cl_git_pass(git_oid_fromstr(&head_commit_oid, "e34ef1afe54eb526fd92eec66084125f340f1d65")); cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_oid)); - cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_oid_fromstr(&revert_commit_oid, "71eb9c2b53dbbf3c45fb28b27c850db4b7fb8011")); cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_commit_oid)); @@ -379,7 +379,7 @@ void test_revert_workdir__conflict_use_ours(void) git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac"); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); @@ -415,7 +415,7 @@ void test_revert_workdir__rename_1_of_2(void) git_oid_fromstr(&head_oid, "cef56612d71a6af8d8015691e4865f7fece905b5"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&revert_oid, "55568c8de5322ff9a95d72747a239cdb64a19965"); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); @@ -449,7 +449,7 @@ void test_revert_workdir__rename(void) git_oid_fromstr(&head_oid, "55568c8de5322ff9a95d72747a239cdb64a19965"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); git_oid_fromstr(&revert_oid, "0aa8c7e40d342fff78d60b29a4ba8e993ed79c51"); cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid)); @@ -478,7 +478,7 @@ void test_revert_workdir__head(void) /* HEAD is 2d440f2b3147d3dc7ad1085813478d6d869d5a4d */ cl_git_pass(git_repository_head(&head, repo)); cl_git_pass(git_reference_peel((git_object **)&commit, head, GIT_OBJ_COMMIT)); - cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_revert(repo, commit, NULL)); cl_assert(merge_test_index(repo_index, merge_index_entries, 4)); @@ -515,7 +515,7 @@ void test_revert_workdir__merge_fails_without_mainline_specified(void) git_oid_fromstr(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); cl_must_fail(git_revert(repo, head, NULL)); cl_assert(!git_path_exists(TEST_REPO_PATH "/.git/MERGE_MSG")); @@ -542,7 +542,7 @@ void test_revert_workdir__merge_first_parent(void) git_oid_fromstr(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_revert(repo, head, &opts)); @@ -567,7 +567,7 @@ void test_revert_workdir__merge_second_parent(void) git_oid_fromstr(&head_oid, "5acdc74af27172ec491d213ee36cea7eb9ef2579"); cl_git_pass(git_commit_lookup(&head, repo, &head_oid)); - cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL)); + cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD, NULL, NULL, NULL)); cl_git_pass(git_revert(repo, head, &opts)); diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c index b015db18b..ff05fa249 100644 --- a/tests/revwalk/basic.c +++ b/tests/revwalk/basic.c @@ -49,12 +49,12 @@ static const int result_bytes = 24; static int get_commit_index(git_oid *raw_oid) { int i; - char oid[40]; + char oid[GIT_OID_HEXSZ]; git_oid_fmt(oid, raw_oid); for (i = 0; i < commit_count; ++i) - if (memcmp(oid, commit_ids[i], 40) == 0) + if (memcmp(oid, commit_ids[i], GIT_OID_HEXSZ) == 0) return i; return -1; @@ -74,9 +74,9 @@ static int test_walk_only(git_revwalk *walk, while (git_revwalk_next(&oid, walk) == 0) { result_array[i++] = get_commit_index(&oid); /*{ - char str[41]; + char str[GIT_OID_HEXSZ+1]; git_oid_fmt(str, &oid); - str[40] = 0; + str[GIT_OID_HEXSZ] = 0; printf(" %d) %s\n", i, str); }*/ } diff --git a/tests/revwalk/mergebase.c b/tests/revwalk/mergebase.c index 677e1a1b6..fa974eb9a 100644 --- a/tests/revwalk/mergebase.c +++ b/tests/revwalk/mergebase.c @@ -127,7 +127,7 @@ void test_revwalk_mergebase__prefer_youngest_merge_base(void) { git_oid result, one, two, expected; - cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f ")); + cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f")); cl_git_pass(git_oid_fromstr(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_oid_fromstr(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd")); @@ -140,7 +140,7 @@ void test_revwalk_mergebase__multiple_merge_bases(void) git_oid one, two, expected1, expected2; git_oidarray result = {NULL, 0}; - cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f ")); + cl_git_pass(git_oid_fromstr(&one, "a4a7dce85cf63874e984719f4fdd239f5145052f")); cl_git_pass(git_oid_fromstr(&two, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); cl_git_pass(git_oid_fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_oid_fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a")); @@ -153,6 +153,26 @@ void test_revwalk_mergebase__multiple_merge_bases(void) git_oidarray_free(&result); } +void test_revwalk_mergebase__multiple_merge_bases_many_commits(void) +{ + git_oid expected1, expected2; + git_oidarray result = {NULL, 0}; + + git_oid *input = git__malloc(sizeof(git_oid) * 2); + + cl_git_pass(git_oid_fromstr(&input[0], "a4a7dce85cf63874e984719f4fdd239f5145052f")); + cl_git_pass(git_oid_fromstr(&input[1], "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); + cl_git_pass(git_oid_fromstr(&expected1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); + cl_git_pass(git_oid_fromstr(&expected2, "9fd738e8f7967c078dceed8190330fc8648ee56a")); + + cl_git_pass(git_merge_bases_many(&result, _repo, 2, input)); + cl_assert_equal_i(2, result.count); + cl_assert_equal_oid(&expected1, &result.ids[0]); + cl_assert_equal_oid(&expected2, &result.ids[1]); + + git_oidarray_free(&result); +} + void test_revwalk_mergebase__no_off_by_one_missing(void) { git_oid result, one, two; diff --git a/tests/stash/save.c b/tests/stash/save.c index 3b301bfc0..a5bdd0cbe 100644 --- a/tests/stash/save.c +++ b/tests/stash/save.c @@ -368,6 +368,23 @@ void test_stash_save__including_untracked_without_any_untracked_file_creates_an_ assert_object_oid("stash^3^{tree}", EMPTY_TREE, GIT_OBJ_TREE); } +void test_stash_save__ignored_directory(void) +{ + cl_git_pass(p_mkdir("stash/ignored_directory", 0777)); + cl_git_pass(p_mkdir("stash/ignored_directory/sub", 0777)); + cl_git_mkfile("stash/ignored_directory/sub/some_file", "stuff"); + + assert_status(repo, "ignored_directory/sub/some_file", GIT_STATUS_WT_NEW); + cl_git_pass(git_ignore_add_rule(repo, "ignored_directory/")); + assert_status(repo, "ignored_directory/sub/some_file", GIT_STATUS_IGNORED); + + cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED)); + + cl_assert(!git_path_exists("stash/ignored_directory/sub/some_file")); + cl_assert(!git_path_exists("stash/ignored_directory/sub")); + cl_assert(!git_path_exists("stash/ignored_directory")); +} + void test_stash_save__skip_submodules(void) { git_repository *untracked_repo; diff --git a/tests/threads/basic.c b/tests/threads/basic.c index a329ee7f9..eb15293c7 100644 --- a/tests/threads/basic.c +++ b/tests/threads/basic.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" +#include "thread_helpers.h" #include "cache.h" @@ -34,3 +35,16 @@ void test_threads_basic__multiple_init(void) cl_git_pass(git_repository_open(&nested_repo, cl_fixture("testrepo.git"))); git_repository_free(nested_repo); } + +static void *set_error(void *dummy) +{ + giterr_set(GITERR_INVALID, "oh no, something happened!\n"); + + return dummy; +} + +/* Set errors so we can check that we free it */ +void test_threads_basic__set_error(void) +{ + run_in_parallel(1, 4, set_error, NULL, NULL); +} diff --git a/tests/transport/register.c b/tests/transport/register.c index 937194c1c..ea917d5d3 100644 --- a/tests/transport/register.c +++ b/tests/transport/register.c @@ -47,6 +47,7 @@ void test_transport_register__custom_transport_ssh(void) cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1); #else cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath")); + transport->free(transport); #endif cl_git_pass(git_transport_register("ssh", dummy_transport, NULL)); @@ -62,5 +63,6 @@ void test_transport_register__custom_transport_ssh(void) cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1); #else cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath")); + transport->free(transport); #endif } |