Skip to content

Commit 5e26391

Browse files
committed
checkout: FORCE doesn't halt on dirty index
If the index is dirty, allow `GIT_CHECKOUT_FORCE` to obliterate unsaved changes. This is in keeping with its name and description.
1 parent b242cdb commit 5e26391

File tree

3 files changed

+19
-26
lines changed

3 files changed

+19
-26
lines changed

src/checkout.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,16 +2412,25 @@ static int checkout_data_init(
24122412
* and those should not be overwritten.)
24132413
*/
24142414
if (data->index != git_iterator_index(target)) {
2415-
if ((error = git_index_read_safely(data->index)) < 0)
2416-
goto cleanup;
2417-
2418-
/* cannot checkout if unresolved conflicts exist */
2419-
if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) == 0 &&
2420-
git_index_has_conflicts(data->index)) {
2421-
error = GIT_ECONFLICT;
2422-
giterr_set(GITERR_CHECKOUT,
2423-
"unresolved conflicts exist in the index");
2424-
goto cleanup;
2415+
if (data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) {
2416+
/* When forcing, we can blindly re-read the index */
2417+
if ((error = git_index_read(data->index, false)) < 0)
2418+
goto cleanup;
2419+
} else {
2420+
/*
2421+
* When not being forced, we need to check for unresolved
2422+
* conflicts and unsaved changes in the index before
2423+
* proceeding.
2424+
*/
2425+
if (git_index_has_conflicts(data->index)) {
2426+
error = GIT_ECONFLICT;
2427+
giterr_set(GITERR_CHECKOUT,
2428+
"unresolved conflicts exist in the index");
2429+
goto cleanup;
2430+
}
2431+
2432+
if ((error = git_index_read_safely(data->index)) < 0)
2433+
goto cleanup;
24252434
}
24262435

24272436
/* clean conflict data in the current index */

tests/checkout/tree.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -672,12 +672,9 @@ void test_checkout_tree__can_cancel_checkout_from_notify(void)
672672
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
673673
git_oid oid;
674674
git_object *obj = NULL;
675-
git_index *index = NULL;
676675

677676
assert_on_branch(g_repo, "master");
678677

679-
cl_git_pass(git_repository_index(&index, g_repo));
680-
681678
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
682679
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
683680

@@ -704,8 +701,6 @@ void test_checkout_tree__can_cancel_checkout_from_notify(void)
704701
else
705702
cl_assert_equal_i(4, ca.count);
706703

707-
cl_git_pass(git_index_read(index, 1));
708-
709704
/* and again with a different stopping point and return code */
710705
ca.filename = "README";
711706
ca.error = 123;
@@ -721,7 +716,6 @@ void test_checkout_tree__can_cancel_checkout_from_notify(void)
721716
cl_assert_equal_i(1, ca.count);
722717

723718
git_object_free(obj);
724-
git_index_free(index);
725719
}
726720

727721
void test_checkout_tree__can_checkout_with_last_workdir_item_missing(void)
@@ -1502,11 +1496,9 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void)
15021496
git_reference *head;
15031497
git_object *obj;
15041498
size_t conflicts = 0;
1505-
git_index *index;
15061499

15071500
assert_on_branch(g_repo, "master");
15081501

1509-
cl_git_pass(git_repository_index(&index, g_repo));
15101502
cl_git_pass(git_repository_head(&head, g_repo));
15111503
cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT));
15121504

@@ -1525,8 +1517,6 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void)
15251517
cl_git_fail_with(GIT_ECONFLICT, git_checkout_tree(g_repo, obj, &opts));
15261518
cl_assert_equal_i(4, conflicts);
15271519

1528-
cl_git_pass(git_index_read(index, 1));
1529-
15301520
/* but force should succeed and update the index */
15311521
opts.checkout_strategy |= GIT_CHECKOUT_FORCE;
15321522
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
@@ -1535,7 +1525,6 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void)
15351525

15361526
git_object_free(obj);
15371527
git_reference_free(head);
1538-
git_index_free(index);
15391528
}
15401529

15411530
void test_checkout_tree__mode_change_is_force_updated(void)

tests/checkout/typechange.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@ static int make_submodule_dirty(git_submodule *sm, const char *name, void *paylo
259259
void test_checkout_typechange__checkout_with_conflicts(void)
260260
{
261261
int i;
262-
git_index *index;
263262
git_object *obj;
264263
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
265264
notify_counts cts = {0};
@@ -290,10 +289,6 @@ void test_checkout_typechange__checkout_with_conflicts(void)
290289
cl_assert_equal_i(cts.updates, 0);
291290
cl_assert_equal_i(cts.ignored, 0);
292291

293-
cl_git_pass(git_repository_index(&index, g_repo));
294-
cl_git_pass(git_index_read(index, 1));
295-
git_index_free(index);
296-
297292
opts.checkout_strategy =
298293
GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
299294
memset(&cts, 0, sizeof(cts));

0 commit comments

Comments
 (0)