]>
Commit | Line | Data |
---|---|---|
ee8bb8ba | 1 | #include "clar_libgit2.h" |
2 | #include "posix.h" | |
3 | #include "reset_helpers.h" | |
4 | #include "path.h" | |
22a2d3d5 | 5 | #include "futils.h" |
ee8bb8ba | 6 | |
7 | static git_repository *repo; | |
8 | static git_object *target; | |
9 | ||
10 | void test_reset_hard__initialize(void) | |
11 | { | |
12 | repo = cl_git_sandbox_init("status"); | |
13 | target = NULL; | |
14 | } | |
15 | ||
16 | void test_reset_hard__cleanup(void) | |
17 | { | |
54a1a042 ET |
18 | if (target != NULL) { |
19 | git_object_free(target); | |
20 | target = NULL; | |
21 | } | |
9094d30b | 22 | |
ee8bb8ba | 23 | cl_git_sandbox_cleanup(); |
24 | } | |
25 | ||
402b92cf RB |
26 | static int strequal_ignore_eol(const char *exp, const char *str) |
27 | { | |
28 | while (*exp && *str) { | |
29 | if (*exp != *str) { | |
30 | while (*exp == '\r' || *exp == '\n') ++exp; | |
31 | while (*str == '\r' || *str == '\n') ++str; | |
32 | if (*exp != *str) | |
33 | return false; | |
34 | } else { | |
35 | exp++; str++; | |
36 | } | |
37 | } | |
38 | return (!*exp && !*str); | |
39 | } | |
40 | ||
8064ecba | 41 | void test_reset_hard__resetting_reverts_modified_files(void) |
ee8bb8ba | 42 | { |
8064ecba RB |
43 | git_buf path = GIT_BUF_INIT, content = GIT_BUF_INIT; |
44 | int i; | |
45 | static const char *files[4] = { | |
46 | "current_file", | |
47 | "modified_file", | |
48 | "staged_new_file", | |
49 | "staged_changes_modified_file" }; | |
50 | static const char *before[4] = { | |
51 | "current_file\n", | |
52 | "modified_file\nmodified_file\n", | |
53 | "staged_new_file\n", | |
54 | "staged_changes_modified_file\nstaged_changes_modified_file\nstaged_changes_modified_file\n" | |
55 | }; | |
56 | static const char *after[4] = { | |
57 | "current_file\n", | |
58 | "modified_file\n", | |
cf208031 | 59 | NULL, |
8064ecba RB |
60 | "staged_changes_modified_file\n" |
61 | }; | |
62 | const char *wd = git_repository_workdir(repo); | |
63 | ||
64 | cl_assert(wd); | |
65 | ||
66 | for (i = 0; i < 4; ++i) { | |
67 | cl_git_pass(git_buf_joinpath(&path, wd, files[i])); | |
68 | cl_git_pass(git_futils_readbuffer(&content, path.ptr)); | |
69 | cl_assert_equal_s(before[i], content.ptr); | |
70 | } | |
71 | ||
0d847a31 | 72 | cl_git_pass(git_revparse_single(&target, repo, "26a125e")); |
ee8bb8ba | 73 | |
23a17803 | 74 | cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); |
ee8bb8ba | 75 | |
8064ecba RB |
76 | for (i = 0; i < 4; ++i) { |
77 | cl_git_pass(git_buf_joinpath(&path, wd, files[i])); | |
78 | if (after[i]) { | |
79 | cl_git_pass(git_futils_readbuffer(&content, path.ptr)); | |
402b92cf | 80 | cl_assert(strequal_ignore_eol(after[i], content.ptr)); |
8064ecba RB |
81 | } else { |
82 | cl_assert(!git_path_exists(path.ptr)); | |
83 | } | |
84 | } | |
85 | ||
ac3d33df JK |
86 | git_buf_dispose(&content); |
87 | git_buf_dispose(&path); | |
ee8bb8ba | 88 | } |
fa5d94a0 | 89 | |
90 | void test_reset_hard__cannot_reset_in_a_bare_repository(void) | |
91 | { | |
92 | git_repository *bare; | |
93 | ||
94 | cl_git_pass(git_repository_open(&bare, cl_fixture("testrepo.git"))); | |
95 | cl_assert(git_repository_is_bare(bare) == true); | |
96 | ||
0d847a31 | 97 | cl_git_pass(git_revparse_single(&target, bare, KNOWN_COMMIT_IN_BARE_REPO)); |
fa5d94a0 | 98 | |
23a17803 | 99 | cl_assert_equal_i(GIT_EBAREREPO, git_reset(bare, target, GIT_RESET_HARD, NULL)); |
fa5d94a0 | 100 | |
101 | git_repository_free(bare); | |
102 | } | |
632d8b23 | 103 | |
54a1a042 ET |
104 | static void index_entry_init(git_index *index, int side, git_oid *oid) |
105 | { | |
106 | git_index_entry entry; | |
1fed6b07 | 107 | |
54a1a042 | 108 | memset(&entry, 0x0, sizeof(git_index_entry)); |
1fed6b07 | 109 | |
54a1a042 | 110 | entry.path = "conflicting_file"; |
ac3d33df | 111 | GIT_INDEX_ENTRY_STAGE_SET(&entry, side); |
54a1a042 | 112 | entry.mode = 0100644; |
d541170c | 113 | git_oid_cpy(&entry.id, oid); |
1fed6b07 | 114 | |
54a1a042 ET |
115 | cl_git_pass(git_index_add(index, &entry)); |
116 | } | |
117 | ||
118 | static void unmerged_index_init(git_index *index, int entries) | |
119 | { | |
120 | int write_ancestor = 1; | |
121 | int write_ours = 2; | |
122 | int write_theirs = 4; | |
123 | git_oid ancestor, ours, theirs; | |
1fed6b07 | 124 | |
ba52879b CMN |
125 | git_oid_fromstr(&ancestor, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); |
126 | git_oid_fromstr(&ours, "32504b727382542f9f089e24fddac5e78533e96c"); | |
127 | git_oid_fromstr(&theirs, "061d42a44cacde5726057b67558821d95db96f19"); | |
1fed6b07 | 128 | |
54a1a042 | 129 | cl_git_rewritefile("status/conflicting_file", "conflicting file\n"); |
1fed6b07 | 130 | |
54a1a042 ET |
131 | if (entries & write_ancestor) |
132 | index_entry_init(index, 1, &ancestor); | |
1fed6b07 | 133 | |
54a1a042 ET |
134 | if (entries & write_ours) |
135 | index_entry_init(index, 2, &ours); | |
1fed6b07 | 136 | |
54a1a042 ET |
137 | if (entries & write_theirs) |
138 | index_entry_init(index, 3, &theirs); | |
139 | } | |
140 | ||
141 | void test_reset_hard__resetting_reverts_unmerged(void) | |
142 | { | |
143 | git_index *index; | |
144 | int entries; | |
1fed6b07 | 145 | |
54a1a042 ET |
146 | /* Ensure every permutation of non-zero stage entries results in the |
147 | * path being cleaned up. */ | |
148 | for (entries = 1; entries < 8; entries++) { | |
149 | cl_git_pass(git_repository_index(&index, repo)); | |
1fed6b07 | 150 | |
54a1a042 ET |
151 | unmerged_index_init(index, entries); |
152 | cl_git_pass(git_index_write(index)); | |
1fed6b07 | 153 | |
0d847a31 | 154 | cl_git_pass(git_revparse_single(&target, repo, "26a125e")); |
23a17803 | 155 | cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); |
1fed6b07 | 156 | |
54a1a042 | 157 | cl_assert(git_path_exists("status/conflicting_file") == 0); |
1fed6b07 | 158 | |
54a1a042 ET |
159 | git_object_free(target); |
160 | target = NULL; | |
1fed6b07 | 161 | |
162 | git_index_free(index); | |
54a1a042 ET |
163 | } |
164 | } | |
165 | ||
632d8b23 ET |
166 | void test_reset_hard__cleans_up_merge(void) |
167 | { | |
168 | git_buf merge_head_path = GIT_BUF_INIT, | |
169 | merge_msg_path = GIT_BUF_INIT, | |
170 | merge_mode_path = GIT_BUF_INIT, | |
171 | orig_head_path = GIT_BUF_INIT; | |
172 | ||
173 | cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD")); | |
174 | cl_git_mkfile(git_buf_cstr(&merge_head_path), "beefbeefbeefbeefbeefbeefbeefbeefbeefbeef\n"); | |
175 | ||
176 | cl_git_pass(git_buf_joinpath(&merge_msg_path, git_repository_path(repo), "MERGE_MSG")); | |
c31ae146 | 177 | cl_git_mkfile(git_buf_cstr(&merge_msg_path), "Merge commit 0017bd4ab1ec30440b17bae1680cff124ab5f1f6\n"); |
632d8b23 | 178 | |
c31ae146 ET |
179 | cl_git_pass(git_buf_joinpath(&merge_mode_path, git_repository_path(repo), "MERGE_MODE")); |
180 | cl_git_mkfile(git_buf_cstr(&merge_mode_path), ""); | |
632d8b23 ET |
181 | |
182 | cl_git_pass(git_buf_joinpath(&orig_head_path, git_repository_path(repo), "ORIG_HEAD")); | |
183 | cl_git_mkfile(git_buf_cstr(&orig_head_path), "0017bd4ab1ec30440b17bae1680cff124ab5f1f6"); | |
184 | ||
0d847a31 | 185 | cl_git_pass(git_revparse_single(&target, repo, "0017bd4")); |
23a17803 | 186 | cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); |
632d8b23 ET |
187 | |
188 | cl_assert(!git_path_exists(git_buf_cstr(&merge_head_path))); | |
189 | cl_assert(!git_path_exists(git_buf_cstr(&merge_msg_path))); | |
190 | cl_assert(!git_path_exists(git_buf_cstr(&merge_mode_path))); | |
191 | ||
192 | cl_assert(git_path_exists(git_buf_cstr(&orig_head_path))); | |
193 | cl_git_pass(p_unlink(git_buf_cstr(&orig_head_path))); | |
194 | ||
ac3d33df JK |
195 | git_buf_dispose(&merge_head_path); |
196 | git_buf_dispose(&merge_msg_path); | |
197 | git_buf_dispose(&merge_mode_path); | |
198 | git_buf_dispose(&orig_head_path); | |
632d8b23 | 199 | } |
86746b4b BS |
200 | |
201 | void test_reset_hard__reflog_is_correct(void) | |
202 | { | |
23a17803 | 203 | git_buf buf = GIT_BUF_INIT; |
a5815a2a | 204 | git_annotated_commit *annotated; |
86746b4b BS |
205 | const char *exp_msg = "commit: Add a file which name should appear before the " |
206 | "\"subdir/\" folder while being dealt with by the treewalker"; | |
207 | ||
208 | reflog_check(repo, "HEAD", 3, "emeric.fermas@gmail.com", exp_msg); | |
209 | reflog_check(repo, "refs/heads/master", 3, "emeric.fermas@gmail.com", exp_msg); | |
210 | ||
211 | /* Branch not moving, no reflog entry */ | |
212 | cl_git_pass(git_revparse_single(&target, repo, "HEAD^{commit}")); | |
23a17803 | 213 | cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); |
86746b4b BS |
214 | reflog_check(repo, "HEAD", 3, "emeric.fermas@gmail.com", exp_msg); |
215 | reflog_check(repo, "refs/heads/master", 3, "emeric.fermas@gmail.com", exp_msg); | |
216 | ||
ae32c54e CMN |
217 | git_object_free(target); |
218 | ||
a5815a2a | 219 | /* Moved branch, expect id in message */ |
86746b4b | 220 | cl_git_pass(git_revparse_single(&target, repo, "HEAD~^{commit}")); |
23a17803 CMN |
221 | cl_git_pass(git_buf_printf(&buf, "reset: moving to %s", git_oid_tostr_s(git_object_id(target)))); |
222 | cl_git_pass(git_reset(repo, target, GIT_RESET_HARD, NULL)); | |
223 | reflog_check(repo, "HEAD", 4, NULL, git_buf_cstr(&buf)); | |
224 | reflog_check(repo, "refs/heads/master", 4, NULL, git_buf_cstr(&buf)); | |
fe21d708 | 225 | |
ac3d33df | 226 | git_buf_dispose(&buf); |
a5815a2a CMN |
227 | |
228 | /* Moved branch, expect revspec in message */ | |
229 | exp_msg = "reset: moving to HEAD~^{commit}"; | |
230 | cl_git_pass(git_annotated_commit_from_revspec(&annotated, repo, "HEAD~^{commit}")); | |
231 | cl_git_pass(git_reset_from_annotated(repo, annotated, GIT_RESET_HARD, NULL)); | |
232 | reflog_check(repo, "HEAD", 5, NULL, exp_msg); | |
233 | reflog_check(repo, "refs/heads/master", 5, NULL, exp_msg); | |
234 | ||
235 | git_annotated_commit_free(annotated); | |
236 | ||
86746b4b | 237 | } |
465c3b38 CMN |
238 | |
239 | void test_reset_hard__switch_file_to_dir(void) | |
240 | { | |
ad8aa112 | 241 | git_index_entry entry = {{ 0 }}; |
465c3b38 | 242 | git_index *idx; |
ed5299ac | 243 | git_odb *odb; |
465c3b38 CMN |
244 | git_object *commit; |
245 | git_tree *tree; | |
246 | git_signature *sig; | |
247 | git_oid src_tree_id, tgt_tree_id; | |
248 | git_oid src_id, tgt_id; | |
249 | ||
ed5299ac | 250 | cl_git_pass(git_repository_odb(&odb, repo)); |
ac3d33df | 251 | cl_git_pass(git_odb_write(&entry.id, odb, "", 0, GIT_OBJECT_BLOB)); |
ed5299ac ET |
252 | git_odb_free(odb); |
253 | ||
465c3b38 | 254 | entry.mode = GIT_FILEMODE_BLOB; |
465c3b38 CMN |
255 | cl_git_pass(git_index_new(&idx)); |
256 | cl_git_pass(git_signature_now(&sig, "foo", "bar")); | |
257 | ||
258 | /* Create the old tree */ | |
259 | entry.path = "README"; | |
260 | cl_git_pass(git_index_add(idx, &entry)); | |
261 | entry.path = "dir"; | |
262 | cl_git_pass(git_index_add(idx, &entry)); | |
263 | ||
264 | cl_git_pass(git_index_write_tree_to(&src_tree_id, idx, repo)); | |
265 | cl_git_pass(git_index_clear(idx)); | |
266 | ||
267 | cl_git_pass(git_tree_lookup(&tree, repo, &src_tree_id)); | |
268 | cl_git_pass(git_commit_create(&src_id, repo, NULL, sig, sig, NULL, "foo", tree, 0, NULL)); | |
269 | git_tree_free(tree); | |
270 | ||
271 | /* Create the new tree */ | |
272 | entry.path = "README"; | |
273 | cl_git_pass(git_index_add(idx, &entry)); | |
274 | entry.path = "dir/FILE"; | |
275 | cl_git_pass(git_index_add(idx, &entry)); | |
276 | ||
277 | cl_git_pass(git_index_write_tree_to(&tgt_tree_id, idx, repo)); | |
278 | cl_git_pass(git_tree_lookup(&tree, repo, &tgt_tree_id)); | |
279 | cl_git_pass(git_commit_create(&tgt_id, repo, NULL, sig, sig, NULL, "foo", tree, 0, NULL)); | |
280 | git_tree_free(tree); | |
281 | git_index_free(idx); | |
282 | git_signature_free(sig); | |
283 | ||
284 | /* Let's go to a known state of the src commit with the file named 'dir' */ | |
ac3d33df | 285 | cl_git_pass(git_object_lookup(&commit, repo, &src_id, GIT_OBJECT_COMMIT)); |
465c3b38 CMN |
286 | cl_git_pass(git_reset(repo, commit, GIT_RESET_HARD, NULL)); |
287 | git_object_free(commit); | |
288 | ||
289 | /* And now we move over to the commit with the directory named 'dir' */ | |
ac3d33df | 290 | cl_git_pass(git_object_lookup(&commit, repo, &tgt_id, GIT_OBJECT_COMMIT)); |
465c3b38 CMN |
291 | cl_git_pass(git_reset(repo, commit, GIT_RESET_HARD, NULL)); |
292 | git_object_free(commit); | |
293 | } |