diff options
-rw-r--r-- | CHANGELOG.md | 8 | ||||
-rw-r--r-- | include/git2/diff.h | 29 | ||||
-rw-r--r-- | include/git2/sys/transport.h | 1 | ||||
-rw-r--r-- | src/commit_list.h | 1 | ||||
-rw-r--r-- | src/config_file.c | 15 | ||||
-rw-r--r-- | src/diff.c | 15 | ||||
-rw-r--r-- | src/fileops.c | 57 | ||||
-rw-r--r-- | src/fileops.h | 3 | ||||
-rw-r--r-- | src/index.c | 38 | ||||
-rw-r--r-- | src/merge.c | 192 | ||||
-rw-r--r-- | tests/config/stress.c | 20 | ||||
-rw-r--r-- | tests/diff/notify.c | 29 | ||||
-rw-r--r-- | tests/diff/tree.c | 2 | ||||
-rw-r--r-- | tests/resources/redundant.git/HEAD | 1 | ||||
-rwxr-xr-x | tests/resources/redundant.git/config | 5 | ||||
-rw-r--r-- | tests/resources/redundant.git/objects/info/packs | 2 | ||||
-rw-r--r-- | tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.idx | bin | 0 -> 121136 bytes | |||
-rw-r--r-- | tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack | bin | 0 -> 309860 bytes | |||
-rw-r--r-- | tests/resources/redundant.git/packed-refs | 3 | ||||
-rw-r--r-- | tests/resources/redundant.git/refs/.gitkeep | 0 | ||||
-rw-r--r-- | tests/revwalk/mergebase.c | 20 |
21 files changed, 365 insertions, 76 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ade3e3b1..0b2e43308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ v0.23 + 1 the opportunity for concurrent operations and not committing any changes until the unlock. +* `git_diff_options` added a new callback `progress_cb` to report on the + progress of the diff as files are being compared. The documentation of + the existing callback `notify_cb` was updated to reflect that it only + gets called when new deltas are added to the diff. + ### API removals ### Breaking API changes @@ -36,6 +41,9 @@ v0.23 + 1 it existed in the index. This does not affect the higher-level `git_index_add_bypath` or `git_index_add_frombuffer` functions. +* The `notify_payload` field of `git_diff_options` was renamed to `payload` + to reflect that it's also the payload for the new progress callback. + v0.23 ------ diff --git a/include/git2/diff.h b/include/git2/diff.h index a0f6db350..cbffdb49a 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -351,6 +351,22 @@ typedef int (*git_diff_notify_cb)( void *payload); /** + * Diff progress callback. + * + * Called before each file comparison. + * + * @param diff_so_far The diff being generated. + * @param old_path The path to the old file or NULL. + * @param new_path The path to the new file or NULL. + * @return Non-zero to abort the diff. + */ +typedef int (*git_diff_progress_cb)( + const git_diff *diff_so_far, + const char *old_path, + const char *new_path, + void *payload); + +/** * Structure describing options about how the diff should be executed. * * Setting all values of the structure to zero will yield the default @@ -370,8 +386,10 @@ typedef int (*git_diff_notify_cb)( * - `max_size` is a file size (in bytes) above which a blob will be marked * as binary automatically; pass a negative value to disable. * - `notify_cb` is an optional callback function, notifying the consumer of - * which files are being examined as the diff is generated - * - `notify_payload` is the payload data to pass to the `notify_cb` function + * changes to the diff as new deltas are added. + * - `progress_cb` is an optional callback function, notifying the consumer of + * which files are being examined as the diff is generated. + * - `payload` is the payload to pass to the callback functions. * - `ignore_submodules` overrides the submodule ignore setting for all * submodules in the diff. */ @@ -383,8 +401,9 @@ typedef struct { git_submodule_ignore_t ignore_submodules; /**< submodule ignore rule */ git_strarray pathspec; /**< defaults to include all paths */ - git_diff_notify_cb notify_cb; - void *notify_payload; + git_diff_notify_cb notify_cb; + git_diff_progress_cb progress_cb; + void *payload; /* options controlling how to diff text is generated */ @@ -403,7 +422,7 @@ typedef struct { * `git_diff_options_init` programmatic initialization. */ #define GIT_DIFF_OPTIONS_INIT \ - {GIT_DIFF_OPTIONS_VERSION, 0, GIT_SUBMODULE_IGNORE_UNSPECIFIED, {NULL,0}, NULL, NULL, 3} + {GIT_DIFF_OPTIONS_VERSION, 0, GIT_SUBMODULE_IGNORE_UNSPECIFIED, {NULL,0}, NULL, NULL, NULL, 3} /** * Initializes a `git_diff_options` with default values. Equivalent to diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h index ca8617f3f..ce0234a18 100644 --- a/include/git2/sys/transport.h +++ b/include/git2/sys/transport.h @@ -10,6 +10,7 @@ #include "git2/net.h" #include "git2/types.h" +#include "git2/strarray.h" /** * @file git2/sys/transport.h diff --git a/src/commit_list.h b/src/commit_list.h index b1d88e016..a6967bcef 100644 --- a/src/commit_list.h +++ b/src/commit_list.h @@ -13,6 +13,7 @@ #define PARENT2 (1 << 1) #define RESULT (1 << 2) #define STALE (1 << 3) +#define ALL_FLAGS (PARENT1 | PARENT2 | STALE | RESULT) #define PARENTS_PER_COMMIT 2 #define COMMIT_ALLOC \ diff --git a/src/config_file.c b/src/config_file.c index 46f21c0f1..5f5e309e0 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -77,8 +77,7 @@ typedef struct git_config_file_iter { (iter) = (tmp)) struct reader { - time_t file_mtime; - size_t file_size; + git_oid checksum; char *file_path; git_buf buffer; char *read_ptr; @@ -285,7 +284,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level) git_buf_init(&reader->buffer, 0); res = git_futils_readbuffer_updated( - &reader->buffer, b->file_path, &reader->file_mtime, &reader->file_size, NULL); + &reader->buffer, b->file_path, &reader->checksum, NULL); /* It's fine if the file doesn't exist */ if (res == GIT_ENOTFOUND) @@ -345,7 +344,7 @@ static int config_refresh(git_config_backend *cfg) reader = git_array_get(b->readers, i); error = git_futils_readbuffer_updated( &reader->buffer, reader->file_path, - &reader->file_mtime, &reader->file_size, &updated); + &reader->checksum, &updated); if (error < 0 && error != GIT_ENOTFOUND) return error; @@ -1618,7 +1617,7 @@ static int read_on_variable( git_buf_init(&r->buffer, 0); result = git_futils_readbuffer_updated( - &r->buffer, r->file_path, &r->file_mtime, &r->file_size, NULL); + &r->buffer, r->file_path, &r->checksum, NULL); if (result == 0) { result = config_read(parse_data->values, parse_data->cfg_file, r, parse_data->level, parse_data->depth+1); @@ -1894,7 +1893,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p } else { /* Lock the file */ if ((result = git_filebuf_open( - &file, cfg->file_path, 0, GIT_CONFIG_FILE_MODE)) < 0) { + &file, cfg->file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) { git_buf_free(&reader->buffer); return result; } @@ -1945,10 +1944,6 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p git_buf_attach(&cfg->locked_content, git_buf_detach(&buf), len); } else { git_filebuf_write(&file, git_buf_cstr(&buf), git_buf_len(&buf)); - - /* refresh stats - if this errors, then commit will error too */ - (void)git_filebuf_stats(&reader->file_mtime, &reader->file_size, &file); - result = git_filebuf_commit(&file); } diff --git a/src/diff.c b/src/diff.c index b5e9b6cd5..c2362358a 100644 --- a/src/diff.c +++ b/src/diff.c @@ -56,7 +56,7 @@ static int diff_insert_delta( if (diff->opts.notify_cb) { error = diff->opts.notify_cb( - diff, delta, matched_pathspec, diff->opts.notify_payload); + diff, delta, matched_pathspec, diff->opts.payload); if (error) { git__free(delta); @@ -1260,7 +1260,18 @@ int git_diff__from_iterators( /* run iterators building diffs */ while (!error && (info.oitem || info.nitem)) { - int cmp = info.oitem ? + int cmp; + + /* report progress */ + if (opts && opts->progress_cb) { + if ((error = opts->progress_cb(diff, + info.oitem ? info.oitem->path : NULL, + info.nitem ? info.nitem->path : NULL, + opts->payload))) + break; + } + + cmp = info.oitem ? (info.nitem ? diff->entrycomp(info.oitem, info.nitem) : -1) : 1; /* create DELETED records for old items not matched in new */ diff --git a/src/fileops.c b/src/fileops.c index 57d2ce9c3..cfc22bb53 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -153,13 +153,15 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) } int git_futils_readbuffer_updated( - git_buf *buf, const char *path, time_t *mtime, size_t *size, int *updated) + git_buf *out, const char *path, git_oid *checksum, int *updated) { + int error; git_file fd; struct stat st; - bool changed = false; + git_buf buf = GIT_BUF_INIT; + git_oid checksum_new; - assert(buf && path && *path); + assert(out && path && *path); if (updated != NULL) *updated = 0; @@ -178,45 +180,50 @@ int git_futils_readbuffer_updated( return -1; } - /* - * If we were given a time and/or a size, we only want to read the file - * if it has been modified. - */ - if (size && *size != (size_t)st.st_size) - changed = true; - if (mtime && *mtime != (time_t)st.st_mtime) - changed = true; - if (!size && !mtime) - changed = true; - - if (!changed) { - return 0; - } - - if (mtime != NULL) - *mtime = st.st_mtime; - if (size != NULL) - *size = (size_t)st.st_size; - if ((fd = git_futils_open_ro(path)) < 0) return fd; - if (git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size) < 0) { + if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) { p_close(fd); return -1; } p_close(fd); + if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) { + git_buf_free(&buf); + return error; + } + + /* + * If we were given a checksum, we only want to use it if it's different + */ + if (checksum && !git_oid__cmp(checksum, &checksum_new)) { + git_buf_free(&buf); + if (updated) + *updated = 0; + + return 0; + } + + /* + * If we're here, the file did change, or the user didn't have an old version + */ + if (checksum) + git_oid_cpy(checksum, &checksum_new); + if (updated != NULL) *updated = 1; + git_buf_swap(out, &buf); + git_buf_free(&buf); + return 0; } int git_futils_readbuffer(git_buf *buf, const char *path) { - return git_futils_readbuffer_updated(buf, path, NULL, NULL, NULL); + return git_futils_readbuffer_updated(buf, path, NULL, NULL); } int git_futils_writebuffer( diff --git a/src/fileops.h b/src/fileops.h index 572ff01a5..c6db1953e 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -13,6 +13,7 @@ #include "path.h" #include "pool.h" #include "strmap.h" +#include "oid.h" /** * Filebuffer methods @@ -21,7 +22,7 @@ */ extern int git_futils_readbuffer(git_buf *obj, const char *path); extern int git_futils_readbuffer_updated( - git_buf *obj, const char *path, time_t *mtime, size_t *size, int *updated); + git_buf *obj, const char *path, git_oid *checksum, int *updated); extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len); extern int git_futils_writebuffer( diff --git a/src/index.c b/src/index.c index 0adc7e157..dcf46fe50 100644 --- a/src/index.c +++ b/src/index.c @@ -2899,6 +2899,7 @@ int git_index_read_index( { git_vector new_entries = GIT_VECTOR_INIT, remove_entries = GIT_VECTOR_INIT; + git_idxmap *new_entries_map = NULL; git_iterator *index_iterator = NULL; git_iterator *new_iterator = NULL; git_iterator_options opts = GIT_ITERATOR_OPTIONS_INIT; @@ -2908,9 +2909,15 @@ int git_index_read_index( int error; if ((error = git_vector_init(&new_entries, new_index->entries.length, index->entries._cmp)) < 0 || - (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0) + (error = git_vector_init(&remove_entries, index->entries.length, NULL)) < 0 || + (error = git_idxmap_alloc(&new_entries_map)) < 0) goto done; + if (index->ignore_case) + kh_resize(idxicase, (khash_t(idxicase) *) new_entries_map, new_index->entries.length); + else + kh_resize(idx, new_entries_map, new_index->entries.length); + opts.flags = GIT_ITERATOR_DONT_IGNORE_CASE; if ((error = git_iterator_for_index(&index_iterator, index, &opts)) < 0 || @@ -2924,6 +2931,7 @@ int git_index_read_index( goto done; while (true) { + git_index_entry *add_entry = NULL, *remove_entry = NULL; int diff; if (old_entry && new_entry) @@ -2936,27 +2944,37 @@ int git_index_read_index( break; if (diff < 0) { - git_vector_insert(&remove_entries, (git_index_entry *)old_entry); + remove_entry = (git_index_entry *)old_entry; } else if (diff > 0) { - if ((error = index_entry_dup(&entry, index, new_entry)) < 0) + if ((error = index_entry_dup(&add_entry, index, new_entry)) < 0) goto done; - - git_vector_insert(&new_entries, entry); } else { /* Path and stage are equal, if the OID is equal, keep it to * keep the stat cache data. */ if (git_oid_equal(&old_entry->id, &new_entry->id)) { - git_vector_insert(&new_entries, (git_index_entry *)old_entry); + add_entry = (git_index_entry *)old_entry; } else { - if ((error = index_entry_dup(&entry, index, new_entry)) < 0) + if ((error = index_entry_dup(&add_entry, index, new_entry)) < 0) goto done; - git_vector_insert(&new_entries, entry); - git_vector_insert(&remove_entries, (git_index_entry *)old_entry); + remove_entry = (git_index_entry *)old_entry; } } + if (add_entry) { + if ((error = git_vector_insert(&new_entries, add_entry)) == 0) + INSERT_IN_MAP_EX(index, new_entries_map, add_entry, error); + } + + if (remove_entry && !error) + error = git_vector_insert(&remove_entries, remove_entry); + + if (error < 0) { + giterr_set(GITERR_INDEX, "failed to insert entry"); + return error; + } + if (diff <= 0) { if ((error = git_iterator_advance(&old_entry, index_iterator)) < 0 && error != GIT_ITEROVER) @@ -2974,6 +2992,7 @@ int git_index_read_index( git_index_reuc_clear(index); git_vector_swap(&new_entries, &index->entries); + new_entries_map = git__swap(index->entries_map, new_entries_map); git_vector_foreach(&remove_entries, i, entry) { if (index->tree) @@ -2985,6 +3004,7 @@ int git_index_read_index( error = 0; done: + git_idxmap_free(new_entries_map); git_vector_free(&new_entries); git_vector_free(&remove_entries); git_iterator_free(index_iterator); diff --git a/src/merge.c b/src/merge.c index ac0caeabd..bad5f9552 100644 --- a/src/merge.c +++ b/src/merge.c @@ -302,30 +302,59 @@ static int interesting(git_pqueue *list) return 0; } -int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos) +static void clear_commit_marks_1(git_commit_list **plist, + git_commit_list_node *commit, unsigned int mark) { - int error; - unsigned int i; - git_commit_list_node *two; - git_commit_list *result = NULL, *tmp = NULL; - git_pqueue list; + while (commit) { + unsigned int i; - /* If there's only the one commit, there can be no merge bases */ - if (twos->length == 0) { - *out = NULL; - return 0; + if (!(mark & commit->flags)) + return; + + commit->flags &= ~mark; + + for (i = 1; i < commit->out_degree; i++) { + git_commit_list_node *p = commit->parents[i]; + git_commit_list_insert(p, plist); + } + + commit = commit->out_degree ? commit->parents[0] : NULL; } +} - /* if the commit is repeated, we have a our merge base already */ - git_vector_foreach(twos, i, two) { - if (one == two) - return git_commit_list_insert(one, out) ? 0 : -1; +static void clear_commit_marks_many(git_vector *commits, unsigned int mark) +{ + git_commit_list *list = NULL; + git_commit_list_node *c; + unsigned int i; + + git_vector_foreach(commits, i, c) { + git_commit_list_insert(c, &list); } - if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0) - return -1; + while (list) + clear_commit_marks_1(&list, git_commit_list_pop(&list), mark); +} - if (git_commit_list_parse(walk, one) < 0) +static void clear_commit_marks(git_commit_list_node *commit, unsigned int mark) +{ + git_commit_list *list = NULL; + git_commit_list_insert(commit, &list); + while (list) + clear_commit_marks_1(&list, git_commit_list_pop(&list), mark); +} + +static int paint_down_to_common( + git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos) +{ + git_pqueue list; + git_commit_list *result = NULL; + git_commit_list_node *two; + + int error; + unsigned int i; + + if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0) return -1; one->flags |= PARENT1; @@ -376,19 +405,138 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l } git_pqueue_free(&list); + *out = result; + return 0; +} + +static int remove_redundant(git_revwalk *walk, git_vector *commits) +{ + git_vector work = GIT_VECTOR_INIT; + unsigned char *redundant; + unsigned int *filled_index; + unsigned int i, j; + int error = 0; + + redundant = git__calloc(commits->length, 1); + GITERR_CHECK_ALLOC(redundant); + filled_index = git__calloc((commits->length - 1), sizeof(unsigned int)); + GITERR_CHECK_ALLOC(filled_index); + + for (i = 0; i < commits->length; ++i) { + if ((error = git_commit_list_parse(walk, commits->contents[i])) < 0) + goto done; + } + + for (i = 0; i < commits->length; ++i) { + git_commit_list *common = NULL; + git_commit_list_node *commit = commits->contents[i]; + + if (redundant[i]) + continue; + + git_vector_clear(&work); + + for (j = 0; j < commits->length; j++) { + if (i == j || redundant[j]) + continue; + + filled_index[work.length] = j; + if ((error = git_vector_insert(&work, commits->contents[j])) < 0) + goto done; + } + + error = paint_down_to_common(&common, walk, commit, &work); + if (error < 0) + goto done; + + if (commit->flags & PARENT2) + redundant[i] = 1; + + for (j = 0; j < work.length; j++) { + git_commit_list_node *w = work.contents[j]; + if (w->flags & PARENT1) + redundant[filled_index[j]] = 1; + } + + clear_commit_marks(commit, ALL_FLAGS); + clear_commit_marks_many(&work, ALL_FLAGS); + + git_commit_list_free(&common); + } + + for (i = 0; i < commits->length; ++i) { + if (redundant[i]) + commits->contents[i] = NULL; + } + +done: + git__free(redundant); + git__free(filled_index); + git_vector_free(&work); + return error; +} + +int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos) +{ + int error; + unsigned int i; + git_commit_list_node *two; + git_commit_list *result = NULL, *tmp = NULL; + + /* If there's only the one commit, there can be no merge bases */ + if (twos->length == 0) { + *out = NULL; + return 0; + } + + /* if the commit is repeated, we have a our merge base already */ + git_vector_foreach(twos, i, two) { + if (one == two) + return git_commit_list_insert(one, out) ? 0 : -1; + } + + if (git_commit_list_parse(walk, one) < 0) + return -1; + + error = paint_down_to_common(&result, walk, one, twos); + if (error < 0) + return error; /* filter out any stale commits in the results */ tmp = result; result = NULL; while (tmp) { - struct git_commit_list *next = tmp->next; - if (!(tmp->item->flags & STALE)) - if (git_commit_list_insert_by_date(tmp->item, &result) == NULL) + git_commit_list_node *c = git_commit_list_pop(&tmp); + if (!(c->flags & STALE)) + if (git_commit_list_insert_by_date(c, &result) == NULL) return -1; + } + + /* + * more than one merge base -- see if there are redundant merge + * bases and remove them + */ + if (result && result->next) { + git_vector redundant = GIT_VECTOR_INIT; + + while (result) + git_vector_insert(&redundant, git_commit_list_pop(&result)); + + clear_commit_marks(one, ALL_FLAGS); + clear_commit_marks_many(twos, ALL_FLAGS); + + if ((error = remove_redundant(walk, &redundant)) < 0) { + git_vector_free(&redundant); + return error; + } + + git_vector_foreach(&redundant, i, two) { + if (two != NULL) + git_commit_list_insert_by_date(two, &result); + } - git__free(tmp); - tmp = next; + git_vector_free(&redundant); } *out = result; diff --git a/tests/config/stress.c b/tests/config/stress.c index 503f44f03..6e960425c 100644 --- a/tests/config/stress.c +++ b/tests/config/stress.c @@ -107,3 +107,23 @@ void test_config_stress__complex(void) git_config_free(config); } + +void test_config_stress__quick_write(void) +{ + git_config *config_w, *config_r; + const char *path = "./config-quick-write"; + const char *key = "quick.write"; + int32_t i; + + /* Create an external writer for one instance with the other one */ + cl_git_pass(git_config_open_ondisk(&config_w, path)); + cl_git_pass(git_config_open_ondisk(&config_r, path)); + + /* Write and read in the same second (repeat to increase the chance of it happening) */ + for (i = 0; i < 10; i++) { + int32_t val; + cl_git_pass(git_config_set_int32(config_w, key, i)); + cl_git_pass(git_config_get_int32(&val, config_r, key)); + cl_assert_equal_i(i, val); + } +} diff --git a/tests/diff/notify.c b/tests/diff/notify.c index 6ef4af573..74abbc93b 100644 --- a/tests/diff/notify.c +++ b/tests/diff/notify.c @@ -55,7 +55,7 @@ static void test_notify( opts.pathspec.strings = searched_pathspecs; opts.pathspec.count = pathspecs_count; - opts.notify_payload = expected_matched_pathspecs; + opts.payload = expected_matched_pathspecs; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); @@ -228,3 +228,30 @@ void test_diff_notify__notify_cb_can_be_used_as_filtering_function(void) git_diff_free(diff); } + +static int progress_abort_diff( + const git_diff *diff_so_far, + const char *old_path, + const char *new_path, + void *payload) +{ + GIT_UNUSED(old_path); + GIT_UNUSED(new_path); + GIT_UNUSED(payload); + + return -42; +} + +void test_diff_notify__progress_cb_can_abort_diff(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff *diff = NULL; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.progress_cb = progress_abort_diff; + + cl_git_fail_with( + git_diff_index_to_workdir(&diff, g_repo, NULL, &opts), -42); +} diff --git a/tests/diff/tree.c b/tests/diff/tree.c index 2bc9e6a55..e4b2a8bbe 100644 --- a/tests/diff/tree.c +++ b/tests/diff/tree.c @@ -90,7 +90,7 @@ void test_diff_tree__0(void) #define DIFF_OPTS(FLAGS, CTXT) \ {GIT_DIFF_OPTIONS_VERSION, (FLAGS), GIT_SUBMODULE_IGNORE_UNSPECIFIED, \ - {NULL,0}, NULL, NULL, (CTXT), 1} + {NULL,0}, NULL, NULL, NULL, (CTXT), 1} void test_diff_tree__options(void) { diff --git a/tests/resources/redundant.git/HEAD b/tests/resources/redundant.git/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests/resources/redundant.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests/resources/redundant.git/config b/tests/resources/redundant.git/config new file mode 100755 index 000000000..2f8958058 --- /dev/null +++ b/tests/resources/redundant.git/config @@ -0,0 +1,5 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + logallrefupdates = true diff --git a/tests/resources/redundant.git/objects/info/packs b/tests/resources/redundant.git/objects/info/packs new file mode 100644 index 000000000..fbf960f10 --- /dev/null +++ b/tests/resources/redundant.git/objects/info/packs @@ -0,0 +1,2 @@ +P pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack + diff --git a/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.idx b/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.idx Binary files differnew file mode 100644 index 000000000..d8e099a98 --- /dev/null +++ b/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.idx diff --git a/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack b/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack Binary files differnew file mode 100644 index 000000000..02ea49f4b --- /dev/null +++ b/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack diff --git a/tests/resources/redundant.git/packed-refs b/tests/resources/redundant.git/packed-refs new file mode 100644 index 000000000..e8bf04d65 --- /dev/null +++ b/tests/resources/redundant.git/packed-refs @@ -0,0 +1,3 @@ +# pack-refs with: peeled fully-peeled +e18fa2788e9c4e12d83150808a31dfbfb1ae364f refs/heads/master +91f4b95df4a59504a9813ba66912562931d990e3 refs/heads/ref2/ref28 diff --git a/tests/resources/redundant.git/refs/.gitkeep b/tests/resources/redundant.git/refs/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/resources/redundant.git/refs/.gitkeep diff --git a/tests/revwalk/mergebase.c b/tests/revwalk/mergebase.c index aafe97d71..ee078b3e7 100644 --- a/tests/revwalk/mergebase.c +++ b/tests/revwalk/mergebase.c @@ -492,3 +492,23 @@ void test_revwalk_mergebase__octopus_merge_branch(void) * * a */ + +void test_revwalk_mergebase__remove_redundant(void) +{ + git_repository *repo; + git_oid one, two, base; + git_oidarray result = {NULL, 0}; + + cl_git_pass(git_repository_open(&repo, cl_fixture("redundant.git"))); + + cl_git_pass(git_oid_fromstr(&one, "d89137c93ba1ee749214ff4ce52ae9137bc833f9")); + cl_git_pass(git_oid_fromstr(&two, "91f4b95df4a59504a9813ba66912562931d990e3")); + cl_git_pass(git_oid_fromstr(&base, "6cb1f2352d974e1c5a776093017e8772416ac97a")); + + cl_git_pass(git_merge_bases(&result, repo, &one, &two)); + cl_assert_equal_i(1, result.count); + cl_assert_equal_oid(&base, &result.ids[0]); + + git_oidarray_free(&result); + git_repository_free(repo); +} |