diff --git a/.mailmap b/.mailmap index 582dae0b99b..3f5a087eaf0 100644 --- a/.mailmap +++ b/.mailmap @@ -1,3 +1,18 @@ -Vicent Martí Vicent Marti +Vicent Martí Vicent Marti Vicent Martí Vicent Martí Michael Schubert schu +Ben Straub Ben Straub +Ben Straub Ben Straub +Carlos Martín Nieto +Carlos Martín Nieto +nulltoken +Scott J. Goldman +Martin Woodward +Peter Drahoš +Adam Roben +Adam Roben +Xavier L. +Xavier L. +Sascha Cunz +Authmillenon +Authmillenon diff --git a/.travis.yml b/.travis.yml index ad1172dfa09..0d5746f2eda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,10 @@ install: # Run the Build script script: + - mkdir _temp + - git init --bare _temp/test.git + - git daemon --listen=localhost --export-all --enable=receive-pack --base-path=_temp _temp 2>/dev/null & + - export GITTEST_REMOTE_URL="git://localhost/test.git" - mkdir _build - cd _build - cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS diff --git a/CMakeLists.txt b/CMakeLists.txt index dfca7363097..5a228e3429f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,6 +277,15 @@ ELSE() ENDIF() FILE(GLOB SRC_GIT2 src/*.c src/transports/*.c src/xdiff/*.c) +# Determine architecture of the machine +IF (CMAKE_SIZEOF_VOID_P EQUAL 8) + ADD_DEFINITIONS(-DGIT_ARCH_64) +ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 4) + ADD_DEFINITIONS(-DGIT_ARCH_32) +ELSE() + message(FATAL_ERROR "Unsupported architecture") +ENDIF() + # Compile and link libgit2 ADD_LIBRARY(git2 ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC}) TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES}) @@ -284,7 +293,7 @@ TARGET_OS_LIBRARIES(git2) # Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240) # Win64+MSVC+static libs = linker error -IF(MSVC AND NOT BUILD_SHARED_LIBS AND (${CMAKE_SIZEOF_VOID_P} MATCHES "8") ) +IF(MSVC AND GIT_ARCH_64 AND NOT BUILD_SHARED_LIBS) SET_TARGET_PROPERTIES(git2 PROPERTIES STATIC_LIBRARY_FLAGS "/MACHINE:x64") ENDIF() @@ -328,7 +337,7 @@ IF (BUILD_CLAR) ADD_CUSTOM_COMMAND( OUTPUT ${CLAR_PATH}/clar.suite - COMMAND ${PYTHON_EXECUTABLE} generate.py -xonline . + COMMAND ${PYTHON_EXECUTABLE} generate.py -f -xonline . DEPENDS ${SRC_TEST} WORKING_DIRECTORY ${CLAR_PATH} ) @@ -388,4 +397,7 @@ IF (BUILD_EXAMPLES) ADD_EXECUTABLE(git-showindex examples/showindex.c) TARGET_LINK_LIBRARIES(git-showindex git2) + + ADD_EXECUTABLE(git-rev-list examples/rev-list.c) + TARGET_LINK_LIBRARIES(git-rev-list git2) ENDIF () diff --git a/README.md b/README.md index ab1d05ec8b2..a2a18765af6 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ release its source code. * Archives: * Website: * API documentation: +* IRC: #libgit2 on irc.freenode.net. What It Can Do ================================== @@ -123,7 +124,7 @@ Here are the bindings to libgit2 that are currently available: * GObject * libgit2-glib * Haskell - * hgit2 + * hgit2 * Lua * luagit2 * .NET @@ -139,7 +140,7 @@ Here are the bindings to libgit2 that are currently available: * Parrot Virtual Machine * parrot-libgit2 * Perl - * git-xs-pm + * Git-Raw * PHP * php-git * Python @@ -155,15 +156,7 @@ we can add it to the list. How Can I Contribute? ================================== -Fork libgit2/libgit2 on GitHub, add your improvement, push it to a branch -in your fork named for the topic, send a pull request. If you change the -API or make other large changes, make a note of it in docs/rel-notes/ in a -file named after the next release. - -You can also file bugs or feature requests under the libgit2 project on -GitHub, or join us on the mailing list by sending an email to: - -libgit2@librelist.com +Check the [contribution guidelines](CONTRIBUTING.md). License diff --git a/docs/merge-df_conflicts.txt b/docs/merge-df_conflicts.txt new file mode 100644 index 00000000000..09780ee2d22 --- /dev/null +++ b/docs/merge-df_conflicts.txt @@ -0,0 +1,41 @@ +Anc / Our / Thr represent the ancestor / ours / theirs side of a merge +from branch "branch" into HEAD. Workdir represents the expected files in +the working directory. Index represents the expected files in the index, +with stage markers. + + Anc Our Thr Workdir Index +1 D D + D/F D/F D/F [0] + +2 D D+ D~HEAD (mod/del) D/F [0] + D/F D/F D [1] + D [2] + +3 D D D/F D/F [0] + D/F + +4 D D+ D~branch (mod/del) D/F [0] + D/F D/F D [1] + D [3] + +5 D D/F (add/add) D/F [2] + D/F D/F [3] + D/F + +6 D/F D/F D D [0] + D + +7 D/F D/F+ D/F (mod/del) D/F [1] + D D~branch (fil/dir) D/F [2] + D [3] + +8 D/F D/F D D [0] + D + +9 D/F D/F+ D/F (mod/del) D/F [1] + D D~HEAD (fil/dir) D [2] + D/F [3] + +10 D/F D/F (fil/dir) D/F [0] + D D~HEAD D [2] + D diff --git a/examples/.gitignore b/examples/.gitignore index e40bfc29f28..e8e0820a5bb 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,4 +1,5 @@ general showindex diff +rev-list *.dSYM diff --git a/examples/Makefile b/examples/Makefile index b306d4800b2..2c18731fdaa 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -3,7 +3,7 @@ CC = gcc CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers LFLAGS = -L../build -lgit2 -lz -APPS = general showindex diff +APPS = general showindex diff rev-list all: $(APPS) diff --git a/examples/diff.c b/examples/diff.c index a153b493b8e..2ef405665d1 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -17,8 +17,8 @@ static int resolve_to_tree( int err = 0; git_object *obj = NULL; - if (git_revparse_single(&obj, repo, identifier) < 0) - return GIT_ENOTFOUND; + if ((err = git_revparse_single(&obj, repo, identifier)) < 0) + return err; switch (git_object_type(obj)) { case GIT_OBJ_TREE: diff --git a/examples/general.c b/examples/general.c index c7853fa62dd..adc7ed8d2f8 100644 --- a/examples/general.c +++ b/examples/general.c @@ -51,6 +51,8 @@ int main (int argc, char** argv) // There are a couple of methods for opening a repository, this being the // simplest. There are also [methods][me] for specifying the index file // and work tree locations, here we assume they are in the normal places. + // + // (Try running this program against tests-clar/resources/testrepo.git.) // // [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository int error; @@ -65,7 +67,7 @@ int main (int argc, char** argv) // For our first example, we will convert a 40 character hex value to the // 20 byte raw SHA1 value. printf("*Hex to Raw*\n"); - char hex[] = "fd6e612585290339ea8bf39c692a7ff6a29cb7c3"; + char hex[] = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"; // The `git_oid` is the structure that keeps the SHA value. We will use // this throughout the example for storing the value of the current SHA @@ -74,8 +76,7 @@ int main (int argc, char** argv) git_oid_fromstr(&oid, hex); // Once we've converted the string into the oid value, we can get the raw - // value of the SHA. - printf("Raw 20 bytes: [%.20s]\n", (&oid)->id); + // value of the SHA by accessing `oid.id` // Next we will convert the 20 byte raw SHA1 value to a human readable 40 // char hex value. @@ -164,7 +165,7 @@ int main (int argc, char** argv) printf("\n*Commit Parsing*\n"); git_commit *commit; - git_oid_fromstr(&oid, "f0877d0b841d75172ec404fc9370173dfffc20d1"); + git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479"); error = git_commit_lookup(&commit, repo, &oid); check_error(error, "looking up commit"); @@ -232,9 +233,9 @@ int main (int argc, char** argv) // Commit objects need a tree to point to and optionally one or more // parents. Here we're creating oid objects to create the commit with, // but you can also use - git_oid_fromstr(&tree_id, "28873d96b4e8f4e33ea30f4c682fd325f7ba56ac"); + git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1"); git_tree_lookup(&tree, repo, &tree_id); - git_oid_fromstr(&parent_id, "f0877d0b841d75172ec404fc9370173dfffc20d1"); + git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); git_commit_lookup(&parent, repo, &parent_id); // Here we actually create the commit object with a single call with all @@ -269,7 +270,7 @@ int main (int argc, char** argv) // We create an oid for the tag object if we know the SHA and look it up // the same way that we would a commit (or any other object). - git_oid_fromstr(&oid, "bc422d45275aca289c51d79830b45cecebff7c3a"); + git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); error = git_tag_lookup(&tag, repo, &oid); check_error(error, "looking up tag"); @@ -313,7 +314,7 @@ int main (int argc, char** argv) // You can also access tree entries by name if you know the name of the // entry you're looking for. - entry = git_tree_entry_byname(tree, "hello.c"); + entry = git_tree_entry_byname(tree, "README"); git_tree_entry_name(entry); // "hello.c" // Once you have the entry object, you can access the content or subtree @@ -339,7 +340,7 @@ int main (int argc, char** argv) printf("\n*Blob Parsing*\n"); git_blob *blob; - git_oid_fromstr(&oid, "af7574ea73f7b166f869ef1a39be126d9a186ae0"); + git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08"); git_blob_lookup(&blob, repo, &oid); // You can access a buffer with the raw contents of the blob directly. @@ -365,7 +366,7 @@ int main (int argc, char** argv) git_revwalk *walk; git_commit *wcommit; - git_oid_fromstr(&oid, "f0877d0b841d75172ec404fc9370173dfffc20d1"); + git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); // To use the revwalker, create a new walker, tell it how you want to sort // the output and then push one or more starting points onto the walker. @@ -495,7 +496,9 @@ int main (int argc, char** argv) git_config *cfg; // Open a config object so we can read global values from it. - git_config_open_ondisk(&cfg, "~/.gitconfig"); + char config_path[256]; + sprintf(config_path, "%s/config", repo_path); + check_error(git_config_open_ondisk(&cfg, config_path), "opening config"); git_config_get_int32(&j, cfg, "help.autocorrect"); printf("Autocorrect: %d\n", j); diff --git a/examples/network/fetch.c b/examples/network/fetch.c index d5caad4de27..6020ec6ecc7 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -16,7 +16,7 @@ struct dl_data { static void progress_cb(const char *str, int len, void *data) { - data = data; + (void)data; printf("remote: %.*s", len, str); fflush(stdout); /* We don't have the \n to force the flush */ } @@ -50,7 +50,7 @@ static void *download(void *ptr) static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) { char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; - data = data; + (void)data; git_oid_fmt(b_str, b); b_str[GIT_OID_HEXSZ] = '\0'; @@ -76,7 +76,11 @@ int fetch(git_repository *repo, int argc, char **argv) pthread_t worker; #endif - argc = argc; + if (argc < 2) { + fprintf(stderr, "usage: %s fetch \n", argv[-1]); + return EXIT_FAILURE; + } + // Figure out whether it's a named remote or a URL printf("Fetching %s for repo %p\n", argv[1], repo); if (git_remote_load(&remote, repo, argv[1]) < 0) { diff --git a/examples/network/git2.c b/examples/network/git2.c index ecb16630b65..5b32ac809a0 100644 --- a/examples/network/git2.c +++ b/examples/network/git2.c @@ -54,6 +54,8 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + git_threads_init(); + for (i = 0; commands[i].name != NULL; ++i) { if (!strcmp(argv[1], commands[i].name)) return run_command(commands[i].fn, --argc, ++argv); diff --git a/examples/network/index-pack.c b/examples/network/index-pack.c index 3fc4f328857..889305da824 100644 --- a/examples/network/index-pack.c +++ b/examples/network/index-pack.c @@ -23,7 +23,7 @@ // the indexing to finish in a worker thread static int index_cb(const git_transfer_progress *stats, void *data) { - data = data; + (void)data; printf("\rProcessing %d of %d", stats->indexed_objects, stats->total_objects); return 0; @@ -39,9 +39,10 @@ int index_pack(git_repository *repo, int argc, char **argv) ssize_t read_bytes; char buf[512]; - repo = repo; + (void)repo; + if (argc < 2) { - fprintf(stderr, "I need a packfile\n"); + fprintf(stderr, "usage: %s index-pack \n", argv[-1]); return EXIT_FAILURE; } diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c index 737eeacd396..25201182831 100644 --- a/examples/network/ls-remote.c +++ b/examples/network/ls-remote.c @@ -8,7 +8,7 @@ static int show_ref__cb(git_remote_head *head, void *payload) { char oid[GIT_OID_HEXSZ + 1] = {0}; - payload = payload; + (void)payload; git_oid_fmt(oid, &head->oid); printf("%s\t%s\n", oid, head->name); return 0; @@ -67,7 +67,11 @@ int ls_remote(git_repository *repo, int argc, char **argv) { int error; - argc = argc; + if (argc < 2) { + fprintf(stderr, "usage: %s ls-remote \n", argv[-1]); + return EXIT_FAILURE; + } + /* If there's a ':' in the name, assume it's an URL */ if (strchr(argv[1], ':') != NULL) { error = use_unnamed(repo, argv[1]); diff --git a/examples/rev-list.c b/examples/rev-list.c new file mode 100644 index 00000000000..d9ec15f7639 --- /dev/null +++ b/examples/rev-list.c @@ -0,0 +1,120 @@ +#include +#include + +#include + +static void check_error(int error_code, const char *action) +{ + if (!error_code) + return; + + const git_error *error = giterr_last(); + fprintf(stderr, "Error %d %s: %s\n", -error_code, action, + (error && error->message) ? error->message : "???"); + exit(1); +} + +static int push_commit(git_revwalk *walk, const git_oid *oid, int hide) +{ + if (hide) + return git_revwalk_hide(walk, oid); + else + return git_revwalk_push(walk, oid); +} + +static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide) +{ + int error; + git_object *obj; + + if ((error = git_revparse_single(&obj, repo, spec)) < 0) + return error; + + error = push_commit(walk, git_object_id(obj), hide); + git_object_free(obj); + return error; +} + +static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide) +{ + git_revspec revspec; + int error = 0; + + if ((error = git_revparse(&revspec, repo, range))) + return error; + + if (revspec.flags & GIT_REVPARSE_MERGE_BASE) { + /* TODO: support "..." */ + return GIT_EINVALIDSPEC; + } + + if ((error = push_commit(walk, git_object_id(revspec.from), !hide))) + goto out; + + error = push_commit(walk, git_object_id(revspec.to), hide); + +out: + git_object_free(revspec.from); + git_object_free(revspec.to); + return error; +} + +static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts) +{ + int hide, i, error; + unsigned int sorting = GIT_SORT_NONE; + + hide = 0; + for (i = 0; i < nopts; i++) { + if (!strcmp(opts[i], "--topo-order")) { + sorting = GIT_SORT_TOPOLOGICAL | (sorting & GIT_SORT_REVERSE); + git_revwalk_sorting(walk, sorting); + } else if (!strcmp(opts[i], "--date-order")) { + sorting = GIT_SORT_TIME | (sorting & GIT_SORT_REVERSE); + git_revwalk_sorting(walk, sorting); + } else if (!strcmp(opts[i], "--reverse")) { + sorting = (sorting & ~GIT_SORT_REVERSE) + | ((sorting & GIT_SORT_REVERSE) ? 0 : GIT_SORT_REVERSE); + git_revwalk_sorting(walk, sorting); + } else if (!strcmp(opts[i], "--not")) { + hide = !hide; + } else if (opts[i][0] == '^') { + if ((error = push_spec(repo, walk, opts[i] + 1, !hide))) + return error; + } else if (strstr(opts[i], "..")) { + if ((error = push_range(repo, walk, opts[i], hide))) + return error; + } else { + if ((error = push_spec(repo, walk, opts[i], hide))) + return error; + } + } + + return 0; +} + +int main (int argc, char **argv) +{ + int error; + git_repository *repo; + git_revwalk *walk; + git_oid oid; + char buf[41]; + + error = git_repository_open_ext(&repo, ".", 0, NULL); + check_error(error, "opening repository"); + + error = git_revwalk_new(&walk, repo); + check_error(error, "allocating revwalk"); + error = revwalk_parseopts(repo, walk, argc-1, argv+1); + check_error(error, "parsing options"); + + while (!git_revwalk_next(&oid, walk)) { + git_oid_fmt(buf, &oid); + buf[40] = '\0'; + printf("%s\n", buf); + } + + return 0; +} + diff --git a/examples/test/test-rev-list.sh b/examples/test/test-rev-list.sh new file mode 100755 index 00000000000..bc0eea7cf46 --- /dev/null +++ b/examples/test/test-rev-list.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +THIS_FILE="$(readlink -f "$0")" +ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")" +PROGRAM="$ROOT"/examples/rev-list +LIBDIR="$ROOT"/build +REPO="$ROOT"/tests-clar/resources/testrepo.git + +cd "$REPO" + +run () { + LD_LIBRARY_PATH="$LIBDIR" "$PROGRAM" "$@" +} + +diff -u - <(run --date-order a4a7dce) </dev/null || +a4a7dce85cf63874e984719f4fdd239f5145052f +c47800c7266a2be04c571c04d5a6614691ea99bd +9fd738e8f7967c078dceed8190330fc8648ee56a +4a202b346bb0fb0db7eff3cffeb3c70babbd2045 +5b5b025afb0b4c913b4c338a42934a3863bf3644 +8496071c1b46c854b31185ea97743be6a8774479 +EOF +diff -u - <(echo "$out") </dev/null || +8496071c1b46c854b31185ea97743be6a8774479 +5b5b025afb0b4c913b4c338a42934a3863bf3644 +4a202b346bb0fb0db7eff3cffeb3c70babbd2045 +9fd738e8f7967c078dceed8190330fc8648ee56a +c47800c7266a2be04c571c04d5a6614691ea99bd +a4a7dce85cf63874e984719f4fdd239f5145052f +EOF +diff -u - <(echo "$out") </dev/null || +a4a7dce85cf63874e984719f4fdd239f5145052f +c47800c7266a2be04c571c04d5a6614691ea99bd +9fd738e8f7967c078dceed8190330fc8648ee56a +4a202b346bb0fb0db7eff3cffeb3c70babbd2045 +5b5b025afb0b4c913b4c338a42934a3863bf3644 +8496071c1b46c854b31185ea97743be6a8774479 +EOF +diff -u - <(echo "$out") < Get the maximum mmap window size * - * opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *): - * Get the maximum memory that will be mapped in total by the library + * * opts(GIT_OPT_SET_MWINDOW_SIZE, size_t): * - * opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t): - * Set the maximum amount of memory that can be mapped at any time + * > Set the maximum mmap window size + * + * * opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *): + * + * > Get the maximum memory that will be mapped in total by the library + * + * * opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t): + * + * >Set the maximum amount of memory that can be mapped at any time * by the library * - * opts(GIT_OPT_GET_SEARCH_PATH, int level, char *out, size_t len) - * Get the search path for a given level of config data. "level" must - * be one of GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, or - * GIT_CONFIG_LEVEL_XDG. The search path is written to the `out` - * buffer up to size `len`. Returns GIT_EBUFS if buffer is too small. - * - * opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path) - * Set the search path for a level of config data. The search path - * applied to shared attributes and ignore files, too. - * - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR. - * Pass NULL to reset to the default (generally based on environment - * variables). Use magic path `$PATH` to include the old value - * of the path (if you want to prepend or append, for instance). - * - `level` must be GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, - * or GIT_CONFIG_LEVEL_XDG. - * - * opts(GIT_OPT_GET_ODB_CACHE_SIZE): - * Get the size of the libgit2 odb cache. - * - * opts(GIT_OPT_SET_ODB_CACHE_SIZE): - * Set the size of the of the libgit2 odb cache. This needs - * to be done before git_repository_open is called, since - * git_repository_open initializes the odb layer. Defaults - * to 128. + * * opts(GIT_OPT_GET_SEARCH_PATH, int level, char *out, size_t len) + * + * > Get the search path for a given level of config data. "level" must + * > be one of `GIT_CONFIG_LEVEL_SYSTEM`, `GIT_CONFIG_LEVEL_GLOBAL`, or + * > `GIT_CONFIG_LEVEL_XDG`. The search path is written to the `out` + * > buffer up to size `len`. Returns GIT_EBUFS if buffer is too small. + * + * * opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path) + * + * > Set the search path for a level of config data. The search path + * > applied to shared attributes and ignore files, too. + * > + * > - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR. + * > Pass NULL to reset to the default (generally based on environment + * > variables). Use magic path `$PATH` to include the old value + * > of the path (if you want to prepend or append, for instance). + * > + * > - `level` must be GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, + * > or GIT_CONFIG_LEVEL_XDG. * * @param option Option key * @param ... value to set the option diff --git a/include/git2/config.h b/include/git2/config.h index 19d4cb78db1..5a2f956fd64 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -43,29 +43,6 @@ typedef struct { typedef int (*git_config_foreach_cb)(const git_config_entry *, void *); - -/** - * Generic backend that implements the interface to - * access a configuration file - */ -struct git_config_backend { - unsigned int version; - struct git_config *cfg; - - /* Open means open the file/database and parse if necessary */ - int (*open)(struct git_config_backend *, unsigned int level); - int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); - int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); - int (*set)(struct git_config_backend *, const char *key, const char *value); - int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); - int (*del)(struct git_config_backend *, const char *key); - int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); - int (*refresh)(struct git_config_backend *); - void (*free)(struct git_config_backend *); -}; -#define GIT_CONFIG_BACKEND_VERSION 1 -#define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} - typedef enum { GIT_CVAR_FALSE = 0, GIT_CVAR_TRUE = 1, @@ -153,30 +130,6 @@ GIT_EXTERN(int) git_config_open_default(git_config **out); */ GIT_EXTERN(int) git_config_new(git_config **out); -/** - * Add a generic config file instance to an existing config - * - * Note that the configuration object will free the file - * automatically. - * - * Further queries on this config object will access each - * of the config file instances in order (instances with - * a higher priority level will be accessed first). - * - * @param cfg the configuration to add the file to - * @param file the configuration file (backend) to add - * @param level the priority level of the backend - * @param force if a config file already exists for the given - * priority level, replace it - * @return 0 on success, GIT_EEXISTS when adding more than one file - * for a given priority level (and force_replace set to 0), or error code - */ -GIT_EXTERN(int) git_config_add_backend( - git_config *cfg, - git_config_backend *file, - unsigned int level, - int force); - /** * Add an on-disk config file instance to an existing config * @@ -192,10 +145,9 @@ GIT_EXTERN(int) git_config_add_backend( * a higher priority level will be accessed first). * * @param cfg the configuration to add the file to - * @param path path to the configuration file (backend) to add + * @param path path to the configuration file to add * @param level the priority level of the backend - * @param force if a config file already exists for the given - * priority level, replace it + * @param force replace config file at the given priority level * @return 0 on success, GIT_EEXISTS when adding more than one file * for a given priority level (and force_replace set to 0), * GIT_ENOTFOUND when the file doesn't exist or error code diff --git a/include/git2/cred_helpers.h b/include/git2/cred_helpers.h index e3eb91d6c30..5d93cf4ddbf 100644 --- a/include/git2/cred_helpers.h +++ b/include/git2/cred_helpers.h @@ -30,11 +30,11 @@ typedef struct git_cred_userpass_payload { /** * Stock callback usable as a git_cred_acquire_cb. This calls * git_cred_userpass_plaintext_new unless the protocol has not specified - * GIT_CREDTYPE_USERPASS_PLAINTEXT as an allowed type. + * `GIT_CREDTYPE_USERPASS_PLAINTEXT` as an allowed type. * * @param cred The newly created credential object. * @param url The resource for which we are demanding a credential. - * @param username_from_url The username that was embedded in a "user@host" + * @param user_from_url The username that was embedded in a "user@host" * remote url, or NULL if not included. * @param allowed_types A bitmask stating which cred types are OK to return. * @param payload The payload provided when specifying this callback. (This is diff --git a/include/git2/diff.h b/include/git2/diff.h index d9ceadf207f..0ef47c018b5 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -88,42 +88,61 @@ typedef enum { GIT_DIFF_INCLUDE_UNTRACKED = (1 << 8), /** Include unmodified files in the diff list */ GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9), + /** Even with GIT_DIFF_INCLUDE_UNTRACKED, an entire untracked directory * will be marked with only a single entry in the diff list; this flag * adds all files under the directory as UNTRACKED entries, too. */ GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10), + /** If the pathspec is set in the diff options, this flags means to * apply it as an exact match instead of as an fnmatch pattern. */ GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 11), + /** Use case insensitive filename comparisons */ GIT_DIFF_DELTAS_ARE_ICASE = (1 << 12), + /** When generating patch text, include the content of untracked files */ GIT_DIFF_INCLUDE_UNTRACKED_CONTENT = (1 << 13), + /** Disable updating of the `binary` flag in delta records. This is * useful when iterating over a diff if you don't need hunk and data * callbacks and want to avoid having to load file completely. */ GIT_DIFF_SKIP_BINARY_CHECK = (1 << 14), + /** Normally, a type change between files will be converted into a * DELETED record for the old and an ADDED record for the new; this * options enabled the generation of TYPECHANGE delta records. */ GIT_DIFF_INCLUDE_TYPECHANGE = (1 << 15), + /** Even with GIT_DIFF_INCLUDE_TYPECHANGE, blob->tree changes still * generally show as a DELETED blob. This flag tries to correctly * label blob->tree transitions as TYPECHANGE records with new_file's * mode set to tree. Note: the tree SHA will not be available. */ GIT_DIFF_INCLUDE_TYPECHANGE_TREES = (1 << 16), + /** Ignore file mode changes */ GIT_DIFF_IGNORE_FILEMODE = (1 << 17), + /** Even with GIT_DIFF_INCLUDE_IGNORED, an entire ignored directory * will be marked with only a single entry in the diff list; this flag * adds all files under the directory as IGNORED entries, too. */ GIT_DIFF_RECURSE_IGNORED_DIRS = (1 << 18), + + /** Core Git scans inside untracked directories, labeling them IGNORED + * if they are empty or only contain ignored files; a directory is + * consider UNTRACKED only if it has an actual untracked file in it. + * This scan is extra work for a case you often don't care about. This + * flag makes libgit2 immediately label an untracked directory as + * UNTRACKED without looking insde it (which differs from core Git). + * Of course, ignore rules are still checked for the directory itself. + */ + GIT_DIFF_FAST_UNTRACKED_DIRS = (1 << 19), } git_diff_option_t; /** diff --git a/include/git2/index.h b/include/git2/index.h index 3d4bd15a83f..d23c3a8ea74 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -84,13 +84,6 @@ typedef struct git_index_entry { char *path; } git_index_entry; -/** Representation of a resolve undo entry in the index. */ -typedef struct git_index_reuc_entry { - unsigned int mode[3]; - git_oid oid[3]; - char *path; -} git_index_reuc_entry; - /** Capabilities of system that affect index actions. */ enum { GIT_INDEXCAP_IGNORE_CASE = 1, @@ -478,102 +471,6 @@ GIT_EXTERN(int) git_index_has_conflicts(const git_index *index); /**@}*/ -/** @name Resolve Undo (REUC) index entry manipulation. - * - * These functions work on the Resolve Undo index extension and contains - * data about the original files that led to a merge conflict. - */ -/**@{*/ - -/** - * Get the count of resolve undo entries currently in the index. - * - * @param index an existing index object - * @return integer of count of current resolve undo entries - */ -GIT_EXTERN(unsigned int) git_index_reuc_entrycount(git_index *index); - -/** - * Finds the resolve undo entry that points to the given path in the Git - * index. - * - * @param at_pos the address to which the position of the reuc entry is written (optional) - * @param index an existing index object - * @param path path to search - * @return 0 if found, < 0 otherwise (GIT_ENOTFOUND) - */ -GIT_EXTERN(int) git_index_reuc_find(size_t *at_pos, git_index *index, const char *path); - -/** - * Get a resolve undo entry from the index. - * - * The returned entry is read-only and should not be modified - * or freed by the caller. - * - * @param index an existing index object - * @param path path to search - * @return the resolve undo entry; NULL if not found - */ -GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_bypath(git_index *index, const char *path); - -/** - * Get a resolve undo entry from the index. - * - * The returned entry is read-only and should not be modified - * or freed by the caller. - * - * @param index an existing index object - * @param n the position of the entry - * @return a pointer to the resolve undo entry; NULL if out of bounds - */ -GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_byindex(git_index *index, size_t n); - -/** - * Adds a resolve undo entry for a file based on the given parameters. - * - * The resolve undo entry contains the OIDs of files that were involved - * in a merge conflict after the conflict has been resolved. This allows - * conflicts to be re-resolved later. - * - * If there exists a resolve undo entry for the given path in the index, - * it will be removed. - * - * This method will fail in bare index instances. - * - * @param index an existing index object - * @param path filename to add - * @param ancestor_mode mode of the ancestor file - * @param ancestor_id oid of the ancestor file - * @param our_mode mode of our file - * @param our_id oid of our file - * @param their_mode mode of their file - * @param their_id oid of their file - * @return 0 or an error code - */ -GIT_EXTERN(int) git_index_reuc_add(git_index *index, const char *path, - int ancestor_mode, git_oid *ancestor_id, - int our_mode, git_oid *our_id, - int their_mode, git_oid *their_id); - -/** - * Remove an resolve undo entry from the index - * - * @param index an existing index object - * @param n position of the resolve undo entry to remove - * @return 0 or an error code - */ -GIT_EXTERN(int) git_index_reuc_remove(git_index *index, size_t n); - -/** - * Remove all resolve undo entries from the index - * - * @param index an existing index object - * @return 0 or an error code - */ -GIT_EXTERN(void) git_index_reuc_clear(git_index *index); - -/**@}*/ - /** @} */ GIT_END_DECL #endif diff --git a/include/git2/indexer.h b/include/git2/indexer.h index dfe6ae5aa7d..262dcd154dc 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -8,31 +8,11 @@ #define _INCLUDE_git_indexer_h__ #include "common.h" +#include "types.h" #include "oid.h" GIT_BEGIN_DECL -/** - * This is passed as the first argument to the callback to allow the - * user to see the progress. - */ -typedef struct git_transfer_progress { - unsigned int total_objects; - unsigned int indexed_objects; - unsigned int received_objects; - size_t received_bytes; -} git_transfer_progress; - - -/** - * Type for progress callbacks during indexing. Return a value less than zero - * to cancel the transfer. - * - * @param stats Structure containing information about the state of the transfer - * @param payload Payload provided by caller - */ -typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); - typedef struct git_indexer_stream git_indexer_stream; /** diff --git a/include/git2/merge.h b/include/git2/merge.h index f4c5d988117..8ca90b95f95 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -7,19 +7,64 @@ #ifndef INCLUDE_git_merge_h__ #define INCLUDE_git_merge_h__ -#include "common.h" -#include "types.h" -#include "oid.h" +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" +#include "git2/checkout.h" +#include "git2/index.h" /** * @file git2/merge.h - * @brief Git merge-base routines - * @defgroup git_revwalk Git merge-base routines + * @brief Git merge routines + * @defgroup git_merge Git merge routines * @ingroup Git * @{ */ GIT_BEGIN_DECL +/** + * Flags for tree_many diff options. A combination of these flags can be + * passed in via the `flags` value in the `git_diff_tree_many_options`. + */ +typedef enum { + /** Detect renames */ + GIT_MERGE_TREE_FIND_RENAMES = (1 << 0), +} git_merge_tree_flags; + +/** + * Automerge options for `git_merge_trees_opts`. + */ +typedef enum { + GIT_MERGE_AUTOMERGE_NORMAL = 0, + GIT_MERGE_AUTOMERGE_NONE = 1, + GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2, + GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3, +} git_merge_automerge_flags; + + +typedef struct { + unsigned int version; + git_merge_tree_flags flags; + + /** Similarity to consider a file renamed (default 50) */ + unsigned int rename_threshold; + + /** Maximum similarity sources to examine (overrides the + * `merge.renameLimit` config) (default 200) + */ + unsigned int target_limit; + + /** Pluggable similarity metric; pass NULL to use internal metric */ + git_diff_similarity_metric *metric; + + /** Flags for automerging content. */ + git_merge_automerge_flags automerge_flags; +} git_merge_tree_opts; + +#define GIT_MERGE_TREE_OPTS_VERSION 1 +#define GIT_MERGE_TREE_OPTS_INIT {GIT_MERGE_TREE_OPTS_VERSION} + + /** * Find a merge base between two commits * @@ -50,6 +95,28 @@ GIT_EXTERN(int) git_merge_base_many( const git_oid input_array[], size_t length); +/** + * Merge two trees, producing a `git_index` that reflects the result of + * the merge. + * + * The returned index must be freed explicitly with `git_index_free`. + * + * @param out pointer to store the index result in + * @param repo repository that contains the given trees + * @param ancestor_tree the common ancestor between the trees (or null if none) + * @param our_tree the tree that reflects the destination tree + * @param their_tree the tree to merge in to `our_tree` + * @param opts the merge tree options (or null for defaults) + * @return zero on success, -1 on failure. + */ +GIT_EXTERN(int) git_merge_trees( + git_index **out, + git_repository *repo, + const git_tree *ancestor_tree, + const git_tree *our_tree, + const git_tree *their_tree, + const git_merge_tree_opts *opts); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/object.h b/include/git2/object.h index e029f01254b..b91b04dbab4 100644 --- a/include/git2/object.h +++ b/include/git2/object.h @@ -188,6 +188,15 @@ GIT_EXTERN(int) git_object_peel( const git_object *object, git_otype target_type); +/** + * Create an in-memory copy of a Git object. The copy must be + * explicitly free'd or it will leak. + * + * @param dest Pointer to store the copy of the object + * @param source Original object to copy + */ +GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source); + /** @} */ GIT_END_DECL diff --git a/include/git2/odb.h b/include/git2/odb.h index 8fd1a95be57..b64436c4d67 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -10,8 +10,6 @@ #include "common.h" #include "types.h" #include "oid.h" -#include "odb_backend.h" -#include "indexer.h" /** * @file git2/odb.h @@ -22,6 +20,11 @@ */ GIT_BEGIN_DECL +/** + * Function type for callbacks from git_odb_foreach. + */ +typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); + /** * Create a new object database with no backends. * @@ -52,42 +55,6 @@ GIT_EXTERN(int) git_odb_new(git_odb **out); */ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); -/** - * Add a custom backend to an existing Object DB - * - * The backends are checked in relative ordering, based on the - * value of the `priority` parameter. - * - * Read for more information. - * - * @param odb database to add the backend to - * @param backend pointer to a git_odb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); - -/** - * Add a custom backend to an existing Object DB; this - * backend will work as an alternate. - * - * Alternate backends are always checked for objects *after* - * all the main backends have been exhausted. - * - * The backends are checked in relative ordering, based on the - * value of the `priority` parameter. - * - * Writing is disabled on alternate backends. - * - * Read for more information. - * - * @param odb database to add the backend to - * @param backend pointer to a git_odb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); - /** * Add an on-disk alternate to an existing Object DB. * @@ -406,6 +373,60 @@ GIT_EXTERN(size_t) git_odb_object_size(git_odb_object *object); */ GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object); +/** + * Add a custom backend to an existing Object DB + * + * The backends are checked in relative ordering, based on the + * value of the `priority` parameter. + * + * Read for more information. + * + * @param odb database to add the backend to + * @param backend pointer to a git_odb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); + +/** + * Add a custom backend to an existing Object DB; this + * backend will work as an alternate. + * + * Alternate backends are always checked for objects *after* + * all the main backends have been exhausted. + * + * The backends are checked in relative ordering, based on the + * value of the `priority` parameter. + * + * Writing is disabled on alternate backends. + * + * Read for more information. + * + * @param odb database to add the backend to + * @param backend pointer to a git_odb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); + +/** + * Get the number of ODB backend objects + * + * @param odb object database + * @return number of backends in the ODB + */ +GIT_EXTERN(size_t) git_odb_num_backends(git_odb *odb); + +/** + * Lookup an ODB backend object by index + * + * @param out output pointer to ODB backend at pos + * @param odb object database + * @param pos index into object database backend list + * @return 0 on success; GIT_ENOTFOUND if pos is invalid; other errors < 0 + */ +GIT_EXTERN(int) git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index dbc3981f69e..4c2493a253c 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -7,106 +7,56 @@ #ifndef INCLUDE_git_odb_backend_h__ #define INCLUDE_git_odb_backend_h__ -#include "common.h" -#include "types.h" -#include "oid.h" -#include "indexer.h" +#include "git2/common.h" +#include "git2/types.h" /** * @file git2/backend.h * @brief Git custom backend functions - * @defgroup git_backend Git custom backend API + * @defgroup git_odb Git object database routines * @ingroup Git * @{ */ GIT_BEGIN_DECL -struct git_odb_stream; -struct git_odb_writepack; +/* + * Constructors for in-box ODB backends. + */ /** - * Function type for callbacks from git_odb_foreach. + * Create a backend for the packfiles. + * + * @param out location to store the odb backend pointer + * @param objects_dir the Git repository's objects directory + * + * @return 0 or an error code */ -typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); +GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); /** - * An instance for a custom backend + * Create a backend for loose objects + * + * @param out location to store the odb backend pointer + * @param objects_dir the Git repository's objects directory + * @param compression_level zlib compression level to use + * @param do_fsync whether to do an fsync() after writing (currently ignored) + * + * @return 0 or an error code */ -struct git_odb_backend { - unsigned int version; - git_odb *odb; - - /* read and read_prefix each return to libgit2 a buffer which - * will be freed later. The buffer should be allocated using - * the function git_odb_backend_malloc to ensure that it can - * be safely freed later. */ - int (* read)( - void **, size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *); - - /* To find a unique object given a prefix - * of its oid. - * The oid given must be so that the - * remaining (GIT_OID_HEXSZ - len)*4 bits - * are 0s. - */ - int (* read_prefix)( - git_oid *, - void **, size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *, - size_t); - - int (* read_header)( - size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *); - - /* The writer may assume that the object - * has already been hashed and is passed - * in the first parameter. - */ - int (* write)( - git_oid *, - struct git_odb_backend *, - const void *, - size_t, - git_otype); - - int (* writestream)( - struct git_odb_stream **, - struct git_odb_backend *, - size_t, - git_otype); - - int (* readstream)( - struct git_odb_stream **, - struct git_odb_backend *, - const git_oid *); - - int (* exists)( - struct git_odb_backend *, - const git_oid *); - - int (* refresh)(struct git_odb_backend *); - - int (* foreach)( - struct git_odb_backend *, - git_odb_foreach_cb cb, - void *payload); - - int (* writepack)( - struct git_odb_writepack **, - struct git_odb_backend *, - git_transfer_progress_callback progress_cb, - void *progress_payload); - - void (* free)(struct git_odb_backend *); -}; +GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); -#define GIT_ODB_BACKEND_VERSION 1 -#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} +/** + * Create a backend out of a single packfile + * + * This can be useful for inspecting the contents of a single + * packfile. + * + * @param out location to store the odb backend pointer + * @param index_file path to the packfile's .idx file + * + * @return 0 or an error code + */ +GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); /** Streaming mode */ enum { @@ -117,33 +67,24 @@ enum { /** A stream to read/write from a backend */ struct git_odb_stream { - struct git_odb_backend *backend; + git_odb_backend *backend; unsigned int mode; - int (*read)(struct git_odb_stream *stream, char *buffer, size_t len); - int (*write)(struct git_odb_stream *stream, const char *buffer, size_t len); - int (*finalize_write)(git_oid *oid_p, struct git_odb_stream *stream); - void (*free)(struct git_odb_stream *stream); + int (*read)(git_odb_stream *stream, char *buffer, size_t len); + int (*write)(git_odb_stream *stream, const char *buffer, size_t len); + int (*finalize_write)(git_oid *oid_p, git_odb_stream *stream); + void (*free)(git_odb_stream *stream); }; /** A stream to write a pack file to the ODB */ struct git_odb_writepack { - struct git_odb_backend *backend; + git_odb_backend *backend; - int (*add)(struct git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); - int (*commit)(struct git_odb_writepack *writepack, git_transfer_progress *stats); - void (*free)(struct git_odb_writepack *writepack); + int (*add)(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); + int (*commit)(git_odb_writepack *writepack, git_transfer_progress *stats); + void (*free)(git_odb_writepack *writepack); }; -GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); - -/** - * Constructors for in-box ODB backends. - */ -GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); -GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); -GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); - GIT_END_DECL #endif diff --git a/include/git2/oid.h b/include/git2/oid.h index 862f4b202b5..b20bb221aee 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -145,19 +145,7 @@ GIT_EXTERN(void) git_oid_cpy(git_oid *out, const git_oid *src); * @param b second oid structure. * @return <0, 0, >0 if a < b, a == b, a > b. */ -GIT_INLINE(int) git_oid_cmp(const git_oid *a, const git_oid *b) -{ - const unsigned char *sha1 = a->id; - const unsigned char *sha2 = b->id; - int i; - - for (i = 0; i < GIT_OID_RAWSZ; i++, sha1++, sha2++) { - if (*sha1 != *sha2) - return *sha1 - *sha2; - } - - return 0; -} +GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b); /** * Compare two oid structures for equality @@ -192,6 +180,16 @@ GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, size_t len); */ GIT_EXTERN(int) git_oid_streq(const git_oid *id, const char *str); +/** + * Compare an oid to an hex formatted object id. + * + * @param id oid structure. + * @param str input hex string of an object id. + * @return -1 if str is not valid, <0 if id sorts before str, + * 0 if id matches str, >0 if id sorts after str. + */ +GIT_EXTERN(int) git_oid_strcmp(const git_oid *id, const char *str); + /** * Check is an oid is all zeros. * diff --git a/include/git2/pack.h b/include/git2/pack.h index 2f033bef666..118b8d55442 100644 --- a/include/git2/pack.h +++ b/include/git2/pack.h @@ -94,6 +94,18 @@ GIT_EXTERN(int) git_packbuilder_insert(git_packbuilder *pb, const git_oid *id, c */ GIT_EXTERN(int) git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *id); +/** + * Insert a commit object + * + * This will add a commit as well as the completed referenced tree. + * + * @param pb The packbuilder + * @param id The oid of the commit + * + * @return 0 or an error code + */ +GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *id); + /** * Write the new pack and the corresponding index to path * diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 8d5be8e4702..a315876aefd 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -21,22 +21,6 @@ */ GIT_BEGIN_DECL -/** - * Create a new reference. Either an oid or a symbolic target must be - * specified. - * - * @param refdb the reference database to associate with this reference - * @param name the reference name - * @param oid the object id for a direct reference - * @param symbolic the target for a symbolic reference - * @return the created git_reference or NULL on error - */ -git_reference *git_reference__alloc( - git_refdb *refdb, - const char *name, - const git_oid *oid, - const char *symbolic); - /** * Create a new reference database with no backends. * @@ -78,20 +62,6 @@ GIT_EXTERN(int) git_refdb_compress(git_refdb *refdb); */ GIT_EXTERN(void) git_refdb_free(git_refdb *refdb); -/** - * Sets the custom backend to an existing reference DB - * - * Read for more information. - * - * @param refdb database to add the backend to - * @param backend pointer to a git_refdb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_refdb_set_backend( - git_refdb *refdb, - git_refdb_backend *backend); - /** @} */ GIT_END_DECL diff --git a/include/git2/refs.h b/include/git2/refs.h index e0451ba8214..e1d425352c3 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -132,6 +132,17 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, */ GIT_EXTERN(const git_oid *) git_reference_target(const git_reference *ref); +/** + * Return the peeled OID target of this reference. + * + * This peeled OID only applies to direct references that point to + * a hard Tag object: it is the result of peeling such Tag. + * + * @param ref The reference + * @return a pointer to the oid if available, NULL otherwise + */ +GIT_EXTERN(const git_oid *) git_reference_target_peel(const git_reference *ref); + /** * Get full name to the reference pointed to by a symbolic reference. * @@ -411,6 +422,13 @@ typedef enum { * (e.g., foo//bar but not foo/bar). */ GIT_REF_FORMAT_REFSPEC_PATTERN = (1 << 1), + + /** + * Interpret the name as part of a refspec in shorthand form + * so the `ONELEVEL` naming rules aren't enforced and 'master' + * becomes a valid name. + */ + GIT_REF_FORMAT_REFSPEC_SHORTHAND = (1 << 2), } git_reference_normalize_t; /** diff --git a/include/git2/refspec.h b/include/git2/refspec.h index ec7830b7c6e..c0b410cbfdc 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -9,6 +9,7 @@ #include "common.h" #include "types.h" +#include "net.h" /** * @file git2/refspec.h @@ -35,6 +36,14 @@ GIT_EXTERN(const char *) git_refspec_src(const git_refspec *refspec); */ GIT_EXTERN(const char *) git_refspec_dst(const git_refspec *refspec); +/** + * Get the refspec's string + * + * @param refspec the refspec + * @returns the refspec's original string + */ +GIT_EXTERN(const char *) git_refspec_string(const git_refspec *refspec); + /** * Get the force update setting * @@ -43,6 +52,14 @@ GIT_EXTERN(const char *) git_refspec_dst(const git_refspec *refspec); */ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); +/** + * Get the refspec's direction. + * + * @param the refspec + * @return GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH + */ +GIT_EXTERN(git_direction) git_refspec_direction(const git_refspec *spec); + /** * Check if a refspec's source descriptor matches a reference * diff --git a/include/git2/remote.h b/include/git2/remote.h index 6f36a3999d8..2aa384a54f3 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -142,39 +142,79 @@ GIT_EXTERN(int) git_remote_set_url(git_remote *remote, const char* url); GIT_EXTERN(int) git_remote_set_pushurl(git_remote *remote, const char* url); /** - * Set the remote's fetch refspec + * Add a fetch refspec to the remote * * @param remote the remote - * @apram spec the new fetch refspec + * @apram refspec the new fetch refspec * @return 0 or an error value */ -GIT_EXTERN(int) git_remote_set_fetchspec(git_remote *remote, const char *spec); +GIT_EXTERN(int) git_remote_add_fetch(git_remote *remote, const char *refspec); /** - * Get the fetch refspec + * Get the remote's list of fetch refspecs * - * @param remote the remote - * @return a pointer to the fetch refspec or NULL if it doesn't exist + * The memory is owned by the user and should be freed with + * `git_strarray_free`. + * + * @param array pointer to the array in which to store the strings + * @param remote the remote to query */ -GIT_EXTERN(const git_refspec *) git_remote_fetchspec(const git_remote *remote); +GIT_EXTERN(int) git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote); /** - * Set the remote's push refspec + * Add a push refspec to the remote * * @param remote the remote - * @param spec the new push refspec + * @param refspec the new push refspec * @return 0 or an error value */ -GIT_EXTERN(int) git_remote_set_pushspec(git_remote *remote, const char *spec); +GIT_EXTERN(int) git_remote_add_push(git_remote *remote, const char *refspec); + +/** + * Get the remote's list of push refspecs + * + * The memory is owned by the user and should be freed with + * `git_strarray_free`. + * + * @param array pointer to the array in which to store the strings + * @param remote the remote to query + */ +GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, git_remote *remote); + +/** + * Clear the refspecs + * + * Remove all configured fetch and push refspecs from the remote. + * + * @param remote the remote + */ +GIT_EXTERN(void) git_remote_clear_refspecs(git_remote *remote); /** - * Get the push refspec + * Get the number of refspecs for a remote * * @param remote the remote - * @return a pointer to the push refspec or NULL if it doesn't exist + * @return the amount of refspecs configured in this remote + */ +GIT_EXTERN(size_t) git_remote_refspec_count(git_remote *remote); + +/** + * Get a refspec from the remote + * + * @param remote the remote to query + * @param n the refspec to get + * @return the nth refspec */ +GIT_EXTERN(const git_refspec *)git_remote_get_refspec(git_remote *remote, size_t n); -GIT_EXTERN(const git_refspec *) git_remote_pushspec(const git_remote *remote); +/** + * Remove a refspec from the remote + * + * @param remote the remote to query + * @param n the refspec to remove + * @return 0 or GIT_ENOTFOUND + */ +GIT_EXTERN(int) git_remote_remove_refspec(git_remote *remote, size_t n); /** * Open a connection to a remote @@ -184,7 +224,8 @@ GIT_EXTERN(const git_refspec *) git_remote_pushspec(const git_remote *remote); * starts up a specific binary which can only do the one or the other. * * @param remote the remote to connect to - * @param direction whether you want to receive or send data + * @param direction GIT_DIRECTION_FETCH if you want to fetch or + * GIT_DIRECTION_PUSH if you want to push * @return 0 or an error code */ GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction); diff --git a/include/git2/repository.h b/include/git2/repository.h index e75c8b136f9..cd238e17c2d 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -123,6 +123,19 @@ GIT_EXTERN(int) git_repository_open_ext( unsigned int flags, const char *ceiling_dirs); +/** + * Open a bare repository on the serverside. + * + * This is a fast open for bare repositories that will come in handy + * if you're e.g. hosting git repositories and need to access them + * efficiently + * + * @param out Pointer to the repo which will be opened. + * @param bare_path Direct path to the bare repository + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_repository_open_bare(git_repository **out, const char *bare_path); + /** * Free a previously allocated repository * @@ -387,21 +400,6 @@ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); */ GIT_EXTERN(int) git_repository_config(git_config **out, git_repository *repo); -/** - * Set the configuration file for this repository - * - * This configuration file will be used for all configuration - * queries involving this repository. - * - * The repository will keep a reference to the config file; - * the user must still free the config after setting it - * to the repository, or it will leak. - * - * @param repo A repository object - * @param config A Config object - */ -GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); - /** * Get the Object Database for this repository. * @@ -418,21 +416,6 @@ GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *con */ GIT_EXTERN(int) git_repository_odb(git_odb **out, git_repository *repo); -/** - * Set the Object Database for this repository - * - * The ODB will be used for all object-related operations - * involving this repository. - * - * The repository will keep a reference to the ODB; the user - * must still free the ODB object after setting it to the - * repository, or it will leak. - * - * @param repo A repository object - * @param odb An ODB object - */ -GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); - /** * Get the Reference Database Backend for this repository. * @@ -449,23 +432,6 @@ GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); */ GIT_EXTERN(int) git_repository_refdb(git_refdb **out, git_repository *repo); -/** - * Set the Reference Database Backend for this repository - * - * The refdb will be used for all reference related operations - * involving this repository. - * - * The repository will keep a reference to the refdb; the user - * must still free the refdb object after setting it to the - * repository, or it will leak. - * - * @param repo A repository object - * @param refdb An refdb object - */ -GIT_EXTERN(void) git_repository_set_refdb( - git_repository *repo, - git_refdb *refdb); - /** * Get the Index file for this repository. * @@ -482,21 +448,6 @@ GIT_EXTERN(void) git_repository_set_refdb( */ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo); -/** - * Set the index file for this repository - * - * This index will be used for all index-related operations - * involving this repository. - * - * The repository will keep a reference to the index file; - * the user must still free the index after setting it - * to the repository, or it will leak. - * - * @param repo A repository object - * @param index An index object - */ -GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); - /** * Retrieve git's prepared message * @@ -675,6 +626,28 @@ typedef enum { */ GIT_EXTERN(int) git_repository_state(git_repository *repo); +/** + * Sets the active namespace for this Git Repository + * + * This namespace affects all reference operations for the repo. + * See `man gitnamespaces` + * + * @param repo The repo + * @param nmspace The namespace. This should not include the refs + * folder, e.g. to namespace all references under `refs/namespaces/foo/`, + * use `foo` as the namespace. + * @return 0 on success, -1 on error + */ +GIT_EXTERN(int) git_repository_set_namespace(git_repository *repo, const char *nmspace); + +/** + * Get the currently active namespace for this repository + * + * @param repo The repo + * @return the active namespace, or NULL if there isn't one + */ +GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 6edb7767c9a..e155c701296 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -21,17 +21,60 @@ GIT_BEGIN_DECL /** - * Find an object, as specified by a revision string. See `man gitrevisions`, or the documentation - * for `git rev-parse` for information on the syntax accepted. + * Find a single object, as specified by a revision string. See `man gitrevisions`, + * or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for + * information on the syntax accepted. * * @param out pointer to output object * @param repo the repository to search in * @param spec the textual specification for an object - * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, - * GIT_EINVALIDSPEC or an error code + * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec); + +/** + * Revparse flags. These indicate the intended behavior of the spec passed to + * git_revparse. + */ +typedef enum { + /** The spec targeted a single object. */ + GIT_REVPARSE_SINGLE = 1 << 0, + /** The spec targeted a range of commits. */ + GIT_REVPARSE_RANGE = 1 << 1, + /** The spec used the '...' operator, which invokes special semantics. */ + GIT_REVPARSE_MERGE_BASE = 1 << 2, +} git_revparse_mode_t; + +/** + * Git Revision Spec: output of a `git_revparse` operation + */ +typedef struct { + /** The left element of the revspec; must be freed by the user */ + git_object *from; + /** The right element of the revspec; must be freed by the user */ + git_object *to; + /** The intent of the revspec */ + unsigned int flags; +} git_revspec; + +/** + * Parse a revision string for `from`, `to`, and intent. See `man gitrevisions` or + * http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for information + * on the syntax accepted. + * + * @param revspec Pointer to an user-allocated git_revspec struct where the result + * of the rev-parse will be stored + * @param repo the repository to search in + * @param spec the rev-parse spec to parse + * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code + */ +GIT_EXTERN(int) git_revparse( + git_revspec *revspec, + git_repository *repo, + const char *spec); + + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index ad57b622ee1..8bfe0b502da 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -92,7 +92,7 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker); * * The given commit will be used as one of the roots * when starting the revision walk. At least one commit - * must be pushed the repository before a walk can + * must be pushed onto the walker before a walk can * be started. * * @param walk the walker being used for the traversal. @@ -216,6 +216,21 @@ GIT_EXTERN(int) git_revwalk_next(git_oid *out, git_revwalk *walk); */ GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode); +/** + * Push and hide the respective endpoints of the given range. + * + * The range should be of the form + * .. + * where each is in the form accepted by 'git_revparse_single'. + * The left-hand commit will be hidden and the right-hand commit pushed. + * + * @param walk the walker being used for the traversal + * @param range the range + * @return 0 or an error code + * + */ +GIT_EXTERN(int) git_revwalk_push_range(git_revwalk *walk, const char *range); + /** * Free a revision walker previously allocated. * diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 1abd33e79f0..004665050d0 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -103,27 +103,44 @@ typedef enum { * * WD_UNTRACKED - wd contains untracked files */ typedef enum { - GIT_SUBMODULE_STATUS_IN_HEAD = (1u << 0), - GIT_SUBMODULE_STATUS_IN_INDEX = (1u << 1), - GIT_SUBMODULE_STATUS_IN_CONFIG = (1u << 2), - GIT_SUBMODULE_STATUS_IN_WD = (1u << 3), - GIT_SUBMODULE_STATUS_INDEX_ADDED = (1u << 4), - GIT_SUBMODULE_STATUS_INDEX_DELETED = (1u << 5), - GIT_SUBMODULE_STATUS_INDEX_MODIFIED = (1u << 6), - GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = (1u << 7), - GIT_SUBMODULE_STATUS_WD_ADDED = (1u << 8), - GIT_SUBMODULE_STATUS_WD_DELETED = (1u << 9), - GIT_SUBMODULE_STATUS_WD_MODIFIED = (1u << 10), - GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11), - GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = (1u << 12), - GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), + GIT_SUBMODULE_STATUS_IN_HEAD = (1u << 0), + GIT_SUBMODULE_STATUS_IN_INDEX = (1u << 1), + GIT_SUBMODULE_STATUS_IN_CONFIG = (1u << 2), + GIT_SUBMODULE_STATUS_IN_WD = (1u << 3), + GIT_SUBMODULE_STATUS_INDEX_ADDED = (1u << 4), + GIT_SUBMODULE_STATUS_INDEX_DELETED = (1u << 5), + GIT_SUBMODULE_STATUS_INDEX_MODIFIED = (1u << 6), + GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = (1u << 7), + GIT_SUBMODULE_STATUS_WD_ADDED = (1u << 8), + GIT_SUBMODULE_STATUS_WD_DELETED = (1u << 9), + GIT_SUBMODULE_STATUS_WD_MODIFIED = (1u << 10), + GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11), + GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = (1u << 12), + GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), } git_submodule_status_t; -#define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ - (((S) & ~(GIT_SUBMODULE_STATUS_IN_HEAD | \ +#define GIT_SUBMODULE_STATUS__IN_FLAGS \ + (GIT_SUBMODULE_STATUS_IN_HEAD | \ GIT_SUBMODULE_STATUS_IN_INDEX | \ GIT_SUBMODULE_STATUS_IN_CONFIG | \ - GIT_SUBMODULE_STATUS_IN_WD)) == 0) + GIT_SUBMODULE_STATUS_IN_WD) + +#define GIT_SUBMODULE_STATUS__INDEX_FLAGS \ + (GIT_SUBMODULE_STATUS_INDEX_ADDED | \ + GIT_SUBMODULE_STATUS_INDEX_DELETED | \ + GIT_SUBMODULE_STATUS_INDEX_MODIFIED) + +#define GIT_SUBMODULE_STATUS__WD_FLAGS \ + ~(GIT_SUBMODULE_STATUS__IN_FLAGS | GIT_SUBMODULE_STATUS__INDEX_FLAGS) + +#define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ + (((S) & ~GIT_SUBMODULE_STATUS__IN_FLAGS) == 0) + +#define GIT_SUBMODULE_STATUS_IS_INDEX_UNMODIFIED(S) \ + (((S) & GIT_SUBMODULE_STATUS__INDEX_FLAGS) == 0) + +#define GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(S) \ + (((S) & GIT_SUBMODULE_STATUS__WD_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_WD_DIRTY(S) \ (((S) & (GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED | \ diff --git a/include/git2/sys/commit.h b/include/git2/sys/commit.h new file mode 100644 index 00000000000..096e028c56d --- /dev/null +++ b/include/git2/sys/commit.h @@ -0,0 +1,45 @@ +/* + * 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_sys_git_commit_h__ +#define INCLUDE_sys_git_commit_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" + +/** + * @file git2/sys/commit.h + * @brief Low-level Git commit creation + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Create new commit in the repository from a list of `git_oid` values + * + * See documentation for `git_commit_create()` for information about the + * parameters, as the meaning is identical excepting that `tree` and + * `parents` now take `git_oid`. This is a dangerous API in that the + * `parents` list of `git_oid`s in not checked for validity. + */ +GIT_EXTERN(int) git_commit_create_from_oids( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]); + +/** @} */ +GIT_END_DECL +#endif diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h new file mode 100644 index 00000000000..1c9deba7cbd --- /dev/null +++ b/include/git2/sys/config.h @@ -0,0 +1,71 @@ +/* + * 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_sys_git_config_backend_h__ +#define INCLUDE_sys_git_config_backend_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/config.h" + +/** + * @file git2/sys/config.h + * @brief Git config backend routines + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Generic backend that implements the interface to + * access a configuration file + */ +struct git_config_backend { + unsigned int version; + struct git_config *cfg; + + /* Open means open the file/database and parse if necessary */ + int (*open)(struct git_config_backend *, unsigned int level); + int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); + int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); + int (*set)(struct git_config_backend *, const char *key, const char *value); + int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); + int (*del)(struct git_config_backend *, const char *key); + int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); + int (*refresh)(struct git_config_backend *); + void (*free)(struct git_config_backend *); +}; +#define GIT_CONFIG_BACKEND_VERSION 1 +#define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} + +/** + * Add a generic config file instance to an existing config + * + * Note that the configuration object will free the file + * automatically. + * + * Further queries on this config object will access each + * of the config file instances in order (instances with + * a higher priority level will be accessed first). + * + * @param cfg the configuration to add the file to + * @param file the configuration file (backend) to add + * @param level the priority level of the backend + * @param force if a config file already exists for the given + * priority level, replace it + * @return 0 on success, GIT_EEXISTS when adding more than one file + * for a given priority level (and force_replace set to 0), or error code + */ +GIT_EXTERN(int) git_config_add_backend( + git_config *cfg, + git_config_backend *file, + unsigned int level, + int force); + +/** @} */ +GIT_END_DECL +#endif diff --git a/include/git2/sys/index.h b/include/git2/sys/index.h new file mode 100644 index 00000000000..f74637f84c8 --- /dev/null +++ b/include/git2/sys/index.h @@ -0,0 +1,180 @@ +/* + * 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_sys_git_index_h__ +#define INCLUDE_sys_git_index_h__ + +/** + * @file git2/sys/index.h + * @brief Low-level Git index manipulation routines + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** Representation of a rename conflict entry in the index. */ +typedef struct git_index_name_entry { + char *ancestor; + char *ours; + char *theirs; +} git_index_name_entry; + +/** Representation of a resolve undo entry in the index. */ +typedef struct git_index_reuc_entry { + unsigned int mode[3]; + git_oid oid[3]; + char *path; +} git_index_reuc_entry; + +/** @name Conflict Name entry functions + * + * These functions work on rename conflict entries. + */ +/**@{*/ + +/** + * Get the count of filename conflict entries currently in the index. + * + * @param index an existing index object + * @return integer of count of current filename conflict entries + */ +GIT_EXTERN(unsigned int) git_index_name_entrycount(git_index *index); + +/** + * Get a filename conflict entry from the index. + * + * The returned entry is read-only and should not be modified + * or freed by the caller. + * + * @param index an existing index object + * @param n the position of the entry + * @return a pointer to the filename conflict entry; NULL if out of bounds + */ +GIT_EXTERN(const git_index_name_entry *) git_index_name_get_byindex( + git_index *index, size_t n); + +/** + * Record the filenames involved in a rename conflict. + * + * @param index an existing index object + * @param ancestor the path of the file as it existed in the ancestor + * @param ours the path of the file as it existed in our tree + * @param theirs the path of the file as it existed in their tree + */ +GIT_EXTERN(int) git_index_name_add(git_index *index, + const char *ancestor, const char *ours, const char *theirs); + +/** + * Remove all filename conflict entries. + * + * @param index an existing index object + * @return 0 or an error code + */ +GIT_EXTERN(void) git_index_name_clear(git_index *index); + +/**@}*/ + +/** @name Resolve Undo (REUC) index entry manipulation. + * + * These functions work on the Resolve Undo index extension and contains + * data about the original files that led to a merge conflict. + */ +/**@{*/ + +/** + * Get the count of resolve undo entries currently in the index. + * + * @param index an existing index object + * @return integer of count of current resolve undo entries + */ +GIT_EXTERN(unsigned int) git_index_reuc_entrycount(git_index *index); + +/** + * Finds the resolve undo entry that points to the given path in the Git + * index. + * + * @param at_pos the address to which the position of the reuc entry is written (optional) + * @param index an existing index object + * @param path path to search + * @return 0 if found, < 0 otherwise (GIT_ENOTFOUND) + */ +GIT_EXTERN(int) git_index_reuc_find(size_t *at_pos, git_index *index, const char *path); + +/** + * Get a resolve undo entry from the index. + * + * The returned entry is read-only and should not be modified + * or freed by the caller. + * + * @param index an existing index object + * @param path path to search + * @return the resolve undo entry; NULL if not found + */ +GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_bypath(git_index *index, const char *path); + +/** + * Get a resolve undo entry from the index. + * + * The returned entry is read-only and should not be modified + * or freed by the caller. + * + * @param index an existing index object + * @param n the position of the entry + * @return a pointer to the resolve undo entry; NULL if out of bounds + */ +GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_byindex(git_index *index, size_t n); + +/** + * Adds a resolve undo entry for a file based on the given parameters. + * + * The resolve undo entry contains the OIDs of files that were involved + * in a merge conflict after the conflict has been resolved. This allows + * conflicts to be re-resolved later. + * + * If there exists a resolve undo entry for the given path in the index, + * it will be removed. + * + * This method will fail in bare index instances. + * + * @param index an existing index object + * @param path filename to add + * @param ancestor_mode mode of the ancestor file + * @param ancestor_id oid of the ancestor file + * @param our_mode mode of our file + * @param our_id oid of our file + * @param their_mode mode of their file + * @param their_id oid of their file + * @return 0 or an error code + */ +GIT_EXTERN(int) git_index_reuc_add(git_index *index, const char *path, + int ancestor_mode, const git_oid *ancestor_id, + int our_mode, const git_oid *our_id, + int their_mode, const git_oid *their_id); + +/** + * Remove an resolve undo entry from the index + * + * @param index an existing index object + * @param n position of the resolve undo entry to remove + * @return 0 or an error code + */ +GIT_EXTERN(int) git_index_reuc_remove(git_index *index, size_t n); + +/** + * Remove all resolve undo entries from the index + * + * @param index an existing index object + * @return 0 or an error code + */ +GIT_EXTERN(void) git_index_reuc_clear(git_index *index); + +/**@}*/ + +/** @} */ +GIT_END_DECL +#endif + diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h new file mode 100644 index 00000000000..3cd2734c043 --- /dev/null +++ b/include/git2/sys/odb_backend.h @@ -0,0 +1,86 @@ +/* + * 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_sys_git_odb_backend_h__ +#define INCLUDE_sys_git_odb_backend_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" +#include "git2/odb.h" + +/** + * @file git2/sys/backend.h + * @brief Git custom backend implementors functions + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * An instance for a custom backend + */ +struct git_odb_backend { + unsigned int version; + git_odb *odb; + + /* read and read_prefix each return to libgit2 a buffer which + * will be freed later. The buffer should be allocated using + * the function git_odb_backend_malloc to ensure that it can + * be safely freed later. */ + int (* read)( + void **, size_t *, git_otype *, git_odb_backend *, const git_oid *); + + /* To find a unique object given a prefix + * of its oid. + * The oid given must be so that the + * remaining (GIT_OID_HEXSZ - len)*4 bits + * are 0s. + */ + int (* read_prefix)( + git_oid *, void **, size_t *, git_otype *, + git_odb_backend *, const git_oid *, size_t); + + int (* read_header)( + size_t *, git_otype *, git_odb_backend *, const git_oid *); + + /* The writer may assume that the object + * has already been hashed and is passed + * in the first parameter. + */ + int (* write)( + git_oid *, git_odb_backend *, const void *, size_t, git_otype); + + int (* writestream)( + git_odb_stream **, git_odb_backend *, size_t, git_otype); + + int (* readstream)( + git_odb_stream **, git_odb_backend *, const git_oid *); + + int (* exists)( + git_odb_backend *, const git_oid *); + + int (* refresh)(git_odb_backend *); + + int (* foreach)( + git_odb_backend *, git_odb_foreach_cb cb, void *payload); + + int (* writepack)( + git_odb_writepack **, git_odb_backend *, + git_transfer_progress_callback progress_cb, void *progress_payload); + + void (* free)(git_odb_backend *); +}; + +#define GIT_ODB_BACKEND_VERSION 1 +#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} + +GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); + +GIT_END_DECL + +#endif diff --git a/include/git2/refdb_backend.h b/include/git2/sys/refdb_backend.h similarity index 62% rename from include/git2/refdb_backend.h rename to include/git2/sys/refdb_backend.h index bf33817d6cd..d5f599fecb2 100644 --- a/include/git2/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -4,12 +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_git_refdb_backend_h__ -#define INCLUDE_git_refdb_backend_h__ +#ifndef INCLUDE_sys_git_refdb_backend_h__ +#define INCLUDE_sys_git_refdb_backend_h__ -#include "common.h" -#include "types.h" -#include "oid.h" +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" /** * @file git2/refdb_backend.h @@ -30,7 +30,7 @@ struct git_refdb_backend { */ int (*exists)( int *exists, - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *ref_name); /** @@ -39,7 +39,7 @@ struct git_refdb_backend { */ int (*lookup)( git_reference **out, - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *ref_name); /** @@ -47,7 +47,7 @@ struct git_refdb_backend { * provide this function. */ int (*foreach)( - struct git_refdb_backend *backend, + git_refdb_backend *backend, unsigned int list_flags, git_reference_foreach_cb callback, void *payload); @@ -59,7 +59,7 @@ struct git_refdb_backend { * against the glob. */ int (*foreach_glob)( - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *glob, unsigned int list_flags, git_reference_foreach_cb callback, @@ -69,13 +69,13 @@ struct git_refdb_backend { * Writes the given reference to the refdb. A refdb implementation * must provide this function. */ - int (*write)(struct git_refdb_backend *backend, const git_reference *ref); + int (*write)(git_refdb_backend *backend, const git_reference *ref); /** * Deletes the given reference from the refdb. A refdb implementation * must provide this function. */ - int (*delete)(struct git_refdb_backend *backend, const git_reference *ref); + int (*delete)(git_refdb_backend *backend, const git_reference *ref); /** * Suggests that the given refdb compress or optimize its references. @@ -84,25 +84,46 @@ struct git_refdb_backend { * implementation may provide this function; if it is not provided, * nothing will be done. */ - int (*compress)(struct git_refdb_backend *backend); + int (*compress)(git_refdb_backend *backend); /** * Frees any resources held by the refdb. A refdb implementation may * provide this function; if it is not provided, nothing will be done. */ - void (*free)(struct git_refdb_backend *backend); + void (*free)(git_refdb_backend *backend); }; #define GIT_ODB_BACKEND_VERSION 1 #define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} /** - * Constructors for default refdb backends. + * Constructors for default filesystem-based refdb backend + * + * Under normal usage, this is called for you when the repository is + * opened / created, but you can use this to explicitly construct a + * filesystem refdb backend for a repository. + * + * @param backend_out Output pointer to the git_refdb_backend object + * @param repo Git repository to access + * @return 0 on success, <0 error code on failure */ GIT_EXTERN(int) git_refdb_backend_fs( - struct git_refdb_backend **backend_out, - git_repository *repo, - git_refdb *refdb); + git_refdb_backend **backend_out, + git_repository *repo); + +/** + * Sets the custom backend to an existing reference DB + * + * The `git_refdb` will take ownership of the `git_refdb_backend` so you + * should NOT free it after calling this function. + * + * @param refdb database to add the backend to + * @param backend pointer to a git_refdb_backend instance + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_refdb_set_backend( + git_refdb *refdb, + git_refdb_backend *backend); GIT_END_DECL diff --git a/include/git2/sys/refs.h b/include/git2/sys/refs.h new file mode 100644 index 00000000000..85963258cd6 --- /dev/null +++ b/include/git2/sys/refs.h @@ -0,0 +1,38 @@ +/* + * 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_sys_git_refdb_h__ +#define INCLUDE_sys_git_refdb_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" + +/** + * Create a new direct reference from an OID. + * + * @param name the reference name + * @param oid the object id for a direct reference + * @param symbolic the target for a symbolic reference + * @return the created git_reference or NULL on error + */ +GIT_EXTERN(git_reference *) git_reference__alloc( + const char *name, + const git_oid *oid, + const git_oid *peel); + +/** + * Create a new symbolic reference. + * + * @param name the reference name + * @param symbolic the target for a symbolic reference + * @return the created git_reference or NULL on error + */ +GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( + const char *name, + const char *target); + +#endif diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h new file mode 100644 index 00000000000..ba3d65ae567 --- /dev/null +++ b/include/git2/sys/repository.h @@ -0,0 +1,106 @@ +/* + * 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_sys_git_repository_h__ +#define INCLUDE_sys_git_repository_h__ + +/** + * @file git2/sys/repository.h + * @brief Git repository custom implementation routines + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Create a new repository with neither backends nor config object + * + * Note that this is only useful if you wish to associate the repository + * with a non-filesystem-backed object database and config store. + * + * @param out The blank repository + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_repository_new(git_repository **out); + + +/** + * Reset all the internal state in a repository. + * + * This will free all the mapped memory and internal objects + * of the repository and leave it in a "blank" state. + * + * There's no need to call this function directly unless you're + * trying to aggressively cleanup the repo before its + * deallocation. `git_repository_free` already performs this operation + * before deallocation the repo. + */ +GIT_EXTERN(void) git_repository__cleanup(git_repository *repo); + +/** + * Set the configuration file for this repository + * + * This configuration file will be used for all configuration + * queries involving this repository. + * + * The repository will keep a reference to the config file; + * the user must still free the config after setting it + * to the repository, or it will leak. + * + * @param repo A repository object + * @param config A Config object + */ +GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); + +/** + * Set the Object Database for this repository + * + * The ODB will be used for all object-related operations + * involving this repository. + * + * The repository will keep a reference to the ODB; the user + * must still free the ODB object after setting it to the + * repository, or it will leak. + * + * @param repo A repository object + * @param odb An ODB object + */ +GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); + +/** + * Set the Reference Database Backend for this repository + * + * The refdb will be used for all reference related operations + * involving this repository. + * + * The repository will keep a reference to the refdb; the user + * must still free the refdb object after setting it to the + * repository, or it will leak. + * + * @param repo A repository object + * @param refdb An refdb object + */ +GIT_EXTERN(void) git_repository_set_refdb(git_repository *repo, git_refdb *refdb); + +/** + * Set the index file for this repository + * + * This index will be used for all index-related operations + * involving this repository. + * + * The repository will keep a reference to the index file; + * the user must still free the index after setting it + * to the repository, or it will leak. + * + * @param repo A repository object + * @param index An index object + */ +GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); + +/** @} */ +GIT_END_DECL +#endif diff --git a/include/git2/tag.h b/include/git2/tag.h index 84c954c27f6..469b1d72bea 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -30,12 +30,8 @@ GIT_BEGIN_DECL * @param id identity of the tag to locate. * @return 0 or an error code */ -GIT_INLINE(int) git_tag_lookup( - git_tag **out, git_repository *repo, const git_oid *id) -{ - return git_object_lookup( - (git_object **)out, repo, id, (git_otype)GIT_OBJ_TAG); -} +GIT_EXTERN(int) git_tag_lookup( + git_tag **out, git_repository *repo, const git_oid *id); /** * Lookup a tag object from the repository, @@ -49,12 +45,8 @@ GIT_INLINE(int) git_tag_lookup( * @param len the length of the short identifier * @return 0 or an error code */ -GIT_INLINE(int) git_tag_lookup_prefix( - git_tag **out, git_repository *repo, const git_oid *id, size_t len) -{ - return git_object_lookup_prefix( - (git_object **)out, repo, id, len, (git_otype)GIT_OBJ_TAG); -} +GIT_EXTERN(int) git_tag_lookup_prefix( + git_tag **out, git_repository *repo, const git_oid *id, size_t len); /** * Close an open tag @@ -66,12 +58,7 @@ GIT_INLINE(int) git_tag_lookup_prefix( * * @param tag the tag to close */ - -GIT_INLINE(void) git_tag_free(git_tag *tag) -{ - git_object_free((git_object *)tag); -} - +GIT_EXTERN(void) git_tag_free(git_tag *tag); /** * Get the id of a tag. @@ -81,6 +68,14 @@ GIT_INLINE(void) git_tag_free(git_tag *tag) */ GIT_EXTERN(const git_oid *) git_tag_id(const git_tag *tag); +/** + * Get the repository that contains the tag. + * + * @param tag A previously loaded tag. + * @return Repository that contains this tag. + */ +GIT_EXTERN(git_repository *) git_tag_owner(const git_tag *tag); + /** * Get the tagged object of a tag * diff --git a/include/git2/tree.h b/include/git2/tree.h index 73bfc86f42e..6ad72204842 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -29,11 +29,8 @@ GIT_BEGIN_DECL * @param id Identity of the tree to locate. * @return 0 or an error code */ -GIT_INLINE(int) git_tree_lookup( - git_tree **out, git_repository *repo, const git_oid *id) -{ - return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TREE); -} +GIT_EXTERN(int) git_tree_lookup( + git_tree **out, git_repository *repo, const git_oid *id); /** * Lookup a tree object from the repository, @@ -47,15 +44,11 @@ GIT_INLINE(int) git_tree_lookup( * @param len the length of the short identifier * @return 0 or an error code */ -GIT_INLINE(int) git_tree_lookup_prefix( +GIT_EXTERN(int) git_tree_lookup_prefix( git_tree **out, git_repository *repo, const git_oid *id, - size_t len) -{ - return git_object_lookup_prefix( - (git_object **)out, repo, id, len, GIT_OBJ_TREE); -} + size_t len); /** * Close an open tree @@ -67,10 +60,7 @@ GIT_INLINE(int) git_tree_lookup_prefix( * * @param tree The tree to close */ -GIT_INLINE(void) git_tree_free(git_tree *tree) -{ - git_object_free((git_object *)tree); -} +GIT_EXTERN(void) git_tree_free(git_tree *tree); /** * Get the id of a tree. diff --git a/include/git2/types.h b/include/git2/types.h index bc15050ce64..aca9ed927e1 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -196,6 +196,26 @@ typedef struct git_push git_push; typedef struct git_remote_head git_remote_head; typedef struct git_remote_callbacks git_remote_callbacks; +/** + * This is passed as the first argument to the callback to allow the + * user to see the progress. + */ +typedef struct git_transfer_progress { + unsigned int total_objects; + unsigned int indexed_objects; + unsigned int received_objects; + size_t received_bytes; +} git_transfer_progress; + +/** + * Type for progress callbacks during indexing. Return a value less than zero + * to cancel the transfer. + * + * @param stats Structure containing information about the state of the transfer + * @param payload Payload provided by caller + */ +typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); + /** @} */ GIT_END_DECL diff --git a/include/git2/version.h b/include/git2/version.h index bc03e85d6c8..630d5152655 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,9 +7,9 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.17.0" +#define LIBGIT2_VERSION "0.18.0" #define LIBGIT2_VER_MAJOR 0 -#define LIBGIT2_VER_MINOR 17 +#define LIBGIT2_VER_MINOR 18 #define LIBGIT2_VER_REVISION 0 #endif diff --git a/src/attr.c b/src/attr.c index 979fecc147c..6dd2c7e2fa7 100644 --- a/src/attr.c +++ b/src/attr.c @@ -312,7 +312,7 @@ static int load_attr_blob_from_index( entry = git_index_get_byindex(index, pos); - if (old_oid && git_oid_cmp(old_oid, &entry->oid) == 0) + if (old_oid && git_oid__cmp(old_oid, &entry->oid) == 0) return GIT_ENOTFOUND; if ((error = git_blob_lookup(blob, repo, &entry->oid)) < 0) diff --git a/src/attr_file.c b/src/attr_file.c index 74bd2133fa9..85cd87624b3 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -8,6 +8,10 @@ static int sort_by_hash_and_name(const void *a_raw, const void *b_raw); static void git_attr_rule__clear(git_attr_rule *rule); +static bool parse_optimized_patterns( + git_attr_fnmatch *spec, + git_pool *pool, + const char *pattern); int git_attr_file__new( git_attr_file **attrs_ptr, @@ -296,7 +300,6 @@ void git_attr_path__free(git_attr_path *info) info->basename = NULL; } - /* * From gitattributes(5): * @@ -345,6 +348,9 @@ int git_attr_fnmatch__parse( assert(spec && base && *base); + if (parse_optimized_patterns(spec, pool, *base)) + return 0; + spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE); allow_space = (spec->flags != 0); @@ -430,6 +436,22 @@ int git_attr_fnmatch__parse( return 0; } +static bool parse_optimized_patterns( + git_attr_fnmatch *spec, + git_pool *pool, + const char *pattern) +{ + if (!pattern[1] && (pattern[0] == '*' || pattern[0] == '.')) { + spec->flags = GIT_ATTR_FNMATCH_MATCH_ALL; + spec->pattern = git_pool_strndup(pool, pattern, 1); + spec->length = 1; + + return true; + } + + return false; +} + static int sort_by_hash_and_name(const void *a_raw, const void *b_raw) { const git_attr_name *a = a_raw; diff --git a/src/attr_file.h b/src/attr_file.h index 2cc8546a2eb..d8abcda58e9 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -27,6 +27,7 @@ #define GIT_ATTR_FNMATCH_HASWILD (1U << 5) #define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6) #define GIT_ATTR_FNMATCH_ICASE (1U << 7) +#define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8) extern const char *git_attr__true; extern const char *git_attr__false; diff --git a/src/blob.c b/src/blob.c index c0514fc1310..a68c4cc3e2f 100644 --- a/src/blob.c +++ b/src/blob.c @@ -8,6 +8,7 @@ #include "git2/common.h" #include "git2/object.h" #include "git2/repository.h" +#include "git2/odb_backend.h" #include "common.h" #include "blob.h" @@ -17,32 +18,34 @@ const void *git_blob_rawcontent(const git_blob *blob) { assert(blob); - return blob->odb_object->raw.data; + return git_odb_object_data(blob->odb_object); } git_off_t git_blob_rawsize(const git_blob *blob) { assert(blob); - return (git_off_t)blob->odb_object->raw.len; + return (git_off_t)git_odb_object_size(blob->odb_object); } int git_blob__getbuf(git_buf *buffer, git_blob *blob) { return git_buf_set( - buffer, blob->odb_object->raw.data, blob->odb_object->raw.len); + buffer, + git_odb_object_data(blob->odb_object), + git_odb_object_size(blob->odb_object)); } -void git_blob__free(git_blob *blob) +void git_blob__free(void *blob) { - git_odb_object_free(blob->odb_object); + git_odb_object_free(((git_blob *)blob)->odb_object); git__free(blob); } -int git_blob__parse(git_blob *blob, git_odb_object *odb_obj) +int git_blob__parse(void *blob, git_odb_object *odb_obj) { assert(blob); git_cached_obj_incref((git_cached_obj *)odb_obj); - blob->odb_object = odb_obj; + ((git_blob *)blob)->odb_object = odb_obj; return 0; } @@ -314,8 +317,8 @@ int git_blob_is_binary(git_blob *blob) assert(blob); - content.ptr = blob->odb_object->raw.data; - content.size = min(blob->odb_object->raw.len, 4000); + content.ptr = blob->odb_object->buffer; + content.size = min(blob->odb_object->cached.size, 4000); return git_buf_text_is_binary(&content); } diff --git a/src/blob.h b/src/blob.h index 524734b1f69..22e37cc3a16 100644 --- a/src/blob.h +++ b/src/blob.h @@ -17,8 +17,8 @@ struct git_blob { git_odb_object *odb_object; }; -void git_blob__free(git_blob *blob); -int git_blob__parse(git_blob *blob, git_odb_object *obj); +void git_blob__free(void *blob); +int git_blob__parse(void *blob, git_odb_object *obj); int git_blob__getbuf(git_buf *buffer, git_blob *blob); #endif diff --git a/src/branch.c b/src/branch.c index 45ecca7515d..88f05252923 100644 --- a/src/branch.c +++ b/src/branch.c @@ -11,6 +11,7 @@ #include "config.h" #include "refspec.h" #include "refs.h" +#include "remote.h" #include "git2/branch.h" @@ -228,7 +229,7 @@ int git_branch_name(const char **out, git_reference *ref) return 0; } -static int retrieve_tracking_configuration( +static int retrieve_upstream_configuration( const char **out, git_repository *repo, const char *canonical_branch_name, @@ -250,7 +251,7 @@ static int retrieve_tracking_configuration( return error; } -int git_branch_tracking__name( +int git_branch_upstream__name( git_buf *tracking_name, git_repository *repo, const char *canonical_branch_name) @@ -266,11 +267,11 @@ int git_branch_tracking__name( if (!git_reference__is_branch(canonical_branch_name)) return not_a_local_branch(canonical_branch_name); - if ((error = retrieve_tracking_configuration( + if ((error = retrieve_upstream_configuration( &remote_name, repo, canonical_branch_name, "branch.%s.remote")) < 0) goto cleanup; - if ((error = retrieve_tracking_configuration( + if ((error = retrieve_upstream_configuration( &merge_name, repo, canonical_branch_name, "branch.%s.merge")) < 0) goto cleanup; @@ -283,12 +284,10 @@ int git_branch_tracking__name( if ((error = git_remote_load(&remote, repo, remote_name)) < 0) goto cleanup; - refspec = git_remote_fetchspec(remote); - if (refspec == NULL - || refspec->src == NULL - || refspec->dst == NULL) { - error = GIT_ENOTFOUND; - goto cleanup; + refspec = git_remote__matching_refspec(remote, merge_name); + if (!refspec) { + error = GIT_ENOTFOUND; + goto cleanup; } if (git_refspec_transform_r(&buf, refspec, merge_name) < 0) @@ -305,23 +304,16 @@ int git_branch_tracking__name( return error; } -int git_branch_remote_name( - char *remote_name_out, - size_t buffer_size, - git_repository *repo, - const char *canonical_branch_name) +static int remote_name(git_buf *buf, git_repository *repo, const char *canonical_branch_name) { git_strarray remote_list = {0}; - size_t i, remote_name_size; + size_t i; git_remote *remote; const git_refspec *fetchspec; int error = 0; char *remote_name = NULL; - assert(repo && canonical_branch_name); - - if (remote_name_out && buffer_size) - *remote_name_out = '\0'; + assert(buf && repo && canonical_branch_name); /* Verify that this is a remote branch */ if (!git_reference__is_remote(canonical_branch_name)) { @@ -338,13 +330,10 @@ int git_branch_remote_name( /* Find matching remotes */ for (i = 0; i < remote_list.count; i++) { if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0) - goto cleanup; - - fetchspec = git_remote_fetchspec(remote); + continue; - /* Defensivly check that we have a fetchspec */ - if (fetchspec && - git_refspec_dst_matches(fetchspec, canonical_branch_name)) { + fetchspec = git_remote__matching_dst_refspec(remote, canonical_branch_name); + if (fetchspec) { /* If we have not already set out yet, then set * it to the matching remote name. Otherwise * multiple remotes match this reference, and it @@ -362,23 +351,10 @@ int git_branch_remote_name( } if (remote_name) { - remote_name_size = strlen(remote_name) + 1; - error = (int) remote_name_size; - - if (remote_name_out) { - if(remote_name_size > buffer_size) { - giterr_set( - GITERR_INVALID, - "Buffer too short to hold the remote name."); - error = GIT_ERROR; - goto cleanup; - } - - memcpy(remote_name_out, remote_name, remote_name_size); - } + git_buf_clear(buf); + error = git_buf_puts(buf, remote_name); } else { error = GIT_ENOTFOUND; - goto cleanup; } cleanup: @@ -386,7 +362,24 @@ int git_branch_remote_name( return error; } -int git_branch_tracking_name( +int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo, const char *refname) +{ + int ret; + git_buf buf = GIT_BUF_INIT; + + if ((ret = remote_name(&buf, repo, refname)) < 0) + return ret; + + if (buffer) + git_buf_copy_cstr(buffer, buffer_len, &buf); + + ret = (int)git_buf_len(&buf) + 1; + git_buf_free(&buf); + + return ret; +} + +int git_branch_upstream_name( char *tracking_branch_name_out, size_t buffer_size, git_repository *repo, @@ -400,7 +393,7 @@ int git_branch_tracking_name( if (tracking_branch_name_out && buffer_size) *tracking_branch_name_out = '\0'; - if ((error = git_branch_tracking__name( + if ((error = git_branch_upstream__name( &buf, repo, canonical_branch_name)) < 0) goto cleanup; @@ -422,14 +415,14 @@ int git_branch_tracking_name( return (int)error; } -int git_branch_tracking( +int git_branch_upstream( git_reference **tracking_out, git_reference *branch) { int error; git_buf tracking_name = GIT_BUF_INIT; - if ((error = git_branch_tracking__name(&tracking_name, + if ((error = git_branch_upstream__name(&tracking_name, git_reference_owner(branch), git_reference_name(branch))) < 0) return error; @@ -442,6 +435,120 @@ int git_branch_tracking( return error; } +static int unset_upstream(git_config *config, const char *shortname) +{ + git_buf buf = GIT_BUF_INIT; + + if (git_buf_printf(&buf, "branch.%s.remote", shortname) < 0) + return -1; + + if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) + goto on_error; + + git_buf_clear(&buf); + if (git_buf_printf(&buf, "branch.%s.merge", shortname) < 0) + goto on_error; + + if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) + goto on_error; + + git_buf_free(&buf); + return 0; + +on_error: + git_buf_free(&buf); + return -1; +} + +int git_branch_set_upstream(git_reference *branch, const char *upstream_name) +{ + git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; + git_reference *upstream; + git_repository *repo; + git_remote *remote = NULL; + git_config *config; + const char *name, *shortname; + int local; + const git_refspec *fetchspec; + + name = git_reference_name(branch); + if (!git_reference__is_branch(name)) + return not_a_local_branch(name); + + if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) + return -1; + + shortname = name + strlen(GIT_REFS_HEADS_DIR); + + if (upstream_name == NULL) + return unset_upstream(config, shortname); + + repo = git_reference_owner(branch); + + /* First we need to figure out whether it's a branch or remote-tracking */ + if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) + local = 1; + else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) + local = 0; + else + return GIT_ENOTFOUND; + + /* + * If it's local, the remote is "." and the branch name is + * simply the refname. Otherwise we need to figure out what + * the remote-tracking branch's name on the remote is and use + * that. + */ + if (local) + git_buf_puts(&value, "."); + else + remote_name(&value, repo, git_reference_name(upstream)); + + if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) + goto on_error; + + if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) + goto on_error; + + if (local) { + if (git_buf_puts(&value, git_reference_name(branch)) < 0) + goto on_error; + } else { + /* Get the remoe-tracking branch's refname in its repo */ + if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0) + goto on_error; + + fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); + git_buf_clear(&value); + if (!fetchspec || git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) + goto on_error; + + git_remote_free(remote); + remote = NULL; + } + + git_buf_clear(&key); + if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) + goto on_error; + + if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) + goto on_error; + + git_reference_free(upstream); + git_buf_free(&key); + git_buf_free(&value); + + return 0; + +on_error: + git_reference_free(upstream); + git_buf_free(&key); + git_buf_free(&value); + git_remote_free(remote); + + return -1; +} + int git_branch_is_head( git_reference *branch) { diff --git a/src/branch.h b/src/branch.h index 8a26c4fea79..d02f2af0de4 100644 --- a/src/branch.h +++ b/src/branch.h @@ -9,7 +9,7 @@ #include "buffer.h" -int git_branch_tracking__name( +int git_branch_upstream__name( git_buf *tracking_name, git_repository *repo, const char *canonical_branch_name); diff --git a/src/cache.c b/src/cache.c index e7f33357722..1360cc97699 100644 --- a/src/cache.c +++ b/src/cache.c @@ -11,100 +11,262 @@ #include "thread-utils.h" #include "util.h" #include "cache.h" +#include "odb.h" +#include "object.h" #include "git2/oid.h" -int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr) +GIT__USE_OIDMAP + +bool git_cache__enabled = true; +ssize_t git_cache__max_storage = (256 * 1024 * 1024); +git_atomic_ssize git_cache__current_storage = {0}; + +static size_t git_cache__max_object_size[8] = { + 0, /* GIT_OBJ__EXT1 */ + 4096, /* GIT_OBJ_COMMIT */ + 4096, /* GIT_OBJ_TREE */ + 0, /* GIT_OBJ_BLOB */ + 4096, /* GIT_OBJ_TAG */ + 0, /* GIT_OBJ__EXT2 */ + 0, /* GIT_OBJ_OFS_DELTA */ + 0 /* GIT_OBJ_REF_DELTA */ +}; + +int git_cache_set_max_object_size(git_otype type, size_t size) { - if (size < 8) - size = 8; - size = git__size_t_powerof2(size); + if (type < 0 || (size_t)type >= ARRAY_SIZE(git_cache__max_object_size)) { + giterr_set(GITERR_INVALID, "type out of range"); + return -1; + } + + git_cache__max_object_size[type] = size; + return 0; +} - cache->size_mask = size - 1; - cache->lru_count = 0; - cache->free_obj = free_ptr; +void git_cache_dump_stats(git_cache *cache) +{ + git_cached_obj *object; - git_mutex_init(&cache->lock); + if (kh_size(cache->map) == 0) + return; - cache->nodes = git__malloc(size * sizeof(git_cached_obj *)); - GITERR_CHECK_ALLOC(cache->nodes); + printf("Cache %p: %d items cached, %d bytes\n", + cache, kh_size(cache->map), (int)cache->used_memory); - memset(cache->nodes, 0x0, size * sizeof(git_cached_obj *)); + kh_foreach_value(cache->map, object, { + char oid_str[9]; + printf(" %s%c %s (%d)\n", + git_object_type2string(object->type), + object->flags == GIT_CACHE_STORE_PARSED ? '*' : ' ', + git_oid_tostr(oid_str, sizeof(oid_str), &object->oid), + (int)object->size + ); + }); +} + +int git_cache_init(git_cache *cache) +{ + cache->used_memory = 0; + cache->map = git_oidmap_alloc(); + git_mutex_init(&cache->lock); return 0; } +/* called with lock */ +static void clear_cache(git_cache *cache) +{ + git_cached_obj *evict = NULL; + + if (kh_size(cache->map) == 0) + return; + + kh_foreach_value(cache->map, evict, { + git_cached_obj_decref(evict); + }); + + kh_clear(oid, cache->map); + git_atomic_ssize_add(&git_cache__current_storage, -cache->used_memory); + cache->used_memory = 0; +} + +void git_cache_clear(git_cache *cache) +{ + if (git_mutex_lock(&cache->lock) < 0) + return; + + clear_cache(cache); + + git_mutex_unlock(&cache->lock); +} + void git_cache_free(git_cache *cache) { - size_t i; + git_cache_clear(cache); - for (i = 0; i < (cache->size_mask + 1); ++i) { - if (cache->nodes[i] != NULL) - git_cached_obj_decref(cache->nodes[i], cache->free_obj); + git_oidmap_free(cache->map); + git_mutex_free(&cache->lock); +} + +/* Called with lock */ +static void cache_evict_entries(git_cache *cache) +{ + uint32_t seed = rand(); + size_t evict_count = 8; + ssize_t evicted_memory = 0; + + /* do not infinite loop if there's not enough entries to evict */ + if (evict_count > kh_size(cache->map)) { + clear_cache(cache); + return; } - git_mutex_free(&cache->lock); - git__free(cache->nodes); + while (evict_count > 0) { + khiter_t pos = seed++ % kh_end(cache->map); + + if (kh_exist(cache->map, pos)) { + git_cached_obj *evict = kh_val(cache->map, pos); + + evict_count--; + evicted_memory += evict->size; + git_cached_obj_decref(evict); + + kh_del(oid, cache->map, pos); + } + } + + cache->used_memory -= evicted_memory; + git_atomic_ssize_add(&git_cache__current_storage, -evicted_memory); } -void *git_cache_get(git_cache *cache, const git_oid *oid) +static bool cache_should_store(git_otype object_type, size_t object_size) { - uint32_t hash; - git_cached_obj *node = NULL, *result = NULL; + size_t max_size = git_cache__max_object_size[object_type]; + return git_cache__enabled && object_size < max_size; +} - memcpy(&hash, oid->id, sizeof(hash)); +static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags) +{ + khiter_t pos; + git_cached_obj *entry = NULL; - if (git_mutex_lock(&cache->lock)) { - giterr_set(GITERR_THREAD, "unable to lock cache mutex"); + if (!git_cache__enabled || git_mutex_lock(&cache->lock) < 0) return NULL; - } - { - node = cache->nodes[hash & cache->size_mask]; + pos = kh_get(oid, cache->map, oid); + if (pos != kh_end(cache->map)) { + entry = kh_val(cache->map, pos); - if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) { - git_cached_obj_incref(node); - result = node; + if (flags && entry->flags != flags) { + entry = NULL; + } else { + git_cached_obj_incref(entry); } } + git_mutex_unlock(&cache->lock); - return result; + return entry; } -void *git_cache_try_store(git_cache *cache, void *_entry) +static void *cache_store(git_cache *cache, git_cached_obj *entry) { - git_cached_obj *entry = _entry; - uint32_t hash; + khiter_t pos; - memcpy(&hash, &entry->oid, sizeof(uint32_t)); + git_cached_obj_incref(entry); - if (git_mutex_lock(&cache->lock)) { - giterr_set(GITERR_THREAD, "unable to lock cache mutex"); - return NULL; - } + if (!cache_should_store(entry->type, entry->size)) + return entry; - { - git_cached_obj *node = cache->nodes[hash & cache->size_mask]; + if (git_mutex_lock(&cache->lock) < 0) + return entry; - /* increase the refcount on this object, because - * the cache now owns it */ - git_cached_obj_incref(entry); + /* soften the load on the cache */ + if (git_cache__current_storage.val > git_cache__max_storage) + cache_evict_entries(cache); - if (node == NULL) { - cache->nodes[hash & cache->size_mask] = entry; - } else if (git_oid_cmp(&node->oid, &entry->oid) == 0) { - git_cached_obj_decref(entry, cache->free_obj); - entry = node; - } else { - git_cached_obj_decref(node, cache->free_obj); - cache->nodes[hash & cache->size_mask] = entry; + pos = kh_get(oid, cache->map, &entry->oid); + + /* not found */ + if (pos == kh_end(cache->map)) { + int rval; + + pos = kh_put(oid, cache->map, &entry->oid, &rval); + if (rval >= 0) { + kh_key(cache->map, pos) = &entry->oid; + kh_val(cache->map, pos) = entry; + git_cached_obj_incref(entry); + cache->used_memory += entry->size; + git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size); } + } + /* found */ + else { + git_cached_obj *stored_entry = kh_val(cache->map, pos); - /* increase the refcount again, because we are - * returning it to the user */ - git_cached_obj_incref(entry); + if (stored_entry->flags == entry->flags) { + git_cached_obj_decref(entry); + git_cached_obj_incref(stored_entry); + entry = stored_entry; + } else if (stored_entry->flags == GIT_CACHE_STORE_RAW && + entry->flags == GIT_CACHE_STORE_PARSED) { + git_cached_obj_decref(stored_entry); + git_cached_obj_incref(entry); + kh_key(cache->map, pos) = &entry->oid; + kh_val(cache->map, pos) = entry; + } else { + /* NO OP */ + } } - git_mutex_unlock(&cache->lock); + git_mutex_unlock(&cache->lock); return entry; } + +void *git_cache_store_raw(git_cache *cache, git_odb_object *entry) +{ + entry->cached.flags = GIT_CACHE_STORE_RAW; + return cache_store(cache, (git_cached_obj *)entry); +} + +void *git_cache_store_parsed(git_cache *cache, git_object *entry) +{ + entry->cached.flags = GIT_CACHE_STORE_PARSED; + return cache_store(cache, (git_cached_obj *)entry); +} + +git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid) +{ + return cache_get(cache, oid, GIT_CACHE_STORE_RAW); +} + +git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid) +{ + return cache_get(cache, oid, GIT_CACHE_STORE_PARSED); +} + +void *git_cache_get_any(git_cache *cache, const git_oid *oid) +{ + return cache_get(cache, oid, GIT_CACHE_STORE_ANY); +} + +void git_cached_obj_decref(void *_obj) +{ + git_cached_obj *obj = _obj; + + if (git_atomic_dec(&obj->refcount) == 0) { + switch (obj->flags) { + case GIT_CACHE_STORE_RAW: + git_odb_object__free(_obj); + break; + + case GIT_CACHE_STORE_PARSED: + git_object__free(_obj); + break; + + default: + git__free(_obj); + break; + } + } +} diff --git a/src/cache.h b/src/cache.h index 7034ec26819..53fbcf4e99b 100644 --- a/src/cache.h +++ b/src/cache.h @@ -12,43 +12,56 @@ #include "git2/odb.h" #include "thread-utils.h" +#include "oidmap.h" -#define GIT_DEFAULT_CACHE_SIZE 128 - -typedef void (*git_cached_obj_freeptr)(void *); +enum { + GIT_CACHE_STORE_ANY = 0, + GIT_CACHE_STORE_RAW = 1, + GIT_CACHE_STORE_PARSED = 2 +}; typedef struct { - git_oid oid; + git_oid oid; + int16_t type; /* git_otype value */ + uint16_t flags; /* GIT_CACHE_STORE value */ + size_t size; git_atomic refcount; } git_cached_obj; typedef struct { - git_cached_obj **nodes; - git_mutex lock; - - unsigned int lru_count; - size_t size_mask; - git_cached_obj_freeptr free_obj; + git_oidmap *map; + git_mutex lock; + ssize_t used_memory; } git_cache; -int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr); +extern bool git_cache__enabled; +extern ssize_t git_cache__max_storage; +extern git_atomic_ssize git_cache__current_storage; + +int git_cache_set_max_object_size(git_otype type, size_t size); + +int git_cache_init(git_cache *cache); void git_cache_free(git_cache *cache); +void git_cache_clear(git_cache *cache); -void *git_cache_try_store(git_cache *cache, void *entry); -void *git_cache_get(git_cache *cache, const git_oid *oid); +void *git_cache_store_raw(git_cache *cache, git_odb_object *entry); +void *git_cache_store_parsed(git_cache *cache, git_object *entry); -GIT_INLINE(void) git_cached_obj_incref(void *_obj) +git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid); +git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid); +void *git_cache_get_any(git_cache *cache, const git_oid *oid); + +GIT_INLINE(size_t) git_cache_size(git_cache *cache) { - git_cached_obj *obj = _obj; - git_atomic_inc(&obj->refcount); + return (size_t)kh_size(cache->map); } -GIT_INLINE(void) git_cached_obj_decref(void *_obj, git_cached_obj_freeptr free_obj) +GIT_INLINE(void) git_cached_obj_incref(void *_obj) { git_cached_obj *obj = _obj; - - if (git_atomic_dec(&obj->refcount) == 0) - free_obj(obj); + git_atomic_inc(&obj->refcount); } +void git_cached_obj_decref(void *_obj); + #endif diff --git a/src/checkout.c b/src/checkout.c index 24fa2102414..21f32d89a47 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -16,6 +16,7 @@ #include "git2/config.h" #include "git2/diff.h" #include "git2/submodule.h" +#include "git2/sys/index.h" #include "refs.h" #include "repository.h" @@ -119,6 +120,7 @@ static bool checkout_is_workdir_modified( const git_index_entry *wditem) { git_oid oid; + const git_index_entry *ie; /* handle "modified" submodule */ if (wditem->mode == GIT_FILEMODE_COMMIT) { @@ -137,7 +139,18 @@ static bool checkout_is_workdir_modified( if (!sm_oid) return false; - return (git_oid_cmp(&baseitem->oid, sm_oid) != 0); + return (git_oid__cmp(&baseitem->oid, sm_oid) != 0); + } + + /* Look at the cache to decide if the workdir is modified. If not, + * we can simply compare the oid in the cache to the baseitem instead + * of hashing the file. + */ + if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) { + if (wditem->mtime.seconds == ie->mtime.seconds && + wditem->mtime.nanoseconds == ie->mtime.nanoseconds && + wditem->file_size == ie->file_size) + return (git_oid__cmp(&baseitem->oid, &ie->oid) != 0); } /* depending on where base is coming from, we may or may not know @@ -151,7 +164,7 @@ static bool checkout_is_workdir_modified( wditem->file_size, &oid) < 0) return false; - return (git_oid_cmp(&baseitem->oid, &oid) != 0); + return (git_oid__cmp(&baseitem->oid, &oid) != 0); } #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \ @@ -454,6 +467,7 @@ static int checkout_action( int cmp = -1, act; int (*strcomp)(const char *, const char *) = data->diff->strcomp; int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp; + int error; /* move workdir iterator to follow along with deltas */ @@ -477,8 +491,11 @@ static int checkout_action( if (cmp == 0) { if (wd->mode == GIT_FILEMODE_TREE) { /* case 2 - entry prefixed by workdir tree */ - if (git_iterator_advance_into(&wd, workdir) < 0) - goto fail; + if ((error = git_iterator_advance_into(&wd, workdir)) < 0) { + if (error != GIT_ENOTFOUND || + git_iterator_advance(&wd, workdir) < 0) + goto fail; + } *wditem_ptr = wd; continue; @@ -698,8 +715,8 @@ static int blob_content_to_file( git_vector filters = GIT_VECTOR_INIT; /* Create a fake git_buf from the blob raw data... */ - filtered.ptr = blob->odb_object->raw.data; - filtered.size = blob->odb_object->raw.len; + filtered.ptr = (void *)git_blob_rawcontent(blob); + filtered.size = (size_t)git_blob_rawsize(blob); /* ... and make sure it doesn't get unexpectedly freed */ dont_free_filtered = true; @@ -1107,7 +1124,6 @@ static int checkout_data_init( git_checkout_opts *proposed) { int error = 0; - git_config *cfg; git_repository *repo = git_iterator_owner(target); memset(data, 0, sizeof(*data)); @@ -1120,9 +1136,6 @@ static int checkout_data_init( if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0) return error; - if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) - return error; - data->repo = repo; GITERR_CHECK_VERSION( @@ -1135,7 +1148,10 @@ static int checkout_data_init( /* refresh config and index content unless NO_REFRESH is given */ if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) { - if ((error = git_config_refresh(cfg)) < 0) + git_config *cfg; + + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 || + (error = git_config_refresh(cfg)) < 0) goto cleanup; /* if we are checking out the index, don't reload, @@ -1172,19 +1188,13 @@ static int checkout_data_init( data->pfx = git_pathspec_prefix(&data->opts.paths); - error = git_config_get_bool(&data->can_symlink, cfg, "core.symlinks"); - if (error < 0) { - if (error != GIT_ENOTFOUND) - goto cleanup; - - /* If "core.symlinks" is not found anywhere, default to true. */ - data->can_symlink = true; - giterr_clear(); - error = 0; - } + if ((error = git_repository__cvar( + &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0) + goto cleanup; if (!data->opts.baseline) { data->opts_free_baseline = true; + error = checkout_lookup_head_tree(&data->opts.baseline, repo); if (error == GIT_EORPHANEDHEAD) { diff --git a/src/clone.c b/src/clone.c index 0bbccd44b09..aeb7bbf5cf0 100644 --- a/src/clone.c +++ b/src/clone.c @@ -132,14 +132,14 @@ static int reference_matches_remote_head( return 0; } - if (git_oid_cmp(&head_info->remote_head_oid, &oid) == 0) { + if (git_oid__cmp(&head_info->remote_head_oid, &oid) == 0) { /* Determine the local reference name from the remote tracking one */ if (git_refspec_transform_l( - &head_info->branchname, + &head_info->branchname, head_info->refspec, reference_name) < 0) return -1; - + if (git_buf_len(&head_info->branchname) > 0) { if (git_buf_sets( &head_info->branchname, @@ -187,6 +187,7 @@ static int get_head_callback(git_remote_head *head, void *payload) static int update_head_to_remote(git_repository *repo, git_remote *remote) { int retcode = -1; + git_refspec dummy_spec; git_remote_head *remote_head; struct head_info head_info; git_buf remote_master_name = GIT_BUF_INIT; @@ -211,8 +212,13 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid); git_buf_init(&head_info.branchname, 16); head_info.repo = repo; - head_info.refspec = git_remote_fetchspec(remote); + head_info.refspec = git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE); head_info.found = 0; + + if (head_info.refspec == NULL) { + memset(&dummy_spec, 0, sizeof(git_refspec)); + head_info.refspec = &dummy_spec; + } /* Determine the remote tracking reference name from the local master */ if (git_refspec_transform_r( @@ -317,12 +323,14 @@ static int create_and_configure_origin( (error = git_remote_set_callbacks(origin, options->remote_callbacks)) < 0) goto on_error; - if (options->fetch_spec && - (error = git_remote_set_fetchspec(origin, options->fetch_spec)) < 0) - goto on_error; + if (options->fetch_spec) { + git_remote_clear_refspecs(origin); + if ((error = git_remote_add_fetch(origin, options->fetch_spec)) < 0) + goto on_error; + } if (options->push_spec && - (error = git_remote_set_pushspec(origin, options->push_spec)) < 0) + (error = git_remote_add_push(origin, options->push_spec)) < 0) goto on_error; if (options->pushurl && diff --git a/src/commit.c b/src/commit.c index e2d3d346b5f..46c02c292c9 100644 --- a/src/commit.c +++ b/src/commit.c @@ -9,6 +9,7 @@ #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" +#include "git2/sys/commit.h" #include "common.h" #include "odb.h" @@ -30,8 +31,10 @@ static void clear_parents(git_commit *commit) git_vector_clear(&commit->parent_ids); } -void git_commit__free(git_commit *commit) +void git_commit__free(void *_commit) { + git_commit *commit = _commit; + clear_parents(commit); git_vector_free(&commit->parent_ids); @@ -44,16 +47,16 @@ void git_commit__free(git_commit *commit) } int git_commit_create_v( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - ...) + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + ...) { va_list ap; int i, res; @@ -76,30 +79,29 @@ int git_commit_create_v( return res; } -int git_commit_create( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - const git_commit *parents[]) +int git_commit_create_from_oids( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; + assert(oid && repo && tree && parent_count >= 0); assert(git_object_owner((const git_object *)tree) == repo); - git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree)); + git_oid__writebuf(&commit, "tree ", tree); - for (i = 0; i < parent_count; ++i) { - assert(git_object_owner((const git_object *)parents[i]) == repo); - git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i])); - } + for (i = 0; i < parent_count; ++i) + git_oid__writebuf(&commit, "parent ", parents[i]); git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); @@ -131,10 +133,46 @@ int git_commit_create( return -1; } -int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) +int git_commit_create( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]) { - const char *buffer = data; - const char *buffer_end = (const char *)data + len; + int retval, i; + const git_oid **parent_oids; + + assert(parent_count >= 0); + + parent_oids = git__malloc(parent_count * sizeof(git_oid *)); + GITERR_CHECK_ALLOC(parent_oids); + + for (i = 0; i < parent_count; ++i) { + assert(git_object_owner((const git_object *)parents[i]) == repo); + parent_oids[i] = git_object_id((const git_object *)parents[i]); + } + + retval = git_commit_create_from_oids( + oid, repo, update_ref, author, committer, + message_encoding, message, + git_object_id((const git_object *)tree), parent_count, parent_oids); + + git__free((void *)parent_oids); + + return retval; +} + +int git_commit__parse(void *_commit, git_odb_object *odb_obj) +{ + git_commit *commit = _commit; + const char *buffer = git_odb_object_data(odb_obj); + const char *buffer_end = buffer + git_odb_object_size(odb_obj); git_oid parent_id; if (git_vector_init(&commit->parent_ids, 4, NULL) < 0) @@ -189,8 +227,8 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) buffer = eoln; } - /* skip blank lines */ - while (buffer < buffer_end - 1 && *buffer == '\n') + /* buffer is now at the end of the header, double-check and move forward into the message */ + if (buffer < buffer_end && *buffer == '\n') buffer++; /* parse commit message */ @@ -206,12 +244,6 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) return -1; } -int git_commit__parse(git_commit *commit, git_odb_object *obj) -{ - assert(commit); - return git_commit__parse_buffer(commit, obj->raw.data, obj->raw.len); -} - #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ _rvalue git_commit_##_name(const git_commit *commit) \ {\ diff --git a/src/commit.h b/src/commit.h index 1ab164c0b65..d0981b125ba 100644 --- a/src/commit.h +++ b/src/commit.h @@ -27,8 +27,7 @@ struct git_commit { char *message; }; -void git_commit__free(git_commit *c); -int git_commit__parse(git_commit *commit, git_odb_object *obj); +void git_commit__free(void *commit); +int git_commit__parse(void *commit, git_odb_object *obj); -int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len); #endif diff --git a/src/commit_list.c b/src/commit_list.c index 603dd754a35..bd5b5201a46 100644 --- a/src/commit_list.c +++ b/src/commit_list.c @@ -100,12 +100,15 @@ git_commit_list_node *git_commit_list_pop(git_commit_list **stack) return item; } -static int commit_quick_parse(git_revwalk *walk, git_commit_list_node *commit, git_rawobj *raw) +static int commit_quick_parse( + git_revwalk *walk, + git_commit_list_node *commit, + const uint8_t *buffer, + size_t buffer_len) { const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; - unsigned char *buffer = raw->data; - unsigned char *buffer_end = buffer + raw->len; - unsigned char *parents_start, *committer_start; + const uint8_t *buffer_end = buffer + buffer_len; + const uint8_t *parents_start, *committer_start; int i, parents = 0; int commit_time; @@ -124,7 +127,7 @@ static int commit_quick_parse(git_revwalk *walk, git_commit_list_node *commit, g for (i = 0; i < parents; ++i) { git_oid oid; - if (git_oid_fromstr(&oid, (char *)buffer + strlen("parent ")) < 0) + if (git_oid_fromstr(&oid, (const char *)buffer + strlen("parent ")) < 0) return -1; commit->parents[i] = git_revwalk__commit_lookup(walk, &oid); @@ -182,11 +185,14 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0) return error; - if (obj->raw.type != GIT_OBJ_COMMIT) { + if (obj->cached.type != GIT_OBJ_COMMIT) { giterr_set(GITERR_INVALID, "Object is no commit object"); error = -1; } else - error = commit_quick_parse(walk, commit, &obj->raw); + error = commit_quick_parse( + walk, commit, + (const uint8_t *)git_odb_object_data(obj), + git_odb_object_size(obj)); git_odb_object_free(obj); return error; diff --git a/src/config.c b/src/config.c index 5379b0ec5e5..2e1268ef373 100644 --- a/src/config.c +++ b/src/config.c @@ -9,6 +9,7 @@ #include "fileops.h" #include "config.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "vector.h" #include "buf_text.h" #include "config_file.h" @@ -292,6 +293,9 @@ int git_config_refresh(git_config *cfg) error = file->refresh(file); } + if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) + git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg)); + return error; } @@ -359,6 +363,7 @@ int git_config_set_bool(git_config *cfg, const char *name, int value) int git_config_set_string(git_config *cfg, const char *name, const char *value) { + int error; git_config_backend *file; file_internal *internal; @@ -368,9 +373,20 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) } internal = git_vector_get(&cfg->files, 0); + if (!internal) { + /* Should we auto-vivify .git/config? Tricky from this location */ + giterr_set(GITERR_CONFIG, "Cannot set value when no config files exist"); + return GIT_ENOTFOUND; + } + file = internal->file; - return file->set(file, name, value); + error = file->set(file, name, value); + + if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) + git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg)); + + return error; } /*********** diff --git a/src/config_cache.c b/src/config_cache.c index 2f36df7d168..84de3a5ed34 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -26,7 +26,7 @@ struct map_data { * files that have the text property set. Alternatives are lf, crlf * and native, which uses the platform's native line ending. The default * value is native. See gitattributes(5) for more information on - * end-of-line conversion. + * end-of-line conversion. */ static git_cvar_map _cvar_map_eol[] = { {GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET}, @@ -37,7 +37,7 @@ static git_cvar_map _cvar_map_eol[] = { /* * core.autocrlf - * Setting this variable to "true" is almost the same as setting + * Setting this variable to "true" is almost the same as setting * the text attribute to "auto" on all files except that text files are * not guaranteed to be normalized: files that contain CRLF in the * repository will not be touched. Use this setting if you want to have @@ -51,9 +51,22 @@ static git_cvar_map _cvar_map_autocrlf[] = { {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT} }; +/* + * Generic map for integer values + */ +static git_cvar_map _cvar_map_int[] = { + {GIT_CVAR_INT32, NULL, 0}, +}; + static struct map_data _cvar_maps[] = { {"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT}, - {"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT} + {"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT}, + {"core.symlinks", NULL, 0, GIT_SYMLINKS_DEFAULT }, + {"core.ignorecase", NULL, 0, GIT_IGNORECASE_DEFAULT }, + {"core.filemode", NULL, 0, GIT_FILEMODE_DEFAULT }, + {"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT }, + {"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT }, + {"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT }, }; int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) @@ -69,12 +82,16 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) if (error < 0) return error; - error = git_config_get_mapped(out, - config, data->cvar_name, data->maps, data->map_count); + if (data->maps) + error = git_config_get_mapped( + out, config, data->cvar_name, data->maps, data->map_count); + else + error = git_config_get_bool(out, config, data->cvar_name); - if (error == GIT_ENOTFOUND) + if (error == GIT_ENOTFOUND) { + giterr_clear(); *out = data->default_value; - + } else if (error < 0) return error; diff --git a/src/config_file.c b/src/config_file.c index 8b51ab21bec..a9a40c366aa 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -12,6 +12,7 @@ #include "buffer.h" #include "buf_text.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "git2/types.h" #include "strmap.h" @@ -481,8 +482,10 @@ static int config_set_multivar( pos = git_strmap_lookup_index(b->values, key); if (!git_strmap_valid_index(b->values, pos)) { + /* If we don't have it, behave like a normal set */ + result = config_set(cfg, name, value); git__free(key); - return GIT_ENOTFOUND; + return result; } var = git_strmap_value_at(b->values, pos); diff --git a/src/date.c b/src/date.c index bbf88eb44bb..ce1721a0b6b 100644 --- a/src/date.c +++ b/src/date.c @@ -681,8 +681,8 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm const char *end = date; int i; - while (isalpha(*++end)); - ; + while (isalpha(*++end)) + /* scan to non-alpha */; for (i = 0; i < 12; i++) { size_t match = match_string(date, month_names[i]); diff --git a/src/diff.c b/src/diff.c index 7152683e7dc..fbff1a6fb02 100644 --- a/src/diff.c +++ b/src/diff.c @@ -14,6 +14,8 @@ #define DIFF_FLAG_IS_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) != 0) #define DIFF_FLAG_ISNT_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) == 0) +#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \ + (VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL)) static git_diff_delta *diff_delta__alloc( git_diff_list *diff, @@ -194,21 +196,21 @@ static git_diff_delta *diff_delta__last_for_item( switch (delta->status) { case GIT_DELTA_UNMODIFIED: case GIT_DELTA_DELETED: - if (git_oid_cmp(&delta->old_file.oid, &item->oid) == 0) + if (git_oid__cmp(&delta->old_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_ADDED: - if (git_oid_cmp(&delta->new_file.oid, &item->oid) == 0) + if (git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_UNTRACKED: if (diff->strcomp(delta->new_file.path, item->path) == 0 && - git_oid_cmp(&delta->new_file.oid, &item->oid) == 0) + git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_MODIFIED: - if (git_oid_cmp(&delta->old_file.oid, &item->oid) == 0 || - git_oid_cmp(&delta->new_file.oid, &item->oid) == 0) + if (git_oid__cmp(&delta->old_file.oid, &item->oid) == 0 || + git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; default: @@ -267,67 +269,157 @@ static int config_bool(git_config *cfg, const char *name, int defvalue) return val; } -static git_diff_list *git_diff_list_alloc( - git_repository *repo, const git_diff_options *opts) +static int config_int(git_config *cfg, const char *name, int defvalue) { - git_config *cfg; + int val = defvalue; + + if (git_config_get_int32(&val, cfg, name) < 0) + giterr_clear(); + + return val; +} + +static const char *diff_mnemonic_prefix( + git_iterator_type_t type, bool left_side) +{ + const char *pfx = ""; + + switch (type) { + case GIT_ITERATOR_TYPE_EMPTY: pfx = "c"; break; + case GIT_ITERATOR_TYPE_TREE: pfx = "c"; break; + case GIT_ITERATOR_TYPE_INDEX: pfx = "i"; break; + case GIT_ITERATOR_TYPE_WORKDIR: pfx = "w"; break; + case GIT_ITERATOR_TYPE_FS: pfx = left_side ? "1" : "2"; break; + default: break; + } + + /* note: without a deeper look at pathspecs, there is no easy way + * to get the (o)bject / (w)ork tree mnemonics working... + */ + + return pfx; +} + +static git_diff_list *diff_list_alloc( + git_repository *repo, + git_iterator *old_iter, + git_iterator *new_iter) +{ + git_diff_options dflt = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = git__calloc(1, sizeof(git_diff_list)); - if (diff == NULL) + if (!diff) return NULL; + assert(repo && old_iter && new_iter); + GIT_REFCOUNT_INC(diff); diff->repo = repo; + diff->old_src = old_iter->type; + diff->new_src = new_iter->type; + memcpy(&diff->opts, &dflt, sizeof(diff->opts)); if (git_vector_init(&diff->deltas, 0, git_diff_delta__cmp) < 0 || - git_pool_init(&diff->pool, 1, 0) < 0) - goto fail; + git_pool_init(&diff->pool, 1, 0) < 0) { + git_diff_list_free(diff); + return NULL; + } + + /* Use case-insensitive compare if either iterator has + * the ignore_case bit set */ + if (!git_iterator_ignore_case(old_iter) && + !git_iterator_ignore_case(new_iter)) { + diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE; + + diff->strcomp = git__strcmp; + diff->strncomp = git__strncmp; + diff->pfxcomp = git__prefixcmp; + diff->entrycomp = git_index_entry__cmp; + } else { + diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE; + + diff->strcomp = git__strcasecmp; + diff->strncomp = git__strncasecmp; + diff->pfxcomp = git__prefixcmp_icase; + diff->entrycomp = git_index_entry__cmp_icase; + } + + return diff; +} + +static int diff_list_apply_options( + git_diff_list *diff, + const git_diff_options *opts) +{ + git_config *cfg; + git_repository *repo = diff->repo; + git_pool *pool = &diff->pool; + int val; + + if (opts) { + /* copy user options (except case sensitivity info from iterators) */ + bool icase = DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE); + memcpy(&diff->opts, opts, sizeof(diff->opts)); + DIFF_FLAG_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE, icase); + + /* initialize pathspec from options */ + if (git_pathspec_init(&diff->pathspec, &opts->pathspec, pool) < 0) + return -1; + } + + /* flag INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ + if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)) + diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; /* load config values that affect diff behavior */ if (git_repository_config__weakptr(&cfg, repo) < 0) - goto fail; - if (config_bool(cfg, "core.symlinks", 1)) + return -1; + + if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS; - if (config_bool(cfg, "core.ignorestat", 0)) + + if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORESTAT) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED; - if (config_bool(cfg, "core.filemode", 1)) + + if ((diff->opts.flags & GIT_DIFF_IGNORE_FILEMODE) == 0 && + !git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_MODE_BITS; - if (config_bool(cfg, "core.trustctime", 1)) + + if (!git_repository__cvar(&val, repo, GIT_CVAR_TRUSTCTIME) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME; + /* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */ - /* TODO: there are certain config settings where even if we were - * not given an options structure, we need the diff list to have one - * so that we can store the altered default values. - * - * - diff.ignoreSubmodules - * - diff.mnemonicprefix - * - diff.noprefix - */ + /* If not given explicit `opts`, check `diff.xyz` configs */ + if (!opts) { + diff->opts.context_lines = config_int(cfg, "diff.context", 3); - if (opts == NULL) { - /* Make sure we default to 3 lines */ - diff->opts.context_lines = 3; - return diff; + if (config_bool(cfg, "diff.ignoreSubmodules", 0)) + diff->opts.flags |= GIT_DIFF_IGNORE_SUBMODULES; } - memcpy(&diff->opts, opts, sizeof(git_diff_options)); - - if(opts->flags & GIT_DIFF_IGNORE_FILEMODE) - diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS; - - /* pathspec init will do nothing for empty pathspec */ - if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0) - goto fail; + /* if either prefix is not set, figure out appropriate value */ + if (!diff->opts.old_prefix || !diff->opts.new_prefix) { + const char *use_old = DIFF_OLD_PREFIX_DEFAULT; + const char *use_new = DIFF_NEW_PREFIX_DEFAULT; - /* TODO: handle config diff.mnemonicprefix, diff.noprefix */ + if (config_bool(cfg, "diff.noprefix", 0)) { + use_old = use_new = ""; + } else if (config_bool(cfg, "diff.mnemonicprefix", 0)) { + use_old = diff_mnemonic_prefix(diff->old_src, true); + use_new = diff_mnemonic_prefix(diff->new_src, false); + } - diff->opts.old_prefix = diff_strdup_prefix(&diff->pool, - opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT); - diff->opts.new_prefix = diff_strdup_prefix(&diff->pool, - opts->new_prefix ? opts->new_prefix : DIFF_NEW_PREFIX_DEFAULT); + if (!diff->opts.old_prefix) + diff->opts.old_prefix = use_old; + if (!diff->opts.new_prefix) + diff->opts.new_prefix = use_new; + } + /* strdup prefix from pool so we're not dependent on external data */ + diff->opts.old_prefix = diff_strdup_prefix(pool, diff->opts.old_prefix); + diff->opts.new_prefix = diff_strdup_prefix(pool, diff->opts.new_prefix); if (!diff->opts.old_prefix || !diff->opts.new_prefix) - goto fail; + return -1; if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) { const char *swap = diff->opts.old_prefix; @@ -335,15 +427,7 @@ static git_diff_list *git_diff_list_alloc( diff->opts.new_prefix = swap; } - /* INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ - if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)) - diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; - - return diff; - -fail: - git_diff_list_free(diff); - return NULL; + return 0; } static void diff_list_free(git_diff_list *diff) @@ -445,24 +529,30 @@ int git_diff__oid_for_file( return result; } +typedef struct { + git_repository *repo; + git_iterator *old_iter; + git_iterator *new_iter; + const git_index_entry *oitem; + const git_index_entry *nitem; + git_buf ignore_prefix; +} diff_in_progress; + #define MODE_BITS_MASK 0000777 static int maybe_modified( - git_iterator *old_iter, - const git_index_entry *oitem, - git_iterator *new_iter, - const git_index_entry *nitem, - git_diff_list *diff) + git_diff_list *diff, + diff_in_progress *info) { git_oid noid, *use_noid = NULL; git_delta_t status = GIT_DELTA_MODIFIED; + const git_index_entry *oitem = info->oitem; + const git_index_entry *nitem = info->nitem; unsigned int omode = oitem->mode; unsigned int nmode = nitem->mode; - bool new_is_workdir = (new_iter->type == GIT_ITERATOR_TYPE_WORKDIR); + bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR); const char *matched_pathspec; - GIT_UNUSED(old_iter); - if (!git_pathspec_match_path( &diff->pathspec, oitem->path, DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH), @@ -542,7 +632,11 @@ static int maybe_modified( unsigned int sm_status = 0; if (git_submodule_status(&sm_status, sub) < 0) return -1; - status = GIT_SUBMODULE_STATUS_IS_UNMODIFIED(sm_status) + + /* check IS_WD_UNMODIFIED because this case is only used + * when the new side of the diff is the working directory + */ + status = GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status) ? GIT_DELTA_UNMODIFIED : GIT_DELTA_MODIFIED; /* grab OID while we are here */ @@ -603,237 +697,312 @@ static bool entry_is_prefixed( item->path[pathlen] == '/'); } -static int diff_list_init_from_iterators( - git_diff_list *diff, - git_iterator *old_iter, - git_iterator *new_iter) +static int diff_scan_inside_untracked_dir( + git_diff_list *diff, diff_in_progress *info, git_delta_t *delta_type) { - diff->old_src = old_iter->type; - diff->new_src = new_iter->type; + int error = 0; + git_buf base = GIT_BUF_INIT; + bool is_ignored; - /* Use case-insensitive compare if either iterator has - * the ignore_case bit set */ - if (!git_iterator_ignore_case(old_iter) && - !git_iterator_ignore_case(new_iter)) - { - diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE; + *delta_type = GIT_DELTA_IGNORED; + git_buf_sets(&base, info->nitem->path); - diff->strcomp = git__strcmp; - diff->strncomp = git__strncmp; - diff->pfxcomp = git__prefixcmp; - diff->entrycomp = git_index_entry__cmp; - } else { - diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE; + /* advance into untracked directory */ + if ((error = git_iterator_advance_into(&info->nitem, info->new_iter)) < 0) { - diff->strcomp = git__strcasecmp; - diff->strncomp = git__strncasecmp; - diff->pfxcomp = git__prefixcmp_icase; - diff->entrycomp = git_index_entry__cmp_icase; + /* skip ahead if empty */ + if (error == GIT_ENOTFOUND) { + giterr_clear(); + error = git_iterator_advance(&info->nitem, info->new_iter); + } + + goto done; } - return 0; + /* look for actual untracked file */ + while (!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { + is_ignored = git_iterator_current_is_ignored(info->new_iter); + + /* need to recurse into non-ignored directories */ + if (!is_ignored && S_ISDIR(info->nitem->mode)) { + if ((error = git_iterator_advance_into( + &info->nitem, info->new_iter)) < 0) + break; + continue; + } + + /* found a non-ignored item - treat parent dir as untracked */ + if (!is_ignored) { + *delta_type = GIT_DELTA_UNTRACKED; + break; + } + + if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0) + break; + } + + /* finish off scan */ + while (!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { + if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0) + break; + } + +done: + git_buf_free(&base); + + return error; } -int git_diff__from_iterators( - git_diff_list **diff_ptr, - git_repository *repo, - git_iterator *old_iter, - git_iterator *new_iter, - const git_diff_options *opts) +static int handle_unmatched_new_item( + git_diff_list *diff, diff_in_progress *info) { int error = 0; - const git_index_entry *oitem, *nitem; - git_buf ignore_prefix = GIT_BUF_INIT; - git_diff_list *diff = git_diff_list_alloc(repo, opts); - - *diff_ptr = NULL; + const git_index_entry *nitem = info->nitem; + git_delta_t delta_type = GIT_DELTA_UNTRACKED; + bool contains_oitem; - if (!diff || diff_list_init_from_iterators(diff, old_iter, new_iter) < 0) - goto fail; + /* check if this is a prefix of the other side */ + contains_oitem = entry_is_prefixed(diff, info->oitem, nitem); - if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { - if (git_iterator_set_ignore_case(old_iter, true) < 0 || - git_iterator_set_ignore_case(new_iter, true) < 0) - goto fail; + /* check if this is contained in an ignored parent directory */ + if (git_buf_len(&info->ignore_prefix)) { + if (diff->pfxcomp(nitem->path, git_buf_cstr(&info->ignore_prefix)) == 0) + delta_type = GIT_DELTA_IGNORED; + else + git_buf_clear(&info->ignore_prefix); } - if (git_iterator_current(&oitem, old_iter) < 0 || - git_iterator_current(&nitem, new_iter) < 0) - goto fail; + if (S_ISDIR(nitem->mode)) { + bool recurse_into_dir = contains_oitem; - /* run iterators building diffs */ - while (oitem || nitem) { - int cmp = oitem ? (nitem ? diff->entrycomp(oitem, nitem) : -1) : 1; + /* if not already inside an ignored dir, check if this is ignored */ + if (delta_type != GIT_DELTA_IGNORED && + git_iterator_current_is_ignored(info->new_iter)) { + delta_type = GIT_DELTA_IGNORED; + git_buf_sets(&info->ignore_prefix, nitem->path); + } - /* create DELETED records for old items not matched in new */ - if (cmp < 0) { - if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0) - goto fail; + /* check if user requests recursion into this type of dir */ + recurse_into_dir = contains_oitem || + (delta_type == GIT_DELTA_UNTRACKED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) || + (delta_type == GIT_DELTA_IGNORED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); + + /* do not advance into directories that contain a .git file */ + if (recurse_into_dir) { + git_buf *full = NULL; + if (git_iterator_current_workdir_path(&full, info->new_iter) < 0) + return -1; + if (full && git_path_contains_dir(full, DOT_GIT)) + recurse_into_dir = false; + } - /* if we are generating TYPECHANGE records then check for that - * instead of just generating a DELETE record - */ - if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && - entry_is_prefixed(diff, nitem, oitem)) - { - /* this entry has become a tree! convert to TYPECHANGE */ - git_diff_delta *last = diff_delta__last_for_item(diff, oitem); - if (last) { - last->status = GIT_DELTA_TYPECHANGE; - last->new_file.mode = GIT_FILEMODE_TREE; - } + /* still have to look into untracked directories to match core git - + * with no untracked files, directory is treated as ignored + */ + if (!recurse_into_dir && + delta_type == GIT_DELTA_UNTRACKED && + DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_FAST_UNTRACKED_DIRS)) + { + git_diff_delta *last; + + /* attempt to insert record for this directory */ + if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) + return error; + + /* if delta wasn't created (because of rules), just skip ahead */ + last = diff_delta__last_for_item(diff, nitem); + if (!last) + return git_iterator_advance(&info->nitem, info->new_iter); + + /* iterate into dir looking for an actual untracked file */ + if (diff_scan_inside_untracked_dir(diff, info, &delta_type) < 0) + return -1; - /* If new_iter is a workdir iterator, then this situation - * will certainly be followed by a series of untracked items. - * Unless RECURSE_UNTRACKED_DIRS is set, skip over them... - */ - if (S_ISDIR(nitem->mode) && - DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) - { - if (git_iterator_advance(&nitem, new_iter) < 0) - goto fail; + /* it iteration changed delta type, the update the record */ + if (delta_type == GIT_DELTA_IGNORED) { + last->status = GIT_DELTA_IGNORED; + + /* remove the record if we don't want ignored records */ + if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_IGNORED)) { + git_vector_pop(&diff->deltas); + git__free(last); } } - if (git_iterator_advance(&oitem, old_iter) < 0) - goto fail; + return 0; } - /* create ADDED, TRACKED, or IGNORED records for new items not - * matched in old (and/or descend into directories as needed) + /* try to advance into directory if necessary */ + if (recurse_into_dir) { + error = git_iterator_advance_into(&info->nitem, info->new_iter); + + /* if real error or no error, proceed with iteration */ + if (error != GIT_ENOTFOUND) + return error; + giterr_clear(); + + /* if directory is empty, can't advance into it, so either skip + * it or ignore it + */ + if (contains_oitem) + return git_iterator_advance(&info->nitem, info->new_iter); + delta_type = GIT_DELTA_IGNORED; + } + } + + /* In core git, the next two checks are effectively reversed -- + * i.e. when an file contained in an ignored directory is explicitly + * ignored, it shows up as an ignored file in the diff list, even though + * other untracked files in the same directory are skipped completely. + * + * To me, this seems odd. If the directory is ignored and the file is + * untracked, we should skip it consistently, regardless of whether it + * happens to match a pattern in the ignore file. + * + * To match the core git behavior, reverse the following two if checks + * so that individual file ignores are checked before container + * directory exclusions are used to skip the file. + */ + else if (delta_type == GIT_DELTA_IGNORED && + DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) + /* item contained in ignored directory, so skip over it */ + return git_iterator_advance(&info->nitem, info->new_iter); + + else if (git_iterator_current_is_ignored(info->new_iter)) + delta_type = GIT_DELTA_IGNORED; + + else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) + delta_type = GIT_DELTA_ADDED; + + /* Actually create the record for this item if necessary */ + if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) + return error; + + /* If user requested TYPECHANGE records, then check for that instead of + * just generating an ADDED/UNTRACKED record + */ + if (delta_type != GIT_DELTA_IGNORED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && + contains_oitem) + { + /* this entry was prefixed with a tree - make TYPECHANGE */ + git_diff_delta *last = diff_delta__last_for_item(diff, nitem); + if (last) { + last->status = GIT_DELTA_TYPECHANGE; + last->old_file.mode = GIT_FILEMODE_TREE; + } + } + + return git_iterator_advance(&info->nitem, info->new_iter); +} + +static int handle_unmatched_old_item( + git_diff_list *diff, diff_in_progress *info) +{ + int error = diff_delta__from_one(diff, GIT_DELTA_DELETED, info->oitem); + if (error < 0) + return error; + + /* if we are generating TYPECHANGE records then check for that + * instead of just generating a DELETE record + */ + if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && + entry_is_prefixed(diff, info->nitem, info->oitem)) + { + /* this entry has become a tree! convert to TYPECHANGE */ + git_diff_delta *last = diff_delta__last_for_item(diff, info->oitem); + if (last) { + last->status = GIT_DELTA_TYPECHANGE; + last->new_file.mode = GIT_FILEMODE_TREE; + } + + /* If new_iter is a workdir iterator, then this situation + * will certainly be followed by a series of untracked items. + * Unless RECURSE_UNTRACKED_DIRS is set, skip over them... */ - else if (cmp > 0) { - git_delta_t delta_type = GIT_DELTA_UNTRACKED; - bool contains_oitem = entry_is_prefixed(diff, oitem, nitem); - - /* check if contained in ignored parent directory */ - if (git_buf_len(&ignore_prefix) && - diff->pfxcomp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0) - delta_type = GIT_DELTA_IGNORED; - - if (S_ISDIR(nitem->mode)) { - /* recurse into directory only if there are tracked items in - * it or if the user requested the contents of untracked - * directories and it is not under an ignored directory. - */ - bool recurse_into_dir = - (delta_type == GIT_DELTA_UNTRACKED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) || - (delta_type == GIT_DELTA_IGNORED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); - - /* do not advance into directories that contain a .git file */ - if (!contains_oitem && recurse_into_dir) { - git_buf *full = NULL; - if (git_iterator_current_workdir_path(&full, new_iter) < 0) - goto fail; - if (git_path_contains_dir(full, DOT_GIT)) - recurse_into_dir = false; - } + if (S_ISDIR(info->nitem->mode) && + DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) + return git_iterator_advance(&info->nitem, info->new_iter); + } - /* if directory is ignored, remember ignore_prefix */ - if ((contains_oitem || recurse_into_dir) && - delta_type == GIT_DELTA_UNTRACKED && - git_iterator_current_is_ignored(new_iter)) - { - git_buf_sets(&ignore_prefix, nitem->path); - delta_type = GIT_DELTA_IGNORED; - - /* skip recursion if we've just learned this is ignored */ - if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) - recurse_into_dir = false; - } + return git_iterator_advance(&info->oitem, info->old_iter); +} - if (contains_oitem || recurse_into_dir) { - /* advance into directory */ - error = git_iterator_advance_into(&nitem, new_iter); +static int handle_matched_item( + git_diff_list *diff, diff_in_progress *info) +{ + int error = 0; - /* if directory is empty, can't advance into it, so skip */ - if (error == GIT_ENOTFOUND) { - giterr_clear(); - error = git_iterator_advance(&nitem, new_iter); + if (!(error = maybe_modified(diff, info)) && + !(error = git_iterator_advance(&info->oitem, info->old_iter))) + error = git_iterator_advance(&info->nitem, info->new_iter); - git_buf_clear(&ignore_prefix); - } + return error; +} - if (error < 0) - goto fail; - continue; - } - } +int git_diff__from_iterators( + git_diff_list **diff_ptr, + git_repository *repo, + git_iterator *old_iter, + git_iterator *new_iter, + const git_diff_options *opts) +{ + int error = 0; + diff_in_progress info; + git_diff_list *diff; - /* In core git, the next two "else if" clauses are effectively - * reversed -- i.e. when an untracked file contained in an - * ignored directory is individually ignored, it shows up as an - * ignored file in the diff list, even though other untracked - * files in the same directory are skipped completely. - * - * To me, this is odd. If the directory is ignored and the file - * is untracked, we should skip it consistently, regardless of - * whether it happens to match a pattern in the ignore file. - * - * To match the core git behavior, just reverse the following - * two "else if" cases so that individual file ignores are - * checked before container directory exclusions are used to - * skip the file. - */ - else if (delta_type == GIT_DELTA_IGNORED && - DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) { - if (git_iterator_advance(&nitem, new_iter) < 0) - goto fail; - continue; /* ignored parent directory, so skip completely */ - } + *diff_ptr = NULL; - else if (git_iterator_current_is_ignored(new_iter)) - delta_type = GIT_DELTA_IGNORED; + diff = diff_list_alloc(repo, old_iter, new_iter); + GITERR_CHECK_ALLOC(diff); - else if (new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) - delta_type = GIT_DELTA_ADDED; + info.repo = repo; + info.old_iter = old_iter; + info.new_iter = new_iter; + git_buf_init(&info.ignore_prefix, 0); - if (diff_delta__from_one(diff, delta_type, nitem) < 0) - goto fail; + /* make iterators have matching icase behavior */ + if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { + if (!(error = git_iterator_set_ignore_case(old_iter, true))) + error = git_iterator_set_ignore_case(new_iter, true); + } - /* if we are generating TYPECHANGE records then check for that - * instead of just generating an ADDED/UNTRACKED record - */ - if (delta_type != GIT_DELTA_IGNORED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && - contains_oitem) - { - /* this entry was prefixed with a tree - make TYPECHANGE */ - git_diff_delta *last = diff_delta__last_for_item(diff, nitem); - if (last) { - last->status = GIT_DELTA_TYPECHANGE; - last->old_file.mode = GIT_FILEMODE_TREE; - } - } + /* finish initialization */ + if (!error && + !(error = diff_list_apply_options(diff, opts)) && + !(error = git_iterator_current(&info.oitem, old_iter))) + error = git_iterator_current(&info.nitem, new_iter); - if (git_iterator_advance(&nitem, new_iter) < 0) - goto fail; - } + /* run iterators building diffs */ + while (!error && (info.oitem || info.nitem)) { + int cmp = info.oitem ? + (info.nitem ? diff->entrycomp(info.oitem, info.nitem) : -1) : 1; + + /* create DELETED records for old items not matched in new */ + if (cmp < 0) + error = handle_unmatched_old_item(diff, &info); + + /* create ADDED, TRACKED, or IGNORED records for new items not + * matched in old (and/or descend into directories as needed) + */ + else if (cmp > 0) + error = handle_unmatched_new_item(diff, &info); /* otherwise item paths match, so create MODIFIED record * (or ADDED and DELETED pair if type changed) */ - else { - assert(oitem && nitem && cmp == 0); - - if (maybe_modified(old_iter, oitem, new_iter, nitem, diff) < 0 || - git_iterator_advance(&oitem, old_iter) < 0 || - git_iterator_advance(&nitem, new_iter) < 0) - goto fail; - } + else + error = handle_matched_item(diff, &info); } - *diff_ptr = diff; - -fail: - if (!*diff_ptr) { + if (!error) + *diff_ptr = diff; + else git_diff_list_free(diff); - error = -1; - } - git_buf_free(&ignore_prefix); + git_buf_free(&info.ignore_prefix); return error; } @@ -855,12 +1024,20 @@ int git_diff_tree_to_tree( const git_diff_options *opts) { int error = 0; + git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE; assert(diff && repo); + /* for tree to tree diff, be case sensitive even if the index is + * currently case insensitive, unless the user explicitly asked + * for case insensitivity + */ + if (opts && (opts->flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0) + iflag = GIT_ITERATOR_IGNORE_CASE; + DIFF_FROM_ITERATORS( - git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), - git_iterator_for_tree(&b, new_tree, 0, pfx, pfx) + git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx), + git_iterator_for_tree(&b, new_tree, iflag, pfx, pfx) ); return error; diff --git a/src/diff.h b/src/diff.h index 8e3cbcd4611..48e20d1e38b 100644 --- a/src/diff.h +++ b/src/diff.h @@ -74,5 +74,17 @@ extern int git_diff__from_iterators( git_iterator *new_iter, const git_diff_options *opts); +int git_diff_find_similar__hashsig_for_file( + void **out, const git_diff_file *f, const char *path, void *p); + +int git_diff_find_similar__hashsig_for_buf( + void **out, const git_diff_file *f, const char *buf, size_t len, void *p); + +void git_diff_find_similar__hashsig_free(void *sig, void *payload); + +int git_diff_find_similar__calc_similarity( + int *score, void *siga, void *sigb, void *payload); + + #endif diff --git a/src/diff_output.c b/src/diff_output.c index e8dd5b3172e..64ff6b5be27 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -101,8 +101,8 @@ static bool diff_delta_is_binary_forced( /* make sure files are conceivably mmap-able */ if ((git_off_t)((size_t)delta->old_file.size) != delta->old_file.size || - (git_off_t)((size_t)delta->new_file.size) != delta->new_file.size) - { + (git_off_t)((size_t)delta->new_file.size) != delta->new_file.size) { + delta->old_file.flags |= GIT_DIFF_FLAG_BINARY; delta->new_file.flags |= GIT_DIFF_FLAG_BINARY; delta->flags |= GIT_DIFF_FLAG_BINARY; @@ -232,8 +232,7 @@ static int get_blob_content( if (git_oid_iszero(&file->oid)) return 0; - if (file->mode == GIT_FILEMODE_COMMIT) - { + if (file->mode == GIT_FILEMODE_COMMIT) { char oidstr[GIT_OID_HEXSZ+1]; git_buf content = GIT_BUF_INIT; @@ -299,8 +298,8 @@ static int get_workdir_sm_content( char oidstr[GIT_OID_HEXSZ+1]; if ((error = git_submodule_lookup(&sm, ctxt->repo, file->path)) < 0 || - (error = git_submodule_status(&sm_status, sm)) < 0) - { + (error = git_submodule_status(&sm_status, sm)) < 0) { + /* GIT_EEXISTS means a "submodule" that has not been git added */ if (error == GIT_EEXISTS) error = 0; @@ -312,8 +311,8 @@ static int get_workdir_sm_content( const git_oid* sm_head; if ((sm_head = git_submodule_wd_id(sm)) != NULL || - (sm_head = git_submodule_head_id(sm)) != NULL) - { + (sm_head = git_submodule_head_id(sm)) != NULL) { + git_oid_cpy(&file->oid, sm_head); file->flags |= GIT_DIFF_FLAG_VALID_OID; } @@ -660,8 +659,8 @@ static int diff_patch_load( */ if (check_if_unmodified && delta->old_file.mode == delta->new_file.mode && - !git_oid_cmp(&delta->old_file.oid, &delta->new_file.oid)) - { + !git_oid__cmp(&delta->old_file.oid, &delta->new_file.oid)) { + delta->status = GIT_DELTA_UNMODIFIED; if ((ctxt->opts->flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0) @@ -675,10 +674,14 @@ static int diff_patch_load( if (!error) { patch->flags |= GIT_DIFF_PATCH_LOADED; + /* patch is diffable only for non-binary, modified files where at + * least one side has data and there is actual change in the data + */ if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0 && delta->status != GIT_DELTA_UNMODIFIED && (patch->old_data.len || patch->new_data.len) && - !git_oid_equal(&delta->old_file.oid, &delta->new_file.oid)) + (patch->old_data.len != patch->new_data.len || + !git_oid_equal(&delta->old_file.oid, &delta->new_file.oid))) patch->flags |= GIT_DIFF_PATCH_DIFFABLE; } @@ -1045,6 +1048,12 @@ char git_diff_status_char(git_delta_t status) return code; } +static int callback_error(void) +{ + giterr_clear(); + return GIT_EUSER; +} + static int print_compact( const git_diff_delta *delta, float progress, void *data) { @@ -1079,10 +1088,7 @@ static int print_compact( if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } @@ -1110,11 +1116,20 @@ int git_diff_print_compact( static int print_oid_range(diff_print_info *pi, const git_diff_delta *delta) { - char start_oid[8], end_oid[8]; + int abbrevlen; + char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; + + if (git_repository__cvar(&abbrevlen, pi->diff->repo, GIT_CVAR_ABBREV) < 0) + return -1; + + abbrevlen += 1; /* for NUL byte */ + if (abbrevlen < 2) + abbrevlen = 2; + else if (abbrevlen > (int)sizeof(start_oid)) + abbrevlen = (int)sizeof(start_oid); - /* TODO: Determine a good actual OID range to print */ - git_oid_tostr(start_oid, sizeof(start_oid), &delta->old_file.oid); - git_oid_tostr(end_oid, sizeof(end_oid), &delta->new_file.oid); + git_oid_tostr(start_oid, abbrevlen, &delta->old_file.oid); + git_oid_tostr(end_oid, abbrevlen, &delta->new_file.oid); /* TODO: Match git diff more closely */ if (delta->old_file.mode == delta->new_file.mode) { @@ -1149,7 +1164,11 @@ static int print_patch_file( GIT_UNUSED(progress); - if (S_ISDIR(delta->new_file.mode)) + if (S_ISDIR(delta->new_file.mode) || + delta->status == GIT_DELTA_UNMODIFIED || + delta->status == GIT_DELTA_IGNORED || + (delta->status == GIT_DELTA_UNTRACKED && + (pi->diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)) return 0; if (!oldpfx) @@ -1183,10 +1202,7 @@ static int print_patch_file( if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) return 0; @@ -1200,10 +1216,7 @@ static int print_patch_file( if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_BINARY, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } @@ -1226,10 +1239,7 @@ static int print_patch_hunk( if (pi->print_cb(d, r, GIT_DIFF_LINE_HUNK_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } @@ -1261,10 +1271,7 @@ static int print_patch_line( if (pi->print_cb(delta, range, line_origin, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } @@ -1371,7 +1378,7 @@ static int diff_single_apply(diff_single_data *data) (has_old ? GIT_DELTA_MODIFIED : GIT_DELTA_ADDED) : (has_old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED); - if (git_oid_cmp(&delta->new_file.oid, &delta->old_file.oid) == 0) + if (git_oid__cmp(&delta->new_file.oid, &delta->old_file.oid) == 0) delta->status = GIT_DELTA_UNMODIFIED; if ((error = diff_delta_is_binary_by_content( diff --git a/src/diff_tform.c b/src/diff_tform.c index efcb19d9551..201a0e8967b 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -170,7 +170,7 @@ int git_diff_merge( return error; } -static int find_similar__hashsig_for_file( +int git_diff_find_similar__hashsig_for_file( void **out, const git_diff_file *f, const char *path, void *p) { git_hashsig_option_t opt = (git_hashsig_option_t)p; @@ -187,12 +187,12 @@ static int find_similar__hashsig_for_file( return error; } -static int find_similar__hashsig_for_buf( +int git_diff_find_similar__hashsig_for_buf( void **out, const git_diff_file *f, const char *buf, size_t len, void *p) { git_hashsig_option_t opt = (git_hashsig_option_t)p; int error = 0; - + GIT_UNUSED(f); error = git_hashsig_create((git_hashsig **)out, buf, len, opt); @@ -204,13 +204,13 @@ static int find_similar__hashsig_for_buf( return error; } -static void find_similar__hashsig_free(void *sig, void *payload) +void git_diff_find_similar__hashsig_free(void *sig, void *payload) { GIT_UNUSED(payload); git_hashsig_free(sig); } -static int find_similar__calc_similarity( +int git_diff_find_similar__calc_similarity( int *score, void *siga, void *sigb, void *payload) { GIT_UNUSED(payload); @@ -291,10 +291,10 @@ static int normalize_find_opts( opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); GITERR_CHECK_ALLOC(opts->metric); - opts->metric->file_signature = find_similar__hashsig_for_file; - opts->metric->buffer_signature = find_similar__hashsig_for_buf; - opts->metric->free_signature = find_similar__hashsig_free; - opts->metric->similarity = find_similar__calc_similarity; + opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; + opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; + opts->metric->free_signature = git_diff_find_similar__hashsig_free; + opts->metric->similarity = git_diff_find_similar__calc_similarity; if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE) opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE; @@ -429,7 +429,7 @@ static int similarity_measure( if (GIT_MODE_TYPE(a_file->mode) != GIT_MODE_TYPE(b_file->mode)) return 0; - if (git_oid_cmp(&a_file->oid, &b_file->oid) == 0) + if (git_oid__cmp(&a_file->oid, &b_file->oid) == 0) return 100; /* update signature cache if needed */ diff --git a/src/fetch.c b/src/fetch.c index b60a95232ef..8ae34bddf7b 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -34,7 +34,7 @@ static int filter_ref__cb(git_remote_head *head, void *payload) if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) p->found_head = 1; - else if (git_refspec_src_matches(p->spec, head->name)) + else if (git_remote__matching_refspec(p->remote, head->name)) match = 1; else if (p->remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL && git_refspec_src_matches(p->tagspec, head->name)) @@ -68,7 +68,6 @@ static int filter_wants(git_remote *remote) * not interested in any particular branch but just the remote's * HEAD, which will be stored in FETCH_HEAD after the fetch. */ - p.spec = git_remote_fetchspec(remote); p.tagspec = &tagspec; p.found_head = 0; p.remote = remote; diff --git a/src/global.c b/src/global.c index b7fd8e257e2..a0571d1270e 100644 --- a/src/global.c +++ b/src/global.c @@ -135,6 +135,12 @@ int git_threads_init(void) void git_threads_shutdown(void) { + if (_tls_init) { + void *ptr = pthread_getspecific(_tls_key); + pthread_setspecific(_tls_key, NULL); + git__free(ptr); + } + pthread_key_delete(_tls_key); _tls_init = 0; git_mutex_free(&git__mwindow_mutex); diff --git a/src/global.h b/src/global.h index f0ad1df29d7..badbc0883ce 100644 --- a/src/global.h +++ b/src/global.h @@ -10,14 +10,6 @@ #include "mwindow.h" #include "hash.h" -#if defined(GIT_THREADS) && defined(_MSC_VER) -# define GIT_MEMORY_BARRIER MemoryBarrier() -#elif defined(GIT_THREADS) -# define GIT_MEMORY_BARRIER __sync_synchronize() -#else -# define GIT_MEMORY_BARRIER /* noop */ -#endif - typedef struct { git_error *last_error; git_error error_t; diff --git a/src/ignore.c b/src/ignore.c index 17779522c48..e150b958512 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -15,24 +15,14 @@ static int parse_ignore_file( git_attr_fnmatch *match = NULL; const char *scan = NULL; char *context = NULL; - bool ignore_case = false; - git_config *cfg = NULL; - int val; - - /* Prefer to have the caller pass in a git_ignores as the parsedata object. - * If they did not, then we can (much more slowly) find the value of - * ignore_case by using the repository object. */ - if (parsedata != NULL) { - ignore_case = ((git_ignores *)parsedata)->ignore_case; - } else { - if ((error = git_repository_config(&cfg, repo)) < 0) - return error; - - if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0) - ignore_case = (val != 0); + int ignore_case = false; - git_config_free(cfg); - } + /* Prefer to have the caller pass in a git_ignores as the parsedata + * object. If they did not, then look up the value of ignore_case */ + if (parsedata != NULL) + ignore_case = ((git_ignores *)parsedata)->ignore_case; + else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0) + return error; if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) { context = ignores->key + 2; @@ -109,8 +99,6 @@ int git_ignore__for_path( { int error = 0; const char *workdir = git_repository_workdir(repo); - git_config *cfg = NULL; - int val; assert(ignores); @@ -118,17 +106,11 @@ int git_ignore__for_path( git_buf_init(&ignores->dir, 0); ignores->ign_internal = NULL; - /* Set the ignore_case flag appropriately */ - if ((error = git_repository_config(&cfg, repo)) < 0) + /* Read the ignore_case flag */ + if ((error = git_repository__cvar( + &ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0) goto cleanup; - if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0) - ignores->ignore_case = (val != 0); - else - ignores->ignore_case = 0; - - git_config_free(cfg); - if ((error = git_vector_init(&ignores->ign_path, 8, NULL)) < 0 || (error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 || (error = git_attr_cache__init(repo)) < 0) diff --git a/src/ignore.h b/src/ignore.h index 5af8e8e7d18..e00e4a8c862 100644 --- a/src/ignore.h +++ b/src/ignore.h @@ -28,7 +28,7 @@ typedef struct { git_attr_file *ign_internal; git_vector ign_path; git_vector ign_global; - unsigned int ignore_case:1; + int ignore_case; } git_ignores; extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign); diff --git a/src/index.c b/src/index.c index 6290ec4e8e3..ee659f8ab73 100644 --- a/src/index.c +++ b/src/index.c @@ -19,6 +19,7 @@ #include "git2/oid.h" #include "git2/blob.h" #include "git2/config.h" +#include "git2/sys/index.h" #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) #define short_entry_size(len) entry_size(struct entry_short, len) @@ -35,6 +36,7 @@ static const unsigned int INDEX_VERSION_NUMBER_EXT = 3; static const unsigned int INDEX_HEADER_SIG = 0x44495243; static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'}; +static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'}; #define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx))) @@ -187,6 +189,51 @@ static int index_icmp(const void *a, const void *b) return diff; } +static int conflict_name_cmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcmp(name_a->ours, name_b->ours); +} + +/** + * TODO: enable this when resolving case insensitive conflicts + */ +#if 0 +static int conflict_name_icmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcasecmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcasecmp(name_a->ours, name_b->ours); +} +#endif + static int reuc_srch(const void *key, const void *array_member) { const git_index_reuc_entry *reuc = array_member; @@ -278,6 +325,7 @@ int git_index_open(git_index **index_out, const char *index_path) } if (git_vector_init(&index->entries, 32, index_cmp) < 0 || + git_vector_init(&index->names, 32, conflict_name_cmp) < 0 || git_vector_init(&index->reuc, 32, reuc_cmp) < 0) return -1; @@ -301,6 +349,7 @@ static void index_free(git_index *index) { git_index_clear(index); git_vector_free(&index->entries); + git_vector_free(&index->names); git_vector_free(&index->reuc); git__free(index->index_file_path); @@ -330,6 +379,8 @@ void git_index_clear(git_index *index) git_vector_clear(&index->entries); git_index_reuc_clear(index); + + git_index_name_clear(index); git_futils_filestamp_set(&index->stamp, NULL); @@ -352,19 +403,18 @@ int git_index_set_caps(git_index *index, unsigned int caps) old_ignore_case = index->ignore_case; if (caps == GIT_INDEXCAP_FROM_OWNER) { - git_config *cfg; + git_repository *repo = INDEX_OWNER(index); int val; - if (INDEX_OWNER(index) == NULL || - git_repository_config__weakptr(&cfg, INDEX_OWNER(index)) < 0) - return create_index_error(-1, - "Cannot get repository config to set index caps"); + if (!repo) + return create_index_error( + -1, "Cannot access repository to set index caps"); - if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0) + if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE)) index->ignore_case = (val != 0); - if (git_config_get_bool(&val, cfg, "core.filemode") == 0) + if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE)) index->distrust_filemode = (val == 0); - if (git_config_get_bool(&val, cfg, "core.symlinks") == 0) + if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS)) index->no_symlinks = (val == 0); } else { @@ -586,8 +636,9 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const static int index_entry_reuc_init(git_index_reuc_entry **reuc_out, const char *path, - int ancestor_mode, git_oid *ancestor_oid, - int our_mode, git_oid *our_oid, int their_mode, git_oid *their_oid) + int ancestor_mode, const git_oid *ancestor_oid, + int our_mode, const git_oid *our_oid, + int their_mode, const git_oid *their_oid) { git_index_reuc_entry *reuc = NULL; @@ -693,7 +744,7 @@ static int index_conflict_to_reuc(git_index *index, const char *path) { git_index_entry *conflict_entries[3]; int ancestor_mode, our_mode, their_mode; - git_oid *ancestor_oid, *our_oid, *their_oid; + git_oid const *ancestor_oid, *our_oid, *their_oid; int ret; if ((ret = git_index_conflict_get(&conflict_entries[0], @@ -947,7 +998,6 @@ int git_index_conflict_get(git_index_entry **ancestor_out, return GIT_ENOTFOUND; for (posmax = git_index_entrycount(index); pos < posmax; ++pos) { - conflict_entry = git_vector_get(&index->entries, pos); if (index->entries_cmp_path(conflict_entry->path, path) != 0) @@ -1043,13 +1093,82 @@ int git_index_has_conflicts(const git_index *index) return 0; } +unsigned int git_index_name_entrycount(git_index *index) +{ + assert(index); + return (unsigned int)index->names.length; +} + +const git_index_name_entry *git_index_name_get_byindex( + git_index *index, size_t n) +{ + assert(index); + + git_vector_sort(&index->names); + return git_vector_get(&index->names, n); +} + +int git_index_name_add(git_index *index, + const char *ancestor, const char *ours, const char *theirs) +{ + git_index_name_entry *conflict_name; + + assert ((ancestor && ours) || (ancestor && theirs) || (ours && theirs)); + + conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GITERR_CHECK_ALLOC(conflict_name); + + if (ancestor) { + conflict_name->ancestor = git__strdup(ancestor); + GITERR_CHECK_ALLOC(conflict_name->ancestor); + } + + if (ours) { + conflict_name->ours = git__strdup(ours); + GITERR_CHECK_ALLOC(conflict_name->ours); + } + + if (theirs) { + conflict_name->theirs = git__strdup(theirs); + GITERR_CHECK_ALLOC(conflict_name->theirs); + } + + return git_vector_insert(&index->names, conflict_name); +} + +void git_index_name_clear(git_index *index) +{ + size_t i; + git_index_name_entry *conflict_name; + + assert(index); + + git_vector_foreach(&index->names, i, conflict_name) { + if (conflict_name->ancestor) + git__free(conflict_name->ancestor); + + if (conflict_name->ours) + git__free(conflict_name->ours); + + if (conflict_name->theirs) + git__free(conflict_name->theirs); + + git__free(conflict_name); + } + + git_vector_clear(&index->names); +} + unsigned int git_index_reuc_entrycount(git_index *index) { assert(index); return (unsigned int)index->reuc.length; } -static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int replace) +static int index_reuc_insert( + git_index *index, + git_index_reuc_entry *reuc, + int replace) { git_index_reuc_entry **existing = NULL; size_t position; @@ -1071,9 +1190,9 @@ static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int r } int git_index_reuc_add(git_index *index, const char *path, - int ancestor_mode, git_oid *ancestor_oid, - int our_mode, git_oid *our_oid, - int their_mode, git_oid *their_oid) + int ancestor_mode, const git_oid *ancestor_oid, + int our_mode, const git_oid *our_oid, + int their_mode, const git_oid *their_oid) { git_index_reuc_entry *reuc = NULL; int error = 0; @@ -1226,6 +1345,52 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) return 0; } + +static int read_conflict_names(git_index *index, const char *buffer, size_t size) +{ + size_t len; + + /* This gets called multiple times, the vector might already be initialized */ + if (index->names._alloc_size == 0 && + git_vector_init(&index->names, 16, conflict_name_cmp) < 0) + return -1; + +#define read_conflict_name(ptr) \ + len = strlen(buffer) + 1; \ + if (size < len) \ + return index_error_invalid("reading conflict name entries"); \ + \ + if (len == 1) \ + ptr = NULL; \ + else { \ + ptr = git__malloc(len); \ + GITERR_CHECK_ALLOC(ptr); \ + memcpy(ptr, buffer, len); \ + } \ + \ + buffer += len; \ + size -= len; + + while (size) { + git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GITERR_CHECK_ALLOC(conflict_name); + + read_conflict_name(conflict_name->ancestor); + read_conflict_name(conflict_name->ours); + read_conflict_name(conflict_name->theirs); + + if (git_vector_insert(&index->names, conflict_name) < 0) + return -1; + } + +#undef read_conflict_name + + /* entries are guaranteed to be sorted on-disk */ + index->names.sorted = 1; + + return 0; +} + static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size) { size_t path_length, entry_size; @@ -1330,6 +1495,9 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { if (read_reuc(index, buffer + 8, dest.extension_size) < 0) return 0; + } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) { + if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0) + return 0; } /* else, unsupported extension. We cannot parse this, but we can skip * it by returning `total_size */ @@ -1345,7 +1513,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer static int parse_index(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; - struct index_header header; + struct index_header header = { 0 }; git_oid checksum_calculated, checksum_expected; #define seek_forward(_increase) { \ @@ -1412,7 +1580,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) /* 160-bit SHA-1 over the content of the index file before this checksum. */ git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer); - if (git_oid_cmp(&checksum_calculated, &checksum_expected) != 0) + if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) return index_error_invalid("calculated checksum does not match expected"); #undef seek_forward @@ -1543,6 +1711,61 @@ static int write_extension(git_filebuf *file, struct index_extension *header, gi return error; } +static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name) +{ + int error = 0; + + if (conflict_name->ancestor == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->ours == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->theirs == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1); + +on_error: + return error; +} + +static int write_name_extension(git_index *index, git_filebuf *file) +{ + git_buf name_buf = GIT_BUF_INIT; + git_vector *out = &index->names; + git_index_name_entry *conflict_name; + struct index_extension extension; + size_t i; + int error = 0; + + git_vector_foreach(out, i, conflict_name) { + if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0) + goto done; + } + + memset(&extension, 0x0, sizeof(struct index_extension)); + memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4); + extension.extension_size = (uint32_t)name_buf.size; + + error = write_extension(file, &extension, &name_buf); + + git_buf_free(&name_buf); + +done: + return error; +} + static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc) { int i; @@ -1613,6 +1836,10 @@ static int write_index(git_index *index, git_filebuf *file) /* TODO: write tree cache extension */ + /* write the rename conflict extension */ + if (index->names.length > 0 && write_name_extension(index, file) < 0) + return -1; + /* write the reuc extension */ if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0) return -1; diff --git a/src/index.h b/src/index.h index 9498907b683..2ad401741b4 100644 --- a/src/index.h +++ b/src/index.h @@ -33,6 +33,7 @@ struct git_index { git_tree_cache *tree; + git_vector names; git_vector reuc; git_vector_cmp entries_cmp_path; diff --git a/src/indexer.c b/src/indexer.c index 2cfbd3a5a35..91b7ba5d980 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -9,7 +9,6 @@ #include "git2/indexer.h" #include "git2/object.h" -#include "git2/oid.h" #include "common.h" #include "pack.h" @@ -17,6 +16,7 @@ #include "posix.h" #include "pack.h" #include "filebuf.h" +#include "oid.h" #include "oidmap.h" #define UINT31_MAX (0x7FFFFFFF) @@ -60,36 +60,19 @@ const git_oid *git_indexer_stream_hash(const git_indexer_stream *idx) static int open_pack(struct git_pack_file **out, const char *filename) { - size_t namelen; struct git_pack_file *pack; - struct stat st; - int fd; - namelen = strlen(filename); - pack = git__calloc(1, sizeof(struct git_pack_file) + namelen + 1); - GITERR_CHECK_ALLOC(pack); - - memcpy(pack->pack_name, filename, namelen + 1); - - if (p_stat(filename, &st) < 0) { - giterr_set(GITERR_OS, "Failed to stat packfile."); - goto cleanup; - } + if (git_packfile_alloc(&pack, filename) < 0) + return -1; - if ((fd = p_open(pack->pack_name, O_RDONLY)) < 0) { + if ((pack->mwf.fd = p_open(pack->pack_name, O_RDONLY)) < 0) { giterr_set(GITERR_OS, "Failed to open packfile."); - goto cleanup; + git_packfile_free(pack); + return -1; } - pack->mwf.fd = fd; - pack->mwf.size = (git_off_t)st.st_size; - *out = pack; return 0; - -cleanup: - git__free(pack); - return -1; } static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack) @@ -120,7 +103,7 @@ static int objects_cmp(const void *a, const void *b) const struct entry *entrya = a; const struct entry *entryb = b; - return git_oid_cmp(&entrya->oid, &entryb->oid); + return git_oid__cmp(&entrya->oid, &entryb->oid); } int git_indexer_stream_new( @@ -391,7 +374,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz { int error = -1; struct git_pack_header hdr; - size_t processed; + size_t processed; git_mwindow_file *mwf = &idx->pack->mwf; assert(idx && data && stats); @@ -404,7 +387,6 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz /* Make sure we set the new size of the pack */ if (idx->opened_pack) { idx->pack->mwf.size += size; - //printf("\nadding %zu for %zu\n", size, idx->pack->mwf.size); } else { if (open_pack(&idx->pack, idx->pack_file.path_lock) < 0) return -1; diff --git a/src/iterator.c b/src/iterator.c index 805a3c987ac..ff08c1ce005 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -26,8 +26,6 @@ (GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE) #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC,REPO) do { \ - (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \ - GITERR_CHECK_ALLOC(P); \ (P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \ (P)->base.cb = &(P)->cb; \ ITERATOR_SET_CB(P,NAME_LC); \ @@ -148,7 +146,8 @@ int git_iterator_for_nothing( const char *start, const char *end) { - empty_iterator *i; + empty_iterator *i = git__calloc(1, sizeof(empty_iterator)); + GITERR_CHECK_ALLOC(i); #define empty_iterator__current empty_iterator__noop #define empty_iterator__advance empty_iterator__noop @@ -578,9 +577,12 @@ int git_iterator_for_tree( if (tree == NULL) return git_iterator_for_nothing(iter, flags, start, end); - if ((error = git_tree__dup(&tree, tree)) < 0) + if ((error = git_object_dup((git_object **)&tree, (git_object *)tree)) < 0) return error; + ti = git__calloc(1, sizeof(tree_iterator)); + GITERR_CHECK_ALLOC(ti); + ITERATOR_BASE_INIT(ti, tree, TREE, git_tree_owner(tree)); if ((error = iterator__update_ignore_case((git_iterator *)ti, flags)) < 0) @@ -810,7 +812,8 @@ int git_iterator_for_index( const char *start, const char *end) { - index_iterator *ii; + index_iterator *ii = git__calloc(1, sizeof(index_iterator)); + GITERR_CHECK_ALLOC(ii); ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index)); @@ -833,237 +836,221 @@ int git_iterator_for_index( } -#define WORKDIR_MAX_DEPTH 100 - -typedef struct workdir_iterator_frame workdir_iterator_frame; -struct workdir_iterator_frame { - workdir_iterator_frame *next; +typedef struct fs_iterator_frame fs_iterator_frame; +struct fs_iterator_frame { + fs_iterator_frame *next; git_vector entries; size_t index; }; -typedef struct { +typedef struct fs_iterator fs_iterator; +struct fs_iterator { git_iterator base; git_iterator_callbacks cb; - workdir_iterator_frame *stack; - git_ignores ignores; + fs_iterator_frame *stack; git_index_entry entry; git_buf path; size_t root_len; - int is_ignored; int depth; -} workdir_iterator; -GIT_INLINE(bool) path_is_dotgit(const git_path_with_stat *ps) -{ - if (!ps) - return false; - else { - const char *path = ps->path; - size_t len = ps->path_len; - - if (len < 4) - return false; - if (path[len - 1] == '/') - len--; - if (tolower(path[len - 1]) != 't' || - tolower(path[len - 2]) != 'i' || - tolower(path[len - 3]) != 'g' || - tolower(path[len - 4]) != '.') - return false; - return (len == 4 || path[len - 5] == '/'); - } -} + int (*enter_dir_cb)(fs_iterator *self); + int (*leave_dir_cb)(fs_iterator *self); + int (*update_entry_cb)(fs_iterator *self); +}; -static workdir_iterator_frame *workdir_iterator__alloc_frame( - workdir_iterator *wi) +#define FS_MAX_DEPTH 100 + +static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) { - workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame)); + fs_iterator_frame *ff = git__calloc(1, sizeof(fs_iterator_frame)); git_vector_cmp entry_compare = CASESELECT( - iterator__ignore_case(wi), + iterator__ignore_case(fi), git_path_with_stat_cmp_icase, git_path_with_stat_cmp); - if (wf == NULL) - return NULL; - - if (git_vector_init(&wf->entries, 0, entry_compare) != 0) { - git__free(wf); - return NULL; + if (ff && git_vector_init(&ff->entries, 0, entry_compare) < 0) { + git__free(ff); + ff = NULL; } - return wf; + return ff; } -static void workdir_iterator__free_frame(workdir_iterator_frame *wf) +static void fs_iterator__free_frame(fs_iterator_frame *ff) { - unsigned int i; + size_t i; git_path_with_stat *path; - git_vector_foreach(&wf->entries, i, path) + git_vector_foreach(&ff->entries, i, path) git__free(path); - git_vector_free(&wf->entries); - git__free(wf); + git_vector_free(&ff->entries); + git__free(ff); +} + +static void fs_iterator__pop_frame( + fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) +{ + if (fi && fi->stack == ff) { + if (!ff->next && !pop_last) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return; + } + + if (fi->leave_dir_cb) + (void)fi->leave_dir_cb(fi); + + fi->stack = ff->next; + fi->depth--; + } + + fs_iterator__free_frame(ff); } -static int workdir_iterator__update_entry(workdir_iterator *wi); +static int fs_iterator__update_entry(fs_iterator *fi); -static int workdir_iterator__entry_cmp(const void *i, const void *item) +static int fs_iterator__entry_cmp(const void *i, const void *item) { - const workdir_iterator *wi = (const workdir_iterator *)i; + const fs_iterator *fi = (const fs_iterator *)i; const git_path_with_stat *ps = item; - return wi->base.prefixcomp(wi->base.start, ps->path); + return fi->base.prefixcomp(fi->base.start, ps->path); } -static void workdir_iterator__seek_frame_start( - workdir_iterator *wi, workdir_iterator_frame *wf) +static void fs_iterator__seek_frame_start( + fs_iterator *fi, fs_iterator_frame *ff) { - if (!wf) + if (!ff) return; - if (wi->base.start) + if (fi->base.start) git_vector_bsearch2( - &wf->index, &wf->entries, workdir_iterator__entry_cmp, wi); + &ff->index, &ff->entries, fs_iterator__entry_cmp, fi); else - wf->index = 0; - - if (path_is_dotgit(git_vector_get(&wf->entries, wf->index))) - wf->index++; + ff->index = 0; } -static int workdir_iterator__expand_dir(workdir_iterator *wi) +static int fs_iterator__expand_dir(fs_iterator *fi) { int error; - workdir_iterator_frame *wf; + fs_iterator_frame *ff; + + if (fi->depth > FS_MAX_DEPTH) { + giterr_set(GITERR_REPOSITORY, + "Directory nesting is too deep (%d)", fi->depth); + return -1; + } - wf = workdir_iterator__alloc_frame(wi); - GITERR_CHECK_ALLOC(wf); + ff = fs_iterator__alloc_frame(fi); + GITERR_CHECK_ALLOC(ff); error = git_path_dirload_with_stat( - wi->path.ptr, wi->root_len, iterator__ignore_case(wi), - wi->base.start, wi->base.end, &wf->entries); + fi->path.ptr, fi->root_len, iterator__ignore_case(fi), + fi->base.start, fi->base.end, &ff->entries); - if (error < 0 || wf->entries.length == 0) { - workdir_iterator__free_frame(wf); + if (error < 0 || ff->entries.length == 0) { + fs_iterator__free_frame(ff); return GIT_ENOTFOUND; } - if (++(wi->depth) > WORKDIR_MAX_DEPTH) { - giterr_set(GITERR_REPOSITORY, - "Working directory is too deep (%d)", wi->depth); - workdir_iterator__free_frame(wf); - return -1; - } - - workdir_iterator__seek_frame_start(wi, wf); + fs_iterator__seek_frame_start(fi, ff); - /* only push new ignores if this is not top level directory */ - if (wi->stack != NULL) { - ssize_t slash_pos = git_buf_rfind_next(&wi->path, '/'); - (void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]); - } + ff->next = fi->stack; + fi->stack = ff; + fi->depth++; - wf->next = wi->stack; - wi->stack = wf; + if (fi->enter_dir_cb && (error = fi->enter_dir_cb(fi)) < 0) + return error; - return workdir_iterator__update_entry(wi); + return fs_iterator__update_entry(fi); } -static int workdir_iterator__current( +static int fs_iterator__current( const git_index_entry **entry, git_iterator *self) { - workdir_iterator *wi = (workdir_iterator *)self; + fs_iterator *fi = (fs_iterator *)self; if (entry) - *entry = (wi->entry.path == NULL) ? NULL : &wi->entry; + *entry = (fi->entry.path == NULL) ? NULL : &fi->entry; return 0; } -static int workdir_iterator__at_end(git_iterator *self) +static int fs_iterator__at_end(git_iterator *self) { - return (((workdir_iterator *)self)->entry.path == NULL); + return (((fs_iterator *)self)->entry.path == NULL); } -static int workdir_iterator__advance_into( +static int fs_iterator__advance_into( const git_index_entry **entry, git_iterator *iter) { int error = 0; - workdir_iterator *wi = (workdir_iterator *)iter; + fs_iterator *fi = (fs_iterator *)iter; iterator__clear_entry(entry); - /* workdir iterator will allow you to explicitly advance into a - * commit/submodule (as well as a tree) to avoid some cases where an - * entry is mislabeled as a submodule in the working directory + /* Allow you to explicitly advance into a commit/submodule (as well as a + * tree) to avoid cases where an entry is mislabeled as a submodule in + * the working directory. The fs iterator will never have COMMMIT + * entries on it's own, but a wrapper might add them. */ - if (wi->entry.path != NULL && - (wi->entry.mode == GIT_FILEMODE_TREE || - wi->entry.mode == GIT_FILEMODE_COMMIT)) + if (fi->entry.path != NULL && + (fi->entry.mode == GIT_FILEMODE_TREE || + fi->entry.mode == GIT_FILEMODE_COMMIT)) /* returns GIT_ENOTFOUND if the directory is empty */ - error = workdir_iterator__expand_dir(wi); + error = fs_iterator__expand_dir(fi); if (!error && entry) - error = workdir_iterator__current(entry, iter); + error = fs_iterator__current(entry, iter); return error; } -static int workdir_iterator__advance( +static int fs_iterator__advance_over( const git_index_entry **entry, git_iterator *self) { int error = 0; - workdir_iterator *wi = (workdir_iterator *)self; - workdir_iterator_frame *wf; + fs_iterator *fi = (fs_iterator *)self; + fs_iterator_frame *ff; git_path_with_stat *next; - /* given include_trees & autoexpand, we might have to go into a tree */ - if (iterator__do_autoexpand(wi) && - wi->entry.path != NULL && - wi->entry.mode == GIT_FILEMODE_TREE) - { - error = workdir_iterator__advance_into(entry, self); - - /* continue silently past empty directories if autoexpanding */ - if (error != GIT_ENOTFOUND) - return error; - giterr_clear(); - error = 0; - } - if (entry != NULL) *entry = NULL; - while (wi->entry.path != NULL) { - wf = wi->stack; - next = git_vector_get(&wf->entries, ++wf->index); + while (fi->entry.path != NULL) { + ff = fi->stack; + next = git_vector_get(&ff->entries, ++ff->index); - if (next != NULL) { - /* match git's behavior of ignoring anything named ".git" */ - if (path_is_dotgit(next)) - continue; - /* else found a good entry */ + if (next != NULL) break; - } - - /* pop stack if anything is left to pop */ - if (!wf->next) { - memset(&wi->entry, 0, sizeof(wi->entry)); - return 0; - } - wi->stack = wf->next; - wi->depth--; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); + fs_iterator__pop_frame(fi, ff, false); } - error = workdir_iterator__update_entry(wi); + error = fs_iterator__update_entry(fi); if (!error && entry != NULL) - error = workdir_iterator__current(entry, self); + error = fs_iterator__current(entry, self); return error; } -static int workdir_iterator__seek(git_iterator *self, const char *prefix) +static int fs_iterator__advance( + const git_index_entry **entry, git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + + /* given include_trees & autoexpand, we might have to go into a tree */ + if (iterator__do_autoexpand(fi) && + fi->entry.path != NULL && + fi->entry.mode == GIT_FILEMODE_TREE) + { + int error = fs_iterator__advance_into(entry, self); + if (error != GIT_ENOTFOUND) + return error; + /* continue silently past empty directories if autoexpanding */ + giterr_clear(); + } + + return fs_iterator__advance_over(entry, self); +} + +static int fs_iterator__seek(git_iterator *self, const char *prefix) { GIT_UNUSED(self); GIT_UNUSED(prefix); @@ -1073,107 +1060,192 @@ static int workdir_iterator__seek(git_iterator *self, const char *prefix) return 0; } -static int workdir_iterator__reset( +static int fs_iterator__reset( git_iterator *self, const char *start, const char *end) { - workdir_iterator *wi = (workdir_iterator *)self; + fs_iterator *fi = (fs_iterator *)self; - while (wi->stack != NULL && wi->stack->next != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); - } - wi->depth = 0; + while (fi->stack != NULL && fi->stack->next != NULL) + fs_iterator__pop_frame(fi, fi->stack, false); + fi->depth = 0; if (iterator__reset_range(self, start, end) < 0) return -1; - workdir_iterator__seek_frame_start(wi, wi->stack); + fs_iterator__seek_frame_start(fi, fi->stack); - return workdir_iterator__update_entry(wi); + return fs_iterator__update_entry(fi); } -static void workdir_iterator__free(git_iterator *self) +static void fs_iterator__free(git_iterator *self) { - workdir_iterator *wi = (workdir_iterator *)self; + fs_iterator *fi = (fs_iterator *)self; - while (wi->stack != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - } + while (fi->stack != NULL) + fs_iterator__pop_frame(fi, fi->stack, true); - git_ignore__free(&wi->ignores); - git_buf_free(&wi->path); + git_buf_free(&fi->path); } -static int workdir_iterator__update_entry(workdir_iterator *wi) +static int fs_iterator__update_entry(fs_iterator *fi) { - int error = 0; git_path_with_stat *ps = - git_vector_get(&wi->stack->entries, wi->stack->index); + git_vector_get(&fi->stack->entries, fi->stack->index); - git_buf_truncate(&wi->path, wi->root_len); - memset(&wi->entry, 0, sizeof(wi->entry)); + git_buf_truncate(&fi->path, fi->root_len); + memset(&fi->entry, 0, sizeof(fi->entry)); if (!ps) return 0; + if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) + return -1; + if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) + return 0; - /* skip over .git entries */ - if (path_is_dotgit(ps)) - return workdir_iterator__advance(NULL, (git_iterator *)wi); + fi->entry.path = ps->path; + git_index_entry__init_from_stat(&fi->entry, &ps->st); + + /* need different mode here to keep directories during iteration */ + fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); + + /* allow wrapper to check/update the entry (can force skip) */ + if (fi->update_entry_cb && + fi->update_entry_cb(fi) == GIT_ENOTFOUND) + return fs_iterator__advance_over(NULL, (git_iterator *)fi); + + /* if this is a tree and trees aren't included, then skip */ + if (fi->entry.mode == GIT_FILEMODE_TREE && !iterator__include_trees(fi)) + return git_iterator_advance(NULL, (git_iterator *)fi); + + return 0; +} + +static int fs_iterator__initialize( + git_iterator **out, fs_iterator *fi, const char *root) +{ + int error; - if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0) + if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { + git__free(fi); return -1; + } + fi->root_len = fi->path.size; - if (iterator__past_end(wi, wi->path.ptr + wi->root_len)) - return 0; + if ((error = fs_iterator__expand_dir(fi)) == GIT_ENOTFOUND) { + giterr_clear(); + error = 0; + } + if (error) { + git_iterator_free((git_iterator *)fi); + fi = NULL; + } - wi->entry.path = ps->path; + *out = (git_iterator *)fi; + return error; +} - wi->is_ignored = -1; +int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end) +{ + fs_iterator *fi = git__calloc(1, sizeof(fs_iterator)); + GITERR_CHECK_ALLOC(fi); - git_index_entry__init_from_stat(&wi->entry, &ps->st); + ITERATOR_BASE_INIT(fi, fs, FS, NULL); - /* need different mode here to keep directories during iteration */ - wi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); + if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) + fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; - /* if this is a file type we don't handle, treat as ignored */ - if (wi->entry.mode == 0) { - wi->is_ignored = 1; - return 0; + return fs_iterator__initialize(out, fi, root); +} + + +typedef struct { + fs_iterator fi; + git_ignores ignores; + int is_ignored; +} workdir_iterator; + +GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) +{ + size_t len; + + if (!path || (len = path->size) < 4) + return false; + + if (path->ptr[len - 1] == '/') + len--; + + if (tolower(path->ptr[len - 1]) != 't' || + tolower(path->ptr[len - 2]) != 'i' || + tolower(path->ptr[len - 3]) != 'g' || + tolower(path->ptr[len - 4]) != '.') + return false; + + return (len == 4 || path->ptr[len - 5] == '/'); +} + +static int workdir_iterator__enter_dir(fs_iterator *fi) +{ + /* only push new ignores if this is not top level directory */ + if (fi->stack->next != NULL) { + workdir_iterator *wi = (workdir_iterator *)fi; + ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); + + (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); } - /* if this isn't a tree, then we're done */ - if (wi->entry.mode != GIT_FILEMODE_TREE) - return 0; + return 0; +} - /* detect submodules */ - error = git_submodule_lookup(NULL, wi->base.repo, wi->entry.path); - if (error == GIT_ENOTFOUND) - giterr_clear(); +static int workdir_iterator__leave_dir(fs_iterator *fi) +{ + workdir_iterator *wi = (workdir_iterator *)fi; + git_ignore__pop_dir(&wi->ignores); + return 0; +} - if (error == GIT_EEXISTS) /* if contains .git, treat as untracked submod */ - error = 0; +static int workdir_iterator__update_entry(fs_iterator *fi) +{ + int error = 0; + workdir_iterator *wi = (workdir_iterator *)fi; + + /* skip over .git entries */ + if (workdir_path_is_dotgit(&fi->path)) + return GIT_ENOTFOUND; + + /* reset is_ignored since we haven't checked yet */ + wi->is_ignored = -1; - /* if submodule, mark as GITLINK and remove trailing slash */ - if (!error) { - size_t len = strlen(wi->entry.path); - assert(wi->entry.path[len - 1] == '/'); - wi->entry.path[len - 1] = '\0'; - wi->entry.mode = S_IFGITLINK; + /* check if apparent tree entries are actually submodules */ + if (fi->entry.mode != GIT_FILEMODE_TREE) return 0; + + error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path); + if (error < 0) + giterr_clear(); + + /* mark submodule (or any dir with .git) as GITLINK and remove slash */ + if (!error || error == GIT_EEXISTS) { + fi->entry.mode = S_IFGITLINK; + fi->entry.path[strlen(fi->entry.path) - 1] = '\0'; } - if (iterator__include_trees(wi)) - return 0; + return 0; +} - return workdir_iterator__advance(NULL, (git_iterator *)wi); +static void workdir_iterator__free(git_iterator *self) +{ + workdir_iterator *wi = (workdir_iterator *)self; + fs_iterator__free(self); + git_ignore__free(&wi->ignores); } int git_iterator_for_workdir( - git_iterator **iter, + git_iterator **out, git_repository *repo, git_iterator_flag_t flags, const char *start, @@ -1182,38 +1254,28 @@ int git_iterator_for_workdir( int error; workdir_iterator *wi; - assert(iter && repo); + if (git_repository__ensure_not_bare(repo, "scan working directory") < 0) + return GIT_EBAREREPO; - if ((error = git_repository__ensure_not_bare( - repo, "scan working directory")) < 0) - return error; + /* initialize as an fs iterator then do overrides */ + wi = git__calloc(1, sizeof(workdir_iterator)); + GITERR_CHECK_ALLOC(wi); + ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); - ITERATOR_BASE_INIT(wi, workdir, WORKDIR, repo); - - if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0) - goto fail; + wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; + wi->fi.cb.free = workdir_iterator__free; + wi->fi.enter_dir_cb = workdir_iterator__enter_dir; + wi->fi.leave_dir_cb = workdir_iterator__leave_dir; + wi->fi.update_entry_cb = workdir_iterator__update_entry; - if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 || - git_path_to_dir(&wi->path) < 0 || - git_ignore__for_path(repo, "", &wi->ignores) < 0) + if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || + (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) { - git__free(wi); - return -1; - } - wi->root_len = wi->path.size; - - if ((error = workdir_iterator__expand_dir(wi)) < 0) { - if (error != GIT_ENOTFOUND) - goto fail; - giterr_clear(); + git_iterator_free((git_iterator *)wi); + return error; } - *iter = (git_iterator *)wi; - return 0; - -fail: - git_iterator_free((git_iterator *)wi); - return error; + return fs_iterator__initialize(out, &wi->fi, git_repository_workdir(repo)); } @@ -1315,7 +1377,8 @@ bool git_iterator_current_is_ignored(git_iterator *iter) if (wi->is_ignored != -1) return (bool)(wi->is_ignored != 0); - if (git_ignore__lookup(&wi->ignores, wi->entry.path, &wi->is_ignored) < 0) + if (git_ignore__lookup( + &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0) wi->is_ignored = true; return (bool)wi->is_ignored; @@ -1340,10 +1403,10 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; - if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->entry.path) + if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->fi.entry.path) *path = NULL; else - *path = &wi->path; + *path = &wi->fi.path; return 0; } diff --git a/src/iterator.h b/src/iterator.h index 4a4e6a9d850..7998f7c6bdf 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -19,6 +19,7 @@ typedef enum { GIT_ITERATOR_TYPE_TREE = 1, GIT_ITERATOR_TYPE_INDEX = 2, GIT_ITERATOR_TYPE_WORKDIR = 3, + GIT_ITERATOR_TYPE_FS = 4, } git_iterator_type_t; typedef enum { @@ -88,6 +89,16 @@ extern int git_iterator_for_workdir( const char *start, const char *end); +/* for filesystem iterators, you have to explicitly pass in the ignore_case + * behavior that you desire + */ +extern int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end); + extern void git_iterator_free(git_iterator *iter); /* Return a git_index_entry structure for the current value the iterator diff --git a/src/merge.c b/src/merge.c index e0010d6a4d7..56290bfadb2 100644 --- a/src/merge.c +++ b/src/merge.c @@ -5,15 +5,54 @@ * a Linking Exception. For full terms see the included COPYING file. */ +#include "common.h" +#include "posix.h" +#include "buffer.h" #include "repository.h" #include "revwalk.h" -#include "buffer.h" +#include "commit_list.h" #include "merge.h" +#include "path.h" #include "refs.h" +#include "object.h" +#include "iterator.h" +#include "refs.h" +#include "diff.h" +#include "checkout.h" +#include "tree.h" +#include "merge_file.h" +#include "blob.h" +#include "hashsig.h" +#include "oid.h" + +#include "git2/types.h" #include "git2/repository.h" +#include "git2/object.h" +#include "git2/commit.h" #include "git2/merge.h" +#include "git2/refs.h" #include "git2/reset.h" -#include "commit_list.h" +#include "git2/checkout.h" +#include "git2/signature.h" +#include "git2/config.h" +#include "git2/tree.h" +#include "git2/sys/index.h" + +#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) + +typedef enum { + TREE_IDX_ANCESTOR = 0, + TREE_IDX_OURS = 1, + TREE_IDX_THEIRS = 2 +} merge_tree_index_t; + +/* Tracks D/F conflicts */ +struct merge_diff_df_data { + const char *df_path; + const char *prev_path; + git_merge_diff *prev_conflict; +}; + int git_repository_merge_cleanup(git_repository *repo) { @@ -48,6 +87,8 @@ int git_repository_merge_cleanup(git_repository *repo) return error; } +/* Merge base computation */ + int git_merge_base_many(git_oid *out, git_repository *repo, const git_oid input_array[], size_t length) { git_revwalk *walk; @@ -177,7 +218,7 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l return -1; if (git_commit_list_parse(walk, one) < 0) - return -1; + return -1; one->flags |= PARENT1; if (git_pqueue_insert(&list, one) < 0) @@ -294,3 +335,1296 @@ int git_repository_mergehead_foreach(git_repository *repo, return error; } + +GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry *b) +{ + int value = 0; + + if (a->path == NULL) + return (b->path == NULL) ? 0 : 1; + + if ((value = a->mode - b->mode) == 0 && + (value = git_oid__cmp(&a->oid, &b->oid)) == 0) + value = strcmp(a->path, b->path); + + return value; +} + +/* Conflict resolution */ + +static int merge_conflict_resolve_trivial( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_empty, theirs_empty; + int ours_changed, theirs_changed, ours_theirs_differ; + git_index_entry const *result = NULL; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + if (conflict->our_status == GIT_DELTA_RENAMED || + conflict->their_status == GIT_DELTA_RENAMED) + return 0; + + ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); + theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); + + ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); + theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); + ours_theirs_differ = ours_changed && theirs_changed && + index_entry_cmp(&conflict->our_entry, &conflict->their_entry); + + /* + * Note: with only one ancestor, some cases are not distinct: + * + * 16: ancest:anc1/anc2, head:anc1, remote:anc2 = result:no merge + * 3: ancest:(empty)^, head:head, remote:(empty) = result:no merge + * 2: ancest:(empty)^, head:(empty), remote:remote = result:no merge + * + * Note that the two cases that take D/F conflicts into account + * specifically do not need to be explicitly tested, as D/F conflicts + * would fail the *empty* test: + * + * 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head + * 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote + * + * Note that many of these cases need not be explicitly tested, as + * they simply degrade to "all different" cases (eg, 11): + * + * 4: ancest:(empty)^, head:head, remote:remote = result:no merge + * 7: ancest:ancest+, head:(empty), remote:remote = result:no merge + * 9: ancest:ancest+, head:head, remote:(empty) = result:no merge + * 11: ancest:ancest+, head:head, remote:remote = result:no merge + */ + + /* 5ALT: ancest:*, head:head, remote:head = result:head */ + if (ours_changed && !ours_empty && !ours_theirs_differ) + result = &conflict->our_entry; + /* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ + else if (ours_changed && ours_empty && theirs_empty) + *resolved = 0; + /* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ + else if (ours_empty && !theirs_changed) + *resolved = 0; + /* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ + else if (!ours_changed && theirs_empty) + *resolved = 0; + /* 13: ancest:ancest+, head:head, remote:ancest = result:head */ + else if (ours_changed && !theirs_changed) + result = &conflict->our_entry; + /* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ + else if (!ours_changed && theirs_changed) + result = &conflict->their_entry; + else + *resolved = 0; + + if (result != NULL && + GIT_MERGE_INDEX_ENTRY_EXISTS(*result) && + (error = git_vector_insert(&diff_list->staged, (void *)result)) >= 0) + *resolved = 1; + + /* Note: trivial resolution does not update the REUC. */ + + return error; +} + +static int merge_conflict_resolve_one_removed( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_empty, theirs_empty; + int ours_changed, theirs_changed; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); + theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); + + ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); + theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); + + /* Removed in both */ + if (ours_changed && ours_empty && theirs_empty) + *resolved = 1; + /* Removed in ours */ + else if (ours_empty && !theirs_changed) + *resolved = 1; + /* Removed in theirs */ + else if (!ours_changed && theirs_empty) + *resolved = 1; + + if (*resolved) + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + return error; +} + + +static int merge_conflict_resolve_one_renamed( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_renamed, theirs_renamed; + int ours_changed, theirs_changed; + git_index_entry *merged; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) || + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) + return 0; + + ours_renamed = (conflict->our_status == GIT_DELTA_RENAMED); + theirs_renamed = (conflict->their_status == GIT_DELTA_RENAMED); + + if (!ours_renamed && !theirs_renamed) + return 0; + + /* Reject one file in a 2->1 conflict */ + if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || + conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + ours_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->our_entry.oid) != 0); + theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->their_entry.oid) != 0); + + /* if both are modified (and not to a common target) require a merge */ + if (ours_changed && theirs_changed && + git_oid__cmp(&conflict->our_entry.oid, &conflict->their_entry.oid) != 0) + return 0; + + if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) + return -1; + + if (ours_changed) + memcpy(merged, &conflict->our_entry, sizeof(git_index_entry)); + else + memcpy(merged, &conflict->their_entry, sizeof(git_index_entry)); + + if (ours_renamed) + merged->path = conflict->our_entry.path; + else + merged->path = conflict->their_entry.path; + + *resolved = 1; + + git_vector_insert(&diff_list->staged, merged); + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + return error; +} + +static int merge_conflict_resolve_automerge( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict, + unsigned int automerge_flags) +{ + git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT, + ours = GIT_MERGE_FILE_INPUT_INIT, + theirs = GIT_MERGE_FILE_INPUT_INIT; + git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT; + git_index_entry *index_entry; + git_odb *odb = NULL; + git_oid automerge_oid; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE) + return 0; + + /* Reject D/F conflicts */ + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE) + return 0; + + /* Reject link/file conflicts. */ + if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) || + (S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode))) + return 0; + + /* Reject name conflicts */ + if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + if ((conflict->our_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && + (conflict->their_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && + strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0) + return 0; + + if ((error = git_repository_odb(&odb, diff_list->repo)) < 0 || + (error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 || + (error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 || + (error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 || + (error = git_merge_files(&result, &ancestor, &ours, &theirs, automerge_flags)) < 0 || + !result.automergeable || + (error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0) + goto done; + + if ((index_entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) + GITERR_CHECK_ALLOC(index_entry); + + index_entry->path = git_pool_strdup(&diff_list->pool, result.path); + GITERR_CHECK_ALLOC(index_entry->path); + + index_entry->file_size = result.len; + index_entry->mode = result.mode; + git_oid_cpy(&index_entry->oid, &automerge_oid); + + git_vector_insert(&diff_list->staged, index_entry); + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + *resolved = 1; + +done: + git_merge_file_input_free(&ancestor); + git_merge_file_input_free(&ours); + git_merge_file_input_free(&theirs); + git_merge_file_result_free(&result); + git_odb_free(odb); + + return error; +} + +static int merge_conflict_resolve( + int *out, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict, + unsigned int automerge_flags) +{ + int resolved = 0; + int error = 0; + + *out = 0; + + if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0) + goto done; + + if (automerge_flags != GIT_MERGE_AUTOMERGE_NONE) { + if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0) + goto done; + + if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0) + goto done; + + if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, automerge_flags)) < 0) + goto done; + } + + *out = resolved; + +done: + return error; +} + +/* Rename detection and coalescing */ + +struct merge_diff_similarity { + unsigned char similarity; + size_t other_idx; +}; + +static int index_entry_similarity_exact( + git_repository *repo, + git_index_entry *a, + size_t a_idx, + git_index_entry *b, + size_t b_idx, + void **cache, + const git_merge_tree_opts *opts) +{ + GIT_UNUSED(repo); + GIT_UNUSED(a_idx); + GIT_UNUSED(b_idx); + GIT_UNUSED(cache); + GIT_UNUSED(opts); + + if (git_oid__cmp(&a->oid, &b->oid) == 0) + return 100; + + return 0; +} + +static int index_entry_similarity_calc( + void **out, + git_repository *repo, + git_index_entry *entry, + const git_merge_tree_opts *opts) +{ + git_blob *blob; + git_diff_file diff_file = {{{0}}}; + git_off_t blobsize; + int error; + + *out = NULL; + + if ((error = git_blob_lookup(&blob, repo, &entry->oid)) < 0) + return error; + + git_oid_cpy(&diff_file.oid, &entry->oid); + diff_file.path = entry->path; + diff_file.size = entry->file_size; + diff_file.mode = entry->mode; + diff_file.flags = 0; + + blobsize = git_blob_rawsize(blob); + + /* file too big for rename processing */ + if (!git__is_sizet(blobsize)) + return 0; + + error = opts->metric->buffer_signature(out, &diff_file, + git_blob_rawcontent(blob), (size_t)blobsize, + opts->metric->payload); + + git_blob_free(blob); + + return error; +} + +static int index_entry_similarity_inexact( + git_repository *repo, + git_index_entry *a, + size_t a_idx, + git_index_entry *b, + size_t b_idx, + void **cache, + const git_merge_tree_opts *opts) +{ + int score = 0; + int error = 0; + + if (GIT_MODE_TYPE(a->mode) != GIT_MODE_TYPE(b->mode)) + return 0; + + /* update signature cache if needed */ + if (!cache[a_idx] && (error = index_entry_similarity_calc(&cache[a_idx], repo, a, opts)) < 0) + return error; + if (!cache[b_idx] && (error = index_entry_similarity_calc(&cache[b_idx], repo, b, opts)) < 0) + return error; + + /* some metrics may not wish to process this file (too big / too small) */ + if (!cache[a_idx] || !cache[b_idx]) + return 0; + + /* compare signatures */ + if (opts->metric->similarity( + &score, cache[a_idx], cache[b_idx], opts->metric->payload) < 0) + return -1; + + /* clip score */ + if (score < 0) + score = 0; + else if (score > 100) + score = 100; + + return score; +} + +static int merge_diff_mark_similarity( + git_repository *repo, + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + struct merge_diff_similarity *similarity_theirs, + int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_tree_opts *), + void **cache, + const git_merge_tree_opts *opts) +{ + size_t i, j; + git_merge_diff *conflict_src, *conflict_tgt; + int similarity; + + git_vector_foreach(&diff_list->conflicts, i, conflict_src) { + /* Items can be the source of a rename iff they have an item in the + * ancestor slot and lack an item in the ours or theirs slot. */ + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry) || + (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry) && + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry))) + continue; + + git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) { + size_t our_idx = diff_list->conflicts.length + j; + size_t their_idx = (diff_list->conflicts.length * 2) + j; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry)) + continue; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { + similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts); + + if (similarity == GIT_EBUFS) + continue; + else if (similarity < 0) + return similarity; + + if (similarity > similarity_ours[i].similarity && + similarity > similarity_ours[j].similarity) { + /* Clear previous best similarity */ + if (similarity_ours[i].similarity > 0) + similarity_ours[similarity_ours[i].other_idx].similarity = 0; + + if (similarity_ours[j].similarity > 0) + similarity_ours[similarity_ours[j].other_idx].similarity = 0; + + similarity_ours[i].similarity = similarity; + similarity_ours[i].other_idx = j; + + similarity_ours[j].similarity = similarity; + similarity_ours[j].other_idx = i; + } + } + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { + similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts); + + if (similarity > similarity_theirs[i].similarity && + similarity > similarity_theirs[j].similarity) { + /* Clear previous best similarity */ + if (similarity_theirs[i].similarity > 0) + similarity_theirs[similarity_theirs[i].other_idx].similarity = 0; + + if (similarity_theirs[j].similarity > 0) + similarity_theirs[similarity_theirs[j].other_idx].similarity = 0; + + similarity_theirs[i].similarity = similarity; + similarity_theirs[i].other_idx = j; + + similarity_theirs[j].similarity = similarity; + similarity_theirs[j].other_idx = i; + } + } + } + } + + return 0; +} + +/* + * Rename conflicts: + * + * Ancestor Ours Theirs + * + * 0a A A A No rename + * b A A* A No rename (ours was rewritten) + * c A A A* No rename (theirs rewritten) + * 1a A A B[A] Rename or rename/edit + * b A B[A] A (automergeable) + * 2 A B[A] B[A] Both renamed (automergeable) + * 3a A B[A] Rename/delete + * b A B[A] (same) + * 4a A B[A] B Rename/add [B~ours B~theirs] + * b A B B[A] (same) + * 5 A B[A] C[A] Both renamed ("1 -> 2") + * 6 A C[A] Both renamed ("2 -> 1") + * B C[B] [C~ours C~theirs] (automergeable) + */ +static void merge_diff_mark_rename_conflict( + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + bool ours_renamed, + size_t ours_source_idx, + struct merge_diff_similarity *similarity_theirs, + bool theirs_renamed, + size_t theirs_source_idx, + git_merge_diff *target, + const git_merge_tree_opts *opts) +{ + git_merge_diff *ours_source = NULL, *theirs_source = NULL; + + if (ours_renamed) + ours_source = diff_list->conflicts.contents[ours_source_idx]; + + if (theirs_renamed) + theirs_source = diff_list->conflicts.contents[theirs_source_idx]; + + /* Detect 2->1 conflicts */ + if (ours_renamed && theirs_renamed) { + /* Both renamed to the same target name. */ + if (ours_source_idx == theirs_source_idx) + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED; + else { + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; + theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; + } + } else if (ours_renamed) { + /* If our source was also renamed in theirs, this is a 1->2 */ + if (similarity_theirs[ours_source_idx].similarity >= opts->rename_threshold) + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; + + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry)) { + ours_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; + target->type = GIT_MERGE_DIFF_RENAMED_ADDED; + } + + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(ours_source->their_entry)) + ours_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; + + else if (ours_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) + ours_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; + } else if (theirs_renamed) { + /* If their source was also renamed in ours, this is a 1->2 */ + if (similarity_ours[theirs_source_idx].similarity >= opts->rename_threshold) + theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; + + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry)) { + theirs_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; + target->type = GIT_MERGE_DIFF_RENAMED_ADDED; + } + + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(theirs_source->our_entry)) + theirs_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; + + else if (theirs_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) + theirs_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; + } +} + +GIT_INLINE(void) merge_diff_coalesce_rename( + git_index_entry *source_entry, + git_delta_t *source_status, + git_index_entry *target_entry, + git_delta_t *target_status) +{ + /* Coalesce the rename target into the rename source. */ + memcpy(source_entry, target_entry, sizeof(git_index_entry)); + *source_status = GIT_DELTA_RENAMED; + + memset(target_entry, 0x0, sizeof(git_index_entry)); + *target_status = GIT_DELTA_UNMODIFIED; +} + +static void merge_diff_list_coalesce_renames( + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + struct merge_diff_similarity *similarity_theirs, + const git_merge_tree_opts *opts) +{ + size_t i; + bool ours_renamed = 0, theirs_renamed = 0; + size_t ours_source_idx = 0, theirs_source_idx = 0; + git_merge_diff *ours_source, *theirs_source, *target; + + for (i = 0; i < diff_list->conflicts.length; i++) { + target = diff_list->conflicts.contents[i]; + + ours_renamed = 0; + theirs_renamed = 0; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry) && + similarity_ours[i].similarity >= opts->rename_threshold) { + ours_source_idx = similarity_ours[i].other_idx; + + ours_source = diff_list->conflicts.contents[ours_source_idx]; + + merge_diff_coalesce_rename( + &ours_source->our_entry, + &ours_source->our_status, + &target->our_entry, + &target->our_status); + + similarity_ours[ours_source_idx].similarity = 0; + similarity_ours[i].similarity = 0; + + ours_renamed = 1; + } + + /* insufficient to determine direction */ + if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry) && + similarity_theirs[i].similarity >= opts->rename_threshold) { + theirs_source_idx = similarity_theirs[i].other_idx; + + theirs_source = diff_list->conflicts.contents[theirs_source_idx]; + + merge_diff_coalesce_rename( + &theirs_source->their_entry, + &theirs_source->their_status, + &target->their_entry, + &target->their_status); + + similarity_theirs[theirs_source_idx].similarity = 0; + similarity_theirs[i].similarity = 0; + + theirs_renamed = 1; + } + + merge_diff_mark_rename_conflict(diff_list, + similarity_ours, ours_renamed, ours_source_idx, + similarity_theirs, theirs_renamed, theirs_source_idx, + target, opts); + } +} + +static int merge_diff_empty(const git_vector *conflicts, size_t idx) +{ + git_merge_diff *conflict = conflicts->contents[idx]; + + return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)); +} + +static void merge_diff_list_count_candidates( + git_merge_diff_list *diff_list, + size_t *src_count, + size_t *tgt_count) +{ + git_merge_diff *entry; + size_t i; + + *src_count = 0; + *tgt_count = 0; + + git_vector_foreach(&diff_list->conflicts, i, entry) { + if (GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry) && + (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->our_entry) || + !GIT_MERGE_INDEX_ENTRY_EXISTS(entry->their_entry))) + src_count++; + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry)) + tgt_count++; + } +} + +int git_merge_diff_list__find_renames( + git_repository *repo, + git_merge_diff_list *diff_list, + const git_merge_tree_opts *opts) +{ + struct merge_diff_similarity *similarity_ours, *similarity_theirs; + void **cache = NULL; + size_t cache_size = 0; + size_t src_count, tgt_count, i; + int error = 0; + + assert(diff_list && opts); + + if ((opts->flags & GIT_MERGE_TREE_FIND_RENAMES) == 0) + return 0; + + similarity_ours = git__calloc(diff_list->conflicts.length, + sizeof(struct merge_diff_similarity)); + GITERR_CHECK_ALLOC(similarity_ours); + + similarity_theirs = git__calloc(diff_list->conflicts.length, + sizeof(struct merge_diff_similarity)); + GITERR_CHECK_ALLOC(similarity_theirs); + + /* Calculate similarity between items that were deleted from the ancestor + * and added in the other branch. + */ + if ((error = merge_diff_mark_similarity(repo, diff_list, similarity_ours, + similarity_theirs, index_entry_similarity_exact, NULL, opts)) < 0) + goto done; + + if (diff_list->conflicts.length <= opts->target_limit) { + cache_size = diff_list->conflicts.length * 3; + cache = git__calloc(cache_size, sizeof(void *)); + GITERR_CHECK_ALLOC(cache); + + merge_diff_list_count_candidates(diff_list, &src_count, &tgt_count); + + if (src_count > opts->target_limit || tgt_count > opts->target_limit) { + /* TODO: report! */ + } else { + if ((error = merge_diff_mark_similarity( + repo, diff_list, similarity_ours, similarity_theirs, + index_entry_similarity_inexact, cache, opts)) < 0) + goto done; + } + } + + /* For entries that are appropriately similar, merge the new name's entry + * into the old name. + */ + merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts); + + /* And remove any entries that were merged and are now empty. */ + git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty); + +done: + if (cache != NULL) { + for (i = 0; i < cache_size; ++i) { + if (cache[i] != NULL) + opts->metric->free_signature(cache[i], opts->metric->payload); + } + + git__free(cache); + } + + git__free(similarity_ours); + git__free(similarity_theirs); + + return error; +} + +/* Directory/file conflict handling */ + +GIT_INLINE(const char *) merge_diff_path( + const git_merge_diff *conflict) +{ + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) + return conflict->ancestor_entry.path; + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry)) + return conflict->our_entry.path; + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) + return conflict->their_entry.path; + + return NULL; +} + +GIT_INLINE(bool) merge_diff_any_side_added_or_modified( + const git_merge_diff *conflict) +{ + if (conflict->our_status == GIT_DELTA_ADDED || + conflict->our_status == GIT_DELTA_MODIFIED || + conflict->their_status == GIT_DELTA_ADDED || + conflict->their_status == GIT_DELTA_MODIFIED) + return true; + + return false; +} + +GIT_INLINE(bool) path_is_prefixed(const char *parent, const char *child) +{ + size_t child_len = strlen(child); + size_t parent_len = strlen(parent); + + if (child_len < parent_len || + strncmp(parent, child, parent_len) != 0) + return 0; + + return (child[parent_len] == '/'); +} + +GIT_INLINE(int) merge_diff_detect_df_conflict( + struct merge_diff_df_data *df_data, + git_merge_diff *conflict) +{ + const char *cur_path = merge_diff_path(conflict); + + /* Determine if this is a D/F conflict or the child of one */ + if (df_data->df_path && + path_is_prefixed(df_data->df_path, cur_path)) + conflict->type = GIT_MERGE_DIFF_DF_CHILD; + else if(df_data->df_path) + df_data->df_path = NULL; + else if (df_data->prev_path && + merge_diff_any_side_added_or_modified(df_data->prev_conflict) && + merge_diff_any_side_added_or_modified(conflict) && + path_is_prefixed(df_data->prev_path, cur_path)) { + conflict->type = GIT_MERGE_DIFF_DF_CHILD; + + df_data->prev_conflict->type = GIT_MERGE_DIFF_DIRECTORY_FILE; + df_data->df_path = df_data->prev_path; + } + + df_data->prev_path = cur_path; + df_data->prev_conflict = conflict; + + return 0; +} + +/* Conflict handling */ + +GIT_INLINE(int) merge_diff_detect_type( + git_merge_diff *conflict) +{ + if (conflict->our_status == GIT_DELTA_ADDED && + conflict->their_status == GIT_DELTA_ADDED) + conflict->type = GIT_MERGE_DIFF_BOTH_ADDED; + else if (conflict->our_status == GIT_DELTA_MODIFIED && + conflict->their_status == GIT_DELTA_MODIFIED) + conflict->type = GIT_MERGE_DIFF_BOTH_MODIFIED; + else if (conflict->our_status == GIT_DELTA_DELETED && + conflict->their_status == GIT_DELTA_DELETED) + conflict->type = GIT_MERGE_DIFF_BOTH_DELETED; + else if (conflict->our_status == GIT_DELTA_MODIFIED && + conflict->their_status == GIT_DELTA_DELETED) + conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; + else if (conflict->our_status == GIT_DELTA_DELETED && + conflict->their_status == GIT_DELTA_MODIFIED) + conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; + else + conflict->type = GIT_MERGE_DIFF_NONE; + + return 0; +} + +GIT_INLINE(int) index_entry_dup( + git_index_entry *out, + git_pool *pool, + const git_index_entry *src) +{ + if (src != NULL) { + memcpy(out, src, sizeof(git_index_entry)); + + if ((out->path = git_pool_strdup(pool, src->path)) == NULL) + return -1; + } + + return 0; +} + +GIT_INLINE(int) merge_delta_type_from_index_entries( + const git_index_entry *ancestor, + const git_index_entry *other) +{ + if (ancestor == NULL && other == NULL) + return GIT_DELTA_UNMODIFIED; + else if (ancestor == NULL && other != NULL) + return GIT_DELTA_ADDED; + else if (ancestor != NULL && other == NULL) + return GIT_DELTA_DELETED; + else if (S_ISDIR(ancestor->mode) ^ S_ISDIR(other->mode)) + return GIT_DELTA_TYPECHANGE; + else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode)) + return GIT_DELTA_TYPECHANGE; + else if (git_oid__cmp(&ancestor->oid, &other->oid) || + ancestor->mode != other->mode) + return GIT_DELTA_MODIFIED; + + return GIT_DELTA_UNMODIFIED; +} + +static git_merge_diff *merge_diff_from_index_entries( + git_merge_diff_list *diff_list, + const git_index_entry **entries) +{ + git_merge_diff *conflict; + git_pool *pool = &diff_list->pool; + + if ((conflict = git_pool_malloc(pool, sizeof(git_merge_diff))) == NULL) + return NULL; + + if (index_entry_dup(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 || + index_entry_dup(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 || + index_entry_dup(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0) + return NULL; + + conflict->our_status = merge_delta_type_from_index_entries( + entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_OURS]); + conflict->their_status = merge_delta_type_from_index_entries( + entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_THEIRS]); + + return conflict; +} + +/* Merge trees */ + +static int merge_index_insert_conflict( + git_merge_diff_list *diff_list, + struct merge_diff_df_data *merge_df_data, + const git_index_entry *tree_items[3]) +{ + git_merge_diff *conflict; + + if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL || + merge_diff_detect_type(conflict) < 0 || + merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 || + git_vector_insert(&diff_list->conflicts, conflict) < 0) + return -1; + + return 0; +} + +static int merge_index_insert_unmodified( + git_merge_diff_list *diff_list, + const git_index_entry *tree_items[3]) +{ + int error = 0; + git_index_entry *entry; + + entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry)); + GITERR_CHECK_ALLOC(entry); + + if ((error = index_entry_dup(entry, &diff_list->pool, tree_items[0])) >= 0) + error = git_vector_insert(&diff_list->staged, entry); + + return error; +} + +int git_merge_diff_list__find_differences( + git_merge_diff_list *diff_list, + const git_tree *ancestor_tree, + const git_tree *our_tree, + const git_tree *their_tree) +{ + git_iterator *iterators[3] = {0}; + const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3]; + git_vector_cmp entry_compare = git_index_entry__cmp; + struct merge_diff_df_data df_data = {0}; + int cur_item_modified; + size_t i, j; + int error = 0; + + assert(diff_list && our_tree && their_tree); + + if ((error = git_iterator_for_tree(&iterators[TREE_IDX_ANCESTOR], (git_tree *)ancestor_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || + (error = git_iterator_for_tree(&iterators[TREE_IDX_OURS], (git_tree *)our_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || + (error = git_iterator_for_tree(&iterators[TREE_IDX_THEIRS], (git_tree *)their_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0) + goto done; + + /* Set up the iterators */ + for (i = 0; i < 3; i++) { + if ((error = git_iterator_current(&items[i], iterators[i])) < 0) + goto done; + } + + while (true) { + for (i = 0; i < 3; i++) + cur_items[i] = NULL; + + best_cur_item = NULL; + cur_item_modified = 0; + + /* Find the next path(s) to consume from each iterator */ + for (i = 0; i < 3; i++) { + if (items[i] == NULL) { + cur_item_modified = 1; + continue; + } + + if (best_cur_item == NULL) { + best_cur_item = items[i]; + cur_items[i] = items[i]; + } else { + int path_diff = entry_compare(items[i], best_cur_item); + + if (path_diff < 0) { + /* + * Found an item that sorts before our current item, make + * our current item this one. + */ + for (j = 0; j < i; j++) + cur_items[j] = NULL; + + cur_item_modified = 1; + best_cur_item = items[i]; + cur_items[i] = items[i]; + } else if (path_diff > 0) { + /* No entry for the current item, this is modified */ + cur_item_modified = 1; + } else if (path_diff == 0) { + cur_items[i] = items[i]; + + if (!cur_item_modified) + cur_item_modified = index_entry_cmp(best_cur_item, items[i]); + } + } + } + + if (best_cur_item == NULL) + break; + + if (cur_item_modified) + error = merge_index_insert_conflict(diff_list, &df_data, cur_items); + else + error = merge_index_insert_unmodified(diff_list, cur_items); + + /* Advance each iterator that participated */ + for (i = 0; i < 3; i++) { + if (cur_items[i] != NULL && + (error = git_iterator_advance(&items[i], iterators[i])) < 0) + goto done; + } + } + +done: + for (i = 0; i < 3; i++) + git_iterator_free(iterators[i]); + + return error; +} + +git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo) +{ + git_merge_diff_list *diff_list = git__calloc(1, sizeof(git_merge_diff_list)); + + if (diff_list == NULL) + return NULL; + + diff_list->repo = repo; + + if (git_vector_init(&diff_list->staged, 0, NULL) < 0 || + git_vector_init(&diff_list->conflicts, 0, NULL) < 0 || + git_vector_init(&diff_list->resolved, 0, NULL) < 0 || + git_pool_init(&diff_list->pool, 1, 0) < 0) + return NULL; + + return diff_list; +} + +static int merge_tree_normalize_opts( + git_repository *repo, + git_merge_tree_opts *opts, + const git_merge_tree_opts *given) +{ + git_config *cfg = NULL; + int error = 0; + + assert(repo && opts); + + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) + return error; + + if (given != NULL) + memcpy(opts, given, sizeof(git_merge_tree_opts)); + else { + git_merge_tree_opts init = GIT_MERGE_TREE_OPTS_INIT; + memcpy(opts, &init, sizeof(init)); + + opts->flags = GIT_MERGE_TREE_FIND_RENAMES; + opts->rename_threshold = GIT_MERGE_TREE_RENAME_THRESHOLD; + } + + if (!opts->target_limit) { + int32_t limit = 0; + + opts->target_limit = GIT_MERGE_TREE_TARGET_LIMIT; + + if (git_config_get_int32(&limit, cfg, "merge.renameLimit") < 0) { + giterr_clear(); + + if (git_config_get_int32(&limit, cfg, "diff.renameLimit") < 0) + giterr_clear(); + } + + if (limit > 0) + opts->target_limit = limit; + } + + /* assign the internal metric with whitespace flag as payload */ + if (!opts->metric) { + opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); + GITERR_CHECK_ALLOC(opts->metric); + + opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; + opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; + opts->metric->free_signature = git_diff_find_similar__hashsig_free; + opts->metric->similarity = git_diff_find_similar__calc_similarity; + + if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE) + opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE; + else if (opts->flags & GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE) + opts->metric->payload = (void *)GIT_HASHSIG_NORMAL; + else + opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; + } + + return 0; +} + + +static int merge_index_insert_reuc( + git_index *index, + size_t idx, + const git_index_entry *entry) +{ + const git_index_reuc_entry *reuc; + int mode[3] = { 0, 0, 0 }; + git_oid const *oid[3] = { NULL, NULL, NULL }; + size_t i; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(*entry)) + return 0; + + if ((reuc = git_index_reuc_get_bypath(index, entry->path)) != NULL) { + for (i = 0; i < 3; i++) { + mode[i] = reuc->mode[i]; + oid[i] = &reuc->oid[i]; + } + } + + mode[idx] = entry->mode; + oid[idx] = &entry->oid; + + return git_index_reuc_add(index, entry->path, + mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]); +} + +int index_from_diff_list(git_index **out, git_merge_diff_list *diff_list) +{ + git_index *index; + size_t i; + git_index_entry *entry; + git_merge_diff *conflict; + int error = 0; + + *out = NULL; + + if ((error = git_index_new(&index)) < 0) + return error; + + git_vector_foreach(&diff_list->staged, i, entry) { + if ((error = git_index_add(index, entry)) < 0) + goto on_error; + } + + git_vector_foreach(&diff_list->conflicts, i, conflict) { + const git_index_entry *ancestor = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? + &conflict->ancestor_entry : NULL; + + const git_index_entry *ours = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + &conflict->our_entry : NULL; + + const git_index_entry *theirs = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + &conflict->their_entry : NULL; + + if ((error = git_index_conflict_add(index, ancestor, ours, theirs)) < 0) + goto on_error; + } + + /* Add each rename entry to the rename portion of the index. */ + git_vector_foreach(&diff_list->conflicts, i, conflict) { + const char *ancestor_path, *our_path, *their_path; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) + continue; + + ancestor_path = conflict->ancestor_entry.path; + + our_path = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + conflict->our_entry.path : NULL; + + their_path = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + conflict->their_entry.path : NULL; + + if ((our_path && strcmp(ancestor_path, our_path) != 0) || + (their_path && strcmp(ancestor_path, their_path) != 0)) { + if ((error = git_index_name_add(index, ancestor_path, our_path, their_path)) < 0) + goto on_error; + } + } + + /* Add each entry in the resolved conflict to the REUC independently, since + * the paths may differ due to renames. */ + git_vector_foreach(&diff_list->resolved, i, conflict) { + const git_index_entry *ancestor = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? + &conflict->ancestor_entry : NULL; + + const git_index_entry *ours = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + &conflict->our_entry : NULL; + + const git_index_entry *theirs = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + &conflict->their_entry : NULL; + + if (ancestor != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_ANCESTOR, ancestor)) < 0) + goto on_error; + + if (ours != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_OURS, ours)) < 0) + goto on_error; + + if (theirs != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_THEIRS, theirs)) < 0) + goto on_error; + } + + *out = index; + return 0; + +on_error: + git_index_free(index); + + return error; +} + +int git_merge_trees( + git_index **out, + git_repository *repo, + const git_tree *ancestor_tree, + const git_tree *our_tree, + const git_tree *their_tree, + const git_merge_tree_opts *given_opts) +{ + git_merge_diff_list *diff_list; + git_merge_tree_opts opts; + git_merge_diff *conflict; + git_vector changes; + size_t i; + int error = 0; + + assert(out && repo && our_tree && their_tree); + + *out = NULL; + + if ((error = merge_tree_normalize_opts(repo, &opts, given_opts)) < 0) + return error; + + diff_list = git_merge_diff_list__alloc(repo); + GITERR_CHECK_ALLOC(diff_list); + + if ((error = git_merge_diff_list__find_differences(diff_list, ancestor_tree, our_tree, their_tree)) < 0 || + (error = git_merge_diff_list__find_renames(repo, diff_list, &opts)) < 0) + goto done; + + memcpy(&changes, &diff_list->conflicts, sizeof(git_vector)); + git_vector_clear(&diff_list->conflicts); + + git_vector_foreach(&changes, i, conflict) { + int resolved = 0; + + if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.automerge_flags)) < 0) + goto done; + + if (!resolved) + git_vector_insert(&diff_list->conflicts, conflict); + } + + if (!given_opts || !given_opts->metric) + git__free(opts.metric); + + error = index_from_diff_list(out, diff_list); + +done: + git_merge_diff_list__free(diff_list); + + return error; +} + +void git_merge_diff_list__free(git_merge_diff_list *diff_list) +{ + if (!diff_list) + return; + + git_vector_free(&diff_list->staged); + git_vector_free(&diff_list->conflicts); + git_vector_free(&diff_list->resolved); + git_pool_clear(&diff_list->pool); + git__free(diff_list); +} + diff --git a/src/merge.h b/src/merge.h index 22c644270da..6307d1569ea 100644 --- a/src/merge.h +++ b/src/merge.h @@ -7,16 +7,121 @@ #ifndef INCLUDE_merge_h__ #define INCLUDE_merge_h__ -#include "git2/types.h" -#include "git2/merge.h" -#include "commit_list.h" #include "vector.h" +#include "commit_list.h" +#include "pool.h" + +#include "git2/merge.h" +#include "git2/types.h" #define GIT_MERGE_MSG_FILE "MERGE_MSG" #define GIT_MERGE_MODE_FILE "MERGE_MODE" -#define MERGE_CONFIG_FILE_MODE 0666 +#define GIT_MERGE_TREE_RENAME_THRESHOLD 50 +#define GIT_MERGE_TREE_TARGET_LIMIT 1000 + +/** Types of changes when files are merged from branch to branch. */ +typedef enum { + /* No conflict - a change only occurs in one branch. */ + GIT_MERGE_DIFF_NONE = 0, + + /* Occurs when a file is modified in both branches. */ + GIT_MERGE_DIFF_BOTH_MODIFIED = (1 << 0), + + /* Occurs when a file is added in both branches. */ + GIT_MERGE_DIFF_BOTH_ADDED = (1 << 1), + + /* Occurs when a file is deleted in both branches. */ + GIT_MERGE_DIFF_BOTH_DELETED = (1 << 2), + + /* Occurs when a file is modified in one branch and deleted in the other. */ + GIT_MERGE_DIFF_MODIFIED_DELETED = (1 << 3), + + /* Occurs when a file is renamed in one branch and modified in the other. */ + GIT_MERGE_DIFF_RENAMED_MODIFIED = (1 << 4), + + /* Occurs when a file is renamed in one branch and deleted in the other. */ + GIT_MERGE_DIFF_RENAMED_DELETED = (1 << 5), + + /* Occurs when a file is renamed in one branch and a file with the same + * name is added in the other. Eg, A->B and new file B. Core git calls + * this a "rename/delete". */ + GIT_MERGE_DIFF_RENAMED_ADDED = (1 << 6), + + /* Occurs when both a file is renamed to the same name in the ours and + * theirs branches. Eg, A->B and A->B in both. Automergeable. */ + GIT_MERGE_DIFF_BOTH_RENAMED = (1 << 7), + + /* Occurs when a file is renamed to different names in the ours and theirs + * branches. Eg, A->B and A->C. */ + GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 = (1 << 8), + + /* Occurs when two files are renamed to the same name in the ours and + * theirs branches. Eg, A->C and B->C. */ + GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 = (1 << 9), + + /* Occurs when an item at a path in one branch is a directory, and an + * item at the same path in a different branch is a file. */ + GIT_MERGE_DIFF_DIRECTORY_FILE = (1 << 10), + + /* The child of a folder that is in a directory/file conflict. */ + GIT_MERGE_DIFF_DF_CHILD = (1 << 11), +} git_merge_diff_type_t; + + +typedef struct { + git_repository *repo; + git_pool pool; + + /* Vector of git_index_entry that represent the merged items that + * have been staged, either because only one side changed, or because + * the two changes were non-conflicting and mergeable. These items + * will be written as staged entries in the main index. + */ + git_vector staged; + + /* Vector of git_merge_diff entries that represent the conflicts that + * have not been automerged. These items will be written to high-stage + * entries in the main index. + */ + git_vector conflicts; + + /* Vector of git_merge_diff that have been automerged. These items + * will be written to the REUC when the index is produced. + */ + git_vector resolved; +} git_merge_diff_list; + +/** + * Description of changes to one file across three trees. + */ +typedef struct { + git_merge_diff_type_t type; + + git_index_entry ancestor_entry; + + git_index_entry our_entry; + git_delta_t our_status; + + git_index_entry their_entry; + git_delta_t their_status; +} git_merge_diff; + +int git_merge__bases_many( + git_commit_list **out, + git_revwalk *walk, + git_commit_list_node *one, + git_vector *twos); + +git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo); + +int git_merge_diff_list__find_differences(git_merge_diff_list *merge_diff_list, + const git_tree *ancestor_tree, + const git_tree *ours_tree, + const git_tree *theirs_tree); + +int git_merge_diff_list__find_renames(git_repository *repo, git_merge_diff_list *merge_diff_list, const git_merge_tree_opts *opts); -int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos); +void git_merge_diff_list__free(git_merge_diff_list *diff_list); #endif diff --git a/src/merge_file.c b/src/merge_file.c new file mode 100644 index 00000000000..4b3f3730b75 --- /dev/null +++ b/src/merge_file.c @@ -0,0 +1,175 @@ +/* + * 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 "merge_file.h" + +#include "git2/repository.h" +#include "git2/object.h" +#include "git2/index.h" + +#include "xdiff/xdiff.h" + +#define GIT_MERGE_FILE_SIDE_EXISTS(X) ((X)->mode != 0) + +GIT_INLINE(const char *) merge_file_best_path( + const git_merge_file_input *ancestor, + const git_merge_file_input *ours, + const git_merge_file_input *theirs) +{ + if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) { + if (strcmp(ours->path, theirs->path) == 0) + return ours->path; + + return NULL; + } + + if (strcmp(ancestor->path, ours->path) == 0) + return theirs->path; + else if(strcmp(ancestor->path, theirs->path) == 0) + return ours->path; + + return NULL; +} + +GIT_INLINE(int) merge_file_best_mode( + const git_merge_file_input *ancestor, + const git_merge_file_input *ours, + const git_merge_file_input *theirs) +{ + /* + * If ancestor didn't exist and either ours or theirs is executable, + * assume executable. Otherwise, if any mode changed from the ancestor, + * use that one. + */ + if (GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) { + if (ours->mode == GIT_FILEMODE_BLOB_EXECUTABLE || + theirs->mode == GIT_FILEMODE_BLOB_EXECUTABLE) + return GIT_FILEMODE_BLOB_EXECUTABLE; + + return GIT_FILEMODE_BLOB; + } + + if (ancestor->mode == ours->mode) + return theirs->mode; + else if(ancestor->mode == theirs->mode) + return ours->mode; + + return 0; +} + +int git_merge_file_input_from_index_entry( + git_merge_file_input *input, + git_repository *repo, + const git_index_entry *entry) +{ + git_odb *odb = NULL; + int error = 0; + + assert(input && repo && entry); + + if (entry->mode == 0) + return 0; + + if ((error = git_repository_odb(&odb, repo)) < 0 || + (error = git_odb_read(&input->odb_object, odb, &entry->oid)) < 0) + goto done; + + input->mode = entry->mode; + input->path = git__strdup(entry->path); + input->mmfile.size = git_odb_object_size(input->odb_object); + input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object); + + if (input->label == NULL) + input->label = entry->path; + +done: + git_odb_free(odb); + + return error; +} + +int git_merge_file_input_from_diff_file( + git_merge_file_input *input, + git_repository *repo, + const git_diff_file *file) +{ + git_odb *odb = NULL; + int error = 0; + + assert(input && repo && file); + + if (file->mode == 0) + return 0; + + if ((error = git_repository_odb(&odb, repo)) < 0 || + (error = git_odb_read(&input->odb_object, odb, &file->oid)) < 0) + goto done; + + input->mode = file->mode; + input->path = git__strdup(file->path); + input->mmfile.size = git_odb_object_size(input->odb_object); + input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object); + + if (input->label == NULL) + input->label = file->path; + +done: + git_odb_free(odb); + + return error; +} + +int git_merge_files( + git_merge_file_result *out, + git_merge_file_input *ancestor, + git_merge_file_input *ours, + git_merge_file_input *theirs, + git_merge_automerge_flags flags) +{ + xmparam_t xmparam; + mmbuffer_t mmbuffer; + int xdl_result; + int error = 0; + + assert(out && ancestor && ours && theirs); + + memset(out, 0x0, sizeof(git_merge_file_result)); + + if (!GIT_MERGE_FILE_SIDE_EXISTS(ours) || !GIT_MERGE_FILE_SIDE_EXISTS(theirs)) + return 0; + + memset(&xmparam, 0x0, sizeof(xmparam_t)); + xmparam.ancestor = ancestor->label; + xmparam.file1 = ours->label; + xmparam.file2 = theirs->label; + + out->path = merge_file_best_path(ancestor, ours, theirs); + out->mode = merge_file_best_mode(ancestor, ours, theirs); + + if (flags == GIT_MERGE_AUTOMERGE_FAVOR_OURS) + xmparam.favor = XDL_MERGE_FAVOR_OURS; + + if (flags == GIT_MERGE_AUTOMERGE_FAVOR_THEIRS) + xmparam.favor = XDL_MERGE_FAVOR_THEIRS; + + if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile, + &theirs->mmfile, &xmparam, &mmbuffer)) < 0) { + giterr_set(GITERR_MERGE, "Failed to merge files."); + error = -1; + goto done; + } + + out->automergeable = (xdl_result == 0); + out->data = (unsigned char *)mmbuffer.ptr; + out->len = mmbuffer.size; + +done: + return error; +} + diff --git a/src/merge_file.h b/src/merge_file.h new file mode 100644 index 00000000000..1aa34893d05 --- /dev/null +++ b/src/merge_file.h @@ -0,0 +1,71 @@ +/* + * 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_filediff_h__ +#define INCLUDE_filediff_h__ + +#include "xdiff/xdiff.h" + +#include "git2/merge.h" + +typedef struct { + const char *label; + char *path; + unsigned int mode; + mmfile_t mmfile; + + git_odb_object *odb_object; +} git_merge_file_input; + +#define GIT_MERGE_FILE_INPUT_INIT {0} + +typedef struct { + bool automergeable; + + const char *path; + int mode; + + unsigned char *data; + size_t len; +} git_merge_file_result; + +#define GIT_MERGE_FILE_RESULT_INIT {0} + +int git_merge_file_input_from_index_entry( + git_merge_file_input *input, + git_repository *repo, + const git_index_entry *entry); + +int git_merge_file_input_from_diff_file( + git_merge_file_input *input, + git_repository *repo, + const git_diff_file *file); + +int git_merge_files( + git_merge_file_result *out, + git_merge_file_input *ancestor, + git_merge_file_input *ours, + git_merge_file_input *theirs, + git_merge_automerge_flags flags); + +GIT_INLINE(void) git_merge_file_input_free(git_merge_file_input *input) +{ + assert(input); + git__free(input->path); + git_odb_object_free(input->odb_object); +} + +GIT_INLINE(void) git_merge_file_result_free(git_merge_file_result *filediff) +{ + if (filediff == NULL) + return; + + /* xdiff uses malloc() not git_malloc, so we use free(), not git_free() */ + if (filediff->data != NULL) + free(filediff->data); +} + +#endif diff --git a/src/mwindow.c b/src/mwindow.c index b35503d4676..7e5fcdfbc71 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -162,7 +162,7 @@ static git_mwindow *new_window( git_mwindow *w; w = git__malloc(sizeof(*w)); - + if (w == NULL) return NULL; diff --git a/src/object.c b/src/object.c index f59e4c7dad1..b87a074043b 100644 --- a/src/object.c +++ b/src/object.c @@ -18,65 +18,38 @@ static const int OBJECT_BASE_SIZE = 4096; -static struct { +typedef struct { const char *str; /* type name string */ - int loose; /* valid loose object type flag */ size_t size; /* size in bytes of the object structure */ -} git_objects_table[] = { + + int (*parse)(void *self, git_odb_object *obj); + void (*free)(void *self); +} git_object_def; + +static git_object_def git_objects_table[] = { /* 0 = GIT_OBJ__EXT1 */ - { "", 0, 0}, + { "", 0, NULL, NULL }, /* 1 = GIT_OBJ_COMMIT */ - { "commit", 1, sizeof(struct git_commit)}, + { "commit", sizeof(git_commit), git_commit__parse, git_commit__free }, /* 2 = GIT_OBJ_TREE */ - { "tree", 1, sizeof(struct git_tree) }, + { "tree", sizeof(git_tree), git_tree__parse, git_tree__free }, /* 3 = GIT_OBJ_BLOB */ - { "blob", 1, sizeof(struct git_blob) }, + { "blob", sizeof(git_blob), git_blob__parse, git_blob__free }, /* 4 = GIT_OBJ_TAG */ - { "tag", 1, sizeof(struct git_tag) }, + { "tag", sizeof(git_tag), git_tag__parse, git_tag__free }, /* 5 = GIT_OBJ__EXT2 */ - { "", 0, 0 }, - + { "", 0, NULL, NULL }, /* 6 = GIT_OBJ_OFS_DELTA */ - { "OFS_DELTA", 0, 0 }, - + { "OFS_DELTA", 0, NULL, NULL }, /* 7 = GIT_OBJ_REF_DELTA */ - { "REF_DELTA", 0, 0 } + { "REF_DELTA", 0, NULL, NULL }, }; -static int create_object(git_object **object_out, git_otype type) -{ - git_object *object = NULL; - - assert(object_out); - - *object_out = NULL; - - switch (type) { - case GIT_OBJ_COMMIT: - case GIT_OBJ_TAG: - case GIT_OBJ_BLOB: - case GIT_OBJ_TREE: - object = git__malloc(git_object__size(type)); - GITERR_CHECK_ALLOC(object); - memset(object, 0x0, git_object__size(type)); - break; - - default: - giterr_set(GITERR_INVALID, "The given type is invalid"); - return -1; - } - - object->type = type; - - *object_out = object; - return 0; -} - int git_object__from_odb_object( git_object **object_out, git_repository *repo, @@ -84,49 +57,55 @@ int git_object__from_odb_object( git_otype type) { int error; + size_t object_size; + git_object_def *def; git_object *object = NULL; - if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { - giterr_set(GITERR_INVALID, "The requested type does not match the type in the ODB"); + assert(object_out); + *object_out = NULL; + + /* Validate type match */ + if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) { + giterr_set(GITERR_INVALID, + "The requested type does not match the type in the ODB"); return GIT_ENOTFOUND; } - type = odb_obj->raw.type; + if ((object_size = git_object__size(odb_obj->cached.type)) == 0) { + giterr_set(GITERR_INVALID, "The requested type is invalid"); + return GIT_ENOTFOUND; + } - if ((error = create_object(&object, type)) < 0) - return error; + /* Allocate and initialize base object */ + object = git__calloc(1, object_size); + GITERR_CHECK_ALLOC(object); - /* Initialize parent object */ git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); + object->cached.type = odb_obj->cached.type; + object->cached.size = odb_obj->cached.size; object->repo = repo; - switch (type) { - case GIT_OBJ_COMMIT: - error = git_commit__parse((git_commit *)object, odb_obj); - break; - - case GIT_OBJ_TREE: - error = git_tree__parse((git_tree *)object, odb_obj); - break; + /* Parse raw object data */ + def = &git_objects_table[odb_obj->cached.type]; + assert(def->free && def->parse); - case GIT_OBJ_TAG: - error = git_tag__parse((git_tag *)object, odb_obj); - break; + if ((error = def->parse(object, odb_obj)) < 0) + def->free(object); + else + *object_out = git_cache_store_parsed(&repo->objects, object); - case GIT_OBJ_BLOB: - error = git_blob__parse((git_blob *)object, odb_obj); - break; + return error; +} - default: - break; - } +void git_object__free(void *obj) +{ + git_otype type = ((git_object *)obj)->cached.type; - if (error < 0) - git_object__free(object); + if (type < 0 || ((size_t)type) >= ARRAY_SIZE(git_objects_table) || + !git_objects_table[type].free) + git__free(obj); else - *object_out = git_cache_try_store(&repo->objects, object); - - return error; + git_objects_table[type].free(obj); } int git_object_lookup_prefix( @@ -154,27 +133,38 @@ int git_object_lookup_prefix( len = GIT_OID_HEXSZ; if (len == GIT_OID_HEXSZ) { + git_cached_obj *cached = NULL; + /* We want to match the full id : we can first look up in the cache, * since there is no need to check for non ambiguousity */ - object = git_cache_get(&repo->objects, id); - if (object != NULL) { - if (type != GIT_OBJ_ANY && type != object->type) { - git_object_free(object); - giterr_set(GITERR_INVALID, "The requested type does not match the type in ODB"); - return GIT_ENOTFOUND; + cached = git_cache_get_any(&repo->objects, id); + if (cached != NULL) { + if (cached->flags == GIT_CACHE_STORE_PARSED) { + object = (git_object *)cached; + + if (type != GIT_OBJ_ANY && type != object->cached.type) { + git_object_free(object); + giterr_set(GITERR_INVALID, + "The requested type does not match the type in ODB"); + return GIT_ENOTFOUND; + } + + *object_out = object; + return 0; + } else if (cached->flags == GIT_CACHE_STORE_RAW) { + odb_obj = (git_odb_object *)cached; + } else { + assert(!"Wrong caching type in the global object cache"); } - - *object_out = object; - return 0; + } else { + /* Object was not found in the cache, let's explore the backends. + * We could just use git_odb_read_unique_short_oid, + * it is the same cost for packed and loose object backends, + * but it may be much more costly for sqlite and hiredis. + */ + error = git_odb_read(&odb_obj, odb, id); } - - /* Object was not found in the cache, let's explore the backends. - * We could just use git_odb_read_unique_short_oid, - * it is the same cost for packed and loose object backends, - * but it may be much more costly for sqlite and hiredis. - */ - error = git_odb_read(&odb_obj, odb, id); } else { git_oid short_oid; @@ -211,41 +201,12 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type); } -void git_object__free(void *_obj) -{ - git_object *object = (git_object *)_obj; - - assert(object); - - switch (object->type) { - case GIT_OBJ_COMMIT: - git_commit__free((git_commit *)object); - break; - - case GIT_OBJ_TREE: - git_tree__free((git_tree *)object); - break; - - case GIT_OBJ_TAG: - git_tag__free((git_tag *)object); - break; - - case GIT_OBJ_BLOB: - git_blob__free((git_blob *)object); - break; - - default: - git__free(object); - break; - } -} - void git_object_free(git_object *object) { if (object == NULL) return; - git_cached_obj_decref((git_cached_obj *)object, git_object__free); + git_cached_obj_decref(object); } const git_oid *git_object_id(const git_object *obj) @@ -257,7 +218,7 @@ const git_oid *git_object_id(const git_object *obj) git_otype git_object_type(const git_object *obj) { assert(obj); - return obj->type; + return obj->cached.type; } git_repository *git_object_owner(const git_object *obj) @@ -293,7 +254,7 @@ int git_object_typeisloose(git_otype type) if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) return 0; - return git_objects_table[type].loose; + return (git_objects_table[type].size > 0) ? 1 : 0; } size_t git_object__size(git_otype type) @@ -360,7 +321,7 @@ int git_object_peel( assert(object && peeled); if (git_object_type(object) == target_type) - return git_object__dup(peeled, (git_object *)object); + return git_object_dup(peeled, (git_object *)object); source = (git_object *)object; @@ -396,3 +357,9 @@ int git_object_peel( return error; } +int git_object_dup(git_object **dest, git_object *source) +{ + git_cached_obj_incref(source); + *dest = source; + return 0; +} diff --git a/src/object.h b/src/object.h index 8788caba6a7..d187c55b734 100644 --- a/src/object.h +++ b/src/object.h @@ -11,19 +11,11 @@ struct git_object { git_cached_obj cached; git_repository *repo; - git_otype type; }; /* fully free the object; internal method, DO NOT EXPORT */ void git_object__free(void *object); -GIT_INLINE(int) git_object__dup(git_object **dest, git_object *source) -{ - git_cached_obj_incref(source); - *dest = source; - return 0; -} - int git_object__from_odb_object( git_object **object_out, git_repository *repo, diff --git a/src/object_api.c b/src/object_api.c new file mode 100644 index 00000000000..838bba3233e --- /dev/null +++ b/src/object_api.c @@ -0,0 +1,129 @@ +/* + * 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/object.h" + +#include "common.h" +#include "repository.h" + +#include "commit.h" +#include "tree.h" +#include "blob.h" +#include "tag.h" + +/** + * Blob + */ +int git_commit_lookup(git_commit **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); +} + +int git_commit_lookup_prefix(git_commit **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); +} + +void git_commit_free(git_commit *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_commit_id(const git_commit *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_commit_owner(const git_commit *obj) +{ + return git_object_owner((const git_object *)obj); +} + + +/** + * Tree + */ +int git_tree_lookup(git_tree **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TREE); +} + +int git_tree_lookup_prefix(git_tree **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_TREE); +} + +void git_tree_free(git_tree *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_tree_id(const git_tree *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_tree_owner(const git_tree *obj) +{ + return git_object_owner((const git_object *)obj); +} + + +/** + * Tag + */ +int git_tag_lookup(git_tag **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TAG); +} + +int git_tag_lookup_prefix(git_tag **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_TAG); +} + +void git_tag_free(git_tag *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_tag_id(const git_tag *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_tag_owner(const git_tag *obj) +{ + return git_object_owner((const git_object *)obj); +} + +/** + * Blob + */ +int git_blob_lookup(git_blob **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_BLOB); +} + +int git_blob_lookup_prefix(git_blob **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_BLOB); +} + +void git_blob_free(git_blob *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_blob_id(const git_blob *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_blob_owner(const git_blob *obj) +{ + return git_object_owner((const git_object *)obj); +} diff --git a/src/odb.c b/src/odb.c index c98df247c94..07e1ea6eb0d 100644 --- a/src/odb.c +++ b/src/odb.c @@ -8,11 +8,13 @@ #include "common.h" #include #include "git2/object.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" #include "delta-apply.h" #include "filter.h" +#include "repository.h" #include "git2/odb_backend.h" #include "git2/oid.h" @@ -29,10 +31,19 @@ typedef struct { git_odb_backend *backend; int priority; - int is_alternate; + bool is_alternate; + ino_t disk_inode; } backend_internal; -size_t git_odb__cache_size = GIT_DEFAULT_CACHE_SIZE; +static git_cache *odb_cache(git_odb *odb) +{ + if (odb->rc.owner != NULL) { + git_repository *owner = odb->rc.owner; + return &owner->objects; + } + + return &odb->own_cache; +} static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth); @@ -54,6 +65,7 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj) if (!git_object_typeisloose(obj->type)) return -1; + if (!obj->data && obj->len != 0) return -1; @@ -70,23 +82,24 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj) } -static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source) +static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source) { - git_odb_object *object = git__malloc(sizeof(git_odb_object)); - memset(object, 0x0, sizeof(git_odb_object)); + git_odb_object *object = git__calloc(1, sizeof(git_odb_object)); - git_oid_cpy(&object->cached.oid, oid); - memcpy(&object->raw, source, sizeof(git_rawobj)); + if (object != NULL) { + git_oid_cpy(&object->cached.oid, oid); + object->cached.type = source->type; + object->cached.size = source->len; + object->buffer = source->data; + } return object; } -static void free_odb_object(void *o) +void git_odb_object__free(void *object) { - git_odb_object *object = (git_odb_object *)o; - if (object != NULL) { - git__free(object->raw.data); + git__free(((git_odb_object *)object)->buffer); git__free(object); } } @@ -98,17 +111,17 @@ const git_oid *git_odb_object_id(git_odb_object *object) const void *git_odb_object_data(git_odb_object *object) { - return object->raw.data; + return object->buffer; } size_t git_odb_object_size(git_odb_object *object) { - return object->raw.len; + return object->cached.size; } git_otype git_odb_object_type(git_odb_object *object) { - return object->raw.type; + return object->cached.type; } void git_odb_object_free(git_odb_object *object) @@ -116,7 +129,7 @@ void git_odb_object_free(git_odb_object *object) if (object == NULL) return; - git_cached_obj_decref((git_cached_obj *)object, &free_odb_object); + git_cached_obj_decref(object); } int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type) @@ -353,9 +366,8 @@ int git_odb_new(git_odb **out) git_odb *db = git__calloc(1, sizeof(*db)); GITERR_CHECK_ALLOC(db); - if (git_cache_init(&db->cache, git_odb__cache_size, &free_odb_object) < 0 || - git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) - { + if (git_cache_init(&db->own_cache) < 0 || + git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) { git__free(db); return -1; } @@ -365,7 +377,9 @@ int git_odb_new(git_odb **out) return 0; } -static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int priority, int is_alternate) +static int add_backend_internal( + git_odb *odb, git_odb_backend *backend, + int priority, bool is_alternate, ino_t disk_inode) { backend_internal *internal; @@ -382,6 +396,7 @@ static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int prio internal->backend = backend; internal->priority = priority; internal->is_alternate = is_alternate; + internal->disk_inode = disk_inode; if (git_vector_insert(&odb->backends, internal) < 0) { git__free(internal); @@ -395,26 +410,74 @@ static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int prio int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority) { - return add_backend_internal(odb, backend, priority, 0); + return add_backend_internal(odb, backend, priority, false, 0); } int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) { - return add_backend_internal(odb, backend, priority, 1); + return add_backend_internal(odb, backend, priority, true, 0); } -static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates, int alternate_depth) +size_t git_odb_num_backends(git_odb *odb) { + assert(odb); + return odb->backends.length; +} + +int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos) +{ + backend_internal *internal; + + assert(odb && odb); + internal = git_vector_get(&odb->backends, pos); + + if (internal && internal->backend) { + *out = internal->backend; + return 0; + } + + return GIT_ENOTFOUND; +} + +static int add_default_backends( + git_odb *db, const char *objects_dir, + bool as_alternates, int alternate_depth) +{ + size_t i; + struct stat st; + ino_t inode; git_odb_backend *loose, *packed; + /* TODO: inodes are not really relevant on Win32, so we need to find + * a cross-platform workaround for this */ +#ifdef GIT_WIN32 + GIT_UNUSED(i); + GIT_UNUSED(st); + + inode = 0; +#else + if (p_stat(objects_dir, &st) < 0) { + giterr_set(GITERR_ODB, "Failed to load object database in '%s'", objects_dir); + return -1; + } + + inode = st.st_ino; + + for (i = 0; i < db->backends.length; ++i) { + backend_internal *backend = git_vector_get(&db->backends, i); + if (backend->disk_inode == inode) + return 0; + } +#endif + /* add the loose object backend */ if (git_odb_backend_loose(&loose, objects_dir, -1, 0) < 0 || - add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates) < 0) + add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0) return -1; /* add the packed file backend */ if (git_odb_backend_pack(&packed, objects_dir) < 0 || - add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates) < 0) + add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0) return -1; return load_alternates(db, objects_dir, alternate_depth); @@ -464,7 +527,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_ alternate = git_buf_cstr(&alternates_path); } - if ((result = add_default_backends(odb, alternate, 1, alternate_depth + 1)) < 0) + if ((result = add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0) break; } @@ -476,7 +539,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_ int git_odb_add_disk_alternate(git_odb *odb, const char *path) { - return add_default_backends(odb, path, 1, 0); + return add_default_backends(odb, path, true, 0); } int git_odb_open(git_odb **out, const char *objects_dir) @@ -514,7 +577,7 @@ static void odb_free(git_odb *db) } git_vector_free(&db->backends); - git_cache_free(&db->cache); + git_cache_free(&db->own_cache); git__free(db); } @@ -535,7 +598,7 @@ int git_odb_exists(git_odb *db, const git_oid *id) assert(db && id); - if ((object = git_cache_get(&db->cache, id)) != NULL) { + if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { git_odb_object_free(object); return (int)true; } @@ -585,9 +648,9 @@ int git_odb__read_header_or_object( assert(db && id && out && len_p && type_p); - if ((object = git_cache_get(&db->cache, id)) != NULL) { - *len_p = object->raw.len; - *type_p = object->raw.type; + if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { + *len_p = object->cached.size; + *type_p = object->cached.type; *out = object; return 0; } @@ -612,8 +675,8 @@ int git_odb__read_header_or_object( if ((error = git_odb_read(&object, db, id)) < 0) return error; /* error already set - pass along */ - *len_p = object->raw.len; - *type_p = object->raw.type; + *len_p = object->cached.size; + *type_p = object->cached.type; *out = object; return 0; @@ -625,6 +688,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) int error; bool refreshed = false; git_rawobj raw; + git_odb_object *object; assert(out && db && id); @@ -633,7 +697,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) return GIT_ENOTFOUND; } - *out = git_cache_get(&db->cache, id); + *out = git_cache_get_raw(odb_cache(db), id); if (*out != NULL) return 0; @@ -659,7 +723,10 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) if (error && error != GIT_PASSTHROUGH) return error; - *out = git_cache_try_store(&db->cache, new_odb_object(id, &raw)); + if ((object = odb_object__alloc(id, &raw)) == NULL) + return -1; + + *out = git_cache_store_raw(odb_cache(db), object); return 0; } @@ -672,6 +739,7 @@ int git_odb_read_prefix( git_rawobj raw; void *data = NULL; bool found = false, refreshed = false; + git_odb_object *object; assert(out && db); @@ -682,7 +750,7 @@ int git_odb_read_prefix( len = GIT_OID_HEXSZ; if (len == GIT_OID_HEXSZ) { - *out = git_cache_get(&db->cache, short_id); + *out = git_cache_get_raw(odb_cache(db), short_id); if (*out != NULL) return 0; } @@ -704,7 +772,7 @@ int git_odb_read_prefix( git__free(data); data = raw.data; - if (found && git_oid_cmp(&full_oid, &found_full_oid)) + if (found && git_oid__cmp(&full_oid, &found_full_oid)) return git_odb__error_ambiguous("multiple matches for prefix"); found_full_oid = full_oid; @@ -723,7 +791,10 @@ int git_odb_read_prefix( if (!found) return git_odb__error_notfound("no match for prefix", short_id); - *out = git_cache_try_store(&db->cache, new_odb_object(&found_full_oid, &raw)); + if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) + return -1; + + *out = git_cache_store_raw(odb_cache(db), object); return 0; } diff --git a/src/odb.h b/src/odb.h index 7c018cc5041..0d9f9e2ea15 100644 --- a/src/odb.h +++ b/src/odb.h @@ -29,14 +29,14 @@ typedef struct { /* EXPORT */ struct git_odb_object { git_cached_obj cached; - git_rawobj raw; + void *buffer; }; /* EXPORT */ struct git_odb { git_refcount rc; git_vector backends; - git_cache cache; + git_cache own_cache; }; /* @@ -96,4 +96,7 @@ int git_odb__read_header_or_object( git_odb_object **out, size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id); +/* fully free the object; internal method, DO NOT EXPORT */ +void git_odb_object__free(void *object); + #endif diff --git a/src/odb_loose.c b/src/odb_loose.c index 68083f7fd35..e78172cf69d 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -8,7 +8,7 @@ #include "common.h" #include #include "git2/object.h" -#include "git2/oid.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" diff --git a/src/odb_pack.c b/src/odb_pack.c index 7240a4ac712..eec79259b85 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -8,7 +8,8 @@ #include "common.h" #include #include "git2/repository.h" -#include "git2/oid.h" +#include "git2/indexer.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" @@ -206,7 +207,7 @@ static int packfile_load__cb(void *_data, git_buf *path) return 0; } - error = git_packfile_check(&pack, path->ptr); + error = git_packfile_alloc(&pack, path->ptr); if (error == GIT_ENOTFOUND) /* ignore missing .pack file as git does */ return 0; @@ -526,80 +527,75 @@ static void pack_backend__free(git_odb_backend *_backend) git__free(backend); } -int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) +static int pack_backend__alloc(struct pack_backend **out, size_t initial_size) { - struct pack_backend *backend = NULL; - struct git_pack_file *packfile = NULL; + struct pack_backend *backend = git__calloc(1, sizeof(struct pack_backend)); + GITERR_CHECK_ALLOC(backend); - if (git_packfile_check(&packfile, idx) < 0) + if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) { + git__free(backend); return -1; + } - backend = git__calloc(1, sizeof(struct pack_backend)); - GITERR_CHECK_ALLOC(backend); backend->parent.version = GIT_ODB_BACKEND_VERSION; - if (git_vector_init(&backend->packs, 1, NULL) < 0) - goto on_error; - - if (git_vector_insert(&backend->packs, packfile) < 0) - goto on_error; - backend->parent.read = &pack_backend__read; backend->parent.read_prefix = &pack_backend__read_prefix; backend->parent.read_header = &pack_backend__read_header; backend->parent.exists = &pack_backend__exists; backend->parent.refresh = &pack_backend__refresh; backend->parent.foreach = &pack_backend__foreach; + backend->parent.writepack = &pack_backend__writepack; backend->parent.free = &pack_backend__free; - *backend_out = (git_odb_backend *)backend; - + *out = backend; return 0; - -on_error: - git_vector_free(&backend->packs); - git__free(backend); - git__free(packfile); - return -1; } -int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) +int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) { struct pack_backend *backend = NULL; - git_buf path = GIT_BUF_INIT; + struct git_pack_file *packfile = NULL; - backend = git__calloc(1, sizeof(struct pack_backend)); - GITERR_CHECK_ALLOC(backend); - backend->parent.version = GIT_ODB_BACKEND_VERSION; + if (pack_backend__alloc(&backend, 1) < 0) + return -1; - if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < 0 || - git_buf_joinpath(&path, objects_dir, "pack") < 0) + if (git_packfile_alloc(&packfile, idx) < 0 || + git_vector_insert(&backend->packs, packfile) < 0) { - git__free(backend); + pack_backend__free((git_odb_backend *)backend); return -1; } - if (git_path_isdir(git_buf_cstr(&path)) == true) { - int error; + *backend_out = (git_odb_backend *)backend; + return 0; +} + +int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) +{ + int error = 0; + struct pack_backend *backend = NULL; + git_buf path = GIT_BUF_INIT; + + if (pack_backend__alloc(&backend, 8) < 0) + return -1; + if (!(error = git_buf_joinpath(&path, objects_dir, "pack")) && + git_path_isdir(git_buf_cstr(&path))) + { backend->pack_folder = git_buf_detach(&path); + error = pack_backend__refresh((git_odb_backend *)backend); - if (error < 0) - return error; } - backend->parent.read = &pack_backend__read; - backend->parent.read_prefix = &pack_backend__read_prefix; - backend->parent.read_header = &pack_backend__read_header; - backend->parent.exists = &pack_backend__exists; - backend->parent.refresh = &pack_backend__refresh; - backend->parent.foreach = &pack_backend__foreach; - backend->parent.writepack = &pack_backend__writepack; - backend->parent.free = &pack_backend__free; + if (error < 0) { + pack_backend__free((git_odb_backend *)backend); + backend = NULL; + } *backend_out = (git_odb_backend *)backend; git_buf_free(&path); - return 0; + return error; } diff --git a/src/oid.c b/src/oid.c index ab69eeb1782..e74640c5776 100644 --- a/src/oid.c +++ b/src/oid.c @@ -166,18 +166,26 @@ void git_oid_cpy(git_oid *out, const git_oid *src) memcpy(out->id, src->id, sizeof(out->id)); } +int git_oid_cmp(const git_oid *a, const git_oid *b) +{ + return git_oid__cmp(a, b); +} + int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) { const unsigned char *a = oid_a->id; const unsigned char *b = oid_b->id; - do { + if (len > GIT_OID_HEXSZ) + len = GIT_OID_HEXSZ; + + while (len > 1) { if (*a != *b) return 1; a++; b++; len -= 2; - } while (len > 1); + }; if (len) if ((*a ^ *b) & 0xf0) @@ -186,14 +194,31 @@ int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) return 0; } -int git_oid_streq(const git_oid *a, const char *str) +int git_oid_strcmp(const git_oid *oid_a, const char *str) { - git_oid id; + const unsigned char *a = oid_a->id; + unsigned char strval; + int hexval; - if (git_oid_fromstr(&id, str) < 0) - return -1; + for (a = oid_a->id; *str && (a - oid_a->id) < GIT_OID_RAWSZ; ++a) { + if ((hexval = git__fromhex(*str++)) < 0) + return -1; + strval = hexval << 4; + if (*str) { + if ((hexval = git__fromhex(*str++)) < 0) + return -1; + strval |= hexval; + } + if (*a != strval) + return (*a - strval); + } - return git_oid_cmp(a, &id) == 0 ? 0 : -1; + return 0; +} + +int git_oid_streq(const git_oid *oid_a, const char *str) +{ + return git_oid_strcmp(oid_a, str) == 0 ? 0 : -1; } int git_oid_iszero(const git_oid *oid_a) diff --git a/src/oid.h b/src/oid.h new file mode 100644 index 00000000000..077d0a4c8f6 --- /dev/null +++ b/src/oid.h @@ -0,0 +1,33 @@ +/* + * 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_oid_h__ +#define INCLUDE_oid_h__ + +#include "git2/oid.h" + +/* + * Compare two oid structures. + * + * @param a first oid structure. + * @param b second oid structure. + * @return <0, 0, >0 if a < b, a == b, a > b. + */ +GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b) +{ + const unsigned char *sha1 = a->id; + const unsigned char *sha2 = b->id; + int i; + + for (i = 0; i < GIT_OID_RAWSZ; i++, sha1++, sha2++) { + if (*sha1 != *sha2) + return *sha1 - *sha2; + } + + return 0; +} + +#endif diff --git a/src/oidmap.h b/src/oidmap.h index 40274cd194f..a29c7cd35ff 100644 --- a/src/oidmap.h +++ b/src/oidmap.h @@ -19,17 +19,15 @@ __KHASH_TYPE(oid, const git_oid *, void *); typedef khash_t(oid) git_oidmap; -GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid) +GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) { - int i; - khint_t h = 0; - for (i = 0; i < 20; ++i) - h = (h << 5) - h + oid->id[i]; + khint_t h; + memcpy(&h, oid, sizeof(khint_t)); return h; } #define GIT__USE_OIDMAP \ - __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, hash_git_oid, git_oid_equal) + __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) #define git_oidmap_alloc() kh_init(oid) #define git_oidmap_free(h) kh_destroy(oid,h), h = NULL diff --git a/src/pack-objects.c b/src/pack-objects.c index 459201f5844..1329a9bc153 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -1284,6 +1284,21 @@ static int cb_tree_walk(const char *root, const git_tree_entry *entry, void *pay git_buf_cstr(&ctx->buf)); } +int git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *oid) +{ + git_commit *commit; + + if (git_commit_lookup(&commit, pb->repo, oid) < 0 || + git_packbuilder_insert(pb, oid, NULL) < 0) + return -1; + + if (git_packbuilder_insert_tree(pb, git_commit_tree_id(commit)) < 0) + return -1; + + git_commit_free(commit); + return 0; +} + int git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *oid) { git_tree *tree; diff --git a/src/pack.c b/src/pack.c index 75ac9818657..417d225f309 100644 --- a/src/pack.c +++ b/src/pack.c @@ -12,8 +12,8 @@ #include "sha1_lookup.h" #include "mwindow.h" #include "fileops.h" +#include "oid.h" -#include "git2/oid.h" #include static int packfile_open(struct git_pack_file *p); @@ -205,13 +205,18 @@ static int pack_index_check(const char *path, struct git_pack_file *p) if (fd < 0) return fd; - if (p_fstat(fd, &st) < 0 || - !S_ISREG(st.st_mode) || + if (p_fstat(fd, &st) < 0) { + p_close(fd); + giterr_set(GITERR_OS, "Unable to stat pack index '%s'", path); + return -1; + } + + if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size) || (idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20) { p_close(fd); - giterr_set(GITERR_OS, "Failed to check pack index."); + giterr_set(GITERR_ODB, "Invalid pack index '%s'", path); return -1; } @@ -288,32 +293,40 @@ static int pack_index_check(const char *path, struct git_pack_file *p) } } - p->index_version = version; p->num_objects = nr; + p->index_version = version; return 0; } static int pack_index_open(struct git_pack_file *p) { char *idx_name; - int error; - size_t name_len, offset; + int error = 0; + size_t name_len, base_len; - if (p->index_map.data) + if (p->index_version > -1) return 0; - idx_name = git__strdup(p->pack_name); - GITERR_CHECK_ALLOC(idx_name); + name_len = strlen(p->pack_name); + assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */ + + if ((idx_name = git__malloc(name_len)) == NULL) + return -1; + + base_len = name_len - strlen(".pack"); + memcpy(idx_name, p->pack_name, base_len); + memcpy(idx_name + base_len, ".idx", sizeof(".idx")); - name_len = strlen(idx_name); - offset = name_len - strlen(".pack"); - assert(offset < name_len); /* make sure no underflow */ + if ((error = git_mutex_lock(&p->lock)) < 0) + return error; - strncpy(idx_name + offset, ".idx", name_len - offset); + if (p->index_version == -1) + error = pack_index_check(idx_name, p); - error = pack_index_check(idx_name, p); git__free(idx_name); + git_mutex_unlock(&p->lock); + return error; } @@ -389,12 +402,12 @@ int git_packfile_unpack_header( * the maximum deflated object size is 2^137, which is just * insane, so we know won't exceed what we have been given. */ -// base = pack_window_open(p, w_curs, *curpos, &left); +/* base = pack_window_open(p, w_curs, *curpos, &left); */ base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left); if (base == NULL) return GIT_EBUFS; - ret = packfile_unpack_header1(&used, size_p, type_p, base, left); + ret = packfile_unpack_header1(&used, size_p, type_p, base, left); git_mwindow_close(w_curs); if (ret == GIT_EBUFS) return ret; @@ -786,23 +799,14 @@ git_off_t get_delta_base( * ***********************************************************/ -static struct git_pack_file *packfile_alloc(size_t extra) -{ - struct git_pack_file *p = git__calloc(1, sizeof(*p) + extra); - if (p != NULL) - p->mwf.fd = -1; - return p; -} - - void git_packfile_free(struct git_pack_file *p) { - assert(p); + if (!p) + return; cache_free(&p->bases); git_mwindow_free_all(&p->mwf); - git_mwindow_file_deregister(&p->mwf); if (p->mwf.fd != -1) p_close(p->mwf.fd); @@ -810,6 +814,8 @@ void git_packfile_free(struct git_pack_file *p) pack_index_free(p); git__free(p->bad_object_sha1); + + git_mutex_free(&p->lock); git__free(p); } @@ -820,17 +826,22 @@ static int packfile_open(struct git_pack_file *p) git_oid sha1; unsigned char *idx_sha1; - assert(p->index_map.data); - - if (!p->index_map.data && pack_index_open(p) < 0) + if (p->index_version == -1 && pack_index_open(p) < 0) return git_odb__error_notfound("failed to open packfile", NULL); + /* if mwf opened by another thread, return now */ + if (git_mutex_lock(&p->lock) < 0) + return packfile_error("failed to get lock for open"); + + if (p->mwf.fd >= 0) { + git_mutex_unlock(&p->lock); + return 0; + } + /* TODO: open with noatime */ p->mwf.fd = git_futils_open_ro(p->pack_name); - if (p->mwf.fd < 0) { - p->mwf.fd = -1; - return -1; - } + if (p->mwf.fd < 0) + goto cleanup; if (p_fstat(p->mwf.fd, &st) < 0 || git_mwindow_file_register(&p->mwf) < 0) @@ -871,44 +882,54 @@ static int packfile_open(struct git_pack_file *p) idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40; - if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) == 0) - return 0; + if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) != 0) + goto cleanup; + + git_mutex_unlock(&p->lock); + return 0; cleanup: giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name); + p_close(p->mwf.fd); p->mwf.fd = -1; + + git_mutex_unlock(&p->lock); + return -1; } -int git_packfile_check(struct git_pack_file **pack_out, const char *path) +int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) { struct stat st; struct git_pack_file *p; - size_t path_len; + size_t path_len = path ? strlen(path) : 0; *pack_out = NULL; - path_len = strlen(path); - p = packfile_alloc(path_len + 2); + + if (path_len < strlen(".idx")) + return git_odb__error_notfound("invalid packfile path", NULL); + + p = git__calloc(1, sizeof(*p) + path_len + 2); GITERR_CHECK_ALLOC(p); + memcpy(p->pack_name, path, path_len + 1); + /* * Make sure a corresponding .pack file exists and that * the index looks sane. */ - path_len -= strlen(".idx"); - if (path_len < 1) { - git__free(p); - return git_odb__error_notfound("invalid packfile path", NULL); - } + if (git__suffixcmp(path, ".idx") == 0) { + size_t root_len = path_len - strlen(".idx"); - memcpy(p->pack_name, path, path_len); + memcpy(p->pack_name + root_len, ".keep", sizeof(".keep")); + if (git_path_exists(p->pack_name) == true) + p->pack_keep = 1; - strcpy(p->pack_name + path_len, ".keep"); - if (git_path_exists(p->pack_name) == true) - p->pack_keep = 1; + memcpy(p->pack_name + root_len, ".pack", sizeof(".pack")); + path_len = path_len - strlen(".idx") + strlen(".pack"); + } - strcpy(p->pack_name + path_len, ".pack"); if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) { git__free(p); return git_odb__error_notfound("packfile not found", NULL); @@ -917,9 +938,13 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) /* ok, it looks sane as far as we can check without * actually mapping the pack file. */ + p->mwf.fd = -1; p->mwf.size = st.st_size; p->pack_local = 1; p->mtime = (git_time_t)st.st_mtime; + p->index_version = -1; + + git_mutex_init(&p->lock); /* see if we can parse the sha1 oid in the packfile name */ if (path_len < 40 || @@ -1034,12 +1059,11 @@ static int pack_entry_find_offset( *offset_out = 0; - if (index == NULL) { + if (p->index_version == -1) { int error; if ((error = pack_index_open(p)) < 0) return error; - assert(p->index_map.data); index = p->index_map.data; @@ -1099,6 +1123,7 @@ static int pack_entry_find_offset( return git_odb__error_notfound("failed to find offset for pack entry", short_oid); if (found > 1) return git_odb__error_ambiguous("found multiple offsets for pack entry"); + *offset_out = nth_packed_object_offset(p, pos); git_oid_fromraw(found_oid, current); @@ -1110,6 +1135,7 @@ static int pack_entry_find_offset( printf("found lo=%d %s\n", lo, hex_sha1); } #endif + return 0; } @@ -1128,7 +1154,7 @@ int git_pack_entry_find( if (len == GIT_OID_HEXSZ && p->num_bad_objects) { unsigned i; for (i = 0; i < p->num_bad_objects; i++) - if (git_oid_cmp(short_oid, &p->bad_object_sha1[i]) == 0) + if (git_oid__cmp(short_oid, &p->bad_object_sha1[i]) == 0) return packfile_error("bad object found in packfile"); } diff --git a/src/pack.h b/src/pack.h index 8d7e33dfe51..aeeac9ce15e 100644 --- a/src/pack.h +++ b/src/pack.h @@ -79,6 +79,7 @@ typedef struct { struct git_pack_file { git_mwindow_file mwf; git_map index_map; + git_mutex lock; /* protect updates to mwf and index_map */ uint32_t num_objects; uint32_t num_bad_objects; @@ -142,7 +143,8 @@ git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs, git_off_t delta_obj_offset); void git_packfile_free(struct git_pack_file *p); -int git_packfile_check(struct git_pack_file **pack_out, const char *path); +int git_packfile_alloc(struct git_pack_file **pack_out, const char *path); + int git_pack_entry_find( struct git_pack_entry *e, struct git_pack_file *p, diff --git a/src/pathspec.c b/src/pathspec.c index 7321802487f..d4eb12582c5 100644 --- a/src/pathspec.c +++ b/src/pathspec.c @@ -38,18 +38,20 @@ char *git_pathspec_prefix(const git_strarray *pathspec) } /* is there anything in the spec that needs to be filtered on */ -bool git_pathspec_is_interesting(const git_strarray *pathspec) +bool git_pathspec_is_empty(const git_strarray *pathspec) { - const char *str; + size_t i; - if (pathspec == NULL || pathspec->count == 0) - return false; - if (pathspec->count > 1) + if (pathspec == NULL) return true; - str = pathspec->strings[0]; - if (!str || !str[0] || (!str[1] && (str[0] == '*' || str[0] == '.'))) - return false; + for (i = 0; i < pathspec->count; ++i) { + const char *str = pathspec->strings[i]; + + if (str && str[0]) + return false; + } + return true; } @@ -61,7 +63,7 @@ int git_pathspec_init( memset(vspec, 0, sizeof(*vspec)); - if (!git_pathspec_is_interesting(strspec)) + if (git_pathspec_is_empty(strspec)) return 0; if (git_vector_init(vspec, strspec->count, NULL) < 0) @@ -138,7 +140,10 @@ bool git_pathspec_match_path( } git_vector_foreach(vspec, i, match) { - int result = use_strcmp(match->pattern, path) ? FNM_NOMATCH : 0; + int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : FNM_NOMATCH; + + if (result == FNM_NOMATCH) + result = use_strcmp(match->pattern, path) ? FNM_NOMATCH : 0; if (fnmatch_flags >= 0 && result == FNM_NOMATCH) result = p_fnmatch(match->pattern, path, fnmatch_flags); diff --git a/src/pathspec.h b/src/pathspec.h index c4456152033..43a94baadcb 100644 --- a/src/pathspec.h +++ b/src/pathspec.h @@ -16,7 +16,7 @@ extern char *git_pathspec_prefix(const git_strarray *pathspec); /* is there anything in the spec that needs to be filtered on */ -extern bool git_pathspec_is_interesting(const git_strarray *pathspec); +extern bool git_pathspec_is_empty(const git_strarray *pathspec); /* build a vector of fnmatch patterns to evaluate efficiently */ extern int git_pathspec_init( diff --git a/src/push.c b/src/push.c index 37f64181279..9b1e78c8eca 100644 --- a/src/push.c +++ b/src/push.c @@ -13,6 +13,7 @@ #include "remote.h" #include "vector.h" #include "push.h" +#include "tree.h" static int push_spec_rref_cmp(const void *a, const void *b) { @@ -98,19 +99,17 @@ static int check_lref(git_push *push, char *ref) /* lref must be resolvable to an existing object */ git_object *obj; int error = git_revparse_single(&obj, push->repo, ref); + git_object_free(obj); - if (error) { - if (error == GIT_ENOTFOUND) - giterr_set(GITERR_REFERENCE, - "src refspec '%s' does not match any existing object", ref); - else - giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); + if (!error) + return 0; - return -1; - } else - git_object_free(obj); - - return 0; + if (error == GIT_ENOTFOUND) + giterr_set(GITERR_REFERENCE, + "src refspec '%s' does not match any existing object", ref); + else + giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); + return -1; } static int parse_refspec(git_push *push, push_spec **spec, const char *str) @@ -178,9 +177,9 @@ int git_push_add_refspec(git_push *push, const char *refspec) int git_push_update_tips(git_push *push) { - git_refspec *fetch_spec = &push->remote->fetch; git_buf remote_ref_name = GIT_BUF_INIT; size_t i, j; + git_refspec *fetch_spec; push_spec *push_spec; git_reference *remote_ref; push_status *status; @@ -192,7 +191,8 @@ int git_push_update_tips(git_push *push) continue; /* Find the corresponding remote ref */ - if (!git_refspec_src_matches(fetch_spec, status->ref)) + fetch_spec = git_remote__matching_refspec(push->remote, status->ref); + if (!fetch_spec) continue; if ((error = git_refspec_transform_r(&remote_ref_name, fetch_spec, status->ref)) < 0) @@ -346,60 +346,162 @@ static int revwalk(git_vector *commits, git_push *push) return error == GIT_ITEROVER ? 0 : error; } -static int queue_objects(git_push *push) +static int enqueue_object( + const git_tree_entry *entry, + git_packbuilder *pb) { - git_vector commits; - git_oid *o; - unsigned int i; + switch (git_tree_entry_type(entry)) { + case GIT_OBJ_COMMIT: + return 0; + case GIT_OBJ_TREE: + return git_packbuilder_insert_tree(pb, &entry->oid); + default: + return git_packbuilder_insert(pb, &entry->oid, entry->filename); + } +} + +static int queue_differences( + git_tree *base, + git_tree *delta, + git_packbuilder *pb) +{ + git_tree *b_child = NULL, *d_child = NULL; + size_t b_length = git_tree_entrycount(base); + size_t d_length = git_tree_entrycount(delta); + size_t i = 0, j = 0; int error; - if (git_vector_init(&commits, 0, NULL) < 0) - return -1; + while (i < b_length && j < d_length) { + const git_tree_entry *b_entry = git_tree_entry_byindex(base, i); + const git_tree_entry *d_entry = git_tree_entry_byindex(delta, j); + int cmp = 0; - if ((error = revwalk(&commits, push)) < 0) - goto on_error; + if (!git_oid__cmp(&b_entry->oid, &d_entry->oid)) + goto loop; - if (!commits.length) { - git_vector_free(&commits); - return 0; /* nothing to do */ - } + cmp = strcmp(b_entry->filename, d_entry->filename); + + /* If the entries are both trees and they have the same name but are + * different, then we'll recurse after adding the right-hand entry */ + if (!cmp && + git_tree_entry__is_tree(b_entry) && + git_tree_entry__is_tree(d_entry)) { + /* Add the right-hand entry */ + if ((error = git_packbuilder_insert(pb, &d_entry->oid, + d_entry->filename)) < 0) + goto on_error; + + /* Acquire the subtrees and recurse */ + if ((error = git_tree_lookup(&b_child, + git_tree_owner(base), &b_entry->oid)) < 0 || + (error = git_tree_lookup(&d_child, + git_tree_owner(delta), &d_entry->oid)) < 0 || + (error = queue_differences(b_child, d_child, pb)) < 0) + goto on_error; - git_vector_foreach(&commits, i, o) { - if ((error = git_packbuilder_insert(push->pb, o, NULL)) < 0) + git_tree_free(b_child); b_child = NULL; + git_tree_free(d_child); d_child = NULL; + } + /* If the object is new or different in the right-hand tree, + * then enumerate it */ + else if (cmp >= 0 && + (error = enqueue_object(d_entry, pb)) < 0) goto on_error; + + loop: + if (cmp <= 0) i++; + if (cmp >= 0) j++; } - git_vector_foreach(&commits, i, o) { - git_object *obj; + /* Drain the right-hand tree of entries */ + for (; j < d_length; j++) + if ((error = enqueue_object(git_tree_entry_byindex(delta, j), pb)) < 0) + goto on_error; + + error = 0; + +on_error: + if (b_child) + git_tree_free(b_child); + + if (d_child) + git_tree_free(d_child); - if ((error = git_object_lookup(&obj, push->repo, o, GIT_OBJ_ANY)) < 0) + return error; +} + +static int queue_objects(git_push *push) +{ + git_vector commits = GIT_VECTOR_INIT; + git_oid *oid; + size_t i; + unsigned j; + int error; + + if ((error = revwalk(&commits, push)) < 0) + goto on_error; + + git_vector_foreach(&commits, i, oid) { + git_commit *parent = NULL, *commit; + git_tree *tree = NULL, *ptree = NULL; + size_t parentcount; + + if ((error = git_commit_lookup(&commit, push->repo, oid)) < 0) goto on_error; - switch (git_object_type(obj)) { - case GIT_OBJ_TAG: /* TODO: expect tags */ - case GIT_OBJ_COMMIT: + /* Insert the commit */ + if ((error = git_packbuilder_insert(push->pb, oid, NULL)) < 0) + goto loop_error; + + parentcount = git_commit_parentcount(commit); + + if (!parentcount) { if ((error = git_packbuilder_insert_tree(push->pb, - git_commit_tree_id((git_commit *)obj))) < 0) { - git_object_free(obj); - goto on_error; + git_commit_tree_id(commit))) < 0) + goto loop_error; + } else { + if ((error = git_tree_lookup(&tree, push->repo, + git_commit_tree_id(commit))) < 0 || + (error = git_packbuilder_insert(push->pb, + git_commit_tree_id(commit), NULL)) < 0) + goto loop_error; + + /* For each parent, add the items which are different */ + for (j = 0; j < parentcount; j++) { + if ((error = git_commit_parent(&parent, commit, j)) < 0 || + (error = git_commit_tree(&ptree, parent)) < 0 || + (error = queue_differences(ptree, tree, push->pb)) < 0) + goto loop_error; + + git_tree_free(ptree); ptree = NULL; + git_commit_free(parent); parent = NULL; } - break; - case GIT_OBJ_TREE: - case GIT_OBJ_BLOB: - default: - git_object_free(obj); - giterr_set(GITERR_INVALID, "Given object type invalid"); - error = -1; - goto on_error; } - git_object_free(obj); + + error = 0; + + loop_error: + if (tree) + git_tree_free(tree); + + if (ptree) + git_tree_free(ptree); + + if (parent) + git_commit_free(parent); + + git_commit_free(commit); + + if (error < 0) + goto on_error; } + error = 0; on_error: - git_vector_foreach(&commits, i, o) { - git__free(o); - } + git_vector_foreach(&commits, i, oid) + git__free(oid); + git_vector_free(&commits); return error; } diff --git a/src/refdb.c b/src/refdb.c index 0d206434324..33a1934d15d 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -7,15 +7,16 @@ #include "common.h" #include "posix.h" + #include "git2/object.h" #include "git2/refs.h" #include "git2/refdb.h" +#include "git2/sys/refdb_backend.h" + #include "hash.h" #include "refdb.h" #include "refs.h" -#include "git2/refdb_backend.h" - int git_refdb_new(git_refdb **out, git_repository *repo) { git_refdb *db; @@ -45,7 +46,7 @@ int git_refdb_open(git_refdb **out, git_repository *repo) return -1; /* Add the default (filesystem) backend */ - if (git_refdb_backend_fs(&dir, repo, db) < 0) { + if (git_refdb_backend_fs(&dir, repo) < 0) { git_refdb_free(db); return -1; } @@ -57,15 +58,19 @@ int git_refdb_open(git_refdb **out, git_repository *repo) return 0; } -int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) +static void refdb_free_backend(git_refdb *db) { if (db->backend) { - if(db->backend->free) + if (db->backend->free) db->backend->free(db->backend); else git__free(db->backend); } +} +int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) +{ + refdb_free_backend(db); db->backend = backend; return 0; @@ -74,24 +79,25 @@ int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) int git_refdb_compress(git_refdb *db) { assert(db); - - if (db->backend->compress) { + + if (db->backend->compress) return db->backend->compress(db->backend); - } - + return 0; } +static void refdb_free(git_refdb *db) +{ + refdb_free_backend(db); + git__free(db); +} + void git_refdb_free(git_refdb *db) { - if (db->backend) { - if(db->backend->free) - db->backend->free(db->backend); - else - git__free(db->backend); - } + if (db == NULL) + return; - git__free(db); + GIT_REFCOUNT_DEC(db, refdb_free); } int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name) @@ -103,9 +109,19 @@ int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name) int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) { - assert(db && db->backend && ref_name); + git_reference *ref; + int error; + + assert(db && db->backend && out && ref_name); - return db->backend->lookup(out, db->backend, ref_name); + if (!(error = db->backend->lookup(&ref, db->backend, ref_name))) { + ref->db = db; + *out = ref; + } else { + *out = NULL; + } + + return error; } int git_refdb_foreach( diff --git a/src/refdb.h b/src/refdb.h index 0969711b92d..047113ac847 100644 --- a/src/refdb.h +++ b/src/refdb.h @@ -41,6 +41,6 @@ int git_refdb_foreach_glob( int git_refdb_write(git_refdb *refdb, const git_reference *ref); -int git_refdb_delete(struct git_refdb *refdb, const git_reference *ref); +int git_refdb_delete(git_refdb *refdb, const git_reference *ref); #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index f00bd72a0c4..c0a32bae747 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -11,14 +11,14 @@ #include "fileops.h" #include "pack.h" #include "reflog.h" -#include "config.h" #include "refdb.h" #include "refdb_fs.h" #include #include #include -#include +#include +#include GIT__USE_STRMAP; @@ -26,8 +26,15 @@ GIT__USE_STRMAP; #define MAX_NESTING_LEVEL 10 enum { - GIT_PACKREF_HAS_PEEL = 1, - GIT_PACKREF_WAS_LOOSE = 2 + PACKREF_HAS_PEEL = 1, + PACKREF_WAS_LOOSE = 2, + PACKREF_CANNOT_PEEL = 4 +}; + +enum { + PEELING_NONE = 0, + PEELING_STANDARD, + PEELING_FULL }; struct packref { @@ -41,10 +48,10 @@ typedef struct refdb_fs_backend { git_refdb_backend parent; git_repository *repo; - const char *path; - git_refdb *refdb; + char *path; git_refcache refcache; + int peeling_mode; } refdb_fs_backend; static int reference_read( @@ -62,7 +69,7 @@ static int reference_read( /* Determine the full path of the file */ if (git_buf_joinpath(&path, repo_path, ref_name) < 0) return -1; - + result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, NULL, updated); git_buf_free(&path); @@ -133,10 +140,6 @@ static int packed_parse_peel( if (tag_ref == NULL) goto corrupt; - /* Ensure reference is a tag */ - if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0) - goto corrupt; - if (buffer + GIT_OID_HEXSZ > buffer_end) goto corrupt; @@ -155,6 +158,7 @@ static int packed_parse_peel( goto corrupt; } + tag_ref->flags |= PACKREF_HAS_PEEL; *buffer_out = buffer; return 0; @@ -175,7 +179,7 @@ static int packed_load(refdb_fs_backend *backend) ref_cache->packfile = git_strmap_alloc(); GITERR_CHECK_ALLOC(ref_cache->packfile); } - + result = reference_read(&packfile, &ref_cache->packfile_time, backend->path, GIT_PACKEDREFS_FILE, &updated); @@ -193,7 +197,7 @@ static int packed_load(refdb_fs_backend *backend) if (result < 0) return -1; - + if (!updated) return 0; @@ -206,6 +210,30 @@ static int packed_load(refdb_fs_backend *backend) buffer_start = (const char *)packfile.ptr; buffer_end = (const char *)(buffer_start) + packfile.size; + backend->peeling_mode = PEELING_NONE; + + if (buffer_start[0] == '#') { + static const char *traits_header = "# pack-refs with: "; + + if (git__prefixcmp(buffer_start, traits_header) == 0) { + char *traits = (char *)buffer_start + strlen(traits_header); + char *traits_end = strchr(traits, '\n'); + + if (traits_end == NULL) + goto parse_failed; + + *traits_end = '\0'; + + if (strstr(traits, " fully-peeled ") != NULL) { + backend->peeling_mode = PEELING_FULL; + } else if (strstr(traits, " peeled ") != NULL) { + backend->peeling_mode = PEELING_STANDARD; + } + + buffer_start = traits_end + 1; + } + } + while (buffer_start < buffer_end && buffer_start[0] == '#') { buffer_start = strchr(buffer_start, '\n'); if (buffer_start == NULL) @@ -224,6 +252,10 @@ static int packed_load(refdb_fs_backend *backend) if (buffer_start[0] == '^') { if (packed_parse_peel(ref, &buffer_start, buffer_end) < 0) goto parse_failed; + } else if (backend->peeling_mode == PEELING_FULL || + (backend->peeling_mode == PEELING_STANDARD && + git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) == 0)) { + ref->flags |= PACKREF_CANNOT_PEEL; } git_strmap_insert(ref_cache->packfile, ref->name, ref, err); @@ -241,7 +273,7 @@ static int packed_load(refdb_fs_backend *backend) return -1; } -static int loose_parse_oid(git_oid *oid, git_buf *file_content) +static int loose_parse_oid(git_oid *oid, const char *filename, git_buf *file_content) { size_t len; const char *str; @@ -263,7 +295,7 @@ static int loose_parse_oid(git_oid *oid, git_buf *file_content) return 0; corrupted: - giterr_set(GITERR_REFERENCE, "Corrupted loose reference file"); + giterr_set(GITERR_REFERENCE, "Corrupted loose reference file: %s", filename); return -1; } @@ -290,13 +322,13 @@ static int loose_lookup_to_packfile( memcpy(ref->name, name, name_len); ref->name[name_len] = 0; - if (loose_parse_oid(&ref->oid, &ref_file) < 0) { + if (loose_parse_oid(&ref->oid, name, &ref_file) < 0) { git_buf_free(&ref_file); git__free(ref); return -1; } - ref->flags = GIT_PACKREF_WAS_LOOSE; + ref->flags = PACKREF_WAS_LOOSE; *ref_out = ref; git_buf_free(&ref_file); @@ -430,12 +462,12 @@ static int loose_lookup( goto done; } - *out = git_reference__alloc(backend->refdb, ref_name, NULL, target); + *out = git_reference__alloc_symbolic(ref_name, target); } else { - if ((error = loose_parse_oid(&oid, &ref_file)) < 0) + if ((error = loose_parse_oid(&oid, ref_name, &ref_file)) < 0) goto done; - - *out = git_reference__alloc(backend->refdb, ref_name, &oid, NULL); + + *out = git_reference__alloc(ref_name, &oid, NULL); } if (*out == NULL) @@ -456,19 +488,19 @@ static int packed_map_entry( if (packed_load(backend) < 0) return -1; - + /* Look up on the packfile */ packfile_refs = backend->refcache.packfile; *pos = git_strmap_lookup_index(packfile_refs, ref_name); - + if (!git_strmap_valid_index(packfile_refs, *pos)) { giterr_set(GITERR_REFERENCE, "Reference '%s' not found", ref_name); return GIT_ENOTFOUND; } *entry = git_strmap_value_at(packfile_refs, *pos); - + return 0; } @@ -480,13 +512,14 @@ static int packed_lookup( struct packref *entry; khiter_t pos; int error = 0; - + if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0) return error; - if ((*out = git_reference__alloc(backend->refdb, ref_name, &entry->oid, NULL)) == NULL) + if ((*out = git_reference__alloc(ref_name, + &entry->oid, &entry->peel)) == NULL) return -1; - + return 0; } @@ -582,7 +615,7 @@ static int refdb_fs_backend__foreach( git_buf refs_path = GIT_BUF_INIT; const char *ref_name; void *ref = NULL; - + GIT_UNUSED(ref); assert(_backend); @@ -590,7 +623,7 @@ static int refdb_fs_backend__foreach( if (packed_load(backend) < 0) return -1; - + /* list all the packed references first */ if (list_type & GIT_REF_OID) { git_strmap_foreach(backend->refcache.packfile, ref_name, ref, { @@ -678,14 +711,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) { git_object *object; - if (ref->flags & GIT_PACKREF_HAS_PEEL) - return 0; - - /* - * Only applies to tags, i.e. references - * in the /refs/tags folder - */ - if (git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) != 0) + if (ref->flags & PACKREF_HAS_PEEL || ref->flags & PACKREF_CANNOT_PEEL) return 0; /* @@ -706,7 +732,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) * Find the object pointed at by this tag */ git_oid_cpy(&ref->peel, git_tag_target_id(tag)); - ref->flags |= GIT_PACKREF_HAS_PEEL; + ref->flags |= PACKREF_HAS_PEEL; /* * The reference has now cached the resolved OID, and is @@ -739,7 +765,7 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file) * This obviously only applies to tags. * The required peels have already been loaded into `ref->peel_target`. */ - if (ref->flags & GIT_PACKREF_HAS_PEEL) { + if (ref->flags & PACKREF_HAS_PEEL) { char peel[GIT_OID_HEXSZ + 1]; git_oid_fmt(peel, &ref->peel); peel[GIT_OID_HEXSZ] = 0; @@ -776,7 +802,7 @@ static int packed_remove_loose( for (i = 0; i < packing_list->length; ++i) { struct packref *ref = git_vector_get(packing_list, i); - if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0) + if ((ref->flags & PACKREF_WAS_LOOSE) == 0) continue; if (git_buf_joinpath(&full_path, backend->path, ref->name) < 0) @@ -924,7 +950,7 @@ static int refdb_fs_backend__delete( repo = backend->repo; /* If a loose reference exists, remove it from the filesystem */ - + if (git_buf_joinpath(&loose_path, repo->path_repository, ref->name) < 0) return -1; @@ -932,7 +958,7 @@ static int refdb_fs_backend__delete( error = p_unlink(loose_path.ptr); loose_deleted = 1; } - + git_buf_free(&loose_path); if (error != 0) @@ -946,7 +972,7 @@ static int refdb_fs_backend__delete( error = packed_write(backend); } - + if (pack_error == GIT_ENOTFOUND) error = loose_deleted ? 0 : GIT_ENOTFOUND; else @@ -993,22 +1019,65 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend) backend = (refdb_fs_backend *)_backend; refcache_free(&backend->refcache); + git__free(backend->path); git__free(backend); } +static int setup_namespace(git_buf *path, git_repository *repo) +{ + char *parts, *start, *end; + + /* Load the path to the repo first */ + git_buf_puts(path, repo->path_repository); + + /* if the repo is not namespaced, nothing else to do */ + if (repo->namespace == NULL) + return 0; + + parts = end = git__strdup(repo->namespace); + if (parts == NULL) + return -1; + + /** + * From `man gitnamespaces`: + * namespaces which include a / will expand to a hierarchy + * of namespaces; for example, GIT_NAMESPACE=foo/bar will store + * refs under refs/namespaces/foo/refs/namespaces/bar/ + */ + while ((start = git__strsep(&end, "/")) != NULL) { + git_buf_printf(path, "refs/namespaces/%s/", start); + } + + git_buf_printf(path, "refs/namespaces/%s/refs", end); + free(parts); + + /* Make sure that the folder with the namespace exists */ + if (git_futils_mkdir_r(git_buf_cstr(path), repo->path_repository, 0777) < 0) + return -1; + + /* Return the root of the namespaced path, i.e. without the trailing '/refs' */ + git_buf_rtruncate_at_char(path, '/'); + return 0; +} + int git_refdb_backend_fs( git_refdb_backend **backend_out, - git_repository *repository, - git_refdb *refdb) + git_repository *repository) { + git_buf path = GIT_BUF_INIT; refdb_fs_backend *backend; backend = git__calloc(1, sizeof(refdb_fs_backend)); GITERR_CHECK_ALLOC(backend); backend->repo = repository; - backend->path = repository->path_repository; - backend->refdb = refdb; + + if (setup_namespace(&path, repository) < 0) { + git__free(backend); + return -1; + } + + backend->path = git_buf_detach(&path); backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; diff --git a/src/refs.c b/src/refs.c index dde2f51a9cc..b85a2e8288a 100644 --- a/src/refs.c +++ b/src/refs.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include GIT__USE_STRMAP; @@ -31,37 +31,58 @@ enum { GIT_PACKREF_WAS_LOOSE = 2 }; +static git_reference *alloc_ref(const char *name) +{ + git_reference *ref; + size_t namelen = strlen(name); + + if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) + return NULL; + + memcpy(ref->name, name, namelen + 1); + + return ref; +} + +git_reference *git_reference__alloc_symbolic( + const char *name, const char *target) +{ + git_reference *ref; + + assert(name && target); + + ref = alloc_ref(name); + if (!ref) + return NULL; + + ref->type = GIT_REF_SYMBOLIC; + + if ((ref->target.symbolic = git__strdup(target)) == NULL) { + git__free(ref); + return NULL; + } + + return ref; +} git_reference *git_reference__alloc( - git_refdb *refdb, const char *name, const git_oid *oid, - const char *symbolic) + const git_oid *peel) { git_reference *ref; - size_t namelen; - - assert(refdb && name && ((oid && !symbolic) || (!oid && symbolic))); - namelen = strlen(name); + assert(name && oid); - if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) + ref = alloc_ref(name); + if (!ref) return NULL; - if (oid) { - ref->type = GIT_REF_OID; - git_oid_cpy(&ref->target.oid, oid); - } else { - ref->type = GIT_REF_SYMBOLIC; + ref->type = GIT_REF_OID; + git_oid_cpy(&ref->target.oid, oid); - if ((ref->target.symbolic = git__strdup(symbolic)) == NULL) { - git__free(ref); - return NULL; - } - } - - ref->db = refdb; - memcpy(ref->name, name, namelen + 1); + if (peel != NULL) + git_oid_cpy(&ref->peel, peel); return ref; } @@ -71,13 +92,8 @@ void git_reference_free(git_reference *reference) if (reference == NULL) return; - if (reference->type == GIT_REF_SYMBOLIC) { + if (reference->type == GIT_REF_SYMBOLIC) git__free(reference->target.symbolic); - reference->target.symbolic = NULL; - } - - reference->db = NULL; - reference->type = GIT_REF_INVALID; git__free(reference); } @@ -238,10 +254,10 @@ int git_reference_lookup_resolved( max_nesting = MAX_NESTING_LEVEL; else if (max_nesting < 0) max_nesting = DEFAULT_NESTING_LEVEL; - + strncpy(scan_name, name, GIT_REFNAME_MAX); scan_type = GIT_REF_SYMBOLIC; - + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) return -1; @@ -259,7 +275,7 @@ int git_reference_lookup_resolved( if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0) return error; - + scan_type = ref->type; } @@ -305,6 +321,16 @@ const git_oid *git_reference_target(const git_reference *ref) return &ref->target.oid; } +const git_oid *git_reference_target_peel(const git_reference *ref) +{ + assert(ref); + + if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel)) + return NULL; + + return &ref->peel; +} + const char *git_reference_symbolic_target(const git_reference *ref) { assert(ref); @@ -327,7 +353,7 @@ static int reference__create( git_refdb *refdb; git_reference *ref = NULL; int error = 0; - + if (ref_out) *ref_out = NULL; @@ -335,15 +361,22 @@ static int reference__create( (error = reference_can_write(repo, normalized, NULL, force)) < 0 || (error = git_repository_refdb__weakptr(&refdb, repo)) < 0) return error; - - if ((ref = git_reference__alloc(refdb, name, oid, symbolic)) == NULL) - return -1; + + if (oid != NULL) { + assert(symbolic == NULL); + ref = git_reference__alloc(name, oid, NULL); + } else { + ref = git_reference__alloc_symbolic(name, symbolic); + } + + GITERR_CHECK_ALLOC(ref); + ref->db = refdb; if ((error = git_refdb_write(refdb, ref)) < 0) { git_reference_free(ref); return error; } - + if (ref_out == NULL) git_reference_free(ref); else @@ -363,17 +396,17 @@ int git_reference_create( int error = 0; assert(repo && name && oid); - + /* Sanity check the reference being created - target must exist. */ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; - + if (!git_odb_exists(odb, oid)) { giterr_set(GITERR_REFERENCE, "Target OID for the reference doesn't exist on the repository"); return -1; } - + return reference__create(ref_out, repo, name, oid, NULL, force); } @@ -388,7 +421,7 @@ int git_reference_symbolic_create( int error = 0; assert(repo && name && target); - + if ((error = git_reference__normalize_name_lax( normalized, sizeof(normalized), target)) < 0) return error; @@ -402,7 +435,7 @@ int git_reference_set_target( const git_oid *id) { assert(out && ref && id); - + if (ref->type != GIT_REF_OID) { giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference"); return -1; @@ -417,13 +450,13 @@ int git_reference_symbolic_set_target( const char *target) { assert(out && ref && target); - + if (ref->type != GIT_REF_SYMBOLIC) { giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference"); return -1; } - + return git_reference_symbolic_create(out, ref->db->repo, ref->name, target, 1); } @@ -437,17 +470,16 @@ int git_reference_rename( char normalized[GIT_REFNAME_MAX]; bool should_head_be_updated = false; git_reference *result = NULL; - git_oid *oid; - const char *symbolic; int error = 0; int reference_has_log; - + *out = NULL; normalization_flags = ref->type == GIT_REF_SYMBOLIC ? GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL; - if ((error = git_reference_normalize_name(normalized, sizeof(normalized), new_name, normalization_flags)) < 0 || + if ((error = git_reference_normalize_name( + normalized, sizeof(normalized), new_name, normalization_flags)) < 0 || (error = reference_can_write(ref->db->repo, normalized, ref->name, force)) < 0) return error; @@ -455,16 +487,18 @@ int git_reference_rename( * Create the new reference. */ if (ref->type == GIT_REF_OID) { - oid = &ref->target.oid; - symbolic = NULL; + result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel); + } else if (ref->type == GIT_REF_SYMBOLIC) { + result = git_reference__alloc_symbolic(new_name, ref->target.symbolic); } else { - oid = NULL; - symbolic = ref->target.symbolic; + assert(0); } - - if ((result = git_reference__alloc(ref->db, new_name, oid, symbolic)) == NULL) + + if (result == NULL) return -1; + result->db = ref->db; + /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) goto on_error; @@ -474,11 +508,11 @@ int git_reference_rename( /* Now delete the old ref and save the new one. */ if ((error = git_refdb_delete(ref->db, ref)) < 0) goto on_error; - + /* Save the new reference. */ if ((error = git_refdb_write(ref->db, result)) < 0) goto rollback; - + /* Update HEAD it was poiting to the reference being renamed. */ if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); @@ -509,11 +543,17 @@ int git_reference_rename( int git_reference_resolve(git_reference **ref_out, const git_reference *ref) { - if (ref->type == GIT_REF_OID) + switch (git_reference_type(ref)) { + case GIT_REF_OID: return git_reference_lookup(ref_out, ref->db->repo, ref->name); - else - return git_reference_lookup_resolved(ref_out, ref->db->repo, - ref->target.symbolic, -1); + + case GIT_REF_SYMBOLIC: + return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); + + default: + giterr_set(GITERR_REFERENCE, "Invalid reference"); + return -1; + } } int git_reference_foreach( @@ -712,6 +752,7 @@ int git_reference__normalize_name( goto cleanup; if ((segments_count == 1 ) && + !(flags & GIT_REF_FORMAT_REFSPEC_SHORTHAND) && !(is_all_caps_and_underscore(name, (size_t)segment_len) || ((flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) goto cleanup; @@ -778,16 +819,20 @@ int git_reference__normalize_name_lax( int git_reference_cmp(git_reference *ref1, git_reference *ref2) { + git_ref_t type1, type2; assert(ref1 && ref2); + type1 = git_reference_type(ref1); + type2 = git_reference_type(ref2); + /* let's put symbolic refs before OIDs */ - if (ref1->type != ref2->type) - return (ref1->type == GIT_REF_SYMBOLIC) ? -1 : 1; + if (type1 != type2) + return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1; - if (ref1->type == GIT_REF_SYMBOLIC) + if (type1 == GIT_REF_SYMBOLIC) return strcmp(ref1->target.symbolic, ref2->target.symbolic); - return git_oid_cmp(&ref1->target.oid, &ref2->target.oid); + return git_oid__cmp(&ref1->target.oid, &ref2->target.oid); } static int reference__update_terminal( @@ -801,7 +846,7 @@ static int reference__update_terminal( if (nesting > MAX_NESTING_LEVEL) return GIT_ENOTFOUND; - + error = git_reference_lookup(&ref, repo, ref_name); /* If we haven't found the reference at all, create a new reference. */ @@ -809,10 +854,10 @@ static int reference__update_terminal( giterr_clear(); return git_reference_create(NULL, repo, ref_name, oid, 0); } - + if (error < 0) return error; - + /* If the ref is a symbolic reference, follow its target. */ if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { error = reference__update_terminal(repo, git_reference_symbolic_target(ref), oid, @@ -822,7 +867,7 @@ static int reference__update_terminal( git_reference_free(ref); error = git_reference_create(NULL, repo, ref_name, oid, 1); } - + return error; } @@ -905,15 +950,6 @@ static int peel_error(int error, git_reference *ref, const char* msg) return error; } -static int reference_target(git_object **object, git_reference *ref) -{ - const git_oid *oid; - - oid = git_reference_target(ref); - - return git_object_lookup(object, git_reference_owner(ref), oid, GIT_OBJ_ANY); -} - int git_reference_peel( git_object **peeled, git_reference *ref, @@ -925,22 +961,37 @@ int git_reference_peel( assert(ref); - if ((error = git_reference_resolve(&resolved, ref)) < 0) - return peel_error(error, ref, "Cannot resolve reference"); + if (ref->type == GIT_REF_OID) { + resolved = ref; + } else { + if ((error = git_reference_resolve(&resolved, ref)) < 0) + return peel_error(error, ref, "Cannot resolve reference"); + } + + if (!git_oid_iszero(&resolved->peel)) { + error = git_object_lookup(&target, + git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY); + } else { + error = git_object_lookup(&target, + git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY); + } - if ((error = reference_target(&target, resolved)) < 0) { + if (error < 0) { peel_error(error, ref, "Cannot retrieve reference target"); goto cleanup; } if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG) - error = git_object__dup(peeled, target); + error = git_object_dup(peeled, target); else error = git_object_peel(peeled, target, target_type); cleanup: git_object_free(target); - git_reference_free(resolved); + + if (resolved != ref) + git_reference_free(resolved); + return error; } diff --git a/src/refs.h b/src/refs.h index 7d63c3fbdae..f487ee3fc39 100644 --- a/src/refs.h +++ b/src/refs.h @@ -13,6 +13,7 @@ #include "git2/refdb.h" #include "strmap.h" #include "buffer.h" +#include "oid.h" #define GIT_REFS_DIR "refs/" #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/" @@ -25,7 +26,7 @@ #define GIT_SYMREF "ref: " #define GIT_PACKEDREFS_FILE "packed-refs" -#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled " +#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled fully-peeled " #define GIT_PACKEDREFS_FILE_MODE 0666 #define GIT_HEAD_FILE "HEAD" @@ -49,14 +50,14 @@ struct git_reference { git_refdb *db; - git_ref_t type; union { git_oid oid; char *symbolic; } target; - + + git_oid peel; char name[0]; }; diff --git a/src/refspec.c b/src/refspec.c index a51b0cfab2b..a907df84c67 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -25,6 +25,7 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) assert(refspec && input); memset(refspec, 0x0, sizeof(git_refspec)); + refspec->push = !is_fetch; lhs = input; if (*lhs == '+') { @@ -59,7 +60,7 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) refspec->pattern = is_glob; refspec->src = git__strndup(lhs, llen); - flags = GIT_REF_FORMAT_ALLOW_ONELEVEL + flags = GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND | (is_glob ? GIT_REF_FORMAT_REFSPEC_PATTERN : 0); if (is_fetch) { @@ -119,6 +120,9 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) } } + refspec->string = git__strdup(input); + GITERR_CHECK_ALLOC(refspec->string); + return 0; invalid: @@ -132,6 +136,7 @@ void git_refspec__free(git_refspec *refspec) git__free(refspec->src); git__free(refspec->dst); + git__free(refspec->string); } const char *git_refspec_src(const git_refspec *refspec) @@ -144,6 +149,11 @@ const char *git_refspec_dst(const git_refspec *refspec) return refspec == NULL ? NULL : refspec->dst; } +const char *git_refspec_string(const git_refspec *refspec) +{ + return refspec == NULL ? NULL : refspec->string; +} + int git_refspec_force(const git_refspec *refspec) { assert(refspec); @@ -264,3 +274,10 @@ int git_refspec_is_wildcard(const git_refspec *spec) return (spec->src[strlen(spec->src) - 1] == '*'); } + +git_direction git_refspec_direction(const git_refspec *spec) +{ + assert(spec); + + return spec->push; +} diff --git a/src/refspec.h b/src/refspec.h index a7a4dd83423..44d484c7b96 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -11,11 +11,13 @@ #include "buffer.h" struct git_refspec { - struct git_refspec *next; + char *string; char *src; char *dst; unsigned int force :1, + push : 1, pattern :1, + dwim :1, matching :1; }; diff --git a/src/remote.c b/src/remote.c index a6f62d6a525..6eaaf8b49c0 100644 --- a/src/remote.c +++ b/src/remote.c @@ -8,6 +8,7 @@ #include "git2/config.h" #include "git2/types.h" #include "git2/oid.h" +#include "git2/net.h" #include "config.h" #include "repository.h" @@ -19,15 +20,26 @@ #include -static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var, bool is_fetch) +static int add_refspec(git_remote *remote, const char *string, bool is_fetch) { - int error; - const char *val; + git_refspec *spec; - if ((error = git_config_get_string(&val, cfg, var)) < 0) - return error; + spec = git__calloc(1, sizeof(git_refspec)); + GITERR_CHECK_ALLOC(spec); + + if (git_refspec__parse(spec, string, is_fetch) < 0) { + git__free(spec); + return -1; + } - return git_refspec__parse(refspec, val, is_fetch); + spec->push = !is_fetch; + if (git_vector_insert(&remote->refspecs, spec) < 0) { + git_refspec__free(spec); + git__free(spec); + return -1; + } + + return 0; } static int download_tags_value(git_remote *remote, git_config *cfg) @@ -99,7 +111,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n } if (fetch != NULL) { - if (git_refspec__parse(&remote->fetch, fetch, true) < 0) + if (add_refspec(remote, fetch, true) < 0) goto on_error; } @@ -186,6 +198,18 @@ int git_remote_create_inmemory(git_remote **out, git_repository *repo, const cha return 0; } +struct refspec_cb_data { + git_remote *remote; + int fetch; +}; + +static int refspec_cb(const git_config_entry *entry, void *payload) +{ + const struct refspec_cb_data *data = (struct refspec_cb_data *)payload; + + return add_refspec(data->remote, entry->value, data->fetch); +} + int git_remote_load(git_remote **out, git_repository *repo, const char *name) { git_remote *remote; @@ -193,6 +217,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) const char *val; int error = 0; git_config *config; + struct refspec_cb_data data; + assert(out && repo && name); @@ -211,7 +237,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); - if (git_vector_init(&remote->refs, 32, NULL) < 0) { + if ((git_vector_init(&remote->refs, 32, NULL) < 0) || + (git_vector_init(&remote->refspecs, 2, NULL))) { error = -1; goto cleanup; } @@ -262,7 +289,9 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } - error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf), true); + data.remote = remote; + data.fetch = true; + error = git_config_get_multivar(config, git_buf_cstr(&buf), NULL, refspec_cb, &data); if (error == GIT_ENOTFOUND) error = 0; @@ -277,7 +306,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } - error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf), false); + data.fetch = false; + error = git_config_get_multivar(config, git_buf_cstr(&buf), NULL, refspec_cb, &data); if (error == GIT_ENOTFOUND) error = 0; @@ -300,36 +330,44 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) return error; } -static int update_config_refspec( - git_config *config, - const char *remote_name, - const git_refspec *refspec, - int git_direction) +static int update_config_refspec(const git_remote *remote, git_config *config, int direction) { - git_buf name = GIT_BUF_INIT, value = GIT_BUF_INIT; + git_buf name = GIT_BUF_INIT; + int push; + const char *dir; + size_t i; int error = -1; - if (refspec->src == NULL || refspec->dst == NULL) - return 0; + push = direction == GIT_DIRECTION_PUSH; + dir = push ? "push" : "fetch"; - if (git_buf_printf( - &name, - "remote.%s.%s", - remote_name, - git_direction == GIT_DIRECTION_FETCH ? "fetch" : "push") < 0) - goto cleanup; + if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0) + return -1; - if (git_refspec__serialize(&value, refspec) < 0) - goto cleanup; + /* Clear out the existing config */ + do { + error = git_config_delete_entry(config, git_buf_cstr(&name)); + } while (!error); - error = git_config_set_string( - config, - git_buf_cstr(&name), - git_buf_cstr(&value)); + if (error != GIT_ENOTFOUND) + return error; + + for (i = 0; i < remote->refspecs.length; i++) { + git_refspec *spec = git_vector_get(&remote->refspecs, i); + + if (spec->push != push) + continue; + + if ((error = git_config_set_multivar(config, git_buf_cstr(&name), "", spec->string)) < 0) { + goto cleanup; + } + } + + giterr_clear(); + error = 0; cleanup: git_buf_free(&name); - git_buf_free(&value); return error; } @@ -383,19 +421,11 @@ int git_remote_save(const git_remote *remote) } } - if (update_config_refspec( - config, - remote->name, - &remote->fetch, - GIT_DIRECTION_FETCH) < 0) - goto on_error; + if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0) + goto on_error; - if (update_config_refspec( - config, - remote->name, - &remote->push, - GIT_DIRECTION_PUSH) < 0) - goto on_error; + if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0) + goto on_error; /* * What action to take depends on the old and new values. This @@ -482,49 +512,6 @@ int git_remote_set_pushurl(git_remote *remote, const char* url) return 0; } -int git_remote_set_fetchspec(git_remote *remote, const char *spec) -{ - git_refspec refspec; - - assert(remote && spec); - - if (git_refspec__parse(&refspec, spec, true) < 0) - return -1; - - git_refspec__free(&remote->fetch); - memcpy(&remote->fetch, &refspec, sizeof(git_refspec)); - - return 0; -} - -const git_refspec *git_remote_fetchspec(const git_remote *remote) -{ - assert(remote); - return &remote->fetch; -} - -int git_remote_set_pushspec(git_remote *remote, const char *spec) -{ - git_refspec refspec; - - assert(remote && spec); - - if (git_refspec__parse(&refspec, spec, false) < 0) - return -1; - - git_refspec__free(&remote->push); - remote->push.src = refspec.src; - remote->push.dst = refspec.dst; - - return 0; -} - -const git_refspec *git_remote_pushspec(const git_remote *remote) -{ - assert(remote); - return &remote->push; -} - const char* git_remote__urlfordirection(git_remote *remote, int direction) { assert(remote); @@ -586,11 +573,6 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) { assert(remote); - if (!git_remote_connected(remote)) { - giterr_set(GITERR_NET, "The remote is not connected"); - return -1; - } - return remote->transport->ls(remote->transport, list_cb, payload); } @@ -651,28 +633,105 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur return 0; } +static int store_refs(git_remote_head *head, void *payload) +{ + git_vector *refs = (git_vector *)payload; + + return git_vector_insert(refs, head); +} + +static int dwim_refspecs(git_vector *refspecs, git_vector *refs) +{ + git_buf buf = GIT_BUF_INIT; + git_refspec *spec; + size_t i, j, pos; + git_remote_head key; + + const char* formatters[] = { + GIT_REFS_DIR "%s", + GIT_REFS_TAGS_DIR "%s", + GIT_REFS_HEADS_DIR "%s", + NULL + }; + + git_vector_foreach(refspecs, i, spec) { + if (spec->dwim) + continue; + + /* shorthand on the lhs */ + if (git__prefixcmp(spec->src, GIT_REFS_DIR)) { + for (j = 0; formatters[j]; j++) { + git_buf_clear(&buf); + if (git_buf_printf(&buf, formatters[j], spec->src) < 0) + return -1; + + key.name = (char *) git_buf_cstr(&buf); + if (!git_vector_search(&pos, refs, &key)) { + /* we found something to match the shorthand, set src to that */ + git__free(spec->src); + spec->src = git_buf_detach(&buf); + } + } + } + + if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) { + /* if it starts with "remotes" then we just prepend "refs/" */ + if (!git__prefixcmp(spec->dst, "remotes/")) { + git_buf_puts(&buf, GIT_REFS_DIR); + } else { + git_buf_puts(&buf, GIT_REFS_HEADS_DIR); + } + + if (git_buf_puts(&buf, spec->dst) < 0) + return -1; + + git__free(spec->dst); + spec->dst = git_buf_detach(&buf); + } + + spec->dwim = 1; + } + + git_buf_free(&buf); + return 0; +} + +static int remote_head_cmp(const void *_a, const void *_b) +{ + const git_remote_head *a = (git_remote_head *) _a; + const git_remote_head *b = (git_remote_head *) _b; + + return git__strcmp_cb(a->name, b->name); +} + int git_remote_download( git_remote *remote, git_transfer_progress_callback progress_cb, void *progress_payload) { int error; + git_vector refs; assert(remote); + if (git_vector_init(&refs, 16, remote_head_cmp) < 0) + return -1; + + if (git_remote_ls(remote, store_refs, &refs) < 0) { + return -1; + } + + error = dwim_refspecs(&remote->refspecs, &refs); + git_vector_free(&refs); + if (error < 0) + return -1; + if ((error = git_fetch_negotiate(remote)) < 0) return error; return git_fetch_download_pack(remote, progress_cb, progress_payload); } -static int update_tips_callback(git_remote_head *head, void *payload) -{ - git_vector *refs = (git_vector *)payload; - - return git_vector_insert(refs, head); -} - static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src) { unsigned int i; @@ -692,21 +751,21 @@ 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_remote *remote, git_vector *update_heads, git_reference *ref) +static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref) { git_reference *resolved_ref = NULL; git_reference *tracking_ref = NULL; git_buf remote_name = GIT_BUF_INIT; int error = 0; - assert(out && remote && ref); + assert(out && spec && ref); *out = NULL; if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 || (!git_reference_is_branch(resolved_ref)) || - (error = git_branch_tracking(&tracking_ref, resolved_ref)) < 0 || - (error = git_refspec_transform_l(&remote_name, &remote->fetch, git_reference_name(tracking_ref))) < 0) { + (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 || + (error = git_refspec_transform_l(&remote_name, spec, git_reference_name(tracking_ref))) < 0) { /* Not an error if HEAD is orphaned or no tracking branch */ if (error == GIT_ENOTFOUND) error = 0; @@ -723,9 +782,8 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_ve return error; } -static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_heads) +static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads) { - struct git_refspec *spec; git_reference *head_ref = NULL; git_fetchhead_ref *fetchhead_ref; git_remote_head *remote_ref, *merge_remote_ref; @@ -736,7 +794,9 @@ static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_hea assert(remote); - spec = &remote->fetch; + /* no heads, nothing to do */ + if (update_heads->length == 0) + return 0; if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0) return -1; @@ -747,7 +807,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_hea /* 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, remote, update_heads, head_ref)) < 0) + (error = remote_head_for_ref(&merge_remote_ref, 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. */ @@ -787,7 +847,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_hea return error; } -int git_remote_update_tips(git_remote *remote) +static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vector *refs) { int error = 0, autotag; unsigned int i = 0; @@ -796,14 +856,11 @@ int git_remote_update_tips(git_remote *remote) git_odb *odb; git_remote_head *head; git_reference *ref; - struct git_refspec *spec; git_refspec tagspec; - git_vector refs, update_heads; + git_vector update_heads; assert(remote); - spec = &remote->fetch; - if (git_repository_odb__weakptr(&odb, remote->repo) < 0) return -1; @@ -811,16 +868,12 @@ int git_remote_update_tips(git_remote *remote) return -1; /* Make a copy of the transport's refs */ - if (git_vector_init(&refs, 16, NULL) < 0 || - git_vector_init(&update_heads, 16, NULL) < 0) + if (git_vector_init(&update_heads, 16, NULL) < 0) return -1; - if (git_remote_ls(remote, update_tips_callback, &refs) < 0) - goto on_error; - /* Let's go find HEAD, if it exists. Check only the first ref in the vector. */ - if (refs.length > 0) { - head = (git_remote_head *)refs.contents[0]; + if (refs->length > 0) { + head = git_vector_get(refs, 0); if (!strcmp(head->name, GIT_HEAD_FILE)) { if (git_reference_create(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0) @@ -831,15 +884,15 @@ int git_remote_update_tips(git_remote *remote) } } - for (; i < refs.length; ++i) { - head = (git_remote_head *)refs.contents[i]; + for (; i < refs->length; ++i) { + head = git_vector_get(refs, i); autotag = 0; /* Ignore malformed ref names (which also saves us from tag^{} */ if (!git_reference_is_valid_name(head->name)) continue; - if (git_refspec_src_matches(spec, head->name)) { + if (git_refspec_src_matches(spec, head->name) && spec->dst) { if (git_refspec_transform_r(&refname, spec, head->name) < 0) goto on_error; } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) { @@ -870,7 +923,7 @@ int git_remote_update_tips(git_remote *remote) if (error == GIT_ENOTFOUND) memset(&old, 0, GIT_OID_RAWSZ); - if (!git_oid_cmp(&old, &head->oid)) + if (!git_oid__cmp(&old, &head->oid)) continue; /* In autotag mode, don't overwrite any locally-existing tags */ @@ -887,17 +940,15 @@ int git_remote_update_tips(git_remote *remote) } if (git_remote_update_fetchhead(remote) && - (error = git_remote_write_fetchhead(remote, &update_heads)) < 0) + (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0) goto on_error; - git_vector_free(&refs); git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); return 0; on_error: - git_vector_free(&refs); git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); @@ -905,6 +956,34 @@ int git_remote_update_tips(git_remote *remote) } +int git_remote_update_tips(git_remote *remote) +{ + git_refspec *spec; + git_vector refs; + size_t i; + + if (git_vector_init(&refs, 16, NULL) < 0) + return -1; + + if (git_remote_ls(remote, store_refs, &refs) < 0) + goto on_error; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push) + continue; + + if (update_tips_for_spec(remote, spec, &refs) < 0) + goto on_error; + } + + git_vector_free(&refs); + return 0; + +on_error: + git_vector_free(&refs); + return -1; +} + int git_remote_connected(git_remote *remote) { assert(remote); @@ -934,6 +1013,9 @@ void git_remote_disconnect(git_remote *remote) void git_remote_free(git_remote *remote) { + git_refspec *spec; + size_t i; + if (remote == NULL) return; @@ -946,8 +1028,12 @@ void git_remote_free(git_remote *remote) git_vector_free(&remote->refs); - git_refspec__free(&remote->fetch); - git_refspec__free(&remote->push); + git_vector_foreach(&remote->refspecs, i, spec) { + git_refspec__free(spec); + git__free(spec); + } + git_vector_free(&remote->refspecs); + git__free(remote->url); git__free(remote->pushurl); git__free(remote->name); @@ -1238,58 +1324,58 @@ static int rename_fetch_refspecs( void *payload) { git_config *config; - const git_refspec *fetch_refspec; - git_buf dst_prefix = GIT_BUF_INIT, serialized = GIT_BUF_INIT; - const char* pos; + git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT; + const git_refspec *spec; + size_t i; int error = -1; - fetch_refspec = git_remote_fetchspec(remote); - - /* Is there a refspec to deal with? */ - if (fetch_refspec->src == NULL && - fetch_refspec->dst == NULL) - return 0; - - if (git_refspec__serialize(&serialized, fetch_refspec) < 0) + if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0) goto cleanup; - /* Is it an in-memory remote? */ - if (!remote->name) { - error = (callback(git_buf_cstr(&serialized), payload) < 0) ? GIT_EUSER : 0; - goto cleanup; - } + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push) + continue; - if (git_buf_printf(&dst_prefix, ":refs/remotes/%s/", remote->name) < 0) - goto cleanup; + /* Every refspec is a problem refspec for an in-memory remote */ + if (!remote->name) { + if (callback(spec->string, payload) < 0) { + error = GIT_EUSER; + goto cleanup; + } - pos = strstr(git_buf_cstr(&serialized), git_buf_cstr(&dst_prefix)); + continue; + } - /* Does the dst part of the refspec follow the extected standard format? */ - if (!pos) { - error = (callback(git_buf_cstr(&serialized), payload) < 0) ? GIT_EUSER : 0; - goto cleanup; - } + /* Does the dst part of the refspec follow the extected standard format? */ + if (strcmp(git_buf_cstr(&base), spec->string)) { + if (callback(spec->string, payload) < 0) { + error = GIT_EUSER; + goto cleanup; + } + + continue; + } - if (git_buf_splice( - &serialized, - pos - git_buf_cstr(&serialized) + strlen(":refs/remotes/"), - strlen(remote->name), new_name, - strlen(new_name)) < 0) + /* If we do want to move it to the new section */ + if (git_buf_printf(&val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0) goto cleanup; - git_refspec__free(&remote->fetch); + if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0) + goto cleanup; - if (git_refspec__parse(&remote->fetch, git_buf_cstr(&serialized), true) < 0) - goto cleanup; + if (git_repository_config__weakptr(&config, remote->repo) < 0) + goto cleanup; - if (git_repository_config__weakptr(&config, remote->repo) < 0) - goto cleanup; + if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0) + goto cleanup; + } - error = update_config_refspec(config, new_name, &remote->fetch, GIT_DIRECTION_FETCH); + error = 0; cleanup: - git_buf_free(&serialized); - git_buf_free(&dst_prefix); + git_buf_free(&base); + git_buf_free(&var); + git_buf_free(&val); return error; } @@ -1390,3 +1476,128 @@ int git_remote_is_valid_name( giterr_clear(); return error == 0; } + +git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname) +{ + git_refspec *spec; + size_t i; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push) + continue; + + if (git_refspec_src_matches(spec, refname)) + return spec; + } + + return NULL; +} + +git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname) +{ + git_refspec *spec; + size_t i; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push) + continue; + + if (git_refspec_dst_matches(spec, refname)) + return spec; + } + + return NULL; +} + +void git_remote_clear_refspecs(git_remote *remote) +{ + git_refspec *spec; + size_t i; + + git_vector_foreach(&remote->refspecs, i, spec) { + git_refspec__free(spec); + git__free(spec); + } + git_vector_clear(&remote->refspecs); +} + +int git_remote_add_fetch(git_remote *remote, const char *refspec) +{ + return add_refspec(remote, refspec, true); +} + +int git_remote_add_push(git_remote *remote, const char *refspec) +{ + return add_refspec(remote, refspec, false); +} + +static int copy_refspecs(git_strarray *array, git_remote *remote, int push) +{ + size_t i; + git_vector refspecs; + git_refspec *spec; + char *dup; + + if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0) + return -1; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push != push) + continue; + + if ((dup = git__strdup(spec->string)) == NULL) + goto on_error; + + if (git_vector_insert(&refspecs, dup) < 0) { + git__free(dup); + goto on_error; + } + } + + array->strings = (char **)refspecs.contents; + array->count = refspecs.length; + + return 0; + +on_error: + git_vector_foreach(&refspecs, i, dup) + git__free(dup); + git_vector_free(&refspecs); + + return -1; +} + +int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote) +{ + return copy_refspecs(array, remote, false); +} + +int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote) +{ + return copy_refspecs(array, remote, true); +} + +size_t git_remote_refspec_count(git_remote *remote) +{ + return remote->refspecs.length; +} + +const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n) +{ + return git_vector_get(&remote->refspecs, n); +} + +int git_remote_remove_refspec(git_remote *remote, size_t n) +{ + git_refspec *spec; + + assert(remote); + + spec = git_vector_get(&remote->refspecs, n); + if (spec) { + git_refspec__free(spec); + git__free(spec); + } + + return git_vector_remove(&remote->refspecs, n); +} diff --git a/src/remote.h b/src/remote.h index 4c1a18aa7f8..c9c26b77dd9 100644 --- a/src/remote.h +++ b/src/remote.h @@ -20,8 +20,7 @@ struct git_remote { char *url; char *pushurl; git_vector refs; - struct git_refspec fetch; - struct git_refspec push; + git_vector refspecs; git_cred_acquire_cb cred_acquire_cb; void *cred_acquire_payload; git_transport *transport; @@ -37,4 +36,7 @@ struct git_remote { const char* git_remote__urlfordirection(struct git_remote *remote, int direction); int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url); +git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname); +git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname); + #endif diff --git a/src/repository.c b/src/repository.c index 0ad7449ba07..e6eaf753c79 100644 --- a/src/repository.c +++ b/src/repository.c @@ -9,6 +9,7 @@ #include "git2/object.h" #include "git2/refdb.h" +#include "git2/sys/repository.h" #include "common.h" #include "repository.h" @@ -31,42 +32,71 @@ #define GIT_TEMPLATE_DIR "/usr/share/git-core/templates" -static void drop_odb(git_repository *repo) +static void set_odb(git_repository *repo, git_odb *odb) { - if (repo->_odb != NULL) { - GIT_REFCOUNT_OWN(repo->_odb, NULL); - git_odb_free(repo->_odb); - repo->_odb = NULL; + if (odb) { + GIT_REFCOUNT_OWN(odb, repo); + GIT_REFCOUNT_INC(odb); + } + + if ((odb = git__swap(repo->_odb, odb)) != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); } } -static void drop_refdb(git_repository *repo) +static void set_refdb(git_repository *repo, git_refdb *refdb) { - if (repo->_refdb != NULL) { - GIT_REFCOUNT_OWN(repo->_refdb, NULL); - git_refdb_free(repo->_refdb); - repo->_refdb = NULL; + if (refdb) { + GIT_REFCOUNT_OWN(refdb, repo); + GIT_REFCOUNT_INC(refdb); + } + + if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) { + GIT_REFCOUNT_OWN(refdb, NULL); + git_refdb_free(refdb); } } -static void drop_config(git_repository *repo) +static void set_config(git_repository *repo, git_config *config) { - if (repo->_config != NULL) { - GIT_REFCOUNT_OWN(repo->_config, NULL); - git_config_free(repo->_config); - repo->_config = NULL; + if (config) { + GIT_REFCOUNT_OWN(config, repo); + GIT_REFCOUNT_INC(config); + } + + if ((config = git__swap(repo->_config, config)) != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); } git_repository__cvar_cache_clear(repo); } -static void drop_index(git_repository *repo) +static void set_index(git_repository *repo, git_index *index) { - if (repo->_index != NULL) { - GIT_REFCOUNT_OWN(repo->_index, NULL); - git_index_free(repo->_index); - repo->_index = NULL; + if (index) { + GIT_REFCOUNT_OWN(index, repo); + GIT_REFCOUNT_INC(index); } + + if ((index = git__swap(repo->_index, index)) != NULL) { + GIT_REFCOUNT_OWN(index, NULL); + git_index_free(index); + } +} + +void git_repository__cleanup(git_repository *repo) +{ + assert(repo); + + git_cache_clear(&repo->objects); + git_attr_cache_flush(repo); + + set_config(repo, NULL); + set_index(repo, NULL); + set_odb(repo, NULL); + set_refdb(repo, NULL); } void git_repository_free(git_repository *repo) @@ -74,17 +104,14 @@ void git_repository_free(git_repository *repo) if (repo == NULL) return; + git_repository__cleanup(repo); + git_cache_free(&repo->objects); - git_attr_cache_flush(repo); git_submodule_config_free(repo); git__free(repo->path_repository); git__free(repo->workdir); - - drop_config(repo); - drop_index(repo); - drop_odb(repo); - drop_refdb(repo); + git__free(repo->namespace); git__free(repo); } @@ -118,7 +145,7 @@ static git_repository *repository_alloc(void) memset(repo, 0x0, sizeof(git_repository)); - if (git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free) < 0) { + if (git_cache_init(&repo->objects) < 0) { git__free(repo); return NULL; } @@ -129,6 +156,12 @@ static git_repository *repository_alloc(void) return repo; } +int git_repository_new(git_repository **out) +{ + *out = repository_alloc(); + return 0; +} + static int load_config_data(git_repository *repo) { int is_bare; @@ -368,6 +401,37 @@ static int find_repo( return error; } +int git_repository_open_bare( + git_repository **repo_ptr, + const char *bare_path) +{ + int error; + git_buf path = GIT_BUF_INIT; + git_repository *repo = NULL; + + if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0) + return error; + + if (!valid_repository_path(&path)) { + git_buf_free(&path); + giterr_set(GITERR_REPOSITORY, "Path is not a repository: %s", bare_path); + return GIT_ENOTFOUND; + } + + repo = repository_alloc(); + GITERR_CHECK_ALLOC(repo); + + repo->path_repository = git_buf_detach(&path); + GITERR_CHECK_ALLOC(repo->path_repository); + + /* of course we're bare! */ + repo->is_bare = 1; + repo->workdir = NULL; + + *repo_ptr = repo; + return 0; +} + int git_repository_open_ext( git_repository **repo_ptr, const char *start_path, @@ -511,39 +575,47 @@ static int load_config( return error; } -int git_repository_config__weakptr(git_config **out, git_repository *repo) +static const char *path_unless_empty(git_buf *buf) { - if (repo->_config == NULL) { - git_buf global_buf = GIT_BUF_INIT, xdg_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; - int res; - - const char *global_config_path = NULL; - const char *xdg_config_path = NULL; - const char *system_config_path = NULL; - - if (git_config_find_global_r(&global_buf) == 0) - global_config_path = global_buf.ptr; + return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL; +} - if (git_config_find_xdg_r(&xdg_buf) == 0) - xdg_config_path = xdg_buf.ptr; +int git_repository_config__weakptr(git_config **out, git_repository *repo) +{ + int error = 0; - if (git_config_find_system_r(&system_buf) == 0) - system_config_path = system_buf.ptr; + if (repo->_config == NULL) { + git_buf global_buf = GIT_BUF_INIT; + git_buf xdg_buf = GIT_BUF_INIT; + git_buf system_buf = GIT_BUF_INIT; + git_config *config; - res = load_config(&repo->_config, repo, global_config_path, xdg_config_path, system_config_path); + git_config_find_global_r(&global_buf); + git_config_find_xdg_r(&xdg_buf); + git_config_find_system_r(&system_buf); + + error = load_config( + &config, repo, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf)); + if (!error) { + GIT_REFCOUNT_OWN(config, repo); + + config = git__compare_and_swap(&repo->_config, NULL, config); + if (config != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); + } + } git_buf_free(&global_buf); git_buf_free(&xdg_buf); git_buf_free(&system_buf); - - if (res < 0) - return -1; - - GIT_REFCOUNT_OWN(repo->_config, repo); } *out = repo->_config; - return 0; + return error; } int git_repository_config(git_config **out, git_repository *repo) @@ -558,36 +630,37 @@ int git_repository_config(git_config **out, git_repository *repo) void git_repository_set_config(git_repository *repo, git_config *config) { assert(repo && config); - - drop_config(repo); - - repo->_config = config; - GIT_REFCOUNT_OWN(repo->_config, repo); - GIT_REFCOUNT_INC(repo->_config); + set_config(repo, config); } int git_repository_odb__weakptr(git_odb **out, git_repository *repo) { + int error = 0; + assert(repo && out); if (repo->_odb == NULL) { git_buf odb_path = GIT_BUF_INIT; - int res; + git_odb *odb; - if (git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR) < 0) - return -1; + git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR); - res = git_odb_open(&repo->_odb, odb_path.ptr); - git_buf_free(&odb_path); /* done with path */ + error = git_odb_open(&odb, odb_path.ptr); + if (!error) { + GIT_REFCOUNT_OWN(odb, repo); - if (res < 0) - return -1; + odb = git__compare_and_swap(&repo->_odb, NULL, odb); + if (odb != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); + } + } - GIT_REFCOUNT_OWN(repo->_odb, repo); + git_buf_free(&odb_path); } *out = repo->_odb; - return 0; + return error; } int git_repository_odb(git_odb **out, git_repository *repo) @@ -602,31 +675,32 @@ int git_repository_odb(git_odb **out, git_repository *repo) void git_repository_set_odb(git_repository *repo, git_odb *odb) { assert(repo && odb); - - drop_odb(repo); - - repo->_odb = odb; - GIT_REFCOUNT_OWN(repo->_odb, repo); - GIT_REFCOUNT_INC(odb); + set_odb(repo, odb); } int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) { + int error = 0; + assert(out && repo); if (repo->_refdb == NULL) { - int res; - - res = git_refdb_open(&repo->_refdb, repo); + git_refdb *refdb; - if (res < 0) - return -1; + error = git_refdb_open(&refdb, repo); + if (!error) { + GIT_REFCOUNT_OWN(refdb, repo); - GIT_REFCOUNT_OWN(repo->_refdb, repo); + refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb); + if (refdb != NULL) { + GIT_REFCOUNT_OWN(refdb, NULL); + git_refdb_free(refdb); + } + } } *out = repo->_refdb; - return 0; + return error; } int git_repository_refdb(git_refdb **out, git_repository *repo) @@ -640,40 +714,40 @@ int git_repository_refdb(git_refdb **out, git_repository *repo) void git_repository_set_refdb(git_repository *repo, git_refdb *refdb) { - assert (repo && refdb); - - drop_refdb(repo); - - repo->_refdb = refdb; - GIT_REFCOUNT_OWN(repo->_refdb, repo); - GIT_REFCOUNT_INC(refdb); + assert(repo && refdb); + set_refdb(repo, refdb); } int git_repository_index__weakptr(git_index **out, git_repository *repo) { + int error = 0; + assert(out && repo); if (repo->_index == NULL) { - int res; git_buf index_path = GIT_BUF_INIT; + git_index *index; - if (git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE) < 0) - return -1; + git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE); - res = git_index_open(&repo->_index, index_path.ptr); - git_buf_free(&index_path); /* done with path */ + error = git_index_open(&index, index_path.ptr); + if (!error) { + GIT_REFCOUNT_OWN(index, repo); - if (res < 0) - return -1; + index = git__compare_and_swap(&repo->_index, NULL, index); + if (index != NULL) { + GIT_REFCOUNT_OWN(index, NULL); + git_index_free(index); + } - GIT_REFCOUNT_OWN(repo->_index, repo); + error = git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER); + } - if (git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER) < 0) - return -1; + git_buf_free(&index_path); } *out = repo->_index; - return 0; + return error; } int git_repository_index(git_index **out, git_repository *repo) @@ -688,12 +762,24 @@ int git_repository_index(git_index **out, git_repository *repo) void git_repository_set_index(git_repository *repo, git_index *index) { assert(repo && index); + set_index(repo, index); +} - drop_index(repo); +int git_repository_set_namespace(git_repository *repo, const char *namespace) +{ + git__free(repo->namespace); - repo->_index = index; - GIT_REFCOUNT_OWN(repo->_index, repo); - GIT_REFCOUNT_INC(index); + if (namespace == NULL) { + repo->namespace = NULL; + return 0; + } + + return (repo->namespace = git__strdup(namespace)) ? 0 : -1; +} + +const char *git_repository_get_namespace(git_repository *repo) +{ + return repo->namespace; } static int check_repositoryformatversion(git_config *config) @@ -1383,14 +1469,13 @@ static int at_least_one_cb(const char *refname, void *payload) static int repo_contains_no_reference(git_repository *repo) { - int error; - - error = git_reference_foreach(repo, GIT_REF_LISTALL, at_least_one_cb, NULL); + int error = git_reference_foreach(repo, GIT_REF_LISTALL, at_least_one_cb, NULL); if (error == GIT_EUSER) return 0; - - return error == 0 ? 1 : error; + if (!error) + return 1; + return error; } int git_repository_is_empty(git_repository *repo) diff --git a/src/repository.h b/src/repository.h index cc2f8c2b8c1..bd5f63dac04 100644 --- a/src/repository.h +++ b/src/repository.h @@ -12,6 +12,7 @@ #include "git2/odb.h" #include "git2/repository.h" #include "git2/object.h" +#include "git2/config.h" #include "index.h" #include "cache.h" @@ -31,7 +32,13 @@ /** Cvar cache identifiers */ typedef enum { GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */ - GIT_CVAR_EOL, /* core.eol */ + GIT_CVAR_EOL, /* core.eol */ + GIT_CVAR_SYMLINKS, /* core.symlinks */ + GIT_CVAR_IGNORECASE, /* core.ignorecase */ + GIT_CVAR_FILEMODE, /* core.filemode */ + GIT_CVAR_IGNORESTAT, /* core.ignorestat */ + GIT_CVAR_TRUSTCTIME, /* core.trustctime */ + GIT_CVAR_ABBREV, /* core.abbrev */ GIT_CVAR_CACHE_MAX } git_cvar_cached; @@ -67,7 +74,21 @@ typedef enum { #else GIT_EOL_NATIVE = GIT_EOL_LF, #endif - GIT_EOL_DEFAULT = GIT_EOL_NATIVE + GIT_EOL_DEFAULT = GIT_EOL_NATIVE, + + /* core.symlinks: bool */ + GIT_SYMLINKS_DEFAULT = GIT_CVAR_TRUE, + /* core.ignorecase */ + GIT_IGNORECASE_DEFAULT = GIT_CVAR_FALSE, + /* core.filemode */ + GIT_FILEMODE_DEFAULT = GIT_CVAR_TRUE, + /* core.ignorestat */ + GIT_IGNORESTAT_DEFAULT = GIT_CVAR_FALSE, + /* core.trustctime */ + GIT_TRUSTCTIME_DEFAULT = GIT_CVAR_TRUE, + /* core.abbrev */ + GIT_ABBREV_DEFAULT = 7, + } git_cvar_value; /* internal repository init flags */ @@ -90,6 +111,7 @@ struct git_repository { char *path_repository; char *workdir; + char *namespace; unsigned is_bare:1; unsigned int lru_counter; diff --git a/src/revparse.c b/src/revparse.c index 1518a7c3c2f..8a22a04f37d 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -16,7 +16,7 @@ static int disambiguate_refname(git_reference **out, git_repository *repo, const char *refname) { - int error, i; + int error = 0, i; bool fallbackmode = true; git_reference *ref; git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT; @@ -107,7 +107,7 @@ static int build_regex(regex_t *regex, const char *pattern) error = regcomp(regex, pattern, REG_EXTENDED); if (!error) return 0; - + error = giterr_set_regex(regex, error); regfree(regex); @@ -125,7 +125,7 @@ static int maybe_describe(git_object**out, git_repository *repo, const char *spe if (substr == NULL) return GIT_ENOTFOUND; - + if (build_regex(®ex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0) return -1; @@ -356,9 +356,9 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch goto cleanup; } - if ((error = git_branch_tracking(&tracking, ref)) < 0) + if ((error = git_branch_upstream(&tracking, ref)) < 0) goto cleanup; - + *base_ref = tracking; cleanup: @@ -432,7 +432,7 @@ static int dereference_to_non_tag(git_object **out, git_object *obj) if (git_object_type(obj) == GIT_OBJ_TAG) return git_tag_peel(out, (git_tag *)obj); - return git_object__dup(out, obj); + return git_object_dup(out, obj); } static int handle_caret_parent_syntax(git_object **out, git_object *obj, int n) @@ -508,7 +508,7 @@ static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex) int error; git_oid oid; git_object *obj; - + while (!(error = git_revwalk_next(&oid, walk))) { error = git_object_lookup(&obj, git_revwalk_repository(walk), &oid, GIT_OBJ_COMMIT); @@ -537,7 +537,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_ if ((error = build_regex(&preg, pattern)) < 0) return error; - + if ((error = git_revwalk_new(&walk, repo)) < 0) goto cleanup; @@ -551,7 +551,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_ goto cleanup; error = walk_and_search(out, walk, &preg); - + cleanup: regfree(&preg); git_revwalk_free(walk); @@ -867,3 +867,46 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec git_buf_free(&buf); return error; } + + +int git_revparse( + git_revspec *revspec, + git_repository *repo, + const char *spec) +{ + const char *dotdot; + int error = 0; + + assert(revspec && repo && spec); + + memset(revspec, 0x0, sizeof(*revspec)); + + if ((dotdot = strstr(spec, "..")) != NULL) { + char *lstr; + const char *rstr; + revspec->flags = GIT_REVPARSE_RANGE; + + lstr = git__substrdup(spec, dotdot - spec); + rstr = dotdot + 2; + if (dotdot[2] == '.') { + revspec->flags |= GIT_REVPARSE_MERGE_BASE; + rstr++; + } + + if ((error = git_revparse_single(&revspec->from, repo, lstr)) < 0) { + return error; + } + + if ((error = git_revparse_single(&revspec->to, repo, rstr)) < 0) { + return error; + } + + git__free((void*)lstr); + } else { + revspec->flags = GIT_REVPARSE_SINGLE; + error = git_revparse_single(&revspec->from, repo, spec); + } + + return error; +} + diff --git a/src/revwalk.c b/src/revwalk.c index 02834ab3659..16f06624d80 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -11,6 +11,7 @@ #include "pool.h" #include "revwalk.h" +#include "git2/revparse.h" #include "merge.h" #include @@ -228,6 +229,31 @@ int git_revwalk_push_ref(git_revwalk *walk, const char *refname) return push_ref(walk, refname, 0); } +int git_revwalk_push_range(git_revwalk *walk, const char *range) +{ + git_revspec revspec; + int error = 0; + + if ((error = git_revparse(&revspec, walk->repo, range))) + return error; + + if (revspec.flags & GIT_REVPARSE_MERGE_BASE) { + /* TODO: support "..." */ + giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk"); + return GIT_EINVALIDSPEC; + } + + if ((error = push_commit(walk, git_object_id(revspec.from), 1))) + goto out; + + error = push_commit(walk, git_object_id(revspec.to), 0); + +out: + git_object_free(revspec.from); + git_object_free(revspec.to); + return error; +} + int git_revwalk_hide_ref(git_revwalk *walk, const char *refname) { assert(walk && refname); diff --git a/src/signature.c b/src/signature.c index 164e8eb678b..649dbcd3d15 100644 --- a/src/signature.c +++ b/src/signature.c @@ -69,7 +69,7 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema if (p->name == NULL || p->email == NULL || p->name[0] == '\0' || p->email[0] == '\0') { git_signature_free(p); - return -1; + return signature_error("Empty name or email"); } p->when.time = time; diff --git a/src/submodule.c b/src/submodule.c index 066a881cb69..0a22e3b13e5 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -7,6 +7,7 @@ #include "common.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "git2/types.h" #include "git2/repository.h" #include "git2/index.h" @@ -1327,7 +1328,7 @@ static int lookup_head_remote(git_buf *url, git_repository *repo) goto cleanup; } - if ((error = git_branch_tracking(&remote, head)) < 0) + if ((error = git_branch_upstream(&remote, head)) < 0) goto cleanup; /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */ diff --git a/src/tag.c b/src/tag.c index 735ba7e1d5f..a4f2e2581fa 100644 --- a/src/tag.c +++ b/src/tag.c @@ -13,20 +13,17 @@ #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" +#include "git2/odb_backend.h" -void git_tag__free(git_tag *tag) +void git_tag__free(void *_tag) { + git_tag *tag = _tag; git_signature_free(tag->tagger); git__free(tag->message); git__free(tag->tag_name); git__free(tag); } -const git_oid *git_tag_id(const git_tag *c) -{ - return git_object_id((const git_object *)c); -} - int git_tag_target(git_object **target, const git_tag *t) { assert(t); @@ -68,7 +65,7 @@ static int tag_error(const char *str) return -1; } -int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) +static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" @@ -78,8 +75,6 @@ int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) size_t text_len; char *search; - const char *buffer_end = buffer + length; - if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) return tag_error("Object field invalid"); @@ -156,6 +151,15 @@ int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) return 0; } +int git_tag__parse(void *_tag, git_odb_object *odb_obj) +{ + git_tag *tag = _tag; + const char *buffer = git_odb_object_data(odb_obj); + const char *buffer_end = buffer + git_odb_object_size(odb_obj); + + return tag_parse(tag, buffer, buffer_end); +} + static int retrieve_tag_reference( git_reference **tag_reference_out, git_buf *ref_name_out, @@ -276,23 +280,23 @@ static int git_tag_create__internal( } int git_tag_create( - git_oid *oid, - git_repository *repo, - const char *tag_name, - const git_object *target, - const git_signature *tagger, - const char *message, - int allow_ref_overwrite) + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_object *target, + const git_signature *tagger, + const char *message, + int allow_ref_overwrite) { return git_tag_create__internal(oid, repo, tag_name, target, tagger, message, allow_ref_overwrite, 1); } int git_tag_create_lightweight( - git_oid *oid, - git_repository *repo, - const char *tag_name, - const git_object *target, - int allow_ref_overwrite) + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_object *target, + int allow_ref_overwrite) { return git_tag_create__internal(oid, repo, tag_name, target, NULL, NULL, allow_ref_overwrite, 0); } @@ -316,14 +320,14 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu return -1; /* validate the buffer */ - if (git_tag__parse_buffer(&tag, buffer, strlen(buffer)) < 0) + if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0) return -1; /* validate the target */ if (git_odb_read(&target_obj, odb, &tag.target) < 0) goto on_error; - if (tag.type != target_obj->raw.type) { + if (tag.type != target_obj->cached.type) { giterr_set(GITERR_TAG, "The type for the given target is invalid"); goto on_error; } @@ -389,14 +393,8 @@ int git_tag_delete(git_repository *repo, const char *tag_name) if ((error = git_reference_delete(tag_ref)) == 0) git_reference_free(tag_ref); - - return error; -} -int git_tag__parse(git_tag *tag, git_odb_object *obj) -{ - assert(tag); - return git_tag__parse_buffer(tag, obj->raw.data, obj->raw.len); + return error; } typedef struct { diff --git a/src/tag.h b/src/tag.h index c8e421ee63b..d0cd393c728 100644 --- a/src/tag.h +++ b/src/tag.h @@ -22,8 +22,7 @@ struct git_tag { char *message; }; -void git_tag__free(git_tag *tag); -int git_tag__parse(git_tag *tag, git_odb_object *obj); -int git_tag__parse_buffer(git_tag *tag, const char *data, size_t len); +void git_tag__free(void *tag); +int git_tag__parse(void *tag, git_odb_object *obj); #endif diff --git a/src/thread-utils.h b/src/thread-utils.h index 2ca290adfaf..49b5f3b5e7b 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -18,6 +18,28 @@ typedef struct { #endif } git_atomic; +#ifdef GIT_ARCH_64 + +typedef struct { +#if defined(GIT_WIN32) + __int64 val; +#else + int64_t val; +#endif +} git_atomic64; + +typedef git_atomic64 git_atomic_ssize; + +#define git_atomic_ssize_add git_atomic64_add + +#else + +typedef git_atomic git_atomic_ssize; + +#define git_atomic_ssize_add git_atomic_add + +#endif + GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) { a->val = val; @@ -57,6 +79,17 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a) #endif } +GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) +{ +#if defined(GIT_WIN32) + return InterlockedExchangeAdd(&a->val, addend); +#elif defined(__GNUC__) + return __sync_add_and_fetch(&a->val, addend); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + GIT_INLINE(int) git_atomic_dec(git_atomic *a) { #if defined(GIT_WIN32) @@ -68,6 +101,35 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a) #endif } +GIT_INLINE(void *) git___compare_and_swap( + volatile void **ptr, void *oldval, void *newval) +{ + volatile void *foundval; +#if defined(GIT_WIN32) + foundval = InterlockedCompareExchangePointer(ptr, newval, oldval); +#elif defined(__GNUC__) + foundval = __sync_val_compare_and_swap(ptr, oldval, newval); +#else +# error "Unsupported architecture for atomic operations" +#endif + return (foundval == oldval) ? oldval : newval; +} + +#ifdef GIT_ARCH_64 + +GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) +{ +#if defined(GIT_WIN32) + return InterlockedExchangeAdd64(&a->val, addend); +#elif defined(__GNUC__) + return __sync_add_and_fetch(&a->val, addend); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + +#endif + #else #define git_thread unsigned int @@ -96,13 +158,55 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a) return ++a->val; } +GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) +{ + a->val += addend; + return a->val; +} + GIT_INLINE(int) git_atomic_dec(git_atomic *a) { return --a->val; } +GIT_INLINE(void *) git___compare_and_swap( + volatile void **ptr, void *oldval, void *newval) +{ + if (*ptr == oldval) + *ptr = newval; + else + oldval = newval; + return oldval; +} + +#ifdef GIT_ARCH_64 + +GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) +{ + a->val += addend; + return a->val; +} + +#endif + #endif +/* Atomically replace oldval with newval + * @return oldval if it was replaced or newval if it was not + */ +#define git__compare_and_swap(P,O,N) \ + git___compare_and_swap((volatile void **)P, O, N) + +#define git__swap(ptr, val) git__compare_and_swap(&ptr, ptr, val) + extern int git_online_cpus(void); +#if defined(GIT_THREADS) && defined(GIT_WIN32) +# define GIT_MEMORY_BARRIER MemoryBarrier() +#elif defined(GIT_THREADS) +# define GIT_MEMORY_BARRIER __sync_synchronize() +#else +# define GIT_MEMORY_BARRIER /* noop */ +#endif + #endif /* INCLUDE_thread_utils_h__ */ diff --git a/src/transports/local.c b/src/transports/local.c index ce89bb213e5..8b4d50c14ac 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -36,7 +36,8 @@ typedef struct { git_atomic cancelled; git_repository *repo; git_vector refs; - unsigned connected : 1; + unsigned connected : 1, + have_refs : 1; } transport_local; static int add_ref(transport_local *t, const char *name) @@ -139,6 +140,7 @@ static int store_refs(transport_local *t) goto on_error; } + t->have_refs = 1; git_strarray_free(&ref_names); return 0; @@ -208,8 +210,8 @@ static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *pay unsigned int i; git_remote_head *head = NULL; - if (!t->connected) { - giterr_set(GITERR_NET, "The transport is not connected"); + if (!t->have_refs) { + giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); return -1; } @@ -280,7 +282,7 @@ static int local_push_copy_object( odb_obj_size) < 0 || odb_stream->finalize_write(&remote_odb_obj_oid, odb_stream) < 0) { error = -1; - } else if (git_oid_cmp(&obj->id, &remote_odb_obj_oid) != 0) { + } else if (git_oid__cmp(&obj->id, &remote_odb_obj_oid) != 0) { giterr_set(GITERR_ODB, "Error when writing object to remote odb " "during local push operation. Remote odb object oid does not " "match local oid."); @@ -569,8 +571,6 @@ static void local_cancel(git_transport *transport) static int local_close(git_transport *transport) { transport_local *t = (transport_local *)transport; - size_t i; - git_remote_head *head; t->connected = 0; @@ -579,13 +579,6 @@ static int local_close(git_transport *transport) t->repo = NULL; } - git_vector_foreach(&t->refs, i, head) { - git__free(head->name); - git__free(head); - } - - git_vector_free(&t->refs); - if (t->url) { git__free(t->url); t->url = NULL; @@ -597,10 +590,19 @@ static int local_close(git_transport *transport) static void local_free(git_transport *transport) { transport_local *t = (transport_local *)transport; + size_t i; + git_remote_head *head; /* Close the transport, if it's still open. */ local_close(transport); + git_vector_foreach(&t->refs, i, head) { + git__free(head->name); + git__free(head); + } + + git_vector_free(&t->refs); + /* Free the transport */ git__free(t); } diff --git a/src/transports/smart.c b/src/transports/smart.c index bfcce0c08d4..416eb221fe5 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -253,7 +253,6 @@ static int git_smart__read_flags(git_transport *transport, int *flags) static int git_smart__close(git_transport *transport) { transport_smart *t = (transport_smart *)transport; - git_vector *refs = &t->refs; git_vector *common = &t->common; unsigned int i; git_pkt *p; @@ -261,11 +260,6 @@ static int git_smart__close(git_transport *transport) ret = git_smart__reset_stream(t, true); - git_vector_foreach(refs, i, p) - git_pkt_free(p); - - git_vector_free(refs); - git_vector_foreach(common, i, p) git_pkt_free(p); @@ -284,6 +278,9 @@ static int git_smart__close(git_transport *transport) static void git_smart__free(git_transport *transport) { transport_smart *t = (transport_smart *)transport; + git_vector *refs = &t->refs; + unsigned int i; + git_pkt *p; /* Make sure that the current stream is closed, if we have one. */ git_smart__close(transport); @@ -291,6 +288,11 @@ static void git_smart__free(git_transport *transport) /* Free the subtransport */ t->wrapped->free(t->wrapped); + git_vector_foreach(refs, i, p) + git_pkt_free(p); + + git_vector_free(refs); + git__free(t); } diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 8acedeb4970..765b914b746 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -5,6 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" +#include "git2/odb_backend.h" #include "smart.h" #include "refs.h" @@ -22,10 +23,16 @@ int git_smart__store_refs(transport_smart *t, int flushes) int error, flush = 0, recvd; const char *line_end; git_pkt *pkt; + git_pkt_ref *ref; + size_t i; /* Clear existing refs in case git_remote_connect() is called again * after git_remote_disconnect(). */ + git_vector_foreach(refs, i, ref) { + git__free(ref->head.name); + git__free(ref); + } git_vector_clear(refs); do { @@ -806,13 +813,13 @@ int git_smart__push(git_transport *transport, git_push *push) transport_smart *t = (transport_smart *)transport; git_smart_subtransport_stream *s; git_buf pktline = GIT_BUF_INIT; - int error = -1; + int error = -1, need_pack = 0; + push_spec *spec; + unsigned int i; #ifdef PUSH_DEBUG { git_remote_head *head; - push_spec *spec; - unsigned int i; char hex[41]; hex[40] = '\0'; git_vector_foreach(&push->remote->refs, i, head) { @@ -830,10 +837,23 @@ int git_smart__push(git_transport *transport, git_push *push) } #endif + /* + * Figure out if we need to send a packfile; which is in all + * cases except when we only send delete commands + */ + git_vector_foreach(&push->specs, i, spec) { + if (spec->lref) { + need_pack = 1; + break; + } + } + if (git_smart__get_push_stream(t, &s) < 0 || gen_pktline(&pktline, push) < 0 || - s->write(s, git_buf_cstr(&pktline), git_buf_len(&pktline)) < 0 || - git_packbuilder_foreach(push->pb, &stream_thunk, s) < 0) + s->write(s, git_buf_cstr(&pktline), git_buf_len(&pktline)) < 0) + goto on_error; + + if (need_pack && git_packbuilder_foreach(push->pb, &stream_thunk, s) < 0) goto on_error; /* If we sent nothing or the server doesn't support report-status, then diff --git a/src/tree.c b/src/tree.c index 17b3c378d9e..79cbcffcbe5 100644 --- a/src/tree.c +++ b/src/tree.c @@ -219,8 +219,9 @@ git_tree_entry *git_tree_entry_dup(const git_tree_entry *entry) return copy; } -void git_tree__free(git_tree *tree) +void git_tree__free(void *_tree) { + git_tree *tree = _tree; size_t i; git_tree_entry *e; @@ -231,16 +232,6 @@ void git_tree__free(git_tree *tree) git__free(tree); } -const git_oid *git_tree_id(const git_tree *t) -{ - return git_object_id((const git_object *)t); -} - -git_repository *git_tree_owner(const git_tree *t) -{ - return git_object_owner((const git_object *)t); -} - git_filemode_t git_tree_entry_filemode(const git_tree_entry *entry) { return (git_filemode_t)entry->attr; @@ -371,8 +362,12 @@ static int tree_error(const char *str, const char *path) return -1; } -static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end) +int git_tree__parse(void *_tree, git_odb_object *odb_obj) { + git_tree *tree = _tree; + const char *buffer = git_odb_object_data(odb_obj); + const char *buffer_end = buffer + git_odb_object_size(odb_obj); + if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) return -1; @@ -416,12 +411,6 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf return 0; } -int git_tree__parse(git_tree *tree, git_odb_object *obj) -{ - assert(tree); - return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len); -} - static size_t find_next_dir(const char *dirname, git_index *index, size_t start) { size_t dirlen, i, entries = git_index_entrycount(index); @@ -525,7 +514,6 @@ static int write_tree( /* Write out the subtree */ written = write_tree(&sub_oid, repo, index, subdir, i); if (written < 0) { - tree_error("Failed to write subtree", subdir); git__free(subdir); goto on_error; } else { diff --git a/src/tree.h b/src/tree.h index 567b5842d79..7cb2dd36c2d 100644 --- a/src/tree.h +++ b/src/tree.h @@ -30,11 +30,6 @@ struct git_treebuilder { size_t entrycount; /* vector may contain "removed" entries */ }; -GIT_INLINE(int) git_tree__dup(git_tree **dest, git_tree *source) -{ - return git_object__dup((git_object **)dest, (git_object *)source); -} - GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) { return (S_ISDIR(e->attr) && !S_ISGITLINK(e->attr)); @@ -42,8 +37,8 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) extern int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2); -void git_tree__free(git_tree *tree); -int git_tree__parse(git_tree *tree, git_odb_object *obj); +void git_tree__free(void *tree); +int git_tree__parse(void *tree, git_odb_object *obj); /** * Lookup the first position in the tree with a given prefix. diff --git a/src/unix/posix.h b/src/unix/posix.h index f4886c5d13f..9c9f837b9c7 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -21,6 +21,8 @@ /* The OpenBSD realpath function behaves differently */ #if !defined(__OpenBSD__) # define p_realpath(p, po) realpath(p, po) +#else +char *p_realpath(const char *, char *); #endif #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) diff --git a/src/unix/realpath.c b/src/unix/realpath.c index f382c2b73e0..15601bd2285 100644 --- a/src/unix/realpath.c +++ b/src/unix/realpath.c @@ -22,7 +22,7 @@ char *p_realpath(const char *pathname, char *resolved) /* Figure out if the file exists */ if (!access(ret, F_OK)) - ret; + return ret; return NULL; } diff --git a/src/util.c b/src/util.c index 44ac1af7368..8c8bc1a6ceb 100644 --- a/src/util.c +++ b/src/util.c @@ -11,6 +11,7 @@ #include #include "posix.h" #include "fileops.h" +#include "cache.h" #ifdef _MSC_VER # include @@ -38,7 +39,6 @@ int git_libgit2_capabilities() /* Declarations for tuneable settings */ extern size_t git_mwindow__window_size; extern size_t git_mwindow__mapped_limit; -extern size_t git_odb__cache_size; static int config_level_to_futils_dir(int config_level) { @@ -94,12 +94,25 @@ int git_libgit2_opts(int key, ...) error = git_futils_dirs_set(error, va_arg(ap, const char *)); break; - case GIT_OPT_GET_ODB_CACHE_SIZE: - *(va_arg(ap, size_t *)) = git_odb__cache_size; + case GIT_OPT_SET_CACHE_OBJECT_LIMIT: + { + git_otype type = (git_otype)va_arg(ap, int); + size_t size = va_arg(ap, size_t); + error = git_cache_set_max_object_size(type, size); + break; + } + + case GIT_OPT_SET_CACHE_MAX_SIZE: + git_cache__max_storage = va_arg(ap, ssize_t); + break; + + case GIT_OPT_ENABLE_CACHING: + git_cache__enabled = (va_arg(ap, int) != 0); break; - case GIT_OPT_SET_ODB_CACHE_SIZE: - git_odb__cache_size = va_arg(ap, size_t); + case GIT_OPT_GET_CACHED_MEMORY: + *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; + *(va_arg(ap, ssize_t *)) = git_cache__max_storage; break; } @@ -672,7 +685,7 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp( void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { -#if defined(__MINGW32__) +#if defined(__MINGW32__) || defined(__OpenBSD__) git__insertsort_r(els, nel, elsize, NULL, cmp, payload); #elif defined(GIT_WIN32) git__qsort_r_glue glue = { cmp, payload }; diff --git a/src/util.h b/src/util.h index c0f27199706..687afe084f6 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,8 @@ #ifndef INCLUDE_util_h__ #define INCLUDE_util_h__ +#include "common.h" + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) #define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits)))) @@ -186,20 +188,20 @@ extern int git__strncmp(const char *a, const char *b, size_t sz); extern int git__strncasecmp(const char *a, const char *b, size_t sz); typedef struct { - short refcount; + git_atomic refcount; void *owner; } git_refcount; typedef void (*git_refcount_freeptr)(void *r); #define GIT_REFCOUNT_INC(r) { \ - ((git_refcount *)(r))->refcount++; \ + git_atomic_inc(&((git_refcount *)(r))->refcount); \ } #define GIT_REFCOUNT_DEC(_r, do_free) { \ git_refcount *r = (git_refcount *)(_r); \ - r->refcount--; \ - if (r->refcount <= 0 && r->owner == NULL) { do_free(_r); } \ + int val = git_atomic_dec(&r->refcount); \ + if (val <= 0 && r->owner == NULL) { do_free(_r); } \ } #define GIT_REFCOUNT_OWN(r, o) { \ @@ -304,7 +306,7 @@ int git__date_parse(git_time_t *out, const char *date); /* * Unescapes a string in-place. - * + * * Edge cases behavior: * - "jackie\" -> "jacky\" * - "chan\\" -> "chan\" diff --git a/src/vector.c b/src/vector.c index f4a818ed287..5ba2fab182e 100644 --- a/src/vector.c +++ b/src/vector.c @@ -277,15 +277,13 @@ void git_vector_swap(git_vector *a, git_vector *b) int git_vector_resize_to(git_vector *v, size_t new_length) { - if (new_length <= v->length) - return 0; - if (new_length > v->_alloc_size && resize_vector(v, new_length) < 0) return -1; - memset(&v->contents[v->length], 0, - sizeof(void *) * (new_length - v->length)); + if (new_length > v->length) + memset(&v->contents[v->length], 0, + sizeof(void *) * (new_length - v->length)); v->length = new_length; diff --git a/src/win32/pthread.c b/src/win32/pthread.c index 105f4b89e33..232709e54af 100644 --- a/src/win32/pthread.c +++ b/src/win32/pthread.c @@ -14,22 +14,28 @@ int pthread_create( void *GIT_RESTRICT arg) { GIT_UNUSED(attr); - *thread = (pthread_t) CreateThread( + *thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL); return *thread ? 0 : -1; } int pthread_join(pthread_t thread, void **value_ptr) { - int ret; - ret = WaitForSingleObject(thread, INFINITE); - if (ret && value_ptr) - GetExitCodeThread(thread, (void*) value_ptr); - return -(!!ret); + DWORD ret = WaitForSingleObject(thread, INFINITE); + + if (ret == WAIT_OBJECT_0) { + if (value_ptr != NULL) + GetExitCodeThread(thread, (void *)value_ptr); + CloseHandle(thread); + return 0; + } + + return -1; } -int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex, - const pthread_mutexattr_t *GIT_RESTRICT mutexattr) +int pthread_mutex_init( + pthread_mutex_t *GIT_RESTRICT mutex, + const pthread_mutexattr_t *GIT_RESTRICT mutexattr) { GIT_UNUSED(mutexattr); InitializeCriticalSection(mutex); diff --git a/src/win32/pthread.h b/src/win32/pthread.h index a219a013701..8277ecf6e8d 100644 --- a/src/win32/pthread.h +++ b/src/win32/pthread.h @@ -25,13 +25,16 @@ typedef HANDLE pthread_cond_t; #define PTHREAD_MUTEX_INITIALIZER {(void*)-1}; -int pthread_create(pthread_t *GIT_RESTRICT, - const pthread_attr_t *GIT_RESTRICT, - void *(*start_routine)(void*), void *__restrict); +int pthread_create( + pthread_t *GIT_RESTRICT, + const pthread_attr_t *GIT_RESTRICT, + void *(*start_routine)(void*), + void *__restrict); int pthread_join(pthread_t, void **); -int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT); +int pthread_mutex_init( + pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT); int pthread_mutex_destroy(pthread_mutex_t *); int pthread_mutex_lock(pthread_mutex_t *); int pthread_mutex_unlock(pthread_mutex_t *); diff --git a/tests-clar/checkout/tree.c b/tests-clar/checkout/tree.c index 5a2eacea19d..eb129f34e4a 100644 --- a/tests-clar/checkout/tree.c +++ b/tests-clar/checkout/tree.c @@ -30,7 +30,6 @@ void test_checkout_tree__cannot_checkout_a_non_treeish(void) { /* blob */ cl_git_pass(git_revparse_single(&g_object, g_repo, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); - cl_git_fail(git_checkout_tree(g_repo, g_object, NULL)); } @@ -283,8 +282,7 @@ void test_checkout_tree__can_checkout_with_pattern(void) g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; - cl_git_pass(git_revparse_single(&g_object, g_repo, - "8496071c1b46c854b31185ea97743be6a8774479")); + cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( @@ -323,8 +321,7 @@ void test_checkout_tree__can_disable_pattern_match(void) g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; - cl_git_pass(git_revparse_single(&g_object, g_repo, - "8496071c1b46c854b31185ea97743be6a8774479")); + cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( @@ -504,3 +501,28 @@ void test_checkout_tree__issue_1397(void) git_object_free(tree); } + +void test_checkout_tree__can_write_to_empty_dirs(void) +{ + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_oid oid; + git_object *obj = NULL; + + assert_on_branch(g_repo, "master"); + + cl_git_pass(p_mkdir("testrepo/a", 0777)); + + /* do first checkout with FORCE because we don't know if testrepo + * base data is clean for a checkout or not + */ + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + + cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); + + cl_assert(git_path_isfile("testrepo/a/b.txt")); + + git_object_free(obj); +} diff --git a/tests-clar/checkout/typechange.c b/tests-clar/checkout/typechange.c index b92cc23fa52..6cf99ac1571 100644 --- a/tests-clar/checkout/typechange.c +++ b/tests-clar/checkout/typechange.c @@ -187,7 +187,7 @@ static void force_create_file(const char *file) GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS); cl_assert(!error || error == GIT_ENOTFOUND); cl_git_pass(git_futils_mkpath2file(file, 0777)); - cl_git_rewritefile(file, "yowza!"); + cl_git_rewritefile(file, "yowza!!"); } void test_checkout_typechange__checkout_with_conflicts(void) diff --git a/tests-clar/clone/empty.c b/tests-clar/clone/empty.c index 0f867257a43..f190523b657 100644 --- a/tests-clar/clone/empty.c +++ b/tests-clar/clone/empty.c @@ -49,7 +49,7 @@ void test_clone_empty__can_clone_an_empty_local_repo_barely(void) /* ...one can still retrieve the name of the remote tracking reference */ cl_assert_equal_i((int)strlen(expected_tracked_branch_name) + 1, - git_branch_tracking_name(buffer, 1024, g_repo_cloned, local_name)); + git_branch_upstream_name(buffer, 1024, g_repo_cloned, local_name)); cl_assert_equal_s(expected_tracked_branch_name, buffer); diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c index 2c4cba4eb75..545fe3a06d8 100644 --- a/tests-clar/clone/nonetwork.c +++ b/tests-clar/clone/nonetwork.c @@ -2,6 +2,7 @@ #include "git2/clone.h" #include "repository.h" +#include "remote.h" #define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository" @@ -148,7 +149,7 @@ void test_clone_nonetwork__custom_fetch_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_remote_fetchspec(g_remote); + actual_fs = git_remote_get_refspec(g_remote, 0); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); @@ -164,7 +165,7 @@ void test_clone_nonetwork__custom_push_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_remote_pushspec(g_remote); + actual_fs = git_remote_get_refspec(g_remote, git_remote_refspec_count(g_remote) - 1); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); } @@ -214,23 +215,23 @@ void test_clone_nonetwork__can_checkout_given_branch(void) void test_clone_nonetwork__can_detached_head(void) { - git_object *commit; + git_object *obj; git_repository *cloned; git_reference *cloned_head; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); - cl_git_pass(git_revparse_single(&commit, g_repo, "master~1")); - cl_git_pass(git_repository_set_head_detached(g_repo, git_object_id(commit))); + cl_git_pass(git_revparse_single(&obj, g_repo, "master~1")); + cl_git_pass(git_repository_set_head_detached(g_repo, git_object_id(obj))); cl_git_pass(git_clone(&cloned, "./foo", "./foo1", &g_options)); cl_assert(git_repository_head_detached(cloned)); cl_git_pass(git_repository_head(&cloned_head, cloned)); - cl_assert(!git_oid_cmp(git_object_id(commit), git_reference_target(cloned_head))); + cl_assert(!git_oid_cmp(git_object_id(obj), git_reference_target(cloned_head))); - git_commit_free((git_commit*)commit); + git_object_free(obj); git_reference_free(cloned_head); git_repository_free(cloned); diff --git a/tests-clar/commit/parse.c b/tests-clar/commit/parse.c index 95c62858856..415860a6e51 100644 --- a/tests-clar/commit/parse.c +++ b/tests-clar/commit/parse.c @@ -264,40 +264,43 @@ gpgsig -----BEGIN PGP SIGNATURE-----\n\ a simple commit which works\n", }; -void test_commit_parse__entire_commit(void) +static int parse_commit(git_commit **out, const char *buffer) { - const int broken_commit_count = sizeof(failing_commit_cases) / sizeof(*failing_commit_cases); - const int working_commit_count = sizeof(passing_commit_cases) / sizeof(*passing_commit_cases); - int i; + git_commit *commit; + git_odb_object fake_odb_object; + int error; - for (i = 0; i < broken_commit_count; ++i) { - git_commit *commit; - commit = (git_commit*)git__malloc(sizeof(git_commit)); - memset(commit, 0x0, sizeof(git_commit)); - commit->object.repo = g_repo; + commit = (git_commit*)git__malloc(sizeof(git_commit)); + memset(commit, 0x0, sizeof(git_commit)); + commit->object.repo = g_repo; - cl_git_fail(git_commit__parse_buffer( - commit, failing_commit_cases[i], strlen(failing_commit_cases[i])) - ); + memset(&fake_odb_object, 0x0, sizeof(git_odb_object)); + fake_odb_object.buffer = (char *)buffer; + fake_odb_object.cached.size = strlen(fake_odb_object.buffer); - git_commit__free(commit); - } + error = git_commit__parse(commit, &fake_odb_object); - for (i = 0; i < working_commit_count; ++i) { - git_commit *commit; + *out = commit; + return error; +} + +void test_commit_parse__entire_commit(void) +{ + const int failing_commit_count = ARRAY_SIZE(failing_commit_cases); + const int passing_commit_count = ARRAY_SIZE(passing_commit_cases); + int i; + git_commit *commit; - commit = (git_commit*)git__malloc(sizeof(git_commit)); - memset(commit, 0x0, sizeof(git_commit)); - commit->object.repo = g_repo; + for (i = 0; i < failing_commit_count; ++i) { + cl_git_fail(parse_commit(&commit, failing_commit_cases[i])); + git_commit__free(commit); + } - cl_git_pass(git_commit__parse_buffer( - commit, - passing_commit_cases[i], - strlen(passing_commit_cases[i])) - ); + for (i = 0; i < passing_commit_count; ++i) { + cl_git_pass(parse_commit(&commit, passing_commit_cases[i])); if (!i) - cl_assert_equal_s("\n", git_commit_message(commit)); + cl_assert_equal_s("", git_commit_message(commit)); else cl_assert(git__prefixcmp( git_commit_message(commit), "a simple commit which works") == 0); @@ -366,3 +369,24 @@ void test_commit_parse__details0(void) { } } +void test_commit_parse__leading_lf(void) +{ + git_commit *commit; + const char *buffer = +"tree 1810dff58d8a660512d4832e740f692884338ccd\n\ +parent e90810b8df3e80c413d903f631643c716887138d\n\ +author Vicent Marti 1273848544 +0200\n\ +committer Vicent Marti 1273848544 +0200\n\ +\n\ +\n\ +\n\ +This commit has a few LF at the start of the commit message"; + const char *message = +"\n\ +\n\ +This commit has a few LF at the start of the commit message"; + + cl_git_pass(parse_commit(&commit, buffer)); + cl_assert_equal_s(message, git_commit_message(commit)); + git_commit__free(commit); +} diff --git a/tests-clar/config/backend.c b/tests-clar/config/backend.c index 28502a8babd..3fd6eb11478 100644 --- a/tests-clar/config/backend.c +++ b/tests-clar/config/backend.c @@ -1,4 +1,5 @@ #include "clar_libgit2.h" +#include "git2/sys/config.h" void test_config_backend__checks_version(void) { diff --git a/tests-clar/config/multivar.c b/tests-clar/config/multivar.c index 26537e20a5d..0bda6bcec62 100644 --- a/tests-clar/config/multivar.c +++ b/tests-clar/config/multivar.c @@ -97,6 +97,22 @@ void test_config_multivar__add(void) git_config_free(cfg); } +void test_config_multivar__add_new(void) +{ + const char *var = "a.brand.new"; + git_config *cfg; + int n; + + cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); + + cl_git_pass(git_config_set_multivar(cfg, var, "", "variable")); + n = 0; + cl_git_pass(git_config_get_multivar(cfg, var, NULL, cb, &n)); + cl_assert(n == 1); + + git_config_free(cfg); +} + void test_config_multivar__replace(void) { git_config *cfg; diff --git a/tests-clar/core/oid.c b/tests-clar/core/oid.c index 08791cce651..7ee6fb67dab 100644 --- a/tests-clar/core/oid.c +++ b/tests-clar/core/oid.c @@ -16,15 +16,55 @@ void test_core_oid__initialize(void) void test_core_oid__streq(void) { - cl_assert(git_oid_streq(&id, str_oid) == 0); - cl_assert(git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") == -1); + cl_assert_equal_i(0, git_oid_streq(&id, str_oid)); + cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); - cl_assert(git_oid_streq(&id, "deadbeef") == -1); - cl_assert(git_oid_streq(&id, "I'm not an oid.... :)") == -1); - - cl_assert(git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000") == 0); - cl_assert(git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") == -1); + cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeef")); + cl_assert_equal_i(-1, git_oid_streq(&id, "I'm not an oid.... :)")); - cl_assert(git_oid_streq(&idp, "deadbeef") == -1); - cl_assert(git_oid_streq(&idp, "I'm not an oid.... :)") == -1); + cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000")); + cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ed1")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ec")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); + + cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeef")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "I'm not an oid.... :)")); +} + +void test_core_oid__strcmp(void) +{ + cl_assert_equal_i(0, git_oid_strcmp(&id, str_oid)); + cl_assert(git_oid_strcmp(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); + + cl_assert(git_oid_strcmp(&id, "deadbeef") < 0); + cl_assert_equal_i(-1, git_oid_strcmp(&id, "I'm not an oid.... :)")); + + cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed0000000000000000000000")); + cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed")); + cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ed1") < 0); + cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ec") > 0); + cl_assert(git_oid_strcmp(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); + + cl_assert(git_oid_strcmp(&idp, "deadbeef") < 0); + cl_assert_equal_i(-1, git_oid_strcmp(&idp, "I'm not an oid.... :)")); +} + +void test_core_oid__ncmp(void) +{ + cl_assert(!git_oid_ncmp(&id, &idp, 0)); + cl_assert(!git_oid_ncmp(&id, &idp, 1)); + cl_assert(!git_oid_ncmp(&id, &idp, 2)); + cl_assert(!git_oid_ncmp(&id, &idp, 17)); + cl_assert(!git_oid_ncmp(&id, &idp, 18)); + cl_assert(git_oid_ncmp(&id, &idp, 19)); + cl_assert(git_oid_ncmp(&id, &idp, 40)); + cl_assert(git_oid_ncmp(&id, &idp, 41)); + cl_assert(git_oid_ncmp(&id, &idp, 42)); + + cl_assert(!git_oid_ncmp(&id, &id, 0)); + cl_assert(!git_oid_ncmp(&id, &id, 1)); + cl_assert(!git_oid_ncmp(&id, &id, 39)); + cl_assert(!git_oid_ncmp(&id, &id, 40)); + cl_assert(!git_oid_ncmp(&id, &id, 41)); } diff --git a/tests-clar/core/oidmap.c b/tests-clar/core/oidmap.c new file mode 100644 index 00000000000..ec4b5e77564 --- /dev/null +++ b/tests-clar/core/oidmap.c @@ -0,0 +1,110 @@ +#include "clar_libgit2.h" +#include "oidmap.h" + +GIT__USE_OIDMAP; + +typedef struct { + git_oid oid; + size_t extra; +} oidmap_item; + +#define NITEMS 0x0fff + +void test_core_oidmap__basic(void) +{ + git_oidmap *map; + oidmap_item items[NITEMS]; + uint32_t i, j; + + for (i = 0; i < NITEMS; ++i) { + items[i].extra = i; + for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { + items[i].oid.id[j * 4 ] = (unsigned char)i; + items[i].oid.id[j * 4 + 1] = (unsigned char)(i >> 8); + items[i].oid.id[j * 4 + 2] = (unsigned char)(i >> 16); + items[i].oid.id[j * 4 + 3] = (unsigned char)(i >> 24); + } + } + + map = git_oidmap_alloc(); + cl_assert(map != NULL); + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + int ret; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos == kh_end(map)); + + pos = kh_put(oid, map, &items[i].oid, &ret); + cl_assert(ret != 0); + + kh_val(map, pos) = &items[i]; + } + + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos != kh_end(map)); + + cl_assert_equal_p(kh_val(map, pos), &items[i]); + } + + git_oidmap_free(map); +} + +void test_core_oidmap__hash_collision(void) +{ + git_oidmap *map; + oidmap_item items[NITEMS]; + uint32_t i, j; + + for (i = 0; i < NITEMS; ++i) { + uint32_t segment = i / 8; + int modi = i - (segment * 8); + + items[i].extra = i; + + for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { + items[i].oid.id[j * 4 ] = (unsigned char)modi; + items[i].oid.id[j * 4 + 1] = (unsigned char)(modi >> 8); + items[i].oid.id[j * 4 + 2] = (unsigned char)(modi >> 16); + items[i].oid.id[j * 4 + 3] = (unsigned char)(modi >> 24); + } + + items[i].oid.id[ 8] = (unsigned char)i; + items[i].oid.id[ 9] = (unsigned char)(i >> 8); + items[i].oid.id[10] = (unsigned char)(i >> 16); + items[i].oid.id[11] = (unsigned char)(i >> 24); + } + + map = git_oidmap_alloc(); + cl_assert(map != NULL); + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + int ret; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos == kh_end(map)); + + pos = kh_put(oid, map, &items[i].oid, &ret); + cl_assert(ret != 0); + + kh_val(map, pos) = &items[i]; + } + + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos != kh_end(map)); + + cl_assert_equal_p(kh_val(map, pos), &items[i]); + } + + git_oidmap_free(map); +} diff --git a/tests-clar/core/opts.c b/tests-clar/core/opts.c index 907339d512b..3173c648b2a 100644 --- a/tests-clar/core/opts.c +++ b/tests-clar/core/opts.c @@ -16,15 +16,4 @@ void test_core_opts__readwrite(void) git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val); cl_assert(new_val == old_val); - - git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &old_val); - - cl_assert(old_val == GIT_DEFAULT_CACHE_SIZE); - - git_libgit2_opts(GIT_OPT_SET_ODB_CACHE_SIZE, (size_t)GIT_DEFAULT_CACHE_SIZE*2); - git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &new_val); - - cl_assert(new_val == (GIT_DEFAULT_CACHE_SIZE*2)); - - git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &old_val); } diff --git a/tests-clar/diff/diff_helpers.c b/tests-clar/diff/diff_helpers.c index 19c005e2e0c..e7f97c034fb 100644 --- a/tests-clar/diff/diff_helpers.c +++ b/tests-clar/diff/diff_helpers.c @@ -28,7 +28,15 @@ int diff_file_cb( { diff_expects *e = payload; - GIT_UNUSED(progress); + if (e->debug) + fprintf(stderr, "%c %s (%.3f)\n", + git_diff_status_char(delta->status), + delta->old_file.path, progress); + + if (e->names) + cl_assert_equal_s(e->names[e->files], delta->old_file.path); + if (e->statuses) + cl_assert_equal_i(e->statuses[e->files], (int)delta->status); e->files++; diff --git a/tests-clar/diff/diff_helpers.h b/tests-clar/diff/diff_helpers.h index 674fd8e195a..b39a69d1d81 100644 --- a/tests-clar/diff/diff_helpers.h +++ b/tests-clar/diff/diff_helpers.h @@ -18,6 +18,13 @@ typedef struct { int line_ctxt; int line_adds; int line_dels; + + /* optional arrays of expected specific values */ + const char **names; + int *statuses; + + int debug; + } diff_expects; typedef struct { diff --git a/tests-clar/diff/notify.c b/tests-clar/diff/notify.c new file mode 100644 index 00000000000..433b4a9c1ea --- /dev/null +++ b/tests-clar/diff/notify.c @@ -0,0 +1,228 @@ +#include "clar_libgit2.h" +#include "diff_helpers.h" + +static git_repository *g_repo = NULL; + +void test_diff_notify__initialize(void) +{ +} + +void test_diff_notify__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static int assert_called_notifications( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + bool found = false; + notify_expected *exp = (notify_expected*)payload; + notify_expected *e;; + + GIT_UNUSED(diff_so_far); + + for (e = exp; e->path != NULL; e++) { + if (strcmp(e->path, delta_to_add->new_file.path)) + continue; + + cl_assert_equal_s(e->matched_pathspec, matched_pathspec); + + found = true; + break; + } + + cl_assert(found); + return 0; +} + +static void test_notify( + char **searched_pathspecs, + int pathspecs_count, + notify_expected *expected_matched_pathspecs, + int expected_diffed_files_count) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + diff_expects exp; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = assert_called_notifications; + opts.pathspec.strings = searched_pathspecs; + opts.pathspec.count = pathspecs_count; + + opts.notify_payload = expected_matched_pathspecs; + memset(&exp, 0, sizeof(exp)); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(expected_diffed_files_count, exp.files); + + git_diff_list_free(diff); +} + +void test_diff_notify__notify_single_pathspec(void) +{ + char *searched_pathspecs[] = { + "*_deleted", + }; + notify_expected expected_matched_pathspecs[] = { + { "file_deleted", "*_deleted" }, + { "staged_changes_file_deleted", "*_deleted" }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 2); +} + +void test_diff_notify__notify_multiple_pathspec(void) +{ + char *searched_pathspecs[] = { + "staged_changes_cant_find_me", + "subdir/modified_cant_find_me", + "subdir/*", + "staged*" + }; + notify_expected expected_matched_pathspecs[] = { + { "staged_changes_file_deleted", "staged*" }, + { "staged_changes_modified_file", "staged*" }, + { "staged_delete_modified_file", "staged*" }, + { "staged_new_file_deleted_file", "staged*" }, + { "staged_new_file_modified_file", "staged*" }, + { "subdir/deleted_file", "subdir/*" }, + { "subdir/modified_file", "subdir/*" }, + { "subdir/new_file", "subdir/*" }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 4, expected_matched_pathspecs, 8); +} + +void test_diff_notify__notify_catchall_with_empty_pathspecs(void) +{ + char *searched_pathspecs[] = { + "", + "" + }; + notify_expected expected_matched_pathspecs[] = { + { "file_deleted", NULL }, + { "ignored_file", NULL }, + { "modified_file", NULL }, + { "new_file", NULL }, + { "\xe8\xbf\x99", NULL }, + { "staged_changes_file_deleted", NULL }, + { "staged_changes_modified_file", NULL }, + { "staged_delete_modified_file", NULL }, + { "staged_new_file_deleted_file", NULL }, + { "staged_new_file_modified_file", NULL }, + { "subdir/deleted_file", NULL }, + { "subdir/modified_file", NULL }, + { "subdir/new_file", NULL }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); +} + +void test_diff_notify__notify_catchall(void) +{ + char *searched_pathspecs[] = { + "*", + }; + notify_expected expected_matched_pathspecs[] = { + { "file_deleted", "*" }, + { "ignored_file", "*" }, + { "modified_file", "*" }, + { "new_file", "*" }, + { "\xe8\xbf\x99", "*" }, + { "staged_changes_file_deleted", "*" }, + { "staged_changes_modified_file", "*" }, + { "staged_delete_modified_file", "*" }, + { "staged_new_file_deleted_file", "*" }, + { "staged_new_file_modified_file", "*" }, + { "subdir/deleted_file", "*" }, + { "subdir/modified_file", "*" }, + { "subdir/new_file", "*" }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); +} + +static int abort_diff( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + GIT_UNUSED(diff_so_far); + GIT_UNUSED(delta_to_add); + GIT_UNUSED(matched_pathspec); + GIT_UNUSED(payload); + + return -42; +} + +void test_diff_notify__notify_cb_can_abort_diff(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + char *pathspec = NULL; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = abort_diff; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + pathspec = "file_deleted"; + cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + pathspec = "staged_changes_modified_file"; + cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); +} + +static int filter_all( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + GIT_UNUSED(diff_so_far); + GIT_UNUSED(delta_to_add); + GIT_UNUSED(matched_pathspec); + GIT_UNUSED(payload); + + return 42; +} + +void test_diff_notify__notify_cb_can_be_used_as_filtering_function(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + char *pathspec = NULL; + diff_expects exp; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = filter_all; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + pathspec = "*_deleted"; + memset(&exp, 0, sizeof(exp)); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(0, exp.files); + + git_diff_list_free(diff); +} diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c index 4d17da468fe..40b191dd502 100644 --- a/tests-clar/diff/patch.c +++ b/tests-clar/diff/patch.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "diff_helpers.h" #include "repository.h" #include "buf_text.h" @@ -133,6 +135,84 @@ void test_diff_patch__to_string(void) git_tree_free(one); } +void test_diff_patch__config_options(void) +{ + const char *one_sha = "26a125e"; /* current HEAD */ + git_tree *one; + git_config *cfg; + git_diff_list *diff; + git_diff_patch *patch; + char *text; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + char *onefile = "staged_changes_modified_file"; + const char *expected1 = "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + const char *expected2 = "diff --git i/staged_changes_modified_file w/staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- i/staged_changes_modified_file\n+++ w/staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + const char *expected3 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + const char *expected4 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 70bd9443ada0..906ee7711f4f 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + + g_repo = cl_git_sandbox_init("status"); + cl_git_pass(git_repository_config(&cfg, g_repo)); + one = resolve_commit_oid_to_tree(g_repo, one_sha); + opts.pathspec.count = 1; + opts.pathspec.strings = &onefile; + + + cl_git_pass(git_config_set_string(cfg, "diff.mnemonicprefix", "true")); + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected1, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected2, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + + cl_git_pass(git_config_set_string(cfg, "diff.noprefix", "true")); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected3, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + + cl_git_pass(git_config_set_int32(cfg, "core.abbrev", 12)); + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected4, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + git_tree_free(one); + git_config_free(cfg); +} + void test_diff_patch__hunks_have_correct_line_numbers(void) { git_config *cfg; diff --git a/tests-clar/diff/submodules.c b/tests-clar/diff/submodules.c new file mode 100644 index 00000000000..f152af46fa0 --- /dev/null +++ b/tests-clar/diff/submodules.c @@ -0,0 +1,168 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "../submodule/submodule_helpers.h" + +static git_repository *g_repo = NULL; + +static void setup_submodules(void) +{ + g_repo = cl_git_sandbox_init("submodules"); + cl_fixture_sandbox("testrepo.git"); + rewrite_gitmodules(git_repository_workdir(g_repo)); + p_rename("submodules/testrepo/.gitted", "submodules/testrepo/.git"); +} + +static void setup_submodules2(void) +{ + g_repo = cl_git_sandbox_init("submod2"); + + cl_fixture_sandbox("submod2_target"); + p_rename("submod2_target/.gitted", "submod2_target/.git"); + + rewrite_gitmodules(git_repository_workdir(g_repo)); + p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); + p_rename("submod2/not/.gitted", "submod2/not/.git"); +} + +void test_diff_submodules__initialize(void) +{ +} + +void test_diff_submodules__cleanup(void) +{ + cl_git_sandbox_cleanup(); + + cl_fixture_cleanup("testrepo.git"); + cl_fixture_cleanup("submod2_target"); +} + +static void check_diff_patches(git_diff_list *diff, const char **expected) +{ + const git_diff_delta *delta; + git_diff_patch *patch = NULL; + size_t d, num_d = git_diff_num_deltas(diff); + char *patch_text; + + for (d = 0; d < num_d; ++d, git_diff_patch_free(patch)) { + cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); + + if (delta->status == GIT_DELTA_UNMODIFIED) + continue; + + if (expected[d] && !strcmp(expected[d], "")) + continue; + if (expected[d] && !strcmp(expected[d], "")) + cl_assert(0); + + cl_git_pass(git_diff_patch_to_str(&patch_text, patch)); + + cl_assert_equal_s(expected[d], patch_text); + git__free(patch_text); + } + + cl_assert(expected[d] && !strcmp(expected[d], "")); +} + +void test_diff_submodules__unmodified_submodule(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + NULL, /* added */ + NULL, /* ignored */ + "diff --git a/modified b/modified\nindex 092bfb9..452216e 100644\n--- a/modified\n+++ b/modified\n@@ -1 +1,2 @@\n-yo\n+changed\n+\n", /* modified */ + NULL, /* testrepo.git */ + NULL, /* unmodified */ + NULL, /* untracked */ + "" + }; + + setup_submodules(); + + opts.flags = GIT_DIFF_INCLUDE_IGNORED | + GIT_DIFF_INCLUDE_UNTRACKED | + GIT_DIFF_INCLUDE_UNMODIFIED; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); +} + +void test_diff_submodules__dirty_submodule(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + NULL, /* added */ + NULL, /* ignored */ + "diff --git a/modified b/modified\nindex 092bfb9..452216e 100644\n--- a/modified\n+++ b/modified\n@@ -1 +1,2 @@\n-yo\n+changed\n+\n", /* modified */ + "diff --git a/testrepo b/testrepo\nindex a65fedf..a65fedf 160000\n--- a/testrepo\n+++ b/testrepo\n@@ -1 +1 @@\n-Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750\n+Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750-dirty\n", /* testrepo.git */ + NULL, /* unmodified */ + NULL, /* untracked */ + "" + }; + + setup_submodules(); + + cl_git_rewritefile("submodules/testrepo/README", "heyheyhey"); + cl_git_mkfile("submodules/testrepo/all_new.txt", "never seen before"); + + opts.flags = GIT_DIFF_INCLUDE_IGNORED | + GIT_DIFF_INCLUDE_UNTRACKED | + GIT_DIFF_INCLUDE_UNMODIFIED; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); +} + +void test_diff_submodules__submod2_index_to_wd(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + NULL, /* not-submodule */ + NULL, /* not */ + "diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */ + "diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */ + "diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */ + "diff --git a/sm_changed_untracked_file b/sm_changed_untracked_file\nindex 4800958..4800958 160000\n--- a/sm_changed_untracked_file\n+++ b/sm_changed_untracked_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_untracked_file */ + "diff --git a/sm_missing_commits b/sm_missing_commits\nindex 4800958..5e49635 160000\n--- a/sm_missing_commits\n+++ b/sm_missing_commits\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 5e4963595a9774b90524d35a807169049de8ccad\n", /* sm_missing_commits */ + "" + }; + + setup_submodules2(); + + opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); +} + +void test_diff_submodules__submod2_head_to_index(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_tree *head; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + "diff --git a/sm_added_and_uncommited b/sm_added_and_uncommited\nnew file mode 160000\nindex 0000000..4800958\n--- /dev/null\n+++ b/sm_added_and_uncommited\n@@ -0,0 +1 @@\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n", /* sm_added_and_uncommited */ + "" + }; + + setup_submodules2(); + + cl_git_pass(git_repository_head_tree(&head, g_repo)); + + opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, head, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); + + git_tree_free(head); +} diff --git a/tests-clar/diff/tree.c b/tests-clar/diff/tree.c index 850feefde29..f05c7869e5a 100644 --- a/tests-clar/diff/tree.c +++ b/tests-clar/diff/tree.c @@ -454,3 +454,77 @@ void test_diff_tree__issue_1397(void) cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]); } + +static void set_config_int(git_repository *repo, const char *name, int value) +{ + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, repo)); + cl_git_pass(git_config_set_int32(cfg, name, value)); + git_config_free(cfg); +} + +void test_diff_tree__diff_configs(void) +{ + const char *a_commit = "d70d245e"; + const char *b_commit = "7a9e0b02"; + + g_repo = cl_git_sandbox_init("diff"); + + cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); + cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); + + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); + + cl_assert_equal_i(2, expect.files); + cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(6, expect.hunks); + cl_assert_equal_i(55, expect.lines); + cl_assert_equal_i(33, expect.line_ctxt); + cl_assert_equal_i(7, expect.line_adds); + cl_assert_equal_i(15, expect.line_dels); + + git_diff_list_free(diff); + diff = NULL; + + set_config_int(g_repo, "diff.context", 1); + + memset(&expect, 0, sizeof(expect)); + + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); + + cl_assert_equal_i(2, expect.files); + cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(7, expect.hunks); + cl_assert_equal_i(34, expect.lines); + cl_assert_equal_i(12, expect.line_ctxt); + cl_assert_equal_i(7, expect.line_adds); + cl_assert_equal_i(15, expect.line_dels); + + git_diff_list_free(diff); + diff = NULL; + + set_config_int(g_repo, "diff.context", 0); + set_config_int(g_repo, "diff.noprefix", 1); + + memset(&expect, 0, sizeof(expect)); + + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); + + cl_assert_equal_i(2, expect.files); + cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(7, expect.hunks); + cl_assert_equal_i(22, expect.lines); + cl_assert_equal_i(0, expect.line_ctxt); + cl_assert_equal_i(7, expect.line_adds); + cl_assert_equal_i(15, expect.line_dels); +} diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c index fc95cf8b419..94fd7165d11 100644 --- a/tests-clar/diff/workdir.c +++ b/tests-clar/diff/workdir.c @@ -307,169 +307,6 @@ void test_diff_workdir__to_index_with_pathspec(void) git_diff_list_free(diff); } -static int assert_called_notifications( - const git_diff_list *diff_so_far, - const git_diff_delta *delta_to_add, - const char *matched_pathspec, - void *payload) -{ - bool found = false; - notify_expected *exp = (notify_expected*)payload; - notify_expected *e;; - - GIT_UNUSED(diff_so_far); - - for (e = exp; e->path != NULL; e++) { - if (strcmp(e->path, delta_to_add->new_file.path)) - continue; - - cl_assert_equal_s(e->matched_pathspec, matched_pathspec); - - found = true; - break; - } - - cl_assert(found); - return 0; -} - -void test_diff_workdir__to_index_notify(void) -{ - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_list *diff = NULL; - diff_expects exp; - - char *searched_pathspecs_solo[] = { - "*_deleted", - }; - notify_expected expected_matched_pathspecs_solo[] = { - { "file_deleted", "*_deleted" }, - { "staged_changes_file_deleted", "*_deleted" }, - { NULL, NULL } - }; - - char *searched_pathspecs_multiple[] = { - "staged_changes_cant_find_me", - "subdir/modified_cant_find_me", - "subdir/*", - "staged*" - }; - notify_expected expected_matched_pathspecs_multiple[] = { - { "staged_changes_file_deleted", "staged*" }, - { "staged_changes_modified_file", "staged*" }, - { "staged_delete_modified_file", "staged*" }, - { "staged_new_file_deleted_file", "staged*" }, - { "staged_new_file_modified_file", "staged*" }, - { "subdir/deleted_file", "subdir/*" }, - { "subdir/modified_file", "subdir/*" }, - { "subdir/new_file", "subdir/*" }, - { NULL, NULL } - }; - - g_repo = cl_git_sandbox_init("status"); - - opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; - opts.notify_cb = assert_called_notifications; - opts.pathspec.strings = searched_pathspecs_solo; - opts.pathspec.count = 1; - - opts.notify_payload = &expected_matched_pathspecs_solo; - memset(&exp, 0, sizeof(exp)); - - cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); - cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); - - cl_assert_equal_i(2, exp.files); - - git_diff_list_free(diff); - - opts.pathspec.strings = searched_pathspecs_multiple; - opts.pathspec.count = 4; - opts.notify_payload = &expected_matched_pathspecs_multiple; - memset(&exp, 0, sizeof(exp)); - - cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); - cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); - - cl_assert_equal_i(8, exp.files); - - git_diff_list_free(diff); -} - -static int abort_diff( - const git_diff_list *diff_so_far, - const git_diff_delta *delta_to_add, - const char *matched_pathspec, - void *payload) -{ - GIT_UNUSED(diff_so_far); - GIT_UNUSED(delta_to_add); - GIT_UNUSED(matched_pathspec); - GIT_UNUSED(payload); - - return -42; -} - -void test_diff_workdir__to_index_notify_can_be_aborted_by_callback(void) -{ - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_list *diff = NULL; - char *pathspec = NULL; - - g_repo = cl_git_sandbox_init("status"); - - opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; - opts.notify_cb = abort_diff; - opts.pathspec.strings = &pathspec; - opts.pathspec.count = 1; - - pathspec = "file_deleted"; - cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); - - pathspec = "staged_changes_modified_file"; - cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); -} - -static int filter_all( - const git_diff_list *diff_so_far, - const git_diff_delta *delta_to_add, - const char *matched_pathspec, - void *payload) -{ - GIT_UNUSED(diff_so_far); - GIT_UNUSED(delta_to_add); - GIT_UNUSED(matched_pathspec); - GIT_UNUSED(payload); - - return 42; -} - -void test_diff_workdir__to_index_notify_can_be_used_as_filtering_function(void) -{ - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_list *diff = NULL; - char *pathspec = NULL; - diff_expects exp; - - g_repo = cl_git_sandbox_init("status"); - - opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; - opts.notify_cb = filter_all; - opts.pathspec.strings = &pathspec; - opts.pathspec.count = 1; - - pathspec = "*_deleted"; - memset(&exp, 0, sizeof(exp)); - - cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); - cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); - - cl_assert_equal_i(0, exp.files); - - git_diff_list_free(diff); -} - - void test_diff_workdir__filemode_changes(void) { git_diff_list *diff = NULL; @@ -1071,7 +908,6 @@ void test_diff_workdir__can_diff_empty_file(void) /* baseline - make sure there are no outstanding diffs */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); - git_tree_free(tree); cl_assert_equal_i(2, (int)git_diff_num_deltas(diff)); git_diff_list_free(diff); @@ -1098,6 +934,8 @@ void test_diff_workdir__can_diff_empty_file(void) cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1)); git_diff_patch_free(patch); git_diff_list_free(diff); + + git_tree_free(tree); } void test_diff_workdir__to_index_issue_1397(void) @@ -1195,3 +1033,190 @@ void test_diff_workdir__to_tree_issue_1397(void) git_diff_list_free(diff); git_tree_free(a); } + +void test_diff_workdir__untracked_directory_scenarios(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + diff_expects exp; + char *pathspec = NULL; + static const char *files0[] = { + "subdir/deleted_file", + "subdir/modified_file", + "subdir/new_file", + NULL + }; + static const char *files1[] = { + "subdir/deleted_file", + "subdir/directory/", + "subdir/modified_file", + "subdir/new_file", + NULL + }; + static const char *files2[] = { + "subdir/deleted_file", + "subdir/directory/more/notignored", + "subdir/modified_file", + "subdir/new_file", + NULL + }; + + g_repo = cl_git_sandbox_init("status"); + cl_git_mkfile("status/.gitignore", "ignored\n"); + + opts.context_lines = 3; + opts.interhunk_lines = 1; + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + pathspec = "subdir"; + + /* baseline for "subdir" pathspec */ + + memset(&exp, 0, sizeof(exp)); + exp.names = files0; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(3, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* empty directory */ + + cl_git_pass(p_mkdir("status/subdir/directory", 0777)); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* directory with only ignored files */ + + cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777)); + cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n"); + + cl_git_pass(p_mkdir("status/subdir/directory/another", 0777)); + cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n"); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* directory with ignored directory (contents irrelevant) */ + + cl_git_pass(p_mkdir("status/subdir/directory/more", 0777)); + cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777)); + cl_git_mkfile("status/subdir/directory/more/ignored/notignored", + "inside ignored dir\n"); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* quick version avoids directory scan */ + + opts.flags = opts.flags | GIT_DIFF_FAST_UNTRACKED_DIRS; + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* directory with nested non-ignored content */ + + opts.flags = opts.flags & ~GIT_DIFF_FAST_UNTRACKED_DIRS; + + cl_git_mkfile("status/subdir/directory/more/notignored", + "not ignored deep under untracked\n"); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */ + + opts.flags = opts.flags & ~GIT_DIFF_INCLUDE_IGNORED; + opts.flags = opts.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; + + memset(&exp, 0, sizeof(exp)); + exp.names = files2; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); +} diff --git a/tests-clar/index/names.c b/tests-clar/index/names.c new file mode 100644 index 00000000000..68615531a78 --- /dev/null +++ b/tests-clar/index/names.c @@ -0,0 +1,84 @@ +#include "clar_libgit2.h" +#include "index.h" +#include "git2/sys/index.h" +#include "git2/repository.h" +#include "../reset/reset_helpers.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "mergedrepo" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +// Fixture setup and teardown +void test_index_names__initialize(void) +{ + repo = cl_git_sandbox_init("mergedrepo"); + git_repository_index(&repo_index, repo); +} + +void test_index_names__cleanup(void) +{ + git_index_free(repo_index); + repo_index = NULL; + + cl_git_sandbox_cleanup(); +} + +void test_index_names__add(void) +{ + const git_index_name_entry *conflict_name; + + cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); + cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); + cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); + + cl_assert(git_index_name_entrycount(repo_index) == 3); + + conflict_name = git_index_name_get_byindex(repo_index, 0); + cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); + cl_assert(strcmp(conflict_name->ours, "ours") == 0); + cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); + + conflict_name = git_index_name_get_byindex(repo_index, 1); + cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); + cl_assert(strcmp(conflict_name->ours, "ours2") == 0); + cl_assert(conflict_name->theirs == NULL); + + conflict_name = git_index_name_get_byindex(repo_index, 2); + cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); + cl_assert(conflict_name->ours == NULL); + cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); +} + +void test_index_names__roundtrip(void) +{ + const git_index_name_entry *conflict_name; + + cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); + cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); + cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); + + cl_git_pass(git_index_write(repo_index)); + git_index_clear(repo_index); + cl_assert(git_index_name_entrycount(repo_index) == 0); + + cl_git_pass(git_index_read(repo_index)); + cl_assert(git_index_name_entrycount(repo_index) == 3); + + conflict_name = git_index_name_get_byindex(repo_index, 0); + cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); + cl_assert(strcmp(conflict_name->ours, "ours") == 0); + cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); + + conflict_name = git_index_name_get_byindex(repo_index, 1); + cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); + cl_assert(strcmp(conflict_name->ours, "ours2") == 0); + cl_assert(conflict_name->theirs == NULL); + + conflict_name = git_index_name_get_byindex(repo_index, 2); + cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); + cl_assert(conflict_name->ours == NULL); + cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); + +} diff --git a/tests-clar/index/reuc.c b/tests-clar/index/reuc.c index 4d5955a019e..0e38a92f35a 100644 --- a/tests-clar/index/reuc.c +++ b/tests-clar/index/reuc.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "index.h" +#include "git2/sys/index.h" #include "git2/repository.h" #include "../reset/reset_helpers.h" diff --git a/tests-clar/merge/merge_helpers.c b/tests-clar/merge/merge_helpers.c new file mode 100644 index 00000000000..71bb9678180 --- /dev/null +++ b/tests-clar/merge/merge_helpers.c @@ -0,0 +1,310 @@ +#include "clar_libgit2.h" +#include "buffer.h" +#include "refs.h" +#include "tree.h" +#include "merge_helpers.h" +#include "merge.h" +#include "git2/merge.h" +#include "git2/sys/index.h" + +int merge_trees_from_branches( + git_index **index, git_repository *repo, + const char *ours_name, const char *theirs_name, + git_merge_tree_opts *opts) +{ + git_commit *our_commit, *their_commit, *ancestor_commit = NULL; + git_tree *our_tree, *their_tree, *ancestor_tree = NULL; + git_oid our_oid, their_oid, ancestor_oid; + git_buf branch_buf = GIT_BUF_INIT; + int error; + + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours_name); + cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); + + git_buf_clear(&branch_buf); + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs_name); + cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); + + error = git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit)); + + if (error != GIT_ENOTFOUND) { + cl_git_pass(error); + + cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); + cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); + } + + cl_git_pass(git_commit_tree(&our_tree, our_commit)); + cl_git_pass(git_commit_tree(&their_tree, their_commit)); + + cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, opts)); + + git_buf_free(&branch_buf); + git_tree_free(our_tree); + git_tree_free(their_tree); + git_tree_free(ancestor_tree); + git_commit_free(our_commit); + git_commit_free(their_commit); + git_commit_free(ancestor_commit); + + return 0; +} + +void merge__dump_index_entries(git_vector *index_entries) +{ + size_t i; + const git_index_entry *index_entry; + + printf ("\nINDEX [%d]:\n", (int)index_entries->length); + for (i = 0; i < index_entries->length; i++) { + index_entry = index_entries->contents[i]; + + printf("%o ", index_entry->mode); + printf("%s ", git_oid_allocfmt(&index_entry->oid)); + printf("%d ", git_index_entry_stage(index_entry)); + printf("%s ", index_entry->path); + printf("\n"); + } + printf("\n"); +} + +void merge__dump_names(git_index *index) +{ + size_t i; + const git_index_name_entry *conflict_name; + + for (i = 0; i < git_index_name_entrycount(index); i++) { + conflict_name = git_index_name_get_byindex(index, i); + + printf("%s %s %s\n", conflict_name->ancestor, conflict_name->ours, conflict_name->theirs); + } + printf("\n"); +} + +void merge__dump_reuc(git_index *index) +{ + size_t i; + const git_index_reuc_entry *reuc; + + printf ("\nREUC:\n"); + for (i = 0; i < git_index_reuc_entrycount(index); i++) { + reuc = git_index_reuc_get_byindex(index, i); + + printf("%s ", reuc->path); + printf("%o ", reuc->mode[0]); + printf("%s\n", git_oid_allocfmt(&reuc->oid[0])); + printf(" %o ", reuc->mode[1]); + printf(" %s\n", git_oid_allocfmt(&reuc->oid[1])); + printf(" %o ", reuc->mode[2]); + printf(" %s ", git_oid_allocfmt(&reuc->oid[2])); + printf("\n"); + } + printf("\n"); +} + +static int index_entry_eq_merge_index_entry(const struct merge_index_entry *expected, const git_index_entry *actual) +{ + git_oid expected_oid; + bool test_oid; + + if (strlen(expected->oid_str) != 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected->oid_str)); + test_oid = 1; + } else + test_oid = 0; + + if (actual->mode != expected->mode || + (test_oid && git_oid_cmp(&actual->oid, &expected_oid) != 0) || + git_index_entry_stage(actual) != expected->stage) + return 0; + + if (actual->mode == 0 && (actual->path != NULL || strlen(expected->path) > 0)) + return 0; + + if (actual->mode != 0 && (strcmp(actual->path, expected->path) != 0)) + return 0; + + return 1; +} + +static int name_entry_eq(const char *expected, const char *actual) +{ + if (strlen(expected) == 0) + return (actual == NULL) ? 1 : 0; + + return (strcmp(expected, actual) == 0) ? 1 : 0; +} + +static int name_entry_eq_merge_name_entry(const struct merge_name_entry *expected, const git_index_name_entry *actual) +{ + if (name_entry_eq(expected->ancestor_path, actual->ancestor) == 0 || + name_entry_eq(expected->our_path, actual->ours) == 0 || + name_entry_eq(expected->their_path, actual->theirs) == 0) + return 0; + + return 1; +} + +static int index_conflict_data_eq_merge_diff(const struct merge_index_conflict_data *expected, git_merge_diff *actual) +{ + if (!index_entry_eq_merge_index_entry(&expected->ancestor.entry, &actual->ancestor_entry) || + !index_entry_eq_merge_index_entry(&expected->ours.entry, &actual->our_entry) || + !index_entry_eq_merge_index_entry(&expected->theirs.entry, &actual->their_entry)) + return 0; + + if (expected->ours.status != actual->our_status || + expected->theirs.status != actual->their_status) + return 0; + + return 1; +} + +int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len) +{ + git_merge_diff *actual; + size_t i; + + if (conflicts->length != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + actual = conflicts->contents[i]; + + if (!index_conflict_data_eq_merge_diff(&expected[i], actual)) + return 0; + } + + return 1; +} + +int merge_test_index(git_index *index, const struct merge_index_entry expected[], size_t expected_len) +{ + size_t i; + const git_index_entry *index_entry; + + /* + dump_index_entries(&index->entries); + */ + + if (git_index_entrycount(index) != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + if ((index_entry = git_index_get_byindex(index, i)) == NULL) + return 0; + + if (!index_entry_eq_merge_index_entry(&expected[i], index_entry)) + return 0; + } + + return 1; +} + +int merge_test_names(git_index *index, const struct merge_name_entry expected[], size_t expected_len) +{ + size_t i; + const git_index_name_entry *name_entry; + + /* + dump_names(index); + */ + + if (git_index_name_entrycount(index) != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + if ((name_entry = git_index_name_get_byindex(index, i)) == NULL) + return 0; + + if (! name_entry_eq_merge_name_entry(&expected[i], name_entry)) + return 0; + } + + return 1; +} + +int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len) +{ + size_t i; + const git_index_reuc_entry *reuc_entry; + git_oid expected_oid; + + /* + dump_reuc(index); + */ + + if (git_index_reuc_entrycount(index) != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + if ((reuc_entry = git_index_reuc_get_byindex(index, i)) == NULL) + return 0; + + if (strcmp(reuc_entry->path, expected[i].path) != 0 || + reuc_entry->mode[0] != expected[i].ancestor_mode || + reuc_entry->mode[1] != expected[i].our_mode || + reuc_entry->mode[2] != expected[i].their_mode) + return 0; + + if (expected[i].ancestor_mode > 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].ancestor_oid_str)); + + if (git_oid_cmp(&reuc_entry->oid[0], &expected_oid) != 0) + return 0; + } + + if (expected[i].our_mode > 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].our_oid_str)); + + if (git_oid_cmp(&reuc_entry->oid[1], &expected_oid) != 0) + return 0; + } + + if (expected[i].their_mode > 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].their_oid_str)); + + if (git_oid_cmp(&reuc_entry->oid[2], &expected_oid) != 0) + return 0; + } + } + + return 1; +} + +int dircount(void *payload, git_buf *pathbuf) +{ + int *entries = payload; + size_t len = git_buf_len(pathbuf); + + if (len < 5 || strcmp(pathbuf->ptr + (git_buf_len(pathbuf) - 5), "/.git") != 0) + (*entries)++; + + return 0; +} + +int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len) +{ + size_t actual_len = 0, i; + git_oid actual_oid, expected_oid; + git_buf wd = GIT_BUF_INIT; + + git_buf_puts(&wd, repo->workdir); + git_path_direach(&wd, dircount, &actual_len); + + if (actual_len != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + git_blob_create_fromworkdir(&actual_oid, repo, expected[i].path); + git_oid_fromstr(&expected_oid, expected[i].oid_str); + + if (git_oid_cmp(&actual_oid, &expected_oid) != 0) + return 0; + } + + git_buf_free(&wd); + + return 1; +} diff --git a/tests-clar/merge/merge_helpers.h b/tests-clar/merge/merge_helpers.h new file mode 100644 index 00000000000..cb718e01ab2 --- /dev/null +++ b/tests-clar/merge/merge_helpers.h @@ -0,0 +1,59 @@ +#ifndef INCLUDE_cl_merge_helpers_h__ +#define INCLUDE_cl_merge_helpers_h__ + +#include "merge.h" +#include "git2/merge.h" + +struct merge_index_entry { + uint16_t mode; + char oid_str[41]; + int stage; + char path[128]; +}; + +struct merge_name_entry { + char ancestor_path[128]; + char our_path[128]; + char their_path[128]; +}; + +struct merge_index_with_status { + struct merge_index_entry entry; + unsigned int status; +}; + +struct merge_reuc_entry { + char path[128]; + 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]; +}; + +struct merge_index_conflict_data { + struct merge_index_with_status ancestor; + struct merge_index_with_status ours; + struct merge_index_with_status theirs; + git_merge_diff_type_t change_type; +}; + +int merge_trees_from_branches( + git_index **index, git_repository *repo, + const char *ours_name, const char *theirs_name, + git_merge_tree_opts *opts); + +int merge_test_diff_list(git_merge_diff_list *diff_list, const struct merge_index_entry expected[], size_t expected_len); + +int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len); + +int merge_test_index(git_index *index, const struct merge_index_entry expected[], size_t expected_len); + +int merge_test_names(git_index *index, const struct merge_name_entry expected[], size_t expected_len); + +int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len); + +int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len); + +#endif diff --git a/tests-clar/merge/trees/automerge.c b/tests-clar/merge/trees/automerge.c new file mode 100644 index 00000000000..7592a926e21 --- /dev/null +++ b/tests-clar/merge/trees/automerge.c @@ -0,0 +1,217 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "buffer.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "fileops.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +#define THEIRS_AUTOMERGE_BRANCH "branch" + +#define THEIRS_UNRELATED_BRANCH "unrelated" +#define THEIRS_UNRELATED_OID "55b4e4687e7a0d9ca367016ed930f385d4022e6f" +#define THEIRS_UNRELATED_PARENT "d6cf6c7741b3316826af1314042550c97ded1d50" + +#define OURS_DIRECTORY_FILE "df_side1" +#define THEIRS_DIRECTORY_FILE "df_side2" + +/* Non-conflicting files, index entries are common to every merge operation */ +#define ADDED_IN_MASTER_INDEX_ENTRY \ + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" } +#define AUTOMERGEABLE_INDEX_ENTRY \ + { 0100644, "f2e1550a0c9e53d5811175864a29536642ae3821", 0, "automergeable.txt" } +#define CHANGED_IN_BRANCH_INDEX_ENTRY \ + { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt" } +#define CHANGED_IN_MASTER_INDEX_ENTRY \ + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" } +#define UNCHANGED_INDEX_ENTRY \ + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" } + +/* Expected REUC entries */ +#define AUTOMERGEABLE_REUC_ENTRY \ + { "automergeable.txt", 0100644, 0100644, 0100644, \ + "6212c31dab5e482247d7977e4f0dd3601decf13b", \ + "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", \ + "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe" } +#define CONFLICTING_REUC_ENTRY \ + { "conflicting.txt", 0100644, 0100644, 0100644, \ + "d427e0b2e138501a3d15cc376077a3631e15bd46", \ + "4e886e602529caa9ab11d71f86634bd1b6e0de10", \ + "2bd0a343aeef7a2cf0d158478966a6e587ff3863" } +#define REMOVED_IN_BRANCH_REUC_ENTRY \ + { "removed-in-branch.txt", 0100644, 0100644, 0, \ + "dfe3f22baa1f6fce5447901c3086bae368de6bdd", \ + "dfe3f22baa1f6fce5447901c3086bae368de6bdd", \ + "" } +#define REMOVED_IN_MASTER_REUC_ENTRY \ + { "removed-in-master.txt", 0100644, 0, 0100644, \ + "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", \ + "", \ + "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5" } + +#define AUTOMERGEABLE_MERGED_FILE \ + "this file is changed in master\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is changed in branch\n" + +#define AUTOMERGEABLE_MERGED_FILE_CRLF \ + "this file is changed in master\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is changed in branch\r\n" + +// Fixture setup and teardown +void test_merge_trees_automerge__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_automerge__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_trees_automerge__automerge(void) +{ + git_index *index; + const git_index_entry *entry; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + git_blob *blob; + + struct merge_index_entry merge_index_entries[] = { + ADDED_IN_MASTER_INDEX_ENTRY, + AUTOMERGEABLE_INDEX_ENTRY, + CHANGED_IN_BRANCH_INDEX_ENTRY, + CHANGED_IN_MASTER_INDEX_ENTRY, + + { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 1, "conflicting.txt" }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" }, + { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 3, "conflicting.txt" }, + + UNCHANGED_INDEX_ENTRY, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + AUTOMERGEABLE_REUC_ENTRY, + REMOVED_IN_BRANCH_REUC_ENTRY, + REMOVED_IN_MASTER_REUC_ENTRY + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 3)); + + cl_assert((entry = git_index_get_bypath(index, "automergeable.txt", 0)) != NULL); + cl_assert(entry->file_size == strlen(AUTOMERGEABLE_MERGED_FILE)); + + cl_git_pass(git_object_lookup((git_object **)&blob, repo, &entry->oid, GIT_OBJ_BLOB)); + cl_assert(memcmp(git_blob_rawcontent(blob), AUTOMERGEABLE_MERGED_FILE, entry->file_size) == 0); + + git_index_free(index); + git_blob_free(blob); +} + +void test_merge_trees_automerge__favor_ours(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + ADDED_IN_MASTER_INDEX_ENTRY, + AUTOMERGEABLE_INDEX_ENTRY, + CHANGED_IN_BRANCH_INDEX_ENTRY, + CHANGED_IN_MASTER_INDEX_ENTRY, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, + UNCHANGED_INDEX_ENTRY, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + AUTOMERGEABLE_REUC_ENTRY, + CONFLICTING_REUC_ENTRY, + REMOVED_IN_BRANCH_REUC_ENTRY, + REMOVED_IN_MASTER_REUC_ENTRY, + }; + + opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_OURS; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 4)); + + git_index_free(index); +} + +void test_merge_trees_automerge__favor_theirs(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + ADDED_IN_MASTER_INDEX_ENTRY, + AUTOMERGEABLE_INDEX_ENTRY, + CHANGED_IN_BRANCH_INDEX_ENTRY, + CHANGED_IN_MASTER_INDEX_ENTRY, + { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt" }, + UNCHANGED_INDEX_ENTRY, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + AUTOMERGEABLE_REUC_ENTRY, + CONFLICTING_REUC_ENTRY, + REMOVED_IN_BRANCH_REUC_ENTRY, + REMOVED_IN_MASTER_REUC_ENTRY, + }; + + opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_THEIRS; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 4)); + + git_index_free(index); +} + +void test_merge_trees_automerge__unrelated(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, + { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 2, "automergeable.txt" }, + { 0100644, "d07ec190c306ec690bac349e87d01c4358e49bb2", 3, "automergeable.txt" }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" }, + { 0100644, "4b253da36a0ae8bfce63aeabd8c5b58429925594", 3, "conflicting.txt" }, + { 0100644, "ef58fdd8086c243bdc81f99e379acacfd21d32d6", 0, "new-in-unrelated1.txt" }, + { 0100644, "948ba6e701c1edab0c2d394fb7c5538334129793", 0, "new-in-unrelated2.txt" }, + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_UNRELATED_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 11)); + + git_index_free(index); +} diff --git a/tests-clar/merge/trees/modeconflict.c b/tests-clar/merge/trees/modeconflict.c new file mode 100644 index 00000000000..0661ce5b3e7 --- /dev/null +++ b/tests-clar/merge/trees/modeconflict.c @@ -0,0 +1,59 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "buffer.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "fileops.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" + +#define DF_SIDE1_BRANCH "df_side1" +#define DF_SIDE2_BRANCH "df_side2" + +// Fixture setup and teardown +void test_merge_trees_modeconflict__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_modeconflict__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_trees_modeconflict__df_conflict(void) +{ + git_index *index; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 2, "dir-10" }, + { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 3, "dir-10" }, + { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6" }, + { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 3, "dir-7" }, + { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 1, "dir-7/file.txt" }, + { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 2, "dir-7/file.txt" }, + { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8" }, + { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 2, "dir-9" }, + { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 1, "dir-9/file.txt" }, + { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 3, "dir-9/file.txt" }, + { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new" }, + { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 1, "file-2" }, + { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 2, "file-2" }, + { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new" }, + { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new" }, + { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 1, "file-4" }, + { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 3, "file-4" }, + { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new" }, + { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 2, "file-5/new" }, + { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 3, "file-5/new" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, DF_SIDE1_BRANCH, DF_SIDE2_BRANCH, NULL)); + + cl_assert(merge_test_index(index, merge_index_entries, 20)); + + git_index_free(index); +} diff --git a/tests-clar/merge/trees/renames.c b/tests-clar/merge/trees/renames.c new file mode 100644 index 00000000000..dc0564bc4a0 --- /dev/null +++ b/tests-clar/merge/trees/renames.c @@ -0,0 +1,253 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "buffer.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "fileops.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" + +#define BRANCH_RENAME_OURS "rename_conflict_ours" +#define BRANCH_RENAME_THEIRS "rename_conflict_theirs" + +// Fixture setup and teardown +void test_merge_trees_renames__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_renames__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_trees_renames__index(void) +{ + git_index *index; + git_merge_tree_opts *opts = NULL; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 1, "0b-rewritten-in-ours.txt" }, + { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 2, "0b-rewritten-in-ours.txt" }, + { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 3, "0b-rewritten-in-ours.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 1, "0c-rewritten-in-theirs.txt" }, + { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 2, "0c-rewritten-in-theirs.txt" }, + { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 3, "0c-rewritten-in-theirs.txt" }, + { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, + { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, + { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, + { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, + { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 2, "3a-newname-in-ours-deleted-in-theirs.txt" }, + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 1, "3a-renamed-in-ours-deleted-in-theirs.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 3, "3b-newname-in-theirs-deleted-in-ours.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 1, "3b-renamed-in-theirs-deleted-in-ours.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 2, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 3, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 1, "4a-renamed-in-ours-added-in-theirs.txt" }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 2, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 3, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 1, "4b-renamed-in-theirs-added-in-ours.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 2, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 3, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 1, "5a-renamed-in-ours-added-in-theirs.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 3, "5a-renamed-in-ours-added-in-theirs.txt" }, + { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 2, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 3, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 1, "5b-renamed-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 2, "5b-renamed-in-theirs-added-in-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 2, "6-both-renamed-1-to-2-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 3, "6-both-renamed-1-to-2-theirs.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 1, "6-both-renamed-1-to-2.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 1, "7-both-renamed-side-1.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 3, "7-both-renamed-side-1.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 1, "7-both-renamed-side-2.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 2, "7-both-renamed-side-2.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, + }; + + struct merge_name_entry merge_name_entries[] = { + { + "3a-renamed-in-ours-deleted-in-theirs.txt", + "3a-newname-in-ours-deleted-in-theirs.txt", + "" + }, + + { + "3b-renamed-in-theirs-deleted-in-ours.txt", + "", + "3b-newname-in-theirs-deleted-in-ours.txt", + }, + + { + "4a-renamed-in-ours-added-in-theirs.txt", + "4a-newname-in-ours-added-in-theirs.txt", + "", + }, + + { + "4b-renamed-in-theirs-added-in-ours.txt", + "", + "4b-newname-in-theirs-added-in-ours.txt", + }, + + { + "5a-renamed-in-ours-added-in-theirs.txt", + "5a-newname-in-ours-added-in-theirs.txt", + "5a-renamed-in-ours-added-in-theirs.txt", + }, + + { + "5b-renamed-in-theirs-added-in-ours.txt", + "5b-renamed-in-theirs-added-in-ours.txt", + "5b-newname-in-theirs-added-in-ours.txt", + }, + + { + "6-both-renamed-1-to-2.txt", + "6-both-renamed-1-to-2-ours.txt", + "6-both-renamed-1-to-2-theirs.txt", + }, + + { + "7-both-renamed-side-1.txt", + "7-both-renamed.txt", + "7-both-renamed-side-1.txt", + }, + + { + "7-both-renamed-side-2.txt", + "7-both-renamed-side-2.txt", + "7-both-renamed.txt", + }, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + { "1a-newname-in-ours-edited-in-theirs.txt", + 0, 0100644, 0, + "", + "c3d02eeef75183df7584d8d13ac03053910c1301", + "" }, + + { "1a-newname-in-ours.txt", + 0, 0100644, 0, + "", + "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", + "" }, + + { "1a-renamed-in-ours-edited-in-theirs.txt", + 0100644, 0, 0100644, + "c3d02eeef75183df7584d8d13ac03053910c1301", + "", + "0d872f8e871a30208305978ecbf9e66d864f1638" }, + + { "1a-renamed-in-ours.txt", + 0100644, 0, 0100644, + "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", + "", + "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb" }, + + { "1b-newname-in-theirs-edited-in-ours.txt", + 0, 0, 0100644, + "", + "", + "241a1005cd9b980732741b74385b891142bcba28" }, + + { "1b-newname-in-theirs.txt", + 0, 0, 0100644, + "", + "", + "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136" }, + + { "1b-renamed-in-theirs-edited-in-ours.txt", + 0100644, 0100644, 0, + "241a1005cd9b980732741b74385b891142bcba28", + "ed9523e62e453e50dd9be1606af19399b96e397a", + "" }, + + { "1b-renamed-in-theirs.txt", + 0100644, 0100644, 0, + "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", + "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", + "" }, + + { "2-newname-in-both.txt", + 0, 0100644, 0100644, + "", + "178940b450f238a56c0d75b7955cb57b38191982", + "178940b450f238a56c0d75b7955cb57b38191982" }, + + { "2-renamed-in-both.txt", + 0100644, 0, 0, + "178940b450f238a56c0d75b7955cb57b38191982", + "", + "" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, + BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, + opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 41)); + cl_assert(merge_test_names(index, merge_name_entries, 9)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 10)); + + git_index_free(index); +} + +void test_merge_trees_renames__no_rename_index(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 1, "0b-rewritten-in-ours.txt" }, + { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 2, "0b-rewritten-in-ours.txt" }, + { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 3, "0b-rewritten-in-ours.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 1, "0c-rewritten-in-theirs.txt" }, + { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 2, "0c-rewritten-in-theirs.txt" }, + { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 3, "0c-rewritten-in-theirs.txt" }, + { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, + { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, + { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 1, "1a-renamed-in-ours-edited-in-theirs.txt" }, + { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 3, "1a-renamed-in-ours-edited-in-theirs.txt" }, + { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, + { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, + { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 1, "1b-renamed-in-theirs-edited-in-ours.txt" }, + { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 2, "1b-renamed-in-theirs-edited-in-ours.txt" }, + { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 2, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 3, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 2, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 3, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 2, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 3, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 2, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 3, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-theirs.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, + BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, + &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 32)); + + git_index_free(index); +} + diff --git a/tests-clar/merge/trees/treediff.c b/tests-clar/merge/trees/treediff.c new file mode 100644 index 00000000000..06ea94e0d30 --- /dev/null +++ b/tests-clar/merge/trees/treediff.c @@ -0,0 +1,543 @@ +#include "clar_libgit2.h" +#include "git2/tree.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "diff.h" +#include "hashsig.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" + +#define TREE_OID_ANCESTOR "0d52e3a556e189ba0948ae56780918011c1b167d" +#define TREE_OID_MASTER "1f81433e3161efbf250576c58fede7f6b836f3d3" +#define TREE_OID_BRANCH "eea9286df54245fea72c5b557291470eb825f38f" +#define TREE_OID_RENAMES1 "f5f9dd5886a6ee20272be0aafc790cba43b31931" +#define TREE_OID_RENAMES2 "5fbfbdc04b4eca46f54f4853a3c5a1dce28f5165" + +#define TREE_OID_DF_ANCESTOR "b8a3a806d3950e8c0a03a34f234a92eff0e2c68d" +#define TREE_OID_DF_SIDE1 "ee1d6f164893c1866a323f072eeed36b855656be" +#define TREE_OID_DF_SIDE2 "6178885b38fe96e825ac0f492c0a941f288b37f6" + +#define TREE_OID_RENAME_CONFLICT_ANCESTOR "476dbb3e207313d1d8aaa120c6ad204bf1295e53" +#define TREE_OID_RENAME_CONFLICT_OURS "c4efe31e9decccc8b2b4d3df9aac2cdfe2995618" +#define TREE_OID_RENAME_CONFLICT_THEIRS "9e7f4359c469f309b6057febf4c6e80742cbed5b" + +void test_merge_trees_treediff__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_treediff__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static void test_find_differences( + const char *ancestor_oidstr, + const char *ours_oidstr, + const char *theirs_oidstr, + struct merge_index_conflict_data *treediff_conflict_data, + size_t treediff_conflict_data_len) +{ + git_merge_diff_list *merge_diff_list = git_merge_diff_list__alloc(repo); + git_oid ancestor_oid, ours_oid, theirs_oid; + git_tree *ancestor_tree, *ours_tree, *theirs_tree; + + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + opts.flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.target_limit = 1000; + opts.rename_threshold = 50; + + opts.metric = git__malloc(sizeof(git_diff_similarity_metric)); + cl_assert(opts.metric != NULL); + + opts.metric->file_signature = git_diff_find_similar__hashsig_for_file; + opts.metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; + opts.metric->free_signature = git_diff_find_similar__hashsig_free; + opts.metric->similarity = git_diff_find_similar__calc_similarity; + opts.metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; + + cl_git_pass(git_oid_fromstr(&ancestor_oid, ancestor_oidstr)); + cl_git_pass(git_oid_fromstr(&ours_oid, ours_oidstr)); + cl_git_pass(git_oid_fromstr(&theirs_oid, theirs_oidstr)); + + cl_git_pass(git_tree_lookup(&ancestor_tree, repo, &ancestor_oid)); + cl_git_pass(git_tree_lookup(&ours_tree, repo, &ours_oid)); + cl_git_pass(git_tree_lookup(&theirs_tree, repo, &theirs_oid)); + + cl_git_pass(git_merge_diff_list__find_differences(merge_diff_list, ancestor_tree, ours_tree, theirs_tree)); + cl_git_pass(git_merge_diff_list__find_renames(repo, merge_diff_list, &opts)); + + /* + dump_merge_index(merge_index); + */ + + cl_assert(treediff_conflict_data_len == merge_diff_list->conflicts.length); + + cl_assert(merge_test_merge_conflicts(&merge_diff_list->conflicts, treediff_conflict_data, treediff_conflict_data_len)); + + git_tree_free(ancestor_tree); + git_tree_free(ours_tree); + git_tree_free(theirs_tree); + + git_merge_diff_list__free(merge_diff_list); + + git__free(opts.metric); +} + +void test_merge_trees_treediff__simple(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE + }, + + { + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED + }, + + { + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_NONE + }, + + { + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE + }, + + { + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED + }, + + { + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_NONE + }, + + { + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE + }, + }; + + test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_BRANCH, treediff_conflict_data, 7); +} + +void test_merge_trees_treediff__df_conflicts(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 0, "dir-10" }, GIT_DELTA_ADDED }, + { { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 0, "dir-10" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_BOTH_ADDED, + }, + + { + { { 0100644, "242591eb280ee9eeb2ce63524b9a8b9bc4cb515d", 0, "dir-10/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_BOTH_DELETED, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 0, "dir-7" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 0, "dir-7/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 0, "dir-7/file.txt" }, GIT_DELTA_MODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8" }, GIT_DELTA_ADDED }, + { {0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 0, "dir-9" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 0, "dir-9/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 0, "dir-9/file.txt" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 0, "file-2" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 0, "file-2" }, GIT_DELTA_MODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 0, "file-4" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 0, "file-4" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { { 0100644, "ac4045f965119e6998f4340ed0f411decfb3ec05", 0, "file-5" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_BOTH_DELETED, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 0, "file-5/new" }, GIT_DELTA_ADDED }, + { { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 0, "file-5/new" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_BOTH_ADDED, + }, + }; + + test_find_differences(TREE_OID_DF_ANCESTOR, TREE_OID_DF_SIDE1, TREE_OID_DF_SIDE2, treediff_conflict_data, 20); +} + +void test_merge_trees_treediff__strict_renames(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "renamed-in-branch.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "renamed.txt" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "copied.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_NONE, + }, + }; + + test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_RENAMES1, treediff_conflict_data, 8); +} + +void test_merge_trees_treediff__rename_conflicts(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED, + }, + + { + { { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-renamed-in-ours-edited-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-renamed-in-ours-edited-in-theirs.txt" }, GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_RENAMED_MODIFIED, + }, + + { + { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-renamed-in-theirs-edited-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-renamed-in-theirs-edited-in-ours.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_MODIFIED, + }, + + { + { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-renamed-in-both.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_BOTH_RENAMED, + }, + + { + { { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-renamed-in-ours-deleted-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, GIT_DELTA_RENAMED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_RENAMED_DELETED, + }, + + { + { { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-renamed-in-theirs-deleted-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_DELETED, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 0, "4a-newname-in-ours-added-in-theirs.txt" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-renamed-in-ours-added-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt" }, GIT_DELTA_RENAMED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-renamed-in-theirs-added-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-newname-in-theirs-added-in-ours.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-ours.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-theirs.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2, + }, + + { + { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, + }, + + { + { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, + }, + }; + + test_find_differences(TREE_OID_RENAME_CONFLICT_ANCESTOR, + TREE_OID_RENAME_CONFLICT_OURS, TREE_OID_RENAME_CONFLICT_THEIRS, treediff_conflict_data, 18); +} + +void test_merge_trees_treediff__best_renames(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "45299c1ca5e07bba1fd90843056fb559f96b1f5a", 0, "renamed-90.txt" }, GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_MODIFIED, + }, + + { + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" },GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_MODIFIED_DELETED, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "5843febcb23480df0b5edb22a21c59c772bb8e29", 0, "renamed-50.txt" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "a77a56a49f8f3ae242e02717f18ebbc60c5cc543", 0, "renamed-75.txt" }, GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + }; + + test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_RENAMES2, treediff_conflict_data, 7); +} diff --git a/tests-clar/merge/trees/trivial.c b/tests-clar/merge/trees/trivial.c new file mode 100644 index 00000000000..7d8d2cbf50f --- /dev/null +++ b/tests-clar/merge/trees/trivial.c @@ -0,0 +1,397 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "refs.h" +#include "fileops.h" +#include "git2/sys/index.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + + +// Fixture setup and teardown +void test_merge_trees_trivial__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_trivial__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + + +static int merge_trivial(git_index **index, const char *ours, const char *theirs, bool automerge) +{ + git_commit *our_commit, *their_commit, *ancestor_commit; + git_tree *our_tree, *their_tree, *ancestor_tree; + git_oid our_oid, their_oid, ancestor_oid; + git_buf branch_buf = GIT_BUF_INIT; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE; + + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours); + cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); + + git_buf_clear(&branch_buf); + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs); + cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); + + cl_git_pass(git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))); + cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); + + cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); + cl_git_pass(git_commit_tree(&our_tree, our_commit)); + cl_git_pass(git_commit_tree(&their_tree, their_commit)); + + cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, &opts)); + + git_buf_free(&branch_buf); + git_tree_free(our_tree); + git_tree_free(their_tree); + git_tree_free(ancestor_tree); + git_commit_free(our_commit); + git_commit_free(their_commit); + git_commit_free(ancestor_commit); + + return 0; +} + +static int merge_trivial_conflict_entrycount(git_index *index) +{ + const git_index_entry *entry; + size_t count = 0; + size_t i; + + for (i = 0; i < git_index_entrycount(index); i++) { + cl_assert(entry = git_index_get_byindex(index, i)); + + if (git_index_entry_stage(entry) > 0) + count++; + } + + return count; +} + +/* 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote */ +void test_merge_trees_trivial__2alt(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "new-in-branch.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head */ +void test_merge_trees_trivial__3alt(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "new-in-3alt.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 4: ancest:(empty)^, head:head, remote:remote = result:no merge */ +void test_merge_trees_trivial__4(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "new-and-different.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "new-and-different.txt", 2)); + cl_assert(entry = git_index_get_bypath(result, "new-and-different.txt", 3)); + + git_index_free(result); +} + +/* 5ALT: ancest:*, head:head, remote:head = result:head */ +void test_merge_trees_trivial__5alt_1(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "new-and-same.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 5ALT: ancest:*, head:head, remote:head = result:head */ +void test_merge_trees_trivial__5alt_2(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "modified-to-same.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ +void test_merge_trees_trivial__6(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 1); + cl_assert(entry = git_index_get_bypath(result, "removed-in-both.txt", 1)); + + git_index_free(result); +} + +/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ +void test_merge_trees_trivial__6_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-both.txt")); + + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ +void test_merge_trees_trivial__8(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 3)); + + git_index_free(result); +} + +/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ +void test_merge_trees_trivial__8_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); + + cl_assert(git_index_reuc_entrycount(result) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-8.txt")); + + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ +void test_merge_trees_trivial__7(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 3)); + + git_index_free(result); +} + +/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ +void test_merge_trees_trivial__7_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 3)); + + git_index_free(result); +} + +/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__10(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 2)); + + git_index_free(result); +} + +/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__10_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); + + cl_assert(git_index_reuc_entrycount(result) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-10-branch.txt")); + + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__9(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 2)); + + git_index_free(result); +} + +/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__9_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 2)); + + git_index_free(result); +} + +/* 13: ancest:ancest+, head:head, remote:ancest = result:head */ +void test_merge_trees_trivial__13(void) +{ + git_index *result; + const git_index_entry *entry; + git_oid expected_oid; + + cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "modified-in-13.txt", 0)); + cl_git_pass(git_oid_fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b")); + cl_assert(git_oid_cmp(&entry->oid, &expected_oid) == 0); + + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ +void test_merge_trees_trivial__14(void) +{ + git_index *result; + const git_index_entry *entry; + git_oid expected_oid; + + cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "modified-in-14-branch.txt", 0)); + cl_git_pass(git_oid_fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9")); + cl_assert(git_oid_cmp(&entry->oid, &expected_oid) == 0); + + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 11: ancest:ancest+, head:head, remote:remote = result:no merge */ +void test_merge_trees_trivial__11(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "modified-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 3); + cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 2)); + cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 3)); + + git_index_free(result); +} diff --git a/tests-clar/merge/setup.c b/tests-clar/merge/workdir/setup.c similarity index 85% rename from tests-clar/merge/setup.c rename to tests-clar/merge/workdir/setup.c index 946c67e7bc1..6ae9dbb147c 100644 --- a/tests-clar/merge/setup.c +++ b/tests-clar/merge/workdir/setup.c @@ -32,15 +32,15 @@ static git_index *repo_index; #define OCTO5_OID "e4f618a2c3ed0669308735727df5ebf2447f022f" // Fixture setup and teardown -void test_merge_setup__initialize(void) +void test_merge_workdir_setup__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_repository_index(&repo_index, repo); + git_repository_index(&repo_index, repo); } -void test_merge_setup__cleanup(void) +void test_merge_workdir_setup__cleanup(void) { - git_index_free(repo_index); + git_index_free(repo_index); cl_git_sandbox_cleanup(); } @@ -48,7 +48,8 @@ static void write_file_contents(const char *filename, const char *output) { git_buf file_path_buf = GIT_BUF_INIT; - git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), filename); + git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), + filename); cl_git_rewritefile(file_path_buf.ptr, output); git_buf_free(&file_path_buf); @@ -72,7 +73,7 @@ static int merge_head_foreach_cb(const git_oid *oid, void *payload) return 0; } -void test_merge_setup__head_notfound(void) +void test_merge_workdir_setup__head_notfound(void) { int error; @@ -81,7 +82,7 @@ void test_merge_setup__head_notfound(void) cl_assert(error == GIT_ENOTFOUND); } -void test_merge_setup__head_invalid_oid(void) +void test_merge_workdir_setup__head_invalid_oid(void) { int error; @@ -92,7 +93,7 @@ void test_merge_setup__head_invalid_oid(void) cl_assert(error == -1); } -void test_merge_setup__head_foreach_nonewline(void) +void test_merge_workdir_setup__head_foreach_nonewline(void) { int error; @@ -103,7 +104,7 @@ void test_merge_setup__head_foreach_nonewline(void) cl_assert(error == -1); } -void test_merge_setup__head_foreach_one(void) +void test_merge_workdir_setup__head_foreach_one(void) { const char *expected = THEIRS_SIMPLE_OID; @@ -117,7 +118,7 @@ void test_merge_setup__head_foreach_one(void) cl_assert(cb_data.i == cb_data.len); } -void test_merge_setup__head_foreach_octopus(void) +void test_merge_workdir_setup__head_foreach_octopus(void) { const char *expected[] = { THEIRS_SIMPLE_OID, OCTO1_OID, OCTO2_OID, OCTO3_OID, OCTO4_OID, OCTO5_OID }; diff --git a/tests-clar/network/refspecs.c b/tests-clar/network/refspecs.c index b3d80fb858b..676a1fa996a 100644 --- a/tests-clar/network/refspecs.c +++ b/tests-clar/network/refspecs.c @@ -81,4 +81,7 @@ void test_network_refspecs__parsing(void) assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); + + assert_refspec(GIT_DIRECTION_FETCH, "master", true); + assert_refspec(GIT_DIRECTION_PUSH, "master", true); } diff --git a/tests-clar/network/remote/local.c b/tests-clar/network/remote/local.c index 7e847e654c8..74ef63dc95f 100644 --- a/tests-clar/network/remote/local.c +++ b/tests-clar/network/remote/local.c @@ -100,3 +100,44 @@ void test_network_remote_local__nested_tags_are_completely_peeled(void) cl_git_pass(git_remote_ls(remote, &ensure_peeled__cb, NULL)); } + +void test_network_remote_local__shorthand_fetch_refspec0(void) +{ + const char *refspec = "master:remotes/sloppy/master"; + const char *refspec2 = "master:boh/sloppy/master"; + + 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, NULL, NULL)); + cl_git_pass(git_remote_update_tips(remote)); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master")); + git_reference_free(ref); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/heads/boh/sloppy/master")); + git_reference_free(ref); +} + +void test_network_remote_local__shorthand_fetch_refspec1(void) +{ + const char *refspec = "master"; + const char *refspec2 = "hard_tag"; + + 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, NULL, NULL)); + cl_git_pass(git_remote_update_tips(remote)); + + cl_git_fail(git_reference_lookup(&ref, repo, "refs/remotes/master")); + + cl_git_fail(git_reference_lookup(&ref, repo, "refs/tags/hard_tag")); +} diff --git a/tests-clar/network/remote/remotes.c b/tests-clar/network/remote/remotes.c index a5ff7415fcb..4c24db8eb9c 100644 --- a/tests-clar/network/remote/remotes.c +++ b/tests-clar/network/remote/remotes.c @@ -13,7 +13,7 @@ void test_network_remote_remotes__initialize(void) cl_git_pass(git_remote_load(&_remote, _repo, "test")); - _refspec = git_remote_fetchspec(_remote); + _refspec = git_remote_get_refspec(_remote, 0); cl_assert(_refspec != NULL); } @@ -109,31 +109,57 @@ void test_network_remote_remotes__refspec_parsing(void) cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/test/*"); } -void test_network_remote_remotes__set_fetchspec(void) +void test_network_remote_remotes__add_fetchspec(void) { - cl_git_pass(git_remote_set_fetchspec(_remote, "refs/*:refs/*")); - _refspec = git_remote_fetchspec(_remote); + size_t size; + + size = git_remote_refspec_count(_remote); + + cl_git_pass(git_remote_add_fetch(_remote, "refs/*:refs/*")); + + size++; + cl_assert_equal_i(size, git_remote_refspec_count(_remote)); + + _refspec = git_remote_get_refspec(_remote, size - 1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); + cl_assert_equal_i(_refspec->push, false); } -void test_network_remote_remotes__set_pushspec(void) +void test_network_remote_remotes__add_pushspec(void) { - cl_git_pass(git_remote_set_pushspec(_remote, "refs/*:refs/*")); - _refspec = git_remote_pushspec(_remote); + size_t size; + + size = git_remote_refspec_count(_remote); + + cl_git_pass(git_remote_add_push(_remote, "refs/*:refs/*")); + size++; + cl_assert_equal_i(size, git_remote_refspec_count(_remote)); + + _refspec = git_remote_get_refspec(_remote, size - 1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); + + cl_assert_equal_i(_refspec->push, true); } void test_network_remote_remotes__save(void) { + git_strarray array; + const char *fetch_refspec = "refs/heads/*:refs/remotes/upstream/*"; + const char *push_refspec = "refs/heads/*:refs/heads/*"; + git_remote_free(_remote); _remote = NULL; /* Set up the remote and save it to config */ cl_git_pass(git_remote_create(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2")); - cl_git_pass(git_remote_set_fetchspec(_remote, "refs/heads/*:refs/remotes/upstream/*")); - cl_git_pass(git_remote_set_pushspec(_remote, "refs/heads/*:refs/heads/*")); + git_remote_clear_refspecs(_remote); + + cl_git_pass(git_remote_add_fetch(_remote, fetch_refspec)); + cl_git_pass(git_remote_add_push(_remote, push_refspec)); cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/libgit2_push")); cl_git_pass(git_remote_save(_remote)); git_remote_free(_remote); @@ -142,19 +168,17 @@ void test_network_remote_remotes__save(void) /* Load it from config and make sure everything matches */ cl_git_pass(git_remote_load(&_remote, _repo, "upstream")); - _refspec = git_remote_fetchspec(_remote); - cl_assert(_refspec != NULL); - cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); - cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/upstream/*"); - cl_assert_equal_i(0, git_refspec_force(_refspec)); - - _refspec = git_remote_pushspec(_remote); - cl_assert(_refspec != NULL); - cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); - cl_assert_equal_s(git_refspec_dst(_refspec), "refs/heads/*"); + cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote)); + cl_assert_equal_i(1, array.count); + cl_assert_equal_s(fetch_refspec, array.strings[0]); + git_strarray_free(&array); + cl_git_pass(git_remote_get_push_refspecs(&array, _remote)); + cl_assert_equal_i(1, array.count); + cl_assert_equal_s(push_refspec, array.strings[0]); cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/libgit2_push"); + git_strarray_free(&array); /* remove the pushurl again and see if we can save that too */ cl_git_pass(git_remote_set_pushurl(_remote, NULL)); @@ -265,7 +289,7 @@ void test_network_remote_remotes__add(void) _remote = NULL; cl_git_pass(git_remote_load(&_remote, _repo, "addtest")); - _refspec = git_remote_fetchspec(_remote); + _refspec = git_vector_get(&_remote->refspecs, 0); cl_assert_equal_s("refs/heads/*", git_refspec_src(_refspec)); cl_assert(git_refspec_force(_refspec) == 1); cl_assert_equal_s("refs/remotes/addtest/*", git_refspec_dst(_refspec)); @@ -386,3 +410,43 @@ void test_network_remote_remotes__cannot_create_a_remote_which_name_is_invalid(v assert_cannot_create_remote(".lock", GIT_EINVALIDSPEC); assert_cannot_create_remote("a.lock", GIT_EINVALIDSPEC); } + +static const char *fetch_refspecs[] = { + "+refs/heads/*:refs/remotes/origin/*", + "refs/tags/*:refs/tags/*", + "+refs/pull/*:refs/pull/*", +}; + +static const char *push_refspecs[] = { + "refs/heads/*:refs/heads/*", + "refs/tags/*:refs/tags/*", + "refs/notes/*:refs/notes/*", +}; + +void test_network_remote_remotes__query_refspecs(void) +{ + git_remote *remote; + git_strarray array; + int i; + + cl_git_pass(git_remote_create_inmemory(&remote, _repo, NULL, "git://github.com/libgit2/libgit2")); + + for (i = 0; i < 3; i++) { + cl_git_pass(git_remote_add_fetch(remote, fetch_refspecs[i])); + cl_git_pass(git_remote_add_push(remote, push_refspecs[i])); + } + + cl_git_pass(git_remote_get_fetch_refspecs(&array, remote)); + for (i = 0; i < 3; i++) { + cl_assert_equal_s(fetch_refspecs[i], array.strings[i]); + } + git_strarray_free(&array); + + cl_git_pass(git_remote_get_push_refspecs(&array, remote)); + for (i = 0; i < 3; i++) { + cl_assert_equal_s(push_refspecs[i], array.strings[i]); + } + git_strarray_free(&array); + + git_remote_free(remote); +} diff --git a/tests-clar/object/cache.c b/tests-clar/object/cache.c new file mode 100644 index 00000000000..e06760e2aed --- /dev/null +++ b/tests-clar/object/cache.c @@ -0,0 +1,287 @@ +#include "clar_libgit2.h" +#include "repository.h" + +static git_repository *g_repo; + +void test_object_cache__initialize(void) +{ + g_repo = NULL; +} + +void test_object_cache__cleanup(void) +{ + git_repository_free(g_repo); + g_repo = NULL; + + git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); +} + +static struct { + git_otype type; + const char *sha; +} g_data[] = { + /* HEAD */ + { GIT_OBJ_BLOB, "a8233120f6ad708f843d861ce2b7228ec4e3dec6" }, /* README */ + { GIT_OBJ_BLOB, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc" }, /* branch_file.txt */ + { GIT_OBJ_BLOB, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd" }, /* new.txt */ + + /* refs/heads/subtrees */ + { GIT_OBJ_BLOB, "1385f264afb75a56a5bec74243be9b367ba4ca08" }, /* README */ + { GIT_OBJ_TREE, "f1425cef211cc08caa31e7b545ffb232acb098c3" }, /* ab */ + { GIT_OBJ_BLOB, "d6c93164c249c8000205dd4ec5cbca1b516d487f" }, /* ab/4.txt */ + { GIT_OBJ_TREE, "9a03079b8a8ee85a0bee58bf9be3da8b62414ed4" }, /* ab/c */ + { GIT_OBJ_BLOB, "270b8ea76056d5cad83af921837702d3e3c2924d" }, /* ab/c/3.txt */ + { GIT_OBJ_TREE, "b6361fc6a97178d8fc8639fdeed71c775ab52593" }, /* ab/de */ + { GIT_OBJ_BLOB, "e7b4ad382349ff96dd8199000580b9b1e2042eb0" }, /* ab/de/2.txt */ + { GIT_OBJ_TREE, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54" }, /* ab/de/fgh */ + { GIT_OBJ_BLOB, "1f67fc4386b2d171e0d21be1c447e12660561f9b" }, /* ab/de/fgh/1.txt */ + { GIT_OBJ_BLOB, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, /* branch_file.txt */ + { GIT_OBJ_BLOB, "fa49b077972391ad58037050f2a75f74e3671e92" }, /* new.txt */ + + /* refs/heads/chomped */ + { GIT_OBJ_BLOB, "0266163a49e280c4f5ed1e08facd36a2bd716bcf" }, /* readme.txt */ + + { 0, NULL }, + { 0, NULL } +}; + +void test_object_cache__cache_everything(void) +{ + int i, start; + git_oid oid; + git_odb_object *odb_obj; + git_object *obj; + git_odb *odb; + + git_libgit2_opts( + GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767); + + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_odb(&odb, g_repo)); + + start = (int)git_cache_size(&g_repo->objects); + + for (i = 0; g_data[i].sha != NULL; ++i) { + int count = (int)git_cache_size(&g_repo->objects); + + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + + /* alternate between loading raw and parsed objects */ + if ((i & 1) == 0) { + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } else { + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects)); + } + + cl_assert_equal_i(i, git_cache_size(&g_repo->objects) - start); + + git_odb_free(odb); + + for (i = 0; g_data[i].sha != NULL; ++i) { + int count = (int)git_cache_size(&g_repo->objects); + + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + + cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects)); + } +} + +void test_object_cache__cache_no_blobs(void) +{ + int i, start, nonblobs = 0; + git_oid oid; + git_odb_object *odb_obj; + git_object *obj; + git_odb *odb; + + git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); + + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_odb(&odb, g_repo)); + + start = (int)git_cache_size(&g_repo->objects); + + for (i = 0; g_data[i].sha != NULL; ++i) { + int count = (int)git_cache_size(&g_repo->objects); + + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + + /* alternate between loading raw and parsed objects */ + if ((i & 1) == 0) { + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } else { + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + if (g_data[i].type == GIT_OBJ_BLOB) + cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects)); + else { + cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects)); + nonblobs++; + } + } + + cl_assert_equal_i(nonblobs, git_cache_size(&g_repo->objects) - start); + + git_odb_free(odb); +} + +static void *cache_parsed(void *arg) +{ + int i; + git_oid oid; + git_object *obj; + + for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + for (i = 0; i < ((int *)arg)[1]; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + return arg; +} + +static void *cache_raw(void *arg) +{ + int i; + git_oid oid; + git_odb *odb; + git_odb_object *odb_obj; + + cl_git_pass(git_repository_odb(&odb, g_repo)); + + for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } + + for (i = 0; i < ((int *)arg)[1]; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } + + git_odb_free(odb); + + return arg; +} + +#define REPEAT 20 +#define THREADCOUNT 50 + +void test_object_cache__threadmania(void) +{ + int try, th, max_i; + void *data; + void *(*fn)(void *); + +#ifdef GIT_THREADS + git_thread t[THREADCOUNT]; +#endif + + for (max_i = 0; g_data[max_i].sha != NULL; ++max_i) + /* count up */; + + for (try = 0; try < REPEAT; ++try) { + + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + + for (th = 0; th < THREADCOUNT; ++th) { + data = git__malloc(2 * sizeof(int)); + + ((int *)data)[0] = th; + ((int *)data)[1] = th % max_i; + + fn = (th & 1) ? cache_parsed : cache_raw; + +#ifdef GIT_THREADS + cl_git_pass(git_thread_create(&t[th], NULL, fn, data)); +#else + cl_assert(fn(data) == data); + git__free(data); +#endif + } + +#ifdef GIT_THREADS + for (th = 0; th < THREADCOUNT; ++th) { + cl_git_pass(git_thread_join(t[th], &data)); + cl_assert_equal_i(th, ((int *)data)[0]); + git__free(data); + } +#endif + + git_repository_free(g_repo); + g_repo = NULL; + } +} + +static void *cache_quick(void *arg) +{ + git_oid oid; + git_object *obj; + + cl_git_pass(git_oid_fromstr(&oid, g_data[4].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[4].type == git_object_type(obj)); + git_object_free(obj); + + return arg; +} + +void test_object_cache__fast_thread_rush(void) +{ + int try, th, data[THREADCOUNT*2]; +#ifdef GIT_THREADS + git_thread t[THREADCOUNT*2]; +#endif + + for (try = 0; try < REPEAT; ++try) { + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + + for (th = 0; th < THREADCOUNT*2; ++th) { + data[th] = th; +#ifdef GIT_THREADS + cl_git_pass( + git_thread_create(&t[th], NULL, cache_quick, &data[th])); +#else + cl_assert(cache_quick(&data[th]) == &data[th]); +#endif + } + +#ifdef GIT_THREADS + for (th = 0; th < THREADCOUNT*2; ++th) { + void *rval; + cl_git_pass(git_thread_join(t[th], &rval)); + cl_assert_equal_i(th, *((int *)rval)); + } +#endif + + git_repository_free(g_repo); + g_repo = NULL; + } +} diff --git a/tests-clar/object/raw/write.c b/tests-clar/object/raw/write.c index 1b28d0df7e4..9709c0302cd 100644 --- a/tests-clar/object/raw/write.c +++ b/tests-clar/object/raw/write.c @@ -1,5 +1,6 @@ - #include "clar_libgit2.h" +#include "git2/odb_backend.h" + #include "fileops.h" #include "odb.h" @@ -62,6 +63,7 @@ void test_body(object_data *d, git_rawobj *o) git_odb *db; git_oid id1, id2; git_odb_object *obj; + git_rawobj tmp; make_odb_dir(); cl_git_pass(git_odb_open(&db, odb_dir)); @@ -72,7 +74,12 @@ void test_body(object_data *d, git_rawobj *o) check_object_files(d); cl_git_pass(git_odb_read(&obj, db, &id1)); - cmp_objects(&obj->raw, o); + + tmp.data = obj->buffer; + tmp.len = obj->cached.size; + tmp.type = obj->cached.type; + + cmp_objects(&tmp, o); git_odb_object_free(obj); git_odb_free(db); diff --git a/tests-clar/odb/loose.c b/tests-clar/odb/loose.c index f95dc28d4db..9539bb24c7a 100644 --- a/tests-clar/odb/loose.c +++ b/tests-clar/odb/loose.c @@ -30,6 +30,7 @@ static void test_read_object(object_data *data) git_oid id; git_odb_object *obj; git_odb *odb; + git_rawobj tmp; write_object_files(data); @@ -37,7 +38,11 @@ static void test_read_object(object_data *data) cl_git_pass(git_oid_fromstr(&id, data->id)); cl_git_pass(git_odb_read(&obj, odb, &id)); - cmp_objects((git_rawobj *)&obj->raw, data); + tmp.data = obj->buffer; + tmp.len = obj->cached.size; + tmp.type = obj->cached.type; + + cmp_objects(&tmp, data); git_odb_object_free(obj); git_odb_free(odb); diff --git a/tests-clar/odb/packed.c b/tests-clar/odb/packed.c index 90e9f3abdab..b4f549b58f9 100644 --- a/tests-clar/odb/packed.c +++ b/tests-clar/odb/packed.c @@ -46,8 +46,8 @@ void test_odb_packed__read_header_0(void) cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); - cl_assert(obj->raw.len == len); - cl_assert(obj->raw.type == type); + cl_assert(obj->cached.size == len); + cl_assert(obj->cached.type == type); git_odb_object_free(obj); } @@ -70,8 +70,8 @@ void test_odb_packed__read_header_1(void) cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); - cl_assert(obj->raw.len == len); - cl_assert(obj->raw.type == type); + cl_assert(obj->cached.size == len); + cl_assert(obj->cached.type == type); git_odb_object_free(obj); } diff --git a/tests-clar/odb/packed_one.c b/tests-clar/odb/packed_one.c index e9d246c234a..0c6ed387b4d 100644 --- a/tests-clar/odb/packed_one.c +++ b/tests-clar/odb/packed_one.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" -#include "odb.h" +#include "git2/odb_backend.h" + #include "pack_data_one.h" #include "pack.h" @@ -51,8 +52,8 @@ void test_odb_packed_one__read_header_0(void) cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); - cl_assert(obj->raw.len == len); - cl_assert(obj->raw.type == type); + cl_assert(obj->cached.size == len); + cl_assert(obj->cached.type == type); git_odb_object_free(obj); } diff --git a/tests-clar/odb/sorting.c b/tests-clar/odb/sorting.c index b4f9e44bca4..147a160c873 100644 --- a/tests-clar/odb/sorting.c +++ b/tests-clar/odb/sorting.c @@ -1,13 +1,12 @@ #include "clar_libgit2.h" -#include "git2/odb_backend.h" -#include "odb.h" +#include "git2/sys/odb_backend.h" typedef struct { git_odb_backend base; - int position; + size_t position; } fake_backend; -static git_odb_backend *new_backend(int position) +static git_odb_backend *new_backend(size_t position) { fake_backend *b; @@ -22,14 +21,13 @@ static git_odb_backend *new_backend(int position) static void check_backend_sorting(git_odb *odb) { - unsigned int i; - - for (i = 0; i < odb->backends.length; ++i) { - fake_backend *internal = - *((fake_backend **)git_vector_get(&odb->backends, i)); + size_t i, max_i = git_odb_num_backends(odb); + fake_backend *internal; + for (i = 0; i < max_i; ++i) { + cl_git_pass(git_odb_get_backend((git_odb_backend **)&internal, odb, i)); cl_assert(internal != NULL); - cl_assert(internal->position == (int)i); + cl_assert_equal_sz(i, internal->position); } } diff --git a/tests-clar/online/fetch.c b/tests-clar/online/fetch.c index a0ee7aac815..bfa1eb9721f 100644 --- a/tests-clar/online/fetch.c +++ b/tests-clar/online/fetch.c @@ -134,3 +134,30 @@ void test_online_fetch__can_cancel(void) git_remote_disconnect(remote); git_remote_free(remote); } + +int ls_cb(git_remote_head *rhead, void *payload) +{ + int *nr = payload; + GIT_UNUSED(rhead); + + (*nr)++; + + return 0; +} + +void test_online_fetch__ls_disconnected(void) +{ + git_remote *remote; + int nr_before = 0, nr_after = 0; + + cl_git_pass(git_remote_create(&remote, _repo, "test", + "http://github.com/libgit2/TestGitRepository.git")); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); + cl_git_pass(git_remote_ls(remote, ls_cb, &nr_before)); + git_remote_disconnect(remote); + cl_git_pass(git_remote_ls(remote, ls_cb, &nr_after)); + + cl_assert_equal_i(nr_before, nr_after); + + git_remote_free(remote); +} diff --git a/tests-clar/online/fetchhead.c b/tests-clar/online/fetchhead.c index a8a5bb91867..e14ae0926cb 100644 --- a/tests-clar/online/fetchhead.c +++ b/tests-clar/online/fetchhead.c @@ -42,8 +42,10 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet 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_set_fetchspec(remote, fetchspec); + if(fetchspec != NULL) { + git_remote_clear_refspecs(remote); + git_remote_add_fetch(remote, fetchspec); + } cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_download(remote, NULL, NULL)); diff --git a/tests-clar/online/push.c b/tests-clar/online/push.c index 907d6d29ff3..5dc7974c7d2 100644 --- a/tests-clar/online/push.c +++ b/tests-clar/online/push.c @@ -160,7 +160,7 @@ static int tracking_branch_list_cb(const char *branch_name, git_branch_t branch_ */ static void verify_tracking_branches(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len) { - git_refspec *fetch_spec = &remote->fetch; + git_refspec *fetch_spec; size_t i, j; git_buf msg = GIT_BUF_INIT; git_buf ref_name = GIT_BUF_INIT; @@ -179,7 +179,8 @@ static void verify_tracking_branches(git_remote *remote, expected_ref expected_r /* Convert remote reference name into tracking branch name. * If the spec is not under refs/heads/, then skip. */ - if (!git_refspec_src_matches(fetch_spec, expected_refs[i].name)) + fetch_spec = git_remote__matching_refspec(remote, expected_refs[i].name); + if (!fetch_spec) continue; cl_git_pass(git_refspec_transform_r(&ref_name, fetch_spec, expected_refs[i].name)); diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 6ee09c0c753..243b5bb3758 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -1,13 +1,15 @@ #include "clar_libgit2.h" -#include "refdb.h" -#include "repository.h" + +#include "buffer.h" +#include "posix.h" +#include "path.h" +#include "refs.h" + #include "testdb.h" #define TEST_REPO_PATH "testrepo" static git_repository *repo; -static git_refdb *refdb; -static git_refdb_backend *refdb_backend; int unlink_ref(void *payload, git_buf *file) { @@ -27,7 +29,7 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi const char *repo_path; git_buf repo_refs_dir = GIT_BUF_INIT; int error = 0; - + repo_path = git_repository_path(repo); git_buf_joinpath(&repo_refs_dir, repo_path, "HEAD"); @@ -39,7 +41,7 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi git_buf_joinpath(&repo_refs_dir, git_buf_cstr(&repo_refs_dir), "heads"); if (git_path_direach(&repo_refs_dir, cb, NULL) != 0) return -1; - + git_buf_joinpath(&repo_refs_dir, repo_path, "packed-refs"); if (git_path_exists(git_buf_cstr(&repo_refs_dir)) && cb(NULL, &repo_refs_dir) < 0) @@ -53,17 +55,19 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi void test_refdb_inmemory__initialize(void) { git_buf repo_refs_dir = GIT_BUF_INIT; + git_refdb *refdb; + git_refdb_backend *refdb_backend; repo = cl_git_sandbox_init(TEST_REPO_PATH); cl_git_pass(git_repository_refdb(&refdb, repo)); cl_git_pass(refdb_backend_test(&refdb_backend, repo)); cl_git_pass(git_refdb_set_backend(refdb, refdb_backend)); - - + ref_file_foreach(repo, unlink_ref); git_buf_free(&repo_refs_dir); + git_refdb_free(refdb); } void test_refdb_inmemory__cleanup(void) @@ -75,10 +79,10 @@ void test_refdb_inmemory__doesnt_write_ref_file(void) { git_reference *ref; git_oid oid; - + cl_git_pass(git_oid_fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&ref, repo, GIT_REFS_HEADS_DIR "test1", &oid, 0)); - + ref_file_foreach(repo, empty); git_reference_free(ref); @@ -88,10 +92,10 @@ void test_refdb_inmemory__read(void) { git_reference *write1, *write2, *write3, *read1, *read2, *read3; git_oid oid1, oid2, oid3; - + cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0)); - + cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d")); cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0)); @@ -124,8 +128,8 @@ int foreach_test(const char *ref_name, void *payload) { git_reference *ref; git_oid expected; - int *i = payload; - + size_t *i = payload; + cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); if (*i == 0) @@ -135,10 +139,10 @@ int foreach_test(const char *ref_name, void *payload) else if (*i == 2) cl_git_pass(git_oid_fromstr(&expected, "763d71aadf09a7951596c9746c024e7eece7c7af")); - cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0); - + cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0); + ++(*i); - + git_reference_free(ref); return 0; @@ -149,19 +153,19 @@ void test_refdb_inmemory__foreach(void) git_reference *write1, *write2, *write3; git_oid oid1, oid2, oid3; size_t i = 0; - + cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0)); - + cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d")); cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0)); - + cl_git_pass(git_oid_fromstr(&oid3, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0)); - - cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i)); - cl_assert(i == 3); - + + cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i)); + cl_assert_equal_i(3, (int)i); + git_reference_free(write1); git_reference_free(write2); git_reference_free(write3); @@ -171,17 +175,17 @@ int delete_test(const char *ref_name, void *payload) { git_reference *ref; git_oid expected; - int *i = payload; - + size_t *i = payload; + cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); - - cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d")); - cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0); - + + cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d")); + cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0); + ++(*i); - + git_reference_free(ref); - + return 0; } @@ -190,24 +194,24 @@ void test_refdb_inmemory__delete(void) git_reference *write1, *write2, *write3; git_oid oid1, oid2, oid3; size_t i = 0; - + cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0)); - + cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d")); cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0)); - + cl_git_pass(git_oid_fromstr(&oid3, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0)); - + git_reference_delete(write1); git_reference_free(write1); - + git_reference_delete(write3); git_reference_free(write3); - + cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, delete_test, &i)); - cl_assert(i == 1); + cl_assert_equal_i(1, (int)i); git_reference_free(write2); } diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c index a8e7ba5fef7..627254e4451 100644 --- a/tests-clar/refdb/testdb.c +++ b/tests-clar/refdb/testdb.c @@ -1,23 +1,18 @@ -#include "common.h" #include "vector.h" #include "util.h" -#include -#include -#include -#include +#include "testdb.h" typedef struct refdb_test_backend { git_refdb_backend parent; - + git_repository *repo; - git_refdb *refdb; git_vector refs; } refdb_test_backend; typedef struct refdb_test_entry { char *name; git_ref_t type; - + union { git_oid oid; char *symbolic; @@ -38,19 +33,19 @@ static int refdb_test_backend__exists( refdb_test_backend *backend; refdb_test_entry *entry; size_t i; - + assert(_backend); backend = (refdb_test_backend *)_backend; - + *exists = 0; - + git_vector_foreach(&backend->refs, i, entry) { if (strcmp(entry->name, ref_name) == 0) { *exists = 1; break; } } - + return 0; } @@ -60,18 +55,18 @@ static int refdb_test_backend__write( { refdb_test_backend *backend; refdb_test_entry *entry; - + assert(_backend); backend = (refdb_test_backend *)_backend; entry = git__calloc(1, sizeof(refdb_test_entry)); GITERR_CHECK_ALLOC(entry); - + entry->name = git__strdup(git_reference_name(ref)); GITERR_CHECK_ALLOC(entry->name); - + entry->type = git_reference_type(ref); - + if (entry->type == GIT_REF_OID) git_oid_cpy(&entry->target.oid, git_reference_target(ref)); else { @@ -80,7 +75,7 @@ static int refdb_test_backend__write( } git_vector_insert(&backend->refs, entry); - + return 0; } @@ -95,17 +90,21 @@ static int refdb_test_backend__lookup( assert(_backend); backend = (refdb_test_backend *)_backend; - + git_vector_foreach(&backend->refs, i, entry) { if (strcmp(entry->name, ref_name) == 0) { - const git_oid *oid = - entry->type == GIT_REF_OID ? &entry->target.oid : NULL; - const char *symbolic = - entry->type == GIT_REF_SYMBOLIC ? entry->target.symbolic : NULL; - - if ((*out = git_reference__alloc(backend->refdb, ref_name, oid, symbolic)) == NULL) + + if (entry->type == GIT_REF_OID) { + *out = git_reference__alloc(ref_name, + &entry->target.oid, NULL); + } else if (entry->type == GIT_REF_SYMBOLIC) { + *out = git_reference__alloc_symbolic(ref_name, + entry->target.symbolic); + } + + if (*out == NULL) return -1; - + return 0; } } @@ -122,21 +121,21 @@ static int refdb_test_backend__foreach( refdb_test_backend *backend; refdb_test_entry *entry; size_t i; - + assert(_backend); backend = (refdb_test_backend *)_backend; git_vector_foreach(&backend->refs, i, entry) { if (entry->type == GIT_REF_OID && (list_flags & GIT_REF_OID) == 0) continue; - + if (entry->type == GIT_REF_SYMBOLIC && (list_flags & GIT_REF_SYMBOLIC) == 0) continue; - + if (callback(entry->name, payload) != 0) return GIT_EUSER; } - + return 0; } @@ -144,7 +143,7 @@ static void refdb_test_entry_free(refdb_test_entry *entry) { if (entry->type == GIT_REF_SYMBOLIC) git__free(entry->target.symbolic); - + git__free(entry->name); git__free(entry); } @@ -175,14 +174,14 @@ static void refdb_test_backend__free(git_refdb_backend *_backend) refdb_test_backend *backend; refdb_test_entry *entry; size_t i; - + assert(_backend); backend = (refdb_test_backend *)_backend; git_vector_foreach(&backend->refs, i, entry) refdb_test_entry_free(entry); - git_vector_free(&backend->refs); + git_vector_free(&backend->refs); git__free(backend); } @@ -191,19 +190,13 @@ int refdb_backend_test( git_repository *repo) { refdb_test_backend *backend; - git_refdb *refdb; - int error = 0; - - if ((error = git_repository_refdb(&refdb, repo)) < 0) - return error; backend = git__calloc(1, sizeof(refdb_test_backend)); GITERR_CHECK_ALLOC(backend); - + git_vector_init(&backend->refs, 0, ref_name_cmp); backend->repo = repo; - backend->refdb = refdb; backend->parent.exists = &refdb_test_backend__exists; backend->parent.lookup = &refdb_test_backend__lookup; diff --git a/tests-clar/refdb/testdb.h b/tests-clar/refdb/testdb.h index e38abd96704..a0d1bbc48bd 100644 --- a/tests-clar/refdb/testdb.h +++ b/tests-clar/refdb/testdb.h @@ -1,3 +1,9 @@ +#include +#include +#include +#include +#include + int refdb_backend_test( git_refdb_backend **backend_out, git_repository *repo); diff --git a/tests-clar/refs/branches/remote.c b/tests-clar/refs/branches/remote.c index 5272d1236a7..6043828b30c 100644 --- a/tests-clar/refs/branches/remote.c +++ b/tests-clar/refs/branches/remote.c @@ -42,7 +42,7 @@ void test_refs_branches_remote__insufficient_buffer_returns_error(void) cl_git_fail_with(git_branch_remote_name(remotename, expected_remote_name_length - 1, g_repo, remote_tracking_branch_name), - GIT_ERROR); + expected_remote_name_length); } void test_refs_branches_remote__no_matching_remote_returns_error(void) @@ -69,7 +69,8 @@ void test_refs_branches_remote__ambiguous_remote_returns_error(void) cl_git_pass(git_remote_create(&remote, g_repo, "addtest", "http://github.com/libgit2/libgit2")); /* Update the remote fetch spec */ - cl_git_pass(git_remote_set_fetchspec(remote, "refs/heads/*:refs/remotes/test/*")); + git_remote_clear_refspecs(remote); + cl_git_pass(git_remote_add_fetch(remote, "refs/heads/*:refs/remotes/test/*")); cl_git_pass(git_remote_save(remote)); git_remote_free(remote); diff --git a/tests-clar/refs/branches/tracking.c b/tests-clar/refs/branches/tracking.c deleted file mode 100644 index 30599d9fcd7..00000000000 --- a/tests-clar/refs/branches/tracking.c +++ /dev/null @@ -1,95 +0,0 @@ -#include "clar_libgit2.h" -#include "refs.h" - -static git_repository *repo; -static git_reference *branch, *tracking; - -void test_refs_branches_tracking__initialize(void) -{ - cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); - - branch = NULL; - tracking = NULL; -} - -void test_refs_branches_tracking__cleanup(void) -{ - git_reference_free(tracking); - git_reference_free(branch); - branch = NULL; - - git_repository_free(repo); - repo = NULL; -} - -void test_refs_branches_tracking__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void) -{ - cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); - - cl_git_pass(git_branch_tracking(&tracking, branch)); - - cl_assert_equal_s("refs/remotes/test/master", git_reference_name(tracking)); -} - -void test_refs_branches_tracking__can_retrieve_the_local_tracking_reference_of_a_local_branch(void) -{ - cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/track-local")); - - cl_git_pass(git_branch_tracking(&tracking, branch)); - - cl_assert_equal_s("refs/heads/master", git_reference_name(tracking)); -} - -void test_refs_branches_tracking__cannot_retrieve_a_remote_tracking_reference_from_a_non_branch(void) -{ - cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b")); - - cl_git_fail(git_branch_tracking(&tracking, branch)); -} - -void test_refs_branches_tracking__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void) -{ - cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/subtrees")); - - cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch)); -} - -void test_refs_branches_tracking__trying_to_retrieve_a_remote_tracking_reference_from_a_branch_with_no_fetchspec_returns_GIT_ENOTFOUND(void) -{ - cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/cannot-fetch")); - - cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch)); -} - -static void assert_merge_and_or_remote_key_missing(git_repository *repository, const git_commit *target, const char *entry_name) -{ - git_reference *branch; - - cl_assert_equal_i(GIT_OBJ_COMMIT, git_object_type((git_object*)target)); - cl_git_pass(git_branch_create(&branch, repository, entry_name, (git_commit*)target, 0)); - - cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch)); - - git_reference_free(branch); -} - -void test_refs_branches_tracking__retrieve_a_remote_tracking_reference_from_a_branch_with_no_remote_returns_GIT_ENOTFOUND(void) -{ - git_reference *head; - git_repository *repository; - git_commit *target; - - repository = cl_git_sandbox_init("testrepo.git"); - - cl_git_pass(git_repository_head(&head, repository)); - cl_git_pass(git_reference_peel(((git_object **)&target), head, GIT_OBJ_COMMIT)); - git_reference_free(head); - - assert_merge_and_or_remote_key_missing(repository, target, "remoteless"); - assert_merge_and_or_remote_key_missing(repository, target, "mergeless"); - assert_merge_and_or_remote_key_missing(repository, target, "mergeandremoteless"); - - git_commit_free(target); - - cl_git_sandbox_cleanup(); -} diff --git a/tests-clar/refs/branches/trackingname.c b/tests-clar/refs/branches/trackingname.c deleted file mode 100644 index 5aee33343e9..00000000000 --- a/tests-clar/refs/branches/trackingname.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "clar_libgit2.h" -#include "branch.h" - -static git_repository *repo; -static git_buf tracking_name; - -void test_refs_branches_trackingname__initialize(void) -{ - cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); - - git_buf_init(&tracking_name, 0); -} - -void test_refs_branches_trackingname__cleanup(void) -{ - git_buf_free(&tracking_name); - - git_repository_free(repo); - repo = NULL; -} - -void test_refs_branches_trackingname__can_retrieve_the_remote_tracking_reference_name_of_a_local_branch(void) -{ - cl_git_pass(git_branch_tracking__name( - &tracking_name, repo, "refs/heads/master")); - - cl_assert_equal_s("refs/remotes/test/master", git_buf_cstr(&tracking_name)); -} - -void test_refs_branches_trackingname__can_retrieve_the_local_tracking_reference_name_of_a_local_branch(void) -{ - cl_git_pass(git_branch_tracking__name( - &tracking_name, repo, "refs/heads/track-local")); - - cl_assert_equal_s("refs/heads/master", git_buf_cstr(&tracking_name)); -} - -void test_refs_branches_trackingname__can_return_the_size_of_thelocal_tracking_reference_name_of_a_local_branch(void) -{ - cl_assert_equal_i((int)strlen("refs/heads/master") + 1, - git_branch_tracking_name(NULL, 0, repo, "refs/heads/track-local")); -} diff --git a/tests-clar/refs/branches/upstream.c b/tests-clar/refs/branches/upstream.c new file mode 100644 index 00000000000..2d0ebd24042 --- /dev/null +++ b/tests-clar/refs/branches/upstream.c @@ -0,0 +1,130 @@ +#include "clar_libgit2.h" +#include "refs.h" + +static git_repository *repo; +static git_reference *branch, *upstream; + +void test_refs_branches_upstream__initialize(void) +{ + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + + branch = NULL; + upstream = NULL; +} + +void test_refs_branches_upstream__cleanup(void) +{ + git_reference_free(upstream); + git_reference_free(branch); + branch = NULL; + + git_repository_free(repo); + repo = NULL; +} + +void test_refs_branches_upstream__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); + + cl_git_pass(git_branch_upstream(&upstream, branch)); + + cl_assert_equal_s("refs/remotes/test/master", git_reference_name(upstream)); +} + +void test_refs_branches_upstream__can_retrieve_the_local_upstream_reference_of_a_local_branch(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/track-local")); + + cl_git_pass(git_branch_upstream(&upstream, branch)); + + cl_assert_equal_s("refs/heads/master", git_reference_name(upstream)); +} + +void test_refs_branches_upstream__cannot_retrieve_a_remote_upstream_reference_from_a_non_branch(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b")); + + cl_git_fail(git_branch_upstream(&upstream, branch)); +} + +void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/subtrees")); + + cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); +} + +void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_branch_with_no_fetchspec_returns_GIT_ENOTFOUND(void) +{ + cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/cannot-fetch")); + + cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); +} + +static void assert_merge_and_or_remote_key_missing(git_repository *repository, const git_commit *target, const char *entry_name) +{ + git_reference *branch; + + cl_assert_equal_i(GIT_OBJ_COMMIT, git_object_type((git_object*)target)); + cl_git_pass(git_branch_create(&branch, repository, entry_name, (git_commit*)target, 0)); + + cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); + + git_reference_free(branch); +} + +void test_refs_branches_upstream__retrieve_a_remote_tracking_reference_from_a_branch_with_no_remote_returns_GIT_ENOTFOUND(void) +{ + git_reference *head; + git_repository *repository; + git_commit *target; + + repository = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_repository_head(&head, repository)); + cl_git_pass(git_reference_peel(((git_object **)&target), head, GIT_OBJ_COMMIT)); + git_reference_free(head); + + assert_merge_and_or_remote_key_missing(repository, target, "remoteless"); + assert_merge_and_or_remote_key_missing(repository, target, "mergeless"); + assert_merge_and_or_remote_key_missing(repository, target, "mergeandremoteless"); + + git_commit_free(target); + + cl_git_sandbox_cleanup(); +} + +void test_refs_branches_upstream__set_unset_upstream(void) +{ + git_reference *branch; + git_repository *repository; + const char *value; + git_config *config; + + repository = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/test")); + cl_git_pass(git_branch_set_upstream(branch, "test/master")); + + cl_git_pass(git_repository_config(&config, repository)); + cl_git_pass(git_config_get_string(&value, config, "branch.test.remote")); + cl_assert_equal_s(value, "test"); + cl_git_pass(git_config_get_string(&value, config, "branch.test.merge")); + cl_assert_equal_s(value, "refs/heads/master"); + + cl_git_pass(git_branch_set_upstream(branch, NULL)); + cl_git_fail_with(git_config_get_string(&value, config, "branch.test.merge"), GIT_ENOTFOUND); + cl_git_fail_with(git_config_get_string(&value, config, "branch.test.remote"), GIT_ENOTFOUND); + + git_reference_free(branch); + + cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/master")); + cl_git_pass(git_branch_set_upstream(branch, NULL)); + cl_git_fail_with(git_config_get_string(&value, config, "branch.master.merge"), GIT_ENOTFOUND); + cl_git_fail_with(git_config_get_string(&value, config, "branch.master.remote"), GIT_ENOTFOUND); + + git_reference_free(branch); + + git_config_free(config); + cl_git_sandbox_cleanup(); +} diff --git a/tests-clar/refs/branches/upstreamname.c b/tests-clar/refs/branches/upstreamname.c new file mode 100644 index 00000000000..f05607d4469 --- /dev/null +++ b/tests-clar/refs/branches/upstreamname.c @@ -0,0 +1,42 @@ +#include "clar_libgit2.h" +#include "branch.h" + +static git_repository *repo; +static git_buf upstream_name; + +void test_refs_branches_upstreamname__initialize(void) +{ + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + + git_buf_init(&upstream_name, 0); +} + +void test_refs_branches_upstreamname__cleanup(void) +{ + git_buf_free(&upstream_name); + + git_repository_free(repo); + repo = NULL; +} + +void test_refs_branches_upstreamname__can_retrieve_the_remote_tracking_reference_name_of_a_local_branch(void) +{ + cl_git_pass(git_branch_upstream__name( + &upstream_name, repo, "refs/heads/master")); + + cl_assert_equal_s("refs/remotes/test/master", git_buf_cstr(&upstream_name)); +} + +void test_refs_branches_upstreamname__can_retrieve_the_local_upstream_reference_name_of_a_local_branch(void) +{ + cl_git_pass(git_branch_upstream__name( + &upstream_name, repo, "refs/heads/track-local")); + + cl_assert_equal_s("refs/heads/master", git_buf_cstr(&upstream_name)); +} + +void test_refs_branches_upstreamname__can_return_the_size_of_thelocal_upstream_reference_name_of_a_local_branch(void) +{ + cl_assert_equal_i((int)strlen("refs/heads/master") + 1, + git_branch_upstream_name(NULL, 0, repo, "refs/heads/track-local")); +} diff --git a/tests-clar/refs/delete.c b/tests-clar/refs/delete.c index ac517d8691f..053f412295c 100644 --- a/tests-clar/refs/delete.c +++ b/tests-clar/refs/delete.c @@ -88,4 +88,5 @@ void test_refs_delete__packed_only(void) /* This should pass */ cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); + git_refdb_free(refdb); } diff --git a/tests-clar/refs/pack.c b/tests-clar/refs/pack.c index 973abae305e..412c4c5fd18 100644 --- a/tests-clar/refs/pack.c +++ b/tests-clar/refs/pack.c @@ -25,6 +25,7 @@ static void packall(void) cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); + git_refdb_free(refdb); } void test_refs_pack__empty(void) diff --git a/tests-clar/refs/peel.c b/tests-clar/refs/peel.c index 34bd02ce0c4..f2fb6e25975 100644 --- a/tests-clar/refs/peel.c +++ b/tests-clar/refs/peel.c @@ -1,19 +1,24 @@ #include "clar_libgit2.h" static git_repository *g_repo; +static git_repository *g_peel_repo; void test_refs_peel__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_open(&g_peel_repo, cl_fixture("peeled.git"))); } void test_refs_peel__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; + git_repository_free(g_peel_repo); + g_peel_repo = NULL; } -static void assert_peel( +static void assert_peel_generic( + git_repository *repo, const char *ref_name, git_otype requested_type, const char* expected_sha, @@ -23,7 +28,7 @@ static void assert_peel( git_reference *ref; git_object *peeled; - cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); + cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); cl_git_pass(git_reference_peel(&peeled, ref, requested_type)); @@ -36,6 +41,16 @@ static void assert_peel( git_reference_free(ref); } +static void assert_peel( + const char *ref_name, + git_otype requested_type, + const char* expected_sha, + git_otype expected_type) +{ + assert_peel_generic(g_repo, ref_name, requested_type, + expected_sha, expected_type); +} + static void assert_peel_error(int error, const char *ref_name, git_otype requested_type) { git_reference *ref; @@ -90,3 +105,15 @@ void test_refs_peel__can_peel_into_any_non_tag_object(void) assert_peel("refs/tags/test", GIT_OBJ_ANY, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT); } + +void test_refs_peel__can_peel_fully_peeled_packed_refs(void) +{ + assert_peel_generic(g_peel_repo, + "refs/tags/tag-inside-tags", GIT_OBJ_ANY, + "0df1a5865c8abfc09f1f2182e6a31be550e99f07", + GIT_OBJ_COMMIT); + assert_peel_generic(g_peel_repo, + "refs/foo/tag-outside-tags", GIT_OBJ_ANY, + "0df1a5865c8abfc09f1f2182e6a31be550e99f07", + GIT_OBJ_COMMIT); +} diff --git a/tests-clar/refs/rename.c b/tests-clar/refs/rename.c index e39abeb051c..5ab84c48ecc 100644 --- a/tests-clar/refs/rename.c +++ b/tests-clar/refs/rename.c @@ -284,6 +284,7 @@ void test_refs_rename__overwrite(void) git_reference_free(ref_one); git_reference_free(ref_one_new); git_reference_free(ref_two); + git_refdb_free(refdb); } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index e0bccf4a98e..74472b17587 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -27,11 +27,77 @@ static void test_object_inrepo(const char *spec, const char *expected_oid, git_r git_object_free(obj); } +static void test_id_inrepo( + const char *spec, + const char *expected_left, + const char *expected_right, + git_revparse_mode_t expected_flags, + git_repository *repo) +{ + git_revspec revspec; + int error = git_revparse(&revspec, repo, spec); + + if (expected_left) { + char str[64] = {0}; + cl_assert_equal_i(0, error); + git_oid_fmt(str, git_object_id(revspec.from)); + cl_assert_equal_s(str, expected_left); + git_object_free(revspec.from); + } else { + cl_assert_equal_i(GIT_ENOTFOUND, error); + } + + if (expected_right) { + char str[64] = {0}; + git_oid_fmt(str, git_object_id(revspec.to)); + cl_assert_equal_s(str, expected_right); + git_object_free(revspec.to); + } + + if (expected_flags) + cl_assert_equal_i(expected_flags, revspec.flags); +} + static void test_object(const char *spec, const char *expected_oid) { test_object_inrepo(spec, expected_oid, g_repo); } +static void test_rangelike(const char *rangelike, + const char *expected_left, + const char *expected_right, + git_revparse_mode_t expected_revparseflags) +{ + char objstr[64] = {0}; + git_revspec revspec; + int error; + + error = git_revparse(&revspec, g_repo, rangelike); + + if (expected_left != NULL) { + cl_assert_equal_i(0, error); + cl_assert_equal_i(revspec.flags, expected_revparseflags); + git_oid_fmt(objstr, git_object_id(revspec.from)); + cl_assert_equal_s(objstr, expected_left); + git_oid_fmt(objstr, git_object_id(revspec.to)); + cl_assert_equal_s(objstr, expected_right); + } else + cl_assert(error != 0); + + git_object_free(revspec.from); + git_object_free(revspec.to); +} + + +static void test_id( + const char *spec, + const char *expected_left, + const char *expected_right, + git_revparse_mode_t expected_flags) +{ + test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); +} + void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); @@ -49,7 +115,7 @@ void test_refs_revparse__nonexistant_object(void) test_object("this-does-not-exist~2", NULL); } -static void assert_invalid_spec(const char *invalid_spec) +static void assert_invalid_single_spec(const char *invalid_spec) { cl_assert_equal_i( GIT_EINVALIDSPEC, git_revparse_single(&g_obj, g_repo, invalid_spec)); @@ -57,9 +123,9 @@ static void assert_invalid_spec(const char *invalid_spec) void test_refs_revparse__invalid_reference_name(void) { - assert_invalid_spec("this doesn't make sense"); - assert_invalid_spec("Inv@{id"); - assert_invalid_spec(""); + assert_invalid_single_spec("this doesn't make sense"); + assert_invalid_single_spec("Inv@{id"); + assert_invalid_single_spec(""); } void test_refs_revparse__shas(void) @@ -98,11 +164,11 @@ void test_refs_revparse__describe_output(void) void test_refs_revparse__nth_parent(void) { - assert_invalid_spec("be3563a^-1"); - assert_invalid_spec("^"); - assert_invalid_spec("be3563a^{tree}^"); - assert_invalid_spec("point_to_blob^{blob}^"); - assert_invalid_spec("this doesn't make sense^1"); + assert_invalid_single_spec("be3563a^-1"); + assert_invalid_single_spec("^"); + assert_invalid_single_spec("be3563a^{tree}^"); + assert_invalid_single_spec("point_to_blob^{blob}^"); + assert_invalid_single_spec("this doesn't make sense^1"); test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a"); @@ -129,7 +195,7 @@ void test_refs_revparse__not_tag(void) void test_refs_revparse__to_type(void) { - assert_invalid_spec("wrapped_tag^{trip}"); + assert_invalid_single_spec("wrapped_tag^{trip}"); test_object("point_to_blob^{commit}", NULL); cl_assert_equal_i( GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}")); @@ -142,15 +208,15 @@ void test_refs_revparse__to_type(void) void test_refs_revparse__linear_history(void) { - assert_invalid_spec("~"); + assert_invalid_single_spec("~"); test_object("foo~bar", NULL); - assert_invalid_spec("master~bar"); - assert_invalid_spec("master~-1"); - assert_invalid_spec("master~0bar"); - assert_invalid_spec("this doesn't make sense~2"); - assert_invalid_spec("be3563a^{tree}~"); - assert_invalid_spec("point_to_blob^{blob}~"); + assert_invalid_single_spec("master~bar"); + assert_invalid_single_spec("master~-1"); + assert_invalid_single_spec("master~0bar"); + assert_invalid_single_spec("this doesn't make sense~2"); + assert_invalid_single_spec("be3563a^{tree}~"); + assert_invalid_single_spec("point_to_blob^{blob}~"); test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -161,10 +227,10 @@ void test_refs_revparse__linear_history(void) void test_refs_revparse__chaining(void) { - assert_invalid_spec("master@{0}@{0}"); - assert_invalid_spec("@{u}@{-1}"); - assert_invalid_spec("@{-1}@{-1}"); - assert_invalid_spec("@{-3}@{0}"); + assert_invalid_single_spec("master@{0}@{0}"); + assert_invalid_single_spec("@{u}@{-1}"); + assert_invalid_single_spec("@{-1}@{-1}"); + assert_invalid_single_spec("@{-3}@{0}"); test_object("master@{0}~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("@{u}@{0}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -180,8 +246,8 @@ void test_refs_revparse__chaining(void) void test_refs_revparse__upstream(void) { - assert_invalid_spec("e90810b@{u}"); - assert_invalid_spec("refs/tags/e90810b@{u}"); + assert_invalid_single_spec("e90810b@{u}"); + assert_invalid_single_spec("refs/tags/e90810b@{u}"); test_object("refs/heads/e90810b@{u}", NULL); test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -193,7 +259,7 @@ void test_refs_revparse__upstream(void) void test_refs_revparse__ordinal(void) { - assert_invalid_spec("master@{-2}"); + assert_invalid_single_spec("master@{-2}"); /* TODO: make the test below actually fail * cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{1a}")); @@ -215,9 +281,9 @@ void test_refs_revparse__ordinal(void) void test_refs_revparse__previous_head(void) { - assert_invalid_spec("@{-xyz}"); - assert_invalid_spec("@{-0}"); - assert_invalid_spec("@{-1b}"); + assert_invalid_single_spec("@{-xyz}"); + assert_invalid_single_spec("@{-0}"); + assert_invalid_single_spec("@{-1b}"); test_object("@{-42}", NULL); @@ -277,7 +343,7 @@ void test_refs_revparse__revwalk(void) { test_object("master^{/not found in any commit}", NULL); test_object("master^{/merge}", NULL); - assert_invalid_spec("master^{/((}"); + assert_invalid_single_spec("master^{/((}"); test_object("master^{/anoth}", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("master^{/Merge}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -358,8 +424,8 @@ void test_refs_revparse__date(void) void test_refs_revparse__colon(void) { - assert_invalid_spec(":/"); - assert_invalid_spec("point_to_blob:readme.txt"); + assert_invalid_single_spec(":/"); + assert_invalid_single_spec("point_to_blob:readme.txt"); cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); /* Not implemented */ test_object(":/not found in any commit", NULL); @@ -596,3 +662,36 @@ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void) git_object_free(target); cl_git_sandbox_cleanup(); } + + +void test_refs_revparse__range(void) +{ + assert_invalid_single_spec("be3563a^1..be3563a"); + + test_rangelike("be3563a^1..be3563a", + "9fd738e8f7967c078dceed8190330fc8648ee56a", + "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", + GIT_REVPARSE_RANGE); + + test_rangelike("be3563a^1...be3563a", + "9fd738e8f7967c078dceed8190330fc8648ee56a", + "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + + test_rangelike("be3563a^1.be3563a", NULL, NULL, 0); +} + +void test_refs_revparse__parses_range_operator(void) +{ + test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVPARSE_SINGLE); + test_id("HEAD~3..HEAD", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE); + + test_id("HEAD~3...HEAD", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); +} + diff --git a/tests-clar/repo/getters.c b/tests-clar/repo/getters.c index b372f5b7098..b8ede126c1d 100644 --- a/tests-clar/repo/getters.c +++ b/tests-clar/repo/getters.c @@ -31,10 +31,10 @@ void test_repo_getters__retrieving_the_odb_honors_the_refcount(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_odb(&odb, repo)); - cl_assert(((git_refcount *)odb)->refcount == 2); + cl_assert(((git_refcount *)odb)->refcount.val == 2); git_repository_free(repo); - cl_assert(((git_refcount *)odb)->refcount == 1); + cl_assert(((git_refcount *)odb)->refcount.val == 1); git_odb_free(odb); } diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 00c46d6b10a..ab460735ce8 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -422,7 +422,7 @@ static void build_test_tree( git_treebuilder *builder; const char *scan = fmt, *next; char type, delimiter; - git_filemode_t mode; + git_filemode_t mode = GIT_FILEMODE_BLOB; git_buf name = GIT_BUF_INIT; va_list arglist; @@ -755,47 +755,52 @@ void test_repo_iterator__workdir_icase(void) git_iterator_free(i); } -void test_repo_iterator__workdir_depth(void) +static void build_workdir_tree(const char *root, int dirs, int subs) { int i, j; - git_iterator *iter; - char buf[64]; - - g_repo = cl_git_sandbox_init("icase"); - - for (i = 0; i < 10; ++i) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d", i); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + char buf[64], sub[64]; + for (i = 0; i < dirs; ++i) { if (i % 2 == 0) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/file", i); + p_snprintf(buf, sizeof(buf), "%s/dir%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + + p_snprintf(buf, sizeof(buf), "%s/dir%02d/file", root, i); cl_git_mkfile(buf, buf); + buf[strlen(buf) - 5] = '\0'; + } else { + p_snprintf(buf, sizeof(buf), "%s/DIR%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); } - for (j = 0; j < 10; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + for (j = 0; j < subs; ++j) { + switch (j % 4) { + case 0: p_snprintf(sub, sizeof(sub), "%s/sub%02d", buf, j); break; + case 1: p_snprintf(sub, sizeof(sub), "%s/sUB%02d", buf, j); break; + case 2: p_snprintf(sub, sizeof(sub), "%s/Sub%02d", buf, j); break; + case 3: p_snprintf(sub, sizeof(sub), "%s/SUB%02d", buf, j); break; + } + cl_git_pass(git_futils_mkdir(sub, NULL, 0775, GIT_MKDIR_PATH)); if (j % 2 == 0) { - p_snprintf( - buf, sizeof(buf), "icase/dir%02d/sub%02d/file", i, j); - cl_git_mkfile(buf, buf); + size_t sublen = strlen(sub); + memcpy(&sub[sublen], "/file", sizeof("/file")); + cl_git_mkfile(sub, sub); + sub[sublen] = '\0'; } } } +} - for (i = 1; i < 3; ++i) { - for (j = 0; j < 50; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub01/moar%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); +void test_repo_iterator__workdir_depth(void) +{ + git_iterator *iter; - if (j % 2 == 0) { - p_snprintf(buf, sizeof(buf), - "icase/dir%02d/sub01/moar%02d/file", i, j); - cl_git_mkfile(buf, buf); - } - } - } + g_repo = cl_git_sandbox_init("icase"); + + build_workdir_tree("icase", 10, 10); + build_workdir_tree("icase/DIR01/sUB01", 50, 0); + build_workdir_tree("icase/dir02/sUB01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); @@ -808,3 +813,114 @@ void test_repo_iterator__workdir_depth(void) expect_iterator_items(iter, 337, NULL, 337, NULL); git_iterator_free(iter); } + +void test_repo_iterator__fs(void) +{ + git_iterator *i; + static const char *expect_base[] = { + "DIR01/Sub02/file", + "DIR01/sub00/file", + "current_file", + "dir00/Sub02/file", + "dir00/file", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_trees[] = { + "DIR01/", + "DIR01/SUB03/", + "DIR01/Sub02/", + "DIR01/Sub02/file", + "DIR01/sUB01/", + "DIR01/sub00/", + "DIR01/sub00/file", + "current_file", + "dir00/", + "dir00/SUB03/", + "dir00/Sub02/", + "dir00/Sub02/file", + "dir00/file", + "dir00/sUB01/", + "dir00/sub00/", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_noauto[] = { + "DIR01/", + "current_file", + "dir00/", + "modified_file", + "new_file", + NULL, + }; + + g_repo = cl_git_sandbox_init("status"); + + build_workdir_tree("status/subdir", 2, 4); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", 0, NULL, NULL)); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); + git_iterator_free(i); + + git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); + git_iterator_free(i); +} + +void test_repo_iterator__fs2(void) +{ + git_iterator *i; + static const char *expect_base[] = { + "heads/br2", + "heads/dir", + "heads/master", + "heads/packed-test", + "heads/subtrees", + "heads/test", + "tags/e90810b", + "tags/foo/bar", + "tags/foo/foo/bar", + "tags/point_to_blob", + "tags/test", + NULL, + }; + + g_repo = cl_git_sandbox_init("testrepo"); + + cl_git_pass(git_iterator_for_filesystem( + &i, "testrepo/.git/refs", 0, NULL, NULL)); + expect_iterator_items(i, 11, expect_base, 11, expect_base); + git_iterator_free(i); +} diff --git a/tests-clar/repo/open.c b/tests-clar/repo/open.c index 7f93ae91a0e..6b52537975e 100644 --- a/tests-clar/repo/open.c +++ b/tests-clar/repo/open.c @@ -280,3 +280,38 @@ void test_repo_open__opening_a_non_existing_repository_returns_ENOTFOUND(void) git_repository *repo; cl_assert_equal_i(GIT_ENOTFOUND, git_repository_open(&repo, "i-do-not/exist")); } + +void test_repo_open__no_config(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + git_config *config; + + cl_fixture_sandbox("empty_standard_repo"); + cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); + + /* remove local config */ + cl_git_pass(git_futils_rmdir_r( + "empty_standard_repo/.git/config", NULL, GIT_RMDIR_REMOVE_FILES)); + + /* isolate from system level configs */ + cl_must_pass(p_mkdir("alternate", 0777)); + cl_git_pass(git_path_prettify(&path, "alternate", NULL)); + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); + + git_buf_free(&path); + + cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); + cl_git_pass(git_repository_config(&config, repo)); + + cl_git_fail(git_config_set_string(config, "test.set", "42")); + + git_config_free(config); + git_repository_free(repo); + cl_fixture_cleanup("empty_standard_repo"); +} diff --git a/tests-clar/repo/setters.c b/tests-clar/repo/setters.c index 7e482dee19f..f34f1e471cf 100644 --- a/tests-clar/repo/setters.c +++ b/tests-clar/repo/setters.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "buffer.h" #include "posix.h" #include "util.h" @@ -67,13 +69,13 @@ void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_o git_index *new_index; cl_git_pass(git_index_open(&new_index, "./my-index")); - cl_assert(((git_refcount *)new_index)->refcount == 1); + cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_repository_set_index(repo, new_index); - cl_assert(((git_refcount *)new_index)->refcount == 2); + cl_assert(((git_refcount *)new_index)->refcount.val == 2); git_repository_free(repo); - cl_assert(((git_refcount *)new_index)->refcount == 1); + cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_index_free(new_index); @@ -88,13 +90,13 @@ void test_repo_setters__setting_a_new_odb_on_a_repo_which_already_loaded_one_pro git_odb *new_odb; cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects")); - cl_assert(((git_refcount *)new_odb)->refcount == 1); + cl_assert(((git_refcount *)new_odb)->refcount.val == 1); git_repository_set_odb(repo, new_odb); - cl_assert(((git_refcount *)new_odb)->refcount == 2); + cl_assert(((git_refcount *)new_odb)->refcount.val == 2); git_repository_free(repo); - cl_assert(((git_refcount *)new_odb)->refcount == 1); + cl_assert(((git_refcount *)new_odb)->refcount.val == 1); git_odb_free(new_odb); diff --git a/tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG b/tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG new file mode 100644 index 00000000000..245b18a2c50 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG @@ -0,0 +1 @@ +rename conflict theirs diff --git a/tests-clar/resources/merge-resolve/.gitted/HEAD b/tests-clar/resources/merge-resolve/.gitted/HEAD new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD b/tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD new file mode 100644 index 00000000000..4092d428f13 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD @@ -0,0 +1 @@ +2392a2dacc9efb562b8635d6579fb458751c7c5b diff --git a/tests-clar/resources/merge-resolve/.gitted/config b/tests-clar/resources/merge-resolve/.gitted/config new file mode 100644 index 00000000000..af107929f2d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true diff --git a/tests-clar/resources/merge-resolve/.gitted/description b/tests-clar/resources/merge-resolve/.gitted/description new file mode 100644 index 00000000000..498b267a8c7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests-clar/resources/merge-resolve/.gitted/index b/tests-clar/resources/merge-resolve/.gitted/index new file mode 100644 index 00000000000..230eba9eb26 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/index differ diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/HEAD b/tests-clar/resources/merge-resolve/.gitted/logs/HEAD new file mode 100644 index 00000000000..96cdb337e1d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/HEAD @@ -0,0 +1,236 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563869 -0500 commit (initial): initial +c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563886 -0500 checkout: moving from master to branch +c607fc30883e335def28cd686b51f6cfa02b06ec 7cb63eed597130ba4abb87b3e544b85021905520 Edward Thomson 1351563965 -0500 commit: branch +7cb63eed597130ba4abb87b3e544b85021905520 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563968 -0500 checkout: moving from branch to master +c607fc30883e335def28cd686b51f6cfa02b06ec 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351564033 -0500 commit: master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605785 -0500 checkout: moving from master to ff_branch +977c696519c5a3004c5f1d15d60c89dbeb8f235f 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351605830 -0500 commit: fastforward +33d500f588fbbe65901d82b4e6b008e549064be0 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605889 -0500 checkout: moving from ff_branch to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874933 -0500 checkout: moving from master to octo1 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 16f825815cfd20a07a75c71554e82d8eede0b061 Edward Thomson 1351874954 -0500 commit: octo1 +16f825815cfd20a07a75c71554e82d8eede0b061 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874957 -0500 checkout: moving from octo1 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874960 -0500 checkout: moving from master to octo2 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 158dc7bedb202f5b26502bf3574faa7f4238d56c Edward Thomson 1351874974 -0500 commit: octo2 +158dc7bedb202f5b26502bf3574faa7f4238d56c 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874976 -0500 checkout: moving from octo2 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874980 -0500 checkout: moving from master to octo3 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 50ce7d7d01217679e26c55939eef119e0c93e272 Edward Thomson 1351874998 -0500 commit: octo3 +50ce7d7d01217679e26c55939eef119e0c93e272 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875006 -0500 checkout: moving from octo3 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875010 -0500 checkout: moving from master to octo4 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875023 -0500 commit: octo4 +54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 checkout: moving from octo4 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 checkout: moving from master to octo5 +977c696519c5a3004c5f1d15d60c89dbeb8f235f e4f618a2c3ed0669308735727df5ebf2447f022f Edward Thomson 1351875041 -0500 commit: octo5 +e4f618a2c3ed0669308735727df5ebf2447f022f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 checkout: moving from octo5 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 checkout: moving from master to octo6 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4ca408a8c88655f7586a1b580be6fad138121e98 Edward Thomson 1351875057 -0500 commit: octo5 +4ca408a8c88655f7586a1b580be6fad138121e98 b6f610aef53bd343e6c96227de874c66f00ee8e8 Edward Thomson 1351875065 -0500 commit (amend): octo6 +b6f610aef53bd343e6c96227de874c66f00ee8e8 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875071 -0500 checkout: moving from octo6 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4e0d9401aee78eb345a8685a859d37c8c3c0bbed Edward Thomson 1351875091 -0500 merge octo1 octo2 octo3 octo4: Merge made by the 'octopus' strategy. +4e0d9401aee78eb345a8685a859d37c8c3c0bbed 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875108 -0500 reset: moving to 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae +54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875584 -0500 reset: moving to 977c696519c5a3004c5f1d15d60c89dbeb8f235f +bd593285fc7fe4ca18ccdbabf027f5d689101452 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351990193 -0500 checkout: moving from master to ff_branch +33d500f588fbbe65901d82b4e6b008e549064be0 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351990202 -0500 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990205 -0500 merge master: Fast-forward +bd593285fc7fe4ca18ccdbabf027f5d689101452 fd89f8cffb663ac89095a0f9764902e93ceaca6a Edward Thomson 1351990229 -0500 commit: fastforward +fd89f8cffb663ac89095a0f9764902e93ceaca6a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990233 -0500 checkout: moving from ff_branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352091703 -0600 checkout: moving from master to trivial-2alt +c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092411 -0600 checkout: moving from trivial-2alt to trivial-2alt-branch +c607fc30883e335def28cd686b51f6cfa02b06ec c9174cef549ec94ecbc43ef03cdc775b4950becb Edward Thomson 1352092434 -0600 commit: 2alt-branch +c9174cef549ec94ecbc43ef03cdc775b4950becb c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092440 -0600 checkout: moving from trivial-2alt-branch to trivial-2alt +c607fc30883e335def28cd686b51f6cfa02b06ec 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352092452 -0600 commit: 2alt +bd593285fc7fe4ca18ccdbabf027f5d689101452 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352094476 -0600 checkout: moving from master to trivial-3alt +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094547 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 5459c89aa0026d543ce8343bd89871bce543f9c2 Edward Thomson 1352094580 -0600 commit: 3alt +5459c89aa0026d543ce8343bd89871bce543f9c2 4c9fac0707f8d4195037ae5a681aa48626491541 Edward Thomson 1352094610 -0600 commit: 3alt-branch +4c9fac0707f8d4195037ae5a681aa48626491541 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352094620 -0600 checkout: moving from trivial-3alt to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352094752 -0600 checkout: moving from master to trivial-4 +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094764 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352094815 -0600 commit: trivial-4 +cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094843 -0600 checkout: moving from trivial-4 to trivial-4-branch +c607fc30883e335def28cd686b51f6cfa02b06ec 183310e30fb1499af8c619108ffea4d300b5e778 Edward Thomson 1352094856 -0600 commit: trivial-4-branch +183310e30fb1499af8c619108ffea4d300b5e778 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352094860 -0600 checkout: moving from trivial-4-branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352096588 -0600 checkout: moving from master to trivial-4 +cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096612 -0600 checkout: moving from trivial-4 to trivial-5alt-1 +c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096643 -0600 commit: 5alt-1 +4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096661 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-1-branch +c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096671 -0600 checkout: moving from trivial-5alt-1-branch to trivial-5alt-1 +4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096678 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-1-branch +c607fc30883e335def28cd686b51f6cfa02b06ec 478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 Edward Thomson 1352096689 -0600 commit: 5alt-1-branch +478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096701 -0600 checkout: moving from trivial-5alt-1-branch to trivial-5alt-1 +4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096715 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-2 +c607fc30883e335def28cd686b51f6cfa02b06ec ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096764 -0600 commit: existing file +ebc09d0137cfb0c26697aed0109fb943ad906f3f 3b47b031b3e55ae11e14a05260b1c3ffd6838d55 Edward Thomson 1352096815 -0600 commit: 5alt-2 +3b47b031b3e55ae11e14a05260b1c3ffd6838d55 ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096840 -0600 checkout: moving from trivial-5alt-2 to trivial-5alt-2-branch +ebc09d0137cfb0c26697aed0109fb943ad906f3f f48097eb340dc5a7cae55aabcf1faf4548aa821f Edward Thomson 1352096855 -0600 commit: 5alt-2-branch +f48097eb340dc5a7cae55aabcf1faf4548aa821f bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352096858 -0600 checkout: moving from trivial-5alt-2-branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352097377 -0600 checkout: moving from master to trivial-6 +c607fc30883e335def28cd686b51f6cfa02b06ec f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097389 -0600 commit: 6 +f7c332bd4d4d4b777366cae4d24d1687477576bf 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352097404 -0600 commit: trivial-6 +99b4f7e4f24470fa06b980bc21f1095c2a9425c0 f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097420 -0600 checkout: moving from trivial-6 to trivial-6-branch +f7c332bd4d4d4b777366cae4d24d1687477576bf a43150a738849c59376cf30bb2a68348a83c8f48 Edward Thomson 1352097431 -0600 commit: 6-branch +a43150a738849c59376cf30bb2a68348a83c8f48 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352097442 -0600 checkout: moving from trivial-6-branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352098040 -0600 checkout: moving from master to trivial-6 +99b4f7e4f24470fa06b980bc21f1095c2a9425c0 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352098057 -0600 checkout: moving from trivial-6 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352098792 -0600 checkout: moving from master to trivial-4 +cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352098818 -0600 checkout: moving from trivial-4 to trivial-8 +c607fc30883e335def28cd686b51f6cfa02b06ec 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098884 -0600 commit: trivial-8 +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098947 -0600 checkout: moving from trivial-8 to trivial-8-branch +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 Edward Thomson 1352098979 -0600 commit: trivial-8-branch +52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098982 -0600 checkout: moving from trivial-8-branch to trivial-8 +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 3575826c96a975031d2c14368529cc5c4353a8fd Edward Thomson 1352099000 -0600 commit: trivial-8 +3575826c96a975031d2c14368529cc5c4353a8fd bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352099008 -0600 checkout: moving from trivial-8 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352099776 -0600 checkout: moving from master to trivial-7 +c607fc30883e335def28cd686b51f6cfa02b06ec 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099790 -0600 commit: trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099799 -0600 checkout: moving from trivial-7 to trivial-7-branch +092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099812 -0600 commit: trivial-7-branch +73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099815 -0600 checkout: moving from trivial-7-branch to trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099838 -0600 checkout: moving from trivial-7 to trivial-7-branch +73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099874 -0600 reset: moving to 092ce8682d7f3a2a3a769a6daca58950168ba5c4 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 009b9cab6fdac02915a88ecd078b7a792ed802d8 Edward Thomson 1352099921 -0600 commit: removed in 7 +009b9cab6fdac02915a88ecd078b7a792ed802d8 5195a1b480f66691b667f10a9e41e70115a78351 Edward Thomson 1352099927 -0600 commit (amend): trivial-7-branch +5195a1b480f66691b667f10a9e41e70115a78351 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099937 -0600 checkout: moving from trivial-7-branch to trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 d874671ef5b20184836cb983bb273e5280384d0b Edward Thomson 1352099947 -0600 commit: trivial-7 +d874671ef5b20184836cb983bb273e5280384d0b bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352099949 -0600 checkout: moving from trivial-7 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100174 -0600 checkout: moving from master to trivial-10 +c607fc30883e335def28cd686b51f6cfa02b06ec 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100193 -0600 commit: trivial-10 +53825f41ac8d640612f9423a2f03a69f3d96809a 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100200 -0600 checkout: moving from trivial-10 to trivial-10-branch +53825f41ac8d640612f9423a2f03a69f3d96809a 11f4f3c08b737f5fd896cbefa1425ee63b21b2fa Edward Thomson 1352100211 -0600 commit: trivial-10-branch +11f4f3c08b737f5fd896cbefa1425ee63b21b2fa 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100214 -0600 checkout: moving from trivial-10-branch to trivial-10 +53825f41ac8d640612f9423a2f03a69f3d96809a 0ec5f433959cd46177f745903353efb5be08d151 Edward Thomson 1352100223 -0600 commit: trivial-10 +0ec5f433959cd46177f745903353efb5be08d151 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100225 -0600 checkout: moving from trivial-10 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100270 -0600 checkout: moving from master to trivial-9 +c607fc30883e335def28cd686b51f6cfa02b06ec f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100304 -0600 commit: trivial-9 +f0053b8060bb3f0be5cbcc3147a07ece26bf097e f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100310 -0600 checkout: moving from trivial-9 to trivial-9-branch +f0053b8060bb3f0be5cbcc3147a07ece26bf097e 13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e Edward Thomson 1352100317 -0600 commit: trivial-9-branch +13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100319 -0600 checkout: moving from trivial-9-branch to trivial-9 +f0053b8060bb3f0be5cbcc3147a07ece26bf097e c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a Edward Thomson 1352100333 -0600 commit: trivial-9 +c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100335 -0600 checkout: moving from trivial-9 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100576 -0600 checkout: moving from master to trivial-13 +c607fc30883e335def28cd686b51f6cfa02b06ec 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100589 -0600 commit: trivial-13 +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100604 -0600 checkout: moving from trivial-13 to trivial-13-branch +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c Edward Thomson 1352100610 -0600 commit: trivial-13-branch +05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100612 -0600 checkout: moving from trivial-13-branch to trivial-13 +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa a3fabece9eb8748da810e1e08266fef9b7136ad4 Edward Thomson 1352100625 -0600 commit: trivial-13 +a3fabece9eb8748da810e1e08266fef9b7136ad4 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100627 -0600 checkout: moving from trivial-13 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100936 -0600 checkout: moving from master to trivial-11 +c607fc30883e335def28cd686b51f6cfa02b06ec 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100958 -0600 commit: trivial-11 +35632e43612c06a3ea924bfbacd48333da874c29 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100964 -0600 checkout: moving from trivial-11 to trivial-11-branch +35632e43612c06a3ea924bfbacd48333da874c29 6718a45909532d1fcf5600d0877f7fe7e78f0b86 Edward Thomson 1352100978 -0600 commit: trivial-11-branch +6718a45909532d1fcf5600d0877f7fe7e78f0b86 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100981 -0600 checkout: moving from trivial-11-branch to trivial-11 +35632e43612c06a3ea924bfbacd48333da874c29 3168dca1a561889b045a6441909f4c56145e666d Edward Thomson 1352100992 -0600 commit: trivial-11 +3168dca1a561889b045a6441909f4c56145e666d bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100996 -0600 checkout: moving from trivial-11 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352101098 -0600 checkout: moving from master to trivial-14 +c607fc30883e335def28cd686b51f6cfa02b06ec 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101113 -0600 commit: trivial-14 +596803b523203a4851c824c07366906f8353f4ad 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101117 -0600 checkout: moving from trivial-14 to trivial-14-branch +596803b523203a4851c824c07366906f8353f4ad 8187117062b750eed4f93fd7e899f17b52ce554d Edward Thomson 1352101132 -0600 commit: trivial-14-branch +8187117062b750eed4f93fd7e899f17b52ce554d 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101135 -0600 checkout: moving from trivial-14-branch to trivial-14 +596803b523203a4851c824c07366906f8353f4ad 7e2d058d5fedf8329db44db4fac610d6b1a89159 Edward Thomson 1352101141 -0600 commit: trivial-14 +7e2d058d5fedf8329db44db4fac610d6b1a89159 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352101145 -0600 checkout: moving from trivial-14 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353177749 -0600 checkout: moving from master to renames1 +c607fc30883e335def28cd686b51f6cfa02b06ec 412b32fb66137366147f1801ecc962452757d48a Edward Thomson 1353177886 -0600 commit: renames +412b32fb66137366147f1801ecc962452757d48a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794607 -0600 checkout: moving from renames1 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794647 -0600 checkout: moving from master to renames2 +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353794677 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec ab40af3cb8a3ed2e2843e96d9aa7871336b94573 Edward Thomson 1353794852 -0600 commit: renames2 +ab40af3cb8a3ed2e2843e96d9aa7871336b94573 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794883 -0600 checkout: moving from renames2 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354574697 -0600 checkout: moving from master to df_side1 +bd593285fc7fe4ca18ccdbabf027f5d689101452 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354574962 -0600 commit: df_ancestor +d4207f77243500bec335ab477f9227fcdb1e271a c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1354575027 -0600 commit: df_side1 +c94b27e41064c521120627e07e2035cca1d24ffa d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354575070 -0600 checkout: moving from df_side1 to df_side2 +d4207f77243500bec335ab477f9227fcdb1e271a f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1354575206 -0600 commit: df_side2 +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354575381 -0600 checkout: moving from df_side2 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1355017614 -0600 checkout: moving from master to df_side1 +c94b27e41064c521120627e07e2035cca1d24ffa a90bc3fb6f15181972a2959a921429efbd81a473 Edward Thomson 1355017650 -0600 commit: df_added +a90bc3fb6f15181972a2959a921429efbd81a473 c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1355017673 -0600 checkout: moving from df_side1 to c94b27e +c94b27e41064c521120627e07e2035cca1d24ffa d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355017673 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017673 -0600 rebase -i (squash): df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017676 -0600 rebase -i (finish): returning to refs/heads/df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017715 -0600 reset: moving to df_side2 +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 Edward Thomson 1355017744 -0600 commit: df_added +8c749d9968d4b10dcfb06c9f97d0e5d92d337071 f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017754 -0600 checkout: moving from df_side1 to f8958bd +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355017754 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017754 -0600 rebase -i (squash): df_side2 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017756 -0600 rebase -i (finish): returning to refs/heads/df_side1 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017793 -0600 reset: moving to 005b6fcc8fec71d2550bef8462d169b3c26aa14b +005b6fcc8fec71d2550bef8462d169b3c26aa14b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017826 -0600 reset: moving to 0204a84 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355017847 -0600 checkout: moving from df_side1 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355168677 -0600 checkout: moving from master to df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355168829 -0600 checkout: moving from df_side1 to df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355168838 -0600 checkout: moving from df_side1 to df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b e8107f24196736b870a318a0e28f048e29f6feff Edward Thomson 1355169065 -0600 commit: df_side1 +e8107f24196736b870a318a0e28f048e29f6feff 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355169081 -0600 checkout: moving from df_side1 to 005b6fc +005b6fcc8fec71d2550bef8462d169b3c26aa14b d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169081 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169081 -0600 rebase -i (squash): df_side1 +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169084 -0600 rebase -i (finish): returning to refs/heads/df_side1 +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355169141 -0600 checkout: moving from df_side1 to df_side2 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 944f5dd1a867cab4c2bbcb896493435cae1dcc1a Edward Thomson 1355169174 -0600 commit: both +944f5dd1a867cab4c2bbcb896493435cae1dcc1a 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355169182 -0600 checkout: moving from df_side2 to 0204a84 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169182 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169182 -0600 rebase -i (squash): df_side2 +57079a46233ae2b6df62e9ade71c4948512abefb 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169185 -0600 rebase -i (finish): returning to refs/heads/df_side2 +57079a46233ae2b6df62e9ade71c4948512abefb 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169241 -0600 checkout: moving from df_side2 to df_side1 +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 Edward Thomson 1355169419 -0600 commit: side1 +e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169431 -0600 checkout: moving from df_side1 to 80a8fbb +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169431 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169431 -0600 rebase -i (squash): df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169435 -0600 rebase -i (finish): returning to refs/heads/df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169439 -0600 checkout: moving from df_side1 to df_side2 +57079a46233ae2b6df62e9ade71c4948512abefb 58e853f66699fd02629fd50bde08082bc005933a Edward Thomson 1355169460 -0600 commit: side2 +58e853f66699fd02629fd50bde08082bc005933a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169469 -0600 checkout: moving from df_side2 to 57079a4 +57079a46233ae2b6df62e9ade71c4948512abefb d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169469 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169469 -0600 rebase -i (squash): df_side2 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169471 -0600 rebase -i (finish): returning to refs/heads/df_side2 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169494 -0600 checkout: moving from df_side2 to df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169663 -0600 checkout: moving from df_side1 to d4207f77243500bec335ab477f9227fcdb1e271a +d4207f77243500bec335ab477f9227fcdb1e271a 849619b03ae540acee4d1edec96b86993da6b497 Edward Thomson 1355169683 -0600 commit: both_dirs +849619b03ae540acee4d1edec96b86993da6b497 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169691 -0600 checkout: moving from 849619b03ae540acee4d1edec96b86993da6b497 to d4207f7 +d4207f77243500bec335ab477f9227fcdb1e271a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355169691 -0600 rebase -i (squash): updating HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169691 -0600 rebase -i (squash): df_ancestor +a765fb87eb2f7a1920b73b2d5a057f8f8476a42b 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169706 -0600 checkout: moving from a765fb87eb2f7a1920b73b2d5a057f8f8476a42b to df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169715 -0600 checkout: moving from df_side1 to a765fb87eb2f7a1920b73b2d5a057f8f8476a42b^0 +a765fb87eb2f7a1920b73b2d5a057f8f8476a42b bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169801 -0600 commit: df_side1 +bc744705e1d8a019993cf88f62bc4020f1b80919 bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169822 -0600 checkout: moving from bc744705e1d8a019993cf88f62bc4020f1b80919 to df_side1 +bc744705e1d8a019993cf88f62bc4020f1b80919 fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169826 -0600 checkout: moving from df_side1 to df_side2 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169866 -0600 checkout: moving from df_side2 to a765fb87eb2f7a1920b73b2d5a057f8f8476a42b^0 +a765fb87eb2f7a1920b73b2d5a057f8f8476a42b 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase: df_side2 +95646149ab6b6ba6edc83cff678582538b457b2b 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase finished: returning to refs/heads/df_side2 +95646149ab6b6ba6edc83cff678582538b457b2b bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169949 -0600 checkout: moving from df_side2 to df_side1 +bc744705e1d8a019993cf88f62bc4020f1b80919 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355170046 -0600 checkout: moving from df_side1 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355181639 -0600 checkout: moving from master to df_ancestor +bd593285fc7fe4ca18ccdbabf027f5d689101452 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355181673 -0600 commit: df_ancestor +2da538570bc1e5b2c3e855bf702f35248ad0735f a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181715 -0600 commit: df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181743 -0600 checkout: moving from df_ancestor to df_ancestor +a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181775 -0600 commit: df_side2 +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181793 -0600 checkout: moving from df_ancestor to df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181797 -0600 checkout: moving from df_side1 to df_side2 +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355182062 -0600 checkout: moving from df_side2 to df_ancestor +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182067 -0600 reset: moving to 2da538570bc1e5b2c3e855bf702f35248ad0735f +2da538570bc1e5b2c3e855bf702f35248ad0735f 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182087 -0600 checkout: moving from df_ancestor to df_side2 +2da538570bc1e5b2c3e855bf702f35248ad0735f fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182104 -0600 commit: df_side2 +fc90237dc4891fa6c69827fc465632225e391618 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355182111 -0600 checkout: moving from df_side2 to df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182115 -0600 checkout: moving from df_side1 to df_side2 +fc90237dc4891fa6c69827fc465632225e391618 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355182122 -0600 checkout: moving from df_side2 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 d6cf6c7741b3316826af1314042550c97ded1d50 Edward Thomson 1358997543 -0600 checkout: moving from master to unrelated +d6cf6c7741b3316826af1314042550c97ded1d50 55b4e4687e7a0d9ca367016ed930f385d4022e6f Edward Thomson 1358997664 -0600 commit: conflicting changes +55b4e4687e7a0d9ca367016ed930f385d4022e6f bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1358997675 -0600 checkout: moving from unrelated to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 88e185910a15cd13bdf44854ad037f4842b03b29 Edward Thomson 1365714471 -0500 checkout: moving from master to rename_conflict_ours +88e185910a15cd13bdf44854ad037f4842b03b29 bef6e37b3ee632ba74159168836f382fed21d77d Edward Thomson 1365714516 -0500 checkout: moving from rename_conflict_ours to bef6e37b3ee632ba74159168836f382fed21d77d +bef6e37b3ee632ba74159168836f382fed21d77d 01f149e1b8f84bd8896aaff6d6b22af88459ded0 Edward Thomson 1365714831 -0500 commit: rename ancestor +0000000000000000000000000000000000000000 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365714958 -0500 commit (initial): rename conflict ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 88e185910a15cd13bdf44854ad037f4842b03b29 Edward Thomson 1365714980 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours +88e185910a15cd13bdf44854ad037f4842b03b29 7c2c5228c9e90170d4a35e6558e47163daf092e5 Edward Thomson 1365715250 -0500 commit: rename conflict ours +7c2c5228c9e90170d4a35e6558e47163daf092e5 2f4024ce528d36d8670c289cce5a7963e625bb0c Edward Thomson 1365715274 -0500 checkout: moving from rename_conflict_ours to rename_conflict_theirs +2f4024ce528d36d8670c289cce5a7963e625bb0c 56a638b76b75e068590ac999c2f8621e7f3e264c Edward Thomson 1365715362 -0500 commit: rename conflict theirs +56a638b76b75e068590ac999c2f8621e7f3e264c 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715368 -0500 checkout: moving from rename_conflict_theirs to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 56a638b76b75e068590ac999c2f8621e7f3e264c Edward Thomson 1365715371 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_theirs +56a638b76b75e068590ac999c2f8621e7f3e264c 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715404 -0500 checkout: moving from rename_conflict_theirs to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715438 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715480 -0500 checkout: moving from rename_conflict_ours to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715486 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours +2392a2dacc9efb562b8635d6579fb458751c7c5b f3293571dcd708b6a3faf03818cd2844d000e198 Edward Thomson 1365715538 -0500 commit: rename conflict ours +f3293571dcd708b6a3faf03818cd2844d000e198 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715546 -0500 checkout: moving from rename_conflict_ours to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715550 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_thiers +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715554 -0500 checkout: moving from rename_conflict_thiers to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715557 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_theirs +2392a2dacc9efb562b8635d6579fb458751c7c5b a802e06f1782a9645b9851bc7202cee74a8a4972 Edward Thomson 1365715572 -0500 commit: rename conflict theirs +a802e06f1782a9645b9851bc7202cee74a8a4972 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1365715620 -0500 checkout: moving from rename_conflict_theirs to master diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch new file mode 100644 index 00000000000..8b0acb7020e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563886 -0500 branch: Created from HEAD +c607fc30883e335def28cd686b51f6cfa02b06ec 7cb63eed597130ba4abb87b3e544b85021905520 Edward Thomson 1351563965 -0500 commit: branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor new file mode 100644 index 00000000000..df7695a66dd --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355181639 -0600 branch: Created from HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355181673 -0600 commit: df_ancestor +2da538570bc1e5b2c3e855bf702f35248ad0735f a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181715 -0600 commit: df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181775 -0600 commit: df_side2 +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182067 -0600 reset: moving to 2da538570bc1e5b2c3e855bf702f35248ad0735f diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1 new file mode 100644 index 00000000000..a504ad610bd --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1 @@ -0,0 +1,14 @@ +0000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354574697 -0600 branch: Created from HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354574962 -0600 commit: df_ancestor +d4207f77243500bec335ab477f9227fcdb1e271a c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1354575027 -0600 commit: df_side1 +c94b27e41064c521120627e07e2035cca1d24ffa a90bc3fb6f15181972a2959a921429efbd81a473 Edward Thomson 1355017650 -0600 commit: df_added +a90bc3fb6f15181972a2959a921429efbd81a473 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017676 -0600 rebase -i (finish): refs/heads/df_side1 onto c94b27e +005b6fcc8fec71d2550bef8462d169b3c26aa14b f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017715 -0600 reset: moving to df_side2 +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 Edward Thomson 1355017744 -0600 commit: df_added +8c749d9968d4b10dcfb06c9f97d0e5d92d337071 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017756 -0600 rebase -i (finish): refs/heads/df_side1 onto f8958bd +0204a84f822acbf6386b36d33f1f6bc68bbbf858 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017793 -0600 reset: moving to 005b6fcc8fec71d2550bef8462d169b3c26aa14b +005b6fcc8fec71d2550bef8462d169b3c26aa14b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017826 -0600 reset: moving to 0204a84 +005b6fcc8fec71d2550bef8462d169b3c26aa14b e8107f24196736b870a318a0e28f048e29f6feff Edward Thomson 1355169065 -0600 commit: df_side1 +e8107f24196736b870a318a0e28f048e29f6feff 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169084 -0600 rebase -i (finish): refs/heads/df_side1 onto 005b6fc +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 Edward Thomson 1355169419 -0600 commit: side1 +e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169435 -0600 rebase -i (finish): refs/heads/df_side1 onto 80a8fbb diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2 new file mode 100644 index 00000000000..27d833eda29 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2 @@ -0,0 +1,9 @@ +0000000000000000000000000000000000000000 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354575051 -0600 branch: Created from d4207f77243500bec335ab477f9227fcdb1e271a +d4207f77243500bec335ab477f9227fcdb1e271a f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1354575206 -0600 commit: df_side2 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 944f5dd1a867cab4c2bbcb896493435cae1dcc1a Edward Thomson 1355169174 -0600 commit: both +944f5dd1a867cab4c2bbcb896493435cae1dcc1a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169185 -0600 rebase -i (finish): refs/heads/df_side2 onto 0204a84 +57079a46233ae2b6df62e9ade71c4948512abefb 58e853f66699fd02629fd50bde08082bc005933a Edward Thomson 1355169460 -0600 commit: side2 +58e853f66699fd02629fd50bde08082bc005933a fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169471 -0600 rebase -i (finish): refs/heads/df_side2 onto 57079a4 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase finished: refs/heads/df_side2 onto a765fb87eb2f7a1920b73b2d5a057f8f8476a42b +0000000000000000000000000000000000000000 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182087 -0600 branch: Created from HEAD +2da538570bc1e5b2c3e855bf702f35248ad0735f fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182104 -0600 commit: df_side2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch new file mode 100644 index 00000000000..c4706175d1c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605785 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351605830 -0500 commit: fastforward +33d500f588fbbe65901d82b4e6b008e549064be0 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351990202 -0500 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990205 -0500 merge master: Fast-forward +bd593285fc7fe4ca18ccdbabf027f5d689101452 fd89f8cffb663ac89095a0f9764902e93ceaca6a Edward Thomson 1351990229 -0500 commit: fastforward diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master new file mode 100644 index 00000000000..60475992a29 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563869 -0500 commit (initial): initial +c607fc30883e335def28cd686b51f6cfa02b06ec 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351564033 -0500 commit: master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4e0d9401aee78eb345a8685a859d37c8c3c0bbed Edward Thomson 1351875091 -0500 merge octo1 octo2 octo3 octo4: Merge made by the 'octopus' strategy. +4e0d9401aee78eb345a8685a859d37c8c3c0bbed 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875108 -0500 reset: moving to 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae +54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875584 -0500 reset: moving to 977c696519c5a3004c5f1d15d60c89dbeb8f235f diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1 new file mode 100644 index 00000000000..0b6c9214a3d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874933 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 16f825815cfd20a07a75c71554e82d8eede0b061 Edward Thomson 1351874954 -0500 commit: octo1 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2 new file mode 100644 index 00000000000..5392a4f8652 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874960 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 158dc7bedb202f5b26502bf3574faa7f4238d56c Edward Thomson 1351874974 -0500 commit: octo2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3 new file mode 100644 index 00000000000..7db5617c800 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874980 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 50ce7d7d01217679e26c55939eef119e0c93e272 Edward Thomson 1351874998 -0500 commit: octo3 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4 new file mode 100644 index 00000000000..b0f9e42ef14 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875010 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875023 -0500 commit: octo4 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5 new file mode 100644 index 00000000000..614563edfe3 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f e4f618a2c3ed0669308735727df5ebf2447f022f Edward Thomson 1351875041 -0500 commit: octo5 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6 new file mode 100644 index 00000000000..4c812eaccb2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4ca408a8c88655f7586a1b580be6fad138121e98 Edward Thomson 1351875057 -0500 commit: octo5 +4ca408a8c88655f7586a1b580be6fad138121e98 b6f610aef53bd343e6c96227de874c66f00ee8e8 Edward Thomson 1351875065 -0500 commit (amend): octo6 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1 new file mode 100644 index 00000000000..58a7e0565bf --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353177745 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 412b32fb66137366147f1801ecc962452757d48a Edward Thomson 1353177886 -0600 commit: renames diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2 new file mode 100644 index 00000000000..5645ecee730 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794647 -0600 branch: Created from HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353794677 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec ab40af3cb8a3ed2e2843e96d9aa7871336b94573 Edward Thomson 1353794852 -0600 commit: renames2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10 new file mode 100644 index 00000000000..b6bd247e751 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100171 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100193 -0600 commit: trivial-10 +53825f41ac8d640612f9423a2f03a69f3d96809a 0ec5f433959cd46177f745903353efb5be08d151 Edward Thomson 1352100223 -0600 commit: trivial-10 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch new file mode 100644 index 00000000000..14ce9e545e9 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100200 -0600 branch: Created from HEAD +53825f41ac8d640612f9423a2f03a69f3d96809a 11f4f3c08b737f5fd896cbefa1425ee63b21b2fa Edward Thomson 1352100211 -0600 commit: trivial-10-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11 new file mode 100644 index 00000000000..3e6b7743707 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100930 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100958 -0600 commit: trivial-11 +35632e43612c06a3ea924bfbacd48333da874c29 3168dca1a561889b045a6441909f4c56145e666d Edward Thomson 1352100992 -0600 commit: trivial-11 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch new file mode 100644 index 00000000000..30d5ec7a34b --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100964 -0600 branch: Created from HEAD +35632e43612c06a3ea924bfbacd48333da874c29 6718a45909532d1fcf5600d0877f7fe7e78f0b86 Edward Thomson 1352100978 -0600 commit: trivial-11-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13 new file mode 100644 index 00000000000..3a7302dea28 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100559 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100589 -0600 commit: trivial-13 +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa a3fabece9eb8748da810e1e08266fef9b7136ad4 Edward Thomson 1352100625 -0600 commit: trivial-13 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch new file mode 100644 index 00000000000..bb260424483 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100604 -0600 branch: Created from HEAD +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c Edward Thomson 1352100610 -0600 commit: trivial-13-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14 new file mode 100644 index 00000000000..4b70d2898af --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352101083 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101113 -0600 commit: trivial-14 +596803b523203a4851c824c07366906f8353f4ad 7e2d058d5fedf8329db44db4fac610d6b1a89159 Edward Thomson 1352101141 -0600 commit: trivial-14 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch new file mode 100644 index 00000000000..8e491ca6844 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101117 -0600 branch: Created from HEAD +596803b523203a4851c824c07366906f8353f4ad 8187117062b750eed4f93fd7e899f17b52ce554d Edward Thomson 1352101132 -0600 commit: trivial-14-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt new file mode 100644 index 00000000000..a2a28d40121 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352091695 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352092452 -0600 commit: 2alt diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch new file mode 100644 index 00000000000..a0a48ae3519 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092411 -0600 branch: Created from HEAD +c607fc30883e335def28cd686b51f6cfa02b06ec c9174cef549ec94ecbc43ef03cdc775b4950becb Edward Thomson 1352092434 -0600 commit: 2alt-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt new file mode 100644 index 00000000000..4374d3888b4 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt @@ -0,0 +1,3 @@ +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094547 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 5459c89aa0026d543ce8343bd89871bce543f9c2 Edward Thomson 1352094580 -0600 commit: 3alt +5459c89aa0026d543ce8343bd89871bce543f9c2 4c9fac0707f8d4195037ae5a681aa48626491541 Edward Thomson 1352094610 -0600 commit: 3alt-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch new file mode 100644 index 00000000000..7a2e6f8223c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094594 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4 new file mode 100644 index 00000000000..3ee6d250333 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4 @@ -0,0 +1,2 @@ +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094764 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352094815 -0600 commit: trivial-4 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch new file mode 100644 index 00000000000..51f8a9290df --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094830 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 183310e30fb1499af8c619108ffea4d300b5e778 Edward Thomson 1352094856 -0600 commit: trivial-4-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1 new file mode 100644 index 00000000000..14497029aa9 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096606 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096643 -0600 commit: 5alt-1 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch new file mode 100644 index 00000000000..4cff8352654 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096657 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 Edward Thomson 1352096689 -0600 commit: 5alt-1-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2 new file mode 100644 index 00000000000..3ca077b2969 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096711 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096764 -0600 commit: existing file +ebc09d0137cfb0c26697aed0109fb943ad906f3f 3b47b031b3e55ae11e14a05260b1c3ffd6838d55 Edward Thomson 1352096815 -0600 commit: 5alt-2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch new file mode 100644 index 00000000000..e7bb901f27d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096833 -0600 branch: Created from ebc09d0 +ebc09d0137cfb0c26697aed0109fb943ad906f3f f48097eb340dc5a7cae55aabcf1faf4548aa821f Edward Thomson 1352096855 -0600 commit: 5alt-2-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6 new file mode 100644 index 00000000000..7c717a2105e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352097371 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097389 -0600 commit: 6 +f7c332bd4d4d4b777366cae4d24d1687477576bf 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352097404 -0600 commit: trivial-6 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch new file mode 100644 index 00000000000..715f3ae1c2c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097414 -0600 branch: Created from f7c332bd4d4d4b777366cae4d24d1687477576bf +f7c332bd4d4d4b777366cae4d24d1687477576bf a43150a738849c59376cf30bb2a68348a83c8f48 Edward Thomson 1352097431 -0600 commit: 6-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7 new file mode 100644 index 00000000000..a014f1722b2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352099765 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099790 -0600 commit: trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 d874671ef5b20184836cb983bb273e5280384d0b Edward Thomson 1352099947 -0600 commit: trivial-7 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch new file mode 100644 index 00000000000..22331d78ccf --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099799 -0600 branch: Created from HEAD +092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099812 -0600 commit: trivial-7-branch +73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099874 -0600 reset: moving to 092ce8682d7f3a2a3a769a6daca58950168ba5c4 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 009b9cab6fdac02915a88ecd078b7a792ed802d8 Edward Thomson 1352099921 -0600 commit: removed in 7 +009b9cab6fdac02915a88ecd078b7a792ed802d8 5195a1b480f66691b667f10a9e41e70115a78351 Edward Thomson 1352099927 -0600 commit (amend): trivial-7-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8 new file mode 100644 index 00000000000..7670c35066a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352098816 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098884 -0600 commit: trivial-8 +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 3575826c96a975031d2c14368529cc5c4353a8fd Edward Thomson 1352099000 -0600 commit: trivial-8 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch new file mode 100644 index 00000000000..c4d68edcf8b --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098947 -0600 branch: Created from HEAD +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 Edward Thomson 1352098979 -0600 commit: trivial-8-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9 new file mode 100644 index 00000000000..09a343bdb52 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100268 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100304 -0600 commit: trivial-9 +f0053b8060bb3f0be5cbcc3147a07ece26bf097e c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a Edward Thomson 1352100333 -0600 commit: trivial-9 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch new file mode 100644 index 00000000000..1b126fb7bed --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100310 -0600 branch: Created from HEAD +f0053b8060bb3f0be5cbcc3147a07ece26bf097e 13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e Edward Thomson 1352100317 -0600 commit: trivial-9-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated new file mode 100644 index 00000000000..a83ffc26a56 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated @@ -0,0 +1 @@ +d6cf6c7741b3316826af1314042550c97ded1d50 55b4e4687e7a0d9ca367016ed930f385d4022e6f Edward Thomson 1358997664 -0600 commit: conflicting changes diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/00/5b6fcc8fec71d2550bef8462d169b3c26aa14b b/tests-clar/resources/merge-resolve/.gitted/objects/00/5b6fcc8fec71d2550bef8462d169b3c26aa14b new file mode 100644 index 00000000000..82a8da597f0 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/00/5b6fcc8fec71d2550bef8462d169b3c26aa14b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/00/9b9cab6fdac02915a88ecd078b7a792ed802d8 b/tests-clar/resources/merge-resolve/.gitted/objects/00/9b9cab6fdac02915a88ecd078b7a792ed802d8 new file mode 100644 index 00000000000..f663a3c5146 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/00/9b9cab6fdac02915a88ecd078b7a792ed802d8 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/00/c7d33f1ffa79d19c2272b370fcaeaadba49c08 b/tests-clar/resources/merge-resolve/.gitted/objects/00/c7d33f1ffa79d19c2272b370fcaeaadba49c08 new file mode 100644 index 00000000000..72698dc3df0 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/00/c7d33f1ffa79d19c2272b370fcaeaadba49c08 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/01/f149e1b8f84bd8896aaff6d6b22af88459ded0 b/tests-clar/resources/merge-resolve/.gitted/objects/01/f149e1b8f84bd8896aaff6d6b22af88459ded0 new file mode 100644 index 00000000000..aa6336d3fac Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/01/f149e1b8f84bd8896aaff6d6b22af88459ded0 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/02/04a84f822acbf6386b36d33f1f6bc68bbbf858 b/tests-clar/resources/merge-resolve/.gitted/objects/02/04a84f822acbf6386b36d33f1f6bc68bbbf858 new file mode 100644 index 00000000000..2f0a0e1bb13 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/02/04a84f822acbf6386b36d33f1f6bc68bbbf858 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/02/251f990ca8e92e7ae61d3426163fa821c64001 b/tests-clar/resources/merge-resolve/.gitted/objects/02/251f990ca8e92e7ae61d3426163fa821c64001 new file mode 100644 index 00000000000..d623117c545 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/02/251f990ca8e92e7ae61d3426163fa821c64001 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/03/21415405cb906c46869919af56d51dbbe5e85c b/tests-clar/resources/merge-resolve/.gitted/objects/03/21415405cb906c46869919af56d51dbbe5e85c new file mode 100644 index 00000000000..277bdcff519 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/03/21415405cb906c46869919af56d51dbbe5e85c differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/03/2ebc5ab85d9553bb187d3cd40875ff23a63ed0 b/tests-clar/resources/merge-resolve/.gitted/objects/03/2ebc5ab85d9553bb187d3cd40875ff23a63ed0 new file mode 100644 index 00000000000..e5404d838a8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/03/2ebc5ab85d9553bb187d3cd40875ff23a63ed0 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/03/b87706555accbf874ccd410dbda01e8e70a67f b/tests-clar/resources/merge-resolve/.gitted/objects/03/b87706555accbf874ccd410dbda01e8e70a67f new file mode 100644 index 00000000000..0befcd73567 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/03/b87706555accbf874ccd410dbda01e8e70a67f differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/03/dad1005e5d06d418f50b12e0bcd48ff2306a03 b/tests-clar/resources/merge-resolve/.gitted/objects/03/dad1005e5d06d418f50b12e0bcd48ff2306a03 new file mode 100644 index 00000000000..04011a2ceb5 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/03/dad1005e5d06d418f50b12e0bcd48ff2306a03 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 b/tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 new file mode 100644 index 00000000000..65fa6894fe2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 @@ -0,0 +1 @@ +x+)JMU06`040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5&ؽ +gz43^2 I{| 2mg˾15ӿ,\})TC)0Xvz֛9MՅ'6b# \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/05/8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe b/tests-clar/resources/merge-resolve/.gitted/objects/05/8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe new file mode 100644 index 00000000000..d79dc30ba71 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/05/8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/05/f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c b/tests-clar/resources/merge-resolve/.gitted/objects/05/f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c new file mode 100644 index 00000000000..7b4b152f34b Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/05/f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/07/a759da919f737221791d542f176ab49c88837f b/tests-clar/resources/merge-resolve/.gitted/objects/07/a759da919f737221791d542f176ab49c88837f new file mode 100644 index 00000000000..a34b6c23561 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/07/a759da919f737221791d542f176ab49c88837f differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/07/c514b04698e068892b31c8d352b85813b99c6e b/tests-clar/resources/merge-resolve/.gitted/objects/07/c514b04698e068892b31c8d352b85813b99c6e new file mode 100644 index 00000000000..23ab9217148 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/07/c514b04698e068892b31c8d352b85813b99c6e differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/055301463b7f2f8ee5d368f8ed5c0a40ad8515 b/tests-clar/resources/merge-resolve/.gitted/objects/09/055301463b7f2f8ee5d368f8ed5c0a40ad8515 new file mode 100644 index 00000000000..bf5b0fcc57f Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/09/055301463b7f2f8ee5d368f8ed5c0a40ad8515 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/17bb159596aea4d295f4857da77e8f96b3c7dc b/tests-clar/resources/merge-resolve/.gitted/objects/09/17bb159596aea4d295f4857da77e8f96b3c7dc new file mode 100644 index 00000000000..9fb640dd5c9 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/09/17bb159596aea4d295f4857da77e8f96b3c7dc differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/2ce8682d7f3a2a3a769a6daca58950168ba5c4 b/tests-clar/resources/merge-resolve/.gitted/objects/09/2ce8682d7f3a2a3a769a6daca58950168ba5c4 new file mode 100644 index 00000000000..b709cf461be Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/09/2ce8682d7f3a2a3a769a6daca58950168ba5c4 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/3bebf072dd4bbba88833667d6ffe454df199e1 b/tests-clar/resources/merge-resolve/.gitted/objects/09/3bebf072dd4bbba88833667d6ffe454df199e1 new file mode 100644 index 00000000000..ae13207d749 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/09/3bebf072dd4bbba88833667d6ffe454df199e1 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/768bed22680cdb0859683fa9677ccc8d5a25c1 b/tests-clar/resources/merge-resolve/.gitted/objects/09/768bed22680cdb0859683fa9677ccc8d5a25c1 new file mode 100644 index 00000000000..5f4b4dab13c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/09/768bed22680cdb0859683fa9677ccc8d5a25c1 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/0a/75d9aac1dc84fb5aa51f7325c0ab53242ddef7 b/tests-clar/resources/merge-resolve/.gitted/objects/0a/75d9aac1dc84fb5aa51f7325c0ab53242ddef7 new file mode 100644 index 00000000000..d5377341aad Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/0a/75d9aac1dc84fb5aa51f7325c0ab53242ddef7 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/0c/fd6c54ef6532d862408f562309dc9c74a401e8 b/tests-clar/resources/merge-resolve/.gitted/objects/0c/fd6c54ef6532d862408f562309dc9c74a401e8 new file mode 100644 index 00000000000..40f628f8912 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/0c/fd6c54ef6532d862408f562309dc9c74a401e8 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/0d/52e3a556e189ba0948ae56780918011c1b167d b/tests-clar/resources/merge-resolve/.gitted/objects/0d/52e3a556e189ba0948ae56780918011c1b167d new file mode 100644 index 00000000000..4b633e5043d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/0d/52e3a556e189ba0948ae56780918011c1b167d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/0d/872f8e871a30208305978ecbf9e66d864f1638 b/tests-clar/resources/merge-resolve/.gitted/objects/0d/872f8e871a30208305978ecbf9e66d864f1638 new file mode 100644 index 00000000000..4cbc18e8443 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/0d/872f8e871a30208305978ecbf9e66d864f1638 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/0e/c5f433959cd46177f745903353efb5be08d151 b/tests-clar/resources/merge-resolve/.gitted/objects/0e/c5f433959cd46177f745903353efb5be08d151 new file mode 100644 index 00000000000..1bee56c14b8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/0e/c5f433959cd46177f745903353efb5be08d151 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/11/deab00b2d3a6f5a3073988ac050c2d7b6655e2 b/tests-clar/resources/merge-resolve/.gitted/objects/11/deab00b2d3a6f5a3073988ac050c2d7b6655e2 new file mode 100644 index 00000000000..857b2368673 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/11/deab00b2d3a6f5a3073988ac050c2d7b6655e2 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa b/tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa new file mode 100644 index 00000000000..6555194cb0e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa @@ -0,0 +1 @@ +xQ D\fw)c^` ۴-Q/ơdb^ץjEDC$u> , z@8qjk<٩G>z2Lva2)Veŏ:%˜{A|Ǽ5K@mg9jY _;n,YyP \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/13/d1be4ea52a6ced1d7a1d832f0ee3c399348e5e b/tests-clar/resources/merge-resolve/.gitted/objects/13/d1be4ea52a6ced1d7a1d832f0ee3c399348e5e new file mode 100644 index 00000000000..4e4e175e816 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/13/d1be4ea52a6ced1d7a1d832f0ee3c399348e5e differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/14/39088f509b79b1535b64193137d3ce4b240734 b/tests-clar/resources/merge-resolve/.gitted/objects/14/39088f509b79b1535b64193137d3ce4b240734 new file mode 100644 index 00000000000..51ddf6dcb9e Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/14/39088f509b79b1535b64193137d3ce4b240734 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c b/tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c new file mode 100644 index 00000000000..064423d0c9e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c @@ -0,0 +1,2 @@ +xK!D]sCboi2. bK*Eep73UӾ*NYYIԔ)jL:8<{NޓH6iDC"mqH!9Tm9>R^i.= +G'+~@@j+7أENsFt]7bN) \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 b/tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 new file mode 100644 index 00000000000..82d65253bf9 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 @@ -0,0 +1 @@ +xK!D]sObo hJqo6AJـT1h3'Lՠ.{ec,a`ZJT1#e+هJUi">\+ ץG_X6IvN;^bYgGMM \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/17/8940b450f238a56c0d75b7955cb57b38191982 b/tests-clar/resources/merge-resolve/.gitted/objects/17/8940b450f238a56c0d75b7955cb57b38191982 new file mode 100644 index 00000000000..94e571e6547 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/17/8940b450f238a56c0d75b7955cb57b38191982 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/18/3310e30fb1499af8c619108ffea4d300b5e778 b/tests-clar/resources/merge-resolve/.gitted/objects/18/3310e30fb1499af8c619108ffea4d300b5e778 new file mode 100644 index 00000000000..1c4010d0479 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/18/3310e30fb1499af8c619108ffea4d300b5e778 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/18/cb316b1cefa0f8a6946f0e201a8e1a6f845ab9 b/tests-clar/resources/merge-resolve/.gitted/objects/18/cb316b1cefa0f8a6946f0e201a8e1a6f845ab9 new file mode 100644 index 00000000000..30f3110f122 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/18/cb316b1cefa0f8a6946f0e201a8e1a6f845ab9 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/19/b7ac485269b672a101060894de3ba9c2a24dd1 b/tests-clar/resources/merge-resolve/.gitted/objects/19/b7ac485269b672a101060894de3ba9c2a24dd1 new file mode 100644 index 00000000000..e34ccb855c0 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/19/b7ac485269b672a101060894de3ba9c2a24dd1 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/1c/ff9ec6a47a537380dedfdd17c9e76d74259a2b b/tests-clar/resources/merge-resolve/.gitted/objects/1c/ff9ec6a47a537380dedfdd17c9e76d74259a2b new file mode 100644 index 00000000000..30802bcecd7 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/1c/ff9ec6a47a537380dedfdd17c9e76d74259a2b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/1e/4ff029aee68d0d69ef9eb6efa6cbf1ec732f99 b/tests-clar/resources/merge-resolve/.gitted/objects/1e/4ff029aee68d0d69ef9eb6efa6cbf1ec732f99 new file mode 100644 index 00000000000..5183b8360a0 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/1e/4ff029aee68d0d69ef9eb6efa6cbf1ec732f99 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/1f/81433e3161efbf250576c58fede7f6b836f3d3 b/tests-clar/resources/merge-resolve/.gitted/objects/1f/81433e3161efbf250576c58fede7f6b836f3d3 new file mode 100644 index 00000000000..97085567539 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/1f/81433e3161efbf250576c58fede7f6b836f3d3 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/20/91d94c8bd3eb0835dc5220de5e8bb310fa1513 b/tests-clar/resources/merge-resolve/.gitted/objects/20/91d94c8bd3eb0835dc5220de5e8bb310fa1513 new file mode 100644 index 00000000000..a843890c07c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/20/91d94c8bd3eb0835dc5220de5e8bb310fa1513 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/21/671e290278286fb2ce4c63d01699b67adce331 b/tests-clar/resources/merge-resolve/.gitted/objects/21/671e290278286fb2ce4c63d01699b67adce331 new file mode 100644 index 00000000000..b656d000155 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/21/671e290278286fb2ce4c63d01699b67adce331 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/22/7792b52aaa0b238bea00ec7e509b02623f168c b/tests-clar/resources/merge-resolve/.gitted/objects/22/7792b52aaa0b238bea00ec7e509b02623f168c new file mode 100644 index 00000000000..3bb19bb7721 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/22/7792b52aaa0b238bea00ec7e509b02623f168c differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/23/3c0919c998ed110a4b6ff36f353aec8b713487 b/tests-clar/resources/merge-resolve/.gitted/objects/23/3c0919c998ed110a4b6ff36f353aec8b713487 new file mode 100644 index 00000000000..d0c8c9e1df9 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/23/3c0919c998ed110a4b6ff36f353aec8b713487 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/23/92a2dacc9efb562b8635d6579fb458751c7c5b b/tests-clar/resources/merge-resolve/.gitted/objects/23/92a2dacc9efb562b8635d6579fb458751c7c5b new file mode 100644 index 00000000000..86127a344bc Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/23/92a2dacc9efb562b8635d6579fb458751c7c5b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/24/1a1005cd9b980732741b74385b891142bcba28 b/tests-clar/resources/merge-resolve/.gitted/objects/24/1a1005cd9b980732741b74385b891142bcba28 new file mode 100644 index 00000000000..9b65f666f7c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/24/1a1005cd9b980732741b74385b891142bcba28 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/24/2591eb280ee9eeb2ce63524b9a8b9bc4cb515d b/tests-clar/resources/merge-resolve/.gitted/objects/24/2591eb280ee9eeb2ce63524b9a8b9bc4cb515d new file mode 100644 index 00000000000..74a01373f44 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/24/2591eb280ee9eeb2ce63524b9a8b9bc4cb515d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/24/90b9f1a079420870027deefb49f51d6656cf74 b/tests-clar/resources/merge-resolve/.gitted/objects/24/90b9f1a079420870027deefb49f51d6656cf74 new file mode 100644 index 00000000000..60497caa56d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/24/90b9f1a079420870027deefb49f51d6656cf74 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/25/9d08ca43af9200e9ea9a098e44a5a350ebd9b3 b/tests-clar/resources/merge-resolve/.gitted/objects/25/9d08ca43af9200e9ea9a098e44a5a350ebd9b3 new file mode 100644 index 00000000000..2bae6699897 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/25/9d08ca43af9200e9ea9a098e44a5a350ebd9b3 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/25/c40b7660c08c8fb581f770312f41b9b03119d1 b/tests-clar/resources/merge-resolve/.gitted/objects/25/c40b7660c08c8fb581f770312f41b9b03119d1 new file mode 100644 index 00000000000..185214727f4 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/25/c40b7660c08c8fb581f770312f41b9b03119d1 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/26/153a3ff3649b6c2bb652d3f06878c6e0a172f9 b/tests-clar/resources/merge-resolve/.gitted/objects/26/153a3ff3649b6c2bb652d3f06878c6e0a172f9 new file mode 100644 index 00000000000..4fcaa07e228 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/26/153a3ff3649b6c2bb652d3f06878c6e0a172f9 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/27/133da702ba3c60af2a01e96c2555ff4045d692 b/tests-clar/resources/merge-resolve/.gitted/objects/27/133da702ba3c60af2a01e96c2555ff4045d692 new file mode 100644 index 00000000000..08e61f84410 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/27/133da702ba3c60af2a01e96c2555ff4045d692 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2b/0de5dc27505dcdd83a75c8bf1fcd9462cd7add b/tests-clar/resources/merge-resolve/.gitted/objects/2b/0de5dc27505dcdd83a75c8bf1fcd9462cd7add new file mode 100644 index 00000000000..a95f926f821 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/2b/0de5dc27505dcdd83a75c8bf1fcd9462cd7add differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2b/5f1f181ee3b58ea751f5dd5d8f9b445520a136 b/tests-clar/resources/merge-resolve/.gitted/objects/2b/5f1f181ee3b58ea751f5dd5d8f9b445520a136 new file mode 100644 index 00000000000..d24231eda0f Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/2b/5f1f181ee3b58ea751f5dd5d8f9b445520a136 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 b/tests-clar/resources/merge-resolve/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 new file mode 100644 index 00000000000..d10ca636b6b Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f b/tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f new file mode 100644 index 00000000000..83253f81c68 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f @@ -0,0 +1,2 @@ +xK +1D]N"n{t:L$ UEQ>~7:L D [5ɇ,y2eT@z*.([žunum_|Št@ +apg%haJYծA8թ훠fN4;h[%cOuJWyΏ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 b/tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 new file mode 100644 index 00000000000..1d9f226e2cb --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 @@ -0,0 +1 @@ +x+)JMU067c040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~13zדm9Wu]:$I{| 2mg˾15ӿ,\})TC)0Pavz֛9MՅ'6b \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d b/tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d new file mode 100644 index 00000000000..2de1c5a791f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d @@ -0,0 +1,2 @@ +xQ +0D)rJMxMHz}xfރaRYipkUD $1fQ2q-=Y3R76ġg9e7 bw GJe*˽ |ůSY"5&Нƨng9Z3_;kdO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/31/d5472536041a83d986829240bbbdc897c6f8a6 b/tests-clar/resources/merge-resolve/.gitted/objects/31/d5472536041a83d986829240bbbdc897c6f8a6 new file mode 100644 index 00000000000..5ec5acb5968 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/31/d5472536041a83d986829240bbbdc897c6f8a6 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/32/21dd512b7e2dc4b5bd03046df6c81b2ab2070b b/tests-clar/resources/merge-resolve/.gitted/objects/32/21dd512b7e2dc4b5bd03046df6c81b2ab2070b new file mode 100644 index 00000000000..d36138d796c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/32/21dd512b7e2dc4b5bd03046df6c81b2ab2070b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/33/46d64325b39e5323733492cd55f808994a2475 b/tests-clar/resources/merge-resolve/.gitted/objects/33/46d64325b39e5323733492cd55f808994a2475 new file mode 100644 index 00000000000..11546cea449 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/33/46d64325b39e5323733492cd55f808994a2475 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/33/d500f588fbbe65901d82b4e6b008e549064be0 b/tests-clar/resources/merge-resolve/.gitted/objects/33/d500f588fbbe65901d82b4e6b008e549064be0 new file mode 100644 index 00000000000..061a031b6f0 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/33/d500f588fbbe65901d82b4e6b008e549064be0 @@ -0,0 +1,2 @@ +xA E]s +.hbo.Z x}[ ~kCA<:km`d̑d,!:𦐳P1P qHccHEO[zsK>y>隿ïm6*Rn>O \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 b/tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 new file mode 100644 index 00000000000..c653cec50ce --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 @@ -0,0 +1 @@ +xKj1D) >`7A. $<`Morlm4G&dVd[j2JCъgu_Gu%2:3XزQ'";?wpkm׾&Pf! %QJ%:Cez=6q;iO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/0c6eb3010efc403a6bed682332635314e9ed58 b/tests-clar/resources/merge-resolve/.gitted/objects/35/0c6eb3010efc403a6bed682332635314e9ed58 new file mode 100644 index 00000000000..2eee602335c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/35/0c6eb3010efc403a6bed682332635314e9ed58 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/411bfb77cd2cc431f3a03a2b4976ed94b5d241 b/tests-clar/resources/merge-resolve/.gitted/objects/35/411bfb77cd2cc431f3a03a2b4976ed94b5d241 new file mode 100644 index 00000000000..ea024ccd9e3 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/35/411bfb77cd2cc431f3a03a2b4976ed94b5d241 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/4704d3613ad4228e4786fc76656b11e98236c4 b/tests-clar/resources/merge-resolve/.gitted/objects/35/4704d3613ad4228e4786fc76656b11e98236c4 new file mode 100644 index 00000000000..1dd13c44a00 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/35/4704d3613ad4228e4786fc76656b11e98236c4 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 b/tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 new file mode 100644 index 00000000000..be7684f1913 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 @@ -0,0 +1 @@ +xN !LdMb60^,40;iUFf+)1vB939fG(DIݸʵA$sk]l|L{Ig$m.N5y.\a/]|Ʋ@[g4< Hl?gTsˠzCP \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/75826c96a975031d2c14368529cc5c4353a8fd b/tests-clar/resources/merge-resolve/.gitted/objects/35/75826c96a975031d2c14368529cc5c4353a8fd new file mode 100644 index 00000000000..24e33bc41cf Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/35/75826c96a975031d2c14368529cc5c4353a8fd differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/36/219b49367146cb2e6a1555b5a9ebd4d0328495 b/tests-clar/resources/merge-resolve/.gitted/objects/36/219b49367146cb2e6a1555b5a9ebd4d0328495 new file mode 100644 index 00000000000..7f8044372ad Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/36/219b49367146cb2e6a1555b5a9ebd4d0328495 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/36/4bbe4ce80c7bd31e6307dce77d46e3e1759fb3 b/tests-clar/resources/merge-resolve/.gitted/objects/36/4bbe4ce80c7bd31e6307dce77d46e3e1759fb3 new file mode 100644 index 00000000000..90fd9651f8c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/36/4bbe4ce80c7bd31e6307dce77d46e3e1759fb3 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/37/48859b001c6e627e712a07951aee40afd19b41 b/tests-clar/resources/merge-resolve/.gitted/objects/37/48859b001c6e627e712a07951aee40afd19b41 new file mode 100644 index 00000000000..6a0c389e43a Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/37/48859b001c6e627e712a07951aee40afd19b41 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced b/tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced new file mode 100644 index 00000000000..e95ff3a88f0 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced @@ -0,0 +1,2 @@ +x-MK +1 uSYRą6C6뛪oknYt Ep iDCddLB+8%qk +e6fHB1J4F1l \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/3b/47b031b3e55ae11e14a05260b1c3ffd6838d55 b/tests-clar/resources/merge-resolve/.gitted/objects/3b/47b031b3e55ae11e14a05260b1c3ffd6838d55 new file mode 100644 index 00000000000..82086466f5e Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/3b/47b031b3e55ae11e14a05260b1c3ffd6838d55 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/3b/bf0bf59b20df5d5fc58b9fc1dc07be637c301f b/tests-clar/resources/merge-resolve/.gitted/objects/3b/bf0bf59b20df5d5fc58b9fc1dc07be637c301f new file mode 100644 index 00000000000..723a9ae4c91 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/3b/bf0bf59b20df5d5fc58b9fc1dc07be637c301f differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/3e/f4d30382ca33fdeba9fda895a99e0891ba37aa b/tests-clar/resources/merge-resolve/.gitted/objects/3e/f4d30382ca33fdeba9fda895a99e0891ba37aa new file mode 100644 index 00000000000..49ee1523972 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/3e/f4d30382ca33fdeba9fda895a99e0891ba37aa differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/3e/f9bfe82f9635518ae89152322f3b46fd4ba25b b/tests-clar/resources/merge-resolve/.gitted/objects/3e/f9bfe82f9635518ae89152322f3b46fd4ba25b new file mode 100644 index 00000000000..3b5998ca61d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/3e/f9bfe82f9635518ae89152322f3b46fd4ba25b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/40/2784a46a4a3982294231594cbeb431f506d22c b/tests-clar/resources/merge-resolve/.gitted/objects/40/2784a46a4a3982294231594cbeb431f506d22c new file mode 100644 index 00000000000..a17e05d0f17 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/40/2784a46a4a3982294231594cbeb431f506d22c differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/41/2b32fb66137366147f1801ecc962452757d48a b/tests-clar/resources/merge-resolve/.gitted/objects/41/2b32fb66137366147f1801ecc962452757d48a new file mode 100644 index 00000000000..b183dd78224 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/41/2b32fb66137366147f1801ecc962452757d48a @@ -0,0 +1,2 @@ +xK +1D]IO>"nt:x}xwUxjum'뫈.9=y 6$@T8&Lhf4Aܻf0B(.K>9S< +z_f}]Z]eO:wzރP.ިaNU6O \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/43/aafd43bea779ec74317dc361f45ae3f532a505 b/tests-clar/resources/merge-resolve/.gitted/objects/43/aafd43bea779ec74317dc361f45ae3f532a505 new file mode 100644 index 00000000000..ac86823b67a Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/43/aafd43bea779ec74317dc361f45ae3f532a505 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/43/c338656342227a3a3cd3aa85cbf784061f5425 b/tests-clar/resources/merge-resolve/.gitted/objects/43/c338656342227a3a3cd3aa85cbf784061f5425 new file mode 100644 index 00000000000..d9773118b22 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/43/c338656342227a3a3cd3aa85cbf784061f5425 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/45/299c1ca5e07bba1fd90843056fb559f96b1f5a b/tests-clar/resources/merge-resolve/.gitted/objects/45/299c1ca5e07bba1fd90843056fb559f96b1f5a new file mode 100644 index 00000000000..2093b441033 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/45/299c1ca5e07bba1fd90843056fb559f96b1f5a differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/46/6daf8552b891e5c22bc58c9d7fc1a2eb8f0289 b/tests-clar/resources/merge-resolve/.gitted/objects/46/6daf8552b891e5c22bc58c9d7fc1a2eb8f0289 new file mode 100644 index 00000000000..c39b53aa8f4 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/46/6daf8552b891e5c22bc58c9d7fc1a2eb8f0289 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/47/6dbb3e207313d1d8aaa120c6ad204bf1295e53 b/tests-clar/resources/merge-resolve/.gitted/objects/47/6dbb3e207313d1d8aaa120c6ad204bf1295e53 new file mode 100644 index 00000000000..3e5f66e5560 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/47/6dbb3e207313d1d8aaa120c6ad204bf1295e53 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/47/8172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 b/tests-clar/resources/merge-resolve/.gitted/objects/47/8172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 new file mode 100644 index 00000000000..d9e250e6664 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/47/8172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/49/130a28ef567af9a6a6104c38773fedfa5f9742 b/tests-clar/resources/merge-resolve/.gitted/objects/49/130a28ef567af9a6a6104c38773fedfa5f9742 new file mode 100644 index 00000000000..e2c49f5c45e Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/49/130a28ef567af9a6a6104c38773fedfa5f9742 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/49/9df817155e4bdd3c6ee192a72c52f481818230 b/tests-clar/resources/merge-resolve/.gitted/objects/49/9df817155e4bdd3c6ee192a72c52f481818230 new file mode 100644 index 00000000000..9c7e471dd64 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/49/9df817155e4bdd3c6ee192a72c52f481818230 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4a/9550ebcc97ce22b22f45af7b829bb030d003f5 b/tests-clar/resources/merge-resolve/.gitted/objects/4a/9550ebcc97ce22b22f45af7b829bb030d003f5 new file mode 100644 index 00000000000..6ec674adc57 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4a/9550ebcc97ce22b22f45af7b829bb030d003f5 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4b/253da36a0ae8bfce63aeabd8c5b58429925594 b/tests-clar/resources/merge-resolve/.gitted/objects/4b/253da36a0ae8bfce63aeabd8c5b58429925594 new file mode 100644 index 00000000000..1a4072794bc --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/4b/253da36a0ae8bfce63aeabd8c5b58429925594 @@ -0,0 +1,2 @@ +x A +0 @AAILm l׹vGx#63tW B6%h \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4b/48deed3a433909bfd6b6ab3d4b91348b6af464 b/tests-clar/resources/merge-resolve/.gitted/objects/4b/48deed3a433909bfd6b6ab3d4b91348b6af464 new file mode 100644 index 00000000000..328c8506e07 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4b/48deed3a433909bfd6b6ab3d4b91348b6af464 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 b/tests-clar/resources/merge-resolve/.gitted/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 new file mode 100644 index 00000000000..adf64119a33 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4c/9fac0707f8d4195037ae5a681aa48626491541 b/tests-clar/resources/merge-resolve/.gitted/objects/4c/9fac0707f8d4195037ae5a681aa48626491541 new file mode 100644 index 00000000000..6b8c85e2bec Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4c/9fac0707f8d4195037ae5a681aa48626491541 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4c/a408a8c88655f7586a1b580be6fad138121e98 b/tests-clar/resources/merge-resolve/.gitted/objects/4c/a408a8c88655f7586a1b580be6fad138121e98 new file mode 100644 index 00000000000..15cb7f29af8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4c/a408a8c88655f7586a1b580be6fad138121e98 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4e/0d9401aee78eb345a8685a859d37c8c3c0bbed b/tests-clar/resources/merge-resolve/.gitted/objects/4e/0d9401aee78eb345a8685a859d37c8c3c0bbed new file mode 100644 index 00000000000..57f7eb68c31 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4e/0d9401aee78eb345a8685a859d37c8c3c0bbed differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 b/tests-clar/resources/merge-resolve/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 new file mode 100644 index 00000000000..53168a038b7 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4e/b04c9e79e88f6640d01ff5b25ca2a60764f216 b/tests-clar/resources/merge-resolve/.gitted/objects/4e/b04c9e79e88f6640d01ff5b25ca2a60764f216 new file mode 100644 index 00000000000..f4ec0efecb4 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4e/b04c9e79e88f6640d01ff5b25ca2a60764f216 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4f/e93c0ec83eb6305cbace3dace88ecee1b63cb6 b/tests-clar/resources/merge-resolve/.gitted/objects/4f/e93c0ec83eb6305cbace3dace88ecee1b63cb6 new file mode 100644 index 00000000000..67dc6842fd6 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/4f/e93c0ec83eb6305cbace3dace88ecee1b63cb6 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/50/12fd565b1393bdfda1805d4ec38ce6619e1fd1 b/tests-clar/resources/merge-resolve/.gitted/objects/50/12fd565b1393bdfda1805d4ec38ce6619e1fd1 new file mode 100644 index 00000000000..d629a23a167 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/50/12fd565b1393bdfda1805d4ec38ce6619e1fd1 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/50/4f75ac95a71ef98051817618576a68505b92f9 b/tests-clar/resources/merge-resolve/.gitted/objects/50/4f75ac95a71ef98051817618576a68505b92f9 new file mode 100644 index 00000000000..1b24c721abd Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/50/4f75ac95a71ef98051817618576a68505b92f9 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/50/84fc2a88b6bdba8db93bd3953a8f4fdb470238 b/tests-clar/resources/merge-resolve/.gitted/objects/50/84fc2a88b6bdba8db93bd3953a8f4fdb470238 new file mode 100644 index 00000000000..84c9987ce25 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/50/84fc2a88b6bdba8db93bd3953a8f4fdb470238 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/50/ce7d7d01217679e26c55939eef119e0c93e272 b/tests-clar/resources/merge-resolve/.gitted/objects/50/ce7d7d01217679e26c55939eef119e0c93e272 new file mode 100644 index 00000000000..e2f9f67fdf9 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/50/ce7d7d01217679e26c55939eef119e0c93e272 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/51/95a1b480f66691b667f10a9e41e70115a78351 b/tests-clar/resources/merge-resolve/.gitted/objects/51/95a1b480f66691b667f10a9e41e70115a78351 new file mode 100644 index 00000000000..088ee5498e2 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/51/95a1b480f66691b667f10a9e41e70115a78351 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/52/d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 b/tests-clar/resources/merge-resolve/.gitted/objects/52/d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 new file mode 100644 index 00000000000..6522209bdf9 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/52/d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 @@ -0,0 +1,3 @@ +x] +0})rnD|^`Ђm$FUo3ä,sӽ]" #b"1 9cThS//SYe'+~mrh\cQwFMQϙ]b5M R \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/53/825f41ac8d640612f9423a2f03a69f3d96809a b/tests-clar/resources/merge-resolve/.gitted/objects/53/825f41ac8d640612f9423a2f03a69f3d96809a new file mode 100644 index 00000000000..08cb0b66fe7 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/53/825f41ac8d640612f9423a2f03a69f3d96809a differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/54/269b3f6ec3d7d4ede24dd350dd5d605495c3ae b/tests-clar/resources/merge-resolve/.gitted/objects/54/269b3f6ec3d7d4ede24dd350dd5d605495c3ae new file mode 100644 index 00000000000..4a241533943 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/54/269b3f6ec3d7d4ede24dd350dd5d605495c3ae @@ -0,0 +1,2 @@ +xK +1D]I7 LӌL$FxwUAQj m'؍^v9 d- Ɯ \ ϽC'&`"Ĺ(֡9_sg}]Z}UF?\I&@mt;;ʟ3hzN \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/54/59c89aa0026d543ce8343bd89871bce543f9c2 b/tests-clar/resources/merge-resolve/.gitted/objects/54/59c89aa0026d543ce8343bd89871bce543f9c2 new file mode 100644 index 00000000000..178b833e88a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/54/59c89aa0026d543ce8343bd89871bce543f9c2 @@ -0,0 +1,3 @@ +x !D +,,,,9O bl؁3%mY.C[LEtd`\ %aBH%TvB G%Qphq]nCgP3B(H14yS)W;IVsT^܋>myJ?(_kܖ6-$#-Zzvȟ3 +:NqMB \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/54/7607c690372fe81fab8e3bb44c530e129118fd b/tests-clar/resources/merge-resolve/.gitted/objects/54/7607c690372fe81fab8e3bb44c530e129118fd new file mode 100644 index 00000000000..dccd2200680 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/54/7607c690372fe81fab8e3bb44c530e129118fd differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/55/b4e4687e7a0d9ca367016ed930f385d4022e6f b/tests-clar/resources/merge-resolve/.gitted/objects/55/b4e4687e7a0d9ca367016ed930f385d4022e6f new file mode 100644 index 00000000000..fb157a2146d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/55/b4e4687e7a0d9ca367016ed930f385d4022e6f @@ -0,0 +1 @@ +xQj0DSZvJ \N 7㷱d-{LX' vm*{Z`$U9-TN{,}Kyuۣ78A_Sv.EQgSsxZZX MNRi \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/56/6ab53c220a2eafc1212af1a024513230280ab9 b/tests-clar/resources/merge-resolve/.gitted/objects/56/6ab53c220a2eafc1212af1a024513230280ab9 new file mode 100644 index 00000000000..a8855ae6776 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/56/6ab53c220a2eafc1212af1a024513230280ab9 @@ -0,0 +1,3 @@ +x !D +,˱1؁ ,LD bl؁3%Ihft ١XvY`L2М՝܆NsIbRЧL3Ra$Is,S~qh7~QvՃ6!-Zzvȟ3 +:9M& \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/56/a638b76b75e068590ac999c2f8621e7f3e264c b/tests-clar/resources/merge-resolve/.gitted/objects/56/a638b76b75e068590ac999c2f8621e7f3e264c new file mode 100644 index 00000000000..36289bf7afd --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/56/a638b76b75e068590ac999c2f8621e7f3e264c @@ -0,0 +1 @@ +xAj!Eu vuWB6s%6qΐ$^Rb[{=coj'|褯UjeKLnn5СPY|2`zzQ{ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/57/079a46233ae2b6df62e9ade71c4948512abefb b/tests-clar/resources/merge-resolve/.gitted/objects/57/079a46233ae2b6df62e9ade71c4948512abefb new file mode 100644 index 00000000000..c7eabc46b2d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/57/079a46233ae2b6df62e9ade71c4948512abefb differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/58/43febcb23480df0b5edb22a21c59c772bb8e29 b/tests-clar/resources/merge-resolve/.gitted/objects/58/43febcb23480df0b5edb22a21c59c772bb8e29 new file mode 100644 index 00000000000..f6b2a2bfeb4 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/58/43febcb23480df0b5edb22a21c59c772bb8e29 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/58/e853f66699fd02629fd50bde08082bc005933a b/tests-clar/resources/merge-resolve/.gitted/objects/58/e853f66699fd02629fd50bde08082bc005933a new file mode 100644 index 00000000000..cf6db633cb1 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/58/e853f66699fd02629fd50bde08082bc005933a differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/59/6803b523203a4851c824c07366906f8353f4ad b/tests-clar/resources/merge-resolve/.gitted/objects/59/6803b523203a4851c824c07366906f8353f4ad new file mode 100644 index 00000000000..cbc8cbef31c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/59/6803b523203a4851c824c07366906f8353f4ad differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5c/2411f8075f48a6b2fdb85ebc0d371747c4df15 b/tests-clar/resources/merge-resolve/.gitted/objects/5c/2411f8075f48a6b2fdb85ebc0d371747c4df15 new file mode 100644 index 00000000000..7b41413dad7 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/5c/2411f8075f48a6b2fdb85ebc0d371747c4df15 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5c/341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d b/tests-clar/resources/merge-resolve/.gitted/objects/5c/341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d new file mode 100644 index 00000000000..63c86bd3396 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/5c/341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5c/3b68a71fc4fa5d362fd3875e53137c6a5ab7a5 b/tests-clar/resources/merge-resolve/.gitted/objects/5c/3b68a71fc4fa5d362fd3875e53137c6a5ab7a5 new file mode 100644 index 00000000000..541001456c0 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/5c/3b68a71fc4fa5d362fd3875e53137c6a5ab7a5 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5d/c1018e90b19654bee986b7a0c268804d39659d b/tests-clar/resources/merge-resolve/.gitted/objects/5d/c1018e90b19654bee986b7a0c268804d39659d new file mode 100644 index 00000000000..7500b99146b Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/5d/c1018e90b19654bee986b7a0c268804d39659d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5d/dd0fe66f990dc0e5cf9fec6d9b465240e9537f b/tests-clar/resources/merge-resolve/.gitted/objects/5d/dd0fe66f990dc0e5cf9fec6d9b465240e9537f new file mode 100644 index 00000000000..9d8691eb231 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/5d/dd0fe66f990dc0e5cf9fec6d9b465240e9537f differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5e/b7bb6a146eb3c7fd3990b240a2308eceb1cf8d b/tests-clar/resources/merge-resolve/.gitted/objects/5e/b7bb6a146eb3c7fd3990b240a2308eceb1cf8d new file mode 100644 index 00000000000..aca2666cfbb Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/5e/b7bb6a146eb3c7fd3990b240a2308eceb1cf8d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5f/bfbdc04b4eca46f54f4853a3c5a1dce28f5165 b/tests-clar/resources/merge-resolve/.gitted/objects/5f/bfbdc04b4eca46f54f4853a3c5a1dce28f5165 new file mode 100644 index 00000000000..aec3867c8b2 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/5f/bfbdc04b4eca46f54f4853a3c5a1dce28f5165 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/60/91fc2c036a382a69489e3f518ee5aae9a4e567 b/tests-clar/resources/merge-resolve/.gitted/objects/60/91fc2c036a382a69489e3f518ee5aae9a4e567 new file mode 100644 index 00000000000..fa63afba1ca Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/60/91fc2c036a382a69489e3f518ee5aae9a4e567 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/61/340eeed7340fa6a8792def9a5938bb5d4434bb b/tests-clar/resources/merge-resolve/.gitted/objects/61/340eeed7340fa6a8792def9a5938bb5d4434bb new file mode 100644 index 00000000000..e830cafe5ef Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/61/340eeed7340fa6a8792def9a5938bb5d4434bb differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/61/78885b38fe96e825ac0f492c0a941f288b37f6 b/tests-clar/resources/merge-resolve/.gitted/objects/61/78885b38fe96e825ac0f492c0a941f288b37f6 new file mode 100644 index 00000000000..bedc5f27ecd Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/61/78885b38fe96e825ac0f492c0a941f288b37f6 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/62/12c31dab5e482247d7977e4f0dd3601decf13b b/tests-clar/resources/merge-resolve/.gitted/objects/62/12c31dab5e482247d7977e4f0dd3601decf13b new file mode 100644 index 00000000000..b6f0607bb93 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/62/12c31dab5e482247d7977e4f0dd3601decf13b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/62/269111c3b02a9355badcb9da8678b1bf41787b b/tests-clar/resources/merge-resolve/.gitted/objects/62/269111c3b02a9355badcb9da8678b1bf41787b new file mode 100644 index 00000000000..0edf6599447 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/62/269111c3b02a9355badcb9da8678b1bf41787b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/62/c4f6533c9a3894191fdcb96a3be935ade63f1a b/tests-clar/resources/merge-resolve/.gitted/objects/62/c4f6533c9a3894191fdcb96a3be935ade63f1a new file mode 100644 index 00000000000..c0f822d2cef Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/62/c4f6533c9a3894191fdcb96a3be935ade63f1a differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 b/tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 new file mode 100644 index 00000000000..bc2d7384d25 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 @@ -0,0 +1 @@ +xݏ;1 D}AV\8HIVp|?LyOuN7C] ͥlt:iA(xip,O;o7 UYZ Bý]dUmyk[cͥ)!X{Z \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 b/tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 new file mode 100644 index 00000000000..ffda698f046 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 @@ -0,0 +1 @@ +xM1 DNi`ǹDB~ǧ]ݠY74M8J?$_k[Q,"Zz˟39 LO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/76/63fce0130db092936b137cabd693ec234eb060 b/tests-clar/resources/merge-resolve/.gitted/objects/76/63fce0130db092936b137cabd693ec234eb060 new file mode 100644 index 00000000000..f578a4a680a Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/76/63fce0130db092936b137cabd693ec234eb060 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/76/ab0e2868197ec158ddd6c78d8a0d2fd73d38f9 b/tests-clar/resources/merge-resolve/.gitted/objects/76/ab0e2868197ec158ddd6c78d8a0d2fd73d38f9 new file mode 100644 index 00000000000..4d41ad8cd04 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/76/ab0e2868197ec158ddd6c78d8a0d2fd73d38f9 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/7a/a3edf2bcfee22398e6b55295aa56366b7aaf76 b/tests-clar/resources/merge-resolve/.gitted/objects/7a/a3edf2bcfee22398e6b55295aa56366b7aaf76 new file mode 100644 index 00000000000..09f1e4d3a78 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/7a/a3edf2bcfee22398e6b55295aa56366b7aaf76 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/7c/2c5228c9e90170d4a35e6558e47163daf092e5 b/tests-clar/resources/merge-resolve/.gitted/objects/7c/2c5228c9e90170d4a35e6558e47163daf092e5 new file mode 100644 index 00000000000..52fde92a141 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/7c/2c5228c9e90170d4a35e6558e47163daf092e5 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/7c/b63eed597130ba4abb87b3e544b85021905520 b/tests-clar/resources/merge-resolve/.gitted/objects/7c/b63eed597130ba4abb87b3e544b85021905520 new file mode 100644 index 00000000000..769f29c6e05 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/7c/b63eed597130ba4abb87b3e544b85021905520 @@ -0,0 +1,3 @@ +xK +1D]t'"nH:L$FxwUAQܖ6f7IT*zJ +1#;@rX]ꞺC3A F'aj#Tf acn]_+s[mG'+~m9i PFCQge"N \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/7e/2d058d5fedf8329db44db4fac610d6b1a89159 b/tests-clar/resources/merge-resolve/.gitted/objects/7e/2d058d5fedf8329db44db4fac610d6b1a89159 new file mode 100644 index 00000000000..d12d7b4a712 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/7e/2d058d5fedf8329db44db4fac610d6b1a89159 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/7f/7a2da58126226986d71c6ddfab4afba693280d b/tests-clar/resources/merge-resolve/.gitted/objects/7f/7a2da58126226986d71c6ddfab4afba693280d new file mode 100644 index 00000000000..2f833c2924a Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/7f/7a2da58126226986d71c6ddfab4afba693280d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/80/a8fbb3abb1ba423d554e9630b8fc2e5698f86b b/tests-clar/resources/merge-resolve/.gitted/objects/80/a8fbb3abb1ba423d554e9630b8fc2e5698f86b new file mode 100644 index 00000000000..3daf6c3e077 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/80/a8fbb3abb1ba423d554e9630b8fc2e5698f86b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/81/87117062b750eed4f93fd7e899f17b52ce554d b/tests-clar/resources/merge-resolve/.gitted/objects/81/87117062b750eed4f93fd7e899f17b52ce554d new file mode 100644 index 00000000000..19cac9faf4a Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/81/87117062b750eed4f93fd7e899f17b52ce554d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/83/07d93a155903a5c49576583f0ce1f6ff897c0e b/tests-clar/resources/merge-resolve/.gitted/objects/83/07d93a155903a5c49576583f0ce1f6ff897c0e new file mode 100644 index 00000000000..5a96a4e4e3c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/83/07d93a155903a5c49576583f0ce1f6ff897c0e differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/83/824a8c6658768e2013905219cc8c64cc3d9a2e b/tests-clar/resources/merge-resolve/.gitted/objects/83/824a8c6658768e2013905219cc8c64cc3d9a2e new file mode 100644 index 00000000000..066190fb8cb Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/83/824a8c6658768e2013905219cc8c64cc3d9a2e differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 b/tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 new file mode 100644 index 00000000000..67271ac5095 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 @@ -0,0 +1,3 @@ +xK +1D]v7t3L$ UEVZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^j9!Ɖ9%`<sBާHrS3d Ң2 wI{| 2mg˾15ӿ,\})TC)00avʉz֛9MՅ'6bG \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8b/095d8fd01594f4d14454d073e3ac57b9ce485f b/tests-clar/resources/merge-resolve/.gitted/objects/8b/095d8fd01594f4d14454d073e3ac57b9ce485f new file mode 100644 index 00000000000..4ec01388168 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/8b/095d8fd01594f4d14454d073e3ac57b9ce485f differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a b/tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a new file mode 100644 index 00000000000..f4249c23df4 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a @@ -0,0 +1 @@ +x퐱 0 S{"2d,0^?&SH[8눪E`фrZ*drl, cbF/'gв \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 b/tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 new file mode 100644 index 00000000000..e42393cf71e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 @@ -0,0 +1,2 @@ +xAB!C]s +.acxf`|_ bh5m^mzL`}$26#"8`s.`ԝܺ.!bH\< i",K8ٗ_X>MeЏ:7]AC40뭙Q]Q\.,VO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8f/4433f8593ddd65b7dd43dd4564d841f4d9c8aa b/tests-clar/resources/merge-resolve/.gitted/objects/8f/4433f8593ddd65b7dd43dd4564d841f4d9c8aa new file mode 100644 index 00000000000..d2de777ccde Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/8f/4433f8593ddd65b7dd43dd4564d841f4d9c8aa differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/90/a336c7dacbe295159413559b0043b8bdc60d57 b/tests-clar/resources/merge-resolve/.gitted/objects/90/a336c7dacbe295159413559b0043b8bdc60d57 new file mode 100644 index 00000000000..35453ebfd5d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/90/a336c7dacbe295159413559b0043b8bdc60d57 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/91/2b2d7819cf9c1029e414883857ed61d597a1a5 b/tests-clar/resources/merge-resolve/.gitted/objects/91/2b2d7819cf9c1029e414883857ed61d597a1a5 new file mode 100644 index 00000000000..d5df393e9db Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/91/2b2d7819cf9c1029e414883857ed61d597a1a5 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/91/8bb3e09090a9995d48af9a2a6296d7e6088d1c b/tests-clar/resources/merge-resolve/.gitted/objects/91/8bb3e09090a9995d48af9a2a6296d7e6088d1c new file mode 100644 index 00000000000..c214ab20634 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/91/8bb3e09090a9995d48af9a2a6296d7e6088d1c differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/92/7d4943cdbdc9a667db8e62cfd0a41870235c51 b/tests-clar/resources/merge-resolve/.gitted/objects/92/7d4943cdbdc9a667db8e62cfd0a41870235c51 new file mode 100644 index 00000000000..b6b92c84241 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/92/7d4943cdbdc9a667db8e62cfd0a41870235c51 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/93/77fccdb210540b8c0520cc6e80eb632c20bd25 b/tests-clar/resources/merge-resolve/.gitted/objects/93/77fccdb210540b8c0520cc6e80eb632c20bd25 new file mode 100644 index 00000000000..4b2d93b07de Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/93/77fccdb210540b8c0520cc6e80eb632c20bd25 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/94/4f5dd1a867cab4c2bbcb896493435cae1dcc1a b/tests-clar/resources/merge-resolve/.gitted/objects/94/4f5dd1a867cab4c2bbcb896493435cae1dcc1a new file mode 100644 index 00000000000..14309383131 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/94/4f5dd1a867cab4c2bbcb896493435cae1dcc1a @@ -0,0 +1,2 @@ +xK!D]s +.z7 |2. bhWKVmH0~7z"P9`:Qi)QLEyq=oC*P6-"4l0StAHZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^jnb^nJfZZjQj^ X#3|>^U:'A2R2 I{| 2mg˾15ӿ,\})TC)0H!vʉz֛9MՅ'6bGx \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 b/tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 new file mode 100644 index 00000000000..91113ee8e52 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 @@ -0,0 +1,2 @@ +xK +1D]};7d=oo^UQT\;hk6@g 5rѓ]uOMndgz&c圈'} NJ7p?(G\8CآGTg9x$faxN" \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ab/40af3cb8a3ed2e2843e96d9aa7871336b94573 b/tests-clar/resources/merge-resolve/.gitted/objects/ab/40af3cb8a3ed2e2843e96d9aa7871336b94573 new file mode 100644 index 00000000000..7da1da656f6 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ab/40af3cb8a3ed2e2843e96d9aa7871336b94573 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ab/6c44a2e84492ad4b41bb6bac87353e9d02ac8b b/tests-clar/resources/merge-resolve/.gitted/objects/ab/6c44a2e84492ad4b41bb6bac87353e9d02ac8b new file mode 100644 index 00000000000..d840c1a573d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ab/6c44a2e84492ad4b41bb6bac87353e9d02ac8b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ab/929391ac42572f92110f3deeb4f0844a951e22 b/tests-clar/resources/merge-resolve/.gitted/objects/ab/929391ac42572f92110f3deeb4f0844a951e22 new file mode 100644 index 00000000000..8840d00c5d8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ab/929391ac42572f92110f3deeb4f0844a951e22 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ac/4045f965119e6998f4340ed0f411decfb3ec05 b/tests-clar/resources/merge-resolve/.gitted/objects/ac/4045f965119e6998f4340ed0f411decfb3ec05 new file mode 100644 index 00000000000..4c32d63f82c Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ac/4045f965119e6998f4340ed0f411decfb3ec05 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ad/a14492498136771f69dd451866cabcb0e9ef9a b/tests-clar/resources/merge-resolve/.gitted/objects/ad/a14492498136771f69dd451866cabcb0e9ef9a new file mode 100644 index 00000000000..71023de3902 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ad/a14492498136771f69dd451866cabcb0e9ef9a differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 b/tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 new file mode 100644 index 00000000000..3091b8f3d87 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 @@ -0,0 +1 @@ +x+)JMU067d040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5`nלU7 V.6t6L/R2 I{| 2mg˾15ӿ,\})TC)0<vʉz֛9MՅ'6bN* \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 b/tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 new file mode 100644 index 00000000000..20fa838f203 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 @@ -0,0 +1,2 @@ +xQA1+xċϡ-kI*5f/z af!^/WJcܤ5Lƛ;+B6HZP|`h>\($sX@75}57K ++= ;g @!4!,\$\ \b/Hs#aQ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 b/tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 new file mode 100644 index 00000000000..2820b46ccc1 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 @@ -0,0 +1,5 @@ +xA + {B{M1 ߯>P3F֎7E02 X0̒,)$;:ܷ(: \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b6/f610aef53bd343e6c96227de874c66f00ee8e8 b/tests-clar/resources/merge-resolve/.gitted/objects/b6/f610aef53bd343e6c96227de874c66f00ee8e8 new file mode 100644 index 00000000000..fb102f15dc5 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/b6/f610aef53bd343e6c96227de874c66f00ee8e8 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b7/a2576f9fc20024ac9ef17cb134acbd1ac73127 b/tests-clar/resources/merge-resolve/.gitted/objects/b7/a2576f9fc20024ac9ef17cb134acbd1ac73127 new file mode 100644 index 00000000000..22f2d137d4d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/b7/a2576f9fc20024ac9ef17cb134acbd1ac73127 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b8/a3a806d3950e8c0a03a34f234a92eff0e2c68d b/tests-clar/resources/merge-resolve/.gitted/objects/b8/a3a806d3950e8c0a03a34f234a92eff0e2c68d new file mode 100644 index 00000000000..24f029900e8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/b8/a3a806d3950e8c0a03a34f234a92eff0e2c68d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ba/cac9b3493509aa15e1730e1545fc0919d1dae0 b/tests-clar/resources/merge-resolve/.gitted/objects/ba/cac9b3493509aa15e1730e1545fc0919d1dae0 new file mode 100644 index 00000000000..f35586f7f8f Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ba/cac9b3493509aa15e1730e1545fc0919d1dae0 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/bc/744705e1d8a019993cf88f62bc4020f1b80919 b/tests-clar/resources/merge-resolve/.gitted/objects/bc/744705e1d8a019993cf88f62bc4020f1b80919 new file mode 100644 index 00000000000..0d4bdb3237a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/bc/744705e1d8a019993cf88f62bc4020f1b80919 @@ -0,0 +1,2 @@ +xK +1D]}%%tYH& UJuj7:P(#F̄ģ1+k#vΚS8W|٨%Kpɯ3\Vv#MQg?wH@(c s9t 嶭{kO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/bc/95c75d59386147d1e79a87c33068d8dbfd71f2 b/tests-clar/resources/merge-resolve/.gitted/objects/bc/95c75d59386147d1e79a87c33068d8dbfd71f2 new file mode 100644 index 00000000000..436d5a076a4 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/bc/95c75d59386147d1e79a87c33068d8dbfd71f2 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/bd/593285fc7fe4ca18ccdbabf027f5d689101452 b/tests-clar/resources/merge-resolve/.gitted/objects/bd/593285fc7fe4ca18ccdbabf027f5d689101452 new file mode 100644 index 00000000000..75ab1f0f3f1 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/bd/593285fc7fe4ca18ccdbabf027f5d689101452 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/bd/867fbae2faa80b920b002b80b1c91bcade7784 b/tests-clar/resources/merge-resolve/.gitted/objects/bd/867fbae2faa80b920b002b80b1c91bcade7784 new file mode 100644 index 00000000000..0f7421963a2 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/bd/867fbae2faa80b920b002b80b1c91bcade7784 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/bd/9cb4cd0a770cb9adcb5fce212142ef40ea1c35 b/tests-clar/resources/merge-resolve/.gitted/objects/bd/9cb4cd0a770cb9adcb5fce212142ef40ea1c35 new file mode 100644 index 00000000000..2aafdc64f06 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/bd/9cb4cd0a770cb9adcb5fce212142ef40ea1c35 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/be/f6e37b3ee632ba74159168836f382fed21d77d b/tests-clar/resources/merge-resolve/.gitted/objects/be/f6e37b3ee632ba74159168836f382fed21d77d new file mode 100644 index 00000000000..6c243150dc2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/be/f6e37b3ee632ba74159168836f382fed21d77d @@ -0,0 +1,2 @@ +xK +1D]}3?Ač7p?$=`Ґx}Gރ`)+0ѮUh.NWޓ!Idlj-f 9UV61:̸ !>Z.P0x hhQ+t`1NZe,X[ =vyI_vJ^2$?I7o4{K>V!~|U= \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c5/bbe550b9f09444bdddd3ecf3d97c0b42aa786c b/tests-clar/resources/merge-resolve/.gitted/objects/c5/bbe550b9f09444bdddd3ecf3d97c0b42aa786c new file mode 100644 index 00000000000..2f2ada732bb Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/c5/bbe550b9f09444bdddd3ecf3d97c0b42aa786c differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c6/07fc30883e335def28cd686b51f6cfa02b06ec b/tests-clar/resources/merge-resolve/.gitted/objects/c6/07fc30883e335def28cd686b51f6cfa02b06ec new file mode 100644 index 00000000000..475b87ef9bc --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/c6/07fc30883e335def28cd686b51f6cfa02b06ec @@ -0,0 +1,2 @@ +xQ +1 D)r%n "x/m[[oo{0k)iכ*`ZavJ>,af<EZȳ5%<'.v,;]=2tws-,w8@ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c6/92ecf62007c0ac9fb26e2aa884de2933de15ed b/tests-clar/resources/merge-resolve/.gitted/objects/c6/92ecf62007c0ac9fb26e2aa884de2933de15ed new file mode 100644 index 00000000000..ae430bd4afb Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/c6/92ecf62007c0ac9fb26e2aa884de2933de15ed differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c8/f06f2e3bb2964174677e91f0abead0e43c9e5d b/tests-clar/resources/merge-resolve/.gitted/objects/c8/f06f2e3bb2964174677e91f0abead0e43c9e5d new file mode 100644 index 00000000000..5dae4c3acfa Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/c8/f06f2e3bb2964174677e91f0abead0e43c9e5d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb b/tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb new file mode 100644 index 00000000000..da8dba2445f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb @@ -0,0 +1,2 @@ +xQ +0D)rfnSxfCHx}xfc,˵Y kUb8pu`%|@r3GtB;W]!z'%QiӐdT ?\=d/sYe';^r#l`6m Z7U^e6oVO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c9/4b27e41064c521120627e07e2035cca1d24ffa b/tests-clar/resources/merge-resolve/.gitted/objects/c9/4b27e41064c521120627e07e2035cca1d24ffa new file mode 100644 index 00000000000..fd1ec9fab86 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/c9/4b27e41064c521120627e07e2035cca1d24ffa differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ca/b2cf23998b40f1af2d9d9a756dc9e285a8df4b b/tests-clar/resources/merge-resolve/.gitted/objects/ca/b2cf23998b40f1af2d9d9a756dc9e285a8df4b new file mode 100644 index 00000000000..32ba2aa53a6 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ca/b2cf23998b40f1af2d9d9a756dc9e285a8df4b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/cb/491780d82e46dc88a065b965ab307a038f2bc2 b/tests-clar/resources/merge-resolve/.gitted/objects/cb/491780d82e46dc88a065b965ab307a038f2bc2 new file mode 100644 index 00000000000..cf9cd7d3992 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/cb/491780d82e46dc88a065b965ab307a038f2bc2 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/cb/6693a788715b82440a54e0eacd19ba9f6ec559 b/tests-clar/resources/merge-resolve/.gitted/objects/cb/6693a788715b82440a54e0eacd19ba9f6ec559 new file mode 100644 index 00000000000..e11181a967f Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/cb/6693a788715b82440a54e0eacd19ba9f6ec559 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f b/tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f new file mode 100644 index 00000000000..9a0cb7a0c92 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f @@ -0,0 +1,2 @@ +x] +0})&_H -Fb[6}0L2wPzc*sXb Rt#G$[lvH$kf.ʧLF+ QHD|68Wl.S]uoNOu9Va0^ZF9^# Od \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ce/8860d49e3bea6fd745874a01b7c3e46da8cbc3 b/tests-clar/resources/merge-resolve/.gitted/objects/ce/8860d49e3bea6fd745874a01b7c3e46da8cbc3 new file mode 100644 index 00000000000..860f9952f11 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ce/8860d49e3bea6fd745874a01b7c3e46da8cbc3 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ce/e656c392ad0557b3aae0fb411475c206e2926f b/tests-clar/resources/merge-resolve/.gitted/objects/ce/e656c392ad0557b3aae0fb411475c206e2926f new file mode 100644 index 00000000000..ff0624ccb07 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ce/e656c392ad0557b3aae0fb411475c206e2926f differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/cf/8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d b/tests-clar/resources/merge-resolve/.gitted/objects/cf/8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d new file mode 100644 index 00000000000..36b0289e6f3 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/cf/8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d0/7ec190c306ec690bac349e87d01c4358e49bb2 b/tests-clar/resources/merge-resolve/.gitted/objects/d0/7ec190c306ec690bac349e87d01c4358e49bb2 new file mode 100644 index 00000000000..d52a56ffed5 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/d0/7ec190c306ec690bac349e87d01c4358e49bb2 @@ -0,0 +1,2 @@ +xՏ 0 3aOb%ǑS=HT@u:]uYG%LE;u`_?g~0Ҕ. +׋PӜxvXi ӭf! \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d0/d4594e16f2e19107e3fa7ea63e7aaaff305ffb b/tests-clar/resources/merge-resolve/.gitted/objects/d0/d4594e16f2e19107e3fa7ea63e7aaaff305ffb new file mode 100644 index 00000000000..5f7e286ff81 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d0/d4594e16f2e19107e3fa7ea63e7aaaff305ffb differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d2/f8637f2eab2507a1e13cbc9df4729ec386627e b/tests-clar/resources/merge-resolve/.gitted/objects/d2/f8637f2eab2507a1e13cbc9df4729ec386627e new file mode 100644 index 00000000000..558a8513fd0 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d2/f8637f2eab2507a1e13cbc9df4729ec386627e differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d3/719a5ae8e4d92276b5313ce976f6ee5af2b436 b/tests-clar/resources/merge-resolve/.gitted/objects/d3/719a5ae8e4d92276b5313ce976f6ee5af2b436 new file mode 100644 index 00000000000..930bf5a5e64 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/d3/719a5ae8e4d92276b5313ce976f6ee5af2b436 @@ -0,0 +1,2 @@ +x=10 E}uAHب zRHPT Brh/]?a 48,_MdkуTPF!TZQ? +R֧FN_J͆ h{(kLKV1p+Q A \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d3/7aa3bbfe1c0c49b909781251b956dbabe85f96 b/tests-clar/resources/merge-resolve/.gitted/objects/d3/7aa3bbfe1c0c49b909781251b956dbabe85f96 new file mode 100644 index 00000000000..5902e0f329b Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d3/7aa3bbfe1c0c49b909781251b956dbabe85f96 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d3/7ad72a2052685fc6201c2af90103ad42d2079b b/tests-clar/resources/merge-resolve/.gitted/objects/d3/7ad72a2052685fc6201c2af90103ad42d2079b new file mode 100644 index 00000000000..b2f39bff413 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d3/7ad72a2052685fc6201c2af90103ad42d2079b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d4/207f77243500bec335ab477f9227fcdb1e271a b/tests-clar/resources/merge-resolve/.gitted/objects/d4/207f77243500bec335ab477f9227fcdb1e271a new file mode 100644 index 00000000000..862e4e5bce2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/d4/207f77243500bec335ab477f9227fcdb1e271a @@ -0,0 +1,2 @@ +xK +1D]O'7t:݌H&z:]oZBBXl(昭+d<"6^% A( J,% %5SSmR^؊Nu^뢏O:Wځ| DcFQEn6#Q \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d4/27e0b2e138501a3d15cc376077a3631e15bd46 b/tests-clar/resources/merge-resolve/.gitted/objects/d4/27e0b2e138501a3d15cc376077a3631e15bd46 new file mode 100644 index 00000000000..0b3611ae4c9 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d4/27e0b2e138501a3d15cc376077a3631e15bd46 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d5/093787ef302b941b6aab081b99fb4880038bd8 b/tests-clar/resources/merge-resolve/.gitted/objects/d5/093787ef302b941b6aab081b99fb4880038bd8 new file mode 100644 index 00000000000..7d73449eb3b Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d5/093787ef302b941b6aab081b99fb4880038bd8 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d5/a61b0b4992a4f0caa887fa08b52431e727bb6f b/tests-clar/resources/merge-resolve/.gitted/objects/d5/a61b0b4992a4f0caa887fa08b52431e727bb6f new file mode 100644 index 00000000000..a7921de43c8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d5/a61b0b4992a4f0caa887fa08b52431e727bb6f differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d5/b6fc965c926a1bfc9ee456042b94088b5c5d21 b/tests-clar/resources/merge-resolve/.gitted/objects/d5/b6fc965c926a1bfc9ee456042b94088b5c5d21 new file mode 100644 index 00000000000..924bdbbb585 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d5/b6fc965c926a1bfc9ee456042b94088b5c5d21 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d5/ec1152fe25e9fec00189eb00b3db71db24c218 b/tests-clar/resources/merge-resolve/.gitted/objects/d5/ec1152fe25e9fec00189eb00b3db71db24c218 new file mode 100644 index 00000000000..0d2534bc9be Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d5/ec1152fe25e9fec00189eb00b3db71db24c218 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d6/42b9770c66bba94a08df09b5efb095001f76d7 b/tests-clar/resources/merge-resolve/.gitted/objects/d6/42b9770c66bba94a08df09b5efb095001f76d7 new file mode 100644 index 00000000000..1671f9f2c09 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d6/42b9770c66bba94a08df09b5efb095001f76d7 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d6/462fa3f5292857db599c54aea2bf91616230c5 b/tests-clar/resources/merge-resolve/.gitted/objects/d6/462fa3f5292857db599c54aea2bf91616230c5 new file mode 100644 index 00000000000..baae3f0e012 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d6/462fa3f5292857db599c54aea2bf91616230c5 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 b/tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 new file mode 100644 index 00000000000..8f9ae1fc64f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 @@ -0,0 +1,2 @@ +xQ +1 D)r%i@oje[7̤ZʽMSLBNlm B~>-uY8ꠟt֯]Qa͠3f]>bl(A] \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d8/74671ef5b20184836cb983bb273e5280384d0b b/tests-clar/resources/merge-resolve/.gitted/objects/d8/74671ef5b20184836cb983bb273e5280384d0b new file mode 100644 index 00000000000..1d8037895d1 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d8/74671ef5b20184836cb983bb273e5280384d0b differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d8/fa77b6833082c1ea36b7828a582d4c43882450 b/tests-clar/resources/merge-resolve/.gitted/objects/d8/fa77b6833082c1ea36b7828a582d4c43882450 new file mode 100644 index 00000000000..988145322ec --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/d8/fa77b6833082c1ea36b7828a582d4c43882450 @@ -0,0 +1 @@ +x1 DQkN1&6%lBknaa1kdI(Ur'7LA,+Wm9 I'U͹_ܰN \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d9/63979c237d08b6ba39062ee7bf64c7d34a27f8 b/tests-clar/resources/merge-resolve/.gitted/objects/d9/63979c237d08b6ba39062ee7bf64c7d34a27f8 new file mode 100644 index 00000000000..5fa10405ced Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/d9/63979c237d08b6ba39062ee7bf64c7d34a27f8 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/da/178208145ef585a1bd5ca5f4c9785d738df2cf b/tests-clar/resources/merge-resolve/.gitted/objects/da/178208145ef585a1bd5ca5f4c9785d738df2cf new file mode 100644 index 00000000000..6292118e044 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/da/178208145ef585a1bd5ca5f4c9785d738df2cf differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/db/6261a7c65c7fd678520c9bb6f2c47582ab9ed5 b/tests-clar/resources/merge-resolve/.gitted/objects/db/6261a7c65c7fd678520c9bb6f2c47582ab9ed5 new file mode 100644 index 00000000000..b82e7fcafe9 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/db/6261a7c65c7fd678520c9bb6f2c47582ab9ed5 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/dd/9a570c3400e6e07bc4d7651d6e20b08926b3d9 b/tests-clar/resources/merge-resolve/.gitted/objects/dd/9a570c3400e6e07bc4d7651d6e20b08926b3d9 new file mode 100644 index 00000000000..8fd60cbe8f3 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/dd/9a570c3400e6e07bc4d7651d6e20b08926b3d9 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 b/tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 new file mode 100644 index 00000000000..04dda4a758f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 @@ -0,0 +1 @@ +x퐱 S3ŏlKAB4Wb T5:8Sc ԻP`KIˆO3Z&ؐ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/df/e3f22baa1f6fce5447901c3086bae368de6bdd b/tests-clar/resources/merge-resolve/.gitted/objects/df/e3f22baa1f6fce5447901c3086bae368de6bdd new file mode 100644 index 00000000000..e135694400e Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/df/e3f22baa1f6fce5447901c3086bae368de6bdd differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e0/67f9361140f19391472df8a82d6610813c73b7 b/tests-clar/resources/merge-resolve/.gitted/objects/e0/67f9361140f19391472df8a82d6610813c73b7 new file mode 100644 index 00000000000..955431dd7f8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/e0/67f9361140f19391472df8a82d6610813c73b7 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e1/129b3cfb5898e0fbd606e0cb80b2755e50d161 b/tests-clar/resources/merge-resolve/.gitted/objects/e1/129b3cfb5898e0fbd606e0cb80b2755e50d161 new file mode 100644 index 00000000000..751f1dd3339 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/e1/129b3cfb5898e0fbd606e0cb80b2755e50d161 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e1/7ace1492648c9dc5701bad5c47af9d1b60c4e9 b/tests-clar/resources/merge-resolve/.gitted/objects/e1/7ace1492648c9dc5701bad5c47af9d1b60c4e9 new file mode 100644 index 00000000000..4a812e5dfa8 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/e1/7ace1492648c9dc5701bad5c47af9d1b60c4e9 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 b/tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 new file mode 100644 index 00000000000..7b84ce966db --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 @@ -0,0 +1 @@ +x+)JMU067f040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5%\N,5[e2 I{| 2mg˾15ӿ,\})TC)0Dvz֛9MՅ'6b \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e3/1e7ad3ed298f24e383c4950f4671993ec078e4 b/tests-clar/resources/merge-resolve/.gitted/objects/e3/1e7ad3ed298f24e383c4950f4671993ec078e4 new file mode 100644 index 00000000000..a28ded3fba1 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/e3/1e7ad3ed298f24e383c4950f4671993ec078e4 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e b/tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e new file mode 100644 index 00000000000..8da234114d7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e @@ -0,0 +1,3 @@ +xA@E]s +`@ uH)M=Scz:ʊ(N+6ޛDFe𭭘Yg$+G&F +pG 4mQ\85#FC~QERu);c6'j \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e4/9f917b448d1340b31d76e54ba388268fd4c922 b/tests-clar/resources/merge-resolve/.gitted/objects/e4/9f917b448d1340b31d76e54ba388268fd4c922 new file mode 100644 index 00000000000..870c3e73212 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/e4/9f917b448d1340b31d76e54ba388268fd4c922 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e4/f618a2c3ed0669308735727df5ebf2447f022f b/tests-clar/resources/merge-resolve/.gitted/objects/e4/f618a2c3ed0669308735727df5ebf2447f022f new file mode 100644 index 00000000000..c7e1ee9d7f1 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/e4/f618a2c3ed0669308735727df5ebf2447f022f @@ -0,0 +1,2 @@ +xK!D]s +.iOboi2. bhJQ6b`7:DN.%4uIQYcm`Q¨ aQYa@>ɗEc9%bhf1x}xwUQv kv@`O;$Kșybh2癈sLA ?R\˷ץ(~Yïb-'Yǎp=Njq˟m[zO+ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fa/c03f2c5139618d87d53614c153823bf1f31396 b/tests-clar/resources/merge-resolve/.gitted/objects/fa/c03f2c5139618d87d53614c153823bf1f31396 new file mode 100644 index 00000000000..30e07e5b719 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fa/c03f2c5139618d87d53614c153823bf1f31396 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fa/da9356aa3f74622327a3038ae9c6f92e1c5c1d b/tests-clar/resources/merge-resolve/.gitted/objects/fa/da9356aa3f74622327a3038ae9c6f92e1c5c1d new file mode 100644 index 00000000000..16ce49a1bcb Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fa/da9356aa3f74622327a3038ae9c6f92e1c5c1d differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fb/738a106cfd097a4acb96ce132ecb1ad6c46b03 b/tests-clar/resources/merge-resolve/.gitted/objects/fb/738a106cfd097a4acb96ce132ecb1ad6c46b03 new file mode 100644 index 00000000000..4f1e7268818 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fb/738a106cfd097a4acb96ce132ecb1ad6c46b03 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fc/4c636d6515e9e261f9260dbcf3cc6eca97ea08 b/tests-clar/resources/merge-resolve/.gitted/objects/fc/4c636d6515e9e261f9260dbcf3cc6eca97ea08 new file mode 100644 index 00000000000..be8a810cd86 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fc/4c636d6515e9e261f9260dbcf3cc6eca97ea08 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fc/7d7b805f7a9428574f4f802b2e34cd20ab9d99 b/tests-clar/resources/merge-resolve/.gitted/objects/fc/7d7b805f7a9428574f4f802b2e34cd20ab9d99 new file mode 100644 index 00000000000..20493e68cb7 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fc/7d7b805f7a9428574f4f802b2e34cd20ab9d99 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fc/90237dc4891fa6c69827fc465632225e391618 b/tests-clar/resources/merge-resolve/.gitted/objects/fc/90237dc4891fa6c69827fc465632225e391618 new file mode 100644 index 00000000000..961814baebd Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fc/90237dc4891fa6c69827fc465632225e391618 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fd/57d2d6770fad8e9959124793a17f441b571e66 b/tests-clar/resources/merge-resolve/.gitted/objects/fd/57d2d6770fad8e9959124793a17f441b571e66 new file mode 100644 index 00000000000..21e6b2c558d Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fd/57d2d6770fad8e9959124793a17f441b571e66 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a b/tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a new file mode 100644 index 00000000000..2f9d83b2610 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a @@ -0,0 +1,2 @@ +xK!D]s +.{`cx/ɸ`0 oURy|Y`dPA!4C2d=x#e`BgrubLffG@՗-}KԲUy=];)r0 R$(%o=׶OPw \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fe/5407fc50a53aecb41d1a6e9ea7b612e581af87 b/tests-clar/resources/merge-resolve/.gitted/objects/fe/5407fc50a53aecb41d1a6e9ea7b612e581af87 new file mode 100644 index 00000000000..4ce7d2297be Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/fe/5407fc50a53aecb41d1a6e9ea7b612e581af87 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ff/49d07869831ad761bbdaea026086f8789bcb00 b/tests-clar/resources/merge-resolve/.gitted/objects/ff/49d07869831ad761bbdaea026086f8789bcb00 new file mode 100644 index 00000000000..eada39b77e4 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ff/49d07869831ad761bbdaea026086f8789bcb00 differ diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ff/b312248d607284c290023f9502eea010d34efd b/tests-clar/resources/merge-resolve/.gitted/objects/ff/b312248d607284c290023f9502eea010d34efd new file mode 100644 index 00000000000..7e46c4fe304 Binary files /dev/null and b/tests-clar/resources/merge-resolve/.gitted/objects/ff/b312248d607284c290023f9502eea010d34efd differ diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/branch new file mode 100644 index 00000000000..03f79a3dcfd --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/branch @@ -0,0 +1 @@ +7cb63eed597130ba4abb87b3e544b85021905520 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_ancestor b/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_ancestor new file mode 100644 index 00000000000..4bc37ac6063 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_ancestor @@ -0,0 +1 @@ +2da538570bc1e5b2c3e855bf702f35248ad0735f diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side1 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side1 new file mode 100644 index 00000000000..ca6dd679d02 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side1 @@ -0,0 +1 @@ +a7dbfcbfc1a60709cb80b5ca24539008456531d0 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side2 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side2 new file mode 100644 index 00000000000..b8160f80eb6 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side2 @@ -0,0 +1 @@ +fc90237dc4891fa6c69827fc465632225e391618 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/ff_branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/ff_branch new file mode 100644 index 00000000000..e9e90512f9d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/ff_branch @@ -0,0 +1 @@ +fd89f8cffb663ac89095a0f9764902e93ceaca6a diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/master b/tests-clar/resources/merge-resolve/.gitted/refs/heads/master new file mode 100644 index 00000000000..8a329ae5f7c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/master @@ -0,0 +1 @@ +bd593285fc7fe4ca18ccdbabf027f5d689101452 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo1 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo1 new file mode 100644 index 00000000000..4d2c669023e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo1 @@ -0,0 +1 @@ +16f825815cfd20a07a75c71554e82d8eede0b061 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo2 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo2 new file mode 100644 index 00000000000..f503977a733 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo2 @@ -0,0 +1 @@ +158dc7bedb202f5b26502bf3574faa7f4238d56c diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo3 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo3 new file mode 100644 index 00000000000..b92994f1007 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo3 @@ -0,0 +1 @@ +50ce7d7d01217679e26c55939eef119e0c93e272 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo4 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo4 new file mode 100644 index 00000000000..f33d57cbcbe --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo4 @@ -0,0 +1 @@ +54269b3f6ec3d7d4ede24dd350dd5d605495c3ae diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo5 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo5 new file mode 100644 index 00000000000..e9f943385b5 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo5 @@ -0,0 +1 @@ +e4f618a2c3ed0669308735727df5ebf2447f022f diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo6 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo6 new file mode 100644 index 00000000000..4c5a98ad9c5 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/octo6 @@ -0,0 +1 @@ +b6f610aef53bd343e6c96227de874c66f00ee8e8 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ancestor b/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ancestor new file mode 100644 index 00000000000..4092d428f13 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ancestor @@ -0,0 +1 @@ +2392a2dacc9efb562b8635d6579fb458751c7c5b diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ours b/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ours new file mode 100644 index 00000000000..a1c50dce8d7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ours @@ -0,0 +1 @@ +34bfafff88eaf118402b44e6f3e2dbbf1a582b05 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_theirs b/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_theirs new file mode 100644 index 00000000000..130989399e2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_theirs @@ -0,0 +1 @@ +a802e06f1782a9645b9851bc7202cee74a8a4972 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames1 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames1 new file mode 100644 index 00000000000..3d248102c3e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames1 @@ -0,0 +1 @@ +412b32fb66137366147f1801ecc962452757d48a diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames2 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames2 new file mode 100644 index 00000000000..d22621561bd --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/renames2 @@ -0,0 +1 @@ +ab40af3cb8a3ed2e2843e96d9aa7871336b94573 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10 new file mode 100644 index 00000000000..5b378cd88d7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10 @@ -0,0 +1 @@ +0ec5f433959cd46177f745903353efb5be08d151 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10-branch new file mode 100644 index 00000000000..b3db6c89273 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10-branch @@ -0,0 +1 @@ +11f4f3c08b737f5fd896cbefa1425ee63b21b2fa diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11 new file mode 100644 index 00000000000..154de9a641f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11 @@ -0,0 +1 @@ +3168dca1a561889b045a6441909f4c56145e666d diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11-branch new file mode 100644 index 00000000000..2e411802928 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11-branch @@ -0,0 +1 @@ +6718a45909532d1fcf5600d0877f7fe7e78f0b86 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13 new file mode 100644 index 00000000000..297573a5766 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13 @@ -0,0 +1 @@ +a3fabece9eb8748da810e1e08266fef9b7136ad4 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13-branch new file mode 100644 index 00000000000..22e429a616e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13-branch @@ -0,0 +1 @@ +05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14 new file mode 100644 index 00000000000..89051853ae9 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14 @@ -0,0 +1 @@ +7e2d058d5fedf8329db44db4fac610d6b1a89159 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14-branch new file mode 100644 index 00000000000..0158f950c3a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14-branch @@ -0,0 +1 @@ +8187117062b750eed4f93fd7e899f17b52ce554d diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt new file mode 100644 index 00000000000..474074120ca --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt @@ -0,0 +1 @@ +566ab53c220a2eafc1212af1a024513230280ab9 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt-branch new file mode 100644 index 00000000000..2f5f1a4af08 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt-branch @@ -0,0 +1 @@ +c9174cef549ec94ecbc43ef03cdc775b4950becb diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt new file mode 100644 index 00000000000..18e50ae1255 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt @@ -0,0 +1 @@ +4c9fac0707f8d4195037ae5a681aa48626491541 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt-branch new file mode 100644 index 00000000000..7bc1a8d1592 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt-branch @@ -0,0 +1 @@ +c607fc30883e335def28cd686b51f6cfa02b06ec diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4 new file mode 100644 index 00000000000..f49bbf956e5 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4 @@ -0,0 +1 @@ +cc3e3009134cb88014129fc8858d1101359e5e2f diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4-branch new file mode 100644 index 00000000000..bff519ef184 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4-branch @@ -0,0 +1 @@ +183310e30fb1499af8c619108ffea4d300b5e778 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1 new file mode 100644 index 00000000000..963a7b3362a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1 @@ -0,0 +1 @@ +4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1-branch new file mode 100644 index 00000000000..4a22138e757 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1-branch @@ -0,0 +1 @@ +478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2 new file mode 100644 index 00000000000..aa4ada17e9f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2 @@ -0,0 +1 @@ +3b47b031b3e55ae11e14a05260b1c3ffd6838d55 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2-branch new file mode 100644 index 00000000000..5553cdba100 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2-branch @@ -0,0 +1 @@ +f48097eb340dc5a7cae55aabcf1faf4548aa821f diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6 new file mode 100644 index 00000000000..fb685bb631c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6 @@ -0,0 +1 @@ +99b4f7e4f24470fa06b980bc21f1095c2a9425c0 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6-branch new file mode 100644 index 00000000000..efc4c55ac41 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6-branch @@ -0,0 +1 @@ +a43150a738849c59376cf30bb2a68348a83c8f48 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7 new file mode 100644 index 00000000000..9c9424346a1 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7 @@ -0,0 +1 @@ +d874671ef5b20184836cb983bb273e5280384d0b diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7-branch new file mode 100644 index 00000000000..1762bb5dbc3 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7-branch @@ -0,0 +1 @@ +5195a1b480f66691b667f10a9e41e70115a78351 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8 new file mode 100644 index 00000000000..837c4915a8c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8 @@ -0,0 +1 @@ +3575826c96a975031d2c14368529cc5c4353a8fd diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8-branch new file mode 100644 index 00000000000..874230eff3f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8-branch @@ -0,0 +1 @@ +52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9 b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9 new file mode 100644 index 00000000000..b968a3efbc6 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9 @@ -0,0 +1 @@ +c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9-branch b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9-branch new file mode 100644 index 00000000000..7f3097b6970 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9-branch @@ -0,0 +1 @@ +13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e diff --git a/tests-clar/resources/merge-resolve/.gitted/refs/heads/unrelated b/tests-clar/resources/merge-resolve/.gitted/refs/heads/unrelated new file mode 100644 index 00000000000..bb877be2e66 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/refs/heads/unrelated @@ -0,0 +1 @@ +55b4e4687e7a0d9ca367016ed930f385d4022e6f diff --git a/tests-clar/resources/merge-resolve/added-in-master.txt b/tests-clar/resources/merge-resolve/added-in-master.txt new file mode 100644 index 00000000000..233c0919c99 --- /dev/null +++ b/tests-clar/resources/merge-resolve/added-in-master.txt @@ -0,0 +1 @@ +this file is added in master diff --git a/tests-clar/resources/merge-resolve/automergeable.txt b/tests-clar/resources/merge-resolve/automergeable.txt new file mode 100644 index 00000000000..ee3fa1b8c00 --- /dev/null +++ b/tests-clar/resources/merge-resolve/automergeable.txt @@ -0,0 +1,9 @@ +this file is changed in master +this file is automergeable +this file is automergeable +this file is automergeable +this file is automergeable +this file is automergeable +this file is automergeable +this file is automergeable +this file is automergeable diff --git a/tests-clar/resources/merge-resolve/changed-in-branch.txt b/tests-clar/resources/merge-resolve/changed-in-branch.txt new file mode 100644 index 00000000000..ab6c44a2e84 --- /dev/null +++ b/tests-clar/resources/merge-resolve/changed-in-branch.txt @@ -0,0 +1 @@ +initial revision diff --git a/tests-clar/resources/merge-resolve/changed-in-master.txt b/tests-clar/resources/merge-resolve/changed-in-master.txt new file mode 100644 index 00000000000..11deab00b2d --- /dev/null +++ b/tests-clar/resources/merge-resolve/changed-in-master.txt @@ -0,0 +1 @@ +changed in master diff --git a/tests-clar/resources/merge-resolve/conflicting.txt b/tests-clar/resources/merge-resolve/conflicting.txt new file mode 100644 index 00000000000..4e886e60252 --- /dev/null +++ b/tests-clar/resources/merge-resolve/conflicting.txt @@ -0,0 +1 @@ +this file is changed in master and branch diff --git a/tests-clar/resources/merge-resolve/removed-in-branch.txt b/tests-clar/resources/merge-resolve/removed-in-branch.txt new file mode 100644 index 00000000000..dfe3f22baa1 --- /dev/null +++ b/tests-clar/resources/merge-resolve/removed-in-branch.txt @@ -0,0 +1 @@ +this is removed in branch diff --git a/tests-clar/resources/merge-resolve/unchanged.txt b/tests-clar/resources/merge-resolve/unchanged.txt new file mode 100644 index 00000000000..c8f06f2e3bb --- /dev/null +++ b/tests-clar/resources/merge-resolve/unchanged.txt @@ -0,0 +1 @@ +this file is unchanged in both diff --git a/tests-clar/resources/peeled.git/HEAD b/tests-clar/resources/peeled.git/HEAD new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/tests-clar/resources/peeled.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests-clar/resources/peeled.git/config b/tests-clar/resources/peeled.git/config new file mode 100644 index 00000000000..88300524a00 --- /dev/null +++ b/tests-clar/resources/peeled.git/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true +[remote "origin"] + url = /home/peff/compile/libgit2/tests-clar/resources/peeled + fetch = +refs/*:refs/* + mirror = true diff --git a/tests-clar/resources/peeled.git/objects/info/packs b/tests-clar/resources/peeled.git/objects/info/packs new file mode 100644 index 00000000000..0d88b32e585 --- /dev/null +++ b/tests-clar/resources/peeled.git/objects/info/packs @@ -0,0 +1,2 @@ +P pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack + diff --git a/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.idx b/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.idx new file mode 100644 index 00000000000..9b79e9b85f8 Binary files /dev/null and b/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.idx differ diff --git a/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack b/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack new file mode 100644 index 00000000000..2459ca2870a Binary files /dev/null and b/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack differ diff --git a/tests-clar/resources/peeled.git/packed-refs b/tests-clar/resources/peeled.git/packed-refs new file mode 100644 index 00000000000..ad053d550bc --- /dev/null +++ b/tests-clar/resources/peeled.git/packed-refs @@ -0,0 +1,6 @@ +# pack-refs with: peeled fully-peeled +c2596aa0151888587ec5c0187f261e63412d9e11 refs/foo/tag-outside-tags +^0df1a5865c8abfc09f1f2182e6a31be550e99f07 +0df1a5865c8abfc09f1f2182e6a31be550e99f07 refs/heads/master +c2596aa0151888587ec5c0187f261e63412d9e11 refs/tags/tag-inside-tags +^0df1a5865c8abfc09f1f2182e6a31be550e99f07 diff --git a/tests-clar/resources/peeled.git/refs/heads/master b/tests-clar/resources/peeled.git/refs/heads/master new file mode 100644 index 00000000000..76c15e203e3 --- /dev/null +++ b/tests-clar/resources/peeled.git/refs/heads/master @@ -0,0 +1 @@ +0df1a5865c8abfc09f1f2182e6a31be550e99f07 diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c index 438ec01627d..e8277626059 100644 --- a/tests-clar/revwalk/basic.c +++ b/tests-clar/revwalk/basic.c @@ -1,15 +1,14 @@ #include "clar_libgit2.h" /* - $ git log --oneline --graph --decorate - * a4a7dce (HEAD, br2) Merge branch 'master' into br2 + * a4a7dce [0] Merge branch 'master' into br2 |\ - | * 9fd738e (master) a fourth commit - | * 4a202b3 a third commit - * | c47800c branch commit one + | * 9fd738e [1] a fourth commit + | * 4a202b3 [2] a third commit + * | c47800c [3] branch commit one |/ - * 5b5b025 another commit - * 8496071 testing + * 5b5b025 [5] another commit + * 8496071 [4] testing */ static const char *commit_head = "a4a7dce85cf63874e984719f4fdd239f5145052f"; @@ -39,6 +38,10 @@ static const int commit_sorting_time_reverse[][6] = { {4, 5, 2, 1, 3, 0} }; +static const int commit_sorting_segment[][6] = { + {1, 2, -1, -1, -1, -1} +}; + #define commit_count 6 static const int result_bytes = 24; @@ -57,22 +60,17 @@ static int get_commit_index(git_oid *raw_oid) return -1; } -static int test_walk(git_revwalk *walk, const git_oid *root, - int flags, const int possible_results[][6], int results_count) +static int test_walk_only(git_revwalk *walk, + const int possible_results[][commit_count], int results_count) { git_oid oid; - int i; int result_array[commit_count]; - git_revwalk_sorting(walk, flags); - git_revwalk_push(walk, root); - for (i = 0; i < commit_count; ++i) result_array[i] = -1; i = 0; - while (git_revwalk_next(&oid, walk) == 0) { result_array[i++] = get_commit_index(&oid); /*{ @@ -91,6 +89,15 @@ static int test_walk(git_revwalk *walk, const git_oid *root, return GIT_ERROR; } +static int test_walk(git_revwalk *walk, const git_oid *root, + int flags, const int possible_results[][6], int results_count) +{ + git_revwalk_sorting(walk, flags); + git_revwalk_push(walk, root); + + return test_walk_only(walk, possible_results, results_count); +} + static git_repository *_repo; static git_revwalk *_walk; @@ -189,3 +196,11 @@ void test_revwalk_basic__disallow_non_commit(void) cl_git_pass(git_oid_fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91")); cl_git_fail(git_revwalk_push(_walk, &oid)); } + +void test_revwalk_basic__push_range(void) +{ + git_revwalk_reset(_walk); + git_revwalk_sorting(_walk, 0); + cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e")); + cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1)); +} diff --git a/tests-clar/stash/drop.c b/tests-clar/stash/drop.c index d171390daf1..60b3c72e0ce 100644 --- a/tests-clar/stash/drop.c +++ b/tests-clar/stash/drop.c @@ -160,15 +160,13 @@ void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) retrieve_top_stash_id(&oid); cl_git_pass(git_revparse_single(&next_top_stash, repo, "stash@{1}")); - cl_assert_equal_i( - false, git_oid_cmp(&oid, git_object_id(next_top_stash)) == 0); + cl_assert_equal_i(false, git_oid_cmp(&oid, git_object_id(next_top_stash)) == 0); cl_git_pass(git_stash_drop(repo, 0)); retrieve_top_stash_id(&oid); - cl_assert_equal_i( - true, git_oid_cmp(&oid, git_object_id(next_top_stash)) == 0); + cl_git_pass(git_oid_cmp(&oid, git_object_id(next_top_stash))); git_object_free(next_top_stash); } diff --git a/tests-clar/stash/save.c b/tests-clar/stash/save.c index 588dfc3ea71..eae116ac5b2 100644 --- a/tests-clar/stash/save.c +++ b/tests-clar/stash/save.c @@ -37,10 +37,10 @@ void test_stash_save__cleanup(void) static void assert_object_oid(const char* revision, const char* expected_oid, git_otype type) { - git_object *object; int result; + git_object *obj; - result = git_revparse_single(&object, repo, revision); + result = git_revparse_single(&obj, repo, revision); if (!expected_oid) { cl_assert_equal_i(GIT_ENOTFOUND, result); @@ -48,10 +48,9 @@ static void assert_object_oid(const char* revision, const char* expected_oid, gi } else cl_assert_equal_i(0, result); - cl_assert_equal_i(type, git_object_type(object)); - cl_git_pass(git_oid_streq(git_object_id(object), expected_oid)); - - git_object_free(object); + cl_git_pass(git_oid_streq(git_object_id(obj), expected_oid)); + cl_assert_equal_i(type, git_object_type(obj)); + git_object_free(obj); } static void assert_blob_oid(const char* revision, const char* expected_oid) @@ -147,7 +146,7 @@ static void assert_commit_message_contains(const char *revision, const char *fra { git_commit *commit; - cl_git_pass(git_revparse_single(((git_object **)&commit), repo, revision)); + cl_git_pass(git_revparse_single((git_object**)&commit, repo, revision)); cl_assert(strstr(git_commit_message(commit), fragment) != NULL); diff --git a/tests-clar/status/status_helpers.c b/tests-clar/status/status_helpers.c index 24546d45c65..f073c249127 100644 --- a/tests-clar/status/status_helpers.c +++ b/tests-clar/status/status_helpers.c @@ -40,7 +40,8 @@ int cb_status__single(const char *p, unsigned int s, void *payload) { status_entry_single *data = (status_entry_single *)payload; - GIT_UNUSED(p); + if (data->debug) + fprintf(stderr, "%02d: %s (%04x)\n", data->count, p, s); data->count++; data->status = s; diff --git a/tests-clar/status/status_helpers.h b/tests-clar/status/status_helpers.h index 1aa0263eec1..ae1469e79e2 100644 --- a/tests-clar/status/status_helpers.h +++ b/tests-clar/status/status_helpers.h @@ -24,6 +24,7 @@ extern int cb_status__count(const char *p, unsigned int s, void *payload); typedef struct { int count; unsigned int status; + bool debug; } status_entry_single; /* cb_status__single takes payload of "status_entry_single *" */ diff --git a/tests-clar/status/submodules.c b/tests-clar/status/submodules.c index 4656a87e31f..8365a7f5a7a 100644 --- a/tests-clar/status/submodules.c +++ b/tests-clar/status/submodules.c @@ -165,7 +165,7 @@ void test_status_submodules__moved_head(void) cl_git_pass( git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(6, counts.entry_count); - + git_repository_free(smrepo); } @@ -219,3 +219,4 @@ void test_status_submodules__dirty_workdir_only(void) git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(6, counts.entry_count); } + diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c index a9b8a12ed01..0138b1712ef 100644 --- a/tests-clar/status/worktree.c +++ b/tests-clar/status/worktree.c @@ -258,9 +258,8 @@ void test_status_worktree__ignores(void) static int cb_status__check_592(const char *p, unsigned int s, void *payload) { - GIT_UNUSED(payload); - - if (s != GIT_STATUS_WT_DELETED || (payload != NULL && strcmp(p, (const char *)payload) != 0)) + if (s != GIT_STATUS_WT_DELETED || + (payload != NULL && strcmp(p, (const char *)payload) != 0)) return -1; return 0; diff --git a/tests-clar/status/worktree_init.c b/tests-clar/status/worktree_init.c index b67107aec07..296c27c866b 100644 --- a/tests-clar/status/worktree_init.c +++ b/tests-clar/status/worktree_init.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "fileops.h" #include "ignore.h" #include "status_helpers.h" @@ -321,10 +323,10 @@ void test_status_worktree_init__new_staged_file_must_handle_crlf(void) cl_set_cleanup(&cleanup_new_repo, "getting_started"); cl_git_pass(git_repository_init(&repo, "getting_started", 0)); - // Ensure that repo has core.autocrlf=true + /* Ensure that repo has core.autocrlf=true */ cl_repo_set_bool(repo, "core.autocrlf", true); - cl_git_mkfile("getting_started/testfile.txt", "content\r\n"); // Content with CRLF + cl_git_mkfile("getting_started/testfile.txt", "content\r\n"); /* Content with CRLF */ cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_add_bypath(index, "testfile.txt")); diff --git a/tests-clar/submodule/status.c b/tests-clar/submodule/status.c index 282e827580a..88f38805260 100644 --- a/tests-clar/submodule/status.c +++ b/tests-clar/submodule/status.c @@ -383,3 +383,32 @@ void test_submodule_status__iterator(void) cl_git_pass(git_status_foreach_ext(g_repo, &opts, confirm_submodule_status, &exp)); } + +void test_submodule_status__untracked_dirs_containing_ignored_files(void) +{ + git_buf path = GIT_BUF_INIT; + unsigned int status, expected; + git_submodule *sm; + + cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), "modules/sm_unchanged/info/exclude")); + cl_git_append2file(git_buf_cstr(&path), "\n*.ignored\n"); + + cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged/directory")); + cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0)); + cl_git_pass(git_buf_joinpath(&path, git_buf_cstr(&path), "i_am.ignored")); + cl_git_mkfile(git_buf_cstr(&path), "ignored this file, please\n"); + + cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); + cl_git_pass(git_submodule_status(&status, sm)); + + cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); + + expected = GIT_SUBMODULE_STATUS_IN_HEAD | + GIT_SUBMODULE_STATUS_IN_INDEX | + GIT_SUBMODULE_STATUS_IN_CONFIG | + GIT_SUBMODULE_STATUS_IN_WD; + + cl_assert(status == expected); + + git_buf_free(&path); +}