diff --git a/include/git2/checkout.h b/include/git2/checkout.h
index a4d0a0cef..0bac5690a 100644
--- a/include/git2/checkout.h
+++ b/include/git2/checkout.h
@@ -21,22 +21,39 @@
*/
GIT_BEGIN_DECL
-enum {
- GIT_CHECKOUT_DEFAULT = (1 << 0),
- GIT_CHECKOUT_OVERWRITE_MODIFIED = (1 << 1),
- GIT_CHECKOUT_CREATE_MISSING = (1 << 2),
- GIT_CHECKOUT_REMOVE_UNTRACKED = (1 << 3),
-};
+/**
+ * Checkout behavior flags
+ *
+ * These flags control what checkout does with files. Pass in a
+ * combination of these values OR'ed together.
+ */
+typedef enum {
+ /** Checkout does not update any files in the working directory. */
+ GIT_CHECKOUT_DEFAULT = (1 << 0),
-/* Use zeros to indicate default settings */
+ /** When a file exists and is modified, replace it with new version. */
+ GIT_CHECKOUT_OVERWRITE_MODIFIED = (1 << 1),
+
+ /** When a file does not exist in the working directory, create it. */
+ GIT_CHECKOUT_CREATE_MISSING = (1 << 2),
+
+ /** If an untracked file in found in the working dir, delete it. */
+ GIT_CHECKOUT_REMOVE_UNTRACKED = (1 << 3),
+} git_checkout_strategy_t;
+
+/**
+ * Checkout options structure
+ *
+ * Use zeros to indicate default settings.
+ */
typedef struct git_checkout_opts {
- unsigned int checkout_strategy; /* default: GIT_CHECKOUT_DEFAULT */
- int disable_filters;
- int dir_mode; /* default is 0755 */
- int file_mode; /* default is 0644 */
- int file_open_flags; /* default is O_CREAT | O_TRUNC | O_WRONLY */
+ unsigned int checkout_strategy; /** default: GIT_CHECKOUT_DEFAULT */
+ int disable_filters; /** don't apply filters like CRLF conversion */
+ int dir_mode; /** default is 0755 */
+ int file_mode; /** default is 0644 or 0755 as dictated by blob */
+ int file_open_flags; /** default is O_CREAT | O_TRUNC | O_WRONLY */
- /* Optional callback to notify the consumer of files that
+ /** Optional callback to notify the consumer of files that
* haven't be checked out because a modified version of them
* exist in the working directory.
*
@@ -51,7 +68,7 @@ typedef struct git_checkout_opts {
void *notify_payload;
- /* when not NULL, arrays of fnmatch pattern specifying
+ /** When not NULL, array of fnmatch patterns specifying
* which paths should be taken into account
*/
git_strarray paths;
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 121c40307..1932db029 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -34,21 +34,58 @@ GIT_BEGIN_DECL
* in via the `flags` value in the `git_diff_options`.
*/
enum {
+ /** Normal diff, the default */
GIT_DIFF_NORMAL = 0,
+ /** Reverse the sides of the diff */
GIT_DIFF_REVERSE = (1 << 0),
+ /** Treat all files as text, disabling binary attributes & detection */
GIT_DIFF_FORCE_TEXT = (1 << 1),
+ /** Ignore all whitespace */
GIT_DIFF_IGNORE_WHITESPACE = (1 << 2),
+ /** Ignore changes in amount of whitespace */
GIT_DIFF_IGNORE_WHITESPACE_CHANGE = (1 << 3),
+ /** Ignore whitespace at end of line */
GIT_DIFF_IGNORE_WHITESPACE_EOL = (1 << 4),
+ /** Exclude submodules from the diff completely */
GIT_DIFF_IGNORE_SUBMODULES = (1 << 5),
+ /** Use the "patience diff" algorithm (currently unimplemented) */
GIT_DIFF_PATIENCE = (1 << 6),
+ /** Include ignored files in the diff list */
GIT_DIFF_INCLUDE_IGNORED = (1 << 7),
+ /** Include untracked files in the diff list */
GIT_DIFF_INCLUDE_UNTRACKED = (1 << 8),
+ /** Include unmodified files in the diff list */
GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9),
+ /** Even with the GIT_DIFF_INCLUDE_UNTRACKED flag, when an untracked
+ * directory is found, only a single entry for the directory is added
+ * to the diff list; with this flag, all files under the directory will
+ * be included, 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),
};
/**
@@ -85,24 +122,16 @@ typedef struct git_diff_list git_diff_list;
* Flags that can be set for the file on side of a diff.
*
* Most of the flags are just for internal consumption by libgit2,
- * but some of them may be interesting to external users. They are:
- *
- * - VALID_OID - the `oid` value is computed and correct
- * - FREE_PATH - the `path` string is separated allocated memory
- * - BINARY - this file should be considered binary data
- * - NOT_BINARY - this file should be considered text data
- * - FREE_DATA - the internal file data is kept in allocated memory
- * - UNMAP_DATA - the internal file data is kept in mmap'ed memory
- * - NO_DATA - this side of the diff should not be loaded
+ * but some of them may be interesting to external users.
*/
enum {
- GIT_DIFF_FILE_VALID_OID = (1 << 0),
- GIT_DIFF_FILE_FREE_PATH = (1 << 1),
- GIT_DIFF_FILE_BINARY = (1 << 2),
- GIT_DIFF_FILE_NOT_BINARY = (1 << 3),
- GIT_DIFF_FILE_FREE_DATA = (1 << 4),
- GIT_DIFF_FILE_UNMAP_DATA = (1 << 5),
- GIT_DIFF_FILE_NO_DATA = (1 << 6),
+ GIT_DIFF_FILE_VALID_OID = (1 << 0), /** `oid` value is known correct */
+ GIT_DIFF_FILE_FREE_PATH = (1 << 1), /** `path` is allocated memory */
+ GIT_DIFF_FILE_BINARY = (1 << 2), /** should be considered binary data */
+ GIT_DIFF_FILE_NOT_BINARY = (1 << 3), /** should be considered text data */
+ GIT_DIFF_FILE_FREE_DATA = (1 << 4), /** internal file data is allocated */
+ GIT_DIFF_FILE_UNMAP_DATA = (1 << 5), /** internal file data is mmap'ed */
+ GIT_DIFF_FILE_NO_DATA = (1 << 6), /** file data should not be loaded */
};
/**
@@ -116,7 +145,8 @@ typedef enum {
GIT_DELTA_RENAMED = 4,
GIT_DELTA_COPIED = 5,
GIT_DELTA_IGNORED = 6,
- GIT_DELTA_UNTRACKED = 7
+ GIT_DELTA_UNTRACKED = 7,
+ GIT_DELTA_TYPECHANGE = 8,
} git_delta_t;
/**
diff --git a/include/git2/status.h b/include/git2/status.h
index 0dd98596e..979e6e4ff 100644
--- a/include/git2/status.h
+++ b/include/git2/status.h
@@ -19,19 +19,22 @@
*/
GIT_BEGIN_DECL
-enum {
- GIT_STATUS_CURRENT = 0,
+typedef enum {
+ GIT_STATUS_CURRENT = 0,
- GIT_STATUS_INDEX_NEW = (1 << 0),
- GIT_STATUS_INDEX_MODIFIED = (1 << 1),
- GIT_STATUS_INDEX_DELETED = (1 << 2),
+ GIT_STATUS_INDEX_NEW = (1u << 0),
+ GIT_STATUS_INDEX_MODIFIED = (1u << 1),
+ GIT_STATUS_INDEX_DELETED = (1u << 2),
+ GIT_STATUS_INDEX_RENAMED = (1u << 3),
+ GIT_STATUS_INDEX_TYPECHANGE = (1u << 4),
- GIT_STATUS_WT_NEW = (1 << 3),
- GIT_STATUS_WT_MODIFIED = (1 << 4),
- GIT_STATUS_WT_DELETED = (1 << 5),
+ GIT_STATUS_WT_NEW = (1u << 7),
+ GIT_STATUS_WT_MODIFIED = (1u << 8),
+ GIT_STATUS_WT_DELETED = (1u << 9),
+ GIT_STATUS_WT_TYPECHANGE = (1u << 10),
- GIT_STATUS_IGNORED = (1 << 6),
-};
+ GIT_STATUS_IGNORED = (1u << 14),
+} git_status_t;
/**
* Gather file statuses and run a callback for each one.
diff --git a/include/git2/tree.h b/include/git2/tree.h
index e5261417c..2ee1f4afa 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -100,7 +100,7 @@ GIT_EXTERN(git_tree_entry *) git_tree_entry_dup(const git_tree_entry *entry);
* @param tree a previously loaded tree.
* @return object identity for the tree.
*/
-GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);
+GIT_EXTERN(const git_oid *) git_tree_id(const git_tree *tree);
/**
* Get the number of entries listed in a tree
@@ -108,7 +108,7 @@ GIT_EXTERN(const git_oid *) git_tree_id(git_tree *tree);
* @param tree a previously loaded tree.
* @return the number of entries in the tree
*/
-GIT_EXTERN(unsigned int) git_tree_entrycount(git_tree *tree);
+GIT_EXTERN(unsigned int) git_tree_entrycount(const git_tree *tree);
/**
* Lookup a tree entry by its filename
diff --git a/src/checkout.c b/src/checkout.c
index e429d2876..4782f7724 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -30,6 +30,9 @@ struct checkout_diff_data
git_indexer_stats *stats;
git_repository *owner;
bool can_symlink;
+ bool found_submodules;
+ bool create_submodules;
+ int error;
};
static int buffer_to_file(
@@ -39,18 +42,27 @@ static int buffer_to_file(
int file_open_flags,
mode_t file_mode)
{
- int fd, error_write, error_close;
+ int fd, error, error_close;
- if (git_futils_mkpath2file(path, dir_mode) < 0)
- return -1;
+ if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
+ return error;
if ((fd = p_open(path, file_open_flags, file_mode)) < 0)
- return -1;
+ return fd;
+
+ error = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer));
- error_write = p_write(fd, git_buf_cstr(buffer), git_buf_len(buffer));
error_close = p_close(fd);
- return error_write ? error_write : error_close;
+ if (!error)
+ error = error_close;
+
+ if (!error &&
+ (file_mode & 0100) != 0 &&
+ (error = p_chmod(path, file_mode)) < 0)
+ giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
+
+ return error;
}
static int blob_content_to_file(
@@ -84,7 +96,7 @@ static int blob_content_to_file(
return nb_filters;
if (nb_filters > 0) {
- if (git_blob__getbuf(&unfiltered, blob) < 0)
+ if ((error = git_blob__getbuf(&unfiltered, blob)) < 0)
goto cleanup;
if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0)
@@ -111,8 +123,8 @@ static int blob_content_to_link(git_blob *blob, const char *path, bool can_symli
git_buf linktarget = GIT_BUF_INIT;
int error;
- if (git_blob__getbuf(&linktarget, blob) < 0)
- return -1;
+ if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
+ return error;
if (can_symlink)
error = p_symlink(git_buf_cstr(&linktarget), path);
@@ -124,110 +136,126 @@ static int blob_content_to_link(git_blob *blob, const char *path, bool can_symli
return error;
}
+static int checkout_submodule(
+ struct checkout_diff_data *data,
+ const git_diff_file *file)
+{
+ if (git_futils_mkdir(
+ file->path, git_repository_workdir(data->owner),
+ data->checkout_opts->dir_mode, GIT_MKDIR_PATH) < 0)
+ return -1;
+
+ /* TODO: two cases:
+ * 1 - submodule already checked out, but we need to move the HEAD
+ * to the new OID, or
+ * 2 - submodule not checked out and we should recursively check it out
+ *
+ * Checkout will not execute a pull request on the submodule, but a
+ * clone command should probably be able to. Do we need a submodule
+ * callback option?
+ */
+
+ return 0;
+}
+
static int checkout_blob(
- git_repository *repo,
- const git_oid *blob_oid,
- const char *path,
- mode_t filemode,
- bool can_symlink,
- git_checkout_opts *opts)
+ struct checkout_diff_data *data,
+ const git_diff_file *file)
{
git_blob *blob;
int error;
- if (git_blob_lookup(&blob, repo, blob_oid) < 0)
- return -1; /* Add an error message */
+ git_buf_truncate(data->path, data->workdir_len);
+ if (git_buf_joinpath(data->path, git_buf_cstr(data->path), file->path) < 0)
+ return -1;
- if (S_ISLNK(filemode))
- error = blob_content_to_link(blob, path, can_symlink);
+ if ((error = git_blob_lookup(&blob, data->owner, &file->oid)) < 0)
+ return error;
+
+ if (S_ISLNK(file->mode))
+ error = blob_content_to_link(
+ blob, git_buf_cstr(data->path), data->can_symlink);
else
- error = blob_content_to_file(blob, path, filemode, opts);
+ error = blob_content_to_file(
+ blob, git_buf_cstr(data->path), file->mode, data->checkout_opts);
git_blob_free(blob);
return error;
}
-static int checkout_diff_fn(
- void *cb_data,
- const git_diff_delta *delta,
- float progress)
+static int checkout_remove_the_old(
+ void *cb_data, const git_diff_delta *delta, float progress)
{
- struct checkout_diff_data *data;
- int error = -1;
- git_checkout_opts *opts;
+ struct checkout_diff_data *data = cb_data;
+ git_checkout_opts *opts = data->checkout_opts;
- data = (struct checkout_diff_data *)cb_data;
+ GIT_UNUSED(progress);
+ data->stats->processed++;
- data->stats->processed = (unsigned int)(data->stats->total * progress);
-
- git_buf_truncate(data->path, data->workdir_len);
- if (git_buf_joinpath(data->path, git_buf_cstr(data->path), delta->new_file.path) < 0)
- return -1;
-
- opts = data->checkout_opts;
-
- switch (delta->status) {
- case GIT_DELTA_UNTRACKED:
- if (!(opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED))
- return 0;
-
- if (!git__suffixcmp(delta->new_file.path, "/"))
- error = git_futils_rmdir_r(git_buf_cstr(data->path), GIT_DIRREMOVAL_FILES_AND_DIRS);
- else
- error = p_unlink(git_buf_cstr(data->path));
- break;
-
- case GIT_DELTA_MODIFIED:
- if (!(opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED)) {
-
- if ((opts->skipped_notify_cb != NULL)
- && (opts->skipped_notify_cb(
- delta->new_file.path,
- &delta->old_file.oid,
- delta->old_file.mode,
- opts->notify_payload))) {
- giterr_clear();
- return GIT_EUSER;
- }
-
- return 0;
- }
-
- if (checkout_blob(
- data->owner,
- &delta->old_file.oid,
- git_buf_cstr(data->path),
- delta->old_file.mode,
- data->can_symlink,
- opts) < 0)
- goto cleanup;
-
- break;
-
- case GIT_DELTA_DELETED:
- if (!(opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING))
- return 0;
-
- if (checkout_blob(
- data->owner,
- &delta->old_file.oid,
- git_buf_cstr(data->path),
- delta->old_file.mode,
- data->can_symlink,
- opts) < 0)
- goto cleanup;
-
- break;
-
- default:
- giterr_set(GITERR_INVALID, "Unexpected status (%d) for path '%s'.", delta->status, delta->new_file.path);
- goto cleanup;
+ if ((delta->status == GIT_DELTA_UNTRACKED &&
+ (opts->checkout_strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0) ||
+ (delta->status == GIT_DELTA_TYPECHANGE &&
+ (opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0))
+ {
+ data->error = git_futils_rmdir_r(
+ delta->new_file.path,
+ git_repository_workdir(data->owner),
+ GIT_DIRREMOVAL_FILES_AND_DIRS);
}
- error = 0;
+ return data->error;
+}
+
+static int checkout_create_the_new(
+ void *cb_data, const git_diff_delta *delta, float progress)
+{
+ int error = 0;
+ struct checkout_diff_data *data = cb_data;
+ git_checkout_opts *opts = data->checkout_opts;
+ bool do_checkout = false, do_notify = false;
+
+ GIT_UNUSED(progress);
+ data->stats->processed++;
+
+ if (delta->status == GIT_DELTA_MODIFIED ||
+ delta->status == GIT_DELTA_TYPECHANGE)
+ {
+ if ((opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0)
+ do_checkout = true;
+ else if (opts->skipped_notify_cb != NULL)
+ do_notify = !data->create_submodules;
+ }
+ else if (delta->status == GIT_DELTA_DELETED &&
+ (opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING) != 0)
+ do_checkout = true;
+
+ if (do_notify) {
+ if (opts->skipped_notify_cb(
+ delta->old_file.path, &delta->old_file.oid,
+ delta->old_file.mode, opts->notify_payload))
+ {
+ giterr_clear();
+ error = GIT_EUSER;
+ }
+ }
+
+ if (do_checkout) {
+ bool is_submodule = S_ISGITLINK(delta->old_file.mode);
+
+ if (is_submodule)
+ data->found_submodules = true;
+
+ if (!is_submodule && !data->create_submodules)
+ error = checkout_blob(data, &delta->old_file);
+
+ else if (is_submodule && data->create_submodules)
+ error = checkout_submodule(data, &delta->old_file);
+ }
+
+ if (error)
+ data->error = error;
-cleanup:
return error;
}
@@ -279,7 +307,6 @@ int git_checkout_index(
git_checkout_opts *opts,
git_indexer_stats *stats)
{
- git_index *index = NULL;
git_diff_list *diff = NULL;
git_indexer_stats dummy_stats;
@@ -293,10 +320,13 @@ int git_checkout_index(
assert(repo);
- if ((git_repository__ensure_not_bare(repo, "checkout")) < 0)
- return GIT_EBAREREPO;
+ if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
+ return error;
- diff_opts.flags = GIT_DIFF_INCLUDE_UNTRACKED;
+ diff_opts.flags =
+ GIT_DIFF_INCLUDE_UNTRACKED |
+ GIT_DIFF_INCLUDE_TYPECHANGE |
+ GIT_DIFF_SKIP_BINARY_CHECK;
if (opts && opts->paths.count > 0)
diff_opts.pathspec = opts->paths;
@@ -313,11 +343,8 @@ int git_checkout_index(
stats = &dummy_stats;
stats->processed = 0;
-
- if ((git_repository_index(&index, repo)) < 0)
- goto cleanup;
-
- stats->total = git_index_entrycount(index);
+ /* total based on 3 passes, but it might be 2 if no submodules */
+ stats->total = (unsigned int)git_diff_num_deltas(diff) * 3;
memset(&data, 0, sizeof(data));
@@ -330,12 +357,36 @@ int git_checkout_index(
if ((error = retrieve_symlink_capabilities(repo, &data.can_symlink)) < 0)
goto cleanup;
- error = git_diff_foreach(diff, &data, checkout_diff_fn, NULL, NULL);
+ /* Checkout is best performed with three passes through the diff.
+ *
+ * 1. First do removes, because we iterate in alphabetical order, thus
+ * a new untracked directory will end up sorted *after* a blob that
+ * should be checked out with the same name.
+ * 2. Then checkout all blobs.
+ * 3. Then checkout all submodules in case a new .gitmodules blob was
+ * checked out during pass #2.
+ */
+
+ if (!(error = git_diff_foreach(
+ diff, &data, checkout_remove_the_old, NULL, NULL)) &&
+ !(error = git_diff_foreach(
+ diff, &data, checkout_create_the_new, NULL, NULL)) &&
+ data.found_submodules)
+ {
+ data.create_submodules = true;
+ error = git_diff_foreach(
+ diff, &data, checkout_create_the_new, NULL, NULL);
+ }
+
+ stats->processed = stats->total;
cleanup:
- git_index_free(index);
+ if (error == GIT_EUSER)
+ error = (data.error != 0) ? data.error : -1;
+
git_diff_list_free(diff);
git_buf_free(&workdir);
+
return error;
}
diff --git a/src/clone.c b/src/clone.c
index 82042a46a..85e69ad97 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -330,7 +330,7 @@ static int clone_internal(
if ((retcode = setup_remotes_and_fetch(repo, origin_url, fetch_stats)) < 0) {
/* Failed to fetch; clean up */
git_repository_free(repo);
- git_futils_rmdir_r(path, GIT_DIRREMOVAL_FILES_AND_DIRS);
+ git_futils_rmdir_r(path, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS);
} else {
*out = repo;
retcode = 0;
diff --git a/src/diff.c b/src/diff.c
index 8ab8af3a1..7f500b8e8 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -291,6 +291,36 @@ static int diff_delta__from_two(
return 0;
}
+static git_diff_delta *diff_delta__last_for_item(
+ git_diff_list *diff,
+ const git_index_entry *item)
+{
+ git_diff_delta *delta = git_vector_last(&diff->deltas);
+ if (!delta)
+ return NULL;
+
+ switch (delta->status) {
+ case GIT_DELTA_UNMODIFIED:
+ case GIT_DELTA_DELETED:
+ 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)
+ 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)
+ return delta;
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
static char *diff_strdup_prefix(git_pool *pool, const char *prefix)
{
size_t len = strlen(prefix);
@@ -368,6 +398,10 @@ static git_diff_list *git_diff_list_alloc(
diff->opts.new_prefix = swap;
}
+ /* INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */
+ if (diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE_TREES)
+ diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE;
+
/* only copy pathspec if it is "interesting" so we can test
* diff->pathspec.length > 0 to know if it is worth calling
* fnmatch as we iterate.
@@ -508,6 +542,7 @@ static int maybe_modified(
git_delta_t status = GIT_DELTA_MODIFIED;
unsigned int omode = oitem->mode;
unsigned int nmode = nitem->mode;
+ bool new_is_workdir = (new_iter->type == GIT_ITERATOR_WORKDIR);
GIT_UNUSED(old_iter);
@@ -515,15 +550,14 @@ static int maybe_modified(
return 0;
/* on platforms with no symlinks, preserve mode of existing symlinks */
- if (S_ISLNK(omode) && S_ISREG(nmode) &&
- !(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS) &&
- new_iter->type == GIT_ITERATOR_WORKDIR)
+ if (S_ISLNK(omode) && S_ISREG(nmode) && new_is_workdir &&
+ !(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS))
nmode = omode;
/* on platforms with no execmode, just preserve old mode */
if (!(diff->diffcaps & GIT_DIFFCAPS_TRUST_MODE_BITS) &&
(nmode & MODE_BITS_MASK) != (omode & MODE_BITS_MASK) &&
- new_iter->type == GIT_ITERATOR_WORKDIR)
+ new_is_workdir)
nmode = (nmode & ~MODE_BITS_MASK) | (omode & MODE_BITS_MASK);
/* support "assume unchanged" (poorly, b/c we still stat everything) */
@@ -537,10 +571,14 @@ static int maybe_modified(
/* if basic type of file changed, then split into delete and add */
else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) {
- if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
- diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0)
- return -1;
- return 0;
+ if ((diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE) != 0)
+ status = GIT_DELTA_TYPECHANGE;
+ else {
+ if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
+ diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0)
+ return -1;
+ return 0;
+ }
}
/* if oids and modes match, then file is unmodified */
@@ -551,9 +589,7 @@ static int maybe_modified(
/* if we have an unknown OID and a workdir iterator, then check some
* circumstances that can accelerate things or need special handling
*/
- else if (git_oid_iszero(&nitem->oid) &&
- new_iter->type == GIT_ITERATOR_WORKDIR)
- {
+ else if (git_oid_iszero(&nitem->oid) && new_is_workdir) {
/* TODO: add check against index file st_mtime to avoid racy-git */
/* if the stat data looks exactly alike, then assume the same */
@@ -588,7 +624,7 @@ static int maybe_modified(
/* grab OID while we are here */
if (git_oid_iszero(&nitem->oid)) {
const git_oid *sm_oid = git_submodule_wd_oid(sub);
- if (sub != NULL) {
+ if (sm_oid != NULL) {
git_oid_cpy(&noid, sm_oid);
use_noid = &noid;
}
@@ -600,7 +636,7 @@ static int maybe_modified(
/* if we got here and decided that the files are modified, but we
* haven't calculated the OID of the new item, then calculate it now
*/
- if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->oid)) {
+ if (status != GIT_DELTA_UNMODIFIED && git_oid_iszero(&nitem->oid)) {
if (oid_for_workdir_item(diff->repo, nitem, &noid) < 0)
return -1;
else if (omode == nmode && git_oid_equal(&oitem->oid, &noid))
@@ -630,6 +666,24 @@ static int git_index_entry_cmp_icase(const void *a, const void *b)
return strcasecmp(entry_a->path, entry_b->path);
}
+static bool entry_is_prefixed(
+ const git_index_entry *item,
+ git_iterator *prefix_iterator,
+ const git_index_entry *prefix_item)
+{
+ size_t pathlen;
+
+ if (!prefix_item ||
+ ITERATOR_PREFIXCMP(*prefix_iterator, prefix_item->path, item->path))
+ return false;
+
+ pathlen = strlen(item->path);
+
+ return (item->path[pathlen - 1] == '/' ||
+ prefix_item->path[pathlen] == '\0' ||
+ prefix_item->path[pathlen] == '/');
+}
+
static int diff_from_iterators(
git_repository *repo,
const git_diff_options *opts, /**< can be NULL for defaults */
@@ -679,8 +733,24 @@ static int diff_from_iterators(
/* create DELETED records for old items not matched in new */
if (oitem && (!nitem || entry_compare(oitem, nitem) < 0)) {
- if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
- git_iterator_advance(old_iter, &oitem) < 0)
+ if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0)
+ goto fail;
+
+ /* if we are generating TYPECHANGE records then check for that
+ * instead of just generating a DELETE record
+ */
+ if ((diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE_TREES) != 0 &&
+ entry_is_prefixed(oitem, new_iter, nitem))
+ {
+ /* 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;
+ }
+ }
+
+ if (git_iterator_advance(old_iter, &oitem) < 0)
goto fail;
}
@@ -702,8 +772,7 @@ static int diff_from_iterators(
* directories and it is not under an ignored directory.
*/
bool contains_tracked =
- (oitem &&
- !ITERATOR_PREFIXCMP(*old_iter, oitem->path, nitem->path));
+ entry_is_prefixed(nitem, old_iter, oitem);
bool recurse_untracked =
(delta_type == GIT_DELTA_UNTRACKED &&
(diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0);
@@ -759,8 +828,25 @@ static int diff_from_iterators(
else if (new_iter->type != GIT_ITERATOR_WORKDIR)
delta_type = GIT_DELTA_ADDED;
- if (diff_delta__from_one(diff, delta_type, nitem) < 0 ||
- git_iterator_advance(new_iter, &nitem) < 0)
+ if (diff_delta__from_one(diff, delta_type, nitem) < 0)
+ goto fail;
+
+ /* if we are generating TYPECHANGE records then check for that
+ * instead of just generating an ADD/UNTRACKED record
+ */
+ if (delta_type != GIT_DELTA_IGNORED &&
+ (diff->opts.flags & GIT_DIFF_INCLUDE_TYPECHANGE_TREES) != 0 &&
+ entry_is_prefixed(nitem, old_iter, oitem))
+ {
+ /* this entry was a tree! convert to TYPECHANGE */
+ git_diff_delta *last = diff_delta__last_for_item(diff, oitem);
+ if (last) {
+ last->status = GIT_DELTA_TYPECHANGE;
+ last->old_file.mode = GIT_FILEMODE_TREE;
+ }
+ }
+
+ if (git_iterator_advance(new_iter, &nitem) < 0)
goto fail;
}
diff --git a/src/diff.h b/src/diff.h
index 15745b2f3..c6a26aee7 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -28,17 +28,12 @@ enum {
GIT_DIFFCAPS_USE_DEV = (1 << 4), /* use st_dev? */
};
-typedef struct {
- git_refcount rc;
- git_diff_delta delta;
-} git_diff_delta_refcounted;
-
struct git_diff_list {
git_refcount rc;
git_repository *repo;
git_diff_options opts;
git_vector pathspec;
- git_vector deltas; /* vector of git_diff_delta_refcounted */
+ git_vector deltas; /* vector of git_diff_delta */
git_pool pool;
git_iterator_type_t old_src;
git_iterator_type_t new_src;
diff --git a/src/diff_output.c b/src/diff_output.c
index 10fbd391c..5f0d13c64 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -533,6 +533,11 @@ static int diff_patch_load(
if (delta->binary == 1)
goto cleanup;
+ if (!ctxt->hunk_cb &&
+ !ctxt->data_cb &&
+ (ctxt->opts->flags & GIT_DIFF_SKIP_BINARY_CHECK) != 0)
+ goto cleanup;
+
switch (delta->status) {
case GIT_DELTA_ADDED:
delta->old_file.flags |= GIT_DIFF_FILE_NO_DATA;
@@ -698,8 +703,10 @@ static int diff_patch_generate(
if ((patch->flags & GIT_DIFF_PATCH_DIFFABLE) == 0)
return 0;
- if (ctxt)
- patch->ctxt = ctxt;
+ if (!ctxt->file_cb && !ctxt->hunk_cb)
+ return 0;
+
+ patch->ctxt = ctxt;
memset(&xdiff_callback, 0, sizeof(xdiff_callback));
xdiff_callback.outf = diff_patch_cb;
@@ -1360,7 +1367,9 @@ int git_diff_get_patch(
if (delta_ptr)
*delta_ptr = delta;
- if (!patch_ptr && delta->binary != -1)
+ if (!patch_ptr &&
+ (delta->binary != -1 ||
+ (diff->opts.flags & GIT_DIFF_SKIP_BINARY_CHECK) != 0))
return 0;
diff_context_init(
diff --git a/src/fileops.c b/src/fileops.c
index 6abab8836..3f9e987f0 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -326,10 +326,6 @@ static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
{
git_directory_removal_type removal_type = *(git_directory_removal_type *)opaque;
- assert(removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY
- || removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS
- || removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS);
-
if (git_path_isdir(path->ptr) == true) {
if (git_path_direach(path, _rmdir_recurs_foreach, opaque) < 0)
return -1;
@@ -362,15 +358,24 @@ static int _rmdir_recurs_foreach(void *opaque, git_buf *path)
return 0;
}
-int git_futils_rmdir_r(const char *path, git_directory_removal_type removal_type)
+int git_futils_rmdir_r(
+ const char *path, const char *base, git_directory_removal_type removal_type)
{
int error;
- git_buf p = GIT_BUF_INIT;
+ git_buf fullpath = GIT_BUF_INIT;
+
+ assert(removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY
+ || removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS
+ || removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS);
+
+ /* build path and find "root" where we should start calling mkdir */
+ if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0)
+ return -1;
+
+ error = _rmdir_recurs_foreach(&removal_type, &fullpath);
+
+ git_buf_free(&fullpath);
- error = git_buf_sets(&p, path);
- if (!error)
- error = _rmdir_recurs_foreach(&removal_type, &p);
- git_buf_free(&p);
return error;
}
diff --git a/src/fileops.h b/src/fileops.h
index d2944f460..19f7ffd54 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -107,15 +107,17 @@ typedef enum {
* Remove path and any files and directories beneath it.
*
* @param path Path to to top level directory to process.
- *
+ * @param base Root for relative path.
* @param removal_type GIT_DIRREMOVAL_EMPTY_HIERARCHY to remove a hierarchy
- * of empty directories (will fail if any file is found), GIT_DIRREMOVAL_FILES_AND_DIRS
- * to remove a hierarchy of files and folders, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS to only remove
- * empty directories (no failure on file encounter).
+ * of empty directories (will fail if any file is found),
+ * GIT_DIRREMOVAL_FILES_AND_DIRS to remove a hierarchy of
+ * files and folders,
+ * GIT_DIRREMOVAL_ONLY_EMPTY_DIRS to only remove empty
+ * directories (no failure on file encounter).
*
* @return 0 on success; -1 on error.
*/
-extern int git_futils_rmdir_r(const char *path, git_directory_removal_type removal_type);
+extern int git_futils_rmdir_r(const char *path, const char *base, git_directory_removal_type removal_type);
/**
* Create and open a temporary file with a `_git2_` suffix.
diff --git a/src/iterator.c b/src/iterator.c
index 267687e01..df6da9a87 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -82,7 +82,7 @@ int git_iterator_for_nothing(git_iterator **iter)
typedef struct tree_iterator_frame tree_iterator_frame;
struct tree_iterator_frame {
- tree_iterator_frame *next;
+ tree_iterator_frame *next, *prev;
git_tree *tree;
char *start;
unsigned int index;
@@ -91,7 +91,7 @@ struct tree_iterator_frame {
typedef struct {
git_iterator base;
git_repository *repo;
- tree_iterator_frame *stack;
+ tree_iterator_frame *stack, *tail;
git_index_entry entry;
git_buf path;
bool path_has_filename;
@@ -119,8 +119,10 @@ static void tree_iterator__pop_frame(tree_iterator *ti)
{
tree_iterator_frame *tf = ti->stack;
ti->stack = tf->next;
- if (ti->stack != NULL) /* don't free the initial tree */
- git_tree_free(tf->tree);
+ if (ti->stack != NULL) {
+ git_tree_free(tf->tree); /* don't free the initial tree */
+ ti->stack->prev = NULL; /* disconnect prev */
+ }
git__free(tf);
}
@@ -221,6 +223,7 @@ static int tree_iterator__expand_tree(tree_iterator *ti)
tf->next = ti->stack;
ti->stack = tf;
+ tf->next->prev = tf;
te = tree_iterator__tree_entry(ti);
}
@@ -312,7 +315,7 @@ int git_iterator_for_tree_range(
ITERATOR_BASE_INIT(ti, tree, TREE);
ti->repo = repo;
- ti->stack = tree_iterator__alloc_frame(tree, ti->base.start);
+ ti->stack = ti->tail = tree_iterator__alloc_frame(tree, ti->base.start);
if ((error = tree_iterator__expand_tree(ti)) < 0)
git_iterator_free((git_iterator *)ti);
@@ -864,6 +867,45 @@ int git_iterator_current_tree_entry(
return 0;
}
+int git_iterator_current_parent_tree(
+ git_iterator *iter,
+ const char *parent_path,
+ const git_tree **tree_ptr)
+{
+ tree_iterator *ti = (tree_iterator *)iter;
+ tree_iterator_frame *tf;
+ const char *scan = parent_path;
+
+ if (iter->type != GIT_ITERATOR_TREE || ti->stack == NULL)
+ goto notfound;
+
+ for (tf = ti->tail; tf != NULL; tf = tf->prev) {
+ const git_tree_entry *te;
+
+ if (!*scan) {
+ *tree_ptr = tf->tree;
+ return 0;
+ }
+
+ te = git_tree_entry_byindex(tf->tree, tf->index);
+
+ if (strncmp(scan, te->filename, te->filename_len) != 0)
+ goto notfound;
+
+ scan += te->filename_len;
+
+ if (*scan) {
+ if (*scan != '/')
+ goto notfound;
+ scan++;
+ }
+ }
+
+notfound:
+ *tree_ptr = NULL;
+ return 0;
+}
+
int git_iterator_current_is_ignored(git_iterator *iter)
{
return (iter->type != GIT_ITERATOR_WORKDIR) ? 0 :
diff --git a/src/iterator.h b/src/iterator.h
index 29c8985d4..d7df50137 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -142,6 +142,9 @@ GIT_INLINE(git_iterator_type_t) git_iterator_type(git_iterator *iter)
extern int git_iterator_current_tree_entry(
git_iterator *iter, const git_tree_entry **tree_entry);
+extern int git_iterator_current_parent_tree(
+ git_iterator *iter, const char *parent_path, const git_tree **tree_ptr);
+
extern int git_iterator_current_is_ignored(git_iterator *iter);
/**
diff --git a/src/reflog.c b/src/reflog.c
index 80e40b960..a1ea7a27d 100644
--- a/src/reflog.c
+++ b/src/reflog.c
@@ -372,7 +372,7 @@ int git_reflog_rename(git_reference *ref, const char *new_name)
goto cleanup;
if (git_path_isdir(git_buf_cstr(&new_path)) &&
- (git_futils_rmdir_r(git_buf_cstr(&new_path), GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0))
+ (git_futils_rmdir_r(git_buf_cstr(&new_path), NULL, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0))
goto cleanup;
if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0)
diff --git a/src/refs.c b/src/refs.c
index 740d99eda..833f2fcc8 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -276,14 +276,15 @@ static int loose_write(git_reference *ref)
if (git_buf_joinpath(&ref_path, ref->owner->path_repository, ref->name) < 0)
return -1;
- /* Remove a possibly existing empty directory hierarchy
+ /* Remove a possibly existing empty directory hierarchy
* which name would collide with the reference name
*/
- if (git_path_isdir(git_buf_cstr(&ref_path)) &&
- (git_futils_rmdir_r(git_buf_cstr(&ref_path), GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0)) {
- git_buf_free(&ref_path);
- return -1;
- }
+ if (git_path_isdir(git_buf_cstr(&ref_path)) &&
+ git_futils_rmdir_r(git_buf_cstr(&ref_path), NULL,
+ GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0) {
+ git_buf_free(&ref_path);
+ return -1;
+ }
if (git_filebuf_open(&file, ref_path.ptr, GIT_FILEBUF_FORCE) < 0) {
git_buf_free(&ref_path);
diff --git a/src/status.c b/src/status.c
index a37653db4..f57100d11 100644
--- a/src/status.c
+++ b/src/status.c
@@ -25,7 +25,6 @@ static unsigned int index_delta2status(git_delta_t index_status)
switch (index_status) {
case GIT_DELTA_ADDED:
case GIT_DELTA_COPIED:
- case GIT_DELTA_RENAMED:
st = GIT_STATUS_INDEX_NEW;
break;
case GIT_DELTA_DELETED:
@@ -34,6 +33,12 @@ static unsigned int index_delta2status(git_delta_t index_status)
case GIT_DELTA_MODIFIED:
st = GIT_STATUS_INDEX_MODIFIED;
break;
+ case GIT_DELTA_RENAMED:
+ st = GIT_STATUS_INDEX_RENAMED;
+ break;
+ case GIT_DELTA_TYPECHANGE:
+ st = GIT_STATUS_INDEX_TYPECHANGE;
+ break;
default:
break;
}
@@ -47,8 +52,8 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status)
switch (workdir_status) {
case GIT_DELTA_ADDED:
- case GIT_DELTA_COPIED:
case GIT_DELTA_RENAMED:
+ case GIT_DELTA_COPIED:
case GIT_DELTA_UNTRACKED:
st = GIT_STATUS_WT_NEW;
break;
@@ -61,6 +66,9 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status)
case GIT_DELTA_IGNORED:
st = GIT_STATUS_IGNORED;
break;
+ case GIT_DELTA_TYPECHANGE:
+ st = GIT_STATUS_WT_TYPECHANGE;
+ break;
default:
break;
}
@@ -96,6 +104,8 @@ int git_status_foreach_ext(
memset(&diffopt, 0, sizeof(diffopt));
memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec));
+ diffopt.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
+
if ((opts->flags & GIT_STATUS_OPT_INCLUDE_UNTRACKED) != 0)
diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNTRACKED;
if ((opts->flags & GIT_STATUS_OPT_INCLUDE_IGNORED) != 0)
diff --git a/src/tree.c b/src/tree.c
index 83aa303d4..8d3f2665c 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -180,9 +180,9 @@ void git_tree__free(git_tree *tree)
git__free(tree);
}
-const git_oid *git_tree_id(git_tree *c)
+const git_oid *git_tree_id(const git_tree *c)
{
- return git_object_id((git_object *)c);
+ return git_object_id((const git_object *)c);
}
git_filemode_t git_tree_entry_filemode(const git_tree_entry *entry)
@@ -286,7 +286,7 @@ int git_tree__prefix_position(git_tree *tree, const char *path)
return at_pos;
}
-unsigned int git_tree_entrycount(git_tree *tree)
+unsigned int git_tree_entrycount(const git_tree *tree)
{
assert(tree);
return (unsigned int)tree->entries.length;
diff --git a/tests-clar/checkout/typechange.c b/tests-clar/checkout/typechange.c
new file mode 100644
index 000000000..f013617d5
--- /dev/null
+++ b/tests-clar/checkout/typechange.c
@@ -0,0 +1,72 @@
+#include "clar_libgit2.h"
+#include "git2/checkout.h"
+#include "path.h"
+#include "posix.h"
+
+static git_repository *g_repo = NULL;
+
+static const char *g_typechange_oids[] = {
+ "79b9f23e85f55ea36a472a902e875bc1121a94cb",
+ "9bdb75b73836a99e3dbeea640a81de81031fdc29",
+ "0e7ed140b514b8cae23254cb8656fe1674403aff",
+ "9d0235c7a7edc0889a18f97a42ee6db9fe688447",
+ "9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a",
+ "1b63caae4a5ca96f78e8dfefc376c6a39a142475",
+ "6eae26c90e8ccc4d16208972119c40635489c6f0",
+ NULL
+};
+
+static bool g_typechange_empty[] = {
+ true, false, false, false, false, false, true, true
+};
+
+void test_checkout_typechange__initialize(void)
+{
+ g_repo = cl_git_sandbox_init("typechanges");
+
+ cl_fixture_sandbox("submod2_target");
+ p_rename("submod2_target/.gitted", "submod2_target/.git");
+}
+
+void test_checkout_typechange__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+ cl_fixture_cleanup("submod2_target");
+}
+
+void test_checkout_typechange__checkout_typechanges(void)
+{
+ int i;
+ git_object *obj;
+ git_checkout_opts opts = {0};
+
+ opts.checkout_strategy =
+ GIT_CHECKOUT_REMOVE_UNTRACKED |
+ GIT_CHECKOUT_CREATE_MISSING |
+ GIT_CHECKOUT_OVERWRITE_MODIFIED;
+
+ for (i = 0; g_typechange_oids[i] != NULL; ++i) {
+ cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i]));
+ /* fprintf(stderr, "checking out '%s'\n", g_typechange_oids[i]); */
+
+ cl_git_pass(git_checkout_tree(g_repo, obj, &opts, NULL));
+
+ git_object_free(obj);
+
+ if (!g_typechange_empty[i]) {
+ cl_assert(git_path_isdir("typechanges"));
+ cl_assert(git_path_exists("typechanges/a"));
+ cl_assert(git_path_exists("typechanges/b"));
+ cl_assert(git_path_exists("typechanges/c"));
+ cl_assert(git_path_exists("typechanges/d"));
+ cl_assert(git_path_exists("typechanges/e"));
+ } else {
+ cl_assert(git_path_isdir("typechanges"));
+ cl_assert(!git_path_exists("typechanges/a"));
+ cl_assert(!git_path_exists("typechanges/b"));
+ cl_assert(!git_path_exists("typechanges/c"));
+ cl_assert(!git_path_exists("typechanges/d"));
+ cl_assert(!git_path_exists("typechanges/e"));
+ }
+ }
+}
diff --git a/tests-clar/core/copy.c b/tests-clar/core/copy.c
index 2fdfed863..d0b21f6ec 100644
--- a/tests-clar/core/copy.c
+++ b/tests-clar/core/copy.c
@@ -41,7 +41,7 @@ void test_core_copy__file_in_dir(void)
cl_assert(S_ISREG(st.st_mode));
cl_assert(strlen(content) == (size_t)st.st_size);
- cl_git_pass(git_futils_rmdir_r("an_dir", GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r("an_dir", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_assert(!git_path_isdir("an_dir"));
}
@@ -95,7 +95,7 @@ void test_core_copy__tree(void)
cl_assert(S_ISLNK(st.st_mode));
#endif
- cl_git_pass(git_futils_rmdir_r("t1", GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r("t1", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_assert(!git_path_isdir("t1"));
/* copy with empty dirs, no links, yes dotfiles, no overwrite */
@@ -119,8 +119,8 @@ void test_core_copy__tree(void)
cl_git_fail(git_path_lstat("t2/c/d/l1", &st));
#endif
- cl_git_pass(git_futils_rmdir_r("t2", GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r("t2", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_assert(!git_path_isdir("t2"));
- cl_git_pass(git_futils_rmdir_r("src", GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r("src", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
}
diff --git a/tests-clar/core/mkdir.c b/tests-clar/core/mkdir.c
index 08ba2419e..e5dc6654b 100644
--- a/tests-clar/core/mkdir.c
+++ b/tests-clar/core/mkdir.c
@@ -6,11 +6,11 @@
static void cleanup_basic_dirs(void *ref)
{
GIT_UNUSED(ref);
- git_futils_rmdir_r("d0", GIT_DIRREMOVAL_EMPTY_HIERARCHY);
- git_futils_rmdir_r("d1", GIT_DIRREMOVAL_EMPTY_HIERARCHY);
- git_futils_rmdir_r("d2", GIT_DIRREMOVAL_EMPTY_HIERARCHY);
- git_futils_rmdir_r("d3", GIT_DIRREMOVAL_EMPTY_HIERARCHY);
- git_futils_rmdir_r("d4", GIT_DIRREMOVAL_EMPTY_HIERARCHY);
+ git_futils_rmdir_r("d0", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY);
+ git_futils_rmdir_r("d1", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY);
+ git_futils_rmdir_r("d2", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY);
+ git_futils_rmdir_r("d3", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY);
+ git_futils_rmdir_r("d4", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY);
}
void test_core_mkdir__basic(void)
@@ -56,7 +56,7 @@ void test_core_mkdir__basic(void)
static void cleanup_basedir(void *ref)
{
GIT_UNUSED(ref);
- git_futils_rmdir_r("base", GIT_DIRREMOVAL_EMPTY_HIERARCHY);
+ git_futils_rmdir_r("base", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY);
}
void test_core_mkdir__with_base(void)
@@ -108,7 +108,7 @@ static void cleanup_chmod_root(void *ref)
git__free(mode);
}
- git_futils_rmdir_r("r", GIT_DIRREMOVAL_EMPTY_HIERARCHY);
+ git_futils_rmdir_r("r", NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY);
}
static void check_mode(mode_t expected, mode_t actual)
diff --git a/tests-clar/core/rmdir.c b/tests-clar/core/rmdir.c
index 530f1f908..9ada8f426 100644
--- a/tests-clar/core/rmdir.c
+++ b/tests-clar/core/rmdir.c
@@ -30,7 +30,7 @@ void test_core_rmdir__initialize(void)
/* make sure empty dir can be deleted recusively */
void test_core_rmdir__delete_recursive(void)
{
- cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
+ cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
}
/* make sure non-empty dir cannot be deleted recusively */
@@ -42,10 +42,10 @@ void test_core_rmdir__fail_to_delete_non_empty_dir(void)
cl_git_mkfile(git_buf_cstr(&file), "dummy");
- cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
+ cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
cl_must_pass(p_unlink(file.ptr));
- cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
+ cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_EMPTY_HIERARCHY));
git_buf_free(&file);
}
@@ -58,10 +58,10 @@ void test_core_rmdir__can_skip__non_empty_dir(void)
cl_git_mkfile(git_buf_cstr(&file), "dummy");
- cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS));
+ cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_ONLY_EMPTY_DIRS));
cl_assert(git_path_exists(git_buf_cstr(&file)) == true);
- cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_assert(git_path_exists(empty_tmp_dir) == false);
git_buf_free(&file);
diff --git a/tests-clar/diff/iterator.c b/tests-clar/diff/iterator.c
index cca6450d2..c2ab9940b 100644
--- a/tests-clar/diff/iterator.c
+++ b/tests-clar/diff/iterator.c
@@ -1,6 +1,7 @@
#include "clar_libgit2.h"
#include "diff_helpers.h"
#include "iterator.h"
+#include "tree.h"
void test_diff_iterator__initialize(void)
{
@@ -237,6 +238,103 @@ void test_diff_iterator__tree_range_empty_2(void)
NULL, ".aaa_empty_before", 0, NULL);
}
+static void check_tree_entry(
+ git_iterator *i,
+ const char *oid,
+ const char *oid_p,
+ const char *oid_pp,
+ const char *oid_ppp)
+{
+ const git_index_entry *ie;
+ const git_tree_entry *te;
+ const git_tree *tree;
+ git_buf path = GIT_BUF_INIT;
+
+ cl_git_pass(git_iterator_current_tree_entry(i, &te));
+ cl_assert(te);
+ cl_assert(git_oid_streq(&te->oid, oid) == 0);
+
+ cl_git_pass(git_iterator_current(i, &ie));
+ cl_git_pass(git_buf_sets(&path, ie->path));
+
+ if (oid_p) {
+ git_buf_rtruncate_at_char(&path, '/');
+ cl_git_pass(git_iterator_current_parent_tree(i, path.ptr, &tree));
+ cl_assert(tree);
+ cl_assert(git_oid_streq(git_tree_id(tree), oid_p) == 0);
+ }
+
+ if (oid_pp) {
+ git_buf_rtruncate_at_char(&path, '/');
+ cl_git_pass(git_iterator_current_parent_tree(i, path.ptr, &tree));
+ cl_assert(tree);
+ cl_assert(git_oid_streq(git_tree_id(tree), oid_pp) == 0);
+ }
+
+ if (oid_ppp) {
+ git_buf_rtruncate_at_char(&path, '/');
+ cl_git_pass(git_iterator_current_parent_tree(i, path.ptr, &tree));
+ cl_assert(tree);
+ cl_assert(git_oid_streq(git_tree_id(tree), oid_ppp) == 0);
+ }
+
+ git_buf_free(&path);
+}
+
+void test_diff_iterator__tree_special_functions(void)
+{
+ git_tree *t;
+ git_iterator *i;
+ const git_index_entry *entry;
+ git_repository *repo = cl_git_sandbox_init("attr");
+ int cases = 0;
+ const char *rootoid = "ce39a97a7fb1fa90bcf5e711249c1e507476ae0e";
+
+ t = resolve_commit_oid_to_tree(
+ repo, "24fa9a9fc4e202313e24b648087495441dab432b");
+ cl_assert(t != NULL);
+
+ cl_git_pass(git_iterator_for_tree_range(&i, repo, t, NULL, NULL));
+ cl_git_pass(git_iterator_current(i, &entry));
+
+ while (entry != NULL) {
+ if (strcmp(entry->path, "sub/file") == 0) {
+ cases++;
+ check_tree_entry(
+ i, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057",
+ "ecb97df2a174987475ac816e3847fc8e9f6c596b",
+ rootoid, NULL);
+ }
+ else if (strcmp(entry->path, "sub/sub/subsub.txt") == 0) {
+ cases++;
+ check_tree_entry(
+ i, "9e5bdc47d6a80f2be0ea3049ad74231b94609242",
+ "4e49ba8c5b6c32ff28cd9dcb60be34df50fcc485",
+ "ecb97df2a174987475ac816e3847fc8e9f6c596b", rootoid);
+ }
+ else if (strcmp(entry->path, "subdir/.gitattributes") == 0) {
+ cases++;
+ check_tree_entry(
+ i, "99eae476896f4907224978b88e5ecaa6c5bb67a9",
+ "9fb40b6675dde60b5697afceae91b66d908c02d9",
+ rootoid, NULL);
+ }
+ else if (strcmp(entry->path, "subdir2/subdir2_test1") == 0) {
+ cases++;
+ check_tree_entry(
+ i, "dccada462d3df8ac6de596fb8c896aba9344f941",
+ "2929de282ce999e95183aedac6451d3384559c4b",
+ rootoid, NULL);
+ }
+
+ cl_git_pass(git_iterator_advance(i, &entry));
+ }
+
+ cl_assert_equal_i(4, cases);
+ git_iterator_free(i);
+ git_tree_free(t);
+}
+
/* -- INDEX ITERATOR TESTS -- */
static void index_iterator_test(
diff --git a/tests-clar/object/blob/write.c b/tests-clar/object/blob/write.c
index 722c7b956..87a9e2072 100644
--- a/tests-clar/object/blob/write.c
+++ b/tests-clar/object/blob/write.c
@@ -49,7 +49,7 @@ void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolut
assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
git_buf_free(&full_path);
- cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
}
void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_filepath(void)
@@ -65,5 +65,5 @@ void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_fi
assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);
git_buf_free(&full_path);
- cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_must_pass(git_futils_rmdir_r(ELSEWHERE, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
}
diff --git a/tests-clar/repo/discover.c b/tests-clar/repo/discover.c
index b3d639bd1..b5afab75a 100644
--- a/tests-clar/repo/discover.c
+++ b/tests-clar/repo/discover.c
@@ -135,7 +135,7 @@ void test_repo_discover__0(void)
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB, ceiling_dirs, sub_repository_path);
ensure_repository_discover(REPOSITORY_ALTERNATE_FOLDER_SUB_SUB_SUB, ceiling_dirs, repository_path);
- cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
git_repository_free(repo);
git_buf_free(&ceiling_dirs_buf);
}
diff --git a/tests-clar/repo/open.c b/tests-clar/repo/open.c
index c70ec83a9..ef912fa0e 100644
--- a/tests-clar/repo/open.c
+++ b/tests-clar/repo/open.c
@@ -7,7 +7,7 @@ void test_repo_open__cleanup(void)
cl_git_sandbox_cleanup();
if (git_path_isdir("alternate"))
- git_futils_rmdir_r("alternate", GIT_DIRREMOVAL_FILES_AND_DIRS);
+ git_futils_rmdir_r("alternate", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS);
}
void test_repo_open__bare_empty_repo(void)
@@ -202,8 +202,8 @@ void test_repo_open__bad_gitlinks(void)
cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL));
}
- git_futils_rmdir_r("invalid", GIT_DIRREMOVAL_FILES_AND_DIRS);
- git_futils_rmdir_r("invalid2", GIT_DIRREMOVAL_FILES_AND_DIRS);
+ git_futils_rmdir_r("invalid", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS);
+ git_futils_rmdir_r("invalid2", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS);
}
#ifdef GIT_WIN32
diff --git a/tests-clar/resources/typechanges/.gitted/HEAD b/tests-clar/resources/typechanges/.gitted/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/typechanges/.gitted/config b/tests-clar/resources/typechanges/.gitted/config
new file mode 100644
index 000000000..4cc6e1ddf
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/config
@@ -0,0 +1,12 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
+[submodule "e"]
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git
+[submodule "d"]
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git
+[submodule "b"]
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git
diff --git a/tests-clar/resources/typechanges/.gitted/description b/tests-clar/resources/typechanges/.gitted/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/typechanges/.gitted/index b/tests-clar/resources/typechanges/.gitted/index
new file mode 100644
index 000000000..4f6d12a3b
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/index differ
diff --git a/tests-clar/resources/typechanges/.gitted/info/exclude b/tests-clar/resources/typechanges/.gitted/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/HEAD b/tests-clar/resources/typechanges/.gitted/modules/b/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/config b/tests-clar/resources/typechanges/.gitted/modules/b/config
new file mode 100644
index 000000000..f57cd4a6f
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../b
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/description b/tests-clar/resources/typechanges/.gitted/modules/b/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/index b/tests-clar/resources/typechanges/.gitted/modules/b/index
new file mode 100644
index 000000000..c16a026b7
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/index differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/info/exclude b/tests-clar/resources/typechanges/.gitted/modules/b/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/typechanges/.gitted/modules/b/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 000000000..f4b7094c5
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/typechanges/.gitted/modules/b/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 000000000..56c845e49
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/typechanges/.gitted/modules/b/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 000000000..bd179b5f5
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/typechanges/.gitted/modules/b/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 000000000..ccf49bd15
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/41/bd4bc3df978de695f67ace64c560913da11653 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/typechanges/.gitted/modules/b/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 000000000..53029069a
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/typechanges/.gitted/modules/b/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 000000000..38c791eba
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/5e/4963595a9774b90524d35a807169049de8ccad differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/typechanges/.gitted/modules/b/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 000000000..a26d29993
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic ԤpkΑ\S߇l@.^QpF(:D5zr~ en8
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/typechanges/.gitted/modules/b/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 000000000..83d1ba481
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/73/ba924a80437097795ae839e66e187c55d3babf differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/typechanges/.gitted/modules/b/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 000000000..6d27af8a8
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10Fa0p(N-ӡғq]>ks*? |mi@mV'`).-1x
+uxt(+
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/typechanges/.gitted/modules/b/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 000000000..17458840b
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x
0)?=
NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/typechanges/.gitted/modules/b/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 000000000..83cc29fb1
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/typechanges/.gitted/modules/b/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 000000000..55bda40ef
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/b/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/packed-refs b/tests-clar/resources/typechanges/.gitted/modules/b/packed-refs
new file mode 100644
index 000000000..5a4ebc47c
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/refs/heads/master b/tests-clar/resources/typechanges/.gitted/modules/b/refs/heads/master
new file mode 100644
index 000000000..e12c44d7a
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/typechanges/.gitted/modules/b/refs/remotes/origin/HEAD b/tests-clar/resources/typechanges/.gitted/modules/b/refs/remotes/origin/HEAD
new file mode 100644
index 000000000..6efe28fff
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/b/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/HEAD b/tests-clar/resources/typechanges/.gitted/modules/d/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/config b/tests-clar/resources/typechanges/.gitted/modules/d/config
new file mode 100644
index 000000000..42e1bddda
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../d
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/description b/tests-clar/resources/typechanges/.gitted/modules/d/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/index b/tests-clar/resources/typechanges/.gitted/modules/d/index
new file mode 100644
index 000000000..86d0266e8
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/index differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/info/exclude b/tests-clar/resources/typechanges/.gitted/modules/d/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/typechanges/.gitted/modules/d/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 000000000..f4b7094c5
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/typechanges/.gitted/modules/d/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 000000000..56c845e49
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/typechanges/.gitted/modules/d/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 000000000..bd179b5f5
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/typechanges/.gitted/modules/d/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 000000000..ccf49bd15
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/41/bd4bc3df978de695f67ace64c560913da11653 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/typechanges/.gitted/modules/d/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 000000000..53029069a
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/typechanges/.gitted/modules/d/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 000000000..38c791eba
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/5e/4963595a9774b90524d35a807169049de8ccad differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/typechanges/.gitted/modules/d/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 000000000..a26d29993
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic ԤpkΑ\S߇l@.^QpF(:D5zr~ en8
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/typechanges/.gitted/modules/d/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 000000000..83d1ba481
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/73/ba924a80437097795ae839e66e187c55d3babf differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/typechanges/.gitted/modules/d/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 000000000..6d27af8a8
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10Fa0p(N-ӡғq]>ks*? |mi@mV'`).-1x
+uxt(+
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/typechanges/.gitted/modules/d/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 000000000..17458840b
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x
0)?=
NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/typechanges/.gitted/modules/d/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 000000000..83cc29fb1
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/typechanges/.gitted/modules/d/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 000000000..55bda40ef
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/d/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/packed-refs b/tests-clar/resources/typechanges/.gitted/modules/d/packed-refs
new file mode 100644
index 000000000..5a4ebc47c
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/refs/heads/master b/tests-clar/resources/typechanges/.gitted/modules/d/refs/heads/master
new file mode 100644
index 000000000..e12c44d7a
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/typechanges/.gitted/modules/d/refs/remotes/origin/HEAD b/tests-clar/resources/typechanges/.gitted/modules/d/refs/remotes/origin/HEAD
new file mode 100644
index 000000000..6efe28fff
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/d/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/HEAD b/tests-clar/resources/typechanges/.gitted/modules/e/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/config b/tests-clar/resources/typechanges/.gitted/modules/e/config
new file mode 100644
index 000000000..89b3b9b4f
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/config
@@ -0,0 +1,13 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ worktree = ../../../e
+ ignorecase = true
+[remote "origin"]
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ url = /Users/rb/src/libgit2/tests-clar/resources/submod2_target/.git
+[branch "master"]
+ remote = origin
+ merge = refs/heads/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/description b/tests-clar/resources/typechanges/.gitted/modules/e/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/index b/tests-clar/resources/typechanges/.gitted/modules/e/index
new file mode 100644
index 000000000..cd6e2da6c
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/index differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/info/exclude b/tests-clar/resources/typechanges/.gitted/modules/e/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 b/tests-clar/resources/typechanges/.gitted/modules/e/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1
new file mode 100644
index 000000000..f4b7094c5
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/06/362fe2fdb7010d0e447b4fb450d405420479a1 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 b/tests-clar/resources/typechanges/.gitted/modules/e/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484
new file mode 100644
index 000000000..56c845e49
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/0e/6a3ca48bd47cfe67681acf39aa0b10a0b92484 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 b/tests-clar/resources/typechanges/.gitted/modules/e/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5
new file mode 100644
index 000000000..bd179b5f5
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/17/d0ece6e96460a06592d9d9d000de37ba4232c5 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/41/bd4bc3df978de695f67ace64c560913da11653 b/tests-clar/resources/typechanges/.gitted/modules/e/objects/41/bd4bc3df978de695f67ace64c560913da11653
new file mode 100644
index 000000000..ccf49bd15
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/41/bd4bc3df978de695f67ace64c560913da11653 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 b/tests-clar/resources/typechanges/.gitted/modules/e/objects/48/0095882d281ed676fe5b863569520e54a7d5c0
new file mode 100644
index 000000000..53029069a
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/48/0095882d281ed676fe5b863569520e54a7d5c0 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/5e/4963595a9774b90524d35a807169049de8ccad b/tests-clar/resources/typechanges/.gitted/modules/e/objects/5e/4963595a9774b90524d35a807169049de8ccad
new file mode 100644
index 000000000..38c791eba
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/5e/4963595a9774b90524d35a807169049de8ccad differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/6b/31c659545507c381e9cd34ec508f16c04e149e b/tests-clar/resources/typechanges/.gitted/modules/e/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
new file mode 100644
index 000000000..a26d29993
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/objects/6b/31c659545507c381e9cd34ec508f16c04e149e
@@ -0,0 +1,2 @@
+xQ
+!Evoy*_@g#hOh^9wSòf1*[Ic ԤpkΑ\S߇l@.^QpF(:D5zr~ en8
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/73/ba924a80437097795ae839e66e187c55d3babf b/tests-clar/resources/typechanges/.gitted/modules/e/objects/73/ba924a80437097795ae839e66e187c55d3babf
new file mode 100644
index 000000000..83d1ba481
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/73/ba924a80437097795ae839e66e187c55d3babf differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a b/tests-clar/resources/typechanges/.gitted/modules/e/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
new file mode 100644
index 000000000..6d27af8a8
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/objects/78/0d7397f5e8f8f477fb55b7af3accc2154b2d4a
@@ -0,0 +1,2 @@
+x-10Fa0p(N-ӡғq]>ks*? |mi@mV'`).-1x
+uxt(+
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/78/9efbdadaa4a582778d4584385495559ea0994b b/tests-clar/resources/typechanges/.gitted/modules/e/objects/78/9efbdadaa4a582778d4584385495559ea0994b
new file mode 100644
index 000000000..17458840b
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/objects/78/9efbdadaa4a582778d4584385495559ea0994b
@@ -0,0 +1,2 @@
+x
0)?=
NlOkj8&r
+qJW7B<fK8#Q1C-"e̫>'@
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e b/tests-clar/resources/typechanges/.gitted/modules/e/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e
new file mode 100644
index 000000000..83cc29fb1
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/88/34b635dd468a83cb012f6feace968c1c9f5d6e differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 b/tests-clar/resources/typechanges/.gitted/modules/e/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5
new file mode 100644
index 000000000..55bda40ef
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/modules/e/objects/d0/5f2cd5cc77addf68ed6f50d622c9a4f732e6c5 differ
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/packed-refs b/tests-clar/resources/typechanges/.gitted/modules/e/packed-refs
new file mode 100644
index 000000000..5a4ebc47c
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/packed-refs
@@ -0,0 +1,2 @@
+# pack-refs with: peeled
+480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/refs/heads/master b/tests-clar/resources/typechanges/.gitted/modules/e/refs/heads/master
new file mode 100644
index 000000000..e12c44d7a
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/refs/heads/master
@@ -0,0 +1 @@
+480095882d281ed676fe5b863569520e54a7d5c0
diff --git a/tests-clar/resources/typechanges/.gitted/modules/e/refs/remotes/origin/HEAD b/tests-clar/resources/typechanges/.gitted/modules/e/refs/remotes/origin/HEAD
new file mode 100644
index 000000000..6efe28fff
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/modules/e/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/tests-clar/resources/typechanges/.gitted/objects/0d/78578795b7ca49fd8df6c4b6d27c5c02d991d8 b/tests-clar/resources/typechanges/.gitted/objects/0d/78578795b7ca49fd8df6c4b6d27c5c02d991d8
new file mode 100644
index 000000000..f2d02f4f7
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/0d/78578795b7ca49fd8df6c4b6d27c5c02d991d8 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/0e/7ed140b514b8cae23254cb8656fe1674403aff b/tests-clar/resources/typechanges/.gitted/objects/0e/7ed140b514b8cae23254cb8656fe1674403aff
new file mode 100644
index 000000000..527964c92
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/0e/7ed140b514b8cae23254cb8656fe1674403aff differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/0f/f461da9689266f482d8f6654a4400b4e33c586 b/tests-clar/resources/typechanges/.gitted/objects/0f/f461da9689266f482d8f6654a4400b4e33c586
new file mode 100644
index 000000000..2694e4fa0
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/0f/f461da9689266f482d8f6654a4400b4e33c586 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/18/aa7e45bbe4c3cc24a0b079696c59d36675af97 b/tests-clar/resources/typechanges/.gitted/objects/18/aa7e45bbe4c3cc24a0b079696c59d36675af97
new file mode 100644
index 000000000..032a960b4
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/18/aa7e45bbe4c3cc24a0b079696c59d36675af97 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/1b/63caae4a5ca96f78e8dfefc376c6a39a142475 b/tests-clar/resources/typechanges/.gitted/objects/1b/63caae4a5ca96f78e8dfefc376c6a39a142475
new file mode 100644
index 000000000..d32622e67
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/1b/63caae4a5ca96f78e8dfefc376c6a39a142475 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/1e/abe82aa3b2365a394f6108f24435df6e193d02 b/tests-clar/resources/typechanges/.gitted/objects/1e/abe82aa3b2365a394f6108f24435df6e193d02
new file mode 100644
index 000000000..42d5f92f3
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/1e/abe82aa3b2365a394f6108f24435df6e193d02 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/42/061c01a1c70097d1e4579f29a5adf40abdec95 b/tests-clar/resources/typechanges/.gitted/objects/42/061c01a1c70097d1e4579f29a5adf40abdec95
new file mode 100644
index 000000000..0a8f32e15
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/42/061c01a1c70097d1e4579f29a5adf40abdec95 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/46/2838cee476a87e7cff32196b66fa18ed756592 b/tests-clar/resources/typechanges/.gitted/objects/46/2838cee476a87e7cff32196b66fa18ed756592
new file mode 100644
index 000000000..52af51f74
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/46/2838cee476a87e7cff32196b66fa18ed756592 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/63/499e4ea8e096b831515ceb1d5a7593e4d87ae5 b/tests-clar/resources/typechanges/.gitted/objects/63/499e4ea8e096b831515ceb1d5a7593e4d87ae5
new file mode 100644
index 000000000..afafa89f4
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/63/499e4ea8e096b831515ceb1d5a7593e4d87ae5 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/68/1af94e10eaf262f3ab7cb9b8fd5f4158ba4d3e b/tests-clar/resources/typechanges/.gitted/objects/68/1af94e10eaf262f3ab7cb9b8fd5f4158ba4d3e
new file mode 100644
index 000000000..9e518fc28
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/68/1af94e10eaf262f3ab7cb9b8fd5f4158ba4d3e differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/6a/9008602b811e69a9b7a2d83496f39a794fdeeb b/tests-clar/resources/typechanges/.gitted/objects/6a/9008602b811e69a9b7a2d83496f39a794fdeeb
new file mode 100644
index 000000000..a245727a1
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/6a/9008602b811e69a9b7a2d83496f39a794fdeeb differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/6e/ae26c90e8ccc4d16208972119c40635489c6f0 b/tests-clar/resources/typechanges/.gitted/objects/6e/ae26c90e8ccc4d16208972119c40635489c6f0
new file mode 100644
index 000000000..ea35cd311
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/6e/ae26c90e8ccc4d16208972119c40635489c6f0 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/6f/39eabbb8a7541515e0d35971078bccb502e7e0 b/tests-clar/resources/typechanges/.gitted/objects/6f/39eabbb8a7541515e0d35971078bccb502e7e0
new file mode 100644
index 000000000..c54817598
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/6f/39eabbb8a7541515e0d35971078bccb502e7e0 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/71/54d3083461536dfc71ad5542f3e65e723a06c4 b/tests-clar/resources/typechanges/.gitted/objects/71/54d3083461536dfc71ad5542f3e65e723a06c4
new file mode 100644
index 000000000..9fdd8f245
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/71/54d3083461536dfc71ad5542f3e65e723a06c4 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/75/56c1d893a4c0ca85ac8ac51de47ff399758729 b/tests-clar/resources/typechanges/.gitted/objects/75/56c1d893a4c0ca85ac8ac51de47ff399758729
new file mode 100644
index 000000000..d43630f44
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/75/56c1d893a4c0ca85ac8ac51de47ff399758729 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/76/fef844064c26d5e06c2508240dae661e7231b2 b/tests-clar/resources/typechanges/.gitted/objects/76/fef844064c26d5e06c2508240dae661e7231b2
new file mode 100644
index 000000000..355ce4b5b
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/76/fef844064c26d5e06c2508240dae661e7231b2 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/79/b9f23e85f55ea36a472a902e875bc1121a94cb b/tests-clar/resources/typechanges/.gitted/objects/79/b9f23e85f55ea36a472a902e875bc1121a94cb
new file mode 100644
index 000000000..2b07ad256
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/objects/79/b9f23e85f55ea36a472a902e875bc1121a94cb
@@ -0,0 +1,2 @@
+xA E]sfJbq`I@
+yH;ZeBr6LPY%8&v4Jm֢^*qpJµ;Z
Ơ3ZD1)"%%38_
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/objects/85/28da0ea65eacf1f74f9ed6696adbac547963ad b/tests-clar/resources/typechanges/.gitted/objects/85/28da0ea65eacf1f74f9ed6696adbac547963ad
new file mode 100644
index 000000000..6d2da6c93
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/85/28da0ea65eacf1f74f9ed6696adbac547963ad differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/8b/3726b365824ad5a07c537247f4bc73ed7d37ea b/tests-clar/resources/typechanges/.gitted/objects/8b/3726b365824ad5a07c537247f4bc73ed7d37ea
new file mode 100644
index 000000000..3dc333bc6
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/8b/3726b365824ad5a07c537247f4bc73ed7d37ea differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/93/3e28c1c8a68838a763d250bdf0b2c6068289c3 b/tests-clar/resources/typechanges/.gitted/objects/93/3e28c1c8a68838a763d250bdf0b2c6068289c3
new file mode 100644
index 000000000..02ad0e97a
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/93/3e28c1c8a68838a763d250bdf0b2c6068289c3 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/96/2710fe5b4e453e9e827945b3487c525968ec4a b/tests-clar/resources/typechanges/.gitted/objects/96/2710fe5b4e453e9e827945b3487c525968ec4a
new file mode 100644
index 000000000..d06b06a52
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/96/2710fe5b4e453e9e827945b3487c525968ec4a differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/96/6cf1b3598e195b31b2cde3784f9a19f0728a6f b/tests-clar/resources/typechanges/.gitted/objects/96/6cf1b3598e195b31b2cde3784f9a19f0728a6f
new file mode 100644
index 000000000..5f9ffd4ed
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/96/6cf1b3598e195b31b2cde3784f9a19f0728a6f differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/99/e8bab9ece009f0fba7eb41f850f4c12bedb9b7 b/tests-clar/resources/typechanges/.gitted/objects/99/e8bab9ece009f0fba7eb41f850f4c12bedb9b7
new file mode 100644
index 000000000..ac17defac
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/99/e8bab9ece009f0fba7eb41f850f4c12bedb9b7 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/9b/19edf33a03a0c59cdfc113bfa5c06179bf9b1a b/tests-clar/resources/typechanges/.gitted/objects/9b/19edf33a03a0c59cdfc113bfa5c06179bf9b1a
new file mode 100644
index 000000000..7ab83aefe
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/objects/9b/19edf33a03a0c59cdfc113bfa5c06179bf9b1a
@@ -0,0 +1,5 @@
+xI
+1E]LT
AJЃ7WpyӶ,ZѩUf cXcR C43Y2"NN:HɈo6,sjf#kG
+cys
+MGm2B
+.K)k֑w8CC
\ No newline at end of file
diff --git a/tests-clar/resources/typechanges/.gitted/objects/9b/db75b73836a99e3dbeea640a81de81031fdc29 b/tests-clar/resources/typechanges/.gitted/objects/9b/db75b73836a99e3dbeea640a81de81031fdc29
new file mode 100644
index 000000000..aed4d8165
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/9b/db75b73836a99e3dbeea640a81de81031fdc29 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/9d/0235c7a7edc0889a18f97a42ee6db9fe688447 b/tests-clar/resources/typechanges/.gitted/objects/9d/0235c7a7edc0889a18f97a42ee6db9fe688447
new file mode 100644
index 000000000..3e02a41b2
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/9d/0235c7a7edc0889a18f97a42ee6db9fe688447 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/9e/ffc457877f109b2a4319e14bee613a15f2a00d b/tests-clar/resources/typechanges/.gitted/objects/9e/ffc457877f109b2a4319e14bee613a15f2a00d
new file mode 100644
index 000000000..fb24100fc
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/9e/ffc457877f109b2a4319e14bee613a15f2a00d differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/a0/a9bad6f6f40325198f938a0e3ae981622d7707 b/tests-clar/resources/typechanges/.gitted/objects/a0/a9bad6f6f40325198f938a0e3ae981622d7707
new file mode 100644
index 000000000..b6b7db785
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/a0/a9bad6f6f40325198f938a0e3ae981622d7707 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/b1/977dc4e573b812d4619754c98138c56999dc0d b/tests-clar/resources/typechanges/.gitted/objects/b1/977dc4e573b812d4619754c98138c56999dc0d
new file mode 100644
index 000000000..e1334057c
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/b1/977dc4e573b812d4619754c98138c56999dc0d differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/d7/5992dd02391e128dac332dcc78d649dd9ab095 b/tests-clar/resources/typechanges/.gitted/objects/d7/5992dd02391e128dac332dcc78d649dd9ab095
new file mode 100644
index 000000000..65f1f530f
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/d7/5992dd02391e128dac332dcc78d649dd9ab095 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/da/e2709d638df52212b1f43ff61797ebfedfcc7c b/tests-clar/resources/typechanges/.gitted/objects/da/e2709d638df52212b1f43ff61797ebfedfcc7c
new file mode 100644
index 000000000..355faa61f
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/da/e2709d638df52212b1f43ff61797ebfedfcc7c differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/e1/152adcb9adf37ec551ada9ba377ab53aec3bad b/tests-clar/resources/typechanges/.gitted/objects/e1/152adcb9adf37ec551ada9ba377ab53aec3bad
new file mode 100644
index 000000000..c68fdcfab
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/e1/152adcb9adf37ec551ada9ba377ab53aec3bad differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/e4/ed436a9eb0f198cda722886a5f8d6d6c836b7b b/tests-clar/resources/typechanges/.gitted/objects/e4/ed436a9eb0f198cda722886a5f8d6d6c836b7b
new file mode 100644
index 000000000..c9229ba25
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/e4/ed436a9eb0f198cda722886a5f8d6d6c836b7b differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/tests-clar/resources/typechanges/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644
index 000000000..711223894
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/f2/0b79342712e0b2315647cd8227a573fd3bc46e b/tests-clar/resources/typechanges/.gitted/objects/f2/0b79342712e0b2315647cd8227a573fd3bc46e
new file mode 100644
index 000000000..3962ba6b4
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/f2/0b79342712e0b2315647cd8227a573fd3bc46e differ
diff --git a/tests-clar/resources/typechanges/.gitted/objects/fd/e0147e3b59f381635a3b016e3fe6dacb70779d b/tests-clar/resources/typechanges/.gitted/objects/fd/e0147e3b59f381635a3b016e3fe6dacb70779d
new file mode 100644
index 000000000..e3663da9f
Binary files /dev/null and b/tests-clar/resources/typechanges/.gitted/objects/fd/e0147e3b59f381635a3b016e3fe6dacb70779d differ
diff --git a/tests-clar/resources/typechanges/.gitted/refs/heads/master b/tests-clar/resources/typechanges/.gitted/refs/heads/master
new file mode 100644
index 000000000..546481a33
--- /dev/null
+++ b/tests-clar/resources/typechanges/.gitted/refs/heads/master
@@ -0,0 +1 @@
+6eae26c90e8ccc4d16208972119c40635489c6f0
diff --git a/tests-clar/resources/typechanges/README.md b/tests-clar/resources/typechanges/README.md
new file mode 100644
index 000000000..1f5a95a9f
--- /dev/null
+++ b/tests-clar/resources/typechanges/README.md
@@ -0,0 +1,43 @@
+This is a test repo for libgit2 where tree entries have type changes
+
+Types
+-----
+
+The key types that could be found in tree entries are:
+
+1. GIT_FILEMODE_NEW = 0000000 (i.e. file does not exist)
+2. GIT_FILEMODE_TREE = 0040000
+3. GIT_FILEMODE_BLOB = 0100644
+4. GIT_FILEMODE_BLOB_EXECUTABLE = 0100755
+5. GIT_FILEMODE_LINK = 0120000
+6. GIT_FILEMODE_COMMIT = 0160000
+
+I will try to have every type of transition somewhere in the history
+of this repo.
+
+Commits
+-------
+
+* `a(1--1) b(1--1) c(1--1) d(1--1) e(1--1)`
+ **Initial commit**
+ `79b9f23e85f55ea36a472a902e875bc1121a94cb`
+* `a(1->2) b(1->3) c(1->4) d(1->5) e(1->6)`
+ **Create content**
+ `9bdb75b73836a99e3dbeea640a81de81031fdc29`
+* `a(2->3) b(3->4) c(4->5) d(5->6) e(6->2)`
+ **Changes #1**
+ `0e7ed140b514b8cae23254cb8656fe1674403aff`
+* `a(3->5) b(4->6) c(5->2) d(6->3) e(2->4)`
+ **Changes #2**
+ `9d0235c7a7edc0889a18f97a42ee6db9fe688447`
+* `a(5->3) b(6->4) c(2->5) d(3->6) e(4->2)`
+ **Changes #3**
+ `9b19edf33a03a0c59cdfc113bfa5c06179bf9b1a`
+* `a(3->2) b(4->3) c(5->4) d(6->5) e(2->6)`
+ **Changes #4**
+ `1b63caae4a5ca96f78e8dfefc376c6a39a142475`
+ Matches **Changes #1** except README.md
+* `a(2->1) b(3->1) c(4->1) d(5->1) e(6->1)`
+ **Changes #5**
+ `6eae26c90e8ccc4d16208972119c40635489c6f0`
+ Matches **Initial commit** except README.md and .gitmodules
diff --git a/tests-clar/resources/typechanges/gitmodules b/tests-clar/resources/typechanges/gitmodules
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c
index 0ceba7f16..4f03643c0 100644
--- a/tests-clar/status/worktree.c
+++ b/tests-clar/status/worktree.c
@@ -71,7 +71,7 @@ static int remove_file_cb(void *data, git_buf *file)
return 0;
if (git_path_isdir(filename))
- cl_git_pass(git_futils_rmdir_r(filename, GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(filename, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
else
cl_git_pass(p_unlink(git_buf_cstr(file)));
@@ -314,7 +314,7 @@ void test_status_worktree__issue_592_3(void)
repo = cl_git_sandbox_init("issue_592");
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "c"));
- cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_git_pass(git_status_foreach(repo, cb_status__check_592, "c/a.txt"));
@@ -344,7 +344,7 @@ void test_status_worktree__issue_592_5(void)
repo = cl_git_sandbox_init("issue_592");
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(repo), "t"));
- cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_git_pass(p_mkdir(git_buf_cstr(&path), 0777));
cl_git_pass(git_status_foreach(repo, cb_status__check_592, NULL));
diff --git a/tests-clar/submodule/status.c b/tests-clar/submodule/status.c
index d3a39235a..63073ceca 100644
--- a/tests-clar/submodule/status.c
+++ b/tests-clar/submodule/status.c
@@ -50,7 +50,7 @@ void test_submodule_status__ignore_none(void)
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
- cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_git_fail(git_submodule_lookup(&sm, g_repo, "not_submodule"));
@@ -135,7 +135,7 @@ void test_submodule_status__ignore_untracked(void)
git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
- cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
@@ -195,7 +195,7 @@ void test_submodule_status__ignore_dirty(void)
git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
- cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));
@@ -255,7 +255,7 @@ void test_submodule_status__ignore_all(void)
git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged"));
- cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), GIT_DIRREMOVAL_FILES_AND_DIRS));
+ cl_git_pass(git_futils_rmdir_r(git_buf_cstr(&path), NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
cl_git_pass(git_submodule_foreach(g_repo, set_sm_ignore, &ign));