mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-04 19:39:48 +00:00
Overwrite ignored files on checkout
This commit is contained in:
parent
79194bcdc9
commit
81a2012d99
@ -99,6 +99,11 @@ GIT_BEGIN_DECL
|
||||
* files with unmerged index entries instead. GIT_CHECKOUT_USE_OURS and
|
||||
* GIT_CHECKOUT_USE_THEIRS to proceed with the checkout using either the
|
||||
* stage 2 ("ours") or stage 3 ("theirs") version of files in the index.
|
||||
*
|
||||
* - GIT_CHECKOUT_DONT_OVERWRITE_IGNORED prevents ignored files from being
|
||||
* overwritten. Normally, files that are ignored in the working directory
|
||||
* are not considered "precious" and may be overwritten if the checkout
|
||||
* target contains that file.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_CHECKOUT_NONE = 0, /** default is a dry run, no actual updates */
|
||||
@ -144,6 +149,9 @@ typedef enum {
|
||||
/** Ignore directories in use, they will be left empty */
|
||||
GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES = (1u << 18),
|
||||
|
||||
/** Don't overwrite ignored files that exist in the checkout target */
|
||||
GIT_CHECKOUT_DONT_OVERWRITE_IGNORED = (1u << 19),
|
||||
|
||||
/**
|
||||
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
|
||||
*/
|
||||
|
@ -333,6 +333,7 @@ static int checkout_action_with_wd(
|
||||
int *action,
|
||||
checkout_data *data,
|
||||
const git_diff_delta *delta,
|
||||
git_iterator *workdir,
|
||||
const git_index_entry *wd)
|
||||
{
|
||||
*action = CHECKOUT_ACTION__NONE;
|
||||
@ -346,7 +347,10 @@ static int checkout_action_with_wd(
|
||||
}
|
||||
break;
|
||||
case GIT_DELTA_ADDED: /* case 3, 4 or 6 */
|
||||
*action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
|
||||
if (git_iterator_current_is_ignored(workdir))
|
||||
*action = CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, UPDATE_BLOB);
|
||||
else
|
||||
*action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
|
||||
break;
|
||||
case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */
|
||||
if (checkout_is_workdir_modified(data, &delta->old_file, wd))
|
||||
@ -541,7 +545,7 @@ static int checkout_action(
|
||||
|
||||
if (cmp == 0) {
|
||||
/* case 4 */
|
||||
error = checkout_action_with_wd(action, data, delta, wd);
|
||||
error = checkout_action_with_wd(action, data, delta, workdir, wd);
|
||||
advance = git_iterator_advance;
|
||||
goto done;
|
||||
}
|
||||
@ -554,7 +558,7 @@ static int checkout_action(
|
||||
|
||||
if (delta->status == GIT_DELTA_TYPECHANGE) {
|
||||
if (delta->old_file.mode == GIT_FILEMODE_TREE) {
|
||||
error = checkout_action_with_wd(action, data, delta, wd);
|
||||
error = checkout_action_with_wd(action, data, delta, workdir, wd);
|
||||
advance = git_iterator_advance_into;
|
||||
goto done;
|
||||
}
|
||||
@ -563,7 +567,7 @@ static int checkout_action(
|
||||
delta->new_file.mode == GIT_FILEMODE_COMMIT ||
|
||||
delta->old_file.mode == GIT_FILEMODE_COMMIT)
|
||||
{
|
||||
error = checkout_action_with_wd(action, data, delta, wd);
|
||||
error = checkout_action_with_wd(action, data, delta, workdir, wd);
|
||||
advance = git_iterator_advance;
|
||||
goto done;
|
||||
}
|
||||
@ -1017,8 +1021,10 @@ static int checkout_get_actions(
|
||||
if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
|
||||
(data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
|
||||
{
|
||||
giterr_set(GITERR_CHECKOUT, "%d conflicts prevent checkout",
|
||||
(int)counts[CHECKOUT_ACTION__CONFLICT]);
|
||||
giterr_set(GITERR_CHECKOUT, "%d %s checkout",
|
||||
(int)counts[CHECKOUT_ACTION__CONFLICT],
|
||||
counts[CHECKOUT_ACTION__CONFLICT] == 1 ?
|
||||
"conflict prevents" : "conflicts prevent");
|
||||
error = GIT_EMERGECONFLICT;
|
||||
goto fail;
|
||||
}
|
||||
|
@ -235,6 +235,80 @@ void test_checkout_tree__can_remove_ignored(void)
|
||||
cl_assert(!git_path_isfile("testrepo/ignored_file"));
|
||||
}
|
||||
|
||||
static int checkout_tree_with_blob_ignored_in_workdir(int strategy)
|
||||
{
|
||||
git_oid oid;
|
||||
git_object *obj = NULL;
|
||||
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
int ignored = 0, error;
|
||||
|
||||
assert_on_branch(g_repo, "master");
|
||||
|
||||
/* do first checkout with FORCE because we don't know if testrepo
|
||||
* base data is clean for a checkout or not
|
||||
*/
|
||||
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
|
||||
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||
|
||||
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
|
||||
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/dir"));
|
||||
|
||||
cl_assert(git_path_isfile("testrepo/README"));
|
||||
cl_assert(git_path_isfile("testrepo/branch_file.txt"));
|
||||
cl_assert(git_path_isfile("testrepo/new.txt"));
|
||||
cl_assert(git_path_isfile("testrepo/a/b.txt"));
|
||||
|
||||
cl_assert(!git_path_isdir("testrepo/ab"));
|
||||
|
||||
assert_on_branch(g_repo, "dir");
|
||||
|
||||
git_object_free(obj);
|
||||
|
||||
opts.checkout_strategy = strategy;
|
||||
|
||||
cl_must_pass(p_mkdir("testrepo/ab", 0777));
|
||||
cl_git_mkfile("testrepo/ab/4.txt", "as you wish");
|
||||
|
||||
cl_git_pass(git_ignore_add_rule(g_repo, "ab/4.txt\n"));
|
||||
|
||||
cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "ab/4.txt"));
|
||||
cl_assert_equal_i(1, ignored);
|
||||
|
||||
cl_assert(git_path_isfile("testrepo/ab/4.txt"));
|
||||
|
||||
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/subtrees"));
|
||||
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||
|
||||
error = git_checkout_tree(g_repo, obj, &opts);
|
||||
|
||||
git_object_free(obj);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void test_checkout_tree__conflict_on_ignored_when_not_overwriting(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
cl_git_fail(error = checkout_tree_with_blob_ignored_in_workdir(
|
||||
GIT_CHECKOUT_SAFE | GIT_CHECKOUT_DONT_OVERWRITE_IGNORED));
|
||||
|
||||
cl_assert_equal_i(GIT_EMERGECONFLICT, error);
|
||||
}
|
||||
|
||||
void test_checkout_tree__can_overwrite_ignored_by_default(void)
|
||||
{
|
||||
cl_git_pass(checkout_tree_with_blob_ignored_in_workdir(GIT_CHECKOUT_SAFE));
|
||||
|
||||
cl_git_pass(git_repository_set_head(g_repo, "refs/heads/subtrees"));
|
||||
|
||||
cl_assert(git_path_isfile("testrepo/ab/4.txt"));
|
||||
|
||||
assert_on_branch(g_repo, "subtrees");
|
||||
}
|
||||
|
||||
void test_checkout_tree__can_update_only(void)
|
||||
{
|
||||
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
|
Loading…
Reference in New Issue
Block a user