Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Respect core.filemode in checkout #4545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions src/checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef struct {
git_buf tmp;
unsigned int strategy;
int can_symlink;
int respect_filemode;
bool reload_submodules;
size_t total_steps;
size_t completed_steps;
Expand Down Expand Up @@ -159,17 +160,20 @@ GIT_INLINE(bool) is_workdir_base_or_new(
git_oid__cmp(&newitem->id, workdir_id) == 0);
}

GIT_INLINE(bool) is_file_mode_changed(git_filemode_t a, git_filemode_t b)
GIT_INLINE(bool) is_filemode_changed(git_filemode_t a, git_filemode_t b, int respect_filemode)
{
#ifdef GIT_WIN32
/*
* On Win32 we do not support the executable bit; the file will
* always be 0100644 on disk, don't bother doing a test.
*/
return false;
#else
return (S_ISREG(a) && S_ISREG(b) && a != b);
#endif
/* If core.filemode = false, ignore links in the repository and executable bit changes */
if (!respect_filemode) {
if (a == S_IFLNK)
a = GIT_FILEMODE_BLOB;
if (b == S_IFLNK)
b = GIT_FILEMODE_BLOB;
Copy link
Member Author

@ethomson ethomson Feb 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I anticipate these moving into a check for symlink functionality... But that's not ready yet


a &= ~0111;
b &= ~0111;
}

return (a != b);
}

static bool checkout_is_workdir_modified(
Expand Down Expand Up @@ -217,11 +221,11 @@ static bool checkout_is_workdir_modified(
if (ie != NULL &&
git_index_time_eq(&wditem->mtime, &ie->mtime) &&
wditem->file_size == ie->file_size &&
!is_file_mode_changed(wditem->mode, ie->mode)) {
!is_filemode_changed(wditem->mode, ie->mode, data->respect_filemode)) {

/* The workdir is modified iff the index entry is modified */
return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
is_file_mode_changed(baseitem->mode, ie->mode);
is_filemode_changed(baseitem->mode, ie->mode, data->respect_filemode);
}

/* depending on where base is coming from, we may or may not know
Expand All @@ -234,7 +238,7 @@ static bool checkout_is_workdir_modified(
if (S_ISDIR(wditem->mode))
return false;

if (is_file_mode_changed(baseitem->mode, wditem->mode))
if (is_filemode_changed(baseitem->mode, wditem->mode, data->respect_filemode))
return true;

if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
Expand Down Expand Up @@ -2454,6 +2458,10 @@ static int checkout_data_init(
&data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0)
goto cleanup;

if ((error = git_repository__cvar(
&data->respect_filemode, repo, GIT_CVAR_FILEMODE)) < 0)
goto cleanup;

if (!data->opts.baseline && !data->opts.baseline_index) {
data->opts_free_baseline = true;
error = 0;
Expand Down
83 changes: 83 additions & 0 deletions tests/checkout/head.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,86 @@ void test_checkout_head__typechange_index_and_workdir(void)
git_object_free(target);
git_index_free(index);
}

void test_checkout_head__workdir_filemode_is_simplified(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_object *target, *branch;

opts.checkout_strategy = GIT_CHECKOUT_FORCE;

cl_git_pass(git_revparse_single(&target, g_repo, "a38d028f71eaa590febb7d716b1ca32350cf70da"));
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));

cl_must_pass(p_chmod("testrepo/branch_file.txt", 0666));

/*
* Checkout should not fail with a conflict; though the file mode
* on disk is literally different to the base (0666 vs 0644), Git
* ignores the actual mode and simply treats both as non-executable.
*/
cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff"));

opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE;
opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
cl_git_pass(git_checkout_tree(g_repo, branch, NULL));

git_object_free(branch);
git_object_free(target);
}

void test_checkout_head__obeys_filemode_true(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_object *target, *branch;

opts.checkout_strategy = GIT_CHECKOUT_FORCE;

/* In this commit, `README` is executable */
cl_git_pass(git_revparse_single(&target, g_repo, "f9ed4af42472941da45a3c"));
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));

cl_repo_set_bool(g_repo, "core.filemode", true);
cl_must_pass(p_chmod("testrepo/README", 0644));

/*
* Checkout will fail with a conflict; the file mode is updated in
* the checkout target, but the contents have changed in our branch.
*/
cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff"));

opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE;
opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
cl_git_fail_with(GIT_ECONFLICT, git_checkout_tree(g_repo, branch, NULL));

git_object_free(branch);
git_object_free(target);
}

void test_checkout_head__obeys_filemode_false(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_object *target, *branch;

opts.checkout_strategy = GIT_CHECKOUT_FORCE;

/* In this commit, `README` is executable */
cl_git_pass(git_revparse_single(&target, g_repo, "f9ed4af42472941da45a3c"));
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));

cl_repo_set_bool(g_repo, "core.filemode", false);
cl_must_pass(p_chmod("testrepo/README", 0644));

/*
* Checkout will fail with a conflict; the file contents are updated
* in the checkout target, but the filemode has changed in our branch.
*/
cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff"));

opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE;
opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
cl_git_pass(git_checkout_tree(g_repo, branch, NULL));

git_object_free(branch);
git_object_free(target);
}
3 changes: 2 additions & 1 deletion tests/iterator/workdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ void test_iterator_workdir__filesystem2(void)
static const char *expect_base[] = {
"heads/br2",
"heads/dir",
"heads/executable",
"heads/ident",
"heads/long-file-name",
"heads/master",
Expand All @@ -630,7 +631,7 @@ void test_iterator_workdir__filesystem2(void)

cl_git_pass(git_iterator_for_filesystem(
&i, "testrepo/.git/refs", NULL));
expect_iterator_items(i, 15, expect_base, 15, expect_base);
expect_iterator_items(i, 16, expect_base, 16, expect_base);
git_iterator_free(i);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/refs/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void test_refs_list__all(void)
/* We have exactly 12 refs in total if we include the packed ones:
* there is a reference that exists both in the packfile and as
* loose, but we only list it once */
cl_assert_equal_i((int)ref_list.count, 17);
cl_assert_equal_i((int)ref_list.count, 18);

git_strarray_free(&ref_list);
}
Expand All @@ -51,7 +51,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten
"144344043ba4d4a405da03de3844aa829ae8be0e\n");

cl_git_pass(git_reference_list(&ref_list, g_repo));
cl_assert_equal_i((int)ref_list.count, 17);
cl_assert_equal_i((int)ref_list.count, 18);

git_strarray_free(&ref_list);
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x�N[
B!��U��z�ꁈ~�A8W�� 3�K-?�v�|�f&�R.]�6�1K�-p��%� ��d���&���S�6�;5�u�3��� �9 ΄h|��`U�h8gAk_j������y��Qor����#����ZR;�*�1*�j@ w���g��ǵ�|e��O�
1 change: 1 addition & 0 deletions tests/resources/testrepo/.gitted/refs/heads/executable
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f9ed4af42472941da45a3ce44458455ed227a6be
2 changes: 1 addition & 1 deletion tests/revwalk/basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ void test_revwalk_basic__glob_heads_with_invalid(void)
/* walking */;

/* git log --branches --oneline | wc -l => 16 */
cl_assert_equal_i(19, i);
cl_assert_equal_i(20, i);
}

void test_revwalk_basic__push_head(void)
Expand Down