Blob


1 #!/bin/sh
2 #
3 # Copyright (c) 2019 Stefan Sperling <stsp@openbsd.org>
4 #
5 # Permission to use, copy, modify, and distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
8 #
9 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 . ./common.sh
19 test_cherrypick_basic() {
20 local testroot=`test_init cherrypick_basic`
22 got checkout $testroot/repo $testroot/wt > /dev/null
23 ret=$?
24 if [ $ret -ne 0 ]; then
25 test_done "$testroot" "$ret"
26 return 1
27 fi
29 (cd $testroot/repo && git checkout -q -b newbranch)
30 echo "modified delta on branch" > $testroot/repo/gamma/delta
31 git_commit $testroot/repo -m "committing to delta on newbranch"
33 echo "modified alpha on branch" > $testroot/repo/alpha
34 (cd $testroot/repo && git rm -q beta)
35 echo "new file on branch" > $testroot/repo/epsilon/new
36 (cd $testroot/repo && git add epsilon/new)
37 git_commit $testroot/repo -m "committing more changes on newbranch"
39 local branch_rev=`git_show_head $testroot/repo`
41 echo "modified new file on branch" > $testroot/repo/epsilon/new
42 git_commit $testroot/repo -m "committing more changes on newbranch"
43 local branch_rev2=`git_show_head $testroot/repo`
45 (cd $testroot/wt && got cherrypick $branch_rev > $testroot/stdout)
47 echo "G alpha" > $testroot/stdout.expected
48 echo "D beta" >> $testroot/stdout.expected
49 echo "A epsilon/new" >> $testroot/stdout.expected
50 echo "Merged commit $branch_rev" >> $testroot/stdout.expected
52 cmp -s $testroot/stdout.expected $testroot/stdout
53 ret=$?
54 if [ $ret -ne 0 ]; then
55 diff -u $testroot/stdout.expected $testroot/stdout
56 test_done "$testroot" "$ret"
57 return 1
58 fi
60 echo "modified alpha on branch" > $testroot/content.expected
61 cat $testroot/wt/alpha > $testroot/content
62 cmp -s $testroot/content.expected $testroot/content
63 ret=$?
64 if [ $ret -ne 0 ]; then
65 diff -u $testroot/content.expected $testroot/content
66 test_done "$testroot" "$ret"
67 return 1
68 fi
70 if [ -e $testroot/wt/beta ]; then
71 echo "removed file beta still exists on disk" >&2
72 test_done "$testroot" "1"
73 return 1
74 fi
76 echo "new file on branch" > $testroot/content.expected
77 cat $testroot/wt/epsilon/new > $testroot/content
78 cmp -s $testroot/content.expected $testroot/content
79 ret=$?
80 if [ $ret -ne 0 ]; then
81 diff -u $testroot/content.expected $testroot/content
82 test_done "$testroot" "$ret"
83 return 1
84 fi
86 echo 'M alpha' > $testroot/stdout.expected
87 echo 'D beta' >> $testroot/stdout.expected
88 echo 'A epsilon/new' >> $testroot/stdout.expected
90 (cd $testroot/wt && got status > $testroot/stdout)
92 cmp -s $testroot/stdout.expected $testroot/stdout
93 ret=$?
94 if [ $ret -ne 0 ]; then
95 diff -u $testroot/stdout.expected $testroot/stdout
96 test_done "$testroot" "$ret"
97 return 1
98 fi
100 (cd $testroot/wt && got cherrypick $branch_rev2 > $testroot/stdout)
102 echo "G epsilon/new" > $testroot/stdout.expected
103 echo "Merged commit $branch_rev2" >> $testroot/stdout.expected
105 cmp -s $testroot/stdout.expected $testroot/stdout
106 ret=$?
107 if [ $ret -ne 0 ]; then
108 diff -u $testroot/stdout.expected $testroot/stdout
109 test_done "$testroot" "$ret"
110 return 1
111 fi
113 echo 'M alpha' > $testroot/stdout.expected
114 echo 'D beta' >> $testroot/stdout.expected
115 echo 'A epsilon/new' >> $testroot/stdout.expected
117 (cd $testroot/wt && got status > $testroot/stdout)
119 cmp -s $testroot/stdout.expected $testroot/stdout
120 ret=$?
121 if [ $ret -ne 0 ]; then
122 diff -u $testroot/stdout.expected $testroot/stdout
123 fi
124 test_done "$testroot" "$ret"
127 test_cherrypick_root_commit() {
128 local testroot=`test_init cherrypick_root_commit`
130 got checkout $testroot/repo $testroot/wt > /dev/null
131 ret=$?
132 if [ $ret -ne 0 ]; then
133 test_done "$testroot" "$ret"
134 return 1
135 fi
137 (cd $testroot/repo && git checkout -q -b newbranch)
138 (cd $testroot/repo && git rm -q alpha)
139 (cd $testroot/repo && git rm -q beta)
140 (cd $testroot/repo && git rm -q epsilon/zeta)
141 (cd $testroot/repo && git rm -q gamma/delta)
142 mkdir -p $testroot/repo/epsilon
143 echo "new file on branch" > $testroot/repo/epsilon/new
144 (cd $testroot/repo && git add epsilon/new)
145 git_commit $testroot/repo -m "committing on newbranch"
147 echo "modified new file on branch" >> $testroot/repo/epsilon/new
148 git_commit $testroot/repo -m "committing on newbranch again"
150 tree=`git_show_tree $testroot/repo`
151 root_commit=`git_commit_tree $testroot/repo "new root commit" $tree`
153 (cd $testroot/wt && got cherrypick $root_commit > $testroot/stdout)
155 echo "A epsilon/new" > $testroot/stdout.expected
156 echo "Merged commit $root_commit" >> $testroot/stdout.expected
158 cmp -s $testroot/stdout.expected $testroot/stdout
159 ret=$?
160 if [ $ret -ne 0 ]; then
161 diff -u $testroot/stdout.expected $testroot/stdout
162 test_done "$testroot" "$ret"
163 return 1
164 fi
166 echo "new file on branch" > $testroot/content.expected
167 echo "modified new file on branch" >> $testroot/content.expected
168 cat $testroot/wt/epsilon/new > $testroot/content
169 cmp -s $testroot/content.expected $testroot/content
170 ret=$?
171 if [ $ret -ne 0 ]; then
172 diff -u $testroot/content.expected $testroot/content
173 test_done "$testroot" "$ret"
174 return 1
175 fi
177 echo 'A epsilon/new' > $testroot/stdout.expected
179 (cd $testroot/wt && got status > $testroot/stdout)
181 cmp -s $testroot/stdout.expected $testroot/stdout
182 ret=$?
183 if [ $ret -ne 0 ]; then
184 diff -u $testroot/stdout.expected $testroot/stdout
185 fi
186 test_done "$testroot" "$ret"
189 test_cherrypick_into_work_tree_with_conflicts() {
190 local testroot=`test_init cherrypick_into_work_tree_with_conflicts`
192 got checkout $testroot/repo $testroot/wt > /dev/null
193 ret=$?
194 if [ $ret -ne 0 ]; then
195 test_done "$testroot" "$ret"
196 return 1
197 fi
199 (cd $testroot/repo && git checkout -q -b newbranch)
200 echo "modified delta on branch" > $testroot/repo/gamma/delta
201 git_commit $testroot/repo -m "committing to delta on newbranch"
203 echo "modified alpha on branch" > $testroot/repo/alpha
204 (cd $testroot/repo && git rm -q beta)
205 echo "new file on branch" > $testroot/repo/epsilon/new
206 (cd $testroot/repo && git add epsilon/new)
207 git_commit $testroot/repo -m "committing more changes on newbranch"
209 local branch_rev=`git_show_head $testroot/repo`
211 # fake a merge conflict
212 echo '<<<<<<<' > $testroot/wt/alpha
213 echo 'alpha' >> $testroot/wt/alpha
214 echo '=======' >> $testroot/wt/alpha
215 echo 'alpha, too' >> $testroot/wt/alpha
216 echo '>>>>>>>' >> $testroot/wt/alpha
217 cp $testroot/wt/alpha $testroot/content.expected
219 echo "C alpha" > $testroot/stdout.expected
220 (cd $testroot/wt && got status > $testroot/stdout)
221 cmp -s $testroot/stdout.expected $testroot/stdout
222 ret=$?
223 if [ $ret -ne 0 ]; then
224 diff -u $testroot/stdout.expected $testroot/stdout
225 test_done "$testroot" "$ret"
226 return 1
227 fi
229 (cd $testroot/wt && got cherrypick $branch_rev \
230 > $testroot/stdout 2> $testroot/stderr)
231 ret=$?
232 if [ $ret -eq 0 ]; then
233 echo "cherrypick succeeded unexpectedly" >&2
234 test_done "$testroot" "1"
235 return 1
236 fi
238 echo -n > $testroot/stdout.expected
239 echo -n "got: work tree contains conflicted files; " \
240 > $testroot/stderr.expected
241 echo "these conflicts must be resolved first" \
242 >> $testroot/stderr.expected
244 cmp -s $testroot/stdout.expected $testroot/stdout
245 ret=$?
246 if [ $ret -ne 0 ]; then
247 diff -u $testroot/stdout.expected $testroot/stdout
248 test_done "$testroot" "$ret"
249 return 1
250 fi
252 cmp -s $testroot/stderr.expected $testroot/stderr
253 ret=$?
254 if [ $ret -ne 0 ]; then
255 diff -u $testroot/stderr.expected $testroot/stderr
256 test_done "$testroot" "$ret"
257 return 1
258 fi
260 cmp -s $testroot/content.expected $testroot/wt/alpha
261 ret=$?
262 if [ $ret -ne 0 ]; then
263 diff -u $testroot/content.expected $testroot/wt/alpha
264 fi
265 test_done "$testroot" "$ret"
268 test_cherrypick_into_work_tree_with_mixed_commits() {
269 local testroot=`test_init cherrypick_into_work_tree_with_mixed_commits`
270 local first_rev=`git_show_head $testroot/repo`
272 echo "modified alpha" > $testroot/repo/alpha
273 git_commit $testroot/repo -m "committing to alpha"
274 local second_rev=`git_show_head $testroot/repo`
276 got checkout $testroot/repo $testroot/wt > /dev/null
277 ret=$?
278 if [ $ret -ne 0 ]; then
279 test_done "$testroot" "$ret"
280 return 1
281 fi
283 (cd $testroot/repo && git checkout -q -b newbranch)
284 echo "modified delta on branch" > $testroot/repo/gamma/delta
285 git_commit $testroot/repo -m "committing to delta on newbranch"
287 (cd $testroot/repo && git rm -q beta)
288 echo "new file on branch" > $testroot/repo/epsilon/new
289 (cd $testroot/repo && git add epsilon/new)
290 git_commit $testroot/repo -m "committing more changes on newbranch"
292 local branch_rev=`git_show_head $testroot/repo`
294 (cd $testroot/wt && got update -c $first_rev alpha >/dev/null)
296 (cd $testroot/wt && got cherrypick $branch_rev \
297 > $testroot/stdout 2> $testroot/stderr)
298 ret=$?
299 if [ $ret -eq 0 ]; then
300 echo "cherrypick succeeded unexpectedly" >&2
301 test_done "$testroot" "1"
302 return 1
303 fi
305 echo -n > $testroot/stdout.expected
306 echo -n "got: work tree contains files from multiple base commits; " \
307 > $testroot/stderr.expected
308 echo "the entire work tree must be updated first" \
309 >> $testroot/stderr.expected
311 cmp -s $testroot/stdout.expected $testroot/stdout
312 ret=$?
313 if [ $ret -ne 0 ]; then
314 diff -u $testroot/stdout.expected $testroot/stdout
315 test_done "$testroot" "$ret"
316 return 1
317 fi
319 cmp -s $testroot/stderr.expected $testroot/stderr
320 ret=$?
321 if [ $ret -ne 0 ]; then
322 diff -u $testroot/stderr.expected $testroot/stderr
323 fi
324 test_done "$testroot" "$ret"
328 test_cherrypick_modified_submodule() {
329 local testroot=`test_init cherrypick_modified_submodules`
331 make_single_file_repo $testroot/repo2 foo
333 (cd $testroot/repo && git -c protocol.file.allow=always \
334 submodule -q add ../repo2)
335 (cd $testroot/repo && git commit -q -m 'adding submodule')
337 got checkout $testroot/repo $testroot/wt > /dev/null
339 echo "modified foo" > $testroot/repo2/foo
340 (cd $testroot/repo2 && git commit -q -a -m 'modified a submodule')
342 (cd $testroot/repo && git checkout -q -b newbranch)
343 # Update the repo/repo2 submodule link on newbranch
344 (cd $testroot/repo && git -C repo2 pull -q)
345 (cd $testroot/repo && git add repo2)
346 git_commit $testroot/repo -m "modified submodule link"
347 local commit_id=`git_show_head $testroot/repo`
349 # This cherrypick is a no-op because Got's file index
350 # does not track submodules.
351 (cd $testroot/wt && got cherrypick $commit_id > $testroot/stdout)
353 echo -n > $testroot/stdout.expected
354 cmp -s $testroot/stdout.expected $testroot/stdout
355 ret=$?
356 if [ $ret -ne 0 ]; then
357 diff -u $testroot/stdout.expected $testroot/stdout
358 fi
359 test_done "$testroot" "$ret"
362 test_cherrypick_added_submodule() {
363 local testroot=`test_init cherrypick_added_submodules`
365 got checkout $testroot/repo $testroot/wt > /dev/null
367 make_single_file_repo $testroot/repo2 foo
369 # Add the repo/repo2 submodule on newbranch
370 (cd $testroot/repo && git checkout -q -b newbranch)
371 (cd $testroot/repo && git -c protocol.file.allow=always \
372 submodule -q add ../repo2)
373 (cd $testroot/repo && git commit -q -m 'adding submodule')
374 local commit_id=`git_show_head $testroot/repo`
376 (cd $testroot/wt && got cherrypick $commit_id > $testroot/stdout)
378 echo "A .gitmodules" > $testroot/stdout.expected
379 echo "Merged commit $commit_id" >> $testroot/stdout.expected
380 cmp -s $testroot/stdout.expected $testroot/stdout
381 ret=$?
382 if [ $ret -ne 0 ]; then
383 diff -u $testroot/stdout.expected $testroot/stdout
384 fi
385 test_done "$testroot" "$ret"
388 test_cherrypick_conflict_wt_file_vs_repo_submodule() {
389 local testroot=`test_init cherrypick_conflict_wt_file_vs_repo_submodule`
391 got checkout $testroot/repo $testroot/wt > /dev/null
393 # Add a file which will clash with the submodule
394 echo "This is a file called repo2" > $testroot/wt/repo2
395 (cd $testroot/wt && got add repo2 > /dev/null)
396 (cd $testroot/wt && got commit -m 'add file repo2' > /dev/null)
397 ret=$?
398 if [ $ret -ne 0 ]; then
399 echo "commit failed unexpectedly" >&2
400 test_done "$testroot" "1"
401 return 1
402 fi
404 make_single_file_repo $testroot/repo2 foo
406 # Add the repo/repo2 submodule on newbranch
407 (cd $testroot/repo && git checkout -q -b newbranch)
408 (cd $testroot/repo && git -c protocol.file.allow=always \
409 submodule -q add ../repo2)
410 (cd $testroot/repo && git commit -q -m 'adding submodule')
411 local commit_id=`git_show_head $testroot/repo`
413 # Modify the clashing file such that any modifications brought
414 # in by 'got cherrypick' would require a merge.
415 echo "This file was changed" > $testroot/wt/repo2
417 (cd $testroot/wt && got update >/dev/null)
418 (cd $testroot/wt && got cherrypick $commit_id > $testroot/stdout)
420 echo "A .gitmodules" > $testroot/stdout.expected
421 echo "Merged commit $commit_id" >> $testroot/stdout.expected
422 cmp -s $testroot/stdout.expected $testroot/stdout
423 ret=$?
424 if [ $ret -ne 0 ]; then
425 diff -u $testroot/stdout.expected $testroot/stdout
426 test_done "$testroot" "$ret"
427 return 1
428 fi
430 (cd $testroot/wt && got status > $testroot/stdout)
432 echo "A .gitmodules" > $testroot/stdout.expected
433 echo "M repo2" >> $testroot/stdout.expected
434 cmp -s $testroot/stdout.expected $testroot/stdout
435 ret=$?
436 if [ $ret -ne 0 ]; then
437 diff -u $testroot/stdout.expected $testroot/stdout
438 fi
439 test_done "$testroot" "$ret"
442 test_cherrypick_modified_symlinks() {
443 local testroot=`test_init cherrypick_modified_symlinks`
445 (cd $testroot/repo && ln -s alpha alpha.link)
446 (cd $testroot/repo && ln -s epsilon epsilon.link)
447 (cd $testroot/repo && ln -s /etc/passwd passwd.link)
448 (cd $testroot/repo && ln -s ../beta epsilon/beta.link)
449 (cd $testroot/repo && ln -s nonexistent nonexistent.link)
450 (cd $testroot/repo && git add .)
451 git_commit $testroot/repo -m "add symlinks"
452 local commit_id1=`git_show_head $testroot/repo`
454 got tree -r $testroot/repo -R -c $commit_id1 \
455 > $testroot/stdout
456 cat > $testroot/stdout.expected <<EOF
457 alpha
458 alpha.link@ -> alpha
459 beta
460 epsilon/
461 epsilon/beta.link@ -> ../beta
462 epsilon/zeta
463 epsilon.link@ -> epsilon
464 gamma/
465 gamma/delta
466 nonexistent.link@ -> nonexistent
467 passwd.link@ -> /etc/passwd
468 EOF
469 cmp -s $testroot/stdout.expected $testroot/stdout
470 ret=$?
471 if [ $ret -ne 0 ]; then
472 diff -u $testroot/stdout.expected $testroot/stdout
473 test_done "$testroot" "$ret"
474 return 1
475 fi
477 got branch -r $testroot/repo foo
479 got checkout -b foo $testroot/repo $testroot/wt > /dev/null
481 (cd $testroot/repo && ln -sf beta alpha.link)
482 (cd $testroot/repo && ln -sfh gamma epsilon.link)
483 (cd $testroot/repo && ln -sf ../gamma/delta epsilon/beta.link)
484 (cd $testroot/repo && ln -sf .got/foo $testroot/repo/dotgotfoo.link)
485 (cd $testroot/repo && git rm -q nonexistent.link)
486 (cd $testroot/repo && ln -sf epsilon/zeta zeta.link)
487 (cd $testroot/repo && git add .)
488 git_commit $testroot/repo -m "change symlinks"
489 local commit_id2=`git_show_head $testroot/repo`
491 (cd $testroot/wt && got cherrypick $commit_id2 > $testroot/stdout)
493 echo "G alpha.link" > $testroot/stdout.expected
494 echo "G epsilon/beta.link" >> $testroot/stdout.expected
495 echo "A dotgotfoo.link" >> $testroot/stdout.expected
496 echo "G epsilon.link" >> $testroot/stdout.expected
497 echo "D nonexistent.link" >> $testroot/stdout.expected
498 echo "A zeta.link" >> $testroot/stdout.expected
499 echo "Merged commit $commit_id2" >> $testroot/stdout.expected
500 cmp -s $testroot/stdout.expected $testroot/stdout
501 ret=$?
502 if [ $ret -ne 0 ]; then
503 diff -u $testroot/stdout.expected $testroot/stdout
504 test_done "$testroot" "$ret"
505 return 1
506 fi
508 if ! [ -h $testroot/wt/alpha.link ]; then
509 echo "alpha.link is not a symlink"
510 test_done "$testroot" "1"
511 return 1
512 fi
514 readlink $testroot/wt/alpha.link > $testroot/stdout
515 echo "beta" > $testroot/stdout.expected
516 cmp -s $testroot/stdout.expected $testroot/stdout
517 ret=$?
518 if [ $ret -ne 0 ]; then
519 diff -u $testroot/stdout.expected $testroot/stdout
520 test_done "$testroot" "$ret"
521 return 1
522 fi
524 if ! [ -h $testroot/wt/dotgotfoo.link ]; then
525 echo "dotgotfoo.link is not a symlink"
526 test_done "$testroot" "1"
527 return 1
528 fi
530 readlink $testroot/wt/dotgotfoo.link > $testroot/stdout
531 echo ".got/foo" > $testroot/stdout.expected
532 cmp -s $testroot/stdout.expected $testroot/stdout
533 ret=$?
534 if [ $ret -ne 0 ]; then
535 diff -u $testroot/stdout.expected $testroot/stdout
536 test_done "$testroot" "$ret"
537 return 1
538 fi
540 if ! [ -h $testroot/wt/epsilon.link ]; then
541 echo "epsilon.link is not a symlink"
542 test_done "$testroot" "1"
543 return 1
544 fi
546 readlink $testroot/wt/epsilon.link > $testroot/stdout
547 echo "gamma" > $testroot/stdout.expected
548 cmp -s $testroot/stdout.expected $testroot/stdout
549 ret=$?
550 if [ $ret -ne 0 ]; then
551 diff -u $testroot/stdout.expected $testroot/stdout
552 test_done "$testroot" "$ret"
553 return 1
554 fi
556 if [ -h $testroot/wt/passwd.link ]; then
557 echo -n "passwd.link symlink points outside of work tree: " >&2
558 readlink $testroot/wt/passwd.link >&2
559 test_done "$testroot" "1"
560 return 1
561 fi
563 echo -n "/etc/passwd" > $testroot/content.expected
564 cp $testroot/wt/passwd.link $testroot/content
566 cmp -s $testroot/content.expected $testroot/content
567 ret=$?
568 if [ $ret -ne 0 ]; then
569 diff -u $testroot/content.expected $testroot/content
570 test_done "$testroot" "$ret"
571 return 1
572 fi
574 readlink $testroot/wt/epsilon/beta.link > $testroot/stdout
575 echo "../gamma/delta" > $testroot/stdout.expected
576 cmp -s $testroot/stdout.expected $testroot/stdout
577 ret=$?
578 if [ $ret -ne 0 ]; then
579 diff -u $testroot/stdout.expected $testroot/stdout
580 test_done "$testroot" "$ret"
581 return 1
582 fi
584 if [ -h $testroot/wt/nonexistent.link ]; then
585 echo -n "nonexistent.link still exists on disk: " >&2
586 readlink $testroot/wt/nonexistent.link >&2
587 test_done "$testroot" "1"
588 return 1
589 fi
591 (cd $testroot/wt && got commit -m 'commit cherrypick result' \
592 > /dev/null 2>$testroot/stderr)
593 ret=$?
594 if [ $ret -eq 0 ]; then
595 echo "got commit succeeded unexpectedly" >&2
596 test_done "$testroot" "1"
597 return 1
598 fi
599 echo -n "got: $testroot/wt/dotgotfoo.link: symbolic link points " \
600 > $testroot/stderr.expected
601 echo "outside of paths under version control" \
602 >> $testroot/stderr.expected
603 cmp -s $testroot/stderr.expected $testroot/stderr
604 ret=$?
605 if [ $ret -ne 0 ]; then
606 diff -u $testroot/stderr.expected $testroot/stderr
607 test_done "$testroot" "$ret"
608 return 1
609 fi
611 (cd $testroot/wt && got commit -S -m 'commit cherrypick result' \
612 > /dev/null)
613 ret=$?
614 if [ $ret -ne 0 ]; then
615 echo "got commit failed unexpectedly" >&2
616 test_done "$testroot" "$ret"
617 return 1
618 fi
619 local commit_id2=`git_show_head $testroot/repo`
621 got tree -r $testroot/repo -R -c $commit_id2 \
622 > $testroot/stdout
623 cat > $testroot/stdout.expected <<EOF
624 alpha
625 alpha.link@ -> beta
626 beta
627 dotgotfoo.link@ -> .got/foo
628 epsilon/
629 epsilon/beta.link@ -> ../gamma/delta
630 epsilon/zeta
631 epsilon.link@ -> gamma
632 gamma/
633 gamma/delta
634 passwd.link@ -> /etc/passwd
635 zeta.link@ -> epsilon/zeta
636 EOF
637 cmp -s $testroot/stdout.expected $testroot/stdout
638 ret=$?
639 if [ $ret -ne 0 ]; then
640 diff -u $testroot/stdout.expected $testroot/stdout
641 fi
642 test_done "$testroot" "$ret"
645 test_cherrypick_symlink_conflicts() {
646 local testroot=`test_init cherrypick_symlink_conflicts`
648 (cd $testroot/repo && ln -s alpha alpha.link)
649 (cd $testroot/repo && ln -s epsilon epsilon.link)
650 (cd $testroot/repo && ln -s /etc/passwd passwd.link)
651 (cd $testroot/repo && ln -s ../beta epsilon/beta.link)
652 (cd $testroot/repo && ln -s nonexistent nonexistent.link)
653 (cd $testroot/repo && ln -sf epsilon/zeta zeta.link)
654 (cd $testroot/repo && git add .)
655 git_commit $testroot/repo -m "add symlinks"
656 local commit_id1=`git_show_head $testroot/repo`
658 (cd $testroot/repo && ln -sf beta alpha.link)
659 (cd $testroot/repo && ln -sf beta boo.link)
660 (cd $testroot/repo && ln -sfh gamma epsilon.link)
661 (cd $testroot/repo && ln -sf ../gamma/delta epsilon/beta.link)
662 echo 'this is regular file foo' > $testroot/repo/dotgotfoo.link
663 (cd $testroot/repo && ln -sf .got/bar dotgotbar.link)
664 (cd $testroot/repo && git rm -q nonexistent.link)
665 (cd $testroot/repo && ln -sf gamma/delta zeta.link)
666 (cd $testroot/repo && ln -sf alpha new.link)
667 (cd $testroot/repo && git add .)
668 git_commit $testroot/repo -m "change symlinks"
669 local commit_id2=`git_show_head $testroot/repo`
671 got branch -r $testroot/repo -c $commit_id1 foo
672 got checkout -b foo $testroot/repo $testroot/wt > /dev/null
674 # modified symlink to file A vs modified symlink to file B
675 (cd $testroot/wt && ln -sf gamma/delta alpha.link)
676 # modified symlink to dir A vs modified symlink to file B
677 (cd $testroot/wt && ln -sfh beta epsilon.link)
678 # modeified symlink to file A vs modified symlink to dir B
679 (cd $testroot/wt && ln -sfh ../gamma epsilon/beta.link)
680 # added regular file A vs added bad symlink to file A
681 (cd $testroot/wt && ln -sf .got/foo dotgotfoo.link)
682 (cd $testroot/wt && got add dotgotfoo.link > /dev/null)
683 # added bad symlink to file A vs added regular file A
684 echo 'this is regular file bar' > $testroot/wt/dotgotbar.link
685 (cd $testroot/wt && got add dotgotbar.link > /dev/null)
686 # added symlink to file A vs unversioned file A
687 echo 'this is unversioned file boo' > $testroot/wt/boo.link
688 # removed symlink to non-existent file A vs modified symlink
689 # to nonexistent file B
690 (cd $testroot/wt && ln -sf nonexistent2 nonexistent.link)
691 # modified symlink to file A vs removed symlink to file A
692 (cd $testroot/wt && got rm zeta.link > /dev/null)
693 # added symlink to file A vs added symlink to file B
694 (cd $testroot/wt && ln -sf beta new.link)
695 (cd $testroot/wt && got add new.link > /dev/null)
696 (cd $testroot/wt && got commit -S -m "change symlinks on foo" \
697 > /dev/null)
699 (cd $testroot/wt && got update >/dev/null)
700 (cd $testroot/wt && got cherrypick $commit_id2 > $testroot/stdout)
702 echo -n > $testroot/stdout.expected
703 echo "C alpha.link" >> $testroot/stdout.expected
704 echo "C epsilon/beta.link" >> $testroot/stdout.expected
705 echo "? boo.link" >> $testroot/stdout.expected
706 echo "C epsilon.link" >> $testroot/stdout.expected
707 echo "C dotgotbar.link" >> $testroot/stdout.expected
708 echo "C dotgotfoo.link" >> $testroot/stdout.expected
709 echo "D nonexistent.link" >> $testroot/stdout.expected
710 echo "! zeta.link" >> $testroot/stdout.expected
711 echo "C new.link" >> $testroot/stdout.expected
712 echo "Merged commit $commit_id2" >> $testroot/stdout.expected
713 echo "Files with new merge conflicts: 6" >> $testroot/stdout.expected
714 echo -n "Files which had incoming changes but could not be found " \
715 >> $testroot/stdout.expected
716 echo "in the work tree: 1" >> $testroot/stdout.expected
717 echo -n "Files not merged because an unversioned file was found in " \
718 >> $testroot/stdout.expected
719 echo "the work tree: 1" >> $testroot/stdout.expected
720 cmp -s $testroot/stdout.expected $testroot/stdout
721 ret=$?
722 if [ $ret -ne 0 ]; then
723 diff -u $testroot/stdout.expected $testroot/stdout
724 test_done "$testroot" "$ret"
725 return 1
726 fi
728 if [ -h $testroot/wt/alpha.link ]; then
729 echo "alpha.link is a symlink"
730 test_done "$testroot" "1"
731 return 1
732 fi
734 echo "<<<<<<< merged change: commit $commit_id2" \
735 > $testroot/content.expected
736 echo "beta" >> $testroot/content.expected
737 echo "3-way merge base: commit $commit_id1" \
738 >> $testroot/content.expected
739 echo "alpha" >> $testroot/content.expected
740 echo "=======" >> $testroot/content.expected
741 echo "gamma/delta" >> $testroot/content.expected
742 echo '>>>>>>>' >> $testroot/content.expected
743 echo -n "" >> $testroot/content.expected
745 cp $testroot/wt/alpha.link $testroot/content
746 cmp -s $testroot/content.expected $testroot/content
747 ret=$?
748 if [ $ret -ne 0 ]; then
749 diff -u $testroot/content.expected $testroot/content
750 test_done "$testroot" "$ret"
751 return 1
752 fi
754 if [ -h $testroot/wt/boo.link ]; then
755 echo "boo.link is a symlink"
756 test_done "$testroot" "1"
757 return 1
758 fi
760 echo "this is unversioned file boo" > $testroot/content.expected
761 cp $testroot/wt/boo.link $testroot/content
762 cmp -s $testroot/content.expected $testroot/content
763 ret=$?
764 if [ $ret -ne 0 ]; then
765 diff -u $testroot/content.expected $testroot/content
766 test_done "$testroot" "$ret"
767 return 1
768 fi
770 if [ -h $testroot/wt/epsilon.link ]; then
771 echo "epsilon.link is a symlink"
772 test_done "$testroot" "1"
773 return 1
774 fi
776 echo "<<<<<<< merged change: commit $commit_id2" \
777 > $testroot/content.expected
778 echo "gamma" >> $testroot/content.expected
779 echo "3-way merge base: commit $commit_id1" \
780 >> $testroot/content.expected
781 echo "epsilon" >> $testroot/content.expected
782 echo "=======" >> $testroot/content.expected
783 echo "beta" >> $testroot/content.expected
784 echo '>>>>>>>' >> $testroot/content.expected
785 echo -n "" >> $testroot/content.expected
787 cp $testroot/wt/epsilon.link $testroot/content
788 cmp -s $testroot/content.expected $testroot/content
789 ret=$?
790 if [ $ret -ne 0 ]; then
791 diff -u $testroot/content.expected $testroot/content
792 test_done "$testroot" "$ret"
793 return 1
794 fi
796 if [ -h $testroot/wt/passwd.link ]; then
797 echo -n "passwd.link symlink points outside of work tree: " >&2
798 readlink $testroot/wt/passwd.link >&2
799 test_done "$testroot" "1"
800 return 1
801 fi
803 echo -n "/etc/passwd" > $testroot/content.expected
804 cp $testroot/wt/passwd.link $testroot/content
806 cmp -s $testroot/content.expected $testroot/content
807 ret=$?
808 if [ $ret -ne 0 ]; then
809 diff -u $testroot/content.expected $testroot/content
810 test_done "$testroot" "$ret"
811 return 1
812 fi
814 if [ -h $testroot/wt/epsilon/beta.link ]; then
815 echo "epsilon/beta.link is a symlink"
816 test_done "$testroot" "1"
817 return 1
818 fi
820 echo "<<<<<<< merged change: commit $commit_id2" \
821 > $testroot/content.expected
822 echo "../gamma/delta" >> $testroot/content.expected
823 echo "3-way merge base: commit $commit_id1" \
824 >> $testroot/content.expected
825 echo "../beta" >> $testroot/content.expected
826 echo "=======" >> $testroot/content.expected
827 echo "../gamma" >> $testroot/content.expected
828 echo '>>>>>>>' >> $testroot/content.expected
829 echo -n "" >> $testroot/content.expected
831 cp $testroot/wt/epsilon/beta.link $testroot/content
832 cmp -s $testroot/content.expected $testroot/content
833 ret=$?
834 if [ $ret -ne 0 ]; then
835 diff -u $testroot/content.expected $testroot/content
836 test_done "$testroot" "$ret"
837 return 1
838 fi
840 if [ -h $testroot/wt/nonexistent.link ]; then
841 echo -n "nonexistent.link still exists on disk: " >&2
842 readlink $testroot/wt/nonexistent.link >&2
843 test_done "$testroot" "1"
844 return 1
845 fi
847 if [ -h $testroot/wt/dotgotfoo.link ]; then
848 echo "dotgotfoo.link is a symlink"
849 test_done "$testroot" "1"
850 return 1
851 fi
853 echo "<<<<<<< merged change: commit $commit_id2" \
854 > $testroot/content.expected
855 echo "this is regular file foo" >> $testroot/content.expected
856 echo "=======" >> $testroot/content.expected
857 echo -n ".got/foo" >> $testroot/content.expected
858 echo '>>>>>>>' >> $testroot/content.expected
859 cp $testroot/wt/dotgotfoo.link $testroot/content
860 cmp -s $testroot/content.expected $testroot/content
861 ret=$?
862 if [ $ret -ne 0 ]; then
863 diff -u $testroot/content.expected $testroot/content
864 test_done "$testroot" "$ret"
865 return 1
866 fi
868 if [ -h $testroot/wt/dotgotbar.link ]; then
869 echo "dotgotbar.link is a symlink"
870 test_done "$testroot" "1"
871 return 1
872 fi
873 echo "<<<<<<< merged change: commit $commit_id2" \
874 > $testroot/content.expected
875 echo -n ".got/bar" >> $testroot/content.expected
876 echo "=======" >> $testroot/content.expected
877 echo "this is regular file bar" >> $testroot/content.expected
878 echo '>>>>>>>' >> $testroot/content.expected
879 echo -n "" >> $testroot/content.expected
880 cp $testroot/wt/dotgotbar.link $testroot/content
881 cmp -s $testroot/content.expected $testroot/content
882 ret=$?
883 if [ $ret -ne 0 ]; then
884 diff -u $testroot/content.expected $testroot/content
885 test_done "$testroot" "$ret"
886 return 1
887 fi
889 if [ -h $testroot/wt/new.link ]; then
890 echo "new.link is a symlink"
891 test_done "$testroot" "1"
892 return 1
893 fi
895 echo "<<<<<<< merged change: commit $commit_id2" \
896 > $testroot/content.expected
897 echo "alpha" >> $testroot/content.expected
898 echo "=======" >> $testroot/content.expected
899 echo "beta" >> $testroot/content.expected
900 echo '>>>>>>>' >> $testroot/content.expected
901 echo -n "" >> $testroot/content.expected
903 cp $testroot/wt/new.link $testroot/content
904 cmp -s $testroot/content.expected $testroot/content
905 ret=$?
906 if [ $ret -ne 0 ]; then
907 diff -u $testroot/content.expected $testroot/content
908 test_done "$testroot" "$ret"
909 return 1
910 fi
912 echo "A dotgotfoo.link" > $testroot/stdout.expected
913 echo "M new.link" >> $testroot/stdout.expected
914 echo "D nonexistent.link" >> $testroot/stdout.expected
915 (cd $testroot/wt && got status > $testroot/stdout)
916 ret=$?
917 if [ $ret -ne 0 ]; then
918 diff -u $testroot/stdout.expected $testroot/stdout
919 test_done "$testroot" "$ret"
920 return 1
921 fi
923 test_done "$testroot" "0"
926 test_cherrypick_with_path_prefix_and_empty_tree() {
927 local testroot=`test_init cherrypick_with_path_prefix_and_empty_tree 1`
929 (cd $testroot/repo && git commit --allow-empty \
930 -m "initial empty commit" >/dev/null)
932 (cd $testroot/repo && got br bar >/dev/null)
934 mkdir -p $testroot/repo/epsilon
935 echo "file foo" > $testroot/repo/epsilon/foo
936 (cd $testroot/repo && git add .)
937 git_commit $testroot/repo -m "add file foo"
938 local commit_id=`git_show_head $testroot/repo`
940 got checkout -b bar $testroot/repo $testroot/wt > /dev/null
941 ret=$?
942 if [ $ret -ne 0 ]; then
943 echo "got checkout failed unexpectedly" >&2
944 test_done "$testroot" "$ret"
945 return 1
946 fi
948 mkdir -p $testroot/wt/epsilon
949 echo "new file" > $testroot/wt/epsilon/new
950 (cd $testroot/wt && got add epsilon/new >/dev/null)
951 (cd $testroot/wt && got commit -m "add file on branch bar" > /dev/null)
953 got checkout -b bar -p epsilon $testroot/repo $testroot/wt2 > /dev/null
954 ret=$?
955 if [ $ret -ne 0 ]; then
956 echo "got checkout failed unexpectedly" >&2
957 test_done "$testroot" "$ret"
958 return 1
959 fi
960 (cd $testroot/wt2 && got cherrypick $commit_id > $testroot/stdout)
962 echo "A foo" > $testroot/stdout.expected
963 echo "Merged commit $commit_id" >> $testroot/stdout.expected
965 cmp -s $testroot/stdout.expected $testroot/stdout
966 ret=$?
967 if [ $ret -ne 0 ]; then
968 diff -u $testroot/stdout.expected $testroot/stdout
969 fi
970 test_done "$testroot" "$ret"
973 test_cherrypick_conflict_no_eol() {
974 local testroot=`test_init cherrypick_conflict_no_eol 1`
975 local content_a="aaa\naaa\naaa\naaa\naaa\naaa\n"
976 local content_b="aaa\naaa\nbbb\naaa\naaa\naaa\naaa"
977 local content_c="aaa\naaa\nccc\naaa\naaa\naaa\naaa"
979 printf "$content_a" > $testroot/repo/a
980 (cd $testroot/repo && git add a)
981 git_commit $testroot/repo -m "initial commit"
983 (cd $testroot/repo && got branch newbranch)
985 printf "$content_b" > $testroot/repo/a
986 git_commit $testroot/repo -m "change bbb"
988 printf "$content_c" > $testroot/repo/a
989 git_commit $testroot/repo -m "change ccc"
990 local ccc_commit=`git_show_head $testroot/repo`
992 got checkout -b newbranch $testroot/repo $testroot/wt > /dev/null
993 ret=$?
994 if [ $ret -ne 0 ]; then
995 test_done "$testroot" "$ret"
996 return 1
997 fi
999 (cd $testroot/wt && got cherrypick $ccc_commit > $testroot/stdout)
1001 echo "C a" > $testroot/stdout.expected
1002 echo "Merged commit $ccc_commit" >> $testroot/stdout.expected
1003 echo "Files with new merge conflicts: 1" >> $testroot/stdout.expected
1005 cmp -s $testroot/stdout.expected $testroot/stdout
1006 ret=$?
1007 if [ $ret -ne 0 ]; then
1008 diff -u $testroot/stdout.expected $testroot/stdout
1010 test_done "$testroot" "$ret"
1013 test_cherrypick_conflict_no_eol2() {
1014 local testroot=`test_init cherrypick_conflict_no_eol2 1`
1015 local content_a="aaa\naaa\naaa\naaa\naaa\naaa"
1016 local content_b="aaa\naaa\nbbb\naaa\naaa\naaa"
1017 local content_c="aaa\naaa\nbbb\naaa\naaa\naaa\n"
1019 printf "$content_a" > $testroot/repo/a
1020 (cd $testroot/repo && git add a)
1021 git_commit $testroot/repo -m "initial commit"
1023 (cd $testroot/repo && got branch newbranch)
1025 printf "$content_b" > $testroot/repo/a
1026 git_commit $testroot/repo -m "change bbb"
1028 printf "$content_c" > $testroot/repo/a
1029 git_commit $testroot/repo -m "change ccc"
1030 local ccc_commit=`git_show_head $testroot/repo`
1032 got checkout -b newbranch $testroot/repo $testroot/wt > /dev/null
1033 ret=$?
1034 if [ $ret -ne 0 ]; then
1035 test_done "$testroot" "$ret"
1036 return 1
1039 (cd $testroot/wt && got cherrypick $ccc_commit \
1040 > $testroot/stdout 2> $testroot/stderr)
1042 echo "C a" > $testroot/stdout.expected
1043 echo "Merged commit $ccc_commit" >> $testroot/stdout.expected
1044 echo "Files with new merge conflicts: 1" >> $testroot/stdout.expected
1046 cmp -s $testroot/stdout.expected $testroot/stdout
1047 ret=$?
1048 if [ $ret -ne 0 ]; then
1049 diff -u $testroot/stdout.expected $testroot/stdout
1051 test_done "$testroot" "$ret"
1054 test_cherrypick_unrelated_changes() {
1055 local testroot=`test_init cherrypick_unrelated_changes`
1057 # Sorry about the large HERE document but I have not found
1058 # a smaller reproduction recipe yet...
1059 cat > $testroot/repo/reference.c <<EOF
1060 const struct got_error *
1061 got_ref_alloc(struct got_reference **ref, const char *name,
1062 struct got_object_id *id)
1064 if (!is_valid_ref_name(name))
1065 return got_error_path(name, GOT_ERR_BAD_REF_NAME);
1067 return alloc_ref(ref, name, id, 0);
1070 static const struct got_error *
1071 parse_packed_ref_line(struct got_reference **ref, const char *abs_refname,
1072 const char *line)
1074 struct got_object_id id;
1075 const char *name;
1077 *ref = NULL;
1079 if (line[0] == '#' || line[0] == '^')
1080 return NULL;
1082 if (!got_parse_sha1_digest(id.sha1, line))
1083 return got_error(GOT_ERR_BAD_REF_DATA);
1085 if (abs_refname) {
1086 if (strcmp(line + SHA1_DIGEST_STRING_LENGTH, abs_refname) != 0)
1087 return NULL;
1088 name = abs_refname;
1089 } else
1090 name = line + SHA1_DIGEST_STRING_LENGTH;
1092 return alloc_ref(ref, name, &id, GOT_REF_IS_PACKED);
1095 static const struct got_error *
1096 open_packed_ref(struct got_reference **ref, FILE *f, const char **subdirs,
1097 int nsubdirs, const char *refname)
1099 const struct got_error *err = NULL;
1100 char *abs_refname;
1101 char *line = NULL;
1102 size_t linesize = 0;
1103 ssize_t linelen;
1104 int i, ref_is_absolute = (strncmp(refname, "refs/", 5) == 0);
1106 *ref = NULL;
1108 if (ref_is_absolute)
1109 abs_refname = (char *)refname;
1110 do {
1111 linelen = getline(&line, &linesize, f);
1112 if (linelen == -1) {
1113 if (feof(f))
1114 break;
1115 err = got_ferror(f, GOT_ERR_BAD_REF_DATA);
1116 break;
1118 if (linelen > 0 && line[linelen - 1] == '\n')
1119 line[linelen - 1] = '\0';
1120 for (i = 0; i < nsubdirs; i++) {
1121 if (!ref_is_absolute &&
1122 asprintf(&abs_refname, "refs/%s/%s", subdirs[i],
1123 refname) == -1)
1124 return got_error_from_errno("asprintf");
1125 err = parse_packed_ref_line(ref, abs_refname, line);
1126 if (!ref_is_absolute)
1127 free(abs_refname);
1128 if (err || *ref != NULL)
1129 break;
1131 if (err)
1132 break;
1133 } while (*ref == NULL);
1134 free(line);
1136 return err;
1139 static const struct got_error *
1140 open_ref(struct got_reference **ref, const char *path_refs, const char *subdir,
1141 const char *name, int lock)
1143 const struct got_error *err = NULL;
1144 char *path = NULL;
1145 char *absname = NULL;
1146 int ref_is_absolute = (strncmp(name, "refs/", 5) == 0);
1147 int ref_is_well_known = (subdir[0] == '\0' && is_well_known_ref(name));
1149 *ref = NULL;
1151 if (ref_is_absolute || ref_is_well_known) {
1152 if (asprintf(&path, "%s/%s", path_refs, name) == -1)
1153 return got_error_from_errno("asprintf");
1154 absname = (char *)name;
1155 } else {
1156 if (asprintf(&path, "%s/%s%s%s", path_refs, subdir,
1157 subdir[0] ? "/" : "", name) == -1)
1158 return got_error_from_errno("asprintf");
1160 if (asprintf(&absname, "refs/%s%s%s",
1161 subdir, subdir[0] ? "/" : "", name) == -1) {
1162 err = got_error_from_errno("asprintf");
1163 goto done;
1167 err = parse_ref_file(ref, name, absname, path, lock);
1168 done:
1169 if (!ref_is_absolute && !ref_is_well_known)
1170 free(absname);
1171 free(path);
1172 return err;
1175 const struct got_error *
1176 got_ref_open(struct got_reference **ref, struct got_repository *repo,
1177 const char *refname, int lock)
1179 const struct got_error *err = NULL;
1180 char *path_refs = NULL;
1181 const char *subdirs[] = {
1182 GOT_REF_HEADS, GOT_REF_TAGS, GOT_REF_REMOTES
1184 size_t i;
1185 int well_known = is_well_known_ref(refname);
1186 struct got_lockfile *lf = NULL;
1188 *ref = NULL;
1190 path_refs = get_refs_dir_path(repo, refname);
1191 if (path_refs == NULL) {
1192 err = got_error_from_errno2("get_refs_dir_path", refname);
1193 goto done;
1196 if (well_known) {
1197 err = open_ref(ref, path_refs, "", refname, lock);
1198 } else {
1199 char *packed_refs_path;
1200 FILE *f;
1202 /* Search on-disk refs before packed refs! */
1203 for (i = 0; i < nitems(subdirs); i++) {
1204 err = open_ref(ref, path_refs, subdirs[i], refname,
1205 lock);
1206 if ((err && err->code != GOT_ERR_NOT_REF) || *ref)
1207 goto done;
1210 packed_refs_path = got_repo_get_path_packed_refs(repo);
1211 if (packed_refs_path == NULL) {
1212 err = got_error_from_errno(
1213 "got_repo_get_path_packed_refs");
1214 goto done;
1217 if (lock) {
1218 err = got_lockfile_lock(&lf, packed_refs_path);
1219 if (err)
1220 goto done;
1222 f = fopen(packed_refs_path, "rb");
1223 free(packed_refs_path);
1224 if (f != NULL) {
1225 err = open_packed_ref(ref, f, subdirs, nitems(subdirs),
1226 refname);
1227 if (!err) {
1228 if (fclose(f) == EOF) {
1229 err = got_error_from_errno("fclose");
1230 got_ref_close(*ref);
1231 *ref = NULL;
1232 } else if (*ref)
1233 (*ref)->lf = lf;
1237 done:
1238 if (!err && *ref == NULL)
1239 err = got_error_not_ref(refname);
1240 if (err && lf)
1241 got_lockfile_unlock(lf);
1242 free(path_refs);
1243 return err;
1246 struct got_reference *
1247 got_ref_dup(struct got_reference *ref)
1249 struct got_reference *ret;
1251 ret = calloc(1, sizeof(*ret));
1252 if (ret == NULL)
1253 return NULL;
1255 ret->flags = ref->flags;
1256 if (ref->flags & GOT_REF_IS_SYMBOLIC) {
1257 ret->ref.symref.name = strdup(ref->ref.symref.name);
1258 if (ret->ref.symref.name == NULL) {
1259 free(ret);
1260 return NULL;
1262 ret->ref.symref.ref = strdup(ref->ref.symref.ref);
1263 if (ret->ref.symref.ref == NULL) {
1264 free(ret->ref.symref.name);
1265 free(ret);
1266 return NULL;
1268 } else {
1269 ret->ref.ref.name = strdup(ref->ref.ref.name);
1270 if (ret->ref.ref.name == NULL) {
1271 free(ret);
1272 return NULL;
1274 memcpy(ret->ref.ref.sha1, ref->ref.ref.sha1,
1275 sizeof(ret->ref.ref.sha1));
1278 return ret;
1281 const struct got_error *
1282 got_reflist_entry_dup(struct got_reflist_entry **newp,
1283 struct got_reflist_entry *re)
1285 const struct got_error *err = NULL;
1286 struct got_reflist_entry *new;
1288 *newp = NULL;
1290 new = malloc(sizeof(*new));
1291 if (new == NULL)
1292 return got_error_from_errno("malloc");
1294 new->ref = got_ref_dup(re->ref);
1295 if (new->ref == NULL) {
1296 err = got_error_from_errno("got_ref_dup");
1297 free(new);
1298 return err;
1301 *newp = new;
1302 return NULL;
1305 void
1306 got_ref_list_free(struct got_reflist_head *refs)
1308 struct got_reflist_entry *re;
1310 while ((re = TAILQ_FIRST(refs))) {
1311 TAILQ_REMOVE(refs, re, entry);
1312 free(re);
1315 EOF
1316 (cd $testroot/repo && git add reference.c)
1317 git_commit $testroot/repo -m "added reference.c file"
1318 local base_commit=`git_show_head $testroot/repo`
1320 got checkout $testroot/repo $testroot/wt > /dev/null
1321 ret=$?
1322 if [ $ret -ne 0 ]; then
1323 test_done "$testroot" "$ret"
1324 return 1
1327 (cd $testroot/repo && git checkout -q -b newbranch)
1328 ed -s $testroot/repo/reference.c <<EOF
1329 91a
1330 if (!is_valid_ref_name(name))
1331 return got_error_path(name, GOT_ERR_BAD_REF_NAME);
1336 EOF
1337 git_commit $testroot/repo -m "added lines on newbranch"
1338 local branch_rev1=`git_show_head $testroot/repo`
1340 ed -s $testroot/repo/reference.c <<EOF
1341 255a
1342 got_ref_close(re->ref);
1346 EOF
1347 git_commit $testroot/repo -m "more lines on newbranch"
1349 local branch_rev2=`git_show_head $testroot/repo`
1351 (cd $testroot/wt && got cherrypick $branch_rev2 > $testroot/stdout)
1353 echo "G reference.c" > $testroot/stdout.expected
1354 echo "Merged commit $branch_rev2" >> $testroot/stdout.expected
1356 cmp -s $testroot/stdout.expected $testroot/stdout
1357 ret=$?
1358 if [ $ret -ne 0 ]; then
1359 diff -u $testroot/stdout.expected $testroot/stdout
1360 test_done "$testroot" "$ret"
1361 return 1
1364 cat > $testroot/diff.expected <<EOF
1365 --- reference.c
1366 +++ reference.c
1367 @@ -250,6 +250,7 @@ got_ref_list_free(struct got_reflist_head *refs)
1369 while ((re = TAILQ_FIRST(refs))) {
1370 TAILQ_REMOVE(refs, re, entry);
1371 + got_ref_close(re->ref);
1372 free(re);
1375 EOF
1376 (cd $testroot/wt && got diff |
1377 egrep -v '^(diff|blob|file|commit|path)' > $testroot/diff)
1378 cmp -s $testroot/diff.expected $testroot/diff
1379 ret=$?
1380 if [ $ret -ne 0 ]; then
1381 diff -u $testroot/diff.expected $testroot/diff
1384 test_done "$testroot" "$ret"
1387 test_cherrypick_same_branch() {
1388 local testroot=`test_init cherrypick_same_branch`
1390 got checkout $testroot/repo $testroot/wt > /dev/null
1391 ret=$?
1392 if [ $ret -ne 0 ]; then
1393 test_done "$testroot" "$ret"
1394 return 1
1397 (cd $testroot/repo && git checkout -q -b newbranch)
1398 echo "modified delta on branch" > $testroot/repo/gamma/delta
1399 git_commit $testroot/repo -m "committing to delta on newbranch"
1401 echo "modified alpha on branch" > $testroot/repo/alpha
1402 (cd $testroot/repo && git rm -q beta)
1403 echo "new file on branch" > $testroot/repo/epsilon/new
1404 (cd $testroot/repo && git add epsilon/new)
1405 git_commit $testroot/repo -m "committing more changes on newbranch"
1407 local branch_rev=`git_show_head $testroot/repo`
1409 # picking a commit from the branch's own history does not make
1410 # sense but we should have test coverage for this case regardless
1411 (cd $testroot/wt && got up -b newbranch > /dev/null)
1412 (cd $testroot/wt && got cherrypick $branch_rev > $testroot/stdout)
1414 echo "G alpha" > $testroot/stdout.expected
1415 echo "! beta" >> $testroot/stdout.expected
1416 echo "G epsilon/new" >> $testroot/stdout.expected
1417 echo "Merged commit $branch_rev" >> $testroot/stdout.expected
1418 echo -n "Files which had incoming changes but could not be found " \
1419 >> $testroot/stdout.expected
1420 echo "in the work tree: 1" >> $testroot/stdout.expected
1422 cmp -s $testroot/stdout.expected $testroot/stdout
1423 ret=$?
1424 if [ $ret -ne 0 ]; then
1425 diff -u $testroot/stdout.expected $testroot/stdout
1427 test_done "$testroot" "$ret"
1430 test_cherrypick_dot_on_a_line_by_itself() {
1431 local testroot=`test_init cherrypick_dot_on_a_line_by_itself`
1433 got checkout $testroot/repo $testroot/wt > /dev/null
1434 ret=$?
1435 if [ $ret -ne 0 ]; then
1436 test_done "$testroot" "$ret"
1437 return 1
1440 (cd $testroot/repo && git checkout -q -b newbranch)
1441 printf "modified\n:delta\n.\non\n:branch\n" > $testroot/repo/gamma/delta
1442 git_commit $testroot/repo -m "committing to delta on newbranch"
1443 local branch_rev=`git_show_head $testroot/repo`
1445 (cd $testroot/wt && got cherrypick newbranch > $testroot/stdout)
1447 echo "G gamma/delta" >> $testroot/stdout.expected
1448 echo "Merged commit $branch_rev" >> $testroot/stdout.expected
1450 cmp -s $testroot/stdout.expected $testroot/stdout
1451 ret=$?
1452 if [ $ret -ne 0 ]; then
1453 diff -u $testroot/stdout.expected $testroot/stdout
1454 test_done "$testroot" "$ret"
1455 return 1
1458 printf "modified\n:delta\n.\non\n:branch\n" > $testroot/content.expected
1459 cat $testroot/wt/gamma/delta > $testroot/content
1460 cmp -s $testroot/content.expected $testroot/content
1461 ret=$?
1462 if [ $ret -ne 0 ]; then
1463 diff -u $testroot/content.expected $testroot/content
1465 test_done "$testroot" "$ret"
1468 test_cherrypick_binary_file() {
1469 local testroot=`test_init cherrypick_binary_file`
1470 local commit_id0=`git_show_head $testroot/repo`
1472 got checkout $testroot/repo $testroot/wt > /dev/null
1473 ret=$?
1474 if [ $ret -ne 0 ]; then
1475 test_done "$testroot" "$ret"
1476 return 1
1479 cp /bin/ls $testroot/wt/foo
1480 chmod 755 $testroot/wt/foo
1481 (cd $testroot/wt && got add foo >/dev/null)
1482 (cd $testroot/wt && got commit -m 'add binary file' > /dev/null)
1483 local commit_id1=`git_show_head $testroot/repo`
1485 cp /bin/cat $testroot/wt/foo
1486 chmod 755 $testroot/wt/foo
1487 (cd $testroot/wt && got commit -m 'change binary file' > /dev/null)
1488 local commit_id2=`git_show_head $testroot/repo`
1490 cp /bin/cp $testroot/wt/foo
1491 chmod 755 $testroot/wt/foo
1492 (cd $testroot/wt && got commit -m 'change binary file' > /dev/null)
1493 local commit_id3=`git_show_head $testroot/repo`
1495 (cd $testroot/wt && got rm foo >/dev/null)
1496 (cd $testroot/wt && got commit -m 'remove binary file' > /dev/null)
1497 local commit_id4=`git_show_head $testroot/repo`
1499 # backdate the work tree to make it usable for cherry-picking
1500 (cd $testroot/wt && got up -c $commit_id0 > /dev/null)
1502 # cherry-pick addition of a binary file
1503 (cd $testroot/wt && got cy $commit_id1 > $testroot/stdout)
1505 echo "A foo" > $testroot/stdout.expected
1506 echo "Merged commit $commit_id1" >> $testroot/stdout.expected
1508 cmp -s $testroot/stdout.expected $testroot/stdout
1509 ret=$?
1510 if [ $ret -ne 0 ]; then
1511 diff -u $testroot/stdout.expected $testroot/stdout
1512 test_done "$testroot" "$ret"
1513 return 1
1516 cp /bin/ls $testroot/content.expected
1517 chmod 755 $testroot/content.expected
1518 cp $testroot/wt/foo $testroot/content
1519 cmp -s $testroot/content.expected $testroot/content
1520 ret=$?
1521 if [ $ret -ne 0 ]; then
1522 diff -u $testroot/content.expected $testroot/content
1523 test_done "$testroot" "$ret"
1524 return 1
1527 # cherry-pick modification of a binary file
1528 (cd $testroot/wt && got cy $commit_id2 > $testroot/stdout)
1530 echo "G foo" > $testroot/stdout.expected
1531 echo "Merged commit $commit_id2" >> $testroot/stdout.expected
1533 cmp -s $testroot/stdout.expected $testroot/stdout
1534 ret=$?
1535 if [ $ret -ne 0 ]; then
1536 diff -u $testroot/stdout.expected $testroot/stdout
1537 test_done "$testroot" "$ret"
1538 return 1
1541 cp /bin/cat $testroot/content.expected
1542 chmod 755 $testroot/content.expected
1543 cp $testroot/wt/foo $testroot/content
1544 cmp -s $testroot/content.expected $testroot/content
1545 ret=$?
1546 if [ $ret -ne 0 ]; then
1547 diff -u $testroot/content.expected $testroot/content
1548 test_done "$testroot" "$ret"
1549 return 1
1552 # cherry-pick conflicting addition of a binary file
1553 (cd $testroot/wt && got cy $commit_id1 > $testroot/stdout)
1555 echo "C foo" > $testroot/stdout.expected
1556 echo "Merged commit $commit_id1" >> $testroot/stdout.expected
1557 echo "Files with new merge conflicts: 1" >> $testroot/stdout.expected
1559 cmp -s $testroot/stdout.expected $testroot/stdout
1560 ret=$?
1561 if [ $ret -ne 0 ]; then
1562 diff -u $testroot/stdout.expected $testroot/stdout
1563 test_done "$testroot" "$ret"
1564 return 1
1567 echo "Binary files differ and cannot be merged automatically:" \
1568 > $testroot/content.expected
1569 echo "<<<<<<< merged change: commit $commit_id1" \
1570 >> $testroot/content.expected
1571 echo -n "file " >> $testroot/content.expected
1572 ls $testroot/wt/foo-1-* >> $testroot/content.expected
1573 echo '=======' >> $testroot/content.expected
1574 echo -n "file " >> $testroot/content.expected
1575 ls $testroot/wt/foo-2-* >> $testroot/content.expected
1576 echo '>>>>>>>' >> $testroot/content.expected
1577 cp $testroot/wt/foo $testroot/content
1578 cmp -s $testroot/content.expected $testroot/content
1579 ret=$?
1580 if [ $ret -ne 0 ]; then
1581 diff -u $testroot/content.expected $testroot/content
1582 test_done "$testroot" "$ret"
1583 return 1
1586 # revert local changes to allow further testing
1587 (cd $testroot/wt && got revert -R . >/dev/null)
1589 (cd $testroot/wt && got status > $testroot/stdout)
1590 echo '? foo' > $testroot/stdout.expected
1591 echo -n '? ' >> $testroot/stdout.expected
1592 (cd $testroot/wt && ls foo-1-* >> $testroot/stdout.expected)
1593 echo -n '? ' >> $testroot/stdout.expected
1594 (cd $testroot/wt && ls foo-2-* >> $testroot/stdout.expected)
1595 cmp -s $testroot/stdout.expected $testroot/stdout
1596 ret=$?
1597 if [ $ret -ne 0 ]; then
1598 diff -u $testroot/stdout.expected $testroot/stdout
1599 test_done "$testroot" "$ret"
1600 return 1
1603 # tidy up
1604 rm $testroot/wt/foo $testroot/wt/foo-1-* $testroot/wt/foo-2-*
1605 (cd $testroot/wt && got up -c $commit_id1 > /dev/null)
1607 # cherry-pick conflicting modification of a binary file
1608 (cd $testroot/wt && got cy $commit_id3 > $testroot/stdout)
1610 echo "C foo" > $testroot/stdout.expected
1611 echo "Merged commit $commit_id3" >> $testroot/stdout.expected
1612 echo "Files with new merge conflicts: 1" >> $testroot/stdout.expected
1614 cmp -s $testroot/stdout.expected $testroot/stdout
1615 ret=$?
1616 if [ $ret -ne 0 ]; then
1617 diff -u $testroot/stdout.expected $testroot/stdout
1618 test_done "$testroot" "$ret"
1619 return 1
1622 echo "Binary files differ and cannot be merged automatically:" \
1623 > $testroot/content.expected
1624 echo '<<<<<<<' >> $testroot/content.expected
1625 echo -n "file " >> $testroot/content.expected
1626 ls $testroot/wt/foo-1-* >> $testroot/content.expected
1627 echo "||||||| 3-way merge base: commit $commit_id2" \
1628 >> $testroot/content.expected
1629 echo -n "file " >> $testroot/content.expected
1630 ls $testroot/wt/foo-orig-* >> $testroot/content.expected
1631 echo '=======' >> $testroot/content.expected
1632 echo -n "file " >> $testroot/content.expected
1633 ls $testroot/wt/foo-2-* >> $testroot/content.expected
1634 echo ">>>>>>> merged change: commit $commit_id3" \
1635 >> $testroot/content.expected
1636 cp $testroot/wt/foo $testroot/content
1637 cmp -s $testroot/content.expected $testroot/content
1638 ret=$?
1639 if [ $ret -ne 0 ]; then
1640 diff -u $testroot/content.expected $testroot/content
1641 test_done "$testroot" "$ret"
1642 return 1
1645 cp /bin/ls $testroot/content.expected
1646 chmod 755 $testroot/content.expected
1647 cat $testroot/wt/foo-1-* > $testroot/content
1648 cmp -s $testroot/content.expected $testroot/content
1649 ret=$?
1650 if [ $ret -ne 0 ]; then
1651 diff -u $testroot/content.expected $testroot/content
1652 test_done "$testroot" "$ret"
1653 return 1
1656 cp /bin/cp $testroot/content.expected
1657 chmod 755 $testroot/content.expected
1658 cat $testroot/wt/foo-2-* > $testroot/content
1659 cmp -s $testroot/content.expected $testroot/content
1660 ret=$?
1661 if [ $ret -ne 0 ]; then
1662 diff -u $testroot/content.expected $testroot/content
1663 test_done "$testroot" "$ret"
1664 return 1
1667 # revert local changes to allow further testing
1668 (cd $testroot/wt && got revert -R . > /dev/null)
1669 rm $testroot/wt/foo-1-*
1670 rm $testroot/wt/foo-2-*
1671 (cd $testroot/wt && got up -c $commit_id3 > /dev/null)
1673 # cherry-pick deletion of a binary file
1674 (cd $testroot/wt && got cy $commit_id4 > $testroot/stdout)
1676 echo "D foo" > $testroot/stdout.expected
1677 echo "Merged commit $commit_id4" >> $testroot/stdout.expected
1679 cmp -s $testroot/stdout.expected $testroot/stdout
1680 ret=$?
1681 if [ $ret -ne 0 ]; then
1682 diff -u $testroot/stdout.expected $testroot/stdout
1683 test_done "$testroot" "$ret"
1684 return 1
1687 if [ -e $testroot/wt/foo ]; then
1688 echo "removed file foo still exists on disk" >&2
1689 test_done "$testroot" "1"
1690 return 1
1692 test_done "$testroot" "0"
1695 test_cherrypick_umask() {
1696 local testroot=`test_init cherrypick_umask`
1698 got checkout $testroot/repo $testroot/wt >/dev/null
1699 ret=$?
1700 if [ $ret -ne 0 ]; then
1701 test_done "$testroot" $ret
1702 return 1
1705 (cd "$testroot/wt" && got branch newbranch) >/dev/null
1706 echo "modified alpha on branch" > $testroot/wt/alpha
1707 (cd "$testroot/wt" && got commit -m 'edit alpha') >/dev/null
1708 (cd "$testroot/wt" && got update -b master) >/dev/null
1710 # using a subshell to avoid clobbering global umask
1711 (umask 077 && cd "$testroot/wt" && got cherrypick newbranch) >/dev/null
1712 ret=$?
1713 if [ $ret -ne 0 ]; then
1714 test_done "$testroot" $ret
1715 return 1
1718 if ! ls -l "$testroot/wt/alpha" | grep -q ^-rw-------; then
1719 echo "alpha is not 0600 after cherrypick!" >&2
1720 ls -l "$testroot/wt/alpha" >&2
1721 test_done "$testroot" $ret
1722 return 1
1725 test_done "$testroot" 0
1728 test_parseargs "$@"
1729 run_test test_cherrypick_basic
1730 run_test test_cherrypick_root_commit
1731 run_test test_cherrypick_into_work_tree_with_conflicts
1732 run_test test_cherrypick_into_work_tree_with_mixed_commits
1733 run_test test_cherrypick_modified_submodule
1734 run_test test_cherrypick_added_submodule
1735 run_test test_cherrypick_conflict_wt_file_vs_repo_submodule
1736 run_test test_cherrypick_modified_symlinks
1737 run_test test_cherrypick_symlink_conflicts
1738 run_test test_cherrypick_with_path_prefix_and_empty_tree
1739 run_test test_cherrypick_conflict_no_eol
1740 run_test test_cherrypick_conflict_no_eol2
1741 run_test test_cherrypick_unrelated_changes
1742 run_test test_cherrypick_same_branch
1743 run_test test_cherrypick_dot_on_a_line_by_itself
1744 run_test test_cherrypick_binary_file
1745 run_test test_cherrypick_umask