From dacce80b128501e9821f254c2edb1e93906eac0b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 20 Jun 2013 19:05:38 -0500 Subject: test asserting checkout should not recreate deleted files --- tests-clar/checkout/tree.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests-clar/checkout/tree.c b/tests-clar/checkout/tree.c index 462a46c83..7a1c797a2 100644 --- a/tests-clar/checkout/tree.c +++ b/tests-clar/checkout/tree.c @@ -442,6 +442,36 @@ void test_checkout_tree__checking_out_a_conflicting_content_change_returns_EMERG assert_conflict("branch_file.txt", "hello\n", "5b5b025", "c47800c"); } +void test_checkout_tree__donot_update_deleted_file_by_default(void) +{ + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_oid old_id, new_id; + git_commit *old_commit = NULL, *new_commit = NULL; + git_index *index = NULL; + + opts.checkout_strategy = GIT_CHECKOUT_SAFE; + + cl_git_pass(git_repository_index(&index, g_repo)); + + cl_git_pass(git_oid_fromstr(&old_id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); + cl_git_pass(git_commit_lookup(&old_commit, g_repo, &old_id)); + cl_git_pass(git_reset(g_repo, (git_object *)old_commit, GIT_RESET_HARD)); + + cl_git_pass(p_unlink("testrepo/branch_file.txt")); + cl_git_pass(git_index_remove_bypath(index ,"branch_file.txt")); + cl_git_pass(git_index_write(index)); + + cl_assert(!git_path_exists("testrepo/branch_file.txt")); + + cl_git_pass(git_oid_fromstr(&new_id, "099fabac3a9ea935598528c27f866e34089c2eff")); + cl_git_pass(git_commit_lookup(&new_commit, g_repo, &new_id)); + cl_git_fail(git_checkout_tree(g_repo, (git_object *)new_commit, &opts)); + + git_commit_free(old_commit); + git_commit_free(new_commit); + git_index_free(index); +} + void test_checkout_tree__can_checkout_with_last_workdir_item_missing(void) { git_index *index = NULL; -- cgit v1.2.3 From 36fd9e30651cf0d6b0ef58452ba2974a3544d4d1 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 21 Jun 2013 11:20:54 -0700 Subject: Fix checkout of modified file when missing from wd This fixes the checkout case when a file is modified between the baseline and the target and yet missing in the working directory. The logic for that case appears to have been wrong. This also adds a useful checkout notify callback to the checkout test helpers that will count notifications and also has a debug mode to visualize what checkout thinks that it's doing. --- include/git2/checkout.h | 2 + src/checkout.c | 4 +- tests-clar/checkout/checkout_helpers.c | 95 ++++++++++++++++++++++++++++++++++ tests-clar/checkout/checkout_helpers.h | 17 ++++++ tests-clar/checkout/tree.c | 11 ++++ 5 files changed, 128 insertions(+), 1 deletion(-) diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 6798bf31c..f49e87566 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -183,6 +183,8 @@ typedef enum { GIT_CHECKOUT_NOTIFY_UPDATED = (1u << 2), GIT_CHECKOUT_NOTIFY_UNTRACKED = (1u << 3), GIT_CHECKOUT_NOTIFY_IGNORED = (1u << 4), + + GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu } git_checkout_notify_t; /** Checkout notification callback function */ diff --git a/src/checkout.c b/src/checkout.c index ede0be8e8..065bb50fd 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -220,9 +220,11 @@ static int checkout_action_no_wd( action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE); break; case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */ - case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */ action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; + case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */ + action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, CONFLICT); + break; case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/ if (delta->new_file.mode == GIT_FILEMODE_TREE) action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); diff --git a/tests-clar/checkout/checkout_helpers.c b/tests-clar/checkout/checkout_helpers.c index ab93a89bd..8da024dda 100644 --- a/tests-clar/checkout/checkout_helpers.c +++ b/tests-clar/checkout/checkout_helpers.c @@ -91,3 +91,98 @@ void check_file_contents_nocr_at_line( { check_file_contents_internal(path, expected, true, file, line, msg); } + +int checkout_count_callback( + git_checkout_notify_t why, + const char *path, + const git_diff_file *baseline, + const git_diff_file *target, + const git_diff_file *workdir, + void *payload) +{ + checkout_counts *ct = payload; + + GIT_UNUSED(baseline); GIT_UNUSED(target); GIT_UNUSED(workdir); + + if (why & GIT_CHECKOUT_NOTIFY_CONFLICT) { + ct->n_conflicts++; + + if (ct->debug) { + if (workdir) { + if (baseline) { + if (target) + fprintf(stderr, "M %s (conflicts with M %s)\n", + workdir->path, target->path); + else + fprintf(stderr, "M %s (conflicts with D %s)\n", + workdir->path, baseline->path); + } else { + if (target) + fprintf(stderr, "Existing %s (conflicts with A %s)\n", + workdir->path, target->path); + else + fprintf(stderr, "How can an untracked file be a conflict (%s)\n", workdir->path); + } + } else { + if (baseline) { + if (target) + fprintf(stderr, "D %s (conflicts with M %s)\n", + target->path, baseline->path); + else + fprintf(stderr, "D %s (conflicts with D %s)\n", + baseline->path, baseline->path); + } else { + if (target) + fprintf(stderr, "How can an added file with no workdir be a conflict (%s)\n", target->path); + else + fprintf(stderr, "How can a nonexistent file be a conflict (%s)\n", path); + } + } + } + } + + if (why & GIT_CHECKOUT_NOTIFY_DIRTY) { + ct->n_dirty++; + + if (ct->debug) { + if (workdir) + fprintf(stderr, "M %s\n", workdir->path); + else + fprintf(stderr, "D %s\n", baseline->path); + } + } + + if (why & GIT_CHECKOUT_NOTIFY_UPDATED) { + ct->n_updates++; + + if (ct->debug) { + if (baseline) { + if (target) + fprintf(stderr, "update: M %s\n", path); + else + fprintf(stderr, "update: D %s\n", path); + } else { + if (target) + fprintf(stderr, "update: A %s\n", path); + else + fprintf(stderr, "update: this makes no sense %s\n", path); + } + } + } + + if (why & GIT_CHECKOUT_NOTIFY_UNTRACKED) { + ct->n_untracked++; + + if (ct->debug) + fprintf(stderr, "? %s\n", path); + } + + if (why & GIT_CHECKOUT_NOTIFY_IGNORED) { + ct->n_ignored++; + + if (ct->debug) + fprintf(stderr, "I %s\n", path); + } + + return 0; +} diff --git a/tests-clar/checkout/checkout_helpers.h b/tests-clar/checkout/checkout_helpers.h index 34053809d..0e8da31d1 100644 --- a/tests-clar/checkout/checkout_helpers.h +++ b/tests-clar/checkout/checkout_helpers.h @@ -19,3 +19,20 @@ extern void check_file_contents_nocr_at_line( #define check_file_contents_nocr(PATH,EXP) \ check_file_contents_nocr_at_line(PATH,EXP,__FILE__,__LINE__,"String mismatch: " #EXP " != " #PATH) + +typedef struct { + int n_conflicts; + int n_dirty; + int n_updates; + int n_untracked; + int n_ignored; + int debug; +} checkout_counts; + +extern int checkout_count_callback( + git_checkout_notify_t why, + const char *path, + const git_diff_file *baseline, + const git_diff_file *target, + const git_diff_file *workdir, + void *payload); diff --git a/tests-clar/checkout/tree.c b/tests-clar/checkout/tree.c index 7a1c797a2..5835ab05b 100644 --- a/tests-clar/checkout/tree.c +++ b/tests-clar/checkout/tree.c @@ -448,9 +448,15 @@ void test_checkout_tree__donot_update_deleted_file_by_default(void) git_oid old_id, new_id; git_commit *old_commit = NULL, *new_commit = NULL; git_index *index = NULL; + checkout_counts ct; opts.checkout_strategy = GIT_CHECKOUT_SAFE; + memset(&ct, 0, sizeof(ct)); + opts.notify_flags = GIT_CHECKOUT_NOTIFY_ALL; + opts.notify_cb = checkout_count_callback; + opts.notify_payload = &ct; + cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_oid_fromstr(&old_id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); @@ -465,8 +471,13 @@ void test_checkout_tree__donot_update_deleted_file_by_default(void) cl_git_pass(git_oid_fromstr(&new_id, "099fabac3a9ea935598528c27f866e34089c2eff")); cl_git_pass(git_commit_lookup(&new_commit, g_repo, &new_id)); + + cl_git_fail(git_checkout_tree(g_repo, (git_object *)new_commit, &opts)); + cl_assert_equal_i(1, ct.n_conflicts); + cl_assert_equal_i(1, ct.n_updates); + git_commit_free(old_commit); git_commit_free(new_commit); git_index_free(index); -- cgit v1.2.3