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" != "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 (cd $testroot/wt && got cherrypick $branch_rev > $testroot/stdout)
43 echo "G alpha" > $testroot/stdout.expected
44 echo "D beta" >> $testroot/stdout.expected
45 echo "A epsilon/new" >> $testroot/stdout.expected
46 echo "Merged commit $branch_rev" >> $testroot/stdout.expected
48 cmp -s $testroot/stdout.expected $testroot/stdout
49 ret="$?"
50 if [ "$ret" != "0" ]; then
51 diff -u $testroot/stdout.expected $testroot/stdout
52 test_done "$testroot" "$ret"
53 return 1
54 fi
56 echo "modified alpha on branch" > $testroot/content.expected
57 cat $testroot/wt/alpha > $testroot/content
58 cmp -s $testroot/content.expected $testroot/content
59 ret="$?"
60 if [ "$ret" != "0" ]; then
61 diff -u $testroot/content.expected $testroot/content
62 test_done "$testroot" "$ret"
63 return 1
64 fi
66 if [ -e $testroot/wt/beta ]; then
67 echo "removed file beta still exists on disk" >&2
68 test_done "$testroot" "1"
69 return 1
70 fi
72 echo "new file on branch" > $testroot/content.expected
73 cat $testroot/wt/epsilon/new > $testroot/content
74 cmp -s $testroot/content.expected $testroot/content
75 ret="$?"
76 if [ "$ret" != "0" ]; then
77 diff -u $testroot/content.expected $testroot/content
78 test_done "$testroot" "$ret"
79 return 1
80 fi
82 echo 'M alpha' > $testroot/stdout.expected
83 echo 'D beta' >> $testroot/stdout.expected
84 echo 'A epsilon/new' >> $testroot/stdout.expected
86 (cd $testroot/wt && got status > $testroot/stdout)
88 cmp -s $testroot/stdout.expected $testroot/stdout
89 ret="$?"
90 if [ "$ret" != "0" ]; then
91 diff -u $testroot/stdout.expected $testroot/stdout
92 fi
93 test_done "$testroot" "$ret"
94 }
96 test_cherrypick_root_commit() {
97 local testroot=`test_init cherrypick_root_commit`
99 got checkout $testroot/repo $testroot/wt > /dev/null
100 ret="$?"
101 if [ "$ret" != "0" ]; then
102 test_done "$testroot" "$ret"
103 return 1
104 fi
106 (cd $testroot/repo && git checkout -q -b newbranch)
107 (cd $testroot/repo && git rm -q alpha)
108 (cd $testroot/repo && git rm -q beta)
109 (cd $testroot/repo && git rm -q epsilon/zeta)
110 (cd $testroot/repo && git rm -q gamma/delta)
111 mkdir -p $testroot/repo/epsilon
112 echo "new file on branch" > $testroot/repo/epsilon/new
113 (cd $testroot/repo && git add epsilon/new)
114 git_commit $testroot/repo -m "committing on newbranch"
116 echo "modified new file on branch" >> $testroot/repo/epsilon/new
117 git_commit $testroot/repo -m "committing on newbranch again"
119 tree=`git_show_tree $testroot/repo`
120 root_commit=`git_commit_tree $testroot/repo "new root commit" $tree`
122 (cd $testroot/wt && got cherrypick $root_commit > $testroot/stdout)
124 echo "A epsilon/new" > $testroot/stdout.expected
125 echo "Merged commit $root_commit" >> $testroot/stdout.expected
127 cmp -s $testroot/stdout.expected $testroot/stdout
128 ret="$?"
129 if [ "$ret" != "0" ]; then
130 diff -u $testroot/stdout.expected $testroot/stdout
131 test_done "$testroot" "$ret"
132 return 1
133 fi
135 echo "new file on branch" > $testroot/content.expected
136 echo "modified new file on branch" >> $testroot/content.expected
137 cat $testroot/wt/epsilon/new > $testroot/content
138 cmp -s $testroot/content.expected $testroot/content
139 ret="$?"
140 if [ "$ret" != "0" ]; then
141 diff -u $testroot/content.expected $testroot/content
142 test_done "$testroot" "$ret"
143 return 1
144 fi
146 echo 'A epsilon/new' > $testroot/stdout.expected
148 (cd $testroot/wt && got status > $testroot/stdout)
150 cmp -s $testroot/stdout.expected $testroot/stdout
151 ret="$?"
152 if [ "$ret" != "0" ]; then
153 diff -u $testroot/stdout.expected $testroot/stdout
154 fi
155 test_done "$testroot" "$ret"
158 test_cherrypick_into_work_tree_with_conflicts() {
159 local testroot=`test_init cherrypick_into_work_tree_with_conflicts`
161 got checkout $testroot/repo $testroot/wt > /dev/null
162 ret="$?"
163 if [ "$ret" != "0" ]; then
164 test_done "$testroot" "$ret"
165 return 1
166 fi
168 (cd $testroot/repo && git checkout -q -b newbranch)
169 echo "modified delta on branch" > $testroot/repo/gamma/delta
170 git_commit $testroot/repo -m "committing to delta on newbranch"
172 echo "modified alpha on branch" > $testroot/repo/alpha
173 (cd $testroot/repo && git rm -q beta)
174 echo "new file on branch" > $testroot/repo/epsilon/new
175 (cd $testroot/repo && git add epsilon/new)
176 git_commit $testroot/repo -m "committing more changes on newbranch"
178 local branch_rev=`git_show_head $testroot/repo`
180 # fake a merge conflict
181 echo '<<<<<<<' > $testroot/wt/alpha
182 echo 'alpha' >> $testroot/wt/alpha
183 echo '=======' >> $testroot/wt/alpha
184 echo 'alpha, too' >> $testroot/wt/alpha
185 echo '>>>>>>>' >> $testroot/wt/alpha
186 cp $testroot/wt/alpha $testroot/content.expected
188 echo "C alpha" > $testroot/stdout.expected
189 (cd $testroot/wt && got status > $testroot/stdout)
190 cmp -s $testroot/stdout.expected $testroot/stdout
191 ret="$?"
192 if [ "$ret" != "0" ]; then
193 diff -u $testroot/stdout.expected $testroot/stdout
194 test_done "$testroot" "$ret"
195 return 1
196 fi
198 (cd $testroot/wt && got cherrypick $branch_rev \
199 > $testroot/stdout 2> $testroot/stderr)
200 ret="$?"
201 if [ "$ret" = "0" ]; then
202 echo "cherrypick succeeded unexpectedly" >&2
203 test_done "$testroot" "1"
204 return 1
205 fi
207 echo -n > $testroot/stdout.expected
208 echo -n "got: work tree contains conflicted files; " \
209 > $testroot/stderr.expected
210 echo "these conflicts must be resolved first" \
211 >> $testroot/stderr.expected
213 cmp -s $testroot/stdout.expected $testroot/stdout
214 ret="$?"
215 if [ "$ret" != "0" ]; then
216 diff -u $testroot/stdout.expected $testroot/stdout
217 test_done "$testroot" "$ret"
218 return 1
219 fi
221 cmp -s $testroot/stderr.expected $testroot/stderr
222 ret="$?"
223 if [ "$ret" != "0" ]; then
224 diff -u $testroot/stderr.expected $testroot/stderr
225 test_done "$testroot" "$ret"
226 return 1
227 fi
229 cmp -s $testroot/content.expected $testroot/wt/alpha
230 ret="$?"
231 if [ "$ret" != "0" ]; then
232 diff -u $testroot/content.expected $testroot/wt/alpha
233 fi
234 test_done "$testroot" "$ret"
237 test_cherrypick_modified_submodule() {
238 local testroot=`test_init cherrypick_modified_submodules`
240 make_single_file_repo $testroot/repo2 foo
242 (cd $testroot/repo && git submodule -q add ../repo2)
243 (cd $testroot/repo && git commit -q -m 'adding submodule')
245 got checkout $testroot/repo $testroot/wt > /dev/null
247 echo "modified foo" > $testroot/repo2/foo
248 (cd $testroot/repo2 && git commit -q -a -m 'modified a submodule')
250 (cd $testroot/repo && git checkout -q -b newbranch)
251 # Update the repo/repo2 submodule link on newbranch
252 (cd $testroot/repo && git -C repo2 pull -q)
253 (cd $testroot/repo && git add repo2)
254 git_commit $testroot/repo -m "modified submodule link"
255 local commit_id=`git_show_head $testroot/repo`
257 # This cherrypick is a no-op because Got's file index
258 # does not track submodules.
259 (cd $testroot/wt && got cherrypick $commit_id > $testroot/stdout)
261 echo -n > $testroot/stdout.expected
262 cmp -s $testroot/stdout.expected $testroot/stdout
263 ret="$?"
264 if [ "$ret" != "0" ]; then
265 diff -u $testroot/stdout.expected $testroot/stdout
266 fi
267 test_done "$testroot" "$ret"
270 test_cherrypick_added_submodule() {
271 local testroot=`test_init cherrypick_added_submodules`
273 got checkout $testroot/repo $testroot/wt > /dev/null
275 make_single_file_repo $testroot/repo2 foo
277 # Add the repo/repo2 submodule on newbranch
278 (cd $testroot/repo && git checkout -q -b newbranch)
279 (cd $testroot/repo && git submodule -q add ../repo2)
280 (cd $testroot/repo && git commit -q -m 'adding submodule')
281 local commit_id=`git_show_head $testroot/repo`
283 (cd $testroot/wt && got cherrypick $commit_id > $testroot/stdout)
285 echo "A .gitmodules" > $testroot/stdout.expected
286 echo "Merged commit $commit_id" >> $testroot/stdout.expected
287 cmp -s $testroot/stdout.expected $testroot/stdout
288 ret="$?"
289 if [ "$ret" != "0" ]; then
290 diff -u $testroot/stdout.expected $testroot/stdout
291 fi
292 test_done "$testroot" "$ret"
295 test_cherrypick_conflict_wt_file_vs_repo_submodule() {
296 local testroot=`test_init cherrypick_conflict_wt_file_vs_repo_submodule`
298 got checkout $testroot/repo $testroot/wt > /dev/null
300 # Add a file which will clash with the submodule
301 echo "This is a file called repo2" > $testroot/wt/repo2
302 (cd $testroot/wt && got add repo2 > /dev/null)
303 (cd $testroot/wt && got commit -m 'add file repo2' > /dev/null)
304 ret="$?"
305 if [ "$ret" != "0" ]; then
306 echo "commit failed unexpectedly" >&2
307 test_done "$testroot" "1"
308 return 1
309 fi
311 make_single_file_repo $testroot/repo2 foo
313 # Add the repo/repo2 submodule on newbranch
314 (cd $testroot/repo && git checkout -q -b newbranch)
315 (cd $testroot/repo && git submodule -q add ../repo2)
316 (cd $testroot/repo && git commit -q -m 'adding submodule')
317 local commit_id=`git_show_head $testroot/repo`
319 # Modify the clashing file such that any modifications brought
320 # in by 'got cherrypick' would require a merge.
321 echo "This file was changed" > $testroot/wt/repo2
323 (cd $testroot/wt && got update >/dev/null)
324 (cd $testroot/wt && got cherrypick $commit_id > $testroot/stdout)
326 echo "A .gitmodules" > $testroot/stdout.expected
327 echo "Merged commit $commit_id" >> $testroot/stdout.expected
328 cmp -s $testroot/stdout.expected $testroot/stdout
329 ret="$?"
330 if [ "$ret" != "0" ]; then
331 diff -u $testroot/stdout.expected $testroot/stdout
332 test_done "$testroot" "$ret"
333 return 1
334 fi
336 (cd $testroot/wt && got status > $testroot/stdout)
338 echo "A .gitmodules" > $testroot/stdout.expected
339 echo "M repo2" >> $testroot/stdout.expected
340 cmp -s $testroot/stdout.expected $testroot/stdout
341 ret="$?"
342 if [ "$ret" != "0" ]; then
343 diff -u $testroot/stdout.expected $testroot/stdout
344 fi
345 test_done "$testroot" "$ret"
348 test_cherrypick_modified_symlinks() {
349 local testroot=`test_init cherrypick_modified_symlinks`
351 (cd $testroot/repo && ln -s alpha alpha.link)
352 (cd $testroot/repo && ln -s epsilon epsilon.link)
353 (cd $testroot/repo && ln -s /etc/passwd passwd.link)
354 (cd $testroot/repo && ln -s ../beta epsilon/beta.link)
355 (cd $testroot/repo && ln -s nonexistent nonexistent.link)
356 (cd $testroot/repo && git add .)
357 git_commit $testroot/repo -m "add symlinks"
358 local commit_id1=`git_show_head $testroot/repo`
360 got branch -r $testroot/repo foo
362 got checkout -b foo $testroot/repo $testroot/wt > /dev/null
364 (cd $testroot/repo && ln -sf beta alpha.link)
365 (cd $testroot/repo && ln -sfh gamma epsilon.link)
366 (cd $testroot/repo && ln -sf ../gamma/delta epsilon/beta.link)
367 (cd $testroot/repo && ln -sf .got/bar $testroot/repo/dotgotfoo.link)
368 (cd $testroot/repo && git rm -q nonexistent.link)
369 (cd $testroot/repo && ln -sf epsilon/zeta zeta.link)
370 (cd $testroot/repo && git add .)
371 git_commit $testroot/repo -m "change symlinks"
372 local commit_id2=`git_show_head $testroot/repo`
374 (cd $testroot/wt && got cherrypick $commit_id2 > $testroot/stdout)
376 echo "G alpha.link" > $testroot/stdout.expected
377 echo "G epsilon/beta.link" >> $testroot/stdout.expected
378 echo "A dotgotfoo.link" >> $testroot/stdout.expected
379 echo "G epsilon.link" >> $testroot/stdout.expected
380 echo "D nonexistent.link" >> $testroot/stdout.expected
381 echo "A zeta.link" >> $testroot/stdout.expected
382 echo "Merged commit $commit_id2" >> $testroot/stdout.expected
383 cmp -s $testroot/stdout.expected $testroot/stdout
384 ret="$?"
385 if [ "$ret" != "0" ]; then
386 diff -u $testroot/stdout.expected $testroot/stdout
387 test_done "$testroot" "$ret"
388 return 1
389 fi
391 if ! [ -h $testroot/wt/alpha.link ]; then
392 echo "alpha.link is not a symlink"
393 test_done "$testroot" "1"
394 return 1
395 fi
397 readlink $testroot/wt/alpha.link > $testroot/stdout
398 echo "beta" > $testroot/stdout.expected
399 cmp -s $testroot/stdout.expected $testroot/stdout
400 ret="$?"
401 if [ "$ret" != "0" ]; then
402 diff -u $testroot/stdout.expected $testroot/stdout
403 test_done "$testroot" "$ret"
404 return 1
405 fi
407 if ! [ -h $testroot/wt/epsilon.link ]; then
408 echo "epsilon.link is not a symlink"
409 test_done "$testroot" "1"
410 return 1
411 fi
413 readlink $testroot/wt/epsilon.link > $testroot/stdout
414 echo "gamma" > $testroot/stdout.expected
415 cmp -s $testroot/stdout.expected $testroot/stdout
416 ret="$?"
417 if [ "$ret" != "0" ]; then
418 diff -u $testroot/stdout.expected $testroot/stdout
419 test_done "$testroot" "$ret"
420 return 1
421 fi
423 if [ -h $testroot/wt/passwd.link ]; then
424 echo -n "passwd.link symlink points outside of work tree: " >&2
425 readlink $testroot/wt/passwd.link >&2
426 test_done "$testroot" "1"
427 return 1
428 fi
430 echo -n "/etc/passwd" > $testroot/content.expected
431 cp $testroot/wt/passwd.link $testroot/content
433 cmp -s $testroot/content.expected $testroot/content
434 ret="$?"
435 if [ "$ret" != "0" ]; then
436 diff -u $testroot/content.expected $testroot/content
437 test_done "$testroot" "$ret"
438 return 1
439 fi
441 readlink $testroot/wt/epsilon/beta.link > $testroot/stdout
442 echo "../gamma/delta" > $testroot/stdout.expected
443 cmp -s $testroot/stdout.expected $testroot/stdout
444 ret="$?"
445 if [ "$ret" != "0" ]; then
446 diff -u $testroot/stdout.expected $testroot/stdout
447 test_done "$testroot" "$ret"
448 return 1
449 fi
451 if [ -h $testroot/wt/nonexistent.link ]; then
452 echo -n "nonexistent.link still exists on disk: " >&2
453 readlink $testroot/wt/nonexistent.link >&2
454 test_done "$testroot" "1"
455 return 1
456 fi
458 test_done "$testroot" "0"
461 test_cherrypick_symlink_conflicts() {
462 local testroot=`test_init cherrypick_symlink_conflicts`
464 (cd $testroot/repo && ln -s alpha alpha.link)
465 (cd $testroot/repo && ln -s epsilon epsilon.link)
466 (cd $testroot/repo && ln -s /etc/passwd passwd.link)
467 (cd $testroot/repo && ln -s ../beta epsilon/beta.link)
468 (cd $testroot/repo && ln -s nonexistent nonexistent.link)
469 (cd $testroot/repo && ln -sf epsilon/zeta zeta.link)
470 (cd $testroot/repo && git add .)
471 git_commit $testroot/repo -m "add symlinks"
472 local commit_id1=`git_show_head $testroot/repo`
474 (cd $testroot/repo && ln -sf beta alpha.link)
475 (cd $testroot/repo && ln -sf beta boo.link)
476 (cd $testroot/repo && ln -sfh gamma epsilon.link)
477 (cd $testroot/repo && ln -sf ../gamma/delta epsilon/beta.link)
478 echo 'this is regular file foo' > $testroot/repo/dotgotfoo.link
479 (cd $testroot/repo && ln -sf .got/bar dotgotbar.link)
480 (cd $testroot/repo && git rm -q nonexistent.link)
481 (cd $testroot/repo && ln -sf gamma/delta zeta.link)
482 (cd $testroot/repo && ln -sf alpha new.link)
483 (cd $testroot/repo && git add .)
484 git_commit $testroot/repo -m "change symlinks"
485 local commit_id2=`git_show_head $testroot/repo`
487 got branch -r $testroot/repo -c $commit_id1 foo
488 got checkout -b foo $testroot/repo $testroot/wt > /dev/null
490 # modified symlink to file A vs modified symlink to file B
491 (cd $testroot/wt && ln -sf gamma/delta alpha.link)
492 # modified symlink to dir A vs modified symlink to file B
493 (cd $testroot/wt && ln -sfh beta epsilon.link)
494 # modeified symlink to file A vs modified symlink to dir B
495 (cd $testroot/wt && ln -sfh ../gamma epsilon/beta.link)
496 # added regular file A vs added bad symlink to file A
497 (cd $testroot/wt && ln -sf .got/bar dotgotfoo.link)
498 (cd $testroot/wt && got add dotgotfoo.link > /dev/null)
499 # added bad symlink to file A vs added regular file A
500 echo 'this is regular file bar' > $testroot/wt/dotgotbar.link
501 (cd $testroot/wt && got add dotgotbar.link > /dev/null)
502 # added symlink to file A vs unversioned file A
503 echo 'this is unversioned file boo' > $testroot/wt/boo.link
504 # removed symlink to non-existent file A vs modified symlink
505 # to nonexistent file B
506 (cd $testroot/wt && ln -sf nonexistent2 nonexistent.link)
507 # modified symlink to file A vs removed symlink to file A
508 (cd $testroot/wt && got rm zeta.link > /dev/null)
509 # added symlink to file A vs added symlink to file B
510 (cd $testroot/wt && ln -sf beta new.link)
511 (cd $testroot/wt && got add new.link > /dev/null)
512 (cd $testroot/wt && got commit -S -m "change symlinks on foo" \
513 > /dev/null)
515 (cd $testroot/wt && got update >/dev/null)
516 (cd $testroot/wt && got cherrypick $commit_id2 > $testroot/stdout)
518 echo -n > $testroot/stdout.expected
519 echo "C alpha.link" >> $testroot/stdout.expected
520 echo "C epsilon/beta.link" >> $testroot/stdout.expected
521 echo "? boo.link" >> $testroot/stdout.expected
522 echo "C epsilon.link" >> $testroot/stdout.expected
523 echo "C dotgotbar.link" >> $testroot/stdout.expected
524 echo "C dotgotfoo.link" >> $testroot/stdout.expected
525 echo "D nonexistent.link" >> $testroot/stdout.expected
526 echo "! zeta.link" >> $testroot/stdout.expected
527 echo "C new.link" >> $testroot/stdout.expected
528 echo "Merged commit $commit_id2" >> $testroot/stdout.expected
529 echo "Files with new merge conflicts: 6" >> $testroot/stdout.expected
530 cmp -s $testroot/stdout.expected $testroot/stdout
531 ret="$?"
532 if [ "$ret" != "0" ]; then
533 diff -u $testroot/stdout.expected $testroot/stdout
534 test_done "$testroot" "$ret"
535 return 1
536 fi
538 if [ -h $testroot/wt/alpha.link ]; then
539 echo "alpha.link is a symlink"
540 test_done "$testroot" "1"
541 return 1
542 fi
544 echo "<<<<<<< merged change: commit $commit_id2" \
545 > $testroot/content.expected
546 echo "beta" >> $testroot/content.expected
547 echo "3-way merge base: commit $commit_id1" \
548 >> $testroot/content.expected
549 echo "alpha" >> $testroot/content.expected
550 echo "=======" >> $testroot/content.expected
551 echo "gamma/delta" >> $testroot/content.expected
552 echo '>>>>>>>' >> $testroot/content.expected
553 echo -n "" >> $testroot/content.expected
555 cp $testroot/wt/alpha.link $testroot/content
556 cmp -s $testroot/content.expected $testroot/content
557 ret="$?"
558 if [ "$ret" != "0" ]; then
559 diff -u $testroot/content.expected $testroot/content
560 test_done "$testroot" "$ret"
561 return 1
562 fi
564 if [ -h $testroot/wt/boo.link ]; then
565 echo "boo.link is a symlink"
566 test_done "$testroot" "1"
567 return 1
568 fi
570 echo "this is unversioned file boo" > $testroot/content.expected
571 cp $testroot/wt/boo.link $testroot/content
572 cmp -s $testroot/content.expected $testroot/content
573 ret="$?"
574 if [ "$ret" != "0" ]; then
575 diff -u $testroot/content.expected $testroot/content
576 test_done "$testroot" "$ret"
577 return 1
578 fi
580 if [ -h $testroot/wt/epsilon.link ]; then
581 echo "epsilon.link is a symlink"
582 test_done "$testroot" "1"
583 return 1
584 fi
586 echo "<<<<<<< merged change: commit $commit_id2" \
587 > $testroot/content.expected
588 echo "gamma" >> $testroot/content.expected
589 echo "3-way merge base: commit $commit_id1" \
590 >> $testroot/content.expected
591 echo "epsilon" >> $testroot/content.expected
592 echo "=======" >> $testroot/content.expected
593 echo "beta" >> $testroot/content.expected
594 echo '>>>>>>>' >> $testroot/content.expected
595 echo -n "" >> $testroot/content.expected
597 cp $testroot/wt/epsilon.link $testroot/content
598 cmp -s $testroot/content.expected $testroot/content
599 ret="$?"
600 if [ "$ret" != "0" ]; then
601 diff -u $testroot/content.expected $testroot/content
602 test_done "$testroot" "$ret"
603 return 1
604 fi
606 if [ -h $testroot/wt/passwd.link ]; then
607 echo -n "passwd.link symlink points outside of work tree: " >&2
608 readlink $testroot/wt/passwd.link >&2
609 test_done "$testroot" "1"
610 return 1
611 fi
613 echo -n "/etc/passwd" > $testroot/content.expected
614 cp $testroot/wt/passwd.link $testroot/content
616 cmp -s $testroot/content.expected $testroot/content
617 ret="$?"
618 if [ "$ret" != "0" ]; then
619 diff -u $testroot/content.expected $testroot/content
620 test_done "$testroot" "$ret"
621 return 1
622 fi
624 if [ -h $testroot/wt/epsilon/beta.link ]; then
625 echo "epsilon/beta.link is a symlink"
626 test_done "$testroot" "1"
627 return 1
628 fi
630 echo "<<<<<<< merged change: commit $commit_id2" \
631 > $testroot/content.expected
632 echo "../gamma/delta" >> $testroot/content.expected
633 echo "3-way merge base: commit $commit_id1" \
634 >> $testroot/content.expected
635 echo "../beta" >> $testroot/content.expected
636 echo "=======" >> $testroot/content.expected
637 echo "../gamma" >> $testroot/content.expected
638 echo '>>>>>>>' >> $testroot/content.expected
639 echo -n "" >> $testroot/content.expected
641 cp $testroot/wt/epsilon/beta.link $testroot/content
642 cmp -s $testroot/content.expected $testroot/content
643 ret="$?"
644 if [ "$ret" != "0" ]; then
645 diff -u $testroot/content.expected $testroot/content
646 test_done "$testroot" "$ret"
647 return 1
648 fi
650 if [ -h $testroot/wt/nonexistent.link ]; then
651 echo -n "nonexistent.link still exists on disk: " >&2
652 readlink $testroot/wt/nonexistent.link >&2
653 test_done "$testroot" "1"
654 return 1
655 fi
657 if [ -h $testroot/wt/dotgotfoo.link ]; then
658 echo "dotgotfoo.link is a symlink"
659 test_done "$testroot" "1"
660 return 1
661 fi
663 echo "<<<<<<< merged change: commit $commit_id2" \
664 > $testroot/content.expected
665 echo "this is regular file foo" >> $testroot/content.expected
666 echo "=======" >> $testroot/content.expected
667 echo -n ".got/bar" >> $testroot/content.expected
668 echo '>>>>>>>' >> $testroot/content.expected
669 cp $testroot/wt/dotgotfoo.link $testroot/content
670 cmp -s $testroot/content.expected $testroot/content
671 ret="$?"
672 if [ "$ret" != "0" ]; then
673 diff -u $testroot/content.expected $testroot/content
674 test_done "$testroot" "$ret"
675 return 1
676 fi
678 if [ -h $testroot/wt/dotgotbar.link ]; then
679 echo "dotgotbar.link is a symlink"
680 test_done "$testroot" "1"
681 return 1
682 fi
683 echo "<<<<<<< merged change: commit $commit_id2" \
684 > $testroot/content.expected
685 echo -n ".got/bar" >> $testroot/content.expected
686 echo "=======" >> $testroot/content.expected
687 echo "this is regular file bar" >> $testroot/content.expected
688 echo '>>>>>>>' >> $testroot/content.expected
689 echo -n "" >> $testroot/content.expected
690 cp $testroot/wt/dotgotbar.link $testroot/content
691 cmp -s $testroot/content.expected $testroot/content
692 ret="$?"
693 if [ "$ret" != "0" ]; then
694 diff -u $testroot/content.expected $testroot/content
695 test_done "$testroot" "$ret"
696 return 1
697 fi
699 if [ -h $testroot/wt/new.link ]; then
700 echo "new.link is a symlink"
701 test_done "$testroot" "1"
702 return 1
703 fi
705 echo "<<<<<<< merged change: commit $commit_id2" \
706 > $testroot/content.expected
707 echo "alpha" >> $testroot/content.expected
708 echo "=======" >> $testroot/content.expected
709 echo "beta" >> $testroot/content.expected
710 echo '>>>>>>>' >> $testroot/content.expected
711 echo -n "" >> $testroot/content.expected
713 cp $testroot/wt/new.link $testroot/content
714 cmp -s $testroot/content.expected $testroot/content
715 ret="$?"
716 if [ "$ret" != "0" ]; then
717 diff -u $testroot/content.expected $testroot/content
718 test_done "$testroot" "$ret"
719 return 1
720 fi
722 echo "A dotgotfoo.link" > $testroot/stdout.expected
723 echo "M new.link" >> $testroot/stdout.expected
724 echo "D nonexistent.link" >> $testroot/stdout.expected
725 (cd $testroot/wt && got status > $testroot/stdout)
726 if [ "$ret" != "0" ]; then
727 diff -u $testroot/stdout.expected $testroot/stdout
728 test_done "$testroot" "$ret"
729 return 1
730 fi
732 test_done "$testroot" "0"
735 test_cherrypick_with_path_prefix_and_empty_tree() {
736 local testroot=`test_init cherrypick_with_path_prefix_and_empty_tree 1`
738 (cd $testroot/repo && git commit --allow-empty \
739 -m "initial empty commit" >/dev/null)
741 (cd $testroot/repo && got br bar >/dev/null)
743 mkdir -p $testroot/repo/epsilon
744 echo "file foo" > $testroot/repo/epsilon/foo
745 (cd $testroot/repo && git add .)
746 git_commit $testroot/repo -m "add file foo"
747 local commit_id=`git_show_head $testroot/repo`
749 got checkout -b bar $testroot/repo $testroot/wt > /dev/null
750 ret="$?"
751 if [ "$ret" != "0" ]; then
752 echo "got checkout failed unexpectedly" >&2
753 test_done "$testroot" "$ret"
754 return 1
755 fi
757 mkdir -p $testroot/wt/epsilon
758 echo "new file" > $testroot/wt/epsilon/new
759 (cd $testroot/wt && got add epsilon/new >/dev/null)
760 (cd $testroot/wt && got commit -m "add file on branch bar" > /dev/null)
762 got checkout -b bar -p epsilon $testroot/repo $testroot/wt2 > /dev/null
763 ret="$?"
764 if [ "$ret" != "0" ]; then
765 echo "got checkout failed unexpectedly" >&2
766 test_done "$testroot" "$ret"
767 return 1
768 fi
769 (cd $testroot/wt2 && got cherrypick $commit_id > $testroot/stdout)
771 echo "A foo" > $testroot/stdout.expected
772 echo "Merged commit $commit_id" >> $testroot/stdout.expected
774 cmp -s $testroot/stdout.expected $testroot/stdout
775 ret="$?"
776 if [ "$ret" != "0" ]; then
777 diff -u $testroot/stdout.expected $testroot/stdout
778 fi
779 test_done "$testroot" "$ret"
782 test_cherrypick_conflict_no_eol() {
783 local testroot=`test_init cherrypick_conflict_no_eol 1`
784 local content_a="aaa\naaa\naaa\naaa\naaa\naaa\n"
785 local content_b="aaa\naaa\nbbb\naaa\naaa\naaa\naaa"
786 local content_c="aaa\naaa\nccc\naaa\naaa\naaa\naaa"
788 printf "$content_a" > $testroot/repo/a
789 (cd $testroot/repo && git add a)
790 git_commit $testroot/repo -m "initial commit"
792 (cd $testroot/repo && got branch newbranch)
794 printf "$content_b" > $testroot/repo/a
795 git_commit $testroot/repo -m "change bbb"
797 printf "$content_c" > $testroot/repo/a
798 git_commit $testroot/repo -m "change ccc"
799 local ccc_commit=`git_show_head $testroot/repo`
801 got checkout -b newbranch $testroot/repo $testroot/wt > /dev/null
802 ret="$?"
803 if [ "$ret" != "0" ]; then
804 test_done "$testroot" "$ret"
805 return 1
806 fi
808 (cd $testroot/wt && got cherrypick $ccc_commit > $testroot/stdout)
810 echo "C a" > $testroot/stdout.expected
811 echo "Merged commit $ccc_commit" >> $testroot/stdout.expected
812 echo "Files with new merge conflicts: 1" >> $testroot/stdout.expected
814 cmp -s $testroot/stdout.expected $testroot/stdout
815 ret="$?"
816 if [ "$ret" != "0" ]; then
817 diff -u $testroot/stdout.expected $testroot/stdout
818 fi
819 test_done "$testroot" "$ret"
822 test_cherrypick_conflict_no_eol2() {
823 local testroot=`test_init cherrypick_conflict_no_eol2 1`
824 local content_a="aaa\naaa\naaa\naaa\naaa\naaa"
825 local content_b="aaa\naaa\nbbb\naaa\naaa\naaa"
826 local content_c="aaa\naaa\nbbb\naaa\naaa\naaa\n"
828 printf "$content_a" > $testroot/repo/a
829 (cd $testroot/repo && git add a)
830 git_commit $testroot/repo -m "initial commit"
832 (cd $testroot/repo && got branch newbranch)
834 printf "$content_b" > $testroot/repo/a
835 git_commit $testroot/repo -m "change bbb"
837 printf "$content_c" > $testroot/repo/a
838 git_commit $testroot/repo -m "change ccc"
839 local ccc_commit=`git_show_head $testroot/repo`
841 got checkout -b newbranch $testroot/repo $testroot/wt > /dev/null
842 ret="$?"
843 if [ "$ret" != "0" ]; then
844 test_done "$testroot" "$ret"
845 return 1
846 fi
848 (cd $testroot/wt && got cherrypick $ccc_commit \
849 > $testroot/stdout 2> $testroot/stderr)
851 echo "C a" > $testroot/stdout.expected
852 echo "Merged commit $ccc_commit" >> $testroot/stdout.expected
853 echo "Files with new merge conflicts: 1" >> $testroot/stdout.expected
855 cmp -s $testroot/stdout.expected $testroot/stdout
856 ret="$?"
857 if [ "$ret" != "0" ]; then
858 diff -u $testroot/stdout.expected $testroot/stdout
859 fi
860 test_done "$testroot" "$ret"
863 test_cherrypick_unrelated_changes() {
864 local testroot=`test_init cherrypick_unrelated_changes`
866 # Sorry about the large HERE document but I have not found
867 # a smaller reproduction recipe yet...
868 cat > $testroot/repo/reference.c <<EOF
869 const struct got_error *
870 got_ref_alloc(struct got_reference **ref, const char *name,
871 struct got_object_id *id)
873 if (!is_valid_ref_name(name))
874 return got_error_path(name, GOT_ERR_BAD_REF_NAME);
876 return alloc_ref(ref, name, id, 0);
879 static const struct got_error *
880 parse_packed_ref_line(struct got_reference **ref, const char *abs_refname,
881 const char *line)
883 struct got_object_id id;
884 const char *name;
886 *ref = NULL;
888 if (line[0] == '#' || line[0] == '^')
889 return NULL;
891 if (!got_parse_sha1_digest(id.sha1, line))
892 return got_error(GOT_ERR_BAD_REF_DATA);
894 if (abs_refname) {
895 if (strcmp(line + SHA1_DIGEST_STRING_LENGTH, abs_refname) != 0)
896 return NULL;
897 name = abs_refname;
898 } else
899 name = line + SHA1_DIGEST_STRING_LENGTH;
901 return alloc_ref(ref, name, &id, GOT_REF_IS_PACKED);
904 static const struct got_error *
905 open_packed_ref(struct got_reference **ref, FILE *f, const char **subdirs,
906 int nsubdirs, const char *refname)
908 const struct got_error *err = NULL;
909 char *abs_refname;
910 char *line = NULL;
911 size_t linesize = 0;
912 ssize_t linelen;
913 int i, ref_is_absolute = (strncmp(refname, "refs/", 5) == 0);
915 *ref = NULL;
917 if (ref_is_absolute)
918 abs_refname = (char *)refname;
919 do {
920 linelen = getline(&line, &linesize, f);
921 if (linelen == -1) {
922 if (feof(f))
923 break;
924 err = got_ferror(f, GOT_ERR_BAD_REF_DATA);
925 break;
927 if (linelen > 0 && line[linelen - 1] == '\n')
928 line[linelen - 1] = '\0';
929 for (i = 0; i < nsubdirs; i++) {
930 if (!ref_is_absolute &&
931 asprintf(&abs_refname, "refs/%s/%s", subdirs[i],
932 refname) == -1)
933 return got_error_from_errno("asprintf");
934 err = parse_packed_ref_line(ref, abs_refname, line);
935 if (!ref_is_absolute)
936 free(abs_refname);
937 if (err || *ref != NULL)
938 break;
940 if (err)
941 break;
942 } while (*ref == NULL);
943 free(line);
945 return err;
948 static const struct got_error *
949 open_ref(struct got_reference **ref, const char *path_refs, const char *subdir,
950 const char *name, int lock)
952 const struct got_error *err = NULL;
953 char *path = NULL;
954 char *absname = NULL;
955 int ref_is_absolute = (strncmp(name, "refs/", 5) == 0);
956 int ref_is_well_known = (subdir[0] == '\0' && is_well_known_ref(name));
958 *ref = NULL;
960 if (ref_is_absolute || ref_is_well_known) {
961 if (asprintf(&path, "%s/%s", path_refs, name) == -1)
962 return got_error_from_errno("asprintf");
963 absname = (char *)name;
964 } else {
965 if (asprintf(&path, "%s/%s%s%s", path_refs, subdir,
966 subdir[0] ? "/" : "", name) == -1)
967 return got_error_from_errno("asprintf");
969 if (asprintf(&absname, "refs/%s%s%s",
970 subdir, subdir[0] ? "/" : "", name) == -1) {
971 err = got_error_from_errno("asprintf");
972 goto done;
976 err = parse_ref_file(ref, name, absname, path, lock);
977 done:
978 if (!ref_is_absolute && !ref_is_well_known)
979 free(absname);
980 free(path);
981 return err;
984 const struct got_error *
985 got_ref_open(struct got_reference **ref, struct got_repository *repo,
986 const char *refname, int lock)
988 const struct got_error *err = NULL;
989 char *path_refs = NULL;
990 const char *subdirs[] = {
991 GOT_REF_HEADS, GOT_REF_TAGS, GOT_REF_REMOTES
992 };
993 size_t i;
994 int well_known = is_well_known_ref(refname);
995 struct got_lockfile *lf = NULL;
997 *ref = NULL;
999 path_refs = get_refs_dir_path(repo, refname);
1000 if (path_refs == NULL) {
1001 err = got_error_from_errno2("get_refs_dir_path", refname);
1002 goto done;
1005 if (well_known) {
1006 err = open_ref(ref, path_refs, "", refname, lock);
1007 } else {
1008 char *packed_refs_path;
1009 FILE *f;
1011 /* Search on-disk refs before packed refs! */
1012 for (i = 0; i < nitems(subdirs); i++) {
1013 err = open_ref(ref, path_refs, subdirs[i], refname,
1014 lock);
1015 if ((err && err->code != GOT_ERR_NOT_REF) || *ref)
1016 goto done;
1019 packed_refs_path = got_repo_get_path_packed_refs(repo);
1020 if (packed_refs_path == NULL) {
1021 err = got_error_from_errno(
1022 "got_repo_get_path_packed_refs");
1023 goto done;
1026 if (lock) {
1027 err = got_lockfile_lock(&lf, packed_refs_path);
1028 if (err)
1029 goto done;
1031 f = fopen(packed_refs_path, "rb");
1032 free(packed_refs_path);
1033 if (f != NULL) {
1034 err = open_packed_ref(ref, f, subdirs, nitems(subdirs),
1035 refname);
1036 if (!err) {
1037 if (fclose(f) == EOF) {
1038 err = got_error_from_errno("fclose");
1039 got_ref_close(*ref);
1040 *ref = NULL;
1041 } else if (*ref)
1042 (*ref)->lf = lf;
1046 done:
1047 if (!err && *ref == NULL)
1048 err = got_error_not_ref(refname);
1049 if (err && lf)
1050 got_lockfile_unlock(lf);
1051 free(path_refs);
1052 return err;
1055 struct got_reference *
1056 got_ref_dup(struct got_reference *ref)
1058 struct got_reference *ret;
1060 ret = calloc(1, sizeof(*ret));
1061 if (ret == NULL)
1062 return NULL;
1064 ret->flags = ref->flags;
1065 if (ref->flags & GOT_REF_IS_SYMBOLIC) {
1066 ret->ref.symref.name = strdup(ref->ref.symref.name);
1067 if (ret->ref.symref.name == NULL) {
1068 free(ret);
1069 return NULL;
1071 ret->ref.symref.ref = strdup(ref->ref.symref.ref);
1072 if (ret->ref.symref.ref == NULL) {
1073 free(ret->ref.symref.name);
1074 free(ret);
1075 return NULL;
1077 } else {
1078 ret->ref.ref.name = strdup(ref->ref.ref.name);
1079 if (ret->ref.ref.name == NULL) {
1080 free(ret);
1081 return NULL;
1083 memcpy(ret->ref.ref.sha1, ref->ref.ref.sha1,
1084 sizeof(ret->ref.ref.sha1));
1087 return ret;
1090 const struct got_error *
1091 got_reflist_entry_dup(struct got_reflist_entry **newp,
1092 struct got_reflist_entry *re)
1094 const struct got_error *err = NULL;
1095 struct got_reflist_entry *new;
1097 *newp = NULL;
1099 new = malloc(sizeof(*new));
1100 if (new == NULL)
1101 return got_error_from_errno("malloc");
1103 new->ref = got_ref_dup(re->ref);
1104 if (new->ref == NULL) {
1105 err = got_error_from_errno("got_ref_dup");
1106 free(new);
1107 return err;
1110 *newp = new;
1111 return NULL;
1114 void
1115 got_ref_list_free(struct got_reflist_head *refs)
1117 struct got_reflist_entry *re;
1119 while ((re = TAILQ_FIRST(refs))) {
1120 TAILQ_REMOVE(refs, re, entry);
1121 free(re);
1125 EOF
1126 (cd $testroot/repo && git add reference.c)
1127 git_commit $testroot/repo -m "added reference.c file"
1128 local base_commit=`git_show_head $testroot/repo`
1130 got checkout $testroot/repo $testroot/wt > /dev/null
1131 ret="$?"
1132 if [ "$ret" != "0" ]; then
1133 test_done "$testroot" "$ret"
1134 return 1
1137 (cd $testroot/repo && git checkout -q -b newbranch)
1138 ed -s $testroot/repo/reference.c <<EOF
1139 91a
1140 if (!is_valid_ref_name(name))
1141 return got_error_path(name, GOT_ERR_BAD_REF_NAME);
1146 EOF
1147 git_commit $testroot/repo -m "added lines on newbranch"
1148 local branch_rev1=`git_show_head $testroot/repo`
1150 ed -s $testroot/repo/reference.c <<EOF
1151 255a
1152 got_ref_close(re->ref);
1156 EOF
1157 git_commit $testroot/repo -m "more lines on newbranch"
1159 local branch_rev2=`git_show_head $testroot/repo`
1161 (cd $testroot/wt && got cherrypick $branch_rev2 > $testroot/stdout)
1163 echo "G reference.c" > $testroot/stdout.expected
1164 echo "Merged commit $branch_rev2" >> $testroot/stdout.expected
1166 cmp -s $testroot/stdout.expected $testroot/stdout
1167 ret="$?"
1168 if [ "$ret" != "0" ]; then
1169 diff -u $testroot/stdout.expected $testroot/stdout
1170 test_done "$testroot" "$ret"
1171 return 1
1174 cat > $testroot/diff.expected <<EOF
1175 --- reference.c
1176 +++ reference.c
1177 @@ -250,6 +250,7 @@ got_ref_list_free(struct got_reflist_head *refs)
1179 while ((re = TAILQ_FIRST(refs))) {
1180 TAILQ_REMOVE(refs, re, entry);
1181 + got_ref_close(re->ref);
1182 free(re);
1185 EOF
1186 (cd $testroot/wt && got diff |
1187 egrep -v '^(diff|blob|file)' > $testroot/diff)
1188 cmp -s $testroot/diff.expected $testroot/diff
1189 ret="$?"
1190 if [ "$ret" != "0" ]; then
1191 diff -u $testroot/diff.expected $testroot/diff
1194 test_done "$testroot" "$ret"
1197 test_parseargs "$@"
1198 run_test test_cherrypick_basic
1199 run_test test_cherrypick_root_commit
1200 run_test test_cherrypick_into_work_tree_with_conflicts
1201 run_test test_cherrypick_modified_submodule
1202 run_test test_cherrypick_added_submodule
1203 run_test test_cherrypick_conflict_wt_file_vs_repo_submodule
1204 run_test test_cherrypick_modified_symlinks
1205 run_test test_cherrypick_symlink_conflicts
1206 run_test test_cherrypick_with_path_prefix_and_empty_tree
1207 run_test test_cherrypick_conflict_no_eol
1208 run_test test_cherrypick_conflict_no_eol2
1209 run_test test_cherrypick_unrelated_changes