summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md8
-rw-r--r--include/git2/diff.h29
-rw-r--r--include/git2/sys/transport.h1
-rw-r--r--src/commit_list.h1
-rw-r--r--src/config_file.c15
-rw-r--r--src/diff.c15
-rw-r--r--src/fileops.c57
-rw-r--r--src/fileops.h3
-rw-r--r--src/index.c38
-rw-r--r--src/merge.c192
-rw-r--r--tests/config/stress.c20
-rw-r--r--tests/diff/notify.c29
-rw-r--r--tests/diff/tree.c2
-rw-r--r--tests/resources/redundant.git/HEAD1
-rwxr-xr-xtests/resources/redundant.git/config5
-rw-r--r--tests/resources/redundant.git/objects/info/packs2
-rw-r--r--tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.idxbin0 -> 121136 bytes
-rw-r--r--tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.packbin0 -> 309860 bytes
-rw-r--r--tests/resources/redundant.git/packed-refs3
-rw-r--r--tests/resources/redundant.git/refs/.gitkeep0
-rw-r--r--tests/revwalk/mergebase.c20
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
new file mode 100644
index 000000000..d8e099a98
--- /dev/null
+++ b/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.idx
Binary files differ
diff --git a/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack b/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack
new file mode 100644
index 000000000..02ea49f4b
--- /dev/null
+++ b/tests/resources/redundant.git/objects/pack/pack-3d944c0c5bcb6b16209af847052c6ff1a521529d.pack
Binary files differ
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);
+}