]> git.proxmox.com Git - libgit2.git/blob - tests/repo/head.c
Merge pull request #2808 from libgit2/cmn/repo-ident
[libgit2.git] / tests / repo / head.c
1 #include "clar_libgit2.h"
2 #include "refs.h"
3 #include "repo_helpers.h"
4 #include "posix.h"
5
6 static const char *g_email = "foo@example.com";
7 static git_repository *repo;
8
9 void test_repo_head__initialize(void)
10 {
11 repo = cl_git_sandbox_init("testrepo.git");
12 cl_git_pass(git_repository_set_ident(repo, "Foo Bar", g_email));
13 }
14
15 void test_repo_head__cleanup(void)
16 {
17 cl_git_sandbox_cleanup();
18 }
19
20 static void check_last_reflog_entry(const char *email, const char *message)
21 {
22 git_reflog *log;
23 const git_reflog_entry *entry;
24
25 cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE));
26 cl_assert(git_reflog_entrycount(log) > 0);
27 entry = git_reflog_entry_byindex(log, 0);
28 if (email)
29 cl_assert_equal_s(email, git_reflog_entry_committer(entry)->email);
30 if (message)
31 cl_assert_equal_s(message, git_reflog_entry_message(entry));
32 git_reflog_free(log);
33 }
34
35 void test_repo_head__head_detached(void)
36 {
37 git_reference *ref;
38
39 cl_assert_equal_i(false, git_repository_head_detached(repo));
40
41 cl_git_pass(git_repository_detach_head(repo));
42 check_last_reflog_entry(g_email, "checkout: moving from master to a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
43 cl_assert_equal_i(true, git_repository_head_detached(repo));
44
45 /* take the repo back to it's original state */
46 cl_git_pass(git_reference_symbolic_create(&ref, repo, "HEAD", "refs/heads/master",
47 true, "REATTACH"));
48 git_reference_free(ref);
49
50 check_last_reflog_entry(g_email, "REATTACH");
51 cl_assert_equal_i(false, git_repository_head_detached(repo));
52 }
53
54 void test_repo_head__unborn_head(void)
55 {
56 git_reference *ref;
57
58 cl_git_pass(git_repository_head_detached(repo));
59
60 make_head_unborn(repo, NON_EXISTING_HEAD);
61
62 cl_assert(git_repository_head_unborn(repo) == 1);
63
64
65 /* take the repo back to it's original state */
66 cl_git_pass(git_reference_symbolic_create(&ref, repo, "HEAD", "refs/heads/master", 1, NULL));
67 cl_assert(git_repository_head_unborn(repo) == 0);
68
69 git_reference_free(ref);
70 }
71
72 void test_repo_head__set_head_Attaches_HEAD_to_un_unborn_branch_when_the_branch_doesnt_exist(void)
73 {
74 git_reference *head;
75
76 cl_git_pass(git_repository_set_head(repo, "refs/heads/doesnt/exist/yet"));
77
78 cl_assert_equal_i(false, git_repository_head_detached(repo));
79
80 cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_head(&head, repo));
81 }
82
83 void test_repo_head__set_head_Returns_ENOTFOUND_when_the_reference_doesnt_exist(void)
84 {
85 cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head(repo, "refs/tags/doesnt/exist/yet"));
86 }
87
88 void test_repo_head__set_head_Fails_when_the_reference_points_to_a_non_commitish(void)
89 {
90 cl_git_fail(git_repository_set_head(repo, "refs/tags/point_to_blob"));
91 }
92
93 void test_repo_head__set_head_Attaches_HEAD_when_the_reference_points_to_a_branch(void)
94 {
95 git_reference *head;
96
97 cl_git_pass(git_repository_set_head(repo, "refs/heads/br2"));
98
99 cl_assert_equal_i(false, git_repository_head_detached(repo));
100
101 cl_git_pass(git_repository_head(&head, repo));
102 cl_assert_equal_s("refs/heads/br2", git_reference_name(head));
103
104 git_reference_free(head);
105 }
106
107 static void assert_head_is_correctly_detached(void)
108 {
109 git_reference *head;
110 git_object *commit;
111
112 cl_assert_equal_i(true, git_repository_head_detached(repo));
113
114 cl_git_pass(git_repository_head(&head, repo));
115
116 cl_git_pass(git_object_lookup(&commit, repo, git_reference_target(head), GIT_OBJ_COMMIT));
117
118 git_object_free(commit);
119 git_reference_free(head);
120 }
121
122 void test_repo_head__set_head_Detaches_HEAD_when_the_reference_doesnt_point_to_a_branch(void)
123 {
124 cl_git_pass(git_repository_set_head(repo, "refs/tags/test"));
125
126 cl_assert_equal_i(true, git_repository_head_detached(repo));
127
128 assert_head_is_correctly_detached();
129 }
130
131 void test_repo_head__set_head_detached_Return_ENOTFOUND_when_the_object_doesnt_exist(void)
132 {
133 git_oid oid;
134
135 cl_git_pass(git_oid_fromstr(&oid, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
136
137 cl_assert_equal_i(GIT_ENOTFOUND, git_repository_set_head_detached(repo, &oid));
138 }
139
140 void test_repo_head__set_head_detached_Fails_when_the_object_isnt_a_commitish(void)
141 {
142 git_object *blob;
143
144 cl_git_pass(git_revparse_single(&blob, repo, "point_to_blob"));
145
146 cl_git_fail(git_repository_set_head_detached(repo, git_object_id(blob)));
147
148 git_object_free(blob);
149 }
150
151 void test_repo_head__set_head_detached_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void)
152 {
153 git_object *tag;
154
155 cl_git_pass(git_revparse_single(&tag, repo, "tags/test"));
156 cl_assert_equal_i(GIT_OBJ_TAG, git_object_type(tag));
157
158 cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag)));
159
160 assert_head_is_correctly_detached();
161
162 git_object_free(tag);
163 }
164
165 void test_repo_head__detach_head_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void)
166 {
167 cl_assert_equal_i(false, git_repository_head_detached(repo));
168
169 cl_git_pass(git_repository_detach_head(repo));
170
171 assert_head_is_correctly_detached();
172 }
173
174 void test_repo_head__detach_head_Fails_if_HEAD_and_point_to_a_non_commitish(void)
175 {
176 git_reference *head;
177
178 cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/tags/point_to_blob", 1, NULL));
179
180 cl_git_fail(git_repository_detach_head(repo));
181
182 git_reference_free(head);
183 }
184
185 void test_repo_head__detaching_an_unborn_branch_returns_GIT_EUNBORNBRANCH(void)
186 {
187 make_head_unborn(repo, NON_EXISTING_HEAD);
188
189 cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_detach_head(repo));
190 }
191
192 void test_repo_head__retrieving_an_unborn_branch_returns_GIT_EUNBORNBRANCH(void)
193 {
194 git_reference *head;
195
196 make_head_unborn(repo, NON_EXISTING_HEAD);
197
198 cl_assert_equal_i(GIT_EUNBORNBRANCH, git_repository_head(&head, repo));
199 }
200
201 void test_repo_head__retrieving_a_missing_head_returns_GIT_ENOTFOUND(void)
202 {
203 git_reference *head;
204
205 delete_head(repo);
206
207 cl_assert_equal_i(GIT_ENOTFOUND, git_repository_head(&head, repo));
208 }
209
210 void test_repo_head__can_tell_if_an_unborn_head_is_detached(void)
211 {
212 make_head_unborn(repo, NON_EXISTING_HEAD);
213
214 cl_assert_equal_i(false, git_repository_head_detached(repo));
215 }
216
217 static void test_reflog(git_repository *repo, size_t idx,
218 const char *old_spec, const char *new_spec,
219 const char *email, const char *message)
220 {
221 git_reflog *log;
222 const git_reflog_entry *entry;
223
224 cl_git_pass(git_reflog_read(&log, repo, "HEAD"));
225 entry = git_reflog_entry_byindex(log, idx);
226
227 if (old_spec) {
228 git_object *obj;
229 cl_git_pass(git_revparse_single(&obj, repo, old_spec));
230 cl_assert_equal_oid(git_object_id(obj), git_reflog_entry_id_old(entry));
231 git_object_free(obj);
232 }
233 if (new_spec) {
234 git_object *obj;
235 cl_git_pass(git_revparse_single(&obj, repo, new_spec));
236 cl_assert_equal_oid(git_object_id(obj), git_reflog_entry_id_new(entry));
237 git_object_free(obj);
238 }
239
240 if (email) {
241 cl_assert_equal_s(email, git_reflog_entry_committer(entry)->email);
242 }
243 if (message) {
244 cl_assert_equal_s(message, git_reflog_entry_message(entry));
245 }
246
247 git_reflog_free(log);
248 }
249
250 void test_repo_head__setting_head_updates_reflog(void)
251 {
252 git_object *tag;
253 git_signature *sig;
254
255 cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
256
257 cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
258 cl_git_pass(git_repository_set_head(repo, "refs/heads/unborn"));
259 cl_git_pass(git_revparse_single(&tag, repo, "tags/test"));
260 cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag)));
261 cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
262
263 test_reflog(repo, 2, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked");
264 test_reflog(repo, 1, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d");
265 test_reflog(repo, 0, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked");
266
267 git_object_free(tag);
268 git_signature_free(sig);
269 }
270
271 static void assert_head_reflog(git_repository *repo, size_t idx,
272 const char *old_id, const char *new_id, const char *message)
273 {
274 git_reflog *log;
275 const git_reflog_entry *entry;
276 char id_str[GIT_OID_HEXSZ + 1] = {0};
277
278 cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE));
279 entry = git_reflog_entry_byindex(log, idx);
280
281 git_oid_fmt(id_str, git_reflog_entry_id_old(entry));
282 cl_assert_equal_s(old_id, id_str);
283
284 git_oid_fmt(id_str, git_reflog_entry_id_new(entry));
285 cl_assert_equal_s(new_id, id_str);
286
287 cl_assert_equal_s(message, git_reflog_entry_message(entry));
288
289 git_reflog_free(log);
290 }
291
292 void test_repo_head__detaching_writes_reflog(void)
293 {
294 git_signature *sig;
295 git_oid id;
296 const char *msg;
297
298 cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
299
300 msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d";
301 git_oid_fromstr(&id, "e90810b8df3e80c413d903f631643c716887138d");
302 cl_git_pass(git_repository_set_head_detached(repo, &id));
303 assert_head_reflog(repo, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
304 "e90810b8df3e80c413d903f631643c716887138d", msg);
305
306 msg = "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked";
307 cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
308 assert_head_reflog(repo, 0, "e90810b8df3e80c413d903f631643c716887138d",
309 "258f0e2a959a364e40ed6603d5d44fbb24765b10", msg);
310
311 git_signature_free(sig);
312 }
313
314 void test_repo_head__orphan_branch_does_not_count(void)
315 {
316 git_oid id;
317 const char *msg;
318
319 /* Have something known */
320 msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d";
321 git_oid_fromstr(&id, "e90810b8df3e80c413d903f631643c716887138d");
322 cl_git_pass(git_repository_set_head_detached(repo, &id));
323 assert_head_reflog(repo, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
324 "e90810b8df3e80c413d903f631643c716887138d", msg);
325
326 /* Switching to an orphan branch does not write tot he reflog */
327 cl_git_pass(git_repository_set_head(repo, "refs/heads/orphan"));
328 assert_head_reflog(repo, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750",
329 "e90810b8df3e80c413d903f631643c716887138d", msg);
330
331 /* And coming back, we set the source to zero */
332 msg = "checkout: moving from orphan to haacked";
333 cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
334 assert_head_reflog(repo, 0, "0000000000000000000000000000000000000000",
335 "258f0e2a959a364e40ed6603d5d44fbb24765b10", msg);
336 }
337
338 void test_repo_head__set_to_current_target(void)
339 {
340 git_reflog *log;
341 size_t nentries, nentries_after;
342
343 cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE));
344 nentries = git_reflog_entrycount(log);
345 git_reflog_free(log);
346
347 cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
348 cl_git_pass(git_repository_set_head(repo, "refs/heads/haacked"));
349
350 cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE));
351 nentries_after = git_reflog_entrycount(log);
352 git_reflog_free(log);
353
354 cl_assert_equal_i(nentries + 1, nentries_after);
355 }
356
357 void test_repo_head__branch_birth(void)
358 {
359 git_signature *sig;
360 git_oid id;
361 git_tree *tree;
362 git_reference *ref;
363 const char *msg;
364 git_reflog *log;
365 size_t nentries, nentries_after;
366
367 cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE));
368 nentries = git_reflog_entrycount(log);
369 git_reflog_free(log);
370
371 cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
372
373 cl_git_pass(git_repository_head(&ref, repo));
374 cl_git_pass(git_reference_peel((git_object **) &tree, ref, GIT_OBJ_TREE));
375 git_reference_free(ref);
376
377 cl_git_pass(git_repository_set_head(repo, "refs/heads/orphan"));
378
379 cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE));
380 nentries_after = git_reflog_entrycount(log);
381 git_reflog_free(log);
382
383 cl_assert_equal_i(nentries, nentries_after);
384
385 msg = "message 2";
386 cl_git_pass(git_commit_create(&id, repo, "HEAD", sig, sig, NULL, msg, tree, 0, NULL));
387
388 git_tree_free(tree);
389
390 cl_git_pass(git_reflog_read(&log, repo, "refs/heads/orphan"));
391 cl_assert_equal_i(1, git_reflog_entrycount(log));
392 git_reflog_free(log);
393
394 cl_git_pass(git_reflog_read(&log, repo, GIT_HEAD_FILE));
395 nentries_after = git_reflog_entrycount(log);
396 git_reflog_free(log);
397
398 cl_assert_equal_i(nentries + 1, nentries_after);
399
400 git_signature_free(sig);
401
402 }
403
404 static size_t entrycount(git_repository *repo, const char *name)
405 {
406 git_reflog *log;
407 size_t ret;
408
409 cl_git_pass(git_reflog_read(&log, repo, name));
410 ret = git_reflog_entrycount(log);
411 git_reflog_free(log);
412
413 return ret;
414 }
415
416 void test_repo_head__symref_chain(void)
417 {
418 git_signature *sig;
419 git_oid id;
420 git_tree *tree;
421 git_reference *ref;
422 const char *msg;
423 size_t nentries, nentries_master;
424
425 nentries = entrycount(repo, GIT_HEAD_FILE);
426
427 cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
428
429 cl_git_pass(git_repository_head(&ref, repo));
430 cl_git_pass(git_reference_peel((git_object **) &tree, ref, GIT_OBJ_TREE));
431 git_reference_free(ref);
432
433 nentries_master = entrycount(repo, "refs/heads/master");
434
435 msg = "message 1";
436 cl_git_pass(git_reference_symbolic_create(&ref, repo, "refs/heads/master", "refs/heads/foo", 1, msg));
437 git_reference_free(ref);
438
439 cl_assert_equal_i(0, entrycount(repo, "refs/heads/foo"));
440 cl_assert_equal_i(nentries, entrycount(repo, GIT_HEAD_FILE));
441 cl_assert_equal_i(nentries_master, entrycount(repo, "refs/heads/master"));
442
443 msg = "message 2";
444 cl_git_pass(git_commit_create(&id, repo, "HEAD", sig, sig, NULL, msg, tree, 0, NULL));
445 git_tree_free(tree);
446
447 cl_assert_equal_i(1, entrycount(repo, "refs/heads/foo"));
448 cl_assert_equal_i(nentries +1, entrycount(repo, GIT_HEAD_FILE));
449 cl_assert_equal_i(nentries_master, entrycount(repo, "refs/heads/master"));
450
451 git_signature_free(sig);
452
453 }