mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-02 19:32:23 +00:00
Merge pull request #968 from arrbee/diff-support-typechange
Support TYPECHANGE records in status and adjust checkout accordingly
This commit is contained in:
commit
4c47a8bcfe
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
261
src/checkout.c
261
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
124
src/diff.c
124
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 :
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
13
src/refs.c
13
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);
|
||||
|
14
src/status.c
14
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)
|
||||
|
@ -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;
|
||||
|
72
tests-clar/checkout/typechange.c
Normal file
72
tests-clar/checkout/typechange.c
Normal file
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
1
tests-clar/resources/typechanges/.gitted/HEAD
Normal file
1
tests-clar/resources/typechanges/.gitted/HEAD
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
12
tests-clar/resources/typechanges/.gitted/config
Normal file
12
tests-clar/resources/typechanges/.gitted/config
Normal file
@ -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
|
1
tests-clar/resources/typechanges/.gitted/description
Normal file
1
tests-clar/resources/typechanges/.gitted/description
Normal file
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
tests-clar/resources/typechanges/.gitted/index
Normal file
BIN
tests-clar/resources/typechanges/.gitted/index
Normal file
Binary file not shown.
6
tests-clar/resources/typechanges/.gitted/info/exclude
Normal file
6
tests-clar/resources/typechanges/.gitted/info/exclude
Normal file
@ -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]
|
||||
# *~
|
1
tests-clar/resources/typechanges/.gitted/modules/b/HEAD
Normal file
1
tests-clar/resources/typechanges/.gitted/modules/b/HEAD
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
13
tests-clar/resources/typechanges/.gitted/modules/b/config
Normal file
13
tests-clar/resources/typechanges/.gitted/modules/b/config
Normal file
@ -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
|
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
tests-clar/resources/typechanges/.gitted/modules/b/index
Normal file
BIN
tests-clar/resources/typechanges/.gitted/modules/b/index
Normal file
Binary file not shown.
@ -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]
|
||||
# *~
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x•<>Q
|
||||
!EϋvoΕΣy*Ρ_Ών@Ηg#h‚£ϋOhύ^Ξ9w«¥¤<0E>κSoΜ€f1*²<>Α[”<18>‰¬§θIc Τ¤<CEA4>μκ¤p£οµΑkηΞ‘\›ΏΏSί‡Ώlµά@.¤΄^<5E>QpF‹(ζ:<3A>ϊD<CF8A>5Εσ“zr~ ρen8
|
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x-Ë1Â0Faæžâߨ0pŽÀìÄÐ(N-ÅöÐÛÓ¡Ò“¾é±ãq]>ksÅ*š? |m“‡Õçiª@ÛÖý¶¼m»¨V£…£<E280A6>'©î`)”.Ø-1¨x
|
||||
u„xãòt(+
|
@ -0,0 +1,2 @@
|
||||
x
α
…0<>)ÞŠ?=
¥ÉÄNŠlO¤k®¸‹jÛúÿ¹8&„«¨ ãr
”
|
||||
ïqJWñ°7<EFBFBD>¾B<<3C>ÉáöfÙìK8#Q1C-‘"eª·Ì«£Š°ð>¼'@
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
# pack-refs with: peeled
|
||||
480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
|
@ -0,0 +1 @@
|
||||
480095882d281ed676fe5b863569520e54a7d5c0
|
@ -0,0 +1 @@
|
||||
ref: refs/remotes/origin/master
|
1
tests-clar/resources/typechanges/.gitted/modules/d/HEAD
Normal file
1
tests-clar/resources/typechanges/.gitted/modules/d/HEAD
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
13
tests-clar/resources/typechanges/.gitted/modules/d/config
Normal file
13
tests-clar/resources/typechanges/.gitted/modules/d/config
Normal file
@ -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
|
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
tests-clar/resources/typechanges/.gitted/modules/d/index
Normal file
BIN
tests-clar/resources/typechanges/.gitted/modules/d/index
Normal file
Binary file not shown.
@ -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]
|
||||
# *~
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x•<>Q
|
||||
!EϋvoΕΣy*Ρ_Ών@Ηg#h‚£ϋOhύ^Ξ9w«¥¤<0E>κSoΜ€f1*²<>Α[”<18>‰¬§θIc Τ¤<CEA4>μκ¤p£οµΑkηΞ‘\›ΏΏSί‡Ώlµά@.¤΄^<5E>QpF‹(ζ:<3A>ϊD<CF8A>5Εσ“zr~ ρen8
|
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x-Ë1Â0Faæžâߨ0pŽÀìÄÐ(N-ÅöÐÛÓ¡Ò“¾é±ãq]>ksÅ*š? |m“‡Õçiª@ÛÖý¶¼m»¨V£…£<E280A6>'©î`)”.Ø-1¨x
|
||||
u„xãòt(+
|
@ -0,0 +1,2 @@
|
||||
x
α
…0<>)ÞŠ?=
¥ÉÄNŠlO¤k®¸‹jÛúÿ¹8&„«¨ ãr
”
|
||||
ïqJWñ°7<EFBFBD>¾B<<3C>ÉáöfÙìK8#Q1C-‘"eª·Ì«£Š°ð>¼'@
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
# pack-refs with: peeled
|
||||
480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
|
@ -0,0 +1 @@
|
||||
480095882d281ed676fe5b863569520e54a7d5c0
|
@ -0,0 +1 @@
|
||||
ref: refs/remotes/origin/master
|
1
tests-clar/resources/typechanges/.gitted/modules/e/HEAD
Normal file
1
tests-clar/resources/typechanges/.gitted/modules/e/HEAD
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
13
tests-clar/resources/typechanges/.gitted/modules/e/config
Normal file
13
tests-clar/resources/typechanges/.gitted/modules/e/config
Normal file
@ -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
|
@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
tests-clar/resources/typechanges/.gitted/modules/e/index
Normal file
BIN
tests-clar/resources/typechanges/.gitted/modules/e/index
Normal file
Binary file not shown.
@ -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]
|
||||
# *~
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x•<>Q
|
||||
!EϋvoΕΣy*Ρ_Ών@Ηg#h‚£ϋOhύ^Ξ9w«¥¤<0E>κSoΜ€f1*²<>Α[”<18>‰¬§θIc Τ¤<CEA4>μκ¤p£οµΑkηΞ‘\›ΏΏSί‡Ώlµά@.¤΄^<5E>QpF‹(ζ:<3A>ϊD<CF8A>5Εσ“zr~ ρen8
|
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x-Ë1Â0Faæžâߨ0pŽÀìÄÐ(N-ÅöÐÛÓ¡Ò“¾é±ãq]>ksÅ*š? |m“‡Õçiª@ÛÖý¶¼m»¨V£…£<E280A6>'©î`)”.Ø-1¨x
|
||||
u„xãòt(+
|
@ -0,0 +1,2 @@
|
||||
x
α
…0<>)ÞŠ?=
¥ÉÄNŠlO¤k®¸‹jÛúÿ¹8&„«¨ ãr
”
|
||||
ïqJWñ°7<EFBFBD>¾B<<3C>ÉáöfÙìK8#Q1C-‘"eª·Ì«£Š°ð>¼'@
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
# pack-refs with: peeled
|
||||
480095882d281ed676fe5b863569520e54a7d5c0 refs/remotes/origin/master
|
@ -0,0 +1 @@
|
||||
480095882d281ed676fe5b863569520e54a7d5c0
|
@ -0,0 +1 @@
|
||||
ref: refs/remotes/origin/master
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user