]> git.proxmox.com Git - libgit2.git/blob - tests/checkout/head.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / tests / checkout / head.c
1 #include "clar_libgit2.h"
2 #include "refs.h"
3 #include "repo/repo_helpers.h"
4 #include "path.h"
5 #include "futils.h"
6
7 static git_repository *g_repo;
8
9 void test_checkout_head__initialize(void)
10 {
11 g_repo = cl_git_sandbox_init("testrepo");
12 }
13
14 void test_checkout_head__cleanup(void)
15 {
16 cl_git_sandbox_cleanup();
17 }
18
19 void test_checkout_head__unborn_head_returns_GIT_EUNBORNBRANCH(void)
20 {
21 make_head_unborn(g_repo, NON_EXISTING_HEAD);
22
23 cl_assert_equal_i(GIT_EUNBORNBRANCH, git_checkout_head(g_repo, NULL));
24 }
25
26 void test_checkout_head__with_index_only_tree(void)
27 {
28 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
29 git_index *index;
30
31 /* let's start by getting things into a known state */
32
33 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
34 cl_git_pass(git_checkout_head(g_repo, &opts));
35
36 /* now let's stage some new stuff including a new directory */
37
38 cl_git_pass(git_repository_index(&index, g_repo));
39
40 p_mkdir("testrepo/newdir", 0777);
41 cl_git_mkfile("testrepo/newdir/newfile.txt", "new file\n");
42
43 cl_git_pass(git_index_add_bypath(index, "newdir/newfile.txt"));
44 cl_git_pass(git_index_write(index));
45
46 cl_assert(git_fs_path_isfile("testrepo/newdir/newfile.txt"));
47 cl_assert(git_index_get_bypath(index, "newdir/newfile.txt", 0) != NULL);
48
49 git_index_free(index);
50
51 /* okay, so now we have staged this new file; let's see if we can remove */
52
53 opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
54 cl_git_pass(git_checkout_head(g_repo, &opts));
55
56 cl_git_pass(git_repository_index(&index, g_repo));
57
58 cl_assert(!git_fs_path_isfile("testrepo/newdir/newfile.txt"));
59 cl_assert(git_index_get_bypath(index, "newdir/newfile.txt", 0) == NULL);
60
61 git_index_free(index);
62 }
63
64 void test_checkout_head__do_not_remove_untracked_file(void)
65 {
66 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
67 git_index *index;
68
69 cl_git_pass(p_mkdir("testrepo/tracked", 0755));
70 cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
71 cl_git_mkfile("testrepo/tracked/untracked", "untracked\n");
72
73 cl_git_pass(git_repository_index(&index, g_repo));
74 cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
75 cl_git_pass(git_index_write(index));
76
77 git_index_free(index);
78
79 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
80 cl_git_pass(git_checkout_head(g_repo, &opts));
81
82 cl_assert(!git_fs_path_isfile("testrepo/tracked/tracked"));
83 cl_assert(git_fs_path_isfile("testrepo/tracked/untracked"));
84 }
85
86 void test_checkout_head__do_not_remove_untracked_file_in_subdir(void)
87 {
88 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
89 git_index *index;
90
91 cl_git_pass(p_mkdir("testrepo/tracked", 0755));
92 cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755));
93 cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
94 cl_git_mkfile("testrepo/tracked/subdir/tracked", "tracked\n");
95 cl_git_mkfile("testrepo/tracked/subdir/untracked", "untracked\n");
96
97 cl_git_pass(git_repository_index(&index, g_repo));
98 cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
99 cl_git_pass(git_index_add_bypath(index, "tracked/subdir/tracked"));
100 cl_git_pass(git_index_write(index));
101
102 git_index_free(index);
103
104 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
105 cl_git_pass(git_checkout_head(g_repo, &opts));
106
107 cl_assert(!git_fs_path_isfile("testrepo/tracked/tracked"));
108 cl_assert(!git_fs_path_isfile("testrepo/tracked/subdir/tracked"));
109 cl_assert(git_fs_path_isfile("testrepo/tracked/subdir/untracked"));
110 }
111
112 void test_checkout_head__do_remove_untracked_paths(void)
113 {
114 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
115 git_index *index;
116 char *paths[] = {"tracked/untracked"};
117
118 cl_git_pass(p_mkdir("testrepo/tracked", 0755));
119 cl_git_pass(p_mkdir("testrepo/tracked/subdir", 0755));
120 cl_git_mkfile("testrepo/tracked/tracked", "tracked\n");
121 cl_git_mkfile("testrepo/tracked/untracked", "untracked\n");
122
123 cl_git_pass(git_repository_index(&index, g_repo));
124 cl_git_pass(git_index_add_bypath(index, "tracked/tracked"));
125 cl_git_pass(git_index_write(index));
126
127 git_index_free(index);
128
129 opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED;
130 opts.paths.strings = paths;
131 opts.paths.count = 1;
132 cl_git_pass(git_checkout_head(g_repo, &opts));
133
134 cl_assert(git_fs_path_isfile("testrepo/tracked/tracked"));
135 cl_assert(!git_fs_path_isfile("testrepo/tracked/untracked"));
136 }
137
138 void test_checkout_head__do_remove_tracked_subdir(void)
139 {
140 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
141 git_index *index;
142
143 cl_git_pass(p_mkdir("testrepo/subdir", 0755));
144 cl_git_pass(p_mkdir("testrepo/subdir/tracked", 0755));
145 cl_git_mkfile("testrepo/subdir/tracked-file", "tracked\n");
146 cl_git_mkfile("testrepo/subdir/untracked-file", "untracked\n");
147 cl_git_mkfile("testrepo/subdir/tracked/tracked1", "tracked\n");
148 cl_git_mkfile("testrepo/subdir/tracked/tracked2", "tracked\n");
149
150 cl_git_pass(git_repository_index(&index, g_repo));
151 cl_git_pass(git_index_add_bypath(index, "subdir/tracked-file"));
152 cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked1"));
153 cl_git_pass(git_index_add_bypath(index, "subdir/tracked/tracked2"));
154 cl_git_pass(git_index_write(index));
155
156 git_index_free(index);
157
158 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
159 cl_git_pass(git_checkout_head(g_repo, &opts));
160
161 cl_assert(!git_fs_path_isdir("testrepo/subdir/tracked"));
162 cl_assert(!git_fs_path_isfile("testrepo/subdir/tracked-file"));
163 cl_assert(git_fs_path_isfile("testrepo/subdir/untracked-file"));
164 }
165
166 void test_checkout_head__typechange_workdir(void)
167 {
168 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
169 git_object *target;
170 struct stat st;
171
172 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
173
174 cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
175 cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
176
177 cl_must_pass(p_chmod("testrepo/new.txt", 0755));
178 cl_git_pass(git_checkout_head(g_repo, &opts));
179
180 cl_git_pass(p_stat("testrepo/new.txt", &st));
181 cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
182
183 git_object_free(target);
184 }
185
186 void test_checkout_head__typechange_index_and_workdir(void)
187 {
188 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
189 git_object *target;
190 git_index *index;
191 struct stat st;
192
193 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
194
195 cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
196 cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
197
198 cl_must_pass(p_chmod("testrepo/new.txt", 0755));
199 cl_git_pass(git_repository_index(&index, g_repo));
200 cl_git_pass(git_index_add_bypath(index, "new.txt"));
201 cl_git_pass(git_index_write(index));
202 cl_git_pass(git_checkout_head(g_repo, &opts));
203
204 cl_git_pass(p_stat("testrepo/new.txt", &st));
205 cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
206
207 git_object_free(target);
208 git_index_free(index);
209 }
210
211 void test_checkout_head__workdir_filemode_is_simplified(void)
212 {
213 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
214 git_object *target, *branch;
215
216 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
217
218 cl_git_pass(git_revparse_single(&target, g_repo, "a38d028f71eaa590febb7d716b1ca32350cf70da"));
219 cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
220
221 cl_must_pass(p_chmod("testrepo/branch_file.txt", 0666));
222
223 /*
224 * Checkout should not fail with a conflict; though the file mode
225 * on disk is literally different to the base (0666 vs 0644), Git
226 * ignores the actual mode and simply treats both as non-executable.
227 */
228 cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff"));
229
230 opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE;
231 opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
232 cl_git_pass(git_checkout_tree(g_repo, branch, NULL));
233
234 git_object_free(branch);
235 git_object_free(target);
236 }
237
238 void test_checkout_head__obeys_filemode_true(void)
239 {
240 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
241 git_object *target, *branch;
242
243 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
244
245 /* In this commit, `README` is executable */
246 cl_git_pass(git_revparse_single(&target, g_repo, "f9ed4af42472941da45a3c"));
247 cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
248
249 cl_repo_set_bool(g_repo, "core.filemode", true);
250 cl_must_pass(p_chmod("testrepo/README", 0644));
251
252 /*
253 * Checkout will fail with a conflict; the file mode is updated in
254 * the checkout target, but the contents have changed in our branch.
255 */
256 cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff"));
257
258 opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE;
259 opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
260 cl_git_fail_with(GIT_ECONFLICT, git_checkout_tree(g_repo, branch, NULL));
261
262 git_object_free(branch);
263 git_object_free(target);
264 }
265
266 void test_checkout_head__obeys_filemode_false(void)
267 {
268 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
269 git_object *target, *branch;
270
271 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
272
273 /* In this commit, `README` is executable */
274 cl_git_pass(git_revparse_single(&target, g_repo, "f9ed4af42472941da45a3c"));
275 cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
276
277 cl_repo_set_bool(g_repo, "core.filemode", false);
278 cl_must_pass(p_chmod("testrepo/README", 0644));
279
280 /*
281 * Checkout will fail with a conflict; the file contents are updated
282 * in the checkout target, but the filemode has changed in our branch.
283 */
284 cl_git_pass(git_revparse_single(&branch, g_repo, "099fabac3a9ea935598528c27f866e34089c2eff"));
285
286 opts.checkout_strategy &= ~GIT_CHECKOUT_FORCE;
287 opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
288 cl_git_pass(git_checkout_tree(g_repo, branch, NULL));
289
290 git_object_free(branch);
291 git_object_free(target);
292 }