From 3c2f75b590c35675cc67dc43cabe2298bec86afc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 26 Jun 2006 13:46:52 -0700 Subject: t4013: add tests for diff/log family output options. Signed-off-by: Junio C Hamano --- t/t4013-diff-various.sh | 202 +++++++++++++++++++++ t/t4013/diff.diff-tree_--cc_master | 30 +++ t/t4013/diff.diff-tree_--patch-with-raw_initial | 2 + t/t4013/diff.diff-tree_--patch-with-stat_initial | 2 + ...-tree_--pretty=oneline_--patch-with-raw_initial | 2 + ...tree_--pretty=oneline_--patch-with-stat_initial | 2 + ...-pretty=oneline_--root_--patch-with-raw_initial | 33 ++++ ...pretty=oneline_--root_--patch-with-stat_initial | 35 ++++ ...ff.diff-tree_--pretty=oneline_--root_-p_initial | 29 +++ .../diff.diff-tree_--pretty=oneline_--root_initial | 6 + t/t4013/diff.diff-tree_--pretty=oneline_-p_initial | 2 + t/t4013/diff.diff-tree_--pretty=oneline_initial | 2 + ...iff.diff-tree_--pretty_--patch-with-raw_initial | 2 + ...ff.diff-tree_--pretty_--patch-with-stat_initial | 2 + .../diff.diff-tree_--pretty_--patch-with-stat_side | 43 +++++ ...f-tree_--pretty_--root_--patch-with-raw_initial | 38 ++++ ...-tree_--pretty_--root_--patch-with-stat_initial | 39 ++++ ...f-tree_--pretty_--root_--stat_--summary_initial | 15 ++ .../diff.diff-tree_--pretty_--root_--stat_initial | 12 ++ t/t4013/diff.diff-tree_--pretty_--root_-p_initial | 34 ++++ t/t4013/diff.diff-tree_--pretty_--root_initial | 11 ++ ...iff.diff-tree_--pretty_--stat_--summary_initial | 2 + t/t4013/diff.diff-tree_--pretty_--stat_initial | 2 + t/t4013/diff.diff-tree_--pretty_--summary_initial | 2 + t/t4013/diff.diff-tree_--pretty_-p_initial | 2 + t/t4013/diff.diff-tree_--pretty_-p_side | 38 ++++ t/t4013/diff.diff-tree_--pretty_initial | 2 + t/t4013/diff.diff-tree_--pretty_side | 11 ++ t/t4013/diff.diff-tree_--root_--abbrev_initial | 6 + .../diff.diff-tree_--root_--patch-with-raw_initial | 33 ++++ ...diff.diff-tree_--root_--patch-with-stat_initial | 34 ++++ t/t4013/diff.diff-tree_--root_-p_initial | 29 +++ .../diff.diff-tree_--root_-r_--abbrev=4_initial | 6 + t/t4013/diff.diff-tree_--root_-r_--abbrev_initial | 6 + t/t4013/diff.diff-tree_--root_-r_initial | 6 + t/t4013/diff.diff-tree_--root_initial | 6 + t/t4013/diff.diff-tree_-c_--abbrev_master | 5 + t/t4013/diff.diff-tree_-c_master | 5 + t/t4013/diff.diff-tree_-p_-m_master | 80 ++++++++ t/t4013/diff.diff-tree_-p_initial | 2 + t/t4013/diff.diff-tree_-p_master | 2 + t/t4013/diff.diff-tree_-r_--abbrev=4_initial | 2 + t/t4013/diff.diff-tree_-r_--abbrev_initial | 2 + t/t4013/diff.diff-tree_-r_initial | 2 + t/t4013/diff.diff-tree_initial | 2 + t/t4013/diff.diff-tree_master | 2 + t/t4013/diff.log_--patch-with-stat_master | 127 +++++++++++++ t/t4013/diff.log_--patch-with-stat_master_--_dir_ | 72 ++++++++ t/t4013/diff.log_--root_--patch-with-stat_master | 159 ++++++++++++++++ t/t4013/diff.log_--root_-p_master | 140 ++++++++++++++ t/t4013/diff.log_--root_master | 32 ++++ t/t4013/diff.log_-SF_master | 8 + t/t4013/diff.log_-p_master | 113 ++++++++++++ t/t4013/diff.log_master | 32 ++++ t/t4013/diff.show_--patch-with-raw_side | 42 +++++ t/t4013/diff.show_--patch-with-stat_--summary_side | 44 +++++ t/t4013/diff.show_--patch-with-stat_side | 43 +++++ t/t4013/diff.show_--root_initial | 34 ++++ t/t4013/diff.show_--stat_--summary_side | 13 ++ t/t4013/diff.show_--stat_side | 12 ++ t/t4013/diff.show_initial | 7 + t/t4013/diff.show_master | 36 ++++ t/t4013/diff.show_side | 38 ++++ t/t4013/diff.whatchanged_--patch-with-stat_master | 114 ++++++++++++ ...ff.whatchanged_--patch-with-stat_master_--_dir_ | 59 ++++++ ...anged_--root_--patch-with-stat_--summary_master | 158 ++++++++++++++++ ...iff.whatchanged_--root_--patch-with-stat_master | 152 ++++++++++++++++ t/t4013/diff.whatchanged_--root_-p_master | 133 ++++++++++++++ t/t4013/diff.whatchanged_--root_master | 40 ++++ t/t4013/diff.whatchanged_-SF_master | 9 + t/t4013/diff.whatchanged_-p_master | 100 ++++++++++ t/t4013/diff.whatchanged_master | 30 +++ 72 files changed, 2579 insertions(+) create mode 100755 t/t4013-diff-various.sh create mode 100644 t/t4013/diff.diff-tree_--cc_master create mode 100644 t/t4013/diff.diff-tree_--patch-with-raw_initial create mode 100644 t/t4013/diff.diff-tree_--patch-with-stat_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_-p_initial create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--stat_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_-p_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--stat_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--summary_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_-p_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_-p_side create mode 100644 t/t4013/diff.diff-tree_--pretty_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_side create mode 100644 t/t4013/diff.diff-tree_--root_--abbrev_initial create mode 100644 t/t4013/diff.diff-tree_--root_--patch-with-raw_initial create mode 100644 t/t4013/diff.diff-tree_--root_--patch-with-stat_initial create mode 100644 t/t4013/diff.diff-tree_--root_-p_initial create mode 100644 t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial create mode 100644 t/t4013/diff.diff-tree_--root_-r_--abbrev_initial create mode 100644 t/t4013/diff.diff-tree_--root_-r_initial create mode 100644 t/t4013/diff.diff-tree_--root_initial create mode 100644 t/t4013/diff.diff-tree_-c_--abbrev_master create mode 100644 t/t4013/diff.diff-tree_-c_master create mode 100644 t/t4013/diff.diff-tree_-p_-m_master create mode 100644 t/t4013/diff.diff-tree_-p_initial create mode 100644 t/t4013/diff.diff-tree_-p_master create mode 100644 t/t4013/diff.diff-tree_-r_--abbrev=4_initial create mode 100644 t/t4013/diff.diff-tree_-r_--abbrev_initial create mode 100644 t/t4013/diff.diff-tree_-r_initial create mode 100644 t/t4013/diff.diff-tree_initial create mode 100644 t/t4013/diff.diff-tree_master create mode 100644 t/t4013/diff.log_--patch-with-stat_master create mode 100644 t/t4013/diff.log_--patch-with-stat_master_--_dir_ create mode 100644 t/t4013/diff.log_--root_--patch-with-stat_master create mode 100644 t/t4013/diff.log_--root_-p_master create mode 100644 t/t4013/diff.log_--root_master create mode 100644 t/t4013/diff.log_-SF_master create mode 100644 t/t4013/diff.log_-p_master create mode 100644 t/t4013/diff.log_master create mode 100644 t/t4013/diff.show_--patch-with-raw_side create mode 100644 t/t4013/diff.show_--patch-with-stat_--summary_side create mode 100644 t/t4013/diff.show_--patch-with-stat_side create mode 100644 t/t4013/diff.show_--root_initial create mode 100644 t/t4013/diff.show_--stat_--summary_side create mode 100644 t/t4013/diff.show_--stat_side create mode 100644 t/t4013/diff.show_initial create mode 100644 t/t4013/diff.show_master create mode 100644 t/t4013/diff.show_side create mode 100644 t/t4013/diff.whatchanged_--patch-with-stat_master create mode 100644 t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ create mode 100644 t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master create mode 100644 t/t4013/diff.whatchanged_--root_--patch-with-stat_master create mode 100644 t/t4013/diff.whatchanged_--root_-p_master create mode 100644 t/t4013/diff.whatchanged_--root_master create mode 100644 t/t4013/diff.whatchanged_-SF_master create mode 100644 t/t4013/diff.whatchanged_-p_master create mode 100644 t/t4013/diff.whatchanged_master (limited to 't') diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh new file mode 100755 index 0000000000..802e0ba01d --- /dev/null +++ b/t/t4013-diff-various.sh @@ -0,0 +1,202 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='Various diff formatting options' + +. ./test-lib.sh + +test_expect_success setup ' + + GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" && + GIT_COMMITTER_DATE="2006-06-26 00:00:00 +0000" && + export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && + + mkdir dir && + for i in 1 2 3; do echo $i; done >file0 && + for i in A B; do echo $i; done >dir/sub && + cat file0 >file2 && + git add file0 file2 dir/sub && + git commit -m Initial && + + git branch initial && + git branch side && + + GIT_AUTHOR_DATE="2006-06-26 00:01:00 +0000" && + GIT_COMMITTER_DATE="2006-06-26 00:01:00 +0000" && + export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && + + for i in 4 5 6; do echo $i; done >>file0 && + for i in C D; do echo $i; done >>dir/sub && + rm -f file2 && + git update-index --remove file0 file2 dir/sub && + git commit -m Second && + + GIT_AUTHOR_DATE="2006-06-26 00:02:00 +0000" && + GIT_COMMITTER_DATE="2006-06-26 00:02:00 +0000" && + export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && + + for i in A B C; do echo $i; done >file1 && + git add file1 && + for i in E F; do echo $i; done >>dir/sub && + git update-index dir/sub && + git commit -m Third && + + GIT_AUTHOR_DATE="2006-06-26 00:03:00 +0000" && + GIT_COMMITTER_DATE="2006-06-26 00:03:00 +0000" && + export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && + + git checkout side && + for i in A B C; do echo $i; done >>file0 && + for i in 1 2; do echo $i; done >>dir/sub && + cat dir/sub >file3 && + git add file3 && + git update-index file0 dir/sub && + git commit -m Side && + + GIT_AUTHOR_DATE="2006-06-26 00:04:00 +0000" && + GIT_COMMITTER_DATE="2006-06-26 00:04:00 +0000" && + export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && + + git checkout master && + git pull -s ours . side && + + GIT_AUTHOR_DATE="2006-06-26 00:05:00 +0000" && + GIT_COMMITTER_DATE="2006-06-26 00:05:00 +0000" && + export GIT_AUTHOR_DATE GIT_COMMITTER_DATE && + + for i in A B C; do echo $i; done >>file0 && + for i in 1 2; do echo $i; done >>dir/sub && + git update-index file0 dir/sub && + + EDITOR=: VISUAL=: git commit --amend && + git show-branch +' + +: <<\EOF +! [initial] Initial + * [master] Merge branch 'side' + ! [side] Side +--- + - [master] Merge branch 'side' + *+ [side] Side + * [master^] Second ++*+ [initial] Initial +EOF + +while read cmd +do + case "$cmd" in + '' | '#'*) continue ;; + esac + test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'` + cnt=`expr $test_count + 1` + pfx=`printf "%04d" $cnt` + expect="../t4013/diff.$test" + actual="$pfx-diff.$test" + + test_expect_success "git $cmd" ' + { + echo "\$ git $cmd" + git $cmd + echo "\$" + } >"$actual" && + if test -f "$expect" + then + diff -u "$expect" "$actual" && + rm -f "$actual" + else + # this is to help developing new tests. + cp "$actual" "$expect" + false + fi + ' +done <<\EOF +diff-tree initial +diff-tree -r initial +diff-tree -r --abbrev initial +diff-tree -r --abbrev=4 initial +diff-tree --root initial +diff-tree --root --abbrev initial +diff-tree --root -r initial +diff-tree --root -r --abbrev initial +diff-tree --root -r --abbrev=4 initial +diff-tree -p initial +diff-tree --root -p initial +diff-tree --patch-with-stat initial +diff-tree --root --patch-with-stat initial +diff-tree --patch-with-raw initial +diff-tree --root --patch-with-raw initial + +diff-tree --pretty initial +diff-tree --pretty --root initial +diff-tree --pretty -p initial +diff-tree --pretty --stat initial +diff-tree --pretty --summary initial +diff-tree --pretty --stat --summary initial +diff-tree --pretty --root -p initial +diff-tree --pretty --root --stat initial +#diff-tree --pretty --root --summary initial +diff-tree --pretty --root --stat --summary initial +diff-tree --pretty --patch-with-stat initial +diff-tree --pretty --root --patch-with-stat initial +diff-tree --pretty --patch-with-raw initial +diff-tree --pretty --root --patch-with-raw initial + +diff-tree --pretty=oneline initial +diff-tree --pretty=oneline --root initial +diff-tree --pretty=oneline -p initial +diff-tree --pretty=oneline --root -p initial +diff-tree --pretty=oneline --patch-with-stat initial +diff-tree --pretty=oneline --root --patch-with-stat initial +diff-tree --pretty=oneline --patch-with-raw initial +diff-tree --pretty=oneline --root --patch-with-raw initial + +diff-tree --pretty side +diff-tree --pretty -p side +diff-tree --pretty --patch-with-stat side + +diff-tree master +diff-tree -p master +diff-tree -p -m master +diff-tree -c master +diff-tree -c --abbrev master +diff-tree --cc master + +log master +log -p master +log --root master +log --root -p master +log --patch-with-stat master +log --root --patch-with-stat master +#log --root --patch-with-stat --summary master +log -SF master + +whatchanged master +whatchanged -p master +whatchanged --root master +whatchanged --root -p master +whatchanged --patch-with-stat master +whatchanged --root --patch-with-stat master +whatchanged --root --patch-with-stat --summary master +whatchanged -SF master + +log --patch-with-stat master -- dir/ +whatchanged --patch-with-stat master -- dir/ + +show initial +show --root initial +show side +show master +show --stat side +show --stat --summary side +show --patch-with-stat side +show --patch-with-raw side +show --patch-with-stat --summary side + + + +EOF + +test_done diff --git a/t/t4013/diff.diff-tree_--cc_master b/t/t4013/diff.diff-tree_--cc_master new file mode 100644 index 0000000000..e57d943bdc --- /dev/null +++ b/t/t4013/diff.diff-tree_--cc_master @@ -0,0 +1,30 @@ +$ git diff-tree --cc master +176b998f5d647cbd77a9d8acf4531e930754d16d +diff --cc dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --cc file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C +$ diff --git a/t/t4013/diff.diff-tree_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--patch-with-raw_initial new file mode 100644 index 0000000000..fc177ab3f2 --- /dev/null +++ b/t/t4013/diff.diff-tree_--patch-with-raw_initial @@ -0,0 +1,2 @@ +$ git diff-tree --patch-with-raw initial +$ diff --git a/t/t4013/diff.diff-tree_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--patch-with-stat_initial new file mode 100644 index 0000000000..bd905b1c57 --- /dev/null +++ b/t/t4013/diff.diff-tree_--patch-with-stat_initial @@ -0,0 +1,2 @@ +$ git diff-tree --patch-with-stat initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial new file mode 100644 index 0000000000..7bb8b45e3e --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty=oneline --patch-with-raw initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial new file mode 100644 index 0000000000..cbdde4f400 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty=oneline --patch-with-stat initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial new file mode 100644 index 0000000000..cd79f1a0ff --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial @@ -0,0 +1,33 @@ +$ git diff-tree --pretty=oneline --root --patch-with-raw initial +444ac553ac7612cc88969031b02b3767fb8a353a Initial +:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0 +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial new file mode 100644 index 0000000000..49e26fb99a --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial @@ -0,0 +1,35 @@ +$ git diff-tree --pretty=oneline --root --patch-with-stat initial +444ac553ac7612cc88969031b02b3767fb8a353a Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial new file mode 100644 index 0000000000..3c5092c699 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial @@ -0,0 +1,29 @@ +$ git diff-tree --pretty=oneline --root -p initial +444ac553ac7612cc88969031b02b3767fb8a353a Initial +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_initial new file mode 100644 index 0000000000..08920ac658 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_initial @@ -0,0 +1,6 @@ +$ git diff-tree --pretty=oneline --root initial +444ac553ac7612cc88969031b02b3767fb8a353a Initial +:000000 040000 0000000000000000000000000000000000000000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 A dir +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0 +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2 +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_-p_initial b/t/t4013/diff.diff-tree_--pretty=oneline_-p_initial new file mode 100644 index 0000000000..94b76bfef1 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_-p_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty=oneline -p initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_initial b/t/t4013/diff.diff-tree_--pretty=oneline_initial new file mode 100644 index 0000000000..d50970d574 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty=oneline_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty=oneline initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial new file mode 100644 index 0000000000..3a85316d8a --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty --patch-with-raw initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial new file mode 100644 index 0000000000..2e08239a46 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty --patch-with-stat initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side new file mode 100644 index 0000000000..4d30e7eddc --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side @@ -0,0 +1,43 @@ +$ git diff-tree --pretty --patch-with-stat side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial new file mode 100644 index 0000000000..a3203bd19b --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial @@ -0,0 +1,38 @@ +$ git diff-tree --pretty --root --patch-with-raw initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + +:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0 +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial new file mode 100644 index 0000000000..7dfa6af3c9 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial @@ -0,0 +1,39 @@ +$ git diff-tree --pretty --root --patch-with-stat initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial new file mode 100644 index 0000000000..43bfce253e --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial @@ -0,0 +1,15 @@ +$ git diff-tree --pretty --root --stat --summary initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial new file mode 100644 index 0000000000..9154aa4d47 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial @@ -0,0 +1,12 @@ +$ git diff-tree --pretty --root --stat initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_-p_initial b/t/t4013/diff.diff-tree_--pretty_--root_-p_initial new file mode 100644 index 0000000000..d0411f64ec --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_-p_initial @@ -0,0 +1,34 @@ +$ git diff-tree --pretty --root -p initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_initial b/t/t4013/diff.diff-tree_--pretty_--root_initial new file mode 100644 index 0000000000..94e32eabb1 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_initial @@ -0,0 +1,11 @@ +$ git diff-tree --pretty --root initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + +:000000 040000 0000000000000000000000000000000000000000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 A dir +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0 +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial new file mode 100644 index 0000000000..c22983ac4a --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty --stat --summary initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--stat_initial new file mode 100644 index 0000000000..8fdcfb4c0a --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--stat_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty --stat initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--summary_initial new file mode 100644 index 0000000000..9bc2c4fbad --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--summary_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty --summary initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_-p_initial b/t/t4013/diff.diff-tree_--pretty_-p_initial new file mode 100644 index 0000000000..3c9942faf4 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_-p_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty -p initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_-p_side b/t/t4013/diff.diff-tree_--pretty_-p_side new file mode 100644 index 0000000000..b993aa7b89 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_-p_side @@ -0,0 +1,38 @@ +$ git diff-tree --pretty -p side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_initial b/t/t4013/diff.diff-tree_--pretty_initial new file mode 100644 index 0000000000..14715bf7d0 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_initial @@ -0,0 +1,2 @@ +$ git diff-tree --pretty initial +$ diff --git a/t/t4013/diff.diff-tree_--pretty_side b/t/t4013/diff.diff-tree_--pretty_side new file mode 100644 index 0000000000..e9b6e1c102 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_side @@ -0,0 +1,11 @@ +$ git diff-tree --pretty side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +:040000 040000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 f977ed46ae6873c1c30ab878e15a4accedc3618b M dir +:100644 100644 01e79c32a8c99c557f0757da7cb6d65b3414466d f4615da674c09df322d6ba8d6b21ecfb1b1ba510 M file0 +:000000 100644 0000000000000000000000000000000000000000 7289e35bff32727c08dda207511bec138fdb9ea5 A file3 +$ diff --git a/t/t4013/diff.diff-tree_--root_--abbrev_initial b/t/t4013/diff.diff-tree_--root_--abbrev_initial new file mode 100644 index 0000000000..5aa84b2a86 --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_--abbrev_initial @@ -0,0 +1,6 @@ +$ git diff-tree --root --abbrev initial +444ac553ac7612cc88969031b02b3767fb8a353a +:000000 040000 0000000... da7a33f... A dir +:000000 100644 0000000... 01e79c3... A file0 +:000000 100644 0000000... 01e79c3... A file2 +$ diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-raw_initial b/t/t4013/diff.diff-tree_--root_--patch-with-raw_initial new file mode 100644 index 0000000000..d295e475dd --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_--patch-with-raw_initial @@ -0,0 +1,33 @@ +$ git diff-tree --root --patch-with-raw initial +444ac553ac7612cc88969031b02b3767fb8a353a +:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0 +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial new file mode 100644 index 0000000000..1562b62708 --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial @@ -0,0 +1,34 @@ +$ git diff-tree --root --patch-with-stat initial +444ac553ac7612cc88969031b02b3767fb8a353a + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--root_-p_initial b/t/t4013/diff.diff-tree_--root_-p_initial new file mode 100644 index 0000000000..3219c72fcb --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_-p_initial @@ -0,0 +1,29 @@ +$ git diff-tree --root -p initial +444ac553ac7612cc88969031b02b3767fb8a353a +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial b/t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial new file mode 100644 index 0000000000..0c5361688c --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial @@ -0,0 +1,6 @@ +$ git diff-tree --root -r --abbrev=4 initial +444ac553ac7612cc88969031b02b3767fb8a353a +:000000 100644 0000... 35d2... A dir/sub +:000000 100644 0000... 01e7... A file0 +:000000 100644 0000... 01e7... A file2 +$ diff --git a/t/t4013/diff.diff-tree_--root_-r_--abbrev_initial b/t/t4013/diff.diff-tree_--root_-r_--abbrev_initial new file mode 100644 index 0000000000..c7b460faf6 --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_-r_--abbrev_initial @@ -0,0 +1,6 @@ +$ git diff-tree --root -r --abbrev initial +444ac553ac7612cc88969031b02b3767fb8a353a +:000000 100644 0000000... 35d242b... A dir/sub +:000000 100644 0000000... 01e79c3... A file0 +:000000 100644 0000000... 01e79c3... A file2 +$ diff --git a/t/t4013/diff.diff-tree_--root_-r_initial b/t/t4013/diff.diff-tree_--root_-r_initial new file mode 100644 index 0000000000..eed435e175 --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_-r_initial @@ -0,0 +1,6 @@ +$ git diff-tree --root -r initial +444ac553ac7612cc88969031b02b3767fb8a353a +:000000 100644 0000000000000000000000000000000000000000 35d242ba79ae89ac695e26b3d4c27a8e6f028f9e A dir/sub +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0 +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2 +$ diff --git a/t/t4013/diff.diff-tree_--root_initial b/t/t4013/diff.diff-tree_--root_initial new file mode 100644 index 0000000000..ddf6b068ab --- /dev/null +++ b/t/t4013/diff.diff-tree_--root_initial @@ -0,0 +1,6 @@ +$ git diff-tree --root initial +444ac553ac7612cc88969031b02b3767fb8a353a +:000000 040000 0000000000000000000000000000000000000000 da7a33fa77d8066d6698643940ce5860fe2d7fb3 A dir +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file0 +:000000 100644 0000000000000000000000000000000000000000 01e79c32a8c99c557f0757da7cb6d65b3414466d A file2 +$ diff --git a/t/t4013/diff.diff-tree_-c_--abbrev_master b/t/t4013/diff.diff-tree_-c_--abbrev_master new file mode 100644 index 0000000000..39d511a7cf --- /dev/null +++ b/t/t4013/diff.diff-tree_-c_--abbrev_master @@ -0,0 +1,5 @@ +$ git diff-tree -c --abbrev master +176b998f5d647cbd77a9d8acf4531e930754d16d +::100644 100644 100644 cead32e... 7289e35... 992913c... MM dir/sub +::100644 100644 100644 b414108... f4615da... 10a8a9f... MM file0 +$ diff --git a/t/t4013/diff.diff-tree_-c_master b/t/t4013/diff.diff-tree_-c_master new file mode 100644 index 0000000000..c258efe222 --- /dev/null +++ b/t/t4013/diff.diff-tree_-c_master @@ -0,0 +1,5 @@ +$ git diff-tree -c master +176b998f5d647cbd77a9d8acf4531e930754d16d +::100644 100644 100644 cead32e925b1420c84c14cbf7cf755e7e45af8ad 7289e35bff32727c08dda207511bec138fdb9ea5 992913c5aa0a5476d10c49ed0f21fc0c6d1aedf3 MM dir/sub +::100644 100644 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 f4615da674c09df322d6ba8d6b21ecfb1b1ba510 10a8a9f3657f91a156b9f0184ed79a20adef9f7f MM file0 +$ diff --git a/t/t4013/diff.diff-tree_-p_-m_master b/t/t4013/diff.diff-tree_-p_-m_master new file mode 100644 index 0000000000..1be721560a --- /dev/null +++ b/t/t4013/diff.diff-tree_-p_-m_master @@ -0,0 +1,80 @@ +$ git diff-tree -p -m master +176b998f5d647cbd77a9d8acf4531e930754d16d +diff --git a/dir/sub b/dir/sub +index cead32e..992913c 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -4,3 +4,5 @@ C + D + E + F ++1 ++2 +diff --git a/file0 b/file0 +index b414108..10a8a9f 100644 +--- a/file0 ++++ b/file0 +@@ -4,3 +4,6 @@ + 4 + 5 + 6 ++A ++B ++C +176b998f5d647cbd77a9d8acf4531e930754d16d +diff --git a/dir/sub b/dir/sub +index 7289e35..992913c 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,4 +1,8 @@ + A + B ++C ++D ++E ++F + 1 + 2 +diff --git a/file0 b/file0 +index f4615da..10a8a9f 100644 +--- a/file0 ++++ b/file0 +@@ -1,6 +1,9 @@ + 1 + 2 + 3 ++4 ++5 ++6 + A + B + C +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 +diff --git a/file3 b/file3 +deleted file mode 100644 +index 7289e35..0000000 +--- a/file3 ++++ /dev/null +@@ -1,4 +0,0 @@ +-A +-B +-1 +-2 +$ diff --git a/t/t4013/diff.diff-tree_-p_initial b/t/t4013/diff.diff-tree_-p_initial new file mode 100644 index 0000000000..e20ce88370 --- /dev/null +++ b/t/t4013/diff.diff-tree_-p_initial @@ -0,0 +1,2 @@ +$ git diff-tree -p initial +$ diff --git a/t/t4013/diff.diff-tree_-p_master b/t/t4013/diff.diff-tree_-p_master new file mode 100644 index 0000000000..b182875fb2 --- /dev/null +++ b/t/t4013/diff.diff-tree_-p_master @@ -0,0 +1,2 @@ +$ git diff-tree -p master +$ diff --git a/t/t4013/diff.diff-tree_-r_--abbrev=4_initial b/t/t4013/diff.diff-tree_-r_--abbrev=4_initial new file mode 100644 index 0000000000..c5a3aa5aa4 --- /dev/null +++ b/t/t4013/diff.diff-tree_-r_--abbrev=4_initial @@ -0,0 +1,2 @@ +$ git diff-tree -r --abbrev=4 initial +$ diff --git a/t/t4013/diff.diff-tree_-r_--abbrev_initial b/t/t4013/diff.diff-tree_-r_--abbrev_initial new file mode 100644 index 0000000000..0b689b773c --- /dev/null +++ b/t/t4013/diff.diff-tree_-r_--abbrev_initial @@ -0,0 +1,2 @@ +$ git diff-tree -r --abbrev initial +$ diff --git a/t/t4013/diff.diff-tree_-r_initial b/t/t4013/diff.diff-tree_-r_initial new file mode 100644 index 0000000000..1765d83ce4 --- /dev/null +++ b/t/t4013/diff.diff-tree_-r_initial @@ -0,0 +1,2 @@ +$ git diff-tree -r initial +$ diff --git a/t/t4013/diff.diff-tree_initial b/t/t4013/diff.diff-tree_initial new file mode 100644 index 0000000000..b49fc53457 --- /dev/null +++ b/t/t4013/diff.diff-tree_initial @@ -0,0 +1,2 @@ +$ git diff-tree initial +$ diff --git a/t/t4013/diff.diff-tree_master b/t/t4013/diff.diff-tree_master new file mode 100644 index 0000000000..fe9226f8a1 --- /dev/null +++ b/t/t4013/diff.diff-tree_master @@ -0,0 +1,2 @@ +$ git diff-tree master +$ diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master new file mode 100644 index 0000000000..b97969dc98 --- /dev/null +++ b/t/t4013/diff.log_--patch-with-stat_master @@ -0,0 +1,127 @@ +$ git log --patch-with-stat master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ new file mode 100644 index 0000000000..71a6d0f853 --- /dev/null +++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ @@ -0,0 +1,72 @@ +$ git log --patch-with-stat master -- dir/ +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master new file mode 100644 index 0000000000..1e9bdc4c1c --- /dev/null +++ b/t/t4013/diff.log_--root_--patch-with-stat_master @@ -0,0 +1,159 @@ +$ git log --root --patch-with-stat master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.log_--root_-p_master b/t/t4013/diff.log_--root_-p_master new file mode 100644 index 0000000000..2296986ad1 --- /dev/null +++ b/t/t4013/diff.log_--root_-p_master @@ -0,0 +1,140 @@ +$ git log --root -p master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.log_--root_master b/t/t4013/diff.log_--root_master new file mode 100644 index 0000000000..7554a468d1 --- /dev/null +++ b/t/t4013/diff.log_--root_master @@ -0,0 +1,32 @@ +$ git log --root master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4013/diff.log_-SF_master b/t/t4013/diff.log_-SF_master new file mode 100644 index 0000000000..f307b4d2a8 --- /dev/null +++ b/t/t4013/diff.log_-SF_master @@ -0,0 +1,8 @@ +$ git log -SF master +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +$ diff --git a/t/t4013/diff.log_-p_master b/t/t4013/diff.log_-p_master new file mode 100644 index 0000000000..e82a72f6f8 --- /dev/null +++ b/t/t4013/diff.log_-p_master @@ -0,0 +1,113 @@ +$ git log -p master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4013/diff.log_master b/t/t4013/diff.log_master new file mode 100644 index 0000000000..7b86ed1f5d --- /dev/null +++ b/t/t4013/diff.log_master @@ -0,0 +1,32 @@ +$ git log master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4013/diff.show_--patch-with-raw_side b/t/t4013/diff.show_--patch-with-raw_side new file mode 100644 index 0000000000..221b46a7cc --- /dev/null +++ b/t/t4013/diff.show_--patch-with-raw_side @@ -0,0 +1,42 @@ +$ git show --patch-with-raw side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +:100644 100644 35d242b... 7289e35... M dir/sub +:100644 100644 01e79c3... f4615da... M file0 +:000000 100644 0000000... 7289e35... A file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.show_--patch-with-stat_--summary_side b/t/t4013/diff.show_--patch-with-stat_--summary_side new file mode 100644 index 0000000000..377f2b7b7a --- /dev/null +++ b/t/t4013/diff.show_--patch-with-stat_--summary_side @@ -0,0 +1,44 @@ +$ git show --patch-with-stat --summary side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.show_--patch-with-stat_side b/t/t4013/diff.show_--patch-with-stat_side new file mode 100644 index 0000000000..fb14c530d2 --- /dev/null +++ b/t/t4013/diff.show_--patch-with-stat_side @@ -0,0 +1,43 @@ +$ git show --patch-with-stat side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.show_--root_initial b/t/t4013/diff.show_--root_initial new file mode 100644 index 0000000000..8c89136c4d --- /dev/null +++ b/t/t4013/diff.show_--root_initial @@ -0,0 +1,34 @@ +$ git show --root initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.show_--stat_--summary_side b/t/t4013/diff.show_--stat_--summary_side new file mode 100644 index 0000000000..5bd5977628 --- /dev/null +++ b/t/t4013/diff.show_--stat_--summary_side @@ -0,0 +1,13 @@ +$ git show --stat --summary side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 +$ diff --git a/t/t4013/diff.show_--stat_side b/t/t4013/diff.show_--stat_side new file mode 100644 index 0000000000..3b22327e48 --- /dev/null +++ b/t/t4013/diff.show_--stat_side @@ -0,0 +1,12 @@ +$ git show --stat side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.show_initial b/t/t4013/diff.show_initial new file mode 100644 index 0000000000..4c4066ae48 --- /dev/null +++ b/t/t4013/diff.show_initial @@ -0,0 +1,7 @@ +$ git show initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4013/diff.show_master b/t/t4013/diff.show_master new file mode 100644 index 0000000000..3772a87e13 --- /dev/null +++ b/t/t4013/diff.show_master @@ -0,0 +1,36 @@ +$ git show master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +diff --cc dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --cc file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C +$ diff --git a/t/t4013/diff.show_side b/t/t4013/diff.show_side new file mode 100644 index 0000000000..530a073b19 --- /dev/null +++ b/t/t4013/diff.show_side @@ -0,0 +1,38 @@ +$ git show side +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master new file mode 100644 index 0000000000..a89b573f45 --- /dev/null +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master @@ -0,0 +1,114 @@ +$ git whatchanged --patch-with-stat master +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 +$ diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ new file mode 100644 index 0000000000..b6d9752164 --- /dev/null +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ @@ -0,0 +1,59 @@ +$ git whatchanged --patch-with-stat master -- dir/ +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +$ diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master new file mode 100644 index 0000000000..f707bfa3a1 --- /dev/null +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master @@ -0,0 +1,158 @@ +$ git whatchanged --root --patch-with-stat --summary master +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master new file mode 100644 index 0000000000..61aca41711 --- /dev/null +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master @@ -0,0 +1,152 @@ +$ git whatchanged --root --patch-with-stat master +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.whatchanged_--root_-p_master b/t/t4013/diff.whatchanged_--root_-p_master new file mode 100644 index 0000000000..b4cd05e576 --- /dev/null +++ b/t/t4013/diff.whatchanged_--root_-p_master @@ -0,0 +1,133 @@ +$ git whatchanged --root -p master +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.whatchanged_--root_master b/t/t4013/diff.whatchanged_--root_master new file mode 100644 index 0000000000..011a22178f --- /dev/null +++ b/t/t4013/diff.whatchanged_--root_master @@ -0,0 +1,40 @@ +$ git whatchanged --root master +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +:100644 100644 35d242b... 7289e35... M dir/sub +:100644 100644 01e79c3... f4615da... M file0 +:000000 100644 0000000... 7289e35... A file3 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +:100644 100644 8422d40... cead32e... M dir/sub +:000000 100644 0000000... b1e6722... A file1 + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +:100644 100644 35d242b... 8422d40... M dir/sub +:100644 100644 01e79c3... b414108... M file0 +:100644 000000 01e79c3... 0000000... D file2 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + +:000000 100644 0000000... 35d242b... A dir/sub +:000000 100644 0000000... 01e79c3... A file0 +:000000 100644 0000000... 01e79c3... A file2 +$ diff --git a/t/t4013/diff.whatchanged_-SF_master b/t/t4013/diff.whatchanged_-SF_master new file mode 100644 index 0000000000..a4fe6f8a39 --- /dev/null +++ b/t/t4013/diff.whatchanged_-SF_master @@ -0,0 +1,9 @@ +$ git whatchanged -SF master +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +:100644 100644 8422d40... cead32e... M dir/sub +$ diff --git a/t/t4013/diff.whatchanged_-p_master b/t/t4013/diff.whatchanged_-p_master new file mode 100644 index 0000000000..f9a4456725 --- /dev/null +++ b/t/t4013/diff.whatchanged_-p_master @@ -0,0 +1,100 @@ +$ git whatchanged -p master +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 +$ diff --git a/t/t4013/diff.whatchanged_master b/t/t4013/diff.whatchanged_master new file mode 100644 index 0000000000..c22416c006 --- /dev/null +++ b/t/t4013/diff.whatchanged_master @@ -0,0 +1,30 @@ +$ git whatchanged master +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +:100644 100644 35d242b... 7289e35... M dir/sub +:100644 100644 01e79c3... f4615da... M file0 +:000000 100644 0000000... 7289e35... A file3 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +:100644 100644 8422d40... cead32e... M dir/sub +:000000 100644 0000000... b1e6722... A file1 + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + +:100644 100644 35d242b... 8422d40... M dir/sub +:100644 100644 01e79c3... b414108... M file0 +:100644 000000 01e79c3... 0000000... D file2 +$ -- cgit v1.3-5-g9baa From 47979d5d5bb86d058dce77801648734abe1e593b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 26 Jun 2006 23:29:11 -0700 Subject: t4013: add more tests around -c and --cc Signed-off-by: Junio C Hamano --- t/t4013-diff-various.sh | 28 ++- ...ff-tree_--cc_--patch-with-stat_--summary_master | 35 ++++ ...diff-tree_--cc_--patch-with-stat_--summary_side | 39 ++++ .../diff.diff-tree_--cc_--stat_--summary_master | 6 + t/t4013/diff.diff-tree_--cc_--stat_--summary_side | 8 + t/t4013/diff.diff-tree_--cc_--stat_master | 6 + t/t4013/diff.diff-tree_-c_--stat_--summary_master | 6 + t/t4013/diff.diff-tree_-c_--stat_--summary_side | 8 + t/t4013/diff.diff-tree_-c_--stat_master | 6 + ....log_--patch-with-stat_--summary_master_--_dir_ | 72 ++++++++ ..._--root_--cc_--patch-with-stat_--summary_master | 198 +++++++++++++++++++++ ...f.log_--root_--patch-with-stat_--summary_master | 165 +++++++++++++++++ ...og_--root_-c_--patch-with-stat_--summary_master | 198 +++++++++++++++++++++ t/t4013/diff.log_-SF_-p_master | 18 ++ ...nged_--patch-with-stat_--summary_master_--_dir_ | 59 ++++++ ..._--root_--cc_--patch-with-stat_--summary_master | 198 +++++++++++++++++++++ ...ed_--root_-c_--patch-with-stat_--summary_master | 198 +++++++++++++++++++++ t/t4013/diff.whatchanged_-SF_-p_master | 18 ++ 18 files changed, 1263 insertions(+), 3 deletions(-) create mode 100644 t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master create mode 100644 t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side create mode 100644 t/t4013/diff.diff-tree_--cc_--stat_--summary_master create mode 100644 t/t4013/diff.diff-tree_--cc_--stat_--summary_side create mode 100644 t/t4013/diff.diff-tree_--cc_--stat_master create mode 100644 t/t4013/diff.diff-tree_-c_--stat_--summary_master create mode 100644 t/t4013/diff.diff-tree_-c_--stat_--summary_side create mode 100644 t/t4013/diff.diff-tree_-c_--stat_master create mode 100644 t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ create mode 100644 t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master create mode 100644 t/t4013/diff.log_--root_--patch-with-stat_--summary_master create mode 100644 t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master create mode 100644 t/t4013/diff.log_-SF_-p_master create mode 100644 t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ create mode 100644 t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master create mode 100644 t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master create mode 100644 t/t4013/diff.whatchanged_-SF_-p_master (limited to 't') diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 802e0ba01d..22984e3db7 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -163,6 +163,22 @@ diff-tree -p -m master diff-tree -c master diff-tree -c --abbrev master diff-tree --cc master +# stat only should show the diffstat with the first parent +diff-tree -c --stat master +diff-tree --cc --stat master +diff-tree -c --stat --summary master +diff-tree --cc --stat --summary master +# stat summary should show the diffstat and summary with the first parent +diff-tree -c --stat --summary side +diff-tree --cc --stat --summary side +# this one gives an extra newline after stat, which should be removed +# diff-tree --cc --patch-with-stat master +# this one gives an extra newline after stat, which should be removed +# other than that it shows the correct example -- stat and summary are +# against the first parent, and patch-looking combined diff follows. +diff-tree --cc --patch-with-stat --summary master +# this is correct +diff-tree --cc --patch-with-stat --summary side log master log -p master @@ -170,8 +186,11 @@ log --root master log --root -p master log --patch-with-stat master log --root --patch-with-stat master -#log --root --patch-with-stat --summary master +log --root --patch-with-stat --summary master +log --root -c --patch-with-stat --summary master +log --root --cc --patch-with-stat --summary master log -SF master +log -SF -p master whatchanged master whatchanged -p master @@ -180,10 +199,15 @@ whatchanged --root -p master whatchanged --patch-with-stat master whatchanged --root --patch-with-stat master whatchanged --root --patch-with-stat --summary master +whatchanged --root -c --patch-with-stat --summary master +whatchanged --root --cc --patch-with-stat --summary master whatchanged -SF master +whatchanged -SF -p master log --patch-with-stat master -- dir/ whatchanged --patch-with-stat master -- dir/ +log --patch-with-stat --summary master -- dir/ +whatchanged --patch-with-stat --summary master -- dir/ show initial show --root initial @@ -195,8 +219,6 @@ show --patch-with-stat side show --patch-with-raw side show --patch-with-stat --summary side - - EOF test_done diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master new file mode 100644 index 0000000000..e6d0c80567 --- /dev/null +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master @@ -0,0 +1,35 @@ +$ git diff-tree --cc --patch-with-stat --summary master +176b998f5d647cbd77a9d8acf4531e930754d16d + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + + +diff --cc dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --cc file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C +$ diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side new file mode 100644 index 0000000000..a61ad8cb13 --- /dev/null +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side @@ -0,0 +1,39 @@ +$ git diff-tree --cc --patch-with-stat --summary side +c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master new file mode 100644 index 0000000000..712ffd2d89 --- /dev/null +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master @@ -0,0 +1,6 @@ +$ git diff-tree --cc --stat --summary master +176b998f5d647cbd77a9d8acf4531e930754d16d + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side new file mode 100644 index 0000000000..50362be7bf --- /dev/null +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side @@ -0,0 +1,8 @@ +$ git diff-tree --cc --stat --summary side +c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 +$ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master new file mode 100644 index 0000000000..8d5bdc985a --- /dev/null +++ b/t/t4013/diff.diff-tree_--cc_--stat_master @@ -0,0 +1,6 @@ +$ git diff-tree --cc --stat master +176b998f5d647cbd77a9d8acf4531e930754d16d + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master new file mode 100644 index 0000000000..2d239feb5d --- /dev/null +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master @@ -0,0 +1,6 @@ +$ git diff-tree -c --stat --summary master +176b998f5d647cbd77a9d8acf4531e930754d16d + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_side b/t/t4013/diff.diff-tree_-c_--stat_--summary_side new file mode 100644 index 0000000000..2afcca11f4 --- /dev/null +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_side @@ -0,0 +1,8 @@ +$ git diff-tree -c --stat --summary side +c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 +$ diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master new file mode 100644 index 0000000000..226300b93c --- /dev/null +++ b/t/t4013/diff.diff-tree_-c_--stat_master @@ -0,0 +1,6 @@ +$ git diff-tree -c --stat master +176b998f5d647cbd77a9d8acf4531e930754d16d + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ new file mode 100644 index 0000000000..cc5537697d --- /dev/null +++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ @@ -0,0 +1,72 @@ +$ git log --patch-with-stat --summary master -- dir/ +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master new file mode 100644 index 0000000000..fafd9ee59e --- /dev/null +++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master @@ -0,0 +1,198 @@ +$ git log --root --cc --patch-with-stat --summary master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' +--- + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + + +diff --cc dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --cc file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master new file mode 100644 index 0000000000..b24a504759 --- /dev/null +++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master @@ -0,0 +1,165 @@ +$ git log --root --patch-with-stat --summary master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master new file mode 100644 index 0000000000..51e39cda00 --- /dev/null +++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master @@ -0,0 +1,198 @@ +$ git log --root -c --patch-with-stat --summary master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' +--- + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + + +diff --combined dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --combined file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.log_-SF_-p_master b/t/t4013/diff.log_-SF_-p_master new file mode 100644 index 0000000000..db2264c6e9 --- /dev/null +++ b/t/t4013/diff.log_-SF_-p_master @@ -0,0 +1,18 @@ +$ git log -SF -p master +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +$ diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ new file mode 100644 index 0000000000..054513f312 --- /dev/null +++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ @@ -0,0 +1,59 @@ +$ git whatchanged --patch-with-stat --summary master -- dir/ +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +$ diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master new file mode 100644 index 0000000000..370b5810ee --- /dev/null +++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master @@ -0,0 +1,198 @@ +$ git whatchanged --root --cc --patch-with-stat --summary master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' +--- + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + + +diff --cc dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --cc file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master new file mode 100644 index 0000000000..d6404b11be --- /dev/null +++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master @@ -0,0 +1,198 @@ +$ git whatchanged --root -c --patch-with-stat --summary master +commit 176b998f5d647cbd77a9d8acf4531e930754d16d +Merge: 889b315... c7a2ab9... +Author: A U Thor +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' +--- + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + + +diff --combined dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --combined file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a +Author: A U Thor +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + create mode 100644 file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + create mode 100644 file1 + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +commit 7952a93e09bf565b5592766a438b40cd81f4846f +Author: A U Thor +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + delete mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 +++ + 3 files changed, 8 insertions(+), 0 deletions(-) + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 + +diff --git a/dir/sub b/dir/sub +new file mode 100644 +index 0000000..35d242b +--- /dev/null ++++ b/dir/sub +@@ -0,0 +1,2 @@ ++A ++B +diff --git a/file0 b/file0 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file0 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +diff --git a/file2 b/file2 +new file mode 100644 +index 0000000..01e79c3 +--- /dev/null ++++ b/file2 +@@ -0,0 +1,3 @@ ++1 ++2 ++3 +$ diff --git a/t/t4013/diff.whatchanged_-SF_-p_master b/t/t4013/diff.whatchanged_-SF_-p_master new file mode 100644 index 0000000000..6a76f4e604 --- /dev/null +++ b/t/t4013/diff.whatchanged_-SF_-p_master @@ -0,0 +1,18 @@ +$ git whatchanged -SF -p master +commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +Author: A U Thor +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +$ -- cgit v1.3-5-g9baa From 9e76bab14e50c46c624ae35f13c527a7a1b1185d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 27 Jun 2006 15:36:19 -0700 Subject: t4013 test updates for new output code. These are updates to the test vector that shows the "incompatibility" of the new output code. The changes are actually the good ones, so instead of keeping the older output we adjust the test to the new code. Signed-off-by: Junio C Hamano --- t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master | 1 - .../diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial | 1 - t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master | 3 +-- t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master | 3 +-- .../diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master | 3 +-- t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master | 3 +-- 6 files changed, 4 insertions(+), 10 deletions(-) (limited to 't') diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master index e6d0c80567..0ac9800913 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master @@ -4,7 +4,6 @@ $ git diff-tree --cc --patch-with-stat --summary master file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) - diff --cc dir/sub index cead32e,7289e35..992913c --- a/dir/sub diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial index 49e26fb99a..d5c333a378 100644 --- a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial @@ -1,6 +1,5 @@ $ git diff-tree --pretty=oneline --root --patch-with-stat initial 444ac553ac7612cc88969031b02b3767fb8a353a Initial ---- dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master index fafd9ee59e..b652c6a823 100644 --- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master @@ -5,12 +5,11 @@ Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' ---- + dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) - diff --cc dir/sub index cead32e,7289e35..992913c --- a/dir/sub diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master index 51e39cda00..3a155d288c 100644 --- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master @@ -5,12 +5,11 @@ Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' ---- + dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) - diff --combined dir/sub index cead32e,7289e35..992913c --- a/dir/sub diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master index 370b5810ee..e9e17cdafb 100644 --- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master @@ -5,12 +5,11 @@ Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' ---- + dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) - diff --cc dir/sub index cead32e,7289e35..992913c --- a/dir/sub diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master index d6404b11be..596765e804 100644 --- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master @@ -5,12 +5,11 @@ Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 Merge branch 'side' ---- + dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) - diff --combined dir/sub index cead32e,7289e35..992913c --- a/dir/sub -- cgit v1.3-5-g9baa From d410e43b35a8044472606a7e7018aa64d96a5f0f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 29 Jun 2006 00:01:07 -0700 Subject: t4013: add format-patch tests. Signed-off-by: Junio C Hamano --- t/t4013-diff-various.sh | 10 +- ....format-patch_--attach_--stdout_initial..master | 165 +++++++++++++++++++++ ...format-patch_--attach_--stdout_initial..master^ | 106 +++++++++++++ ...ff.format-patch_--attach_--stdout_initial..side | 60 ++++++++ t/t4013/diff.format-patch_--stdout_initial..master | 120 +++++++++++++++ .../diff.format-patch_--stdout_initial..master^ | 76 ++++++++++ t/t4013/diff.format-patch_--stdout_initial..side | 45 ++++++ 7 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_initial..master create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_initial..master^ create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_initial..side create mode 100644 t/t4013/diff.format-patch_--stdout_initial..master create mode 100644 t/t4013/diff.format-patch_--stdout_initial..master^ create mode 100644 t/t4013/diff.format-patch_--stdout_initial..side (limited to 't') diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 22984e3db7..f4f3c3a56d 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -85,6 +85,7 @@ test_expect_success setup ' +*+ [initial] Initial EOF +V=`git version | sed -e 's/^git version //'` while read cmd do case "$cmd" in @@ -99,7 +100,7 @@ do test_expect_success "git $cmd" ' { echo "\$ git $cmd" - git $cmd + git $cmd | sed -e "s/$V/g-i-t--v-e-r-s-i-o-n/" echo "\$" } >"$actual" && if test -f "$expect" @@ -219,6 +220,13 @@ show --patch-with-stat side show --patch-with-raw side show --patch-with-stat --summary side +format-patch --stdout initial..side +format-patch --stdout initial..master^ +format-patch --stdout initial..master +format-patch --attach --stdout initial..side +format-patch --attach --stdout initial..master^ +format-patch --attach --stdout initial..master + EOF test_done diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master new file mode 100644 index 0000000000..a89bbbbcfb --- /dev/null +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -0,0 +1,165 @@ +$ git format-patch --attach --stdout initial..master +From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:01:00 +0000 +Subject: [PATCH] Second +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; + name="7952a93e09bf565b5592766a438b40cd81f4846f.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; + filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:02:00 +0000 +Subject: [PATCH] Third +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; + name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; + filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH] Side +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; + name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; + filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ new file mode 100644 index 0000000000..4de9091a40 --- /dev/null +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -0,0 +1,106 @@ +$ git format-patch --attach --stdout initial..master^ +From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:01:00 +0000 +Subject: [PATCH] Second +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; + name="7952a93e09bf565b5592766a438b40cd81f4846f.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; + filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 + +--------------g-i-t--v-e-r-s-i-o-n-- + + + +From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:02:00 +0000 +Subject: [PATCH] Third +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; + name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; + filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side new file mode 100644 index 0000000000..3769fa6daf --- /dev/null +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side @@ -0,0 +1,60 @@ +$ git format-patch --attach --stdout initial..side +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH] Side +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------g-i-t--v-e-r-s-i-o-n" + +This is a multi-part message in MIME format. +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/plain; charset=UTF-8; format=fixed +Content-Transfer-Encoding: 8bit +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) +--------------g-i-t--v-e-r-s-i-o-n +Content-Type: text/x-patch; + name="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; + filename="c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a.diff" + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 + +--------------g-i-t--v-e-r-s-i-o-n-- + + +$ diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master new file mode 100644 index 0000000000..b7b4e7ca91 --- /dev/null +++ b/t/t4013/diff.format-patch_--stdout_initial..master @@ -0,0 +1,120 @@ +$ git format-patch --stdout initial..master +From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:01:00 +0000 +Subject: [PATCH] Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 +-- +g-i-t--v-e-r-s-i-o-n + + +From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:02:00 +0000 +Subject: [PATCH] Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C +-- +g-i-t--v-e-r-s-i-o-n + + +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH] Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +-- +g-i-t--v-e-r-s-i-o-n + +$ diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^ new file mode 100644 index 0000000000..e56dd98df3 --- /dev/null +++ b/t/t4013/diff.format-patch_--stdout_initial..master^ @@ -0,0 +1,76 @@ +$ git format-patch --stdout initial..master^ +From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:01:00 +0000 +Subject: [PATCH] Second +--- + dir/sub | 2 ++ + file0 | 3 +++ + file2 | 3 --- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..8422d40 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++C ++D +diff --git a/file0 b/file0 +index 01e79c3..b414108 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++4 ++5 ++6 +diff --git a/file2 b/file2 +deleted file mode 100644 +index 01e79c3..0000000 +--- a/file2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-1 +-2 +-3 +-- +g-i-t--v-e-r-s-i-o-n + + +From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:02:00 +0000 +Subject: [PATCH] Third +--- + dir/sub | 2 ++ + file1 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 8422d40..cead32e 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -2,3 +2,5 @@ A + B + C + D ++E ++F +diff --git a/file1 b/file1 +new file mode 100644 +index 0000000..b1e6722 +--- /dev/null ++++ b/file1 +@@ -0,0 +1,3 @@ ++A ++B ++C +-- +g-i-t--v-e-r-s-i-o-n + +$ diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side new file mode 100644 index 0000000000..e7ddbf4814 --- /dev/null +++ b/t/t4013/diff.format-patch_--stdout_initial..side @@ -0,0 +1,45 @@ +$ git format-patch --stdout initial..side +From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 +From: A U Thor +Date: Mon, 26 Jun 2006 00:03:00 +0000 +Subject: [PATCH] Side +--- + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +-- +g-i-t--v-e-r-s-i-o-n + +$ -- cgit v1.3-5-g9baa From 026625e78eaf8ea2ae960525c367b5e8f1629fd4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 29 Jun 2006 12:00:12 -0700 Subject: t4013: note improvements brought by the new output code. Signed-off-by: Junio C Hamano --- t/t4013-diff-various.sh | 18 ++++++++---- .../diff.diff-tree_--cc_--patch-with-stat_master | 34 ++++++++++++++++++++++ ....diff-tree_--pretty_--root_--summary_-r_initial | 11 +++++++ ...iff.diff-tree_--pretty_--root_--summary_initial | 11 +++++++ 4 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 t/t4013/diff.diff-tree_--cc_--patch-with-stat_master create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--summary_initial (limited to 't') diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index f4f3c3a56d..026832761f 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -138,7 +138,10 @@ diff-tree --pretty --summary initial diff-tree --pretty --stat --summary initial diff-tree --pretty --root -p initial diff-tree --pretty --root --stat initial -#diff-tree --pretty --root --summary initial +# improved by Timo's patch +diff-tree --pretty --root --summary initial +# improved by Timo's patch +diff-tree --pretty --root --summary -r initial diff-tree --pretty --root --stat --summary initial diff-tree --pretty --patch-with-stat initial diff-tree --pretty --root --patch-with-stat initial @@ -150,6 +153,7 @@ diff-tree --pretty=oneline --root initial diff-tree --pretty=oneline -p initial diff-tree --pretty=oneline --root -p initial diff-tree --pretty=oneline --patch-with-stat initial +# improved by Timo's patch diff-tree --pretty=oneline --root --patch-with-stat initial diff-tree --pretty=oneline --patch-with-raw initial diff-tree --pretty=oneline --root --patch-with-raw initial @@ -172,11 +176,9 @@ diff-tree --cc --stat --summary master # stat summary should show the diffstat and summary with the first parent diff-tree -c --stat --summary side diff-tree --cc --stat --summary side -# this one gives an extra newline after stat, which should be removed -# diff-tree --cc --patch-with-stat master -# this one gives an extra newline after stat, which should be removed -# other than that it shows the correct example -- stat and summary are -# against the first parent, and patch-looking combined diff follows. +# improved by Timo's patch +diff-tree --cc --patch-with-stat master +# improved by Timo's patch diff-tree --cc --patch-with-stat --summary master # this is correct diff-tree --cc --patch-with-stat --summary side @@ -188,7 +190,9 @@ log --root -p master log --patch-with-stat master log --root --patch-with-stat master log --root --patch-with-stat --summary master +# improved by Timo's patch log --root -c --patch-with-stat --summary master +# improved by Timo's patch log --root --cc --patch-with-stat --summary master log -SF master log -SF -p master @@ -200,7 +204,9 @@ whatchanged --root -p master whatchanged --patch-with-stat master whatchanged --root --patch-with-stat master whatchanged --root --patch-with-stat --summary master +# improved by Timo's patch whatchanged --root -c --patch-with-stat --summary master +# improved by Timo's patch whatchanged --root --cc --patch-with-stat --summary master whatchanged -SF master whatchanged -SF -p master diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master new file mode 100644 index 0000000000..f6ecf76366 --- /dev/null +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master @@ -0,0 +1,34 @@ +$ git diff-tree --cc --patch-with-stat master +176b998f5d647cbd77a9d8acf4531e930754d16d + dir/sub | 2 ++ + file0 | 3 +++ + 2 files changed, 5 insertions(+), 0 deletions(-) + +diff --cc dir/sub +index cead32e,7289e35..992913c +--- a/dir/sub ++++ b/dir/sub +@@@ -1,6 -1,4 +1,8 @@@ + A + B + +C + +D + +E + +F ++ 1 ++ 2 +diff --cc file0 +index b414108,f4615da..10a8a9f +--- a/file0 ++++ b/file0 +@@@ -1,6 -1,6 +1,9 @@@ + 1 + 2 + 3 + +4 + +5 + +6 ++ A ++ B ++ C +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial b/t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial new file mode 100644 index 0000000000..ccdaafb377 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial @@ -0,0 +1,11 @@ +$ git diff-tree --pretty --root --summary -r initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + + create mode 100644 dir/sub + create mode 100644 file0 + create mode 100644 file2 +$ diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--summary_initial new file mode 100644 index 0000000000..ea48205537 --- /dev/null +++ b/t/t4013/diff.diff-tree_--pretty_--root_--summary_initial @@ -0,0 +1,11 @@ +$ git diff-tree --pretty --root --summary initial +commit 444ac553ac7612cc88969031b02b3767fb8a353a +Author: A U Thor +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial + + create mode 040000 dir + create mode 100644 file0 + create mode 100644 file2 +$ -- cgit v1.3-5-g9baa From b319b02e2a75bfe71829cfe1506b86ec7644987d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 1 Jul 2006 22:02:17 -0700 Subject: t4013: add "diff" UI program tests. Signed-off-by: Junio C Hamano --- t/t4013-diff-various.sh | 9 ++++++ t/t4013/diff.diff_--abbrev_initial..side | 32 +++++++++++++++++++ .../diff.diff_--patch-with-raw_-r_initial..side | 36 +++++++++++++++++++++ t/t4013/diff.diff_--patch-with-raw_initial..side | 36 +++++++++++++++++++++ .../diff.diff_--patch-with-stat_-r_initial..side | 37 ++++++++++++++++++++++ t/t4013/diff.diff_--patch-with-stat_initial..side | 37 ++++++++++++++++++++++ t/t4013/diff.diff_--stat_initial..side | 6 ++++ t/t4013/diff.diff_-r_--stat_initial..side | 6 ++++ t/t4013/diff.diff_-r_initial..side | 32 +++++++++++++++++++ t/t4013/diff.diff_initial..side | 32 +++++++++++++++++++ 10 files changed, 263 insertions(+) create mode 100644 t/t4013/diff.diff_--abbrev_initial..side create mode 100644 t/t4013/diff.diff_--patch-with-raw_-r_initial..side create mode 100644 t/t4013/diff.diff_--patch-with-raw_initial..side create mode 100644 t/t4013/diff.diff_--patch-with-stat_-r_initial..side create mode 100644 t/t4013/diff.diff_--patch-with-stat_initial..side create mode 100644 t/t4013/diff.diff_--stat_initial..side create mode 100644 t/t4013/diff.diff_-r_--stat_initial..side create mode 100644 t/t4013/diff.diff_-r_initial..side create mode 100644 t/t4013/diff.diff_initial..side (limited to 't') diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index f4f3c3a56d..1d2f7f9f7d 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -227,6 +227,15 @@ format-patch --attach --stdout initial..side format-patch --attach --stdout initial..master^ format-patch --attach --stdout initial..master +diff --abbrev initial..side +diff -r initial..side +diff --stat initial..side +diff -r --stat initial..side +diff initial..side +diff --patch-with-stat initial..side +diff --patch-with-raw initial..side +diff --patch-with-stat -r initial..side +diff --patch-with-raw -r initial..side EOF test_done diff --git a/t/t4013/diff.diff_--abbrev_initial..side b/t/t4013/diff.diff_--abbrev_initial..side new file mode 100644 index 0000000000..a88e66f817 --- /dev/null +++ b/t/t4013/diff.diff_--abbrev_initial..side @@ -0,0 +1,32 @@ +$ git diff --abbrev initial..side +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff_--patch-with-raw_-r_initial..side b/t/t4013/diff.diff_--patch-with-raw_-r_initial..side new file mode 100644 index 0000000000..3590dc79a6 --- /dev/null +++ b/t/t4013/diff.diff_--patch-with-raw_-r_initial..side @@ -0,0 +1,36 @@ +$ git diff --patch-with-raw -r initial..side +:100644 100644 35d242b... 7289e35... M dir/sub +:100644 100644 01e79c3... f4615da... M file0 +:000000 100644 0000000... 7289e35... A file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff_--patch-with-raw_initial..side b/t/t4013/diff.diff_--patch-with-raw_initial..side new file mode 100644 index 0000000000..b21d5dc6f3 --- /dev/null +++ b/t/t4013/diff.diff_--patch-with-raw_initial..side @@ -0,0 +1,36 @@ +$ git diff --patch-with-raw initial..side +:100644 100644 35d242b... 7289e35... M dir/sub +:100644 100644 01e79c3... f4615da... M file0 +:000000 100644 0000000... 7289e35... A file3 + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side new file mode 100644 index 0000000000..9ed317a198 --- /dev/null +++ b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side @@ -0,0 +1,37 @@ +$ git diff --patch-with-stat -r initial..side + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff_--patch-with-stat_initial..side b/t/t4013/diff.diff_--patch-with-stat_initial..side new file mode 100644 index 0000000000..8b50629e66 --- /dev/null +++ b/t/t4013/diff.diff_--patch-with-stat_initial..side @@ -0,0 +1,37 @@ +$ git diff --patch-with-stat initial..side + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) + +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff_--stat_initial..side b/t/t4013/diff.diff_--stat_initial..side new file mode 100644 index 0000000000..0517b5d631 --- /dev/null +++ b/t/t4013/diff.diff_--stat_initial..side @@ -0,0 +1,6 @@ +$ git diff --stat initial..side + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.diff_-r_--stat_initial..side b/t/t4013/diff.diff_-r_--stat_initial..side new file mode 100644 index 0000000000..245220d3f9 --- /dev/null +++ b/t/t4013/diff.diff_-r_--stat_initial..side @@ -0,0 +1,6 @@ +$ git diff -r --stat initial..side + dir/sub | 2 ++ + file0 | 3 +++ + file3 | 4 ++++ + 3 files changed, 9 insertions(+), 0 deletions(-) +$ diff --git a/t/t4013/diff.diff_-r_initial..side b/t/t4013/diff.diff_-r_initial..side new file mode 100644 index 0000000000..5bb2fe2f28 --- /dev/null +++ b/t/t4013/diff.diff_-r_initial..side @@ -0,0 +1,32 @@ +$ git diff -r initial..side +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ diff --git a/t/t4013/diff.diff_initial..side b/t/t4013/diff.diff_initial..side new file mode 100644 index 0000000000..c8adaf5958 --- /dev/null +++ b/t/t4013/diff.diff_initial..side @@ -0,0 +1,32 @@ +$ git diff initial..side +diff --git a/dir/sub b/dir/sub +index 35d242b..7289e35 100644 +--- a/dir/sub ++++ b/dir/sub +@@ -1,2 +1,4 @@ + A + B ++1 ++2 +diff --git a/file0 b/file0 +index 01e79c3..f4615da 100644 +--- a/file0 ++++ b/file0 +@@ -1,3 +1,6 @@ + 1 + 2 + 3 ++A ++B ++C +diff --git a/file3 b/file3 +new file mode 100644 +index 0000000..7289e35 +--- /dev/null ++++ b/file3 +@@ -0,0 +1,4 @@ ++A ++B ++1 ++2 +$ -- cgit v1.3-5-g9baa From f560069bc59e155c3078ba5482ce69ded68849df Mon Sep 17 00:00:00 2001 From: Ryan Anderson Date: Mon, 3 Jul 2006 21:30:01 -0400 Subject: annotate: Support annotation of files on other revisions. This is a bug fix, and cleans up one or two other things spotted during the course of tracking down the main bug here. Also, the test-suite is updated to reflect this case. Signed-off-by: Ryan Anderson (cherry picked from 2f7554b4db3ab2c2d3866b160245c91c9236fc9a commit) Signed-off-by: Junio C Hamano --- t/t8001-annotate.sh | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 't') diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh index 2496397da3..70e2ad23ae 100755 --- a/t/t8001-annotate.sh +++ b/t/t8001-annotate.sh @@ -6,4 +6,10 @@ test_description='git-annotate' PROG='git annotate' . ../annotate-tests.sh +test_expect_success \ + 'Annotating an old revision works' \ + '[ $(git annotate file master | awk "{print \$3}" | grep -c "^A$") == 2 ] && \ + [ $(git annotate file master | awk "{print \$3}" | grep -c "^B$") == 2 ]' + + test_done -- cgit v1.3-5-g9baa From 280242d1cc1fe2847f649d2f16b273e168fcbc48 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 2 Jul 2006 16:03:59 -0700 Subject: send-email: do not barf when Term::ReadLine does not like your terminal As long as we do not need to readline from the terminal, we should not barf when starting up the program. Without this patch, t9001 test on Cygwin occasionally died with the following error message: Unable to get Terminal Size. The TIOCGWINSZ ioctl didn't work. The COLUMNS and LINES environment variables didn't work. The resize program didn't work. at /usr/lib/perl5/vendor_perl/5.8/cygwin/Term/ReadKey.pm line 362. Compilation failed in require at /usr/lib/perl5/vendor_perl/5.8/Term/ReadLine/Perl.pm line 58. Acked-by: Ryan Anderson Signed-off-by: Junio C Hamano --- git-send-email.perl | 18 +++++++++++++++++- t/t9001-send-email.sh | 11 +++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) (limited to 't') diff --git a/git-send-email.perl b/git-send-email.perl index c5d9e73351..b04b8f40e9 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -22,6 +22,17 @@ use Term::ReadLine; use Getopt::Long; use Data::Dumper; +package FakeTerm; +sub new { + my ($class, $reason) = @_; + return bless \$reason, shift; +} +sub readline { + my $self = shift; + die "Cannot use readline on FakeTerm: $$self"; +} +package main; + # most mail servers generate the Date: header, but not all... $ENV{LC_ALL} = 'C'; use POSIX qw/strftime/; @@ -46,7 +57,12 @@ my $smtp_server; # Example reply to: #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>'; -my $term = new Term::ReadLine 'git-send-email'; +my $term = eval { + new Term::ReadLine 'git-send-email'; +}; +if ($@) { + $term = new FakeTerm "$@: going non-interactive"; +} # Begin by accumulating all the variables (defined above), that we will end up # needing, first, from the command line: diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index a61da1efbd..e9ea33c18d 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -25,10 +25,13 @@ test_expect_success \ git add fake.sendmail GIT_AUTHOR_NAME="A" git commit -a -m "Second."' -test_expect_success \ - 'Extract patches and send' \ - 'git format-patch -n HEAD^1 - git send-email -from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" ./0001*txt' +test_expect_success 'Extract patches' ' + patches=`git format-patch -n HEAD^1` +' + +test_expect_success 'Send patches' ' + git send-email -from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors +' cat >expected <<\EOF !nobody@example.com! -- cgit v1.3-5-g9baa From 30a95f30730a5ee738ad6ef17e76e61ad7c1f53e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 3 Jul 2006 18:09:54 -0700 Subject: t6200: fmt-merge-msg test. Signed-off-by: Junio C Hamano --- t/t6200-fmt-merge-msg.sh | 163 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100755 t/t6200-fmt-merge-msg.sh (limited to 't') diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh new file mode 100755 index 0000000000..63e49f310c --- /dev/null +++ b/t/t6200-fmt-merge-msg.sh @@ -0,0 +1,163 @@ +#!/bin/sh +# +# Copyright (c) 2006, Junio C Hamano +# + +test_description='fmt-merge-msg test' + +. ./test-lib.sh + +datestamp=1151939923 +setdate () { + GIT_COMMITTER_DATE="$datestamp +0200" + GIT_AUTHOR_DATE="$datestamp +0200" + datestamp=`expr "$datestamp" + 1` + export GIT_COMMITTER_DATE GIT_AUTHOR_DATE +} + +test_expect_success setup ' + echo one >one && + git add one && + setdate && + git commit -m "Initial" && + + echo uno >one && + echo dos >two && + git add two && + setdate && + git commit -a -m "Second" && + + git checkout -b left && + + echo $datestamp >one && + setdate && + git commit -a -m "Common #1" && + + echo $datestamp >one && + setdate && + git commit -a -m "Common #2" && + + git branch right && + + echo $datestamp >two && + setdate && + git commit -a -m "Left #3" && + + echo $datestamp >two && + setdate && + git commit -a -m "Left #4" && + + echo $datestamp >two && + setdate && + git commit -a -m "Left #5" && + + git checkout right && + + echo $datestamp >three && + git add three && + setdate && + git commit -a -m "Right #3" && + + echo $datestamp >three && + setdate && + git commit -a -m "Right #4" && + + echo $datestamp >three && + setdate && + git commit -a -m "Right #5" && + + git show-branch +' + +cat >expected <<\EOF +Merge branch 'left' +EOF + +test_expect_success 'merge-msg test #1' ' + + git checkout master && + git fetch . left && + + git fmt-merge-msg <.git/FETCH_HEAD >actual && + diff -u actual expected +' + +cat >expected <<\EOF +Merge branch 'left' of ../trash +EOF + +test_expect_success 'merge-msg test #2' ' + + git checkout master && + git fetch ../trash left && + + git fmt-merge-msg <.git/FETCH_HEAD >actual && + diff -u actual expected +' + +cat >expected <<\EOF +Merge branch 'left' + +* left: + Left #5 + Left #4 + Left #3 + Common #2 + Common #1 +EOF + +test_expect_success 'merge-msg test #3' ' + + git repo-config merge.summary true && + + git checkout master && + setdate && + git fetch . left && + + git fmt-merge-msg <.git/FETCH_HEAD >actual && + diff -u actual expected +' + +cat >expected <<\EOF +Merge branches 'left' and 'right' + +* left: + Left #5 + Left #4 + Left #3 + Common #2 + Common #1 + +* right: + Right #5 + Right #4 + Right #3 + Common #2 + Common #1 +EOF + +test_expect_success 'merge-msg test #4' ' + + git repo-config merge.summary true && + + git checkout master && + setdate && + git fetch . left right && + + git fmt-merge-msg <.git/FETCH_HEAD >actual && + diff -u actual expected +' + +test_expect_success 'merge-msg test #5' ' + + git repo-config merge.summary yes && + + git checkout master && + setdate && + git fetch . left right && + + git fmt-merge-msg <.git/FETCH_HEAD >actual && + diff -u actual expected +' + +test_done -- cgit v1.3-5-g9baa From 4d62eaabeb283d6dab56cfb2f2e54144b98afafd Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 4 Jul 2006 01:04:24 -0700 Subject: t8001-annotate: fix a bash-ism in this test Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- t/t8001-annotate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 't') diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh index 70e2ad23ae..3a6490e8f8 100755 --- a/t/t8001-annotate.sh +++ b/t/t8001-annotate.sh @@ -8,8 +8,8 @@ PROG='git annotate' test_expect_success \ 'Annotating an old revision works' \ - '[ $(git annotate file master | awk "{print \$3}" | grep -c "^A$") == 2 ] && \ - [ $(git annotate file master | awk "{print \$3}" | grep -c "^B$") == 2 ]' + '[ $(git annotate file master | awk "{print \$3}" | grep -c "^A$") -eq 2 ] && \ + [ $(git annotate file master | awk "{print \$3}" | grep -c "^B$") -eq 2 ]' test_done -- cgit v1.3-5-g9baa From 60d02ccc18408e54ace8692532fcc73d4035b3c2 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 6 Jul 2006 00:14:16 -0700 Subject: git-svn: migrate out of contrib Allow NO_SVN_TESTS to be defined to skip git-svn tests. These tests are time-consuming due to SVN being slow, and even more so if SVN Perl libraries are not available. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- .gitignore | 1 + Documentation/git-svn.txt | 319 ++ Makefile | 6 +- contrib/git-svn/.gitignore | 4 - contrib/git-svn/Makefile | 44 - contrib/git-svn/git-svn.perl | 3378 ---------------------- contrib/git-svn/git-svn.txt | 319 -- contrib/git-svn/t/lib-git-svn.sh | 45 - contrib/git-svn/t/t0000-contrib-git-svn.sh | 232 -- contrib/git-svn/t/t0001-contrib-git-svn-props.sh | 126 - contrib/git-svn/t/t0002-deep-rmdir.sh | 29 - contrib/git-svn/t/t0003-graft-branches.sh | 63 - contrib/git-svn/t/t0004-follow-parent.sh | 44 - contrib/git-svn/t/t0005-commit-diff.sh | 41 - git-svn.perl | 3378 ++++++++++++++++++++++ t/Makefile | 10 + t/lib-git-svn.sh | 43 + t/t9100-git-svn-basic.sh | 234 ++ t/t9101-git-svn-props.sh | 126 + t/t9102-git-svn-deep-rmdir.sh | 29 + t/t9103-git-svn-graft-branches.sh | 63 + t/t9104-git-svn-follow-parent.sh | 44 + t/t9105-git-svn-commit-diff.sh | 41 + 23 files changed, 4293 insertions(+), 4326 deletions(-) create mode 100644 Documentation/git-svn.txt delete mode 100644 contrib/git-svn/.gitignore delete mode 100644 contrib/git-svn/Makefile delete mode 100755 contrib/git-svn/git-svn.perl delete mode 100644 contrib/git-svn/git-svn.txt delete mode 100644 contrib/git-svn/t/lib-git-svn.sh delete mode 100644 contrib/git-svn/t/t0000-contrib-git-svn.sh delete mode 100644 contrib/git-svn/t/t0001-contrib-git-svn-props.sh delete mode 100644 contrib/git-svn/t/t0002-deep-rmdir.sh delete mode 100644 contrib/git-svn/t/t0003-graft-branches.sh delete mode 100644 contrib/git-svn/t/t0004-follow-parent.sh delete mode 100644 contrib/git-svn/t/t0005-commit-diff.sh create mode 100755 git-svn.perl create mode 100644 t/lib-git-svn.sh create mode 100755 t/t9100-git-svn-basic.sh create mode 100755 t/t9101-git-svn-props.sh create mode 100755 t/t9102-git-svn-deep-rmdir.sh create mode 100755 t/t9103-git-svn-graft-branches.sh create mode 100755 t/t9104-git-svn-follow-parent.sh create mode 100755 t/t9105-git-svn-commit-diff.sh (limited to 't') diff --git a/.gitignore b/.gitignore index 2bcc604afe..52d61f3193 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,7 @@ git-ssh-push git-ssh-upload git-status git-stripspace +git-svn git-svnimport git-symbolic-ref git-tag diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt new file mode 100644 index 0000000000..f7d3de48f0 --- /dev/null +++ b/Documentation/git-svn.txt @@ -0,0 +1,319 @@ +git-svn(1) +========== + +NAME +---- +git-svn - bidirectional operation between a single Subversion branch and git + +SYNOPSIS +-------- +'git-svn' [options] [arguments] + +DESCRIPTION +----------- +git-svn is a simple conduit for changesets between a single Subversion +branch and git. + +git-svn is not to be confused with git-svnimport. The were designed +with very different goals in mind. + +git-svn is designed for an individual developer who wants a +bidirectional flow of changesets between a single branch in Subversion +and an arbitrary number of branches in git. git-svnimport is designed +for read-only operation on repositories that match a particular layout +(albeit the recommended one by SVN developers). + +For importing svn, git-svnimport is potentially more powerful when +operating on repositories organized under the recommended +trunk/branch/tags structure, and should be faster, too. + +git-svn mostly ignores the very limited view of branching that +Subversion has. This allows git-svn to be much easier to use, +especially on repositories that are not organized in a manner that +git-svnimport is designed for. + +COMMANDS +-------- +init:: + Creates an empty git repository with additional metadata + directories for git-svn. The Subversion URL must be specified + as a command-line argument. + +fetch:: + Fetch unfetched revisions from the Subversion URL we are + tracking. refs/remotes/git-svn will be updated to the + latest revision. + + Note: You should never attempt to modify the remotes/git-svn + branch outside of git-svn. Instead, create a branch from + remotes/git-svn and work on that branch. Use the 'commit' + command (see below) to write git commits back to + remotes/git-svn. + + See 'Additional Fetch Arguments' if you are interested in + manually joining branches on commit. + +commit:: + Commit specified commit or tree objects to SVN. This relies on + your imported fetch data being up-to-date. This makes + absolutely no attempts to do patching when committing to SVN, it + simply overwrites files with those specified in the tree or + commit. All merging is assumed to have taken place + independently of git-svn functions. + +rebuild:: + Not a part of daily usage, but this is a useful command if + you've just cloned a repository (using git-clone) that was + tracked with git-svn. Unfortunately, git-clone does not clone + git-svn metadata and the svn working tree that git-svn uses for + its operations. This rebuilds the metadata so git-svn can + resume fetch operations. A Subversion URL may be optionally + specified at the command-line if the directory/repository you're + tracking has moved or changed protocols. + +show-ignore:: + Recursively finds and lists the svn:ignore property on + directories. The output is suitable for appending to + the $GIT_DIR/info/exclude file. + +OPTIONS +------- +-r :: +--revision :: + Only used with the 'fetch' command. + + Takes any valid -r svn would accept and passes it + directly to svn. -r: ranges and "{" DATE "}" syntax + is also supported. This is passed directly to svn, see svn + documentation for more details. + + This can allow you to make partial mirrors when running fetch. + +-:: +--stdin:: + Only used with the 'commit' command. + + Read a list of commits from stdin and commit them in reverse + order. Only the leading sha1 is read from each line, so + git-rev-list --pretty=oneline output can be used. + +--rmdir:: + Only used with the 'commit' command. + + Remove directories from the SVN tree if there are no files left + behind. SVN can version empty directories, and they are not + removed by default if there are no files left in them. git + cannot version empty directories. Enabling this flag will make + the commit to SVN act like git. + + repo-config key: svn.rmdir + +-e:: +--edit:: + Only used with the 'commit' command. + + Edit the commit message before committing to SVN. This is off by + default for objects that are commits, and forced on when committing + tree objects. + + repo-config key: svn.edit + +-l:: +--find-copies-harder:: + Both of these are only used with the 'commit' command. + + They are both passed directly to git-diff-tree see + git-diff-tree(1) for more information. + + repo-config key: svn.l + repo-config key: svn.findcopiesharder + +-A:: +--authors-file=:: + + Syntax is compatible with the files used by git-svnimport and + git-cvsimport: + +------------------------------------------------------------------------ +loginname = Joe User +------------------------------------------------------------------------ + + If this option is specified and git-svn encounters an SVN + committer name that does not exist in the authors-file, git-svn + will abort operation. The user will then have to add the + appropriate entry. Re-running the previous git-svn command + after the authors-file is modified should continue operation. + + repo-config key: svn.authors-file + +ADVANCED OPTIONS +---------------- +-b:: +--branch :: + Used with 'fetch' or 'commit'. + + This can be used to join arbitrary git branches to remotes/git-svn + on new commits where the tree object is equivalent. + + When used with different GIT_SVN_ID values, tags and branches in + SVN can be tracked this way, as can some merges where the heads + end up having completely equivalent content. This can even be + used to track branches across multiple SVN _repositories_. + + This option may be specified multiple times, once for each + branch. + + repo-config key: svn.branch + +-i:: +--id :: + This sets GIT_SVN_ID (instead of using the environment). See + the section on "Tracking Multiple Repositories or Branches" for + more information on using GIT_SVN_ID. + +COMPATIBILITY OPTIONS +--------------------- +--upgrade:: + Only used with the 'rebuild' command. + + Run this if you used an old version of git-svn that used + "git-svn-HEAD" instead of "remotes/git-svn" as the branch + for tracking the remote. + +--no-ignore-externals:: + Only used with the 'fetch' and 'rebuild' command. + + By default, git-svn passes --ignore-externals to svn to avoid + fetching svn:external trees into git. Pass this flag to enable + externals tracking directly via git. + + Versions of svn that do not support --ignore-externals are + automatically detected and this flag will be automatically + enabled for them. + + Otherwise, do not enable this flag unless you know what you're + doing. + + repo-config key: svn.noignoreexternals + +Basic Examples +~~~~~~~~~~~~~~ + +Tracking and contributing to an Subversion managed-project: + +------------------------------------------------------------------------ +# Initialize a tree (like git init-db): + git-svn init http://svn.foo.org/project/trunk +# Fetch remote revisions: + git-svn fetch +# Create your own branch to hack on: + git checkout -b my-branch remotes/git-svn +# Commit only the git commits you want to SVN: + git-svn commit [ ...] +# Commit all the git commits from my-branch that don't exist in SVN: + git-svn commit remotes/git-svn..my-branch +# Something is committed to SVN, pull the latest into your branch: + git-svn fetch && git pull . remotes/git-svn +# Append svn:ignore settings to the default git exclude file: + git-svn show-ignore >> .git/info/exclude +------------------------------------------------------------------------ + +DESIGN PHILOSOPHY +----------------- +Merge tracking in Subversion is lacking and doing branched development +with Subversion is cumbersome as a result. git-svn completely forgoes +any automated merge/branch tracking on the Subversion side and leaves it +entirely up to the user on the git side. It's simply not worth it to do +a useful translation when the the original signal is weak. + +TRACKING MULTIPLE REPOSITORIES OR BRANCHES +------------------------------------------ +This is for advanced users, most users should ignore this section. + +Because git-svn does not care about relationships between different +branches or directories in a Subversion repository, git-svn has a simple +hack to allow it to track an arbitrary number of related _or_ unrelated +SVN repositories via one git repository. Simply set the GIT_SVN_ID +environment variable to a name other other than "git-svn" (the default) +and git-svn will ignore the contents of the $GIT_DIR/git-svn directory +and instead do all of its work in $GIT_DIR/$GIT_SVN_ID for that +invocation. The interface branch will be remotes/$GIT_SVN_ID, instead of +remotes/git-svn. Any remotes/$GIT_SVN_ID branch should never be modified +by the user outside of git-svn commands. + +ADDITIONAL FETCH ARGUMENTS +-------------------------- +This is for advanced users, most users should ignore this section. + +Unfetched SVN revisions may be imported as children of existing commits +by specifying additional arguments to 'fetch'. Additional parents may +optionally be specified in the form of sha1 hex sums at the +command-line. Unfetched SVN revisions may also be tied to particular +git commits with the following syntax: + + svn_revision_number=git_commit_sha1 + +This allows you to tie unfetched SVN revision 375 to your current HEAD:: + + `git-svn fetch 375=$(git-rev-parse HEAD)` + +Advanced Example: Tracking a Reorganized Repository +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you're tracking a directory that has moved, or otherwise been +branched or tagged off of another directory in the repository and you +care about the full history of the project, then you can read this +section. + +This is how Yann Dirson tracked the trunk of the ufoai directory when +the /trunk directory of his repository was moved to /ufoai/trunk and +he needed to continue tracking /ufoai/trunk where /trunk left off. + +------------------------------------------------------------------------ + # This log message shows when the repository was reorganized: + r166 | ydirson | 2006-03-02 01:36:55 +0100 (Thu, 02 Mar 2006) | 1 line + Changed paths: + D /trunk + A /ufoai/trunk (from /trunk:165) + + # First we start tracking the old revisions: + GIT_SVN_ID=git-oldsvn git-svn init \ + https://svn.sourceforge.net/svnroot/ufoai/trunk + GIT_SVN_ID=git-oldsvn git-svn fetch -r1:165 + + # And now, we continue tracking the new revisions: + GIT_SVN_ID=git-newsvn git-svn init \ + https://svn.sourceforge.net/svnroot/ufoai/ufoai/trunk + GIT_SVN_ID=git-newsvn git-svn fetch \ + 166=`git-rev-parse refs/remotes/git-oldsvn` +------------------------------------------------------------------------ + +BUGS +---- +If somebody commits a conflicting changeset to SVN at a bad moment +(right before you commit) causing a conflict and your commit to fail, +your svn working tree ($GIT_DIR/git-svn/tree) may be dirtied. The +easiest thing to do is probably just to rm -rf $GIT_DIR/git-svn/tree and +run 'rebuild'. + +We ignore all SVN properties except svn:executable. Too difficult to +map them since we rely heavily on git write-tree being _exactly_ the +same on both the SVN and git working trees and I prefer not to clutter +working trees with metadata files. + +svn:keywords can't be ignored in Subversion (at least I don't know of +a way to ignore them). + +Renamed and copied directories are not detected by git and hence not +tracked when committing to SVN. I do not plan on adding support for +this as it's quite difficult and time-consuming to get working for all +the possible corner cases (git doesn't do it, either). Renamed and +copied files are fully supported if they're similar enough for git to +detect them. + +Author +------ +Written by Eric Wong . + +Documentation +------------- +Written by Eric Wong . diff --git a/Makefile b/Makefile index 202f26171a..a0e90c012f 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,10 @@ all: # Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. # Enable it on Windows. By default, symrefs are still used. # +# Define NO_SVN_TESTS if you want to skip time-consuming SVN interopability +# tests. These tests take up a significant amount of the total test time +# but are not needed unless you plan to talk to SVN repos. +# # Define PPC_SHA1 environment variable when running make to make use of # a bundled SHA1 routine optimized for PowerPC. # @@ -134,7 +138,7 @@ SCRIPT_PERL = \ git-shortlog.perl git-rerere.perl \ git-annotate.perl git-cvsserver.perl \ git-svnimport.perl git-mv.perl git-cvsexportcommit.perl \ - git-send-email.perl + git-send-email.perl git-svn.perl SCRIPT_PYTHON = \ git-merge-recursive.py diff --git a/contrib/git-svn/.gitignore b/contrib/git-svn/.gitignore deleted file mode 100644 index d8d87e3af9..0000000000 --- a/contrib/git-svn/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -git-svn -git-svn.xml -git-svn.html -git-svn.1 diff --git a/contrib/git-svn/Makefile b/contrib/git-svn/Makefile deleted file mode 100644 index 7c20946943..0000000000 --- a/contrib/git-svn/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -all: git-svn - -prefix?=$(HOME) -bindir=$(prefix)/bin -mandir=$(prefix)/man -man1=$(mandir)/man1 -INSTALL?=install -doc_conf=../../Documentation/asciidoc.conf --include ../../config.mak - -git-svn: git-svn.perl - cp $< $@ - chmod +x $@ - -install: all - $(INSTALL) -d -m755 $(DESTDIR)$(bindir) - $(INSTALL) git-svn $(DESTDIR)$(bindir) - -install-doc: doc - $(INSTALL) git-svn.1 $(DESTDIR)$(man1) - -doc: git-svn.1 -git-svn.1 : git-svn.xml - xmlto man git-svn.xml -git-svn.xml : git-svn.txt - asciidoc -b docbook -d manpage \ - -f ../../Documentation/asciidoc.conf $< -git-svn.html : git-svn.txt - asciidoc -b xhtml11 -d manpage \ - -f ../../Documentation/asciidoc.conf $< -test: git-svn - cd t && for i in t????-*.sh; do $(SHELL) ./$$i $(TEST_FLAGS); done - -# we can test NO_OPTIMIZE_COMMITS independently of LC_ALL -full-test: - $(MAKE) test GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C - $(MAKE) test GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C - $(MAKE) test GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \ - LC_ALL=en_US.UTF-8 - $(MAKE) test GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \ - LC_ALL=en_US.UTF-8 - -clean: - rm -f git-svn *.xml *.html *.1 diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl deleted file mode 100755 index 8bc4188e03..0000000000 --- a/contrib/git-svn/git-svn.perl +++ /dev/null @@ -1,3378 +0,0 @@ -#!/usr/bin/env perl -# Copyright (C) 2006, Eric Wong -# License: GPL v2 or later -use warnings; -use strict; -use vars qw/ $AUTHOR $VERSION - $SVN_URL $SVN_INFO $SVN_WC $SVN_UUID - $GIT_SVN_INDEX $GIT_SVN - $GIT_DIR $GIT_SVN_DIR $REVDB/; -$AUTHOR = 'Eric Wong '; -$VERSION = '1.1.1-broken'; - -use Cwd qw/abs_path/; -$GIT_DIR = abs_path($ENV{GIT_DIR} || '.git'); -$ENV{GIT_DIR} = $GIT_DIR; - -my $LC_ALL = $ENV{LC_ALL}; -my $TZ = $ENV{TZ}; -# make sure the svn binary gives consistent output between locales and TZs: -$ENV{TZ} = 'UTC'; -$ENV{LC_ALL} = 'C'; -$| = 1; # unbuffer STDOUT - -# If SVN:: library support is added, please make the dependencies -# optional and preserve the capability to use the command-line client. -# use eval { require SVN::... } to make it lazy load -# We don't use any modules not in the standard Perl distribution: -use Carp qw/croak/; -use IO::File qw//; -use File::Basename qw/dirname basename/; -use File::Path qw/mkpath/; -use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev pass_through/; -use File::Spec qw//; -use POSIX qw/strftime/; -use IPC::Open3; -use Memoize; -memoize('revisions_eq'); -memoize('cmt_metadata'); -memoize('get_commit_time'); - -my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib); -$_use_lib = 1 unless $ENV{GIT_SVN_NO_LIB}; -libsvn_load(); -my $_optimize_commits = 1 unless $ENV{GIT_SVN_NO_OPTIMIZE_COMMITS}; -my $sha1 = qr/[a-f\d]{40}/; -my $sha1_short = qr/[a-f\d]{4,40}/; -my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit, - $_find_copies_harder, $_l, $_cp_similarity, $_cp_remote, - $_repack, $_repack_nr, $_repack_flags, $_q, - $_message, $_file, $_follow_parent, $_no_metadata, - $_template, $_shared, $_no_default_regex, $_no_graft_copy, - $_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit, - $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m); -my (@_branch_from, %tree_map, %users, %rusers, %equiv); -my ($_svn_co_url_revs, $_svn_pg_peg_revs); -my @repo_path_split_cache; - -my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext, - 'branch|b=s' => \@_branch_from, - 'follow-parent|follow' => \$_follow_parent, - 'branch-all-refs|B' => \$_branch_all_refs, - 'authors-file|A=s' => \$_authors, - 'repack:i' => \$_repack, - 'no-metadata' => \$_no_metadata, - 'quiet|q' => \$_q, - 'repack-flags|repack-args|repack-opts=s' => \$_repack_flags); - -my ($_trunk, $_tags, $_branches); -my %multi_opts = ( 'trunk|T=s' => \$_trunk, - 'tags|t=s' => \$_tags, - 'branches|b=s' => \$_branches ); -my %init_opts = ( 'template=s' => \$_template, 'shared' => \$_shared ); -my %cmt_opts = ( 'edit|e' => \$_edit, - 'rmdir' => \$_rmdir, - 'find-copies-harder' => \$_find_copies_harder, - 'l=i' => \$_l, - 'copy-similarity|C=i'=> \$_cp_similarity -); - -# yes, 'native' sets "\n". Patches to fix this for non-*nix systems welcome: -my %EOL = ( CR => "\015", LF => "\012", CRLF => "\015\012", native => "\012" ); - -my %cmd = ( - fetch => [ \&fetch, "Download new revisions from SVN", - { 'revision|r=s' => \$_revision, %fc_opts } ], - init => [ \&init, "Initialize a repo for tracking" . - " (requires URL argument)", - \%init_opts ], - commit => [ \&commit, "Commit git revisions to SVN", - { 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ], - 'show-ignore' => [ \&show_ignore, "Show svn:ignore listings", - { 'revision|r=i' => \$_revision } ], - rebuild => [ \&rebuild, "Rebuild git-svn metadata (after git clone)", - { 'no-ignore-externals' => \$_no_ignore_ext, - 'copy-remote|remote=s' => \$_cp_remote, - 'upgrade' => \$_upgrade } ], - 'graft-branches' => [ \&graft_branches, - 'Detect merges/branches from already imported history', - { 'merge-rx|m' => \@_opt_m, - 'branch|b=s' => \@_branch_from, - 'branch-all-refs|B' => \$_branch_all_refs, - 'no-default-regex' => \$_no_default_regex, - 'no-graft-copy' => \$_no_graft_copy } ], - 'multi-init' => [ \&multi_init, - 'Initialize multiple trees (like git-svnimport)', - { %multi_opts, %fc_opts } ], - 'multi-fetch' => [ \&multi_fetch, - 'Fetch multiple trees (like git-svnimport)', - \%fc_opts ], - 'log' => [ \&show_log, 'Show commit logs', - { 'limit=i' => \$_limit, - 'revision|r=s' => \$_revision, - 'verbose|v' => \$_verbose, - 'incremental' => \$_incremental, - 'oneline' => \$_oneline, - 'show-commit' => \$_show_commit, - 'authors-file|A=s' => \$_authors, - } ], - 'commit-diff' => [ \&commit_diff, 'Commit a diff between two trees', - { 'message|m=s' => \$_message, - 'file|F=s' => \$_file, - %cmt_opts } ], -); - -my $cmd; -for (my $i = 0; $i < @ARGV; $i++) { - if (defined $cmd{$ARGV[$i]}) { - $cmd = $ARGV[$i]; - splice @ARGV, $i, 1; - last; - } -}; - -my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd); - -read_repo_config(\%opts); -my $rv = GetOptions(%opts, 'help|H|h' => \$_help, - 'version|V' => \$_version, - 'id|i=s' => \$GIT_SVN); -exit 1 if (!$rv && $cmd ne 'log'); - -set_default_vals(); -usage(0) if $_help; -version() if $_version; -usage(1) unless defined $cmd; -init_vars(); -load_authors() if $_authors; -load_all_refs() if $_branch_all_refs; -svn_compat_check() unless $_use_lib; -migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init)$/; -$cmd{$cmd}->[0]->(@ARGV); -exit 0; - -####################### primary functions ###################### -sub usage { - my $exit = shift || 0; - my $fd = $exit ? \*STDERR : \*STDOUT; - print $fd <<""; -git-svn - bidirectional operations between a single Subversion tree and git -Usage: $0 [options] [arguments]\n - - print $fd "Available commands:\n" unless $cmd; - - foreach (sort keys %cmd) { - next if $cmd && $cmd ne $_; - print $fd ' ',pack('A13',$_),$cmd{$_}->[1],"\n"; - foreach (keys %{$cmd{$_}->[2]}) { - # prints out arguments as they should be passed: - my $x = s#[:=]s$## ? '' : s#[:=]i$## ? '' : ''; - print $fd ' ' x 17, join(', ', map { length $_ > 1 ? - "--$_" : "-$_" } - split /\|/,$_)," $x\n"; - } - } - print $fd <<""; -\nGIT_SVN_ID may be set in the environment or via the --id/-i switch to an -arbitrary identifier if you're tracking multiple SVN branches/repositories in -one git repository and want to keep them separate. See git-svn(1) for more -information. - - exit $exit; -} - -sub version { - print "git-svn version $VERSION\n"; - exit 0; -} - -sub rebuild { - if (quiet_run(qw/git-rev-parse --verify/,"refs/remotes/$GIT_SVN^0")) { - copy_remote_ref(); - } - $SVN_URL = shift or undef; - my $newest_rev = 0; - if ($_upgrade) { - sys('git-update-ref',"refs/remotes/$GIT_SVN","$GIT_SVN-HEAD"); - } else { - check_upgrade_needed(); - } - - my $pid = open(my $rev_list,'-|'); - defined $pid or croak $!; - if ($pid == 0) { - exec("git-rev-list","refs/remotes/$GIT_SVN") or croak $!; - } - my $latest; - while (<$rev_list>) { - chomp; - my $c = $_; - croak "Non-SHA1: $c\n" unless $c =~ /^$sha1$/o; - my @commit = grep(/^git-svn-id: /,`git-cat-file commit $c`); - next if (!@commit); # skip merges - my ($url, $rev, $uuid) = extract_metadata($commit[$#commit]); - if (!$rev || !$uuid) { - croak "Unable to extract revision or UUID from ", - "$c, $commit[$#commit]\n"; - } - - # if we merged or otherwise started elsewhere, this is - # how we break out of it - next if (defined $SVN_UUID && ($uuid ne $SVN_UUID)); - next if (defined $SVN_URL && defined $url && ($url ne $SVN_URL)); - - unless (defined $latest) { - if (!$SVN_URL && !$url) { - croak "SVN repository location required: $url\n"; - } - $SVN_URL ||= $url; - $SVN_UUID ||= $uuid; - setup_git_svn(); - $latest = $rev; - } - revdb_set($REVDB, $rev, $c); - print "r$rev = $c\n"; - $newest_rev = $rev if ($rev > $newest_rev); - } - close $rev_list or croak $?; - - goto out if $_use_lib; - if (!chdir $SVN_WC) { - svn_cmd_checkout($SVN_URL, $latest, $SVN_WC); - chdir $SVN_WC or croak $!; - } - - $pid = fork; - defined $pid or croak $!; - if ($pid == 0) { - my @svn_up = qw(svn up); - push @svn_up, '--ignore-externals' unless $_no_ignore_ext; - sys(@svn_up,"-r$newest_rev"); - $ENV{GIT_INDEX_FILE} = $GIT_SVN_INDEX; - index_changes(); - exec('git-write-tree') or croak $!; - } - waitpid $pid, 0; - croak $? if $?; -out: - if ($_upgrade) { - print STDERR <<""; -Keeping deprecated refs/head/$GIT_SVN-HEAD for now. Please remove it -when you have upgraded your tools and habits to use refs/remotes/$GIT_SVN - - } -} - -sub init { - my $url = shift or die "SVN repository location required " . - "as a command-line argument\n"; - $url =~ s!/+$!!; # strip trailing slash - - if (my $repo_path = shift) { - unless (-d $repo_path) { - mkpath([$repo_path]); - } - $GIT_DIR = $ENV{GIT_DIR} = $repo_path . "/.git"; - init_vars(); - } - - $SVN_URL = $url; - unless (-d $GIT_DIR) { - my @init_db = ('git-init-db'); - push @init_db, "--template=$_template" if defined $_template; - push @init_db, "--shared" if defined $_shared; - sys(@init_db); - } - setup_git_svn(); -} - -sub fetch { - check_upgrade_needed(); - $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url"); - my $ret = $_use_lib ? fetch_lib(@_) : fetch_cmd(@_); - if ($ret->{commit} && quiet_run(qw(git-rev-parse --verify - refs/heads/master^0))) { - sys(qw(git-update-ref refs/heads/master),$ret->{commit}); - } - return $ret; -} - -sub fetch_cmd { - my (@parents) = @_; - my @log_args = -d $SVN_WC ? ($SVN_WC) : ($SVN_URL); - unless ($_revision) { - $_revision = -d $SVN_WC ? 'BASE:HEAD' : '0:HEAD'; - } - push @log_args, "-r$_revision"; - push @log_args, '--stop-on-copy' unless $_no_stop_copy; - - my $svn_log = svn_log_raw(@log_args); - - my $base = next_log_entry($svn_log) or croak "No base revision!\n"; - # don't need last_revision from grab_base_rev() because - # user could've specified a different revision to skip (they - # didn't want to import certain revisions into git for whatever - # reason, so trust $base->{revision} instead. - my (undef, $last_commit) = svn_grab_base_rev(); - unless (-d $SVN_WC) { - svn_cmd_checkout($SVN_URL,$base->{revision},$SVN_WC); - chdir $SVN_WC or croak $!; - read_uuid(); - $last_commit = git_commit($base, @parents); - assert_tree($last_commit); - } else { - chdir $SVN_WC or croak $!; - read_uuid(); - # looks like a user manually cp'd and svn switch'ed - unless ($last_commit) { - sys(qw/svn revert -R ./); - assert_svn_wc_clean($base->{revision}); - $last_commit = git_commit($base, @parents); - assert_tree($last_commit); - } - } - my @svn_up = qw(svn up); - push @svn_up, '--ignore-externals' unless $_no_ignore_ext; - my $last = $base; - while (my $log_msg = next_log_entry($svn_log)) { - if ($last->{revision} >= $log_msg->{revision}) { - croak "Out of order: last >= current: ", - "$last->{revision} >= $log_msg->{revision}\n"; - } - # Revert is needed for cases like: - # https://svn.musicpd.org/Jamming/trunk (r166:167), but - # I can't seem to reproduce something like that on a test... - sys(qw/svn revert -R ./); - assert_svn_wc_clean($last->{revision}); - sys(@svn_up,"-r$log_msg->{revision}"); - $last_commit = git_commit($log_msg, $last_commit, @parents); - $last = $log_msg; - } - close $svn_log->{fh}; - $last->{commit} = $last_commit; - return $last; -} - -sub fetch_lib { - my (@parents) = @_; - $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url"); - my $repo; - ($repo, $SVN_PATH) = repo_path_split($SVN_URL); - $SVN_LOG ||= libsvn_connect($repo); - $SVN ||= libsvn_connect($repo); - my ($last_rev, $last_commit) = svn_grab_base_rev(); - my ($base, $head) = libsvn_parse_revision($last_rev); - if ($base > $head) { - return { revision => $last_rev, commit => $last_commit } - } - my $index = set_index($GIT_SVN_INDEX); - - # limit ourselves and also fork() since get_log won't release memory - # after processing a revision and SVN stuff seems to leak - my $inc = 1000; - my ($min, $max) = ($base, $head < $base+$inc ? $head : $base+$inc); - read_uuid(); - if (defined $last_commit) { - unless (-e $GIT_SVN_INDEX) { - sys(qw/git-read-tree/, $last_commit); - } - chomp (my $x = `git-write-tree`); - my ($y) = (`git-cat-file commit $last_commit` - =~ /^tree ($sha1)/m); - if ($y ne $x) { - unlink $GIT_SVN_INDEX or croak $!; - sys(qw/git-read-tree/, $last_commit); - } - chomp ($x = `git-write-tree`); - if ($y ne $x) { - print STDERR "trees ($last_commit) $y != $x\n", - "Something is seriously wrong...\n"; - } - } - while (1) { - # fork, because using SVN::Pool with get_log() still doesn't - # seem to help enough to keep memory usage down. - defined(my $pid = fork) or croak $!; - if (!$pid) { - $SVN::Error::handler = \&libsvn_skip_unknown_revs; - - # Yes I'm perfectly aware that the fourth argument - # below is the limit revisions number. Unfortunately - # performance sucks with it enabled, so it's much - # faster to fetch revision ranges instead of relying - # on the limiter. - libsvn_get_log($SVN_LOG, '/'.$SVN_PATH, - $min, $max, 0, 1, 1, - sub { - my $log_msg; - if ($last_commit) { - $log_msg = libsvn_fetch( - $last_commit, @_); - $last_commit = git_commit( - $log_msg, - $last_commit, - @parents); - } else { - $log_msg = libsvn_new_tree(@_); - $last_commit = git_commit( - $log_msg, @parents); - } - }); - exit 0; - } - waitpid $pid, 0; - croak $? if $?; - ($last_rev, $last_commit) = svn_grab_base_rev(); - last if ($max >= $head); - $min = $max + 1; - $max += $inc; - $max = $head if ($max > $head); - } - restore_index($index); - return { revision => $last_rev, commit => $last_commit }; -} - -sub commit { - my (@commits) = @_; - check_upgrade_needed(); - if ($_stdin || !@commits) { - print "Reading from stdin...\n"; - @commits = (); - while () { - if (/\b($sha1_short)\b/o) { - unshift @commits, $1; - } - } - } - my @revs; - foreach my $c (@commits) { - chomp(my @tmp = safe_qx('git-rev-parse',$c)); - if (scalar @tmp == 1) { - push @revs, $tmp[0]; - } elsif (scalar @tmp > 1) { - push @revs, reverse (safe_qx('git-rev-list',@tmp)); - } else { - die "Failed to rev-parse $c\n"; - } - } - chomp @revs; - $_use_lib ? commit_lib(@revs) : commit_cmd(@revs); - print "Done committing ",scalar @revs," revisions to SVN\n"; -} - -sub commit_cmd { - my (@revs) = @_; - - chdir $SVN_WC or croak "Unable to chdir $SVN_WC: $!\n"; - my $info = svn_info('.'); - my $fetched = fetch(); - if ($info->{Revision} != $fetched->{revision}) { - print STDERR "There are new revisions that were fetched ", - "and need to be merged (or acknowledged) ", - "before committing.\n"; - exit 1; - } - $info = svn_info('.'); - read_uuid($info); - my $last = $fetched; - foreach my $c (@revs) { - my $mods = svn_checkout_tree($last, $c); - if (scalar @$mods == 0) { - print "Skipping, no changes detected\n"; - next; - } - $last = svn_commit_tree($last, $c); - } -} - -sub commit_lib { - my (@revs) = @_; - my ($r_last, $cmt_last) = svn_grab_base_rev(); - defined $r_last or die "Must have an existing revision to commit\n"; - my $fetched = fetch(); - if ($r_last != $fetched->{revision}) { - print STDERR "There are new revisions that were fetched ", - "and need to be merged (or acknowledged) ", - "before committing.\n", - "last rev: $r_last\n", - " current: $fetched->{revision}\n"; - exit 1; - } - read_uuid(); - my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : (); - my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$"; - - set_svn_commit_env(); - foreach my $c (@revs) { - my $log_msg = get_commit_message($c, $commit_msg); - - # fork for each commit because there's a memory leak I - # can't track down... (it's probably in the SVN code) - defined(my $pid = open my $fh, '-|') or croak $!; - if (!$pid) { - my $ed = SVN::Git::Editor->new( - { r => $r_last, - ra => $SVN, - c => $c, - svn_path => $SVN_PATH - }, - $SVN->get_commit_editor( - $log_msg->{msg}, - sub { - libsvn_commit_cb( - @_, $c, - $log_msg->{msg}, - $r_last, - $cmt_last) - }, - @lock) - ); - my $mods = libsvn_checkout_tree($cmt_last, $c, $ed); - if (@$mods == 0) { - print "No changes\nr$r_last = $cmt_last\n"; - $ed->abort_edit; - } else { - $ed->close_edit; - } - exit 0; - } - my ($r_new, $cmt_new, $no); - while (<$fh>) { - print $_; - chomp; - if (/^r(\d+) = ($sha1)$/o) { - ($r_new, $cmt_new) = ($1, $2); - } elsif ($_ eq 'No changes') { - $no = 1; - } - } - close $fh or croak $?; - if (! defined $r_new && ! defined $cmt_new) { - unless ($no) { - die "Failed to parse revision information\n"; - } - } else { - ($r_last, $cmt_last) = ($r_new, $cmt_new); - } - } - $ENV{LC_ALL} = 'C'; - unlink $commit_msg; -} - -sub show_ignore { - $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url"); - $_use_lib ? show_ignore_lib() : show_ignore_cmd(); -} - -sub show_ignore_cmd { - require File::Find or die $!; - if (defined $_revision) { - die "-r/--revision option doesn't work unless the Perl SVN ", - "libraries are used\n"; - } - chdir $SVN_WC or croak $!; - my %ign; - File::Find::find({wanted=>sub{if(lstat $_ && -d _ && -d "$_/.svn"){ - s#^\./##; - @{$ign{$_}} = svn_propget_base('svn:ignore', $_); - }}, no_chdir=>1},'.'); - - print "\n# /\n"; - foreach (@{$ign{'.'}}) { print '/',$_ if /\S/ } - delete $ign{'.'}; - foreach my $i (sort keys %ign) { - print "\n# ",$i,"\n"; - foreach (@{$ign{$i}}) { print '/',$i,'/',$_ if /\S/ } - } -} - -sub show_ignore_lib { - my $repo; - ($repo, $SVN_PATH) = repo_path_split($SVN_URL); - $SVN ||= libsvn_connect($repo); - my $r = defined $_revision ? $_revision : $SVN->get_latest_revnum; - libsvn_traverse_ignore(\*STDOUT, $SVN_PATH, $r); -} - -sub graft_branches { - my $gr_file = "$GIT_DIR/info/grafts"; - my ($grafts, $comments) = read_grafts($gr_file); - my $gr_sha1; - - if (%$grafts) { - # temporarily disable our grafts file to make this idempotent - chomp($gr_sha1 = safe_qx(qw/git-hash-object -w/,$gr_file)); - rename $gr_file, "$gr_file~$gr_sha1" or croak $!; - } - - my $l_map = read_url_paths(); - my @re = map { qr/$_/is } @_opt_m if @_opt_m; - unless ($_no_default_regex) { - push @re, (qr/\b(?:merge|merging|merged)\s+with\s+([\w\.\-]+)/i, - qr/\b(?:merge|merging|merged)\s+([\w\.\-]+)/i, - qr/\b(?:from|of)\s+([\w\.\-]+)/i ); - } - foreach my $u (keys %$l_map) { - if (@re) { - foreach my $p (keys %{$l_map->{$u}}) { - graft_merge_msg($grafts,$l_map,$u,$p,@re); - } - } - unless ($_no_graft_copy) { - if ($_use_lib) { - graft_file_copy_lib($grafts,$l_map,$u); - } else { - graft_file_copy_cmd($grafts,$l_map,$u); - } - } - } - graft_tree_joins($grafts); - - write_grafts($grafts, $comments, $gr_file); - unlink "$gr_file~$gr_sha1" if $gr_sha1; -} - -sub multi_init { - my $url = shift; - $_trunk ||= 'trunk'; - $_trunk =~ s#/+$##; - $url =~ s#/+$## if $url; - if ($_trunk !~ m#^[a-z\+]+://#) { - $_trunk = '/' . $_trunk if ($_trunk !~ m#^/#); - unless ($url) { - print STDERR "E: '$_trunk' is not a complete URL ", - "and a separate URL is not specified\n"; - exit 1; - } - $_trunk = $url . $_trunk; - } - if ($GIT_SVN eq 'git-svn') { - print "GIT_SVN_ID set to 'trunk' for $_trunk\n"; - $GIT_SVN = $ENV{GIT_SVN_ID} = 'trunk'; - } - init_vars(); - init($_trunk); - complete_url_ls_init($url, $_branches, '--branches/-b', ''); - complete_url_ls_init($url, $_tags, '--tags/-t', 'tags/'); -} - -sub multi_fetch { - # try to do trunk first, since branches/tags - # may be descended from it. - if (-e "$GIT_DIR/svn/trunk/info/url") { - fetch_child_id('trunk', @_); - } - rec_fetch('', "$GIT_DIR/svn", @_); -} - -sub show_log { - my (@args) = @_; - my ($r_min, $r_max); - my $r_last = -1; # prevent dupes - rload_authors() if $_authors; - if (defined $TZ) { - $ENV{TZ} = $TZ; - } else { - delete $ENV{TZ}; - } - if (defined $_revision) { - if ($_revision =~ /^(\d+):(\d+)$/) { - ($r_min, $r_max) = ($1, $2); - } elsif ($_revision =~ /^\d+$/) { - $r_min = $r_max = $_revision; - } else { - print STDERR "-r$_revision is not supported, use ", - "standard \'git log\' arguments instead\n"; - exit 1; - } - } - - my $pid = open(my $log,'-|'); - defined $pid or croak $!; - if (!$pid) { - exec(git_svn_log_cmd($r_min,$r_max), @args) or croak $!; - } - setup_pager(); - my (@k, $c, $d); - - while (<$log>) { - if (/^commit ($sha1_short)/o) { - my $cmt = $1; - if ($c && cmt_showable($c) && $c->{r} != $r_last) { - $r_last = $c->{r}; - process_commit($c, $r_min, $r_max, \@k) or - goto out; - } - $d = undef; - $c = { c => $cmt }; - } elsif (/^author (.+) (\d+) ([\-\+]?\d+)$/) { - get_author_info($c, $1, $2, $3); - } elsif (/^(?:tree|parent|committer) /) { - # ignore - } elsif (/^:\d{6} \d{6} $sha1_short/o) { - push @{$c->{raw}}, $_; - } elsif (/^diff /) { - $d = 1; - push @{$c->{diff}}, $_; - } elsif ($d) { - push @{$c->{diff}}, $_; - } elsif (/^ (git-svn-id:.+)$/) { - (undef, $c->{r}, undef) = extract_metadata($1); - } elsif (s/^ //) { - push @{$c->{l}}, $_; - } - } - if ($c && defined $c->{r} && $c->{r} != $r_last) { - $r_last = $c->{r}; - process_commit($c, $r_min, $r_max, \@k); - } - if (@k) { - my $swap = $r_max; - $r_max = $r_min; - $r_min = $swap; - process_commit($_, $r_min, $r_max) foreach reverse @k; - } -out: - close $log; - print '-' x72,"\n" unless $_incremental || $_oneline; -} - -sub commit_diff_usage { - print STDERR "Usage: $0 commit-diff []\n"; - exit 1 -} - -sub commit_diff { - if (!$_use_lib) { - print STDERR "commit-diff must be used with SVN libraries\n"; - exit 1; - } - my $ta = shift or commit_diff_usage(); - my $tb = shift or commit_diff_usage(); - if (!eval { $SVN_URL = shift || file_to_s("$GIT_SVN_DIR/info/url") }) { - print STDERR "Needed URL or usable git-svn id command-line\n"; - commit_diff_usage(); - } - if (defined $_message && defined $_file) { - print STDERR "Both --message/-m and --file/-F specified ", - "for the commit message.\n", - "I have no idea what you mean\n"; - exit 1; - } - if (defined $_file) { - $_message = file_to_s($_message); - } else { - $_message ||= get_commit_message($tb, - "$GIT_DIR/.svn-commit.tmp.$$")->{msg}; - } - my $repo; - ($repo, $SVN_PATH) = repo_path_split($SVN_URL); - $SVN_LOG ||= libsvn_connect($repo); - $SVN ||= libsvn_connect($repo); - my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : (); - my $ed = SVN::Git::Editor->new({ r => $SVN->get_latest_revnum, - ra => $SVN, c => $tb, - svn_path => $SVN_PATH - }, - $SVN->get_commit_editor($_message, - sub {print "Committed $_[0]\n"},@lock) - ); - my $mods = libsvn_checkout_tree($ta, $tb, $ed); - if (@$mods == 0) { - print "No changes\n$ta == $tb\n"; - $ed->abort_edit; - } else { - $ed->close_edit; - } -} - -########################### utility functions ######################### - -sub cmt_showable { - my ($c) = @_; - return 1 if defined $c->{r}; - if ($c->{l} && $c->{l}->[-1] eq "...\n" && - $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) { - my @msg = safe_qx(qw/git-cat-file commit/, $c->{c}); - shift @msg while ($msg[0] ne "\n"); - shift @msg; - @{$c->{l}} = grep !/^git-svn-id: /, @msg; - - (undef, $c->{r}, undef) = extract_metadata( - (grep(/^git-svn-id: /, @msg))[-1]); - } - return defined $c->{r}; -} - -sub git_svn_log_cmd { - my ($r_min, $r_max) = @_; - my @cmd = (qw/git-log --abbrev-commit --pretty=raw - --default/, "refs/remotes/$GIT_SVN"); - push @cmd, '--summary' if $_verbose; - return @cmd unless defined $r_max; - if ($r_max == $r_min) { - push @cmd, '--max-count=1'; - if (my $c = revdb_get($REVDB, $r_max)) { - push @cmd, $c; - } - } else { - my ($c_min, $c_max); - $c_max = revdb_get($REVDB, $r_max); - $c_min = revdb_get($REVDB, $r_min); - if ($c_min && $c_max) { - if ($r_max > $r_max) { - push @cmd, "$c_min..$c_max"; - } else { - push @cmd, "$c_max..$c_min"; - } - } elsif ($r_max > $r_min) { - push @cmd, $c_max; - } else { - push @cmd, $c_min; - } - } - return @cmd; -} - -sub fetch_child_id { - my $id = shift; - print "Fetching $id\n"; - my $ref = "$GIT_DIR/refs/remotes/$id"; - defined(my $pid = open my $fh, '-|') or croak $!; - if (!$pid) { - $_repack = undef; - $GIT_SVN = $ENV{GIT_SVN_ID} = $id; - init_vars(); - fetch(@_); - exit 0; - } - while (<$fh>) { - print $_; - check_repack() if (/^r\d+ = $sha1/); - } - close $fh or croak $?; -} - -sub rec_fetch { - my ($pfx, $p, @args) = @_; - my @dir; - foreach (sort <$p/*>) { - if (-r "$_/info/url") { - $pfx .= '/' if $pfx && $pfx !~ m!/$!; - my $id = $pfx . basename $_; - next if $id eq 'trunk'; - fetch_child_id($id, @args); - } elsif (-d $_) { - push @dir, $_; - } - } - foreach (@dir) { - my $x = $_; - $x =~ s!^\Q$GIT_DIR\E/svn/!!; - rec_fetch($x, $_); - } -} - -sub complete_url_ls_init { - my ($url, $var, $switch, $pfx) = @_; - unless ($var) { - print STDERR "W: $switch not specified\n"; - return; - } - $var =~ s#/+$##; - if ($var !~ m#^[a-z\+]+://#) { - $var = '/' . $var if ($var !~ m#^/#); - unless ($url) { - print STDERR "E: '$var' is not a complete URL ", - "and a separate URL is not specified\n"; - exit 1; - } - $var = $url . $var; - } - chomp(my @ls = $_use_lib ? libsvn_ls_fullurl($var) - : safe_qx(qw/svn ls --non-interactive/, $var)); - my $old = $GIT_SVN; - defined(my $pid = fork) or croak $!; - if (!$pid) { - foreach my $u (map { "$var/$_" } (grep m!/$!, @ls)) { - $u =~ s#/+$##; - if ($u !~ m!\Q$var\E/(.+)$!) { - print STDERR "W: Unrecognized URL: $u\n"; - die "This should never happen\n"; - } - my $id = $pfx.$1; - print "init $u => $id\n"; - $GIT_SVN = $ENV{GIT_SVN_ID} = $id; - init_vars(); - init($u); - } - exit 0; - } - waitpid $pid, 0; - croak $? if $?; -} - -sub common_prefix { - my $paths = shift; - my %common; - foreach (@$paths) { - my @tmp = split m#/#, $_; - my $p = ''; - while (my $x = shift @tmp) { - $p .= "/$x"; - $common{$p} ||= 0; - $common{$p}++; - } - } - foreach (sort {length $b <=> length $a} keys %common) { - if ($common{$_} == @$paths) { - return $_; - } - } - return ''; -} - -# grafts set here are 'stronger' in that they're based on actual tree -# matches, and won't be deleted from merge-base checking in write_grafts() -sub graft_tree_joins { - my $grafts = shift; - map_tree_joins() if (@_branch_from && !%tree_map); - return unless %tree_map; - - git_svn_each(sub { - my $i = shift; - defined(my $pid = open my $fh, '-|') or croak $!; - if (!$pid) { - exec qw/git-rev-list --pretty=raw/, - "refs/remotes/$i" or croak $!; - } - while (<$fh>) { - next unless /^commit ($sha1)$/o; - my $c = $1; - my ($t) = (<$fh> =~ /^tree ($sha1)$/o); - next unless $tree_map{$t}; - - my $l; - do { - $l = readline $fh; - } until ($l =~ /^committer (?:.+) (\d+) ([\-\+]?\d+)$/); - - my ($s, $tz) = ($1, $2); - if ($tz =~ s/^\+//) { - $s += tz_to_s_offset($tz); - } elsif ($tz =~ s/^\-//) { - $s -= tz_to_s_offset($tz); - } - - my ($url_a, $r_a, $uuid_a) = cmt_metadata($c); - - foreach my $p (@{$tree_map{$t}}) { - next if $p eq $c; - my $mb = eval { - safe_qx('git-merge-base', $c, $p) - }; - next unless ($@ || $?); - if (defined $r_a) { - # see if SVN says it's a relative - my ($url_b, $r_b, $uuid_b) = - cmt_metadata($p); - next if (defined $url_b && - defined $url_a && - ($url_a eq $url_b) && - ($uuid_a eq $uuid_b)); - if ($uuid_a eq $uuid_b) { - if ($r_b < $r_a) { - $grafts->{$c}->{$p} = 2; - next; - } elsif ($r_b > $r_a) { - $grafts->{$p}->{$c} = 2; - next; - } - } - } - my $ct = get_commit_time($p); - if ($ct < $s) { - $grafts->{$c}->{$p} = 2; - } elsif ($ct > $s) { - $grafts->{$p}->{$c} = 2; - } - # what should we do when $ct == $s ? - } - } - close $fh or croak $?; - }); -} - -# this isn't funky-filename safe, but good enough for now... -sub graft_file_copy_cmd { - my ($grafts, $l_map, $u) = @_; - my $paths = $l_map->{$u}; - my $pfx = common_prefix([keys %$paths]); - $SVN_URL ||= $u.$pfx; - my $pid = open my $fh, '-|'; - defined $pid or croak $!; - unless ($pid) { - my @exec = qw/svn log -v/; - push @exec, "-r$_revision" if defined $_revision; - exec @exec, $u.$pfx or croak $!; - } - my ($r, $mp) = (undef, undef); - while (<$fh>) { - chomp; - if (/^\-{72}$/) { - $mp = $r = undef; - } elsif (/^r(\d+) \| /) { - $r = $1 unless defined $r; - } elsif (/^Changed paths:/) { - $mp = 1; - } elsif ($mp && m#^ [AR] /(\S.*?) \(from /(\S+?):(\d+)\)$#) { - my ($p1, $p0, $r0) = ($1, $2, $3); - my $c = find_graft_path_commit($paths, $p1, $r); - next unless $c; - find_graft_path_parents($grafts, $paths, $c, $p0, $r0); - } - } -} - -sub graft_file_copy_lib { - my ($grafts, $l_map, $u) = @_; - my $tree_paths = $l_map->{$u}; - my $pfx = common_prefix([keys %$tree_paths]); - my ($repo, $path) = repo_path_split($u.$pfx); - $SVN_LOG ||= libsvn_connect($repo); - $SVN ||= libsvn_connect($repo); - - my ($base, $head) = libsvn_parse_revision(); - my $inc = 1000; - my ($min, $max) = ($base, $head < $base+$inc ? $head : $base+$inc); - my $eh = $SVN::Error::handler; - $SVN::Error::handler = \&libsvn_skip_unknown_revs; - while (1) { - my $pool = SVN::Pool->new; - libsvn_get_log($SVN_LOG, "/$path", $min, $max, 0, 1, 1, - sub { - libsvn_graft_file_copies($grafts, $tree_paths, - $path, @_); - }, $pool); - $pool->clear; - last if ($max >= $head); - $min = $max + 1; - $max += $inc; - $max = $head if ($max > $head); - } - $SVN::Error::handler = $eh; -} - -sub process_merge_msg_matches { - my ($grafts, $l_map, $u, $p, $c, @matches) = @_; - my (@strong, @weak); - foreach (@matches) { - # merging with ourselves is not interesting - next if $_ eq $p; - if ($l_map->{$u}->{$_}) { - push @strong, $_; - } else { - push @weak, $_; - } - } - foreach my $w (@weak) { - last if @strong; - # no exact match, use branch name as regexp. - my $re = qr/\Q$w\E/i; - foreach (keys %{$l_map->{$u}}) { - if (/$re/) { - push @strong, $l_map->{$u}->{$_}; - last; - } - } - last if @strong; - $w = basename($w); - $re = qr/\Q$w\E/i; - foreach (keys %{$l_map->{$u}}) { - if (/$re/) { - push @strong, $l_map->{$u}->{$_}; - last; - } - } - } - my ($rev) = ($c->{m} =~ /^git-svn-id:\s(?:\S+?)\@(\d+) - \s(?:[a-f\d\-]+)$/xsm); - unless (defined $rev) { - ($rev) = ($c->{m} =~/^git-svn-id:\s(\d+) - \@(?:[a-f\d\-]+)/xsm); - return unless defined $rev; - } - foreach my $m (@strong) { - my ($r0, $s0) = find_rev_before($rev, $m, 1); - $grafts->{$c->{c}}->{$s0} = 1 if defined $s0; - } -} - -sub graft_merge_msg { - my ($grafts, $l_map, $u, $p, @re) = @_; - - my $x = $l_map->{$u}->{$p}; - my $rl = rev_list_raw($x); - while (my $c = next_rev_list_entry($rl)) { - foreach my $re (@re) { - my (@br) = ($c->{m} =~ /$re/g); - next unless @br; - process_merge_msg_matches($grafts,$l_map,$u,$p,$c,@br); - } - } -} - -sub read_uuid { - return if $SVN_UUID; - if ($_use_lib) { - my $pool = SVN::Pool->new; - $SVN_UUID = $SVN->get_uuid($pool); - $pool->clear; - } else { - my $info = shift || svn_info('.'); - $SVN_UUID = $info->{'Repository UUID'} or - croak "Repository UUID unreadable\n"; - } -} - -sub quiet_run { - my $pid = fork; - defined $pid or croak $!; - if (!$pid) { - open my $null, '>', '/dev/null' or croak $!; - open STDERR, '>&', $null or croak $!; - open STDOUT, '>&', $null or croak $!; - exec @_ or croak $!; - } - waitpid $pid, 0; - return $?; -} - -sub repo_path_split { - my $full_url = shift; - $full_url =~ s#/+$##; - - foreach (@repo_path_split_cache) { - if ($full_url =~ s#$_##) { - my $u = $1; - $full_url =~ s#^/+##; - return ($u, $full_url); - } - } - - my ($url, $path) = ($full_url =~ m!^([a-z\+]+://[^/]*)(.*)$!i); - $path =~ s#^/+##; - my @paths = split(m#/+#, $path); - - if ($_use_lib) { - while (1) { - $SVN = libsvn_connect($url); - last if (defined $SVN && - defined eval { $SVN->get_latest_revnum }); - my $n = shift @paths || last; - $url .= "/$n"; - } - } else { - while (quiet_run(qw/svn ls --non-interactive/, $url)) { - my $n = shift @paths || last; - $url .= "/$n"; - } - } - push @repo_path_split_cache, qr/^(\Q$url\E)/; - $path = join('/',@paths); - return ($url, $path); -} - -sub setup_git_svn { - defined $SVN_URL or croak "SVN repository location required\n"; - unless (-d $GIT_DIR) { - croak "GIT_DIR=$GIT_DIR does not exist!\n"; - } - mkpath([$GIT_SVN_DIR]); - mkpath(["$GIT_SVN_DIR/info"]); - open my $fh, '>>',$REVDB or croak $!; - close $fh; - s_to_file($SVN_URL,"$GIT_SVN_DIR/info/url"); - -} - -sub assert_svn_wc_clean { - return if $_use_lib; - my ($svn_rev) = @_; - croak "$svn_rev is not an integer!\n" unless ($svn_rev =~ /^\d+$/); - my $lcr = svn_info('.')->{'Last Changed Rev'}; - if ($svn_rev != $lcr) { - print STDERR "Checking for copy-tree ... "; - my @diff = grep(/^Index: /,(safe_qx(qw(svn diff), - "-r$lcr:$svn_rev"))); - if (@diff) { - croak "Nope! Expected r$svn_rev, got r$lcr\n"; - } else { - print STDERR "OK!\n"; - } - } - my @status = grep(!/^Performing status on external/,(`svn status`)); - @status = grep(!/^\s*$/,@status); - if (scalar @status) { - print STDERR "Tree ($SVN_WC) is not clean:\n"; - print STDERR $_ foreach @status; - croak; - } -} - -sub get_tree_from_treeish { - my ($treeish) = @_; - croak "Not a sha1: $treeish\n" unless $treeish =~ /^$sha1$/o; - chomp(my $type = `git-cat-file -t $treeish`); - my $expected; - while ($type eq 'tag') { - chomp(($treeish, $type) = `git-cat-file tag $treeish`); - } - if ($type eq 'commit') { - $expected = (grep /^tree /,`git-cat-file commit $treeish`)[0]; - ($expected) = ($expected =~ /^tree ($sha1)$/); - die "Unable to get tree from $treeish\n" unless $expected; - } elsif ($type eq 'tree') { - $expected = $treeish; - } else { - die "$treeish is a $type, expected tree, tag or commit\n"; - } - return $expected; -} - -sub assert_tree { - return if $_use_lib; - my ($treeish) = @_; - my $expected = get_tree_from_treeish($treeish); - - my $tmpindex = $GIT_SVN_INDEX.'.assert-tmp'; - if (-e $tmpindex) { - unlink $tmpindex or croak $!; - } - my $old_index = set_index($tmpindex); - index_changes(1); - chomp(my $tree = `git-write-tree`); - restore_index($old_index); - if ($tree ne $expected) { - croak "Tree mismatch, Got: $tree, Expected: $expected\n"; - } - unlink $tmpindex; -} - -sub parse_diff_tree { - my $diff_fh = shift; - local $/ = "\0"; - my $state = 'meta'; - my @mods; - while (<$diff_fh>) { - chomp $_; # this gets rid of the trailing "\0" - if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s - $sha1\s($sha1)\s([MTCRAD])\d*$/xo) { - push @mods, { mode_a => $1, mode_b => $2, - sha1_b => $3, chg => $4 }; - if ($4 =~ /^(?:C|R)$/) { - $state = 'file_a'; - } else { - $state = 'file_b'; - } - } elsif ($state eq 'file_a') { - my $x = $mods[$#mods] or croak "Empty array\n"; - if ($x->{chg} !~ /^(?:C|R)$/) { - croak "Error parsing $_, $x->{chg}\n"; - } - $x->{file_a} = $_; - $state = 'file_b'; - } elsif ($state eq 'file_b') { - my $x = $mods[$#mods] or croak "Empty array\n"; - if (exists $x->{file_a} && $x->{chg} !~ /^(?:C|R)$/) { - croak "Error parsing $_, $x->{chg}\n"; - } - if (!exists $x->{file_a} && $x->{chg} =~ /^(?:C|R)$/) { - croak "Error parsing $_, $x->{chg}\n"; - } - $x->{file_b} = $_; - $state = 'meta'; - } else { - croak "Error parsing $_\n"; - } - } - close $diff_fh or croak $?; - - return \@mods; -} - -sub svn_check_prop_executable { - my $m = shift; - return if -l $m->{file_b}; - if ($m->{mode_b} =~ /755$/) { - chmod((0755 &~ umask),$m->{file_b}) or croak $!; - if ($m->{mode_a} !~ /755$/) { - sys(qw(svn propset svn:executable 1), $m->{file_b}); - } - -x $m->{file_b} or croak "$m->{file_b} is not executable!\n"; - } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { - sys(qw(svn propdel svn:executable), $m->{file_b}); - chmod((0644 &~ umask),$m->{file_b}) or croak $!; - -x $m->{file_b} and croak "$m->{file_b} is executable!\n"; - } -} - -sub svn_ensure_parent_path { - my $dir_b = dirname(shift); - svn_ensure_parent_path($dir_b) if ($dir_b ne File::Spec->curdir); - mkpath([$dir_b]) unless (-d $dir_b); - sys(qw(svn add -N), $dir_b) unless (-d "$dir_b/.svn"); -} - -sub precommit_check { - my $mods = shift; - my (%rm_file, %rmdir_check, %added_check); - - my %o = ( D => 0, R => 1, C => 2, A => 3, M => 3, T => 3 ); - foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) { - if ($m->{chg} eq 'R') { - if (-d $m->{file_b}) { - err_dir_to_file("$m->{file_a} => $m->{file_b}"); - } - # dir/$file => dir/file/$file - my $dirname = dirname($m->{file_b}); - while ($dirname ne File::Spec->curdir) { - if ($dirname ne $m->{file_a}) { - $dirname = dirname($dirname); - next; - } - err_file_to_dir("$m->{file_a} => $m->{file_b}"); - } - # baz/zzz => baz (baz is a file) - $dirname = dirname($m->{file_a}); - while ($dirname ne File::Spec->curdir) { - if ($dirname ne $m->{file_b}) { - $dirname = dirname($dirname); - next; - } - err_dir_to_file("$m->{file_a} => $m->{file_b}"); - } - } - if ($m->{chg} =~ /^(D|R)$/) { - my $t = $1 eq 'D' ? 'file_b' : 'file_a'; - $rm_file{ $m->{$t} } = 1; - my $dirname = dirname( $m->{$t} ); - my $basename = basename( $m->{$t} ); - $rmdir_check{$dirname}->{$basename} = 1; - } elsif ($m->{chg} =~ /^(?:A|C)$/) { - if (-d $m->{file_b}) { - err_dir_to_file($m->{file_b}); - } - my $dirname = dirname( $m->{file_b} ); - my $basename = basename( $m->{file_b} ); - $added_check{$dirname}->{$basename} = 1; - while ($dirname ne File::Spec->curdir) { - if ($rm_file{$dirname}) { - err_file_to_dir($m->{file_b}); - } - $dirname = dirname $dirname; - } - } - } - return (\%rmdir_check, \%added_check); - - sub err_dir_to_file { - my $file = shift; - print STDERR "Node change from directory to file ", - "is not supported by Subversion: ",$file,"\n"; - exit 1; - } - sub err_file_to_dir { - my $file = shift; - print STDERR "Node change from file to directory ", - "is not supported by Subversion: ",$file,"\n"; - exit 1; - } -} - - -sub get_diff { - my ($from, $treeish) = @_; - assert_tree($from); - print "diff-tree $from $treeish\n"; - my $pid = open my $diff_fh, '-|'; - defined $pid or croak $!; - if ($pid == 0) { - my @diff_tree = qw(git-diff-tree -z -r); - if ($_cp_similarity) { - push @diff_tree, "-C$_cp_similarity"; - } else { - push @diff_tree, '-C'; - } - push @diff_tree, '--find-copies-harder' if $_find_copies_harder; - push @diff_tree, "-l$_l" if defined $_l; - exec(@diff_tree, $from, $treeish) or croak $!; - } - return parse_diff_tree($diff_fh); -} - -sub svn_checkout_tree { - my ($from, $treeish) = @_; - my $mods = get_diff($from->{commit}, $treeish); - return $mods unless (scalar @$mods); - my ($rm, $add) = precommit_check($mods); - - my %o = ( D => 1, R => 0, C => -1, A => 3, M => 3, T => 3 ); - foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) { - if ($m->{chg} eq 'C') { - svn_ensure_parent_path( $m->{file_b} ); - sys(qw(svn cp), $m->{file_a}, $m->{file_b}); - apply_mod_line_blob($m); - svn_check_prop_executable($m); - } elsif ($m->{chg} eq 'D') { - sys(qw(svn rm --force), $m->{file_b}); - } elsif ($m->{chg} eq 'R') { - svn_ensure_parent_path( $m->{file_b} ); - sys(qw(svn mv --force), $m->{file_a}, $m->{file_b}); - apply_mod_line_blob($m); - svn_check_prop_executable($m); - } elsif ($m->{chg} eq 'M') { - apply_mod_line_blob($m); - svn_check_prop_executable($m); - } elsif ($m->{chg} eq 'T') { - sys(qw(svn rm --force),$m->{file_b}); - apply_mod_line_blob($m); - sys(qw(svn add), $m->{file_b}); - svn_check_prop_executable($m); - } elsif ($m->{chg} eq 'A') { - svn_ensure_parent_path( $m->{file_b} ); - apply_mod_line_blob($m); - sys(qw(svn add), $m->{file_b}); - svn_check_prop_executable($m); - } else { - croak "Invalid chg: $m->{chg}\n"; - } - } - - assert_tree($treeish); - if ($_rmdir) { # remove empty directories - handle_rmdir($rm, $add); - } - assert_tree($treeish); - return $mods; -} - -sub libsvn_checkout_tree { - my ($from, $treeish, $ed) = @_; - my $mods = get_diff($from, $treeish); - return $mods unless (scalar @$mods); - my %o = ( D => 1, R => 0, C => -1, A => 3, M => 3, T => 3 ); - foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) { - my $f = $m->{chg}; - if (defined $o{$f}) { - $ed->$f($m, $_q); - } else { - croak "Invalid change type: $f\n"; - } - } - $ed->rmdirs($_q) if $_rmdir; - return $mods; -} - -# svn ls doesn't work with respect to the current working tree, but what's -# in the repository. There's not even an option for it... *sigh* -# (added files don't show up and removed files remain in the ls listing) -sub svn_ls_current { - my ($dir, $rm, $add) = @_; - chomp(my @ls = safe_qx('svn','ls',$dir)); - my @ret = (); - foreach (@ls) { - s#/$##; # trailing slashes are evil - push @ret, $_ unless $rm->{$dir}->{$_}; - } - if (exists $add->{$dir}) { - push @ret, keys %{$add->{$dir}}; - } - return \@ret; -} - -sub handle_rmdir { - my ($rm, $add) = @_; - - foreach my $dir (sort {length $b <=> length $a} keys %$rm) { - my $ls = svn_ls_current($dir, $rm, $add); - next if (scalar @$ls); - sys(qw(svn rm --force),$dir); - - my $dn = dirname $dir; - $rm->{ $dn }->{ basename $dir } = 1; - $ls = svn_ls_current($dn, $rm, $add); - while (scalar @$ls == 0 && $dn ne File::Spec->curdir) { - sys(qw(svn rm --force),$dn); - $dir = basename $dn; - $dn = dirname $dn; - $rm->{ $dn }->{ $dir } = 1; - $ls = svn_ls_current($dn, $rm, $add); - } - } -} - -sub get_commit_message { - my ($commit, $commit_msg) = (@_); - my %log_msg = ( msg => '' ); - open my $msg, '>', $commit_msg or croak $!; - - chomp(my $type = `git-cat-file -t $commit`); - if ($type eq 'commit') { - my $pid = open my $msg_fh, '-|'; - defined $pid or croak $!; - - if ($pid == 0) { - exec(qw(git-cat-file commit), $commit) or croak $!; - } - my $in_msg = 0; - while (<$msg_fh>) { - if (!$in_msg) { - $in_msg = 1 if (/^\s*$/); - } elsif (/^git-svn-id: /) { - # skip this, we regenerate the correct one - # on re-fetch anyways - } else { - print $msg $_ or croak $!; - } - } - close $msg_fh or croak $?; - } - close $msg or croak $!; - - if ($_edit || ($type eq 'tree')) { - my $editor = $ENV{VISUAL} || $ENV{EDITOR} || 'vi'; - system($editor, $commit_msg); - } - - # file_to_s removes all trailing newlines, so just use chomp() here: - open $msg, '<', $commit_msg or croak $!; - { local $/; chomp($log_msg{msg} = <$msg>); } - close $msg or croak $!; - - return \%log_msg; -} - -sub set_svn_commit_env { - if (defined $LC_ALL) { - $ENV{LC_ALL} = $LC_ALL; - } else { - delete $ENV{LC_ALL}; - } -} - -sub svn_commit_tree { - my ($last, $commit) = @_; - my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$"; - my $log_msg = get_commit_message($commit, $commit_msg); - my ($oneline) = ($log_msg->{msg} =~ /([^\n\r]+)/); - print "Committing $commit: $oneline\n"; - - set_svn_commit_env(); - my @ci_output = safe_qx(qw(svn commit -F),$commit_msg); - $ENV{LC_ALL} = 'C'; - unlink $commit_msg; - my ($committed) = ($ci_output[$#ci_output] =~ /(\d+)/); - if (!defined $committed) { - my $out = join("\n",@ci_output); - print STDERR "W: Trouble parsing \`svn commit' output:\n\n", - $out, "\n\nAssuming English locale..."; - ($committed) = ($out =~ /^Committed revision \d+\./sm); - defined $committed or die " FAILED!\n", - "Commit output failed to parse committed revision!\n", - print STDERR " OK\n"; - } - - my @svn_up = qw(svn up); - push @svn_up, '--ignore-externals' unless $_no_ignore_ext; - if ($_optimize_commits && ($committed == ($last->{revision} + 1))) { - push @svn_up, "-r$committed"; - sys(@svn_up); - my $info = svn_info('.'); - my $date = $info->{'Last Changed Date'} or die "Missing date\n"; - if ($info->{'Last Changed Rev'} != $committed) { - croak "$info->{'Last Changed Rev'} != $committed\n" - } - my ($Y,$m,$d,$H,$M,$S,$tz) = ($date =~ - /(\d{4})\-(\d\d)\-(\d\d)\s - (\d\d)\:(\d\d)\:(\d\d)\s([\-\+]\d+)/x) - or croak "Failed to parse date: $date\n"; - $log_msg->{date} = "$tz $Y-$m-$d $H:$M:$S"; - $log_msg->{author} = $info->{'Last Changed Author'}; - $log_msg->{revision} = $committed; - $log_msg->{msg} .= "\n"; - $log_msg->{parents} = [ $last->{commit} ]; - $log_msg->{commit} = git_commit($log_msg, $commit); - return $log_msg; - } - # resync immediately - push @svn_up, "-r$last->{revision}"; - sys(@svn_up); - return fetch("$committed=$commit"); -} - -sub rev_list_raw { - my (@args) = @_; - my $pid = open my $fh, '-|'; - defined $pid or croak $!; - if (!$pid) { - exec(qw/git-rev-list --pretty=raw/, @args) or croak $!; - } - return { fh => $fh, t => { } }; -} - -sub next_rev_list_entry { - my $rl = shift; - my $fh = $rl->{fh}; - my $x = $rl->{t}; - while (<$fh>) { - if (/^commit ($sha1)$/o) { - if ($x->{c}) { - $rl->{t} = { c => $1 }; - return $x; - } else { - $x->{c} = $1; - } - } elsif (/^parent ($sha1)$/o) { - $x->{p}->{$1} = 1; - } elsif (s/^ //) { - $x->{m} ||= ''; - $x->{m} .= $_; - } - } - return ($x != $rl->{t}) ? $x : undef; -} - -# read the entire log into a temporary file (which is removed ASAP) -# and store the file handle + parser state -sub svn_log_raw { - my (@log_args) = @_; - my $log_fh = IO::File->new_tmpfile or croak $!; - my $pid = fork; - defined $pid or croak $!; - if (!$pid) { - open STDOUT, '>&', $log_fh or croak $!; - exec (qw(svn log), @log_args) or croak $! - } - waitpid $pid, 0; - croak $? if $?; - seek $log_fh, 0, 0 or croak $!; - return { state => 'sep', fh => $log_fh }; -} - -sub next_log_entry { - my $log = shift; # retval of svn_log_raw() - my $ret = undef; - my $fh = $log->{fh}; - - while (<$fh>) { - chomp; - if (/^\-{72}$/) { - if ($log->{state} eq 'msg') { - if ($ret->{lines}) { - $ret->{msg} .= $_."\n"; - unless(--$ret->{lines}) { - $log->{state} = 'sep'; - } - } else { - croak "Log parse error at: $_\n", - $ret->{revision}, - "\n"; - } - next; - } - if ($log->{state} ne 'sep') { - croak "Log parse error at: $_\n", - "state: $log->{state}\n", - $ret->{revision}, - "\n"; - } - $log->{state} = 'rev'; - - # if we have an empty log message, put something there: - if ($ret) { - $ret->{msg} ||= "\n"; - delete $ret->{lines}; - return $ret; - } - next; - } - if ($log->{state} eq 'rev' && s/^r(\d+)\s*\|\s*//) { - my $rev = $1; - my ($author, $date, $lines) = split(/\s*\|\s*/, $_, 3); - ($lines) = ($lines =~ /(\d+)/); - my ($Y,$m,$d,$H,$M,$S,$tz) = ($date =~ - /(\d{4})\-(\d\d)\-(\d\d)\s - (\d\d)\:(\d\d)\:(\d\d)\s([\-\+]\d+)/x) - or croak "Failed to parse date: $date\n"; - $ret = { revision => $rev, - date => "$tz $Y-$m-$d $H:$M:$S", - author => $author, - lines => $lines, - msg => '' }; - if (defined $_authors && ! defined $users{$author}) { - die "Author: $author not defined in ", - "$_authors file\n"; - } - $log->{state} = 'msg_start'; - next; - } - # skip the first blank line of the message: - if ($log->{state} eq 'msg_start' && /^$/) { - $log->{state} = 'msg'; - } elsif ($log->{state} eq 'msg') { - if ($ret->{lines}) { - $ret->{msg} .= $_."\n"; - unless (--$ret->{lines}) { - $log->{state} = 'sep'; - } - } else { - croak "Log parse error at: $_\n", - $ret->{revision},"\n"; - } - } - } - return $ret; -} - -sub svn_info { - my $url = shift || $SVN_URL; - - my $pid = open my $info_fh, '-|'; - defined $pid or croak $!; - - if ($pid == 0) { - exec(qw(svn info),$url) or croak $!; - } - - my $ret = {}; - # only single-lines seem to exist in svn info output - while (<$info_fh>) { - chomp $_; - if (m#^([^:]+)\s*:\s*(\S.*)$#) { - $ret->{$1} = $2; - push @{$ret->{-order}}, $1; - } - } - close $info_fh or croak $?; - return $ret; -} - -sub sys { system(@_) == 0 or croak $? } - -sub eol_cp { - my ($from, $to) = @_; - my $es = svn_propget_base('svn:eol-style', $to); - open my $rfd, '<', $from or croak $!; - binmode $rfd or croak $!; - open my $wfd, '>', $to or croak $!; - binmode $wfd or croak $!; - eol_cp_fd($rfd, $wfd, $es); - close $rfd or croak $!; - close $wfd or croak $!; -} - -sub eol_cp_fd { - my ($rfd, $wfd, $es) = @_; - my $eol = defined $es ? $EOL{$es} : undef; - my $buf; - use bytes; - while (1) { - my ($r, $w, $t); - defined($r = sysread($rfd, $buf, 4096)) or croak $!; - return unless $r; - if ($eol) { - if ($buf =~ /\015$/) { - my $c; - defined($r = sysread($rfd,$c,1)) or croak $!; - $buf .= $c if $r > 0; - } - $buf =~ s/(?:\015\012|\015|\012)/$eol/gs; - $r = length($buf); - } - for ($w = 0; $w < $r; $w += $t) { - $t = syswrite($wfd, $buf, $r - $w, $w) or croak $!; - } - } - no bytes; -} - -sub do_update_index { - my ($z_cmd, $cmd, $no_text_base) = @_; - - my $z = open my $p, '-|'; - defined $z or croak $!; - unless ($z) { exec @$z_cmd or croak $! } - - my $pid = open my $ui, '|-'; - defined $pid or croak $!; - unless ($pid) { - exec('git-update-index',"--$cmd",'-z','--stdin') or croak $!; - } - local $/ = "\0"; - while (my $x = <$p>) { - chomp $x; - if (!$no_text_base && lstat $x && ! -l _ && - svn_propget_base('svn:keywords', $x)) { - my $mode = -x _ ? 0755 : 0644; - my ($v,$d,$f) = File::Spec->splitpath($x); - my $tb = File::Spec->catfile($d, '.svn', 'tmp', - 'text-base',"$f.svn-base"); - $tb =~ s#^/##; - unless (-f $tb) { - $tb = File::Spec->catfile($d, '.svn', - 'text-base',"$f.svn-base"); - $tb =~ s#^/##; - } - unlink $x or croak $!; - eol_cp($tb, $x); - chmod(($mode &~ umask), $x) or croak $!; - } - print $ui $x,"\0"; - } - close $ui or croak $?; -} - -sub index_changes { - return if $_use_lib; - - if (!-f "$GIT_SVN_DIR/info/exclude") { - open my $fd, '>>', "$GIT_SVN_DIR/info/exclude" or croak $!; - print $fd '.svn',"\n"; - close $fd or croak $!; - } - my $no_text_base = shift; - do_update_index([qw/git-diff-files --name-only -z/], - 'remove', - $no_text_base); - do_update_index([qw/git-ls-files -z --others/, - "--exclude-from=$GIT_SVN_DIR/info/exclude"], - 'add', - $no_text_base); -} - -sub s_to_file { - my ($str, $file, $mode) = @_; - open my $fd,'>',$file or croak $!; - print $fd $str,"\n" or croak $!; - close $fd or croak $!; - chmod ($mode &~ umask, $file) if (defined $mode); -} - -sub file_to_s { - my $file = shift; - open my $fd,'<',$file or croak "$!: file: $file\n"; - local $/; - my $ret = <$fd>; - close $fd or croak $!; - $ret =~ s/\s*$//s; - return $ret; -} - -sub assert_revision_unknown { - my $r = shift; - if (my $c = revdb_get($REVDB, $r)) { - croak "$r = $c already exists! Why are we refetching it?"; - } -} - -sub trees_eq { - my ($x, $y) = @_; - my @x = safe_qx('git-cat-file','commit',$x); - my @y = safe_qx('git-cat-file','commit',$y); - if (($y[0] ne $x[0]) || $x[0] !~ /^tree $sha1\n$/ - || $y[0] !~ /^tree $sha1\n$/) { - print STDERR "Trees not equal: $y[0] != $x[0]\n"; - return 0 - } - return 1; -} - -sub git_commit { - my ($log_msg, @parents) = @_; - assert_revision_unknown($log_msg->{revision}); - map_tree_joins() if (@_branch_from && !%tree_map); - - my (@tmp_parents, @exec_parents, %seen_parent); - if (my $lparents = $log_msg->{parents}) { - @tmp_parents = @$lparents - } - # commit parents can be conditionally bound to a particular - # svn revision via: "svn_revno=commit_sha1", filter them out here: - foreach my $p (@parents) { - next unless defined $p; - if ($p =~ /^(\d+)=($sha1_short)$/o) { - if ($1 == $log_msg->{revision}) { - push @tmp_parents, $2; - } - } else { - push @tmp_parents, $p if $p =~ /$sha1_short/o; - } - } - my $tree = $log_msg->{tree}; - if (!defined $tree) { - my $index = set_index($GIT_SVN_INDEX); - index_changes(); - chomp($tree = `git-write-tree`); - croak $? if $?; - restore_index($index); - } - - # just in case we clobber the existing ref, we still want that ref - # as our parent: - if (my $cur = eval { file_to_s("$GIT_DIR/refs/remotes/$GIT_SVN") }) { - push @tmp_parents, $cur; - } - - if (exists $tree_map{$tree}) { - foreach my $p (@{$tree_map{$tree}}) { - my $skip; - foreach (@tmp_parents) { - # see if a common parent is found - my $mb = eval { - safe_qx('git-merge-base', $_, $p) - }; - next if ($@ || $?); - $skip = 1; - last; - } - next if $skip; - my ($url_p, $r_p, $uuid_p) = cmt_metadata($p); - next if (($SVN_UUID eq $uuid_p) && - ($log_msg->{revision} > $r_p)); - next if (defined $url_p && defined $SVN_URL && - ($SVN_UUID eq $uuid_p) && - ($url_p eq $SVN_URL)); - push @tmp_parents, $p; - } - } - foreach (@tmp_parents) { - next if $seen_parent{$_}; - $seen_parent{$_} = 1; - push @exec_parents, $_; - # MAXPARENT is defined to 16 in commit-tree.c: - last if @exec_parents > 16; - } - - set_commit_env($log_msg); - my @exec = ('git-commit-tree', $tree); - push @exec, '-p', $_ foreach @exec_parents; - defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec)) - or croak $!; - print $msg_fh $log_msg->{msg} or croak $!; - unless ($_no_metadata) { - print $msg_fh "\ngit-svn-id: $SVN_URL\@$log_msg->{revision}", - " $SVN_UUID\n" or croak $!; - } - $msg_fh->flush == 0 or croak $!; - close $msg_fh or croak $!; - chomp(my $commit = do { local $/; <$out_fh> }); - close $out_fh or croak $!; - waitpid $pid, 0; - croak $? if $?; - if ($commit !~ /^$sha1$/o) { - die "Failed to commit, invalid sha1: $commit\n"; - } - sys('git-update-ref',"refs/remotes/$GIT_SVN",$commit); - revdb_set($REVDB, $log_msg->{revision}, $commit); - - # this output is read via pipe, do not change: - print "r$log_msg->{revision} = $commit\n"; - check_repack(); - return $commit; -} - -sub check_repack { - if ($_repack && (--$_repack_nr == 0)) { - $_repack_nr = $_repack; - sys("git repack $_repack_flags"); - } -} - -sub set_commit_env { - my ($log_msg) = @_; - my $author = $log_msg->{author}; - if (!defined $author || length $author == 0) { - $author = '(no author)'; - } - my ($name,$email) = defined $users{$author} ? @{$users{$author}} - : ($author,"$author\@$SVN_UUID"); - $ENV{GIT_AUTHOR_NAME} = $ENV{GIT_COMMITTER_NAME} = $name; - $ENV{GIT_AUTHOR_EMAIL} = $ENV{GIT_COMMITTER_EMAIL} = $email; - $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_msg->{date}; -} - -sub apply_mod_line_blob { - my $m = shift; - if ($m->{mode_b} =~ /^120/) { - blob_to_symlink($m->{sha1_b}, $m->{file_b}); - } else { - blob_to_file($m->{sha1_b}, $m->{file_b}); - } -} - -sub blob_to_symlink { - my ($blob, $link) = @_; - defined $link or croak "\$link not defined!\n"; - croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o; - if (-l $link || -f _) { - unlink $link or croak $!; - } - - my $dest = `git-cat-file blob $blob`; # no newline, so no chomp - symlink $dest, $link or croak $!; -} - -sub blob_to_file { - my ($blob, $file) = @_; - defined $file or croak "\$file not defined!\n"; - croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o; - if (-l $file || -f _) { - unlink $file or croak $!; - } - - open my $blob_fh, '>', $file or croak "$!: $file\n"; - my $pid = fork; - defined $pid or croak $!; - - if ($pid == 0) { - open STDOUT, '>&', $blob_fh or croak $!; - exec('git-cat-file','blob',$blob) or croak $!; - } - waitpid $pid, 0; - croak $? if $?; - - close $blob_fh or croak $!; -} - -sub safe_qx { - my $pid = open my $child, '-|'; - defined $pid or croak $!; - if ($pid == 0) { - exec(@_) or croak $!; - } - my @ret = (<$child>); - close $child or croak $?; - die $? if $?; # just in case close didn't error out - return wantarray ? @ret : join('',@ret); -} - -sub svn_compat_check { - if ($_follow_parent) { - print STDERR 'E: --follow-parent functionality is only ', - "available when SVN libraries are used\n"; - exit 1; - } - my @co_help = safe_qx(qw(svn co -h)); - unless (grep /ignore-externals/,@co_help) { - print STDERR "W: Installed svn version does not support ", - "--ignore-externals\n"; - $_no_ignore_ext = 1; - } - if (grep /usage: checkout URL\[\@REV\]/,@co_help) { - $_svn_co_url_revs = 1; - } - if (grep /\[TARGET\[\@REV\]\.\.\.\]/, `svn propget -h`) { - $_svn_pg_peg_revs = 1; - } - - # I really, really hope nobody hits this... - unless (grep /stop-on-copy/, (safe_qx(qw(svn log -h)))) { - print STDERR <<''; -W: The installed svn version does not support the --stop-on-copy flag in - the log command. - Lets hope the directory you're tracking is not a branch or tag - and was never moved within the repository... - - $_no_stop_copy = 1; - } -} - -# *sigh*, new versions of svn won't honor -r without URL@, -# (and they won't honor URL@ without -r, too!) -sub svn_cmd_checkout { - my ($url, $rev, $dir) = @_; - my @cmd = ('svn','co', "-r$rev"); - push @cmd, '--ignore-externals' unless $_no_ignore_ext; - $url .= "\@$rev" if $_svn_co_url_revs; - sys(@cmd, $url, $dir); -} - -sub check_upgrade_needed { - if (!-r $REVDB) { - -d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]); - open my $fh, '>>',$REVDB or croak $!; - close $fh; - } - my $old = eval { - my $pid = open my $child, '-|'; - defined $pid or croak $!; - if ($pid == 0) { - close STDERR; - exec('git-rev-parse',"$GIT_SVN-HEAD") or croak $!; - } - my @ret = (<$child>); - close $child or croak $?; - die $? if $?; # just in case close didn't error out - return wantarray ? @ret : join('',@ret); - }; - return unless $old; - my $head = eval { safe_qx('git-rev-parse',"refs/remotes/$GIT_SVN") }; - if ($@ || !$head) { - print STDERR "Please run: $0 rebuild --upgrade\n"; - exit 1; - } -} - -# fills %tree_map with a reverse mapping of trees to commits. Useful -# for finding parents to commit on. -sub map_tree_joins { - my %seen; - foreach my $br (@_branch_from) { - my $pid = open my $pipe, '-|'; - defined $pid or croak $!; - if ($pid == 0) { - exec(qw(git-rev-list --topo-order --pretty=raw), $br) - or croak $!; - } - while (<$pipe>) { - if (/^commit ($sha1)$/o) { - my $commit = $1; - - # if we've seen a commit, - # we've seen its parents - last if $seen{$commit}; - my ($tree) = (<$pipe> =~ /^tree ($sha1)$/o); - unless (defined $tree) { - die "Failed to parse commit $commit\n"; - } - push @{$tree_map{$tree}}, $commit; - $seen{$commit} = 1; - } - } - close $pipe; # we could be breaking the pipe early - } -} - -sub load_all_refs { - if (@_branch_from) { - print STDERR '--branch|-b parameters are ignored when ', - "--branch-all-refs|-B is passed\n"; - } - - # don't worry about rev-list on non-commit objects/tags, - # it shouldn't blow up if a ref is a blob or tree... - chomp(@_branch_from = `git-rev-parse --symbolic --all`); -} - -# ' = real-name ' mapping based on git-svnimport: -sub load_authors { - open my $authors, '<', $_authors or die "Can't open $_authors $!\n"; - while (<$authors>) { - chomp; - next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; - my ($user, $name, $email) = ($1, $2, $3); - $users{$user} = [$name, $email]; - } - close $authors or croak $!; -} - -sub rload_authors { - open my $authors, '<', $_authors or die "Can't open $_authors $!\n"; - while (<$authors>) { - chomp; - next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; - my ($user, $name, $email) = ($1, $2, $3); - $rusers{"$name <$email>"} = $user; - } - close $authors or croak $!; -} - -sub svn_propget_base { - my ($p, $f) = @_; - $f .= '@BASE' if $_svn_pg_peg_revs; - return safe_qx(qw/svn propget/, $p, $f); -} - -sub git_svn_each { - my $sub = shift; - foreach (`git-rev-parse --symbolic --all`) { - next unless s#^refs/remotes/##; - chomp $_; - next unless -f "$GIT_DIR/svn/$_/info/url"; - &$sub($_); - } -} - -sub migrate_revdb { - git_svn_each(sub { - my $id = shift; - defined(my $pid = fork) or croak $!; - if (!$pid) { - $GIT_SVN = $ENV{GIT_SVN_ID} = $id; - init_vars(); - exit 0 if -r $REVDB; - print "Upgrading svn => git mapping...\n"; - -d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]); - open my $fh, '>>',$REVDB or croak $!; - close $fh; - rebuild(); - print "Done upgrading. You may now delete the ", - "deprecated $GIT_SVN_DIR/revs directory\n"; - exit 0; - } - waitpid $pid, 0; - croak $? if $?; - }); -} - -sub migration_check { - migrate_revdb() unless (-e $REVDB); - return if (-d "$GIT_DIR/svn" || !-d $GIT_DIR); - print "Upgrading repository...\n"; - unless (-d "$GIT_DIR/svn") { - mkdir "$GIT_DIR/svn" or croak $!; - } - print "Data from a previous version of git-svn exists, but\n\t", - "$GIT_SVN_DIR\n\t(required for this version ", - "($VERSION) of git-svn) does not.\n"; - - foreach my $x (`git-rev-parse --symbolic --all`) { - next unless $x =~ s#^refs/remotes/##; - chomp $x; - next unless -f "$GIT_DIR/$x/info/url"; - my $u = eval { file_to_s("$GIT_DIR/$x/info/url") }; - next unless $u; - my $dn = dirname("$GIT_DIR/svn/$x"); - mkpath([$dn]) unless -d $dn; - rename "$GIT_DIR/$x", "$GIT_DIR/svn/$x" or croak "$!: $x"; - } - migrate_revdb() if (-d $GIT_SVN_DIR && !-w $REVDB); - print "Done upgrading.\n"; -} - -sub find_rev_before { - my ($r, $id, $eq_ok) = @_; - my $f = "$GIT_DIR/svn/$id/.rev_db"; - return (undef,undef) unless -r $f; - --$r unless $eq_ok; - while ($r > 0) { - if (my $c = revdb_get($f, $r)) { - return ($r, $c); - } - --$r; - } - return (undef, undef); -} - -sub init_vars { - $GIT_SVN ||= $ENV{GIT_SVN_ID} || 'git-svn'; - $GIT_SVN_DIR = "$GIT_DIR/svn/$GIT_SVN"; - $REVDB = "$GIT_SVN_DIR/.rev_db"; - $GIT_SVN_INDEX = "$GIT_SVN_DIR/index"; - $SVN_URL = undef; - $SVN_WC = "$GIT_SVN_DIR/tree"; - %tree_map = (); -} - -# convert GetOpt::Long specs for use by git-repo-config -sub read_repo_config { - return unless -d $GIT_DIR; - my $opts = shift; - foreach my $o (keys %$opts) { - my $v = $opts->{$o}; - my ($key) = ($o =~ /^([a-z\-]+)/); - $key =~ s/-//g; - my $arg = 'git-repo-config'; - $arg .= ' --int' if ($o =~ /[:=]i$/); - $arg .= ' --bool' if ($o !~ /[:=][sfi]$/); - if (ref $v eq 'ARRAY') { - chomp(my @tmp = `$arg --get-all svn.$key`); - @$v = @tmp if @tmp; - } else { - chomp(my $tmp = `$arg --get svn.$key`); - if ($tmp && !($arg =~ / --bool / && $tmp eq 'false')) { - $$v = $tmp; - } - } - } -} - -sub set_default_vals { - if (defined $_repack) { - $_repack = 1000 if ($_repack <= 0); - $_repack_nr = $_repack; - $_repack_flags ||= '-d'; - } -} - -sub read_grafts { - my $gr_file = shift; - my ($grafts, $comments) = ({}, {}); - if (open my $fh, '<', $gr_file) { - my @tmp; - while (<$fh>) { - if (/^($sha1)\s+/) { - my $c = $1; - if (@tmp) { - @{$comments->{$c}} = @tmp; - @tmp = (); - } - foreach my $p (split /\s+/, $_) { - $grafts->{$c}->{$p} = 1; - } - } else { - push @tmp, $_; - } - } - close $fh or croak $!; - @{$comments->{'END'}} = @tmp if @tmp; - } - return ($grafts, $comments); -} - -sub write_grafts { - my ($grafts, $comments, $gr_file) = @_; - - open my $fh, '>', $gr_file or croak $!; - foreach my $c (sort keys %$grafts) { - if ($comments->{$c}) { - print $fh $_ foreach @{$comments->{$c}}; - } - my $p = $grafts->{$c}; - my %x; # real parents - delete $p->{$c}; # commits are not self-reproducing... - my $pid = open my $ch, '-|'; - defined $pid or croak $!; - if (!$pid) { - exec(qw/git-cat-file commit/, $c) or croak $!; - } - while (<$ch>) { - if (/^parent ($sha1)/) { - $x{$1} = $p->{$1} = 1; - } else { - last unless /^\S/; - } - } - close $ch; # breaking the pipe - - # if real parents are the only ones in the grafts, drop it - next if join(' ',sort keys %$p) eq join(' ',sort keys %x); - - my (@ip, @jp, $mb); - my %del = %x; - @ip = @jp = keys %$p; - foreach my $i (@ip) { - next if $del{$i} || $p->{$i} == 2; - foreach my $j (@jp) { - next if $i eq $j || $del{$j} || $p->{$j} == 2; - $mb = eval { safe_qx('git-merge-base',$i,$j) }; - next unless $mb; - chomp $mb; - next if $x{$mb}; - if ($mb eq $j) { - delete $p->{$i}; - $del{$i} = 1; - } elsif ($mb eq $i) { - delete $p->{$j}; - $del{$j} = 1; - } - } - } - - # if real parents are the only ones in the grafts, drop it - next if join(' ',sort keys %$p) eq join(' ',sort keys %x); - - print $fh $c, ' ', join(' ', sort keys %$p),"\n"; - } - if ($comments->{'END'}) { - print $fh $_ foreach @{$comments->{'END'}}; - } - close $fh or croak $!; -} - -sub read_url_paths_all { - my ($l_map, $pfx, $p) = @_; - my @dir; - foreach (<$p/*>) { - if (-r "$_/info/url") { - $pfx .= '/' if $pfx && $pfx !~ m!/$!; - my $id = $pfx . basename $_; - my $url = file_to_s("$_/info/url"); - my ($u, $p) = repo_path_split($url); - $l_map->{$u}->{$p} = $id; - } elsif (-d $_) { - push @dir, $_; - } - } - foreach (@dir) { - my $x = $_; - $x =~ s!^\Q$GIT_DIR\E/svn/!!o; - read_url_paths_all($l_map, $x, $_); - } -} - -# this one only gets ids that have been imported, not new ones -sub read_url_paths { - my $l_map = {}; - git_svn_each(sub { my $x = shift; - my $url = file_to_s("$GIT_DIR/svn/$x/info/url"); - my ($u, $p) = repo_path_split($url); - $l_map->{$u}->{$p} = $x; - }); - return $l_map; -} - -sub extract_metadata { - my $id = shift or return (undef, undef, undef); - my ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\s(\S+?)\@(\d+) - \s([a-f\d\-]+)$/x); - if (!$rev || !$uuid || !$url) { - # some of the original repositories I made had - # indentifiers like this: - ($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)\@([a-f\d\-]+)/); - } - return ($url, $rev, $uuid); -} - -sub cmt_metadata { - return extract_metadata((grep(/^git-svn-id: /, - safe_qx(qw/git-cat-file commit/, shift)))[-1]); -} - -sub get_commit_time { - my $cmt = shift; - defined(my $pid = open my $fh, '-|') or croak $!; - if (!$pid) { - exec qw/git-rev-list --pretty=raw -n1/, $cmt or croak $!; - } - while (<$fh>) { - /^committer\s(?:.+) (\d+) ([\-\+]?\d+)$/ or next; - my ($s, $tz) = ($1, $2); - if ($tz =~ s/^\+//) { - $s += tz_to_s_offset($tz); - } elsif ($tz =~ s/^\-//) { - $s -= tz_to_s_offset($tz); - } - close $fh; - return $s; - } - die "Can't get commit time for commit: $cmt\n"; -} - -sub tz_to_s_offset { - my ($tz) = @_; - $tz =~ s/(\d\d)$//; - return ($1 * 60) + ($tz * 3600); -} - -sub setup_pager { # translated to Perl from pager.c - return unless (-t *STDOUT); - my $pager = $ENV{PAGER}; - if (!defined $pager) { - $pager = 'less'; - } elsif (length $pager == 0 || $pager eq 'cat') { - return; - } - pipe my $rfd, my $wfd or return; - defined(my $pid = fork) or croak $!; - if (!$pid) { - open STDOUT, '>&', $wfd or croak $!; - return; - } - open STDIN, '<&', $rfd or croak $!; - $ENV{LESS} ||= '-S'; - exec $pager or croak "Can't run pager: $!\n";; -} - -sub get_author_info { - my ($dest, $author, $t, $tz) = @_; - $author =~ s/(?:^\s*|\s*$)//g; - $dest->{a_raw} = $author; - my $_a; - if ($_authors) { - $_a = $rusers{$author} || undef; - } - if (!$_a) { - ($_a) = ($author =~ /<([^>]+)\@[^>]+>$/); - } - $dest->{t} = $t; - $dest->{tz} = $tz; - $dest->{a} = $_a; - # Date::Parse isn't in the standard Perl distro :( - if ($tz =~ s/^\+//) { - $t += tz_to_s_offset($tz); - } elsif ($tz =~ s/^\-//) { - $t -= tz_to_s_offset($tz); - } - $dest->{t_utc} = $t; -} - -sub process_commit { - my ($c, $r_min, $r_max, $defer) = @_; - if (defined $r_min && defined $r_max) { - if ($r_min == $c->{r} && $r_min == $r_max) { - show_commit($c); - return 0; - } - return 1 if $r_min == $r_max; - if ($r_min < $r_max) { - # we need to reverse the print order - return 0 if (defined $_limit && --$_limit < 0); - push @$defer, $c; - return 1; - } - if ($r_min != $r_max) { - return 1 if ($r_min < $c->{r}); - return 1 if ($r_max > $c->{r}); - } - } - return 0 if (defined $_limit && --$_limit < 0); - show_commit($c); - return 1; -} - -sub show_commit { - my $c = shift; - if ($_oneline) { - my $x = "\n"; - if (my $l = $c->{l}) { - while ($l->[0] =~ /^\s*$/) { shift @$l } - $x = $l->[0]; - } - $_l_fmt ||= 'A' . length($c->{r}); - print 'r',pack($_l_fmt, $c->{r}),' | '; - print "$c->{c} | " if $_show_commit; - print $x; - } else { - show_commit_normal($c); - } -} - -sub show_commit_normal { - my ($c) = @_; - print '-' x72, "\nr$c->{r} | "; - print "$c->{c} | " if $_show_commit; - print "$c->{a} | ", strftime("%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)", - localtime($c->{t_utc})), ' | '; - my $nr_line = 0; - - if (my $l = $c->{l}) { - while ($l->[$#$l] eq "\n" && $l->[($#$l - 1)] eq "\n") { - pop @$l; - } - $nr_line = scalar @$l; - if (!$nr_line) { - print "1 line\n\n\n"; - } else { - if ($nr_line == 1) { - $nr_line = '1 line'; - } else { - $nr_line .= ' lines'; - } - print $nr_line, "\n\n"; - print $_ foreach @$l; - } - } else { - print "1 line\n\n"; - - } - foreach my $x (qw/raw diff/) { - if ($c->{$x}) { - print "\n"; - print $_ foreach @{$c->{$x}} - } - } -} - -sub libsvn_load { - return unless $_use_lib; - $_use_lib = eval { - require SVN::Core; - if ($SVN::Core::VERSION lt '1.1.0') { - die "Need SVN::Core 1.1.0 or better ", - "(got $SVN::Core::VERSION) ", - "Falling back to command-line svn\n"; - } - require SVN::Ra; - require SVN::Delta; - push @SVN::Git::Editor::ISA, 'SVN::Delta::Editor'; - my $kill_stupid_warnings = $SVN::Node::none.$SVN::Node::file. - $SVN::Node::dir.$SVN::Node::unknown. - $SVN::Node::none.$SVN::Node::file. - $SVN::Node::dir.$SVN::Node::unknown; - 1; - }; -} - -sub libsvn_connect { - my ($url) = @_; - my $auth = SVN::Core::auth_open([SVN::Client::get_simple_provider(), - SVN::Client::get_ssl_server_trust_file_provider(), - SVN::Client::get_username_provider()]); - my $s = eval { SVN::Ra->new(url => $url, auth => $auth) }; - return $s; -} - -sub libsvn_get_file { - my ($gui, $f, $rev) = @_; - my $p = $f; - return unless ($p =~ s#^\Q$SVN_PATH\E/##); - - my ($hash, $pid, $in, $out); - my $pool = SVN::Pool->new; - defined($pid = open3($in, $out, '>&STDERR', - qw/git-hash-object -w --stdin/)) or croak $!; - # redirect STDOUT for SVN 1.1.x compatibility - open my $stdout, '>&', \*STDOUT or croak $!; - open STDOUT, '>&', $in or croak $!; - my ($r, $props) = $SVN->get_file($f, $rev, \*STDOUT, $pool); - $in->flush == 0 or croak $!; - open STDOUT, '>&', $stdout or croak $!; - close $in or croak $!; - close $stdout or croak $!; - $pool->clear; - chomp($hash = do { local $/; <$out> }); - close $out or croak $!; - waitpid $pid, 0; - $hash =~ /^$sha1$/o or die "not a sha1: $hash\n"; - - my $mode = exists $props->{'svn:executable'} ? '100755' : '100644'; - if (exists $props->{'svn:special'}) { - $mode = '120000'; - my $link = `git-cat-file blob $hash`; - $link =~ s/^link // or die "svn:special file with contents: <", - $link, "> is not understood\n"; - defined($pid = open3($in, $out, '>&STDERR', - qw/git-hash-object -w --stdin/)) or croak $!; - print $in $link; - $in->flush == 0 or croak $!; - close $in or croak $!; - chomp($hash = do { local $/; <$out> }); - close $out or croak $!; - waitpid $pid, 0; - $hash =~ /^$sha1$/o or die "not a sha1: $hash\n"; - } - print $gui $mode,' ',$hash,"\t",$p,"\0" or croak $!; -} - -sub libsvn_log_entry { - my ($rev, $author, $date, $msg, $parents) = @_; - my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T - (\d\d)\:(\d\d)\:(\d\d).\d+Z$/x) - or die "Unable to parse date: $date\n"; - if (defined $_authors && ! defined $users{$author}) { - die "Author: $author not defined in $_authors file\n"; - } - return { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S", - author => $author, msg => $msg."\n", parents => $parents || [] } -} - -sub process_rm { - my ($gui, $last_commit, $f) = @_; - $f =~ s#^\Q$SVN_PATH\E/?## or return; - # remove entire directories. - if (safe_qx('git-ls-tree',$last_commit,'--',$f) =~ /^040000 tree/) { - defined(my $pid = open my $ls, '-|') or croak $!; - if (!$pid) { - exec(qw/git-ls-tree -r --name-only -z/, - $last_commit,'--',$f) or croak $!; - } - local $/ = "\0"; - while (<$ls>) { - print $gui '0 ',0 x 40,"\t",$_ or croak $!; - } - close $ls or croak $?; - } else { - print $gui '0 ',0 x 40,"\t",$f,"\0" or croak $!; - } -} - -sub libsvn_fetch { - my ($last_commit, $paths, $rev, $author, $date, $msg) = @_; - open my $gui, '| git-update-index -z --index-info' or croak $!; - my @amr; - foreach my $f (keys %$paths) { - my $m = $paths->{$f}->action(); - $f =~ s#^/+##; - if ($m =~ /^[DR]$/) { - print "\t$m\t$f\n" unless $_q; - process_rm($gui, $last_commit, $f); - next if $m eq 'D'; - # 'R' can be file replacements, too, right? - } - my $pool = SVN::Pool->new; - my $t = $SVN->check_path($f, $rev, $pool); - if ($t == $SVN::Node::file) { - if ($m =~ /^[AMR]$/) { - push @amr, [ $m, $f ]; - } else { - die "Unrecognized action: $m, ($f r$rev)\n"; - } - } - $pool->clear; - } - foreach (@amr) { - print "\t$_->[0]\t$_->[1]\n" unless $_q; - libsvn_get_file($gui, $_->[1], $rev) - } - close $gui or croak $?; - return libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]); -} - -sub svn_grab_base_rev { - defined(my $pid = open my $fh, '-|') or croak $!; - if (!$pid) { - open my $null, '>', '/dev/null' or croak $!; - open STDERR, '>&', $null or croak $!; - exec qw/git-rev-parse --verify/,"refs/remotes/$GIT_SVN^0" - or croak $!; - } - chomp(my $c = do { local $/; <$fh> }); - close $fh; - if (defined $c && length $c) { - my ($url, $rev, $uuid) = cmt_metadata($c); - return ($rev, $c) if defined $rev; - } - if ($_no_metadata) { - my $offset = -41; # from tail - my $rl; - open my $fh, '<', $REVDB or - die "--no-metadata specified and $REVDB not readable\n"; - seek $fh, $offset, 2; - $rl = readline $fh; - defined $rl or return (undef, undef); - chomp $rl; - while ($c ne $rl && tell $fh != 0) { - $offset -= 41; - seek $fh, $offset, 2; - $rl = readline $fh; - defined $rl or return (undef, undef); - chomp $rl; - } - my $rev = tell $fh; - croak $! if ($rev < -1); - $rev = ($rev - 41) / 41; - close $fh or croak $!; - return ($rev, $c); - } - return (undef, undef); -} - -sub libsvn_parse_revision { - my $base = shift; - my $head = $SVN->get_latest_revnum(); - if (!defined $_revision || $_revision eq 'BASE:HEAD') { - return ($base + 1, $head) if (defined $base); - return (0, $head); - } - return ($1, $2) if ($_revision =~ /^(\d+):(\d+)$/); - return ($_revision, $_revision) if ($_revision =~ /^\d+$/); - if ($_revision =~ /^BASE:(\d+)$/) { - return ($base + 1, $1) if (defined $base); - return (0, $head); - } - return ($1, $head) if ($_revision =~ /^(\d+):HEAD$/); - die "revision argument: $_revision not understood by git-svn\n", - "Try using the command-line svn client instead\n"; -} - -sub libsvn_traverse { - my ($gui, $pfx, $path, $rev) = @_; - my $cwd = "$pfx/$path"; - my $pool = SVN::Pool->new; - $cwd =~ s#^/+##g; - my ($dirent, $r, $props) = $SVN->get_dir($cwd, $rev, $pool); - foreach my $d (keys %$dirent) { - my $t = $dirent->{$d}->kind; - if ($t == $SVN::Node::dir) { - libsvn_traverse($gui, $cwd, $d, $rev); - } elsif ($t == $SVN::Node::file) { - print "\tA\t$cwd/$d\n" unless $_q; - libsvn_get_file($gui, "$cwd/$d", $rev); - } - } - $pool->clear; -} - -sub libsvn_traverse_ignore { - my ($fh, $path, $r) = @_; - $path =~ s#^/+##g; - my $pool = SVN::Pool->new; - my ($dirent, undef, $props) = $SVN->get_dir($path, $r, $pool); - my $p = $path; - $p =~ s#^\Q$SVN_PATH\E/?##; - print $fh length $p ? "\n# $p\n" : "\n# /\n"; - if (my $s = $props->{'svn:ignore'}) { - $s =~ s/[\r\n]+/\n/g; - chomp $s; - if (length $p == 0) { - $s =~ s#\n#\n/$p#g; - print $fh "/$s\n"; - } else { - $s =~ s#\n#\n/$p/#g; - print $fh "/$p/$s\n"; - } - } - foreach (sort keys %$dirent) { - next if $dirent->{$_}->kind != $SVN::Node::dir; - libsvn_traverse_ignore($fh, "$path/$_", $r); - } - $pool->clear; -} - -sub revisions_eq { - my ($path, $r0, $r1) = @_; - return 1 if $r0 == $r1; - my $nr = 0; - if ($_use_lib) { - # should be OK to use Pool here (r1 - r0) should be small - my $pool = SVN::Pool->new; - libsvn_get_log($SVN, "/$path", $r0, $r1, - 0, 1, 1, sub {$nr++}, $pool); - $pool->clear; - } else { - my ($url, undef) = repo_path_split($SVN_URL); - my $svn_log = svn_log_raw("$url/$path","-r$r0:$r1"); - while (next_log_entry($svn_log)) { $nr++ } - close $svn_log->{fh}; - } - return 0 if ($nr > 1); - return 1; -} - -sub libsvn_find_parent_branch { - my ($paths, $rev, $author, $date, $msg) = @_; - my $svn_path = '/'.$SVN_PATH; - - # look for a parent from another branch: - my $i = $paths->{$svn_path} or return; - my $branch_from = $i->copyfrom_path or return; - my $r = $i->copyfrom_rev; - print STDERR "Found possible branch point: ", - "$branch_from => $svn_path, $r\n"; - $branch_from =~ s#^/##; - my $l_map = {}; - read_url_paths_all($l_map, '', "$GIT_DIR/svn"); - my $url = $SVN->{url}; - defined $l_map->{$url} or return; - my $id = $l_map->{$url}->{$branch_from}; - if (!defined $id && $_follow_parent) { - print STDERR "Following parent: $branch_from\@$r\n"; - # auto create a new branch and follow it - $id = basename($branch_from); - $id .= '@'.$r if -r "$GIT_DIR/svn/$id"; - while (-r "$GIT_DIR/svn/$id") { - # just grow a tail if we're not unique enough :x - $id .= '-'; - } - } - return unless defined $id; - - my ($r0, $parent) = find_rev_before($r,$id,1); - if ($_follow_parent && (!defined $r0 || !defined $parent)) { - defined(my $pid = fork) or croak $!; - if (!$pid) { - $GIT_SVN = $ENV{GIT_SVN_ID} = $id; - init_vars(); - $SVN_URL = "$url/$branch_from"; - $SVN_LOG = $SVN = undef; - setup_git_svn(); - # we can't assume SVN_URL exists at r+1: - $_revision = "0:$r"; - fetch_lib(); - exit 0; - } - waitpid $pid, 0; - croak $? if $?; - ($r0, $parent) = find_rev_before($r,$id,1); - } - return unless (defined $r0 && defined $parent); - if (revisions_eq($branch_from, $r0, $r)) { - unlink $GIT_SVN_INDEX; - print STDERR "Found branch parent: ($GIT_SVN) $parent\n"; - sys(qw/git-read-tree/, $parent); - return libsvn_fetch($parent, $paths, $rev, - $author, $date, $msg); - } - print STDERR "Nope, branch point not imported or unknown\n"; - return undef; -} - -sub libsvn_get_log { - my ($ra, @args) = @_; - if ($SVN::Core::VERSION le '1.2.0') { - splice(@args, 3, 1); - } - $ra->get_log(@args); -} - -sub libsvn_new_tree { - if (my $log_entry = libsvn_find_parent_branch(@_)) { - return $log_entry; - } - my ($paths, $rev, $author, $date, $msg) = @_; - open my $gui, '| git-update-index -z --index-info' or croak $!; - my $pool = SVN::Pool->new; - libsvn_traverse($gui, '', $SVN_PATH, $rev, $pool); - $pool->clear; - close $gui or croak $?; - return libsvn_log_entry($rev, $author, $date, $msg); -} - -sub find_graft_path_commit { - my ($tree_paths, $p1, $r1) = @_; - foreach my $x (keys %$tree_paths) { - next unless ($p1 =~ /^\Q$x\E/); - my $i = $tree_paths->{$x}; - my ($r0, $parent) = find_rev_before($r1,$i,1); - return $parent if (defined $r0 && $r0 == $r1); - print STDERR "r$r1 of $i not imported\n"; - next; - } - return undef; -} - -sub find_graft_path_parents { - my ($grafts, $tree_paths, $c, $p0, $r0) = @_; - foreach my $x (keys %$tree_paths) { - next unless ($p0 =~ /^\Q$x\E/); - my $i = $tree_paths->{$x}; - my ($r, $parent) = find_rev_before($r0, $i, 1); - if (defined $r && defined $parent && revisions_eq($x,$r,$r0)) { - my ($url_b, undef, $uuid_b) = cmt_metadata($c); - my ($url_a, undef, $uuid_a) = cmt_metadata($parent); - next if ($url_a && $url_b && $url_a eq $url_b && - $uuid_b eq $uuid_a); - $grafts->{$c}->{$parent} = 1; - } - } -} - -sub libsvn_graft_file_copies { - my ($grafts, $tree_paths, $path, $paths, $rev) = @_; - foreach (keys %$paths) { - my $i = $paths->{$_}; - my ($m, $p0, $r0) = ($i->action, $i->copyfrom_path, - $i->copyfrom_rev); - next unless (defined $p0 && defined $r0); - - my $p1 = $_; - $p1 =~ s#^/##; - $p0 =~ s#^/##; - my $c = find_graft_path_commit($tree_paths, $p1, $rev); - next unless $c; - find_graft_path_parents($grafts, $tree_paths, $c, $p0, $r0); - } -} - -sub set_index { - my $old = $ENV{GIT_INDEX_FILE}; - $ENV{GIT_INDEX_FILE} = shift; - return $old; -} - -sub restore_index { - my ($old) = @_; - if (defined $old) { - $ENV{GIT_INDEX_FILE} = $old; - } else { - delete $ENV{GIT_INDEX_FILE}; - } -} - -sub libsvn_commit_cb { - my ($rev, $date, $committer, $c, $msg, $r_last, $cmt_last) = @_; - if ($_optimize_commits && $rev == ($r_last + 1)) { - my $log = libsvn_log_entry($rev,$committer,$date,$msg); - $log->{tree} = get_tree_from_treeish($c); - my $cmt = git_commit($log, $cmt_last, $c); - my @diff = safe_qx('git-diff-tree', $cmt, $c); - if (@diff) { - print STDERR "Trees differ: $cmt $c\n", - join('',@diff),"\n"; - exit 1; - } - } else { - fetch("$rev=$c"); - } -} - -sub libsvn_ls_fullurl { - my $fullurl = shift; - my ($repo, $path) = repo_path_split($fullurl); - $SVN ||= libsvn_connect($repo); - my @ret; - my $pool = SVN::Pool->new; - my ($dirent, undef, undef) = $SVN->get_dir($path, - $SVN->get_latest_revnum, $pool); - foreach my $d (keys %$dirent) { - if ($dirent->{$d}->kind == $SVN::Node::dir) { - push @ret, "$d/"; # add '/' for compat with cli svn - } - } - $pool->clear; - return @ret; -} - - -sub libsvn_skip_unknown_revs { - my $err = shift; - my $errno = $err->apr_err(); - # Maybe the branch we're tracking didn't - # exist when the repo started, so it's - # not an error if it doesn't, just continue - # - # Wonderfully consistent library, eh? - # 160013 - svn:// and file:// - # 175002 - http(s):// - # More codes may be discovered later... - if ($errno == 175002 || $errno == 160013) { - return; - } - croak "Error from SVN, ($errno): ", $err->expanded_message,"\n"; -}; - -# Tie::File seems to be prone to offset errors if revisions get sparse, -# it's not that fast, either. Tie::File is also not in Perl 5.6. So -# one of my favorite modules is out :< Next up would be one of the DBM -# modules, but I'm not sure which is most portable... So I'll just -# go with something that's plain-text, but still capable of -# being randomly accessed. So here's my ultra-simple fixed-width -# database. All records are 40 characters + "\n", so it's easy to seek -# to a revision: (41 * rev) is the byte offset. -# A record of 40 0s denotes an empty revision. -# And yes, it's still pretty fast (faster than Tie::File). -sub revdb_set { - my ($file, $rev, $commit) = @_; - length $commit == 40 or croak "arg3 must be a full SHA1 hexsum\n"; - open my $fh, '+<', $file or croak $!; - my $offset = $rev * 41; - # assume that append is the common case: - seek $fh, 0, 2 or croak $!; - my $pos = tell $fh; - if ($pos < $offset) { - print $fh (('0' x 40),"\n") x (($offset - $pos) / 41); - } - seek $fh, $offset, 0 or croak $!; - print $fh $commit,"\n"; - close $fh or croak $!; -} - -sub revdb_get { - my ($file, $rev) = @_; - my $ret; - my $offset = $rev * 41; - open my $fh, '<', $file or croak $!; - seek $fh, $offset, 0; - if (tell $fh == $offset) { - $ret = readline $fh; - if (defined $ret) { - chomp $ret; - $ret = undef if ($ret =~ /^0{40}$/); - } - } - close $fh or croak $!; - return $ret; -} - -sub copy_remote_ref { - my $origin = $_cp_remote ? $_cp_remote : 'origin'; - my $ref = "refs/remotes/$GIT_SVN"; - if (safe_qx('git-ls-remote', $origin, $ref)) { - sys(qw/git fetch/, $origin, "$ref:$ref"); - } else { - die "Unable to find remote reference: ", - "refs/remotes/$GIT_SVN on $origin\n"; - } -} - -package SVN::Git::Editor; -use vars qw/@ISA/; -use strict; -use warnings; -use Carp qw/croak/; -use IO::File; - -sub new { - my $class = shift; - my $git_svn = shift; - my $self = SVN::Delta::Editor->new(@_); - bless $self, $class; - foreach (qw/svn_path c r ra /) { - die "$_ required!\n" unless (defined $git_svn->{$_}); - $self->{$_} = $git_svn->{$_}; - } - $self->{pool} = SVN::Pool->new; - $self->{bat} = { '' => $self->open_root($self->{r}, $self->{pool}) }; - $self->{rm} = { }; - require Digest::MD5; - return $self; -} - -sub split_path { - return ($_[0] =~ m#^(.*?)/?([^/]+)$#); -} - -sub repo_path { - (defined $_[1] && length $_[1]) ? "$_[0]->{svn_path}/$_[1]" - : $_[0]->{svn_path} -} - -sub url_path { - my ($self, $path) = @_; - $self->{ra}->{url} . '/' . $self->repo_path($path); -} - -sub rmdirs { - my ($self, $q) = @_; - my $rm = $self->{rm}; - delete $rm->{''}; # we never delete the url we're tracking - return unless %$rm; - - foreach (keys %$rm) { - my @d = split m#/#, $_; - my $c = shift @d; - $rm->{$c} = 1; - while (@d) { - $c .= '/' . shift @d; - $rm->{$c} = 1; - } - } - delete $rm->{$self->{svn_path}}; - delete $rm->{''}; # we never delete the url we're tracking - return unless %$rm; - - defined(my $pid = open my $fh,'-|') or croak $!; - if (!$pid) { - exec qw/git-ls-tree --name-only -r -z/, $self->{c} or croak $!; - } - local $/ = "\0"; - my @svn_path = split m#/#, $self->{svn_path}; - while (<$fh>) { - chomp; - my @dn = (@svn_path, (split m#/#, $_)); - while (pop @dn) { - delete $rm->{join '/', @dn}; - } - unless (%$rm) { - close $fh; - return; - } - } - close $fh; - - my ($r, $p, $bat) = ($self->{r}, $self->{pool}, $self->{bat}); - foreach my $d (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$rm) { - $self->close_directory($bat->{$d}, $p); - my ($dn) = ($d =~ m#^(.*?)/?(?:[^/]+)$#); - print "\tD+\t/$d/\n" unless $q; - $self->SUPER::delete_entry($d, $r, $bat->{$dn}, $p); - delete $bat->{$d}; - } -} - -sub open_or_add_dir { - my ($self, $full_path, $baton) = @_; - my $p = SVN::Pool->new; - my $t = $self->{ra}->check_path($full_path, $self->{r}, $p); - $p->clear; - if ($t == $SVN::Node::none) { - return $self->add_directory($full_path, $baton, - undef, -1, $self->{pool}); - } elsif ($t == $SVN::Node::dir) { - return $self->open_directory($full_path, $baton, - $self->{r}, $self->{pool}); - } - print STDERR "$full_path already exists in repository at ", - "r$self->{r} and it is not a directory (", - ($t == $SVN::Node::file ? 'file' : 'unknown'),"/$t)\n"; - exit 1; -} - -sub ensure_path { - my ($self, $path) = @_; - my $bat = $self->{bat}; - $path = $self->repo_path($path); - return $bat->{''} unless (length $path); - my @p = split m#/+#, $path; - my $c = shift @p; - $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''}); - while (@p) { - my $c0 = $c; - $c .= '/' . shift @p; - $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0}); - } - return $bat->{$c}; -} - -sub A { - my ($self, $m, $q) = @_; - my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); - my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, - undef, -1); - print "\tA\t$m->{file_b}\n" unless $q; - $self->chg_file($fbat, $m); - $self->close_file($fbat,undef,$self->{pool}); -} - -sub C { - my ($self, $m, $q) = @_; - my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); - my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, - $self->url_path($m->{file_a}), $self->{r}); - print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $q; - $self->chg_file($fbat, $m); - $self->close_file($fbat,undef,$self->{pool}); -} - -sub delete_entry { - my ($self, $path, $pbat) = @_; - my $rpath = $self->repo_path($path); - my ($dir, $file) = split_path($rpath); - $self->{rm}->{$dir} = 1; - $self->SUPER::delete_entry($rpath, $self->{r}, $pbat, $self->{pool}); -} - -sub R { - my ($self, $m, $q) = @_; - my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); - my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, - $self->url_path($m->{file_a}), $self->{r}); - print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $q; - $self->chg_file($fbat, $m); - $self->close_file($fbat,undef,$self->{pool}); - - ($dir, $file) = split_path($m->{file_a}); - $pbat = $self->ensure_path($dir); - $self->delete_entry($m->{file_a}, $pbat); -} - -sub M { - my ($self, $m, $q) = @_; - my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); - my $fbat = $self->open_file($self->repo_path($m->{file_b}), - $pbat,$self->{r},$self->{pool}); - print "\t$m->{chg}\t$m->{file_b}\n" unless $q; - $self->chg_file($fbat, $m); - $self->close_file($fbat,undef,$self->{pool}); -} - -sub T { shift->M(@_) } - -sub change_file_prop { - my ($self, $fbat, $pname, $pval) = @_; - $self->SUPER::change_file_prop($fbat, $pname, $pval, $self->{pool}); -} - -sub chg_file { - my ($self, $fbat, $m) = @_; - if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) { - $self->change_file_prop($fbat,'svn:executable','*'); - } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { - $self->change_file_prop($fbat,'svn:executable',undef); - } - my $fh = IO::File->new_tmpfile or croak $!; - if ($m->{mode_b} =~ /^120/) { - print $fh 'link ' or croak $!; - $self->change_file_prop($fbat,'svn:special','*'); - } elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) { - $self->change_file_prop($fbat,'svn:special',undef); - } - defined(my $pid = fork) or croak $!; - if (!$pid) { - open STDOUT, '>&', $fh or croak $!; - exec qw/git-cat-file blob/, $m->{sha1_b} or croak $!; - } - waitpid $pid, 0; - croak $? if $?; - $fh->flush == 0 or croak $!; - seek $fh, 0, 0 or croak $!; - - my $md5 = Digest::MD5->new; - $md5->addfile($fh) or croak $!; - seek $fh, 0, 0 or croak $!; - - my $exp = $md5->hexdigest; - my $atd = $self->apply_textdelta($fbat, undef, $self->{pool}); - my $got = SVN::TxDelta::send_stream($fh, @$atd, $self->{pool}); - die "Checksum mismatch\nexpected: $exp\ngot: $got\n" if ($got ne $exp); - - close $fh or croak $!; -} - -sub D { - my ($self, $m, $q) = @_; - my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); - print "\tD\t$m->{file_b}\n" unless $q; - $self->delete_entry($m->{file_b}, $pbat); -} - -sub close_edit { - my ($self) = @_; - my ($p,$bat) = ($self->{pool}, $self->{bat}); - foreach (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$bat) { - $self->close_directory($bat->{$_}, $p); - } - $self->SUPER::close_edit($p); - $p->clear; -} - -sub abort_edit { - my ($self) = @_; - $self->SUPER::abort_edit($self->{pool}); - $self->{pool}->clear; -} - -__END__ - -Data structures: - -$svn_log hashref (as returned by svn_log_raw) -{ - fh => file handle of the log file, - state => state of the log file parser (sep/msg/rev/msg_start...) -} - -$log_msg hashref as returned by next_log_entry($svn_log) -{ - msg => 'whitespace-formatted log entry -', # trailing newline is preserved - revision => '8', # integer - date => '2004-02-24T17:01:44.108345Z', # commit date - author => 'committer name' -}; - - -@mods = array of diff-index line hashes, each element represents one line - of diff-index output - -diff-index line ($m hash) -{ - mode_a => first column of diff-index output, no leading ':', - mode_b => second column of diff-index output, - sha1_b => sha1sum of the final blob, - chg => change type [MCRADT], - file_a => original file name of a file (iff chg is 'C' or 'R') - file_b => new/current file name of a file (any chg) -} -; - -# retval of read_url_paths{,_all}(); -$l_map = { - # repository root url - 'https://svn.musicpd.org' => { - # repository path # GIT_SVN_ID - 'mpd/trunk' => 'trunk', - 'mpd/tags/0.11.5' => 'tags/0.11.5', - }, -} - -Notes: - I don't trust the each() function on unless I created %hash myself - because the internal iterator may not have started at base. diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt deleted file mode 100644 index f7d3de48f0..0000000000 --- a/contrib/git-svn/git-svn.txt +++ /dev/null @@ -1,319 +0,0 @@ -git-svn(1) -========== - -NAME ----- -git-svn - bidirectional operation between a single Subversion branch and git - -SYNOPSIS --------- -'git-svn' [options] [arguments] - -DESCRIPTION ------------ -git-svn is a simple conduit for changesets between a single Subversion -branch and git. - -git-svn is not to be confused with git-svnimport. The were designed -with very different goals in mind. - -git-svn is designed for an individual developer who wants a -bidirectional flow of changesets between a single branch in Subversion -and an arbitrary number of branches in git. git-svnimport is designed -for read-only operation on repositories that match a particular layout -(albeit the recommended one by SVN developers). - -For importing svn, git-svnimport is potentially more powerful when -operating on repositories organized under the recommended -trunk/branch/tags structure, and should be faster, too. - -git-svn mostly ignores the very limited view of branching that -Subversion has. This allows git-svn to be much easier to use, -especially on repositories that are not organized in a manner that -git-svnimport is designed for. - -COMMANDS --------- -init:: - Creates an empty git repository with additional metadata - directories for git-svn. The Subversion URL must be specified - as a command-line argument. - -fetch:: - Fetch unfetched revisions from the Subversion URL we are - tracking. refs/remotes/git-svn will be updated to the - latest revision. - - Note: You should never attempt to modify the remotes/git-svn - branch outside of git-svn. Instead, create a branch from - remotes/git-svn and work on that branch. Use the 'commit' - command (see below) to write git commits back to - remotes/git-svn. - - See 'Additional Fetch Arguments' if you are interested in - manually joining branches on commit. - -commit:: - Commit specified commit or tree objects to SVN. This relies on - your imported fetch data being up-to-date. This makes - absolutely no attempts to do patching when committing to SVN, it - simply overwrites files with those specified in the tree or - commit. All merging is assumed to have taken place - independently of git-svn functions. - -rebuild:: - Not a part of daily usage, but this is a useful command if - you've just cloned a repository (using git-clone) that was - tracked with git-svn. Unfortunately, git-clone does not clone - git-svn metadata and the svn working tree that git-svn uses for - its operations. This rebuilds the metadata so git-svn can - resume fetch operations. A Subversion URL may be optionally - specified at the command-line if the directory/repository you're - tracking has moved or changed protocols. - -show-ignore:: - Recursively finds and lists the svn:ignore property on - directories. The output is suitable for appending to - the $GIT_DIR/info/exclude file. - -OPTIONS -------- --r :: ---revision :: - Only used with the 'fetch' command. - - Takes any valid -r svn would accept and passes it - directly to svn. -r: ranges and "{" DATE "}" syntax - is also supported. This is passed directly to svn, see svn - documentation for more details. - - This can allow you to make partial mirrors when running fetch. - --:: ---stdin:: - Only used with the 'commit' command. - - Read a list of commits from stdin and commit them in reverse - order. Only the leading sha1 is read from each line, so - git-rev-list --pretty=oneline output can be used. - ---rmdir:: - Only used with the 'commit' command. - - Remove directories from the SVN tree if there are no files left - behind. SVN can version empty directories, and they are not - removed by default if there are no files left in them. git - cannot version empty directories. Enabling this flag will make - the commit to SVN act like git. - - repo-config key: svn.rmdir - --e:: ---edit:: - Only used with the 'commit' command. - - Edit the commit message before committing to SVN. This is off by - default for objects that are commits, and forced on when committing - tree objects. - - repo-config key: svn.edit - --l:: ---find-copies-harder:: - Both of these are only used with the 'commit' command. - - They are both passed directly to git-diff-tree see - git-diff-tree(1) for more information. - - repo-config key: svn.l - repo-config key: svn.findcopiesharder - --A:: ---authors-file=:: - - Syntax is compatible with the files used by git-svnimport and - git-cvsimport: - ------------------------------------------------------------------------- -loginname = Joe User ------------------------------------------------------------------------- - - If this option is specified and git-svn encounters an SVN - committer name that does not exist in the authors-file, git-svn - will abort operation. The user will then have to add the - appropriate entry. Re-running the previous git-svn command - after the authors-file is modified should continue operation. - - repo-config key: svn.authors-file - -ADVANCED OPTIONS ----------------- --b:: ---branch :: - Used with 'fetch' or 'commit'. - - This can be used to join arbitrary git branches to remotes/git-svn - on new commits where the tree object is equivalent. - - When used with different GIT_SVN_ID values, tags and branches in - SVN can be tracked this way, as can some merges where the heads - end up having completely equivalent content. This can even be - used to track branches across multiple SVN _repositories_. - - This option may be specified multiple times, once for each - branch. - - repo-config key: svn.branch - --i:: ---id :: - This sets GIT_SVN_ID (instead of using the environment). See - the section on "Tracking Multiple Repositories or Branches" for - more information on using GIT_SVN_ID. - -COMPATIBILITY OPTIONS ---------------------- ---upgrade:: - Only used with the 'rebuild' command. - - Run this if you used an old version of git-svn that used - "git-svn-HEAD" instead of "remotes/git-svn" as the branch - for tracking the remote. - ---no-ignore-externals:: - Only used with the 'fetch' and 'rebuild' command. - - By default, git-svn passes --ignore-externals to svn to avoid - fetching svn:external trees into git. Pass this flag to enable - externals tracking directly via git. - - Versions of svn that do not support --ignore-externals are - automatically detected and this flag will be automatically - enabled for them. - - Otherwise, do not enable this flag unless you know what you're - doing. - - repo-config key: svn.noignoreexternals - -Basic Examples -~~~~~~~~~~~~~~ - -Tracking and contributing to an Subversion managed-project: - ------------------------------------------------------------------------- -# Initialize a tree (like git init-db): - git-svn init http://svn.foo.org/project/trunk -# Fetch remote revisions: - git-svn fetch -# Create your own branch to hack on: - git checkout -b my-branch remotes/git-svn -# Commit only the git commits you want to SVN: - git-svn commit [ ...] -# Commit all the git commits from my-branch that don't exist in SVN: - git-svn commit remotes/git-svn..my-branch -# Something is committed to SVN, pull the latest into your branch: - git-svn fetch && git pull . remotes/git-svn -# Append svn:ignore settings to the default git exclude file: - git-svn show-ignore >> .git/info/exclude ------------------------------------------------------------------------- - -DESIGN PHILOSOPHY ------------------ -Merge tracking in Subversion is lacking and doing branched development -with Subversion is cumbersome as a result. git-svn completely forgoes -any automated merge/branch tracking on the Subversion side and leaves it -entirely up to the user on the git side. It's simply not worth it to do -a useful translation when the the original signal is weak. - -TRACKING MULTIPLE REPOSITORIES OR BRANCHES ------------------------------------------- -This is for advanced users, most users should ignore this section. - -Because git-svn does not care about relationships between different -branches or directories in a Subversion repository, git-svn has a simple -hack to allow it to track an arbitrary number of related _or_ unrelated -SVN repositories via one git repository. Simply set the GIT_SVN_ID -environment variable to a name other other than "git-svn" (the default) -and git-svn will ignore the contents of the $GIT_DIR/git-svn directory -and instead do all of its work in $GIT_DIR/$GIT_SVN_ID for that -invocation. The interface branch will be remotes/$GIT_SVN_ID, instead of -remotes/git-svn. Any remotes/$GIT_SVN_ID branch should never be modified -by the user outside of git-svn commands. - -ADDITIONAL FETCH ARGUMENTS --------------------------- -This is for advanced users, most users should ignore this section. - -Unfetched SVN revisions may be imported as children of existing commits -by specifying additional arguments to 'fetch'. Additional parents may -optionally be specified in the form of sha1 hex sums at the -command-line. Unfetched SVN revisions may also be tied to particular -git commits with the following syntax: - - svn_revision_number=git_commit_sha1 - -This allows you to tie unfetched SVN revision 375 to your current HEAD:: - - `git-svn fetch 375=$(git-rev-parse HEAD)` - -Advanced Example: Tracking a Reorganized Repository -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you're tracking a directory that has moved, or otherwise been -branched or tagged off of another directory in the repository and you -care about the full history of the project, then you can read this -section. - -This is how Yann Dirson tracked the trunk of the ufoai directory when -the /trunk directory of his repository was moved to /ufoai/trunk and -he needed to continue tracking /ufoai/trunk where /trunk left off. - ------------------------------------------------------------------------- - # This log message shows when the repository was reorganized: - r166 | ydirson | 2006-03-02 01:36:55 +0100 (Thu, 02 Mar 2006) | 1 line - Changed paths: - D /trunk - A /ufoai/trunk (from /trunk:165) - - # First we start tracking the old revisions: - GIT_SVN_ID=git-oldsvn git-svn init \ - https://svn.sourceforge.net/svnroot/ufoai/trunk - GIT_SVN_ID=git-oldsvn git-svn fetch -r1:165 - - # And now, we continue tracking the new revisions: - GIT_SVN_ID=git-newsvn git-svn init \ - https://svn.sourceforge.net/svnroot/ufoai/ufoai/trunk - GIT_SVN_ID=git-newsvn git-svn fetch \ - 166=`git-rev-parse refs/remotes/git-oldsvn` ------------------------------------------------------------------------- - -BUGS ----- -If somebody commits a conflicting changeset to SVN at a bad moment -(right before you commit) causing a conflict and your commit to fail, -your svn working tree ($GIT_DIR/git-svn/tree) may be dirtied. The -easiest thing to do is probably just to rm -rf $GIT_DIR/git-svn/tree and -run 'rebuild'. - -We ignore all SVN properties except svn:executable. Too difficult to -map them since we rely heavily on git write-tree being _exactly_ the -same on both the SVN and git working trees and I prefer not to clutter -working trees with metadata files. - -svn:keywords can't be ignored in Subversion (at least I don't know of -a way to ignore them). - -Renamed and copied directories are not detected by git and hence not -tracked when committing to SVN. I do not plan on adding support for -this as it's quite difficult and time-consuming to get working for all -the possible corner cases (git doesn't do it, either). Renamed and -copied files are fully supported if they're similar enough for git to -detect them. - -Author ------- -Written by Eric Wong . - -Documentation -------------- -Written by Eric Wong . diff --git a/contrib/git-svn/t/lib-git-svn.sh b/contrib/git-svn/t/lib-git-svn.sh deleted file mode 100644 index d7f972a0c8..0000000000 --- a/contrib/git-svn/t/lib-git-svn.sh +++ /dev/null @@ -1,45 +0,0 @@ -PATH=$PWD/../:$PATH -if test -d ../../../t -then - cd ../../../t -else - echo "Must be run in contrib/git-svn/t" >&2 - exit 1 -fi - -. ./test-lib.sh - -GIT_DIR=$PWD/.git -GIT_SVN_DIR=$GIT_DIR/svn/git-svn -SVN_TREE=$GIT_SVN_DIR/svn-tree - -svnadmin >/dev/null 2>&1 -if test $? != 1 -then - test_expect_success 'skipping contrib/git-svn test' : - test_done - exit -fi - -svn >/dev/null 2>&1 -if test $? != 1 -then - test_expect_success 'skipping contrib/git-svn test' : - test_done - exit -fi - -svnrepo=$PWD/svnrepo - -set -e - -if svnadmin create --help | grep fs-type >/dev/null -then - svnadmin create --fs-type fsfs "$svnrepo" -else - svnadmin create "$svnrepo" -fi - -svnrepo="file://$svnrepo/test-git-svn" - - diff --git a/contrib/git-svn/t/t0000-contrib-git-svn.sh b/contrib/git-svn/t/t0000-contrib-git-svn.sh deleted file mode 100644 index b482bb64c0..0000000000 --- a/contrib/git-svn/t/t0000-contrib-git-svn.sh +++ /dev/null @@ -1,232 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006 Eric Wong -# - -test_description='git-svn tests' -GIT_SVN_LC_ALL=$LC_ALL - -case "$LC_ALL" in -*.UTF-8) - have_utf8=t - ;; -*) - have_utf8= - ;; -esac - -. ./lib-git-svn.sh - -mkdir import -cd import - -echo foo > foo -if test -z "$NO_SYMLINK" -then - ln -s foo foo.link -fi -mkdir -p dir/a/b/c/d/e -echo 'deep dir' > dir/a/b/c/d/e/file -mkdir -p bar -echo 'zzz' > bar/zzz -echo '#!/bin/sh' > exec.sh -chmod +x exec.sh -svn import -m 'import for git-svn' . "$svnrepo" >/dev/null - -cd .. -rm -rf import - -test_expect_success \ - 'initialize git-svn' \ - "git-svn init $svnrepo" - -test_expect_success \ - 'import an SVN revision into git' \ - 'git-svn fetch' - -test_expect_success "checkout from svn" "svn co $svnrepo $SVN_TREE" - -name='try a deep --rmdir with a commit' -git checkout -f -b mybranch remotes/git-svn -mv dir/a/b/c/d/e/file dir/file -cp dir/file file -git update-index --add --remove dir/a/b/c/d/e/file dir/file file -git commit -m "$name" - -test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch && - svn up $SVN_TREE && - test -d $SVN_TREE/dir && test ! -d $SVN_TREE/dir/a" - - -name='detect node change from file to directory #1' -mkdir dir/new_file -mv dir/file dir/new_file/file -mv dir/new_file dir/file -git update-index --remove dir/file -git update-index --add dir/file/file -git commit -m "$name" - -test_expect_failure "$name" \ - 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch' \ - || true - - -name='detect node change from directory to file #1' -rm -rf dir $GIT_DIR/index -git checkout -f -b mybranch2 remotes/git-svn -mv bar/zzz zzz -rm -rf bar -mv zzz bar -git update-index --remove -- bar/zzz -git update-index --add -- bar -git commit -m "$name" - -test_expect_failure "$name" \ - 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch2' \ - || true - - -name='detect node change from file to directory #2' -rm -f $GIT_DIR/index -git checkout -f -b mybranch3 remotes/git-svn -rm bar/zzz -git-update-index --remove bar/zzz -mkdir bar/zzz -echo yyy > bar/zzz/yyy -git-update-index --add bar/zzz/yyy -git commit -m "$name" - -test_expect_failure "$name" \ - 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch3' \ - || true - - -name='detect node change from directory to file #2' -rm -f $GIT_DIR/index -git checkout -f -b mybranch4 remotes/git-svn -rm -rf dir -git update-index --remove -- dir/file -touch dir -echo asdf > dir -git update-index --add -- dir -git commit -m "$name" - -test_expect_failure "$name" \ - 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch4' \ - || true - - -name='remove executable bit from a file' -rm -f $GIT_DIR/index -git checkout -f -b mybranch5 remotes/git-svn -chmod -x exec.sh -git update-index exec.sh -git commit -m "$name" - -test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && - svn up $SVN_TREE && - test ! -x $SVN_TREE/exec.sh" - - -name='add executable bit back file' -chmod +x exec.sh -git update-index exec.sh -git commit -m "$name" - -test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && - svn up $SVN_TREE && - test -x $SVN_TREE/exec.sh" - - - -if test -z "$NO_SYMLINK" -then - name='executable file becomes a symlink to bar/zzz (file)' - rm exec.sh - ln -s bar/zzz exec.sh - git update-index exec.sh - git commit -m "$name" - - test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && - svn up $SVN_TREE && - test -L $SVN_TREE/exec.sh" - - name='new symlink is added to a file that was also just made executable' - chmod +x bar/zzz - ln -s bar/zzz exec-2.sh - git update-index --add bar/zzz exec-2.sh - git commit -m "$name" - - test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && - svn up $SVN_TREE && - test -x $SVN_TREE/bar/zzz && - test -L $SVN_TREE/exec-2.sh" - - name='modify a symlink to become a file' - git help > help || true - rm exec-2.sh - cp help exec-2.sh - git update-index exec-2.sh - git commit -m "$name" - - test_expect_success "$name" \ - "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && - svn up $SVN_TREE && - test -f $SVN_TREE/exec-2.sh && - test ! -L $SVN_TREE/exec-2.sh && - diff -u help $SVN_TREE/exec-2.sh" -fi - - -if test "$have_utf8" = t -then - name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL" - echo '# hello' >> exec-2.sh - git update-index exec-2.sh - git commit -m 'éï∏' - export LC_ALL="$GIT_SVN_LC_ALL" - test_expect_success "$name" "git-svn commit HEAD" - unset LC_ALL -else - echo "UTF-8 locale not set, test skipped ($GIT_SVN_LC_ALL)" -fi - -name='test fetch functionality (svn => git) with alternate GIT_SVN_ID' -GIT_SVN_ID=alt -export GIT_SVN_ID -test_expect_success "$name" \ - "git-svn init $svnrepo && git-svn fetch && - git-rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a && - git-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b && - diff -u a b" - -if test -n "$NO_SYMLINK" -then - test_done - exit 0 -fi - -name='check imported tree checksums expected tree checksums' -rm -f expected -if test "$have_utf8" = t -then - echo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected -fi -cat >> expected <<\EOF -tree 4b9af72bb861eaed053854ec502cf7df72618f0f -tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1 -tree 0b094cbff17168f24c302e297f55bfac65eb8bd3 -tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e -tree 56a30b966619b863674f5978696f4a3594f2fca9 -tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e -tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4 -EOF -test_expect_success "$name" "diff -u a expected" - -test_done - diff --git a/contrib/git-svn/t/t0001-contrib-git-svn-props.sh b/contrib/git-svn/t/t0001-contrib-git-svn-props.sh deleted file mode 100644 index a5a235f100..0000000000 --- a/contrib/git-svn/t/t0001-contrib-git-svn-props.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006 Eric Wong -# - -test_description='git-svn property tests' -. ./lib-git-svn.sh - -mkdir import - -a_crlf= -a_lf= -a_cr= -a_ne_crlf= -a_ne_lf= -a_ne_cr= -a_empty= -a_empty_lf= -a_empty_cr= -a_empty_crlf= - -cd import - cat >> kw.c <<\EOF -/* Somebody prematurely put a keyword into this file */ -/* $Id$ */ -EOF - - printf "Hello\r\nWorld\r\n" > crlf - a_crlf=`git-hash-object -w crlf` - printf "Hello\rWorld\r" > cr - a_cr=`git-hash-object -w cr` - printf "Hello\nWorld\n" > lf - a_lf=`git-hash-object -w lf` - - printf "Hello\r\nWorld" > ne_crlf - a_ne_crlf=`git-hash-object -w ne_crlf` - printf "Hello\nWorld" > ne_lf - a_ne_lf=`git-hash-object -w ne_lf` - printf "Hello\rWorld" > ne_cr - a_ne_cr=`git-hash-object -w ne_cr` - - touch empty - a_empty=`git-hash-object -w empty` - printf "\n" > empty_lf - a_empty_lf=`git-hash-object -w empty_lf` - printf "\r" > empty_cr - a_empty_cr=`git-hash-object -w empty_cr` - printf "\r\n" > empty_crlf - a_empty_crlf=`git-hash-object -w empty_crlf` - - svn import -m 'import for git-svn' . "$svnrepo" >/dev/null -cd .. - -rm -rf import -test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc" -test_expect_success 'setup some commits to svn' \ - 'cd test_wc && - echo Greetings >> kw.c && - svn commit -m "Not yet an Id" && - svn up && - echo Hello world >> kw.c && - svn commit -m "Modified file, but still not yet an Id" && - svn up && - svn propset svn:keywords Id kw.c && - svn commit -m "Propset Id" && - svn up && - cd ..' - -test_expect_success 'initialize git-svn' "git-svn init $svnrepo" -test_expect_success 'fetch revisions from svn' 'git-svn fetch' - -name='test svn:keywords ignoring' -test_expect_success "$name" \ - 'git checkout -b mybranch remotes/git-svn && - echo Hi again >> kw.c && - git commit -a -m "test keywoards ignoring" && - git-svn commit remotes/git-svn..mybranch && - git pull . remotes/git-svn' - -expect='/* $Id$ */' -got="`sed -ne 2p kw.c`" -test_expect_success 'raw $Id$ found in kw.c' "test '$expect' = '$got'" - -test_expect_success "propset CR on crlf files" \ - 'cd test_wc && - svn propset svn:eol-style CR empty && - svn propset svn:eol-style CR crlf && - svn propset svn:eol-style CR ne_crlf && - svn commit -m "propset CR on crlf files" && - svn up && - cd ..' - -test_expect_success 'fetch and pull latest from svn and checkout a new wc' \ - "git-svn fetch && - git pull . remotes/git-svn && - svn co $svnrepo new_wc" - -for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf -do - test_expect_success "Comparing $i" "cmp $i new_wc/$i" -done - - -cd test_wc - printf '$Id$\rHello\rWorld\r' > cr - printf '$Id$\rHello\rWorld' > ne_cr - a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git-hash-object --stdin` - a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git-hash-object --stdin` - test_expect_success 'Set CRLF on cr files' \ - 'svn propset svn:eol-style CRLF cr && - svn propset svn:eol-style CRLF ne_cr && - svn propset svn:keywords Id cr && - svn propset svn:keywords Id ne_cr && - svn commit -m "propset CRLF on cr files" && - svn up' -cd .. -test_expect_success 'fetch and pull latest from svn' \ - 'git-svn fetch && git pull . remotes/git-svn' - -b_cr="`git-hash-object cr`" -b_ne_cr="`git-hash-object ne_cr`" - -test_expect_success 'CRLF + $Id$' "test '$a_cr' = '$b_cr'" -test_expect_success 'CRLF + $Id$ (no newline)' "test '$a_ne_cr' = '$b_ne_cr'" - -test_done diff --git a/contrib/git-svn/t/t0002-deep-rmdir.sh b/contrib/git-svn/t/t0002-deep-rmdir.sh deleted file mode 100644 index d693d183c8..0000000000 --- a/contrib/git-svn/t/t0002-deep-rmdir.sh +++ /dev/null @@ -1,29 +0,0 @@ -test_description='git-svn rmdir' -. ./lib-git-svn.sh - -test_expect_success 'initialize repo' " - mkdir import && - cd import && - mkdir -p deeply/nested/directory/number/1 && - mkdir -p deeply/nested/directory/number/2 && - echo foo > deeply/nested/directory/number/1/file && - echo foo > deeply/nested/directory/number/2/another && - svn import -m 'import for git-svn' . $svnrepo && - cd .. - " - -test_expect_success 'mirror via git-svn' " - git-svn init $svnrepo && - git-svn fetch && - git checkout -f -b test-rmdir remotes/git-svn - " - -test_expect_success 'Try a commit on rmdir' " - git rm -f deeply/nested/directory/number/2/another && - git commit -a -m 'remove another' && - git-svn commit --rmdir HEAD && - svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1 - " - - -test_done diff --git a/contrib/git-svn/t/t0003-graft-branches.sh b/contrib/git-svn/t/t0003-graft-branches.sh deleted file mode 100644 index cc62d4ece8..0000000000 --- a/contrib/git-svn/t/t0003-graft-branches.sh +++ /dev/null @@ -1,63 +0,0 @@ -test_description='git-svn graft-branches' -. ./lib-git-svn.sh - -test_expect_success 'initialize repo' " - mkdir import && - cd import && - mkdir -p trunk branches tags && - echo hello > trunk/readme && - svn import -m 'import for git-svn' . $svnrepo && - cd .. && - svn cp -m 'tag a' $svnrepo/trunk $svnrepo/tags/a && - svn cp -m 'branch a' $svnrepo/trunk $svnrepo/branches/a && - svn co $svnrepo wc && - cd wc && - echo feedme >> branches/a/readme && - svn commit -m hungry && - svn up && - cd trunk && - svn merge -r3:4 $svnrepo/branches/a && - svn commit -m 'merge with a' && - cd ../.. && - svn log -v $svnrepo && - git-svn init -i trunk $svnrepo/trunk && - git-svn init -i a $svnrepo/branches/a && - git-svn init -i tags/a $svnrepo/tags/a && - git-svn fetch -i tags/a && - git-svn fetch -i a && - git-svn fetch -i trunk - " - -r1=`git-rev-list remotes/trunk | tail -n1` -r2=`git-rev-list remotes/tags/a | tail -n1` -r3=`git-rev-list remotes/a | tail -n1` -r4=`git-rev-list remotes/a | head -n1` -r5=`git-rev-list remotes/trunk | head -n1` - -test_expect_success 'test graft-branches regexes and copies' " - test -n "$r1" && - test -n "$r2" && - test -n "$r3" && - test -n "$r4" && - test -n "$r5" && - git-svn graft-branches && - grep '^$r2 $r1' $GIT_DIR/info/grafts && - grep '^$r3 $r1' $GIT_DIR/info/grafts && - grep '^$r5 ' $GIT_DIR/info/grafts | grep '$r4' | grep '$r1' - " - -test_debug 'gitk --all & sleep 1' - -test_expect_success 'test graft-branches with tree-joins' " - rm $GIT_DIR/info/grafts && - git-svn graft-branches --no-default-regex --no-graft-copy -B && - grep '^$r3 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r2' && - grep '^$r2 $r1' $GIT_DIR/info/grafts && - grep '^$r5 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r4' - " - -# the result of this is kinda funky, we have a strange history and -# this is just a test :) -test_debug 'gitk --all &' - -test_done diff --git a/contrib/git-svn/t/t0004-follow-parent.sh b/contrib/git-svn/t/t0004-follow-parent.sh deleted file mode 100644 index 01488ff78a..0000000000 --- a/contrib/git-svn/t/t0004-follow-parent.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006 Eric Wong -# - -test_description='git-svn --follow-parent fetching' -. ./lib-git-svn.sh - -if test -n "$GIT_SVN_NO_LIB" && test "$GIT_SVN_NO_LIB" -ne 0 -then - echo 'Skipping: --follow-parent needs SVN libraries' - test_done - exit 0 -fi - -test_expect_success 'initialize repo' " - mkdir import && - cd import && - mkdir -p trunk && - echo hello > trunk/readme && - svn import -m 'initial' . $svnrepo && - cd .. && - svn co $svnrepo wc && - cd wc && - echo world >> trunk/readme && - svn commit -m 'another commit' && - svn up && - svn mv -m 'rename to thunk' trunk thunk && - svn up && - echo goodbye >> thunk/readme && - svn commit -m 'bye now' && - cd .. - " - -test_expect_success 'init and fetch --follow-parent a moved directory' " - git-svn init -i thunk $svnrepo/thunk && - git-svn fetch --follow-parent -i thunk && - git-rev-parse --verify refs/remotes/trunk && - test '$?' -eq '0' - " - -test_debug 'gitk --all &' - -test_done diff --git a/contrib/git-svn/t/t0005-commit-diff.sh b/contrib/git-svn/t/t0005-commit-diff.sh deleted file mode 100644 index f994b72f80..0000000000 --- a/contrib/git-svn/t/t0005-commit-diff.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006 Eric Wong -test_description='git-svn commit-diff' -. ./lib-git-svn.sh - -if test -n "$GIT_SVN_NO_LIB" && test "$GIT_SVN_NO_LIB" -ne 0 -then - echo 'Skipping: commit-diff needs SVN libraries' - test_done - exit 0 -fi - -test_expect_success 'initialize repo' " - mkdir import && - cd import && - echo hello > readme && - svn import -m 'initial' . $svnrepo && - cd .. && - echo hello > readme && - git update-index --add readme && - git commit -a -m 'initial' && - echo world >> readme && - git commit -a -m 'another' - " - -head=`git rev-parse --verify HEAD^0` -prev=`git rev-parse --verify HEAD^1` - -# the internals of the commit-diff command are the same as the regular -# commit, so only a basic test of functionality is needed since we've -# already tested commit extensively elsewhere - -test_expect_success 'test the commit-diff command' " - test -n '$prev' && test -n '$head' && - git-svn commit-diff '$prev' '$head' '$svnrepo' && - svn co $svnrepo wc && - cmp readme wc/readme - " - -test_done diff --git a/git-svn.perl b/git-svn.perl new file mode 100755 index 0000000000..145eaa865a --- /dev/null +++ b/git-svn.perl @@ -0,0 +1,3378 @@ +#!/usr/bin/env perl +# Copyright (C) 2006, Eric Wong +# License: GPL v2 or later +use warnings; +use strict; +use vars qw/ $AUTHOR $VERSION + $SVN_URL $SVN_INFO $SVN_WC $SVN_UUID + $GIT_SVN_INDEX $GIT_SVN + $GIT_DIR $GIT_SVN_DIR $REVDB/; +$AUTHOR = 'Eric Wong '; +$VERSION = '@@GIT_VERSION@@'; + +use Cwd qw/abs_path/; +$GIT_DIR = abs_path($ENV{GIT_DIR} || '.git'); +$ENV{GIT_DIR} = $GIT_DIR; + +my $LC_ALL = $ENV{LC_ALL}; +my $TZ = $ENV{TZ}; +# make sure the svn binary gives consistent output between locales and TZs: +$ENV{TZ} = 'UTC'; +$ENV{LC_ALL} = 'C'; +$| = 1; # unbuffer STDOUT + +# If SVN:: library support is added, please make the dependencies +# optional and preserve the capability to use the command-line client. +# use eval { require SVN::... } to make it lazy load +# We don't use any modules not in the standard Perl distribution: +use Carp qw/croak/; +use IO::File qw//; +use File::Basename qw/dirname basename/; +use File::Path qw/mkpath/; +use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev pass_through/; +use File::Spec qw//; +use POSIX qw/strftime/; +use IPC::Open3; +use Memoize; +memoize('revisions_eq'); +memoize('cmt_metadata'); +memoize('get_commit_time'); + +my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib); +$_use_lib = 1 unless $ENV{GIT_SVN_NO_LIB}; +libsvn_load(); +my $_optimize_commits = 1 unless $ENV{GIT_SVN_NO_OPTIMIZE_COMMITS}; +my $sha1 = qr/[a-f\d]{40}/; +my $sha1_short = qr/[a-f\d]{4,40}/; +my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit, + $_find_copies_harder, $_l, $_cp_similarity, $_cp_remote, + $_repack, $_repack_nr, $_repack_flags, $_q, + $_message, $_file, $_follow_parent, $_no_metadata, + $_template, $_shared, $_no_default_regex, $_no_graft_copy, + $_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit, + $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m); +my (@_branch_from, %tree_map, %users, %rusers, %equiv); +my ($_svn_co_url_revs, $_svn_pg_peg_revs); +my @repo_path_split_cache; + +my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext, + 'branch|b=s' => \@_branch_from, + 'follow-parent|follow' => \$_follow_parent, + 'branch-all-refs|B' => \$_branch_all_refs, + 'authors-file|A=s' => \$_authors, + 'repack:i' => \$_repack, + 'no-metadata' => \$_no_metadata, + 'quiet|q' => \$_q, + 'repack-flags|repack-args|repack-opts=s' => \$_repack_flags); + +my ($_trunk, $_tags, $_branches); +my %multi_opts = ( 'trunk|T=s' => \$_trunk, + 'tags|t=s' => \$_tags, + 'branches|b=s' => \$_branches ); +my %init_opts = ( 'template=s' => \$_template, 'shared' => \$_shared ); +my %cmt_opts = ( 'edit|e' => \$_edit, + 'rmdir' => \$_rmdir, + 'find-copies-harder' => \$_find_copies_harder, + 'l=i' => \$_l, + 'copy-similarity|C=i'=> \$_cp_similarity +); + +# yes, 'native' sets "\n". Patches to fix this for non-*nix systems welcome: +my %EOL = ( CR => "\015", LF => "\012", CRLF => "\015\012", native => "\012" ); + +my %cmd = ( + fetch => [ \&fetch, "Download new revisions from SVN", + { 'revision|r=s' => \$_revision, %fc_opts } ], + init => [ \&init, "Initialize a repo for tracking" . + " (requires URL argument)", + \%init_opts ], + commit => [ \&commit, "Commit git revisions to SVN", + { 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ], + 'show-ignore' => [ \&show_ignore, "Show svn:ignore listings", + { 'revision|r=i' => \$_revision } ], + rebuild => [ \&rebuild, "Rebuild git-svn metadata (after git clone)", + { 'no-ignore-externals' => \$_no_ignore_ext, + 'copy-remote|remote=s' => \$_cp_remote, + 'upgrade' => \$_upgrade } ], + 'graft-branches' => [ \&graft_branches, + 'Detect merges/branches from already imported history', + { 'merge-rx|m' => \@_opt_m, + 'branch|b=s' => \@_branch_from, + 'branch-all-refs|B' => \$_branch_all_refs, + 'no-default-regex' => \$_no_default_regex, + 'no-graft-copy' => \$_no_graft_copy } ], + 'multi-init' => [ \&multi_init, + 'Initialize multiple trees (like git-svnimport)', + { %multi_opts, %fc_opts } ], + 'multi-fetch' => [ \&multi_fetch, + 'Fetch multiple trees (like git-svnimport)', + \%fc_opts ], + 'log' => [ \&show_log, 'Show commit logs', + { 'limit=i' => \$_limit, + 'revision|r=s' => \$_revision, + 'verbose|v' => \$_verbose, + 'incremental' => \$_incremental, + 'oneline' => \$_oneline, + 'show-commit' => \$_show_commit, + 'authors-file|A=s' => \$_authors, + } ], + 'commit-diff' => [ \&commit_diff, 'Commit a diff between two trees', + { 'message|m=s' => \$_message, + 'file|F=s' => \$_file, + %cmt_opts } ], +); + +my $cmd; +for (my $i = 0; $i < @ARGV; $i++) { + if (defined $cmd{$ARGV[$i]}) { + $cmd = $ARGV[$i]; + splice @ARGV, $i, 1; + last; + } +}; + +my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd); + +read_repo_config(\%opts); +my $rv = GetOptions(%opts, 'help|H|h' => \$_help, + 'version|V' => \$_version, + 'id|i=s' => \$GIT_SVN); +exit 1 if (!$rv && $cmd ne 'log'); + +set_default_vals(); +usage(0) if $_help; +version() if $_version; +usage(1) unless defined $cmd; +init_vars(); +load_authors() if $_authors; +load_all_refs() if $_branch_all_refs; +svn_compat_check() unless $_use_lib; +migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init)$/; +$cmd{$cmd}->[0]->(@ARGV); +exit 0; + +####################### primary functions ###################### +sub usage { + my $exit = shift || 0; + my $fd = $exit ? \*STDERR : \*STDOUT; + print $fd <<""; +git-svn - bidirectional operations between a single Subversion tree and git +Usage: $0 [options] [arguments]\n + + print $fd "Available commands:\n" unless $cmd; + + foreach (sort keys %cmd) { + next if $cmd && $cmd ne $_; + print $fd ' ',pack('A13',$_),$cmd{$_}->[1],"\n"; + foreach (keys %{$cmd{$_}->[2]}) { + # prints out arguments as they should be passed: + my $x = s#[:=]s$## ? '' : s#[:=]i$## ? '' : ''; + print $fd ' ' x 17, join(', ', map { length $_ > 1 ? + "--$_" : "-$_" } + split /\|/,$_)," $x\n"; + } + } + print $fd <<""; +\nGIT_SVN_ID may be set in the environment or via the --id/-i switch to an +arbitrary identifier if you're tracking multiple SVN branches/repositories in +one git repository and want to keep them separate. See git-svn(1) for more +information. + + exit $exit; +} + +sub version { + print "git-svn version $VERSION\n"; + exit 0; +} + +sub rebuild { + if (quiet_run(qw/git-rev-parse --verify/,"refs/remotes/$GIT_SVN^0")) { + copy_remote_ref(); + } + $SVN_URL = shift or undef; + my $newest_rev = 0; + if ($_upgrade) { + sys('git-update-ref',"refs/remotes/$GIT_SVN","$GIT_SVN-HEAD"); + } else { + check_upgrade_needed(); + } + + my $pid = open(my $rev_list,'-|'); + defined $pid or croak $!; + if ($pid == 0) { + exec("git-rev-list","refs/remotes/$GIT_SVN") or croak $!; + } + my $latest; + while (<$rev_list>) { + chomp; + my $c = $_; + croak "Non-SHA1: $c\n" unless $c =~ /^$sha1$/o; + my @commit = grep(/^git-svn-id: /,`git-cat-file commit $c`); + next if (!@commit); # skip merges + my ($url, $rev, $uuid) = extract_metadata($commit[$#commit]); + if (!$rev || !$uuid) { + croak "Unable to extract revision or UUID from ", + "$c, $commit[$#commit]\n"; + } + + # if we merged or otherwise started elsewhere, this is + # how we break out of it + next if (defined $SVN_UUID && ($uuid ne $SVN_UUID)); + next if (defined $SVN_URL && defined $url && ($url ne $SVN_URL)); + + unless (defined $latest) { + if (!$SVN_URL && !$url) { + croak "SVN repository location required: $url\n"; + } + $SVN_URL ||= $url; + $SVN_UUID ||= $uuid; + setup_git_svn(); + $latest = $rev; + } + revdb_set($REVDB, $rev, $c); + print "r$rev = $c\n"; + $newest_rev = $rev if ($rev > $newest_rev); + } + close $rev_list or croak $?; + + goto out if $_use_lib; + if (!chdir $SVN_WC) { + svn_cmd_checkout($SVN_URL, $latest, $SVN_WC); + chdir $SVN_WC or croak $!; + } + + $pid = fork; + defined $pid or croak $!; + if ($pid == 0) { + my @svn_up = qw(svn up); + push @svn_up, '--ignore-externals' unless $_no_ignore_ext; + sys(@svn_up,"-r$newest_rev"); + $ENV{GIT_INDEX_FILE} = $GIT_SVN_INDEX; + index_changes(); + exec('git-write-tree') or croak $!; + } + waitpid $pid, 0; + croak $? if $?; +out: + if ($_upgrade) { + print STDERR <<""; +Keeping deprecated refs/head/$GIT_SVN-HEAD for now. Please remove it +when you have upgraded your tools and habits to use refs/remotes/$GIT_SVN + + } +} + +sub init { + my $url = shift or die "SVN repository location required " . + "as a command-line argument\n"; + $url =~ s!/+$!!; # strip trailing slash + + if (my $repo_path = shift) { + unless (-d $repo_path) { + mkpath([$repo_path]); + } + $GIT_DIR = $ENV{GIT_DIR} = $repo_path . "/.git"; + init_vars(); + } + + $SVN_URL = $url; + unless (-d $GIT_DIR) { + my @init_db = ('git-init-db'); + push @init_db, "--template=$_template" if defined $_template; + push @init_db, "--shared" if defined $_shared; + sys(@init_db); + } + setup_git_svn(); +} + +sub fetch { + check_upgrade_needed(); + $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url"); + my $ret = $_use_lib ? fetch_lib(@_) : fetch_cmd(@_); + if ($ret->{commit} && quiet_run(qw(git-rev-parse --verify + refs/heads/master^0))) { + sys(qw(git-update-ref refs/heads/master),$ret->{commit}); + } + return $ret; +} + +sub fetch_cmd { + my (@parents) = @_; + my @log_args = -d $SVN_WC ? ($SVN_WC) : ($SVN_URL); + unless ($_revision) { + $_revision = -d $SVN_WC ? 'BASE:HEAD' : '0:HEAD'; + } + push @log_args, "-r$_revision"; + push @log_args, '--stop-on-copy' unless $_no_stop_copy; + + my $svn_log = svn_log_raw(@log_args); + + my $base = next_log_entry($svn_log) or croak "No base revision!\n"; + # don't need last_revision from grab_base_rev() because + # user could've specified a different revision to skip (they + # didn't want to import certain revisions into git for whatever + # reason, so trust $base->{revision} instead. + my (undef, $last_commit) = svn_grab_base_rev(); + unless (-d $SVN_WC) { + svn_cmd_checkout($SVN_URL,$base->{revision},$SVN_WC); + chdir $SVN_WC or croak $!; + read_uuid(); + $last_commit = git_commit($base, @parents); + assert_tree($last_commit); + } else { + chdir $SVN_WC or croak $!; + read_uuid(); + # looks like a user manually cp'd and svn switch'ed + unless ($last_commit) { + sys(qw/svn revert -R ./); + assert_svn_wc_clean($base->{revision}); + $last_commit = git_commit($base, @parents); + assert_tree($last_commit); + } + } + my @svn_up = qw(svn up); + push @svn_up, '--ignore-externals' unless $_no_ignore_ext; + my $last = $base; + while (my $log_msg = next_log_entry($svn_log)) { + if ($last->{revision} >= $log_msg->{revision}) { + croak "Out of order: last >= current: ", + "$last->{revision} >= $log_msg->{revision}\n"; + } + # Revert is needed for cases like: + # https://svn.musicpd.org/Jamming/trunk (r166:167), but + # I can't seem to reproduce something like that on a test... + sys(qw/svn revert -R ./); + assert_svn_wc_clean($last->{revision}); + sys(@svn_up,"-r$log_msg->{revision}"); + $last_commit = git_commit($log_msg, $last_commit, @parents); + $last = $log_msg; + } + close $svn_log->{fh}; + $last->{commit} = $last_commit; + return $last; +} + +sub fetch_lib { + my (@parents) = @_; + $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url"); + my $repo; + ($repo, $SVN_PATH) = repo_path_split($SVN_URL); + $SVN_LOG ||= libsvn_connect($repo); + $SVN ||= libsvn_connect($repo); + my ($last_rev, $last_commit) = svn_grab_base_rev(); + my ($base, $head) = libsvn_parse_revision($last_rev); + if ($base > $head) { + return { revision => $last_rev, commit => $last_commit } + } + my $index = set_index($GIT_SVN_INDEX); + + # limit ourselves and also fork() since get_log won't release memory + # after processing a revision and SVN stuff seems to leak + my $inc = 1000; + my ($min, $max) = ($base, $head < $base+$inc ? $head : $base+$inc); + read_uuid(); + if (defined $last_commit) { + unless (-e $GIT_SVN_INDEX) { + sys(qw/git-read-tree/, $last_commit); + } + chomp (my $x = `git-write-tree`); + my ($y) = (`git-cat-file commit $last_commit` + =~ /^tree ($sha1)/m); + if ($y ne $x) { + unlink $GIT_SVN_INDEX or croak $!; + sys(qw/git-read-tree/, $last_commit); + } + chomp ($x = `git-write-tree`); + if ($y ne $x) { + print STDERR "trees ($last_commit) $y != $x\n", + "Something is seriously wrong...\n"; + } + } + while (1) { + # fork, because using SVN::Pool with get_log() still doesn't + # seem to help enough to keep memory usage down. + defined(my $pid = fork) or croak $!; + if (!$pid) { + $SVN::Error::handler = \&libsvn_skip_unknown_revs; + + # Yes I'm perfectly aware that the fourth argument + # below is the limit revisions number. Unfortunately + # performance sucks with it enabled, so it's much + # faster to fetch revision ranges instead of relying + # on the limiter. + libsvn_get_log($SVN_LOG, '/'.$SVN_PATH, + $min, $max, 0, 1, 1, + sub { + my $log_msg; + if ($last_commit) { + $log_msg = libsvn_fetch( + $last_commit, @_); + $last_commit = git_commit( + $log_msg, + $last_commit, + @parents); + } else { + $log_msg = libsvn_new_tree(@_); + $last_commit = git_commit( + $log_msg, @parents); + } + }); + exit 0; + } + waitpid $pid, 0; + croak $? if $?; + ($last_rev, $last_commit) = svn_grab_base_rev(); + last if ($max >= $head); + $min = $max + 1; + $max += $inc; + $max = $head if ($max > $head); + } + restore_index($index); + return { revision => $last_rev, commit => $last_commit }; +} + +sub commit { + my (@commits) = @_; + check_upgrade_needed(); + if ($_stdin || !@commits) { + print "Reading from stdin...\n"; + @commits = (); + while () { + if (/\b($sha1_short)\b/o) { + unshift @commits, $1; + } + } + } + my @revs; + foreach my $c (@commits) { + chomp(my @tmp = safe_qx('git-rev-parse',$c)); + if (scalar @tmp == 1) { + push @revs, $tmp[0]; + } elsif (scalar @tmp > 1) { + push @revs, reverse (safe_qx('git-rev-list',@tmp)); + } else { + die "Failed to rev-parse $c\n"; + } + } + chomp @revs; + $_use_lib ? commit_lib(@revs) : commit_cmd(@revs); + print "Done committing ",scalar @revs," revisions to SVN\n"; +} + +sub commit_cmd { + my (@revs) = @_; + + chdir $SVN_WC or croak "Unable to chdir $SVN_WC: $!\n"; + my $info = svn_info('.'); + my $fetched = fetch(); + if ($info->{Revision} != $fetched->{revision}) { + print STDERR "There are new revisions that were fetched ", + "and need to be merged (or acknowledged) ", + "before committing.\n"; + exit 1; + } + $info = svn_info('.'); + read_uuid($info); + my $last = $fetched; + foreach my $c (@revs) { + my $mods = svn_checkout_tree($last, $c); + if (scalar @$mods == 0) { + print "Skipping, no changes detected\n"; + next; + } + $last = svn_commit_tree($last, $c); + } +} + +sub commit_lib { + my (@revs) = @_; + my ($r_last, $cmt_last) = svn_grab_base_rev(); + defined $r_last or die "Must have an existing revision to commit\n"; + my $fetched = fetch(); + if ($r_last != $fetched->{revision}) { + print STDERR "There are new revisions that were fetched ", + "and need to be merged (or acknowledged) ", + "before committing.\n", + "last rev: $r_last\n", + " current: $fetched->{revision}\n"; + exit 1; + } + read_uuid(); + my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : (); + my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$"; + + set_svn_commit_env(); + foreach my $c (@revs) { + my $log_msg = get_commit_message($c, $commit_msg); + + # fork for each commit because there's a memory leak I + # can't track down... (it's probably in the SVN code) + defined(my $pid = open my $fh, '-|') or croak $!; + if (!$pid) { + my $ed = SVN::Git::Editor->new( + { r => $r_last, + ra => $SVN, + c => $c, + svn_path => $SVN_PATH + }, + $SVN->get_commit_editor( + $log_msg->{msg}, + sub { + libsvn_commit_cb( + @_, $c, + $log_msg->{msg}, + $r_last, + $cmt_last) + }, + @lock) + ); + my $mods = libsvn_checkout_tree($cmt_last, $c, $ed); + if (@$mods == 0) { + print "No changes\nr$r_last = $cmt_last\n"; + $ed->abort_edit; + } else { + $ed->close_edit; + } + exit 0; + } + my ($r_new, $cmt_new, $no); + while (<$fh>) { + print $_; + chomp; + if (/^r(\d+) = ($sha1)$/o) { + ($r_new, $cmt_new) = ($1, $2); + } elsif ($_ eq 'No changes') { + $no = 1; + } + } + close $fh or croak $?; + if (! defined $r_new && ! defined $cmt_new) { + unless ($no) { + die "Failed to parse revision information\n"; + } + } else { + ($r_last, $cmt_last) = ($r_new, $cmt_new); + } + } + $ENV{LC_ALL} = 'C'; + unlink $commit_msg; +} + +sub show_ignore { + $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url"); + $_use_lib ? show_ignore_lib() : show_ignore_cmd(); +} + +sub show_ignore_cmd { + require File::Find or die $!; + if (defined $_revision) { + die "-r/--revision option doesn't work unless the Perl SVN ", + "libraries are used\n"; + } + chdir $SVN_WC or croak $!; + my %ign; + File::Find::find({wanted=>sub{if(lstat $_ && -d _ && -d "$_/.svn"){ + s#^\./##; + @{$ign{$_}} = svn_propget_base('svn:ignore', $_); + }}, no_chdir=>1},'.'); + + print "\n# /\n"; + foreach (@{$ign{'.'}}) { print '/',$_ if /\S/ } + delete $ign{'.'}; + foreach my $i (sort keys %ign) { + print "\n# ",$i,"\n"; + foreach (@{$ign{$i}}) { print '/',$i,'/',$_ if /\S/ } + } +} + +sub show_ignore_lib { + my $repo; + ($repo, $SVN_PATH) = repo_path_split($SVN_URL); + $SVN ||= libsvn_connect($repo); + my $r = defined $_revision ? $_revision : $SVN->get_latest_revnum; + libsvn_traverse_ignore(\*STDOUT, $SVN_PATH, $r); +} + +sub graft_branches { + my $gr_file = "$GIT_DIR/info/grafts"; + my ($grafts, $comments) = read_grafts($gr_file); + my $gr_sha1; + + if (%$grafts) { + # temporarily disable our grafts file to make this idempotent + chomp($gr_sha1 = safe_qx(qw/git-hash-object -w/,$gr_file)); + rename $gr_file, "$gr_file~$gr_sha1" or croak $!; + } + + my $l_map = read_url_paths(); + my @re = map { qr/$_/is } @_opt_m if @_opt_m; + unless ($_no_default_regex) { + push @re, (qr/\b(?:merge|merging|merged)\s+with\s+([\w\.\-]+)/i, + qr/\b(?:merge|merging|merged)\s+([\w\.\-]+)/i, + qr/\b(?:from|of)\s+([\w\.\-]+)/i ); + } + foreach my $u (keys %$l_map) { + if (@re) { + foreach my $p (keys %{$l_map->{$u}}) { + graft_merge_msg($grafts,$l_map,$u,$p,@re); + } + } + unless ($_no_graft_copy) { + if ($_use_lib) { + graft_file_copy_lib($grafts,$l_map,$u); + } else { + graft_file_copy_cmd($grafts,$l_map,$u); + } + } + } + graft_tree_joins($grafts); + + write_grafts($grafts, $comments, $gr_file); + unlink "$gr_file~$gr_sha1" if $gr_sha1; +} + +sub multi_init { + my $url = shift; + $_trunk ||= 'trunk'; + $_trunk =~ s#/+$##; + $url =~ s#/+$## if $url; + if ($_trunk !~ m#^[a-z\+]+://#) { + $_trunk = '/' . $_trunk if ($_trunk !~ m#^/#); + unless ($url) { + print STDERR "E: '$_trunk' is not a complete URL ", + "and a separate URL is not specified\n"; + exit 1; + } + $_trunk = $url . $_trunk; + } + if ($GIT_SVN eq 'git-svn') { + print "GIT_SVN_ID set to 'trunk' for $_trunk\n"; + $GIT_SVN = $ENV{GIT_SVN_ID} = 'trunk'; + } + init_vars(); + init($_trunk); + complete_url_ls_init($url, $_branches, '--branches/-b', ''); + complete_url_ls_init($url, $_tags, '--tags/-t', 'tags/'); +} + +sub multi_fetch { + # try to do trunk first, since branches/tags + # may be descended from it. + if (-e "$GIT_DIR/svn/trunk/info/url") { + fetch_child_id('trunk', @_); + } + rec_fetch('', "$GIT_DIR/svn", @_); +} + +sub show_log { + my (@args) = @_; + my ($r_min, $r_max); + my $r_last = -1; # prevent dupes + rload_authors() if $_authors; + if (defined $TZ) { + $ENV{TZ} = $TZ; + } else { + delete $ENV{TZ}; + } + if (defined $_revision) { + if ($_revision =~ /^(\d+):(\d+)$/) { + ($r_min, $r_max) = ($1, $2); + } elsif ($_revision =~ /^\d+$/) { + $r_min = $r_max = $_revision; + } else { + print STDERR "-r$_revision is not supported, use ", + "standard \'git log\' arguments instead\n"; + exit 1; + } + } + + my $pid = open(my $log,'-|'); + defined $pid or croak $!; + if (!$pid) { + exec(git_svn_log_cmd($r_min,$r_max), @args) or croak $!; + } + setup_pager(); + my (@k, $c, $d); + + while (<$log>) { + if (/^commit ($sha1_short)/o) { + my $cmt = $1; + if ($c && cmt_showable($c) && $c->{r} != $r_last) { + $r_last = $c->{r}; + process_commit($c, $r_min, $r_max, \@k) or + goto out; + } + $d = undef; + $c = { c => $cmt }; + } elsif (/^author (.+) (\d+) ([\-\+]?\d+)$/) { + get_author_info($c, $1, $2, $3); + } elsif (/^(?:tree|parent|committer) /) { + # ignore + } elsif (/^:\d{6} \d{6} $sha1_short/o) { + push @{$c->{raw}}, $_; + } elsif (/^diff /) { + $d = 1; + push @{$c->{diff}}, $_; + } elsif ($d) { + push @{$c->{diff}}, $_; + } elsif (/^ (git-svn-id:.+)$/) { + (undef, $c->{r}, undef) = extract_metadata($1); + } elsif (s/^ //) { + push @{$c->{l}}, $_; + } + } + if ($c && defined $c->{r} && $c->{r} != $r_last) { + $r_last = $c->{r}; + process_commit($c, $r_min, $r_max, \@k); + } + if (@k) { + my $swap = $r_max; + $r_max = $r_min; + $r_min = $swap; + process_commit($_, $r_min, $r_max) foreach reverse @k; + } +out: + close $log; + print '-' x72,"\n" unless $_incremental || $_oneline; +} + +sub commit_diff_usage { + print STDERR "Usage: $0 commit-diff []\n"; + exit 1 +} + +sub commit_diff { + if (!$_use_lib) { + print STDERR "commit-diff must be used with SVN libraries\n"; + exit 1; + } + my $ta = shift or commit_diff_usage(); + my $tb = shift or commit_diff_usage(); + if (!eval { $SVN_URL = shift || file_to_s("$GIT_SVN_DIR/info/url") }) { + print STDERR "Needed URL or usable git-svn id command-line\n"; + commit_diff_usage(); + } + if (defined $_message && defined $_file) { + print STDERR "Both --message/-m and --file/-F specified ", + "for the commit message.\n", + "I have no idea what you mean\n"; + exit 1; + } + if (defined $_file) { + $_message = file_to_s($_message); + } else { + $_message ||= get_commit_message($tb, + "$GIT_DIR/.svn-commit.tmp.$$")->{msg}; + } + my $repo; + ($repo, $SVN_PATH) = repo_path_split($SVN_URL); + $SVN_LOG ||= libsvn_connect($repo); + $SVN ||= libsvn_connect($repo); + my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : (); + my $ed = SVN::Git::Editor->new({ r => $SVN->get_latest_revnum, + ra => $SVN, c => $tb, + svn_path => $SVN_PATH + }, + $SVN->get_commit_editor($_message, + sub {print "Committed $_[0]\n"},@lock) + ); + my $mods = libsvn_checkout_tree($ta, $tb, $ed); + if (@$mods == 0) { + print "No changes\n$ta == $tb\n"; + $ed->abort_edit; + } else { + $ed->close_edit; + } +} + +########################### utility functions ######################### + +sub cmt_showable { + my ($c) = @_; + return 1 if defined $c->{r}; + if ($c->{l} && $c->{l}->[-1] eq "...\n" && + $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) { + my @msg = safe_qx(qw/git-cat-file commit/, $c->{c}); + shift @msg while ($msg[0] ne "\n"); + shift @msg; + @{$c->{l}} = grep !/^git-svn-id: /, @msg; + + (undef, $c->{r}, undef) = extract_metadata( + (grep(/^git-svn-id: /, @msg))[-1]); + } + return defined $c->{r}; +} + +sub git_svn_log_cmd { + my ($r_min, $r_max) = @_; + my @cmd = (qw/git-log --abbrev-commit --pretty=raw + --default/, "refs/remotes/$GIT_SVN"); + push @cmd, '--summary' if $_verbose; + return @cmd unless defined $r_max; + if ($r_max == $r_min) { + push @cmd, '--max-count=1'; + if (my $c = revdb_get($REVDB, $r_max)) { + push @cmd, $c; + } + } else { + my ($c_min, $c_max); + $c_max = revdb_get($REVDB, $r_max); + $c_min = revdb_get($REVDB, $r_min); + if ($c_min && $c_max) { + if ($r_max > $r_max) { + push @cmd, "$c_min..$c_max"; + } else { + push @cmd, "$c_max..$c_min"; + } + } elsif ($r_max > $r_min) { + push @cmd, $c_max; + } else { + push @cmd, $c_min; + } + } + return @cmd; +} + +sub fetch_child_id { + my $id = shift; + print "Fetching $id\n"; + my $ref = "$GIT_DIR/refs/remotes/$id"; + defined(my $pid = open my $fh, '-|') or croak $!; + if (!$pid) { + $_repack = undef; + $GIT_SVN = $ENV{GIT_SVN_ID} = $id; + init_vars(); + fetch(@_); + exit 0; + } + while (<$fh>) { + print $_; + check_repack() if (/^r\d+ = $sha1/); + } + close $fh or croak $?; +} + +sub rec_fetch { + my ($pfx, $p, @args) = @_; + my @dir; + foreach (sort <$p/*>) { + if (-r "$_/info/url") { + $pfx .= '/' if $pfx && $pfx !~ m!/$!; + my $id = $pfx . basename $_; + next if $id eq 'trunk'; + fetch_child_id($id, @args); + } elsif (-d $_) { + push @dir, $_; + } + } + foreach (@dir) { + my $x = $_; + $x =~ s!^\Q$GIT_DIR\E/svn/!!; + rec_fetch($x, $_); + } +} + +sub complete_url_ls_init { + my ($url, $var, $switch, $pfx) = @_; + unless ($var) { + print STDERR "W: $switch not specified\n"; + return; + } + $var =~ s#/+$##; + if ($var !~ m#^[a-z\+]+://#) { + $var = '/' . $var if ($var !~ m#^/#); + unless ($url) { + print STDERR "E: '$var' is not a complete URL ", + "and a separate URL is not specified\n"; + exit 1; + } + $var = $url . $var; + } + chomp(my @ls = $_use_lib ? libsvn_ls_fullurl($var) + : safe_qx(qw/svn ls --non-interactive/, $var)); + my $old = $GIT_SVN; + defined(my $pid = fork) or croak $!; + if (!$pid) { + foreach my $u (map { "$var/$_" } (grep m!/$!, @ls)) { + $u =~ s#/+$##; + if ($u !~ m!\Q$var\E/(.+)$!) { + print STDERR "W: Unrecognized URL: $u\n"; + die "This should never happen\n"; + } + my $id = $pfx.$1; + print "init $u => $id\n"; + $GIT_SVN = $ENV{GIT_SVN_ID} = $id; + init_vars(); + init($u); + } + exit 0; + } + waitpid $pid, 0; + croak $? if $?; +} + +sub common_prefix { + my $paths = shift; + my %common; + foreach (@$paths) { + my @tmp = split m#/#, $_; + my $p = ''; + while (my $x = shift @tmp) { + $p .= "/$x"; + $common{$p} ||= 0; + $common{$p}++; + } + } + foreach (sort {length $b <=> length $a} keys %common) { + if ($common{$_} == @$paths) { + return $_; + } + } + return ''; +} + +# grafts set here are 'stronger' in that they're based on actual tree +# matches, and won't be deleted from merge-base checking in write_grafts() +sub graft_tree_joins { + my $grafts = shift; + map_tree_joins() if (@_branch_from && !%tree_map); + return unless %tree_map; + + git_svn_each(sub { + my $i = shift; + defined(my $pid = open my $fh, '-|') or croak $!; + if (!$pid) { + exec qw/git-rev-list --pretty=raw/, + "refs/remotes/$i" or croak $!; + } + while (<$fh>) { + next unless /^commit ($sha1)$/o; + my $c = $1; + my ($t) = (<$fh> =~ /^tree ($sha1)$/o); + next unless $tree_map{$t}; + + my $l; + do { + $l = readline $fh; + } until ($l =~ /^committer (?:.+) (\d+) ([\-\+]?\d+)$/); + + my ($s, $tz) = ($1, $2); + if ($tz =~ s/^\+//) { + $s += tz_to_s_offset($tz); + } elsif ($tz =~ s/^\-//) { + $s -= tz_to_s_offset($tz); + } + + my ($url_a, $r_a, $uuid_a) = cmt_metadata($c); + + foreach my $p (@{$tree_map{$t}}) { + next if $p eq $c; + my $mb = eval { + safe_qx('git-merge-base', $c, $p) + }; + next unless ($@ || $?); + if (defined $r_a) { + # see if SVN says it's a relative + my ($url_b, $r_b, $uuid_b) = + cmt_metadata($p); + next if (defined $url_b && + defined $url_a && + ($url_a eq $url_b) && + ($uuid_a eq $uuid_b)); + if ($uuid_a eq $uuid_b) { + if ($r_b < $r_a) { + $grafts->{$c}->{$p} = 2; + next; + } elsif ($r_b > $r_a) { + $grafts->{$p}->{$c} = 2; + next; + } + } + } + my $ct = get_commit_time($p); + if ($ct < $s) { + $grafts->{$c}->{$p} = 2; + } elsif ($ct > $s) { + $grafts->{$p}->{$c} = 2; + } + # what should we do when $ct == $s ? + } + } + close $fh or croak $?; + }); +} + +# this isn't funky-filename safe, but good enough for now... +sub graft_file_copy_cmd { + my ($grafts, $l_map, $u) = @_; + my $paths = $l_map->{$u}; + my $pfx = common_prefix([keys %$paths]); + $SVN_URL ||= $u.$pfx; + my $pid = open my $fh, '-|'; + defined $pid or croak $!; + unless ($pid) { + my @exec = qw/svn log -v/; + push @exec, "-r$_revision" if defined $_revision; + exec @exec, $u.$pfx or croak $!; + } + my ($r, $mp) = (undef, undef); + while (<$fh>) { + chomp; + if (/^\-{72}$/) { + $mp = $r = undef; + } elsif (/^r(\d+) \| /) { + $r = $1 unless defined $r; + } elsif (/^Changed paths:/) { + $mp = 1; + } elsif ($mp && m#^ [AR] /(\S.*?) \(from /(\S+?):(\d+)\)$#) { + my ($p1, $p0, $r0) = ($1, $2, $3); + my $c = find_graft_path_commit($paths, $p1, $r); + next unless $c; + find_graft_path_parents($grafts, $paths, $c, $p0, $r0); + } + } +} + +sub graft_file_copy_lib { + my ($grafts, $l_map, $u) = @_; + my $tree_paths = $l_map->{$u}; + my $pfx = common_prefix([keys %$tree_paths]); + my ($repo, $path) = repo_path_split($u.$pfx); + $SVN_LOG ||= libsvn_connect($repo); + $SVN ||= libsvn_connect($repo); + + my ($base, $head) = libsvn_parse_revision(); + my $inc = 1000; + my ($min, $max) = ($base, $head < $base+$inc ? $head : $base+$inc); + my $eh = $SVN::Error::handler; + $SVN::Error::handler = \&libsvn_skip_unknown_revs; + while (1) { + my $pool = SVN::Pool->new; + libsvn_get_log($SVN_LOG, "/$path", $min, $max, 0, 1, 1, + sub { + libsvn_graft_file_copies($grafts, $tree_paths, + $path, @_); + }, $pool); + $pool->clear; + last if ($max >= $head); + $min = $max + 1; + $max += $inc; + $max = $head if ($max > $head); + } + $SVN::Error::handler = $eh; +} + +sub process_merge_msg_matches { + my ($grafts, $l_map, $u, $p, $c, @matches) = @_; + my (@strong, @weak); + foreach (@matches) { + # merging with ourselves is not interesting + next if $_ eq $p; + if ($l_map->{$u}->{$_}) { + push @strong, $_; + } else { + push @weak, $_; + } + } + foreach my $w (@weak) { + last if @strong; + # no exact match, use branch name as regexp. + my $re = qr/\Q$w\E/i; + foreach (keys %{$l_map->{$u}}) { + if (/$re/) { + push @strong, $l_map->{$u}->{$_}; + last; + } + } + last if @strong; + $w = basename($w); + $re = qr/\Q$w\E/i; + foreach (keys %{$l_map->{$u}}) { + if (/$re/) { + push @strong, $l_map->{$u}->{$_}; + last; + } + } + } + my ($rev) = ($c->{m} =~ /^git-svn-id:\s(?:\S+?)\@(\d+) + \s(?:[a-f\d\-]+)$/xsm); + unless (defined $rev) { + ($rev) = ($c->{m} =~/^git-svn-id:\s(\d+) + \@(?:[a-f\d\-]+)/xsm); + return unless defined $rev; + } + foreach my $m (@strong) { + my ($r0, $s0) = find_rev_before($rev, $m, 1); + $grafts->{$c->{c}}->{$s0} = 1 if defined $s0; + } +} + +sub graft_merge_msg { + my ($grafts, $l_map, $u, $p, @re) = @_; + + my $x = $l_map->{$u}->{$p}; + my $rl = rev_list_raw($x); + while (my $c = next_rev_list_entry($rl)) { + foreach my $re (@re) { + my (@br) = ($c->{m} =~ /$re/g); + next unless @br; + process_merge_msg_matches($grafts,$l_map,$u,$p,$c,@br); + } + } +} + +sub read_uuid { + return if $SVN_UUID; + if ($_use_lib) { + my $pool = SVN::Pool->new; + $SVN_UUID = $SVN->get_uuid($pool); + $pool->clear; + } else { + my $info = shift || svn_info('.'); + $SVN_UUID = $info->{'Repository UUID'} or + croak "Repository UUID unreadable\n"; + } +} + +sub quiet_run { + my $pid = fork; + defined $pid or croak $!; + if (!$pid) { + open my $null, '>', '/dev/null' or croak $!; + open STDERR, '>&', $null or croak $!; + open STDOUT, '>&', $null or croak $!; + exec @_ or croak $!; + } + waitpid $pid, 0; + return $?; +} + +sub repo_path_split { + my $full_url = shift; + $full_url =~ s#/+$##; + + foreach (@repo_path_split_cache) { + if ($full_url =~ s#$_##) { + my $u = $1; + $full_url =~ s#^/+##; + return ($u, $full_url); + } + } + + my ($url, $path) = ($full_url =~ m!^([a-z\+]+://[^/]*)(.*)$!i); + $path =~ s#^/+##; + my @paths = split(m#/+#, $path); + + if ($_use_lib) { + while (1) { + $SVN = libsvn_connect($url); + last if (defined $SVN && + defined eval { $SVN->get_latest_revnum }); + my $n = shift @paths || last; + $url .= "/$n"; + } + } else { + while (quiet_run(qw/svn ls --non-interactive/, $url)) { + my $n = shift @paths || last; + $url .= "/$n"; + } + } + push @repo_path_split_cache, qr/^(\Q$url\E)/; + $path = join('/',@paths); + return ($url, $path); +} + +sub setup_git_svn { + defined $SVN_URL or croak "SVN repository location required\n"; + unless (-d $GIT_DIR) { + croak "GIT_DIR=$GIT_DIR does not exist!\n"; + } + mkpath([$GIT_SVN_DIR]); + mkpath(["$GIT_SVN_DIR/info"]); + open my $fh, '>>',$REVDB or croak $!; + close $fh; + s_to_file($SVN_URL,"$GIT_SVN_DIR/info/url"); + +} + +sub assert_svn_wc_clean { + return if $_use_lib; + my ($svn_rev) = @_; + croak "$svn_rev is not an integer!\n" unless ($svn_rev =~ /^\d+$/); + my $lcr = svn_info('.')->{'Last Changed Rev'}; + if ($svn_rev != $lcr) { + print STDERR "Checking for copy-tree ... "; + my @diff = grep(/^Index: /,(safe_qx(qw(svn diff), + "-r$lcr:$svn_rev"))); + if (@diff) { + croak "Nope! Expected r$svn_rev, got r$lcr\n"; + } else { + print STDERR "OK!\n"; + } + } + my @status = grep(!/^Performing status on external/,(`svn status`)); + @status = grep(!/^\s*$/,@status); + if (scalar @status) { + print STDERR "Tree ($SVN_WC) is not clean:\n"; + print STDERR $_ foreach @status; + croak; + } +} + +sub get_tree_from_treeish { + my ($treeish) = @_; + croak "Not a sha1: $treeish\n" unless $treeish =~ /^$sha1$/o; + chomp(my $type = `git-cat-file -t $treeish`); + my $expected; + while ($type eq 'tag') { + chomp(($treeish, $type) = `git-cat-file tag $treeish`); + } + if ($type eq 'commit') { + $expected = (grep /^tree /,`git-cat-file commit $treeish`)[0]; + ($expected) = ($expected =~ /^tree ($sha1)$/); + die "Unable to get tree from $treeish\n" unless $expected; + } elsif ($type eq 'tree') { + $expected = $treeish; + } else { + die "$treeish is a $type, expected tree, tag or commit\n"; + } + return $expected; +} + +sub assert_tree { + return if $_use_lib; + my ($treeish) = @_; + my $expected = get_tree_from_treeish($treeish); + + my $tmpindex = $GIT_SVN_INDEX.'.assert-tmp'; + if (-e $tmpindex) { + unlink $tmpindex or croak $!; + } + my $old_index = set_index($tmpindex); + index_changes(1); + chomp(my $tree = `git-write-tree`); + restore_index($old_index); + if ($tree ne $expected) { + croak "Tree mismatch, Got: $tree, Expected: $expected\n"; + } + unlink $tmpindex; +} + +sub parse_diff_tree { + my $diff_fh = shift; + local $/ = "\0"; + my $state = 'meta'; + my @mods; + while (<$diff_fh>) { + chomp $_; # this gets rid of the trailing "\0" + if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s + $sha1\s($sha1)\s([MTCRAD])\d*$/xo) { + push @mods, { mode_a => $1, mode_b => $2, + sha1_b => $3, chg => $4 }; + if ($4 =~ /^(?:C|R)$/) { + $state = 'file_a'; + } else { + $state = 'file_b'; + } + } elsif ($state eq 'file_a') { + my $x = $mods[$#mods] or croak "Empty array\n"; + if ($x->{chg} !~ /^(?:C|R)$/) { + croak "Error parsing $_, $x->{chg}\n"; + } + $x->{file_a} = $_; + $state = 'file_b'; + } elsif ($state eq 'file_b') { + my $x = $mods[$#mods] or croak "Empty array\n"; + if (exists $x->{file_a} && $x->{chg} !~ /^(?:C|R)$/) { + croak "Error parsing $_, $x->{chg}\n"; + } + if (!exists $x->{file_a} && $x->{chg} =~ /^(?:C|R)$/) { + croak "Error parsing $_, $x->{chg}\n"; + } + $x->{file_b} = $_; + $state = 'meta'; + } else { + croak "Error parsing $_\n"; + } + } + close $diff_fh or croak $?; + + return \@mods; +} + +sub svn_check_prop_executable { + my $m = shift; + return if -l $m->{file_b}; + if ($m->{mode_b} =~ /755$/) { + chmod((0755 &~ umask),$m->{file_b}) or croak $!; + if ($m->{mode_a} !~ /755$/) { + sys(qw(svn propset svn:executable 1), $m->{file_b}); + } + -x $m->{file_b} or croak "$m->{file_b} is not executable!\n"; + } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { + sys(qw(svn propdel svn:executable), $m->{file_b}); + chmod((0644 &~ umask),$m->{file_b}) or croak $!; + -x $m->{file_b} and croak "$m->{file_b} is executable!\n"; + } +} + +sub svn_ensure_parent_path { + my $dir_b = dirname(shift); + svn_ensure_parent_path($dir_b) if ($dir_b ne File::Spec->curdir); + mkpath([$dir_b]) unless (-d $dir_b); + sys(qw(svn add -N), $dir_b) unless (-d "$dir_b/.svn"); +} + +sub precommit_check { + my $mods = shift; + my (%rm_file, %rmdir_check, %added_check); + + my %o = ( D => 0, R => 1, C => 2, A => 3, M => 3, T => 3 ); + foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) { + if ($m->{chg} eq 'R') { + if (-d $m->{file_b}) { + err_dir_to_file("$m->{file_a} => $m->{file_b}"); + } + # dir/$file => dir/file/$file + my $dirname = dirname($m->{file_b}); + while ($dirname ne File::Spec->curdir) { + if ($dirname ne $m->{file_a}) { + $dirname = dirname($dirname); + next; + } + err_file_to_dir("$m->{file_a} => $m->{file_b}"); + } + # baz/zzz => baz (baz is a file) + $dirname = dirname($m->{file_a}); + while ($dirname ne File::Spec->curdir) { + if ($dirname ne $m->{file_b}) { + $dirname = dirname($dirname); + next; + } + err_dir_to_file("$m->{file_a} => $m->{file_b}"); + } + } + if ($m->{chg} =~ /^(D|R)$/) { + my $t = $1 eq 'D' ? 'file_b' : 'file_a'; + $rm_file{ $m->{$t} } = 1; + my $dirname = dirname( $m->{$t} ); + my $basename = basename( $m->{$t} ); + $rmdir_check{$dirname}->{$basename} = 1; + } elsif ($m->{chg} =~ /^(?:A|C)$/) { + if (-d $m->{file_b}) { + err_dir_to_file($m->{file_b}); + } + my $dirname = dirname( $m->{file_b} ); + my $basename = basename( $m->{file_b} ); + $added_check{$dirname}->{$basename} = 1; + while ($dirname ne File::Spec->curdir) { + if ($rm_file{$dirname}) { + err_file_to_dir($m->{file_b}); + } + $dirname = dirname $dirname; + } + } + } + return (\%rmdir_check, \%added_check); + + sub err_dir_to_file { + my $file = shift; + print STDERR "Node change from directory to file ", + "is not supported by Subversion: ",$file,"\n"; + exit 1; + } + sub err_file_to_dir { + my $file = shift; + print STDERR "Node change from file to directory ", + "is not supported by Subversion: ",$file,"\n"; + exit 1; + } +} + + +sub get_diff { + my ($from, $treeish) = @_; + assert_tree($from); + print "diff-tree $from $treeish\n"; + my $pid = open my $diff_fh, '-|'; + defined $pid or croak $!; + if ($pid == 0) { + my @diff_tree = qw(git-diff-tree -z -r); + if ($_cp_similarity) { + push @diff_tree, "-C$_cp_similarity"; + } else { + push @diff_tree, '-C'; + } + push @diff_tree, '--find-copies-harder' if $_find_copies_harder; + push @diff_tree, "-l$_l" if defined $_l; + exec(@diff_tree, $from, $treeish) or croak $!; + } + return parse_diff_tree($diff_fh); +} + +sub svn_checkout_tree { + my ($from, $treeish) = @_; + my $mods = get_diff($from->{commit}, $treeish); + return $mods unless (scalar @$mods); + my ($rm, $add) = precommit_check($mods); + + my %o = ( D => 1, R => 0, C => -1, A => 3, M => 3, T => 3 ); + foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) { + if ($m->{chg} eq 'C') { + svn_ensure_parent_path( $m->{file_b} ); + sys(qw(svn cp), $m->{file_a}, $m->{file_b}); + apply_mod_line_blob($m); + svn_check_prop_executable($m); + } elsif ($m->{chg} eq 'D') { + sys(qw(svn rm --force), $m->{file_b}); + } elsif ($m->{chg} eq 'R') { + svn_ensure_parent_path( $m->{file_b} ); + sys(qw(svn mv --force), $m->{file_a}, $m->{file_b}); + apply_mod_line_blob($m); + svn_check_prop_executable($m); + } elsif ($m->{chg} eq 'M') { + apply_mod_line_blob($m); + svn_check_prop_executable($m); + } elsif ($m->{chg} eq 'T') { + sys(qw(svn rm --force),$m->{file_b}); + apply_mod_line_blob($m); + sys(qw(svn add), $m->{file_b}); + svn_check_prop_executable($m); + } elsif ($m->{chg} eq 'A') { + svn_ensure_parent_path( $m->{file_b} ); + apply_mod_line_blob($m); + sys(qw(svn add), $m->{file_b}); + svn_check_prop_executable($m); + } else { + croak "Invalid chg: $m->{chg}\n"; + } + } + + assert_tree($treeish); + if ($_rmdir) { # remove empty directories + handle_rmdir($rm, $add); + } + assert_tree($treeish); + return $mods; +} + +sub libsvn_checkout_tree { + my ($from, $treeish, $ed) = @_; + my $mods = get_diff($from, $treeish); + return $mods unless (scalar @$mods); + my %o = ( D => 1, R => 0, C => -1, A => 3, M => 3, T => 3 ); + foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) { + my $f = $m->{chg}; + if (defined $o{$f}) { + $ed->$f($m, $_q); + } else { + croak "Invalid change type: $f\n"; + } + } + $ed->rmdirs($_q) if $_rmdir; + return $mods; +} + +# svn ls doesn't work with respect to the current working tree, but what's +# in the repository. There's not even an option for it... *sigh* +# (added files don't show up and removed files remain in the ls listing) +sub svn_ls_current { + my ($dir, $rm, $add) = @_; + chomp(my @ls = safe_qx('svn','ls',$dir)); + my @ret = (); + foreach (@ls) { + s#/$##; # trailing slashes are evil + push @ret, $_ unless $rm->{$dir}->{$_}; + } + if (exists $add->{$dir}) { + push @ret, keys %{$add->{$dir}}; + } + return \@ret; +} + +sub handle_rmdir { + my ($rm, $add) = @_; + + foreach my $dir (sort {length $b <=> length $a} keys %$rm) { + my $ls = svn_ls_current($dir, $rm, $add); + next if (scalar @$ls); + sys(qw(svn rm --force),$dir); + + my $dn = dirname $dir; + $rm->{ $dn }->{ basename $dir } = 1; + $ls = svn_ls_current($dn, $rm, $add); + while (scalar @$ls == 0 && $dn ne File::Spec->curdir) { + sys(qw(svn rm --force),$dn); + $dir = basename $dn; + $dn = dirname $dn; + $rm->{ $dn }->{ $dir } = 1; + $ls = svn_ls_current($dn, $rm, $add); + } + } +} + +sub get_commit_message { + my ($commit, $commit_msg) = (@_); + my %log_msg = ( msg => '' ); + open my $msg, '>', $commit_msg or croak $!; + + chomp(my $type = `git-cat-file -t $commit`); + if ($type eq 'commit') { + my $pid = open my $msg_fh, '-|'; + defined $pid or croak $!; + + if ($pid == 0) { + exec(qw(git-cat-file commit), $commit) or croak $!; + } + my $in_msg = 0; + while (<$msg_fh>) { + if (!$in_msg) { + $in_msg = 1 if (/^\s*$/); + } elsif (/^git-svn-id: /) { + # skip this, we regenerate the correct one + # on re-fetch anyways + } else { + print $msg $_ or croak $!; + } + } + close $msg_fh or croak $?; + } + close $msg or croak $!; + + if ($_edit || ($type eq 'tree')) { + my $editor = $ENV{VISUAL} || $ENV{EDITOR} || 'vi'; + system($editor, $commit_msg); + } + + # file_to_s removes all trailing newlines, so just use chomp() here: + open $msg, '<', $commit_msg or croak $!; + { local $/; chomp($log_msg{msg} = <$msg>); } + close $msg or croak $!; + + return \%log_msg; +} + +sub set_svn_commit_env { + if (defined $LC_ALL) { + $ENV{LC_ALL} = $LC_ALL; + } else { + delete $ENV{LC_ALL}; + } +} + +sub svn_commit_tree { + my ($last, $commit) = @_; + my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$"; + my $log_msg = get_commit_message($commit, $commit_msg); + my ($oneline) = ($log_msg->{msg} =~ /([^\n\r]+)/); + print "Committing $commit: $oneline\n"; + + set_svn_commit_env(); + my @ci_output = safe_qx(qw(svn commit -F),$commit_msg); + $ENV{LC_ALL} = 'C'; + unlink $commit_msg; + my ($committed) = ($ci_output[$#ci_output] =~ /(\d+)/); + if (!defined $committed) { + my $out = join("\n",@ci_output); + print STDERR "W: Trouble parsing \`svn commit' output:\n\n", + $out, "\n\nAssuming English locale..."; + ($committed) = ($out =~ /^Committed revision \d+\./sm); + defined $committed or die " FAILED!\n", + "Commit output failed to parse committed revision!\n", + print STDERR " OK\n"; + } + + my @svn_up = qw(svn up); + push @svn_up, '--ignore-externals' unless $_no_ignore_ext; + if ($_optimize_commits && ($committed == ($last->{revision} + 1))) { + push @svn_up, "-r$committed"; + sys(@svn_up); + my $info = svn_info('.'); + my $date = $info->{'Last Changed Date'} or die "Missing date\n"; + if ($info->{'Last Changed Rev'} != $committed) { + croak "$info->{'Last Changed Rev'} != $committed\n" + } + my ($Y,$m,$d,$H,$M,$S,$tz) = ($date =~ + /(\d{4})\-(\d\d)\-(\d\d)\s + (\d\d)\:(\d\d)\:(\d\d)\s([\-\+]\d+)/x) + or croak "Failed to parse date: $date\n"; + $log_msg->{date} = "$tz $Y-$m-$d $H:$M:$S"; + $log_msg->{author} = $info->{'Last Changed Author'}; + $log_msg->{revision} = $committed; + $log_msg->{msg} .= "\n"; + $log_msg->{parents} = [ $last->{commit} ]; + $log_msg->{commit} = git_commit($log_msg, $commit); + return $log_msg; + } + # resync immediately + push @svn_up, "-r$last->{revision}"; + sys(@svn_up); + return fetch("$committed=$commit"); +} + +sub rev_list_raw { + my (@args) = @_; + my $pid = open my $fh, '-|'; + defined $pid or croak $!; + if (!$pid) { + exec(qw/git-rev-list --pretty=raw/, @args) or croak $!; + } + return { fh => $fh, t => { } }; +} + +sub next_rev_list_entry { + my $rl = shift; + my $fh = $rl->{fh}; + my $x = $rl->{t}; + while (<$fh>) { + if (/^commit ($sha1)$/o) { + if ($x->{c}) { + $rl->{t} = { c => $1 }; + return $x; + } else { + $x->{c} = $1; + } + } elsif (/^parent ($sha1)$/o) { + $x->{p}->{$1} = 1; + } elsif (s/^ //) { + $x->{m} ||= ''; + $x->{m} .= $_; + } + } + return ($x != $rl->{t}) ? $x : undef; +} + +# read the entire log into a temporary file (which is removed ASAP) +# and store the file handle + parser state +sub svn_log_raw { + my (@log_args) = @_; + my $log_fh = IO::File->new_tmpfile or croak $!; + my $pid = fork; + defined $pid or croak $!; + if (!$pid) { + open STDOUT, '>&', $log_fh or croak $!; + exec (qw(svn log), @log_args) or croak $! + } + waitpid $pid, 0; + croak $? if $?; + seek $log_fh, 0, 0 or croak $!; + return { state => 'sep', fh => $log_fh }; +} + +sub next_log_entry { + my $log = shift; # retval of svn_log_raw() + my $ret = undef; + my $fh = $log->{fh}; + + while (<$fh>) { + chomp; + if (/^\-{72}$/) { + if ($log->{state} eq 'msg') { + if ($ret->{lines}) { + $ret->{msg} .= $_."\n"; + unless(--$ret->{lines}) { + $log->{state} = 'sep'; + } + } else { + croak "Log parse error at: $_\n", + $ret->{revision}, + "\n"; + } + next; + } + if ($log->{state} ne 'sep') { + croak "Log parse error at: $_\n", + "state: $log->{state}\n", + $ret->{revision}, + "\n"; + } + $log->{state} = 'rev'; + + # if we have an empty log message, put something there: + if ($ret) { + $ret->{msg} ||= "\n"; + delete $ret->{lines}; + return $ret; + } + next; + } + if ($log->{state} eq 'rev' && s/^r(\d+)\s*\|\s*//) { + my $rev = $1; + my ($author, $date, $lines) = split(/\s*\|\s*/, $_, 3); + ($lines) = ($lines =~ /(\d+)/); + my ($Y,$m,$d,$H,$M,$S,$tz) = ($date =~ + /(\d{4})\-(\d\d)\-(\d\d)\s + (\d\d)\:(\d\d)\:(\d\d)\s([\-\+]\d+)/x) + or croak "Failed to parse date: $date\n"; + $ret = { revision => $rev, + date => "$tz $Y-$m-$d $H:$M:$S", + author => $author, + lines => $lines, + msg => '' }; + if (defined $_authors && ! defined $users{$author}) { + die "Author: $author not defined in ", + "$_authors file\n"; + } + $log->{state} = 'msg_start'; + next; + } + # skip the first blank line of the message: + if ($log->{state} eq 'msg_start' && /^$/) { + $log->{state} = 'msg'; + } elsif ($log->{state} eq 'msg') { + if ($ret->{lines}) { + $ret->{msg} .= $_."\n"; + unless (--$ret->{lines}) { + $log->{state} = 'sep'; + } + } else { + croak "Log parse error at: $_\n", + $ret->{revision},"\n"; + } + } + } + return $ret; +} + +sub svn_info { + my $url = shift || $SVN_URL; + + my $pid = open my $info_fh, '-|'; + defined $pid or croak $!; + + if ($pid == 0) { + exec(qw(svn info),$url) or croak $!; + } + + my $ret = {}; + # only single-lines seem to exist in svn info output + while (<$info_fh>) { + chomp $_; + if (m#^([^:]+)\s*:\s*(\S.*)$#) { + $ret->{$1} = $2; + push @{$ret->{-order}}, $1; + } + } + close $info_fh or croak $?; + return $ret; +} + +sub sys { system(@_) == 0 or croak $? } + +sub eol_cp { + my ($from, $to) = @_; + my $es = svn_propget_base('svn:eol-style', $to); + open my $rfd, '<', $from or croak $!; + binmode $rfd or croak $!; + open my $wfd, '>', $to or croak $!; + binmode $wfd or croak $!; + eol_cp_fd($rfd, $wfd, $es); + close $rfd or croak $!; + close $wfd or croak $!; +} + +sub eol_cp_fd { + my ($rfd, $wfd, $es) = @_; + my $eol = defined $es ? $EOL{$es} : undef; + my $buf; + use bytes; + while (1) { + my ($r, $w, $t); + defined($r = sysread($rfd, $buf, 4096)) or croak $!; + return unless $r; + if ($eol) { + if ($buf =~ /\015$/) { + my $c; + defined($r = sysread($rfd,$c,1)) or croak $!; + $buf .= $c if $r > 0; + } + $buf =~ s/(?:\015\012|\015|\012)/$eol/gs; + $r = length($buf); + } + for ($w = 0; $w < $r; $w += $t) { + $t = syswrite($wfd, $buf, $r - $w, $w) or croak $!; + } + } + no bytes; +} + +sub do_update_index { + my ($z_cmd, $cmd, $no_text_base) = @_; + + my $z = open my $p, '-|'; + defined $z or croak $!; + unless ($z) { exec @$z_cmd or croak $! } + + my $pid = open my $ui, '|-'; + defined $pid or croak $!; + unless ($pid) { + exec('git-update-index',"--$cmd",'-z','--stdin') or croak $!; + } + local $/ = "\0"; + while (my $x = <$p>) { + chomp $x; + if (!$no_text_base && lstat $x && ! -l _ && + svn_propget_base('svn:keywords', $x)) { + my $mode = -x _ ? 0755 : 0644; + my ($v,$d,$f) = File::Spec->splitpath($x); + my $tb = File::Spec->catfile($d, '.svn', 'tmp', + 'text-base',"$f.svn-base"); + $tb =~ s#^/##; + unless (-f $tb) { + $tb = File::Spec->catfile($d, '.svn', + 'text-base',"$f.svn-base"); + $tb =~ s#^/##; + } + unlink $x or croak $!; + eol_cp($tb, $x); + chmod(($mode &~ umask), $x) or croak $!; + } + print $ui $x,"\0"; + } + close $ui or croak $?; +} + +sub index_changes { + return if $_use_lib; + + if (!-f "$GIT_SVN_DIR/info/exclude") { + open my $fd, '>>', "$GIT_SVN_DIR/info/exclude" or croak $!; + print $fd '.svn',"\n"; + close $fd or croak $!; + } + my $no_text_base = shift; + do_update_index([qw/git-diff-files --name-only -z/], + 'remove', + $no_text_base); + do_update_index([qw/git-ls-files -z --others/, + "--exclude-from=$GIT_SVN_DIR/info/exclude"], + 'add', + $no_text_base); +} + +sub s_to_file { + my ($str, $file, $mode) = @_; + open my $fd,'>',$file or croak $!; + print $fd $str,"\n" or croak $!; + close $fd or croak $!; + chmod ($mode &~ umask, $file) if (defined $mode); +} + +sub file_to_s { + my $file = shift; + open my $fd,'<',$file or croak "$!: file: $file\n"; + local $/; + my $ret = <$fd>; + close $fd or croak $!; + $ret =~ s/\s*$//s; + return $ret; +} + +sub assert_revision_unknown { + my $r = shift; + if (my $c = revdb_get($REVDB, $r)) { + croak "$r = $c already exists! Why are we refetching it?"; + } +} + +sub trees_eq { + my ($x, $y) = @_; + my @x = safe_qx('git-cat-file','commit',$x); + my @y = safe_qx('git-cat-file','commit',$y); + if (($y[0] ne $x[0]) || $x[0] !~ /^tree $sha1\n$/ + || $y[0] !~ /^tree $sha1\n$/) { + print STDERR "Trees not equal: $y[0] != $x[0]\n"; + return 0 + } + return 1; +} + +sub git_commit { + my ($log_msg, @parents) = @_; + assert_revision_unknown($log_msg->{revision}); + map_tree_joins() if (@_branch_from && !%tree_map); + + my (@tmp_parents, @exec_parents, %seen_parent); + if (my $lparents = $log_msg->{parents}) { + @tmp_parents = @$lparents + } + # commit parents can be conditionally bound to a particular + # svn revision via: "svn_revno=commit_sha1", filter them out here: + foreach my $p (@parents) { + next unless defined $p; + if ($p =~ /^(\d+)=($sha1_short)$/o) { + if ($1 == $log_msg->{revision}) { + push @tmp_parents, $2; + } + } else { + push @tmp_parents, $p if $p =~ /$sha1_short/o; + } + } + my $tree = $log_msg->{tree}; + if (!defined $tree) { + my $index = set_index($GIT_SVN_INDEX); + index_changes(); + chomp($tree = `git-write-tree`); + croak $? if $?; + restore_index($index); + } + + # just in case we clobber the existing ref, we still want that ref + # as our parent: + if (my $cur = eval { file_to_s("$GIT_DIR/refs/remotes/$GIT_SVN") }) { + push @tmp_parents, $cur; + } + + if (exists $tree_map{$tree}) { + foreach my $p (@{$tree_map{$tree}}) { + my $skip; + foreach (@tmp_parents) { + # see if a common parent is found + my $mb = eval { + safe_qx('git-merge-base', $_, $p) + }; + next if ($@ || $?); + $skip = 1; + last; + } + next if $skip; + my ($url_p, $r_p, $uuid_p) = cmt_metadata($p); + next if (($SVN_UUID eq $uuid_p) && + ($log_msg->{revision} > $r_p)); + next if (defined $url_p && defined $SVN_URL && + ($SVN_UUID eq $uuid_p) && + ($url_p eq $SVN_URL)); + push @tmp_parents, $p; + } + } + foreach (@tmp_parents) { + next if $seen_parent{$_}; + $seen_parent{$_} = 1; + push @exec_parents, $_; + # MAXPARENT is defined to 16 in commit-tree.c: + last if @exec_parents > 16; + } + + set_commit_env($log_msg); + my @exec = ('git-commit-tree', $tree); + push @exec, '-p', $_ foreach @exec_parents; + defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec)) + or croak $!; + print $msg_fh $log_msg->{msg} or croak $!; + unless ($_no_metadata) { + print $msg_fh "\ngit-svn-id: $SVN_URL\@$log_msg->{revision}", + " $SVN_UUID\n" or croak $!; + } + $msg_fh->flush == 0 or croak $!; + close $msg_fh or croak $!; + chomp(my $commit = do { local $/; <$out_fh> }); + close $out_fh or croak $!; + waitpid $pid, 0; + croak $? if $?; + if ($commit !~ /^$sha1$/o) { + die "Failed to commit, invalid sha1: $commit\n"; + } + sys('git-update-ref',"refs/remotes/$GIT_SVN",$commit); + revdb_set($REVDB, $log_msg->{revision}, $commit); + + # this output is read via pipe, do not change: + print "r$log_msg->{revision} = $commit\n"; + check_repack(); + return $commit; +} + +sub check_repack { + if ($_repack && (--$_repack_nr == 0)) { + $_repack_nr = $_repack; + sys("git repack $_repack_flags"); + } +} + +sub set_commit_env { + my ($log_msg) = @_; + my $author = $log_msg->{author}; + if (!defined $author || length $author == 0) { + $author = '(no author)'; + } + my ($name,$email) = defined $users{$author} ? @{$users{$author}} + : ($author,"$author\@$SVN_UUID"); + $ENV{GIT_AUTHOR_NAME} = $ENV{GIT_COMMITTER_NAME} = $name; + $ENV{GIT_AUTHOR_EMAIL} = $ENV{GIT_COMMITTER_EMAIL} = $email; + $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_msg->{date}; +} + +sub apply_mod_line_blob { + my $m = shift; + if ($m->{mode_b} =~ /^120/) { + blob_to_symlink($m->{sha1_b}, $m->{file_b}); + } else { + blob_to_file($m->{sha1_b}, $m->{file_b}); + } +} + +sub blob_to_symlink { + my ($blob, $link) = @_; + defined $link or croak "\$link not defined!\n"; + croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o; + if (-l $link || -f _) { + unlink $link or croak $!; + } + + my $dest = `git-cat-file blob $blob`; # no newline, so no chomp + symlink $dest, $link or croak $!; +} + +sub blob_to_file { + my ($blob, $file) = @_; + defined $file or croak "\$file not defined!\n"; + croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o; + if (-l $file || -f _) { + unlink $file or croak $!; + } + + open my $blob_fh, '>', $file or croak "$!: $file\n"; + my $pid = fork; + defined $pid or croak $!; + + if ($pid == 0) { + open STDOUT, '>&', $blob_fh or croak $!; + exec('git-cat-file','blob',$blob) or croak $!; + } + waitpid $pid, 0; + croak $? if $?; + + close $blob_fh or croak $!; +} + +sub safe_qx { + my $pid = open my $child, '-|'; + defined $pid or croak $!; + if ($pid == 0) { + exec(@_) or croak $!; + } + my @ret = (<$child>); + close $child or croak $?; + die $? if $?; # just in case close didn't error out + return wantarray ? @ret : join('',@ret); +} + +sub svn_compat_check { + if ($_follow_parent) { + print STDERR 'E: --follow-parent functionality is only ', + "available when SVN libraries are used\n"; + exit 1; + } + my @co_help = safe_qx(qw(svn co -h)); + unless (grep /ignore-externals/,@co_help) { + print STDERR "W: Installed svn version does not support ", + "--ignore-externals\n"; + $_no_ignore_ext = 1; + } + if (grep /usage: checkout URL\[\@REV\]/,@co_help) { + $_svn_co_url_revs = 1; + } + if (grep /\[TARGET\[\@REV\]\.\.\.\]/, `svn propget -h`) { + $_svn_pg_peg_revs = 1; + } + + # I really, really hope nobody hits this... + unless (grep /stop-on-copy/, (safe_qx(qw(svn log -h)))) { + print STDERR <<''; +W: The installed svn version does not support the --stop-on-copy flag in + the log command. + Lets hope the directory you're tracking is not a branch or tag + and was never moved within the repository... + + $_no_stop_copy = 1; + } +} + +# *sigh*, new versions of svn won't honor -r without URL@, +# (and they won't honor URL@ without -r, too!) +sub svn_cmd_checkout { + my ($url, $rev, $dir) = @_; + my @cmd = ('svn','co', "-r$rev"); + push @cmd, '--ignore-externals' unless $_no_ignore_ext; + $url .= "\@$rev" if $_svn_co_url_revs; + sys(@cmd, $url, $dir); +} + +sub check_upgrade_needed { + if (!-r $REVDB) { + -d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]); + open my $fh, '>>',$REVDB or croak $!; + close $fh; + } + my $old = eval { + my $pid = open my $child, '-|'; + defined $pid or croak $!; + if ($pid == 0) { + close STDERR; + exec('git-rev-parse',"$GIT_SVN-HEAD") or croak $!; + } + my @ret = (<$child>); + close $child or croak $?; + die $? if $?; # just in case close didn't error out + return wantarray ? @ret : join('',@ret); + }; + return unless $old; + my $head = eval { safe_qx('git-rev-parse',"refs/remotes/$GIT_SVN") }; + if ($@ || !$head) { + print STDERR "Please run: $0 rebuild --upgrade\n"; + exit 1; + } +} + +# fills %tree_map with a reverse mapping of trees to commits. Useful +# for finding parents to commit on. +sub map_tree_joins { + my %seen; + foreach my $br (@_branch_from) { + my $pid = open my $pipe, '-|'; + defined $pid or croak $!; + if ($pid == 0) { + exec(qw(git-rev-list --topo-order --pretty=raw), $br) + or croak $!; + } + while (<$pipe>) { + if (/^commit ($sha1)$/o) { + my $commit = $1; + + # if we've seen a commit, + # we've seen its parents + last if $seen{$commit}; + my ($tree) = (<$pipe> =~ /^tree ($sha1)$/o); + unless (defined $tree) { + die "Failed to parse commit $commit\n"; + } + push @{$tree_map{$tree}}, $commit; + $seen{$commit} = 1; + } + } + close $pipe; # we could be breaking the pipe early + } +} + +sub load_all_refs { + if (@_branch_from) { + print STDERR '--branch|-b parameters are ignored when ', + "--branch-all-refs|-B is passed\n"; + } + + # don't worry about rev-list on non-commit objects/tags, + # it shouldn't blow up if a ref is a blob or tree... + chomp(@_branch_from = `git-rev-parse --symbolic --all`); +} + +# ' = real-name ' mapping based on git-svnimport: +sub load_authors { + open my $authors, '<', $_authors or die "Can't open $_authors $!\n"; + while (<$authors>) { + chomp; + next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; + my ($user, $name, $email) = ($1, $2, $3); + $users{$user} = [$name, $email]; + } + close $authors or croak $!; +} + +sub rload_authors { + open my $authors, '<', $_authors or die "Can't open $_authors $!\n"; + while (<$authors>) { + chomp; + next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; + my ($user, $name, $email) = ($1, $2, $3); + $rusers{"$name <$email>"} = $user; + } + close $authors or croak $!; +} + +sub svn_propget_base { + my ($p, $f) = @_; + $f .= '@BASE' if $_svn_pg_peg_revs; + return safe_qx(qw/svn propget/, $p, $f); +} + +sub git_svn_each { + my $sub = shift; + foreach (`git-rev-parse --symbolic --all`) { + next unless s#^refs/remotes/##; + chomp $_; + next unless -f "$GIT_DIR/svn/$_/info/url"; + &$sub($_); + } +} + +sub migrate_revdb { + git_svn_each(sub { + my $id = shift; + defined(my $pid = fork) or croak $!; + if (!$pid) { + $GIT_SVN = $ENV{GIT_SVN_ID} = $id; + init_vars(); + exit 0 if -r $REVDB; + print "Upgrading svn => git mapping...\n"; + -d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]); + open my $fh, '>>',$REVDB or croak $!; + close $fh; + rebuild(); + print "Done upgrading. You may now delete the ", + "deprecated $GIT_SVN_DIR/revs directory\n"; + exit 0; + } + waitpid $pid, 0; + croak $? if $?; + }); +} + +sub migration_check { + migrate_revdb() unless (-e $REVDB); + return if (-d "$GIT_DIR/svn" || !-d $GIT_DIR); + print "Upgrading repository...\n"; + unless (-d "$GIT_DIR/svn") { + mkdir "$GIT_DIR/svn" or croak $!; + } + print "Data from a previous version of git-svn exists, but\n\t", + "$GIT_SVN_DIR\n\t(required for this version ", + "($VERSION) of git-svn) does not.\n"; + + foreach my $x (`git-rev-parse --symbolic --all`) { + next unless $x =~ s#^refs/remotes/##; + chomp $x; + next unless -f "$GIT_DIR/$x/info/url"; + my $u = eval { file_to_s("$GIT_DIR/$x/info/url") }; + next unless $u; + my $dn = dirname("$GIT_DIR/svn/$x"); + mkpath([$dn]) unless -d $dn; + rename "$GIT_DIR/$x", "$GIT_DIR/svn/$x" or croak "$!: $x"; + } + migrate_revdb() if (-d $GIT_SVN_DIR && !-w $REVDB); + print "Done upgrading.\n"; +} + +sub find_rev_before { + my ($r, $id, $eq_ok) = @_; + my $f = "$GIT_DIR/svn/$id/.rev_db"; + return (undef,undef) unless -r $f; + --$r unless $eq_ok; + while ($r > 0) { + if (my $c = revdb_get($f, $r)) { + return ($r, $c); + } + --$r; + } + return (undef, undef); +} + +sub init_vars { + $GIT_SVN ||= $ENV{GIT_SVN_ID} || 'git-svn'; + $GIT_SVN_DIR = "$GIT_DIR/svn/$GIT_SVN"; + $REVDB = "$GIT_SVN_DIR/.rev_db"; + $GIT_SVN_INDEX = "$GIT_SVN_DIR/index"; + $SVN_URL = undef; + $SVN_WC = "$GIT_SVN_DIR/tree"; + %tree_map = (); +} + +# convert GetOpt::Long specs for use by git-repo-config +sub read_repo_config { + return unless -d $GIT_DIR; + my $opts = shift; + foreach my $o (keys %$opts) { + my $v = $opts->{$o}; + my ($key) = ($o =~ /^([a-z\-]+)/); + $key =~ s/-//g; + my $arg = 'git-repo-config'; + $arg .= ' --int' if ($o =~ /[:=]i$/); + $arg .= ' --bool' if ($o !~ /[:=][sfi]$/); + if (ref $v eq 'ARRAY') { + chomp(my @tmp = `$arg --get-all svn.$key`); + @$v = @tmp if @tmp; + } else { + chomp(my $tmp = `$arg --get svn.$key`); + if ($tmp && !($arg =~ / --bool / && $tmp eq 'false')) { + $$v = $tmp; + } + } + } +} + +sub set_default_vals { + if (defined $_repack) { + $_repack = 1000 if ($_repack <= 0); + $_repack_nr = $_repack; + $_repack_flags ||= '-d'; + } +} + +sub read_grafts { + my $gr_file = shift; + my ($grafts, $comments) = ({}, {}); + if (open my $fh, '<', $gr_file) { + my @tmp; + while (<$fh>) { + if (/^($sha1)\s+/) { + my $c = $1; + if (@tmp) { + @{$comments->{$c}} = @tmp; + @tmp = (); + } + foreach my $p (split /\s+/, $_) { + $grafts->{$c}->{$p} = 1; + } + } else { + push @tmp, $_; + } + } + close $fh or croak $!; + @{$comments->{'END'}} = @tmp if @tmp; + } + return ($grafts, $comments); +} + +sub write_grafts { + my ($grafts, $comments, $gr_file) = @_; + + open my $fh, '>', $gr_file or croak $!; + foreach my $c (sort keys %$grafts) { + if ($comments->{$c}) { + print $fh $_ foreach @{$comments->{$c}}; + } + my $p = $grafts->{$c}; + my %x; # real parents + delete $p->{$c}; # commits are not self-reproducing... + my $pid = open my $ch, '-|'; + defined $pid or croak $!; + if (!$pid) { + exec(qw/git-cat-file commit/, $c) or croak $!; + } + while (<$ch>) { + if (/^parent ($sha1)/) { + $x{$1} = $p->{$1} = 1; + } else { + last unless /^\S/; + } + } + close $ch; # breaking the pipe + + # if real parents are the only ones in the grafts, drop it + next if join(' ',sort keys %$p) eq join(' ',sort keys %x); + + my (@ip, @jp, $mb); + my %del = %x; + @ip = @jp = keys %$p; + foreach my $i (@ip) { + next if $del{$i} || $p->{$i} == 2; + foreach my $j (@jp) { + next if $i eq $j || $del{$j} || $p->{$j} == 2; + $mb = eval { safe_qx('git-merge-base',$i,$j) }; + next unless $mb; + chomp $mb; + next if $x{$mb}; + if ($mb eq $j) { + delete $p->{$i}; + $del{$i} = 1; + } elsif ($mb eq $i) { + delete $p->{$j}; + $del{$j} = 1; + } + } + } + + # if real parents are the only ones in the grafts, drop it + next if join(' ',sort keys %$p) eq join(' ',sort keys %x); + + print $fh $c, ' ', join(' ', sort keys %$p),"\n"; + } + if ($comments->{'END'}) { + print $fh $_ foreach @{$comments->{'END'}}; + } + close $fh or croak $!; +} + +sub read_url_paths_all { + my ($l_map, $pfx, $p) = @_; + my @dir; + foreach (<$p/*>) { + if (-r "$_/info/url") { + $pfx .= '/' if $pfx && $pfx !~ m!/$!; + my $id = $pfx . basename $_; + my $url = file_to_s("$_/info/url"); + my ($u, $p) = repo_path_split($url); + $l_map->{$u}->{$p} = $id; + } elsif (-d $_) { + push @dir, $_; + } + } + foreach (@dir) { + my $x = $_; + $x =~ s!^\Q$GIT_DIR\E/svn/!!o; + read_url_paths_all($l_map, $x, $_); + } +} + +# this one only gets ids that have been imported, not new ones +sub read_url_paths { + my $l_map = {}; + git_svn_each(sub { my $x = shift; + my $url = file_to_s("$GIT_DIR/svn/$x/info/url"); + my ($u, $p) = repo_path_split($url); + $l_map->{$u}->{$p} = $x; + }); + return $l_map; +} + +sub extract_metadata { + my $id = shift or return (undef, undef, undef); + my ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\s(\S+?)\@(\d+) + \s([a-f\d\-]+)$/x); + if (!$rev || !$uuid || !$url) { + # some of the original repositories I made had + # indentifiers like this: + ($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)\@([a-f\d\-]+)/); + } + return ($url, $rev, $uuid); +} + +sub cmt_metadata { + return extract_metadata((grep(/^git-svn-id: /, + safe_qx(qw/git-cat-file commit/, shift)))[-1]); +} + +sub get_commit_time { + my $cmt = shift; + defined(my $pid = open my $fh, '-|') or croak $!; + if (!$pid) { + exec qw/git-rev-list --pretty=raw -n1/, $cmt or croak $!; + } + while (<$fh>) { + /^committer\s(?:.+) (\d+) ([\-\+]?\d+)$/ or next; + my ($s, $tz) = ($1, $2); + if ($tz =~ s/^\+//) { + $s += tz_to_s_offset($tz); + } elsif ($tz =~ s/^\-//) { + $s -= tz_to_s_offset($tz); + } + close $fh; + return $s; + } + die "Can't get commit time for commit: $cmt\n"; +} + +sub tz_to_s_offset { + my ($tz) = @_; + $tz =~ s/(\d\d)$//; + return ($1 * 60) + ($tz * 3600); +} + +sub setup_pager { # translated to Perl from pager.c + return unless (-t *STDOUT); + my $pager = $ENV{PAGER}; + if (!defined $pager) { + $pager = 'less'; + } elsif (length $pager == 0 || $pager eq 'cat') { + return; + } + pipe my $rfd, my $wfd or return; + defined(my $pid = fork) or croak $!; + if (!$pid) { + open STDOUT, '>&', $wfd or croak $!; + return; + } + open STDIN, '<&', $rfd or croak $!; + $ENV{LESS} ||= '-S'; + exec $pager or croak "Can't run pager: $!\n";; +} + +sub get_author_info { + my ($dest, $author, $t, $tz) = @_; + $author =~ s/(?:^\s*|\s*$)//g; + $dest->{a_raw} = $author; + my $_a; + if ($_authors) { + $_a = $rusers{$author} || undef; + } + if (!$_a) { + ($_a) = ($author =~ /<([^>]+)\@[^>]+>$/); + } + $dest->{t} = $t; + $dest->{tz} = $tz; + $dest->{a} = $_a; + # Date::Parse isn't in the standard Perl distro :( + if ($tz =~ s/^\+//) { + $t += tz_to_s_offset($tz); + } elsif ($tz =~ s/^\-//) { + $t -= tz_to_s_offset($tz); + } + $dest->{t_utc} = $t; +} + +sub process_commit { + my ($c, $r_min, $r_max, $defer) = @_; + if (defined $r_min && defined $r_max) { + if ($r_min == $c->{r} && $r_min == $r_max) { + show_commit($c); + return 0; + } + return 1 if $r_min == $r_max; + if ($r_min < $r_max) { + # we need to reverse the print order + return 0 if (defined $_limit && --$_limit < 0); + push @$defer, $c; + return 1; + } + if ($r_min != $r_max) { + return 1 if ($r_min < $c->{r}); + return 1 if ($r_max > $c->{r}); + } + } + return 0 if (defined $_limit && --$_limit < 0); + show_commit($c); + return 1; +} + +sub show_commit { + my $c = shift; + if ($_oneline) { + my $x = "\n"; + if (my $l = $c->{l}) { + while ($l->[0] =~ /^\s*$/) { shift @$l } + $x = $l->[0]; + } + $_l_fmt ||= 'A' . length($c->{r}); + print 'r',pack($_l_fmt, $c->{r}),' | '; + print "$c->{c} | " if $_show_commit; + print $x; + } else { + show_commit_normal($c); + } +} + +sub show_commit_normal { + my ($c) = @_; + print '-' x72, "\nr$c->{r} | "; + print "$c->{c} | " if $_show_commit; + print "$c->{a} | ", strftime("%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)", + localtime($c->{t_utc})), ' | '; + my $nr_line = 0; + + if (my $l = $c->{l}) { + while ($l->[$#$l] eq "\n" && $l->[($#$l - 1)] eq "\n") { + pop @$l; + } + $nr_line = scalar @$l; + if (!$nr_line) { + print "1 line\n\n\n"; + } else { + if ($nr_line == 1) { + $nr_line = '1 line'; + } else { + $nr_line .= ' lines'; + } + print $nr_line, "\n\n"; + print $_ foreach @$l; + } + } else { + print "1 line\n\n"; + + } + foreach my $x (qw/raw diff/) { + if ($c->{$x}) { + print "\n"; + print $_ foreach @{$c->{$x}} + } + } +} + +sub libsvn_load { + return unless $_use_lib; + $_use_lib = eval { + require SVN::Core; + if ($SVN::Core::VERSION lt '1.1.0') { + die "Need SVN::Core 1.1.0 or better ", + "(got $SVN::Core::VERSION) ", + "Falling back to command-line svn\n"; + } + require SVN::Ra; + require SVN::Delta; + push @SVN::Git::Editor::ISA, 'SVN::Delta::Editor'; + my $kill_stupid_warnings = $SVN::Node::none.$SVN::Node::file. + $SVN::Node::dir.$SVN::Node::unknown. + $SVN::Node::none.$SVN::Node::file. + $SVN::Node::dir.$SVN::Node::unknown; + 1; + }; +} + +sub libsvn_connect { + my ($url) = @_; + my $auth = SVN::Core::auth_open([SVN::Client::get_simple_provider(), + SVN::Client::get_ssl_server_trust_file_provider(), + SVN::Client::get_username_provider()]); + my $s = eval { SVN::Ra->new(url => $url, auth => $auth) }; + return $s; +} + +sub libsvn_get_file { + my ($gui, $f, $rev) = @_; + my $p = $f; + return unless ($p =~ s#^\Q$SVN_PATH\E/##); + + my ($hash, $pid, $in, $out); + my $pool = SVN::Pool->new; + defined($pid = open3($in, $out, '>&STDERR', + qw/git-hash-object -w --stdin/)) or croak $!; + # redirect STDOUT for SVN 1.1.x compatibility + open my $stdout, '>&', \*STDOUT or croak $!; + open STDOUT, '>&', $in or croak $!; + my ($r, $props) = $SVN->get_file($f, $rev, \*STDOUT, $pool); + $in->flush == 0 or croak $!; + open STDOUT, '>&', $stdout or croak $!; + close $in or croak $!; + close $stdout or croak $!; + $pool->clear; + chomp($hash = do { local $/; <$out> }); + close $out or croak $!; + waitpid $pid, 0; + $hash =~ /^$sha1$/o or die "not a sha1: $hash\n"; + + my $mode = exists $props->{'svn:executable'} ? '100755' : '100644'; + if (exists $props->{'svn:special'}) { + $mode = '120000'; + my $link = `git-cat-file blob $hash`; + $link =~ s/^link // or die "svn:special file with contents: <", + $link, "> is not understood\n"; + defined($pid = open3($in, $out, '>&STDERR', + qw/git-hash-object -w --stdin/)) or croak $!; + print $in $link; + $in->flush == 0 or croak $!; + close $in or croak $!; + chomp($hash = do { local $/; <$out> }); + close $out or croak $!; + waitpid $pid, 0; + $hash =~ /^$sha1$/o or die "not a sha1: $hash\n"; + } + print $gui $mode,' ',$hash,"\t",$p,"\0" or croak $!; +} + +sub libsvn_log_entry { + my ($rev, $author, $date, $msg, $parents) = @_; + my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T + (\d\d)\:(\d\d)\:(\d\d).\d+Z$/x) + or die "Unable to parse date: $date\n"; + if (defined $_authors && ! defined $users{$author}) { + die "Author: $author not defined in $_authors file\n"; + } + return { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S", + author => $author, msg => $msg."\n", parents => $parents || [] } +} + +sub process_rm { + my ($gui, $last_commit, $f) = @_; + $f =~ s#^\Q$SVN_PATH\E/?## or return; + # remove entire directories. + if (safe_qx('git-ls-tree',$last_commit,'--',$f) =~ /^040000 tree/) { + defined(my $pid = open my $ls, '-|') or croak $!; + if (!$pid) { + exec(qw/git-ls-tree -r --name-only -z/, + $last_commit,'--',$f) or croak $!; + } + local $/ = "\0"; + while (<$ls>) { + print $gui '0 ',0 x 40,"\t",$_ or croak $!; + } + close $ls or croak $?; + } else { + print $gui '0 ',0 x 40,"\t",$f,"\0" or croak $!; + } +} + +sub libsvn_fetch { + my ($last_commit, $paths, $rev, $author, $date, $msg) = @_; + open my $gui, '| git-update-index -z --index-info' or croak $!; + my @amr; + foreach my $f (keys %$paths) { + my $m = $paths->{$f}->action(); + $f =~ s#^/+##; + if ($m =~ /^[DR]$/) { + print "\t$m\t$f\n" unless $_q; + process_rm($gui, $last_commit, $f); + next if $m eq 'D'; + # 'R' can be file replacements, too, right? + } + my $pool = SVN::Pool->new; + my $t = $SVN->check_path($f, $rev, $pool); + if ($t == $SVN::Node::file) { + if ($m =~ /^[AMR]$/) { + push @amr, [ $m, $f ]; + } else { + die "Unrecognized action: $m, ($f r$rev)\n"; + } + } + $pool->clear; + } + foreach (@amr) { + print "\t$_->[0]\t$_->[1]\n" unless $_q; + libsvn_get_file($gui, $_->[1], $rev) + } + close $gui or croak $?; + return libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]); +} + +sub svn_grab_base_rev { + defined(my $pid = open my $fh, '-|') or croak $!; + if (!$pid) { + open my $null, '>', '/dev/null' or croak $!; + open STDERR, '>&', $null or croak $!; + exec qw/git-rev-parse --verify/,"refs/remotes/$GIT_SVN^0" + or croak $!; + } + chomp(my $c = do { local $/; <$fh> }); + close $fh; + if (defined $c && length $c) { + my ($url, $rev, $uuid) = cmt_metadata($c); + return ($rev, $c) if defined $rev; + } + if ($_no_metadata) { + my $offset = -41; # from tail + my $rl; + open my $fh, '<', $REVDB or + die "--no-metadata specified and $REVDB not readable\n"; + seek $fh, $offset, 2; + $rl = readline $fh; + defined $rl or return (undef, undef); + chomp $rl; + while ($c ne $rl && tell $fh != 0) { + $offset -= 41; + seek $fh, $offset, 2; + $rl = readline $fh; + defined $rl or return (undef, undef); + chomp $rl; + } + my $rev = tell $fh; + croak $! if ($rev < -1); + $rev = ($rev - 41) / 41; + close $fh or croak $!; + return ($rev, $c); + } + return (undef, undef); +} + +sub libsvn_parse_revision { + my $base = shift; + my $head = $SVN->get_latest_revnum(); + if (!defined $_revision || $_revision eq 'BASE:HEAD') { + return ($base + 1, $head) if (defined $base); + return (0, $head); + } + return ($1, $2) if ($_revision =~ /^(\d+):(\d+)$/); + return ($_revision, $_revision) if ($_revision =~ /^\d+$/); + if ($_revision =~ /^BASE:(\d+)$/) { + return ($base + 1, $1) if (defined $base); + return (0, $head); + } + return ($1, $head) if ($_revision =~ /^(\d+):HEAD$/); + die "revision argument: $_revision not understood by git-svn\n", + "Try using the command-line svn client instead\n"; +} + +sub libsvn_traverse { + my ($gui, $pfx, $path, $rev) = @_; + my $cwd = "$pfx/$path"; + my $pool = SVN::Pool->new; + $cwd =~ s#^/+##g; + my ($dirent, $r, $props) = $SVN->get_dir($cwd, $rev, $pool); + foreach my $d (keys %$dirent) { + my $t = $dirent->{$d}->kind; + if ($t == $SVN::Node::dir) { + libsvn_traverse($gui, $cwd, $d, $rev); + } elsif ($t == $SVN::Node::file) { + print "\tA\t$cwd/$d\n" unless $_q; + libsvn_get_file($gui, "$cwd/$d", $rev); + } + } + $pool->clear; +} + +sub libsvn_traverse_ignore { + my ($fh, $path, $r) = @_; + $path =~ s#^/+##g; + my $pool = SVN::Pool->new; + my ($dirent, undef, $props) = $SVN->get_dir($path, $r, $pool); + my $p = $path; + $p =~ s#^\Q$SVN_PATH\E/?##; + print $fh length $p ? "\n# $p\n" : "\n# /\n"; + if (my $s = $props->{'svn:ignore'}) { + $s =~ s/[\r\n]+/\n/g; + chomp $s; + if (length $p == 0) { + $s =~ s#\n#\n/$p#g; + print $fh "/$s\n"; + } else { + $s =~ s#\n#\n/$p/#g; + print $fh "/$p/$s\n"; + } + } + foreach (sort keys %$dirent) { + next if $dirent->{$_}->kind != $SVN::Node::dir; + libsvn_traverse_ignore($fh, "$path/$_", $r); + } + $pool->clear; +} + +sub revisions_eq { + my ($path, $r0, $r1) = @_; + return 1 if $r0 == $r1; + my $nr = 0; + if ($_use_lib) { + # should be OK to use Pool here (r1 - r0) should be small + my $pool = SVN::Pool->new; + libsvn_get_log($SVN, "/$path", $r0, $r1, + 0, 1, 1, sub {$nr++}, $pool); + $pool->clear; + } else { + my ($url, undef) = repo_path_split($SVN_URL); + my $svn_log = svn_log_raw("$url/$path","-r$r0:$r1"); + while (next_log_entry($svn_log)) { $nr++ } + close $svn_log->{fh}; + } + return 0 if ($nr > 1); + return 1; +} + +sub libsvn_find_parent_branch { + my ($paths, $rev, $author, $date, $msg) = @_; + my $svn_path = '/'.$SVN_PATH; + + # look for a parent from another branch: + my $i = $paths->{$svn_path} or return; + my $branch_from = $i->copyfrom_path or return; + my $r = $i->copyfrom_rev; + print STDERR "Found possible branch point: ", + "$branch_from => $svn_path, $r\n"; + $branch_from =~ s#^/##; + my $l_map = {}; + read_url_paths_all($l_map, '', "$GIT_DIR/svn"); + my $url = $SVN->{url}; + defined $l_map->{$url} or return; + my $id = $l_map->{$url}->{$branch_from}; + if (!defined $id && $_follow_parent) { + print STDERR "Following parent: $branch_from\@$r\n"; + # auto create a new branch and follow it + $id = basename($branch_from); + $id .= '@'.$r if -r "$GIT_DIR/svn/$id"; + while (-r "$GIT_DIR/svn/$id") { + # just grow a tail if we're not unique enough :x + $id .= '-'; + } + } + return unless defined $id; + + my ($r0, $parent) = find_rev_before($r,$id,1); + if ($_follow_parent && (!defined $r0 || !defined $parent)) { + defined(my $pid = fork) or croak $!; + if (!$pid) { + $GIT_SVN = $ENV{GIT_SVN_ID} = $id; + init_vars(); + $SVN_URL = "$url/$branch_from"; + $SVN_LOG = $SVN = undef; + setup_git_svn(); + # we can't assume SVN_URL exists at r+1: + $_revision = "0:$r"; + fetch_lib(); + exit 0; + } + waitpid $pid, 0; + croak $? if $?; + ($r0, $parent) = find_rev_before($r,$id,1); + } + return unless (defined $r0 && defined $parent); + if (revisions_eq($branch_from, $r0, $r)) { + unlink $GIT_SVN_INDEX; + print STDERR "Found branch parent: ($GIT_SVN) $parent\n"; + sys(qw/git-read-tree/, $parent); + return libsvn_fetch($parent, $paths, $rev, + $author, $date, $msg); + } + print STDERR "Nope, branch point not imported or unknown\n"; + return undef; +} + +sub libsvn_get_log { + my ($ra, @args) = @_; + if ($SVN::Core::VERSION le '1.2.0') { + splice(@args, 3, 1); + } + $ra->get_log(@args); +} + +sub libsvn_new_tree { + if (my $log_entry = libsvn_find_parent_branch(@_)) { + return $log_entry; + } + my ($paths, $rev, $author, $date, $msg) = @_; + open my $gui, '| git-update-index -z --index-info' or croak $!; + my $pool = SVN::Pool->new; + libsvn_traverse($gui, '', $SVN_PATH, $rev, $pool); + $pool->clear; + close $gui or croak $?; + return libsvn_log_entry($rev, $author, $date, $msg); +} + +sub find_graft_path_commit { + my ($tree_paths, $p1, $r1) = @_; + foreach my $x (keys %$tree_paths) { + next unless ($p1 =~ /^\Q$x\E/); + my $i = $tree_paths->{$x}; + my ($r0, $parent) = find_rev_before($r1,$i,1); + return $parent if (defined $r0 && $r0 == $r1); + print STDERR "r$r1 of $i not imported\n"; + next; + } + return undef; +} + +sub find_graft_path_parents { + my ($grafts, $tree_paths, $c, $p0, $r0) = @_; + foreach my $x (keys %$tree_paths) { + next unless ($p0 =~ /^\Q$x\E/); + my $i = $tree_paths->{$x}; + my ($r, $parent) = find_rev_before($r0, $i, 1); + if (defined $r && defined $parent && revisions_eq($x,$r,$r0)) { + my ($url_b, undef, $uuid_b) = cmt_metadata($c); + my ($url_a, undef, $uuid_a) = cmt_metadata($parent); + next if ($url_a && $url_b && $url_a eq $url_b && + $uuid_b eq $uuid_a); + $grafts->{$c}->{$parent} = 1; + } + } +} + +sub libsvn_graft_file_copies { + my ($grafts, $tree_paths, $path, $paths, $rev) = @_; + foreach (keys %$paths) { + my $i = $paths->{$_}; + my ($m, $p0, $r0) = ($i->action, $i->copyfrom_path, + $i->copyfrom_rev); + next unless (defined $p0 && defined $r0); + + my $p1 = $_; + $p1 =~ s#^/##; + $p0 =~ s#^/##; + my $c = find_graft_path_commit($tree_paths, $p1, $rev); + next unless $c; + find_graft_path_parents($grafts, $tree_paths, $c, $p0, $r0); + } +} + +sub set_index { + my $old = $ENV{GIT_INDEX_FILE}; + $ENV{GIT_INDEX_FILE} = shift; + return $old; +} + +sub restore_index { + my ($old) = @_; + if (defined $old) { + $ENV{GIT_INDEX_FILE} = $old; + } else { + delete $ENV{GIT_INDEX_FILE}; + } +} + +sub libsvn_commit_cb { + my ($rev, $date, $committer, $c, $msg, $r_last, $cmt_last) = @_; + if ($_optimize_commits && $rev == ($r_last + 1)) { + my $log = libsvn_log_entry($rev,$committer,$date,$msg); + $log->{tree} = get_tree_from_treeish($c); + my $cmt = git_commit($log, $cmt_last, $c); + my @diff = safe_qx('git-diff-tree', $cmt, $c); + if (@diff) { + print STDERR "Trees differ: $cmt $c\n", + join('',@diff),"\n"; + exit 1; + } + } else { + fetch("$rev=$c"); + } +} + +sub libsvn_ls_fullurl { + my $fullurl = shift; + my ($repo, $path) = repo_path_split($fullurl); + $SVN ||= libsvn_connect($repo); + my @ret; + my $pool = SVN::Pool->new; + my ($dirent, undef, undef) = $SVN->get_dir($path, + $SVN->get_latest_revnum, $pool); + foreach my $d (keys %$dirent) { + if ($dirent->{$d}->kind == $SVN::Node::dir) { + push @ret, "$d/"; # add '/' for compat with cli svn + } + } + $pool->clear; + return @ret; +} + + +sub libsvn_skip_unknown_revs { + my $err = shift; + my $errno = $err->apr_err(); + # Maybe the branch we're tracking didn't + # exist when the repo started, so it's + # not an error if it doesn't, just continue + # + # Wonderfully consistent library, eh? + # 160013 - svn:// and file:// + # 175002 - http(s):// + # More codes may be discovered later... + if ($errno == 175002 || $errno == 160013) { + return; + } + croak "Error from SVN, ($errno): ", $err->expanded_message,"\n"; +}; + +# Tie::File seems to be prone to offset errors if revisions get sparse, +# it's not that fast, either. Tie::File is also not in Perl 5.6. So +# one of my favorite modules is out :< Next up would be one of the DBM +# modules, but I'm not sure which is most portable... So I'll just +# go with something that's plain-text, but still capable of +# being randomly accessed. So here's my ultra-simple fixed-width +# database. All records are 40 characters + "\n", so it's easy to seek +# to a revision: (41 * rev) is the byte offset. +# A record of 40 0s denotes an empty revision. +# And yes, it's still pretty fast (faster than Tie::File). +sub revdb_set { + my ($file, $rev, $commit) = @_; + length $commit == 40 or croak "arg3 must be a full SHA1 hexsum\n"; + open my $fh, '+<', $file or croak $!; + my $offset = $rev * 41; + # assume that append is the common case: + seek $fh, 0, 2 or croak $!; + my $pos = tell $fh; + if ($pos < $offset) { + print $fh (('0' x 40),"\n") x (($offset - $pos) / 41); + } + seek $fh, $offset, 0 or croak $!; + print $fh $commit,"\n"; + close $fh or croak $!; +} + +sub revdb_get { + my ($file, $rev) = @_; + my $ret; + my $offset = $rev * 41; + open my $fh, '<', $file or croak $!; + seek $fh, $offset, 0; + if (tell $fh == $offset) { + $ret = readline $fh; + if (defined $ret) { + chomp $ret; + $ret = undef if ($ret =~ /^0{40}$/); + } + } + close $fh or croak $!; + return $ret; +} + +sub copy_remote_ref { + my $origin = $_cp_remote ? $_cp_remote : 'origin'; + my $ref = "refs/remotes/$GIT_SVN"; + if (safe_qx('git-ls-remote', $origin, $ref)) { + sys(qw/git fetch/, $origin, "$ref:$ref"); + } else { + die "Unable to find remote reference: ", + "refs/remotes/$GIT_SVN on $origin\n"; + } +} + +package SVN::Git::Editor; +use vars qw/@ISA/; +use strict; +use warnings; +use Carp qw/croak/; +use IO::File; + +sub new { + my $class = shift; + my $git_svn = shift; + my $self = SVN::Delta::Editor->new(@_); + bless $self, $class; + foreach (qw/svn_path c r ra /) { + die "$_ required!\n" unless (defined $git_svn->{$_}); + $self->{$_} = $git_svn->{$_}; + } + $self->{pool} = SVN::Pool->new; + $self->{bat} = { '' => $self->open_root($self->{r}, $self->{pool}) }; + $self->{rm} = { }; + require Digest::MD5; + return $self; +} + +sub split_path { + return ($_[0] =~ m#^(.*?)/?([^/]+)$#); +} + +sub repo_path { + (defined $_[1] && length $_[1]) ? "$_[0]->{svn_path}/$_[1]" + : $_[0]->{svn_path} +} + +sub url_path { + my ($self, $path) = @_; + $self->{ra}->{url} . '/' . $self->repo_path($path); +} + +sub rmdirs { + my ($self, $q) = @_; + my $rm = $self->{rm}; + delete $rm->{''}; # we never delete the url we're tracking + return unless %$rm; + + foreach (keys %$rm) { + my @d = split m#/#, $_; + my $c = shift @d; + $rm->{$c} = 1; + while (@d) { + $c .= '/' . shift @d; + $rm->{$c} = 1; + } + } + delete $rm->{$self->{svn_path}}; + delete $rm->{''}; # we never delete the url we're tracking + return unless %$rm; + + defined(my $pid = open my $fh,'-|') or croak $!; + if (!$pid) { + exec qw/git-ls-tree --name-only -r -z/, $self->{c} or croak $!; + } + local $/ = "\0"; + my @svn_path = split m#/#, $self->{svn_path}; + while (<$fh>) { + chomp; + my @dn = (@svn_path, (split m#/#, $_)); + while (pop @dn) { + delete $rm->{join '/', @dn}; + } + unless (%$rm) { + close $fh; + return; + } + } + close $fh; + + my ($r, $p, $bat) = ($self->{r}, $self->{pool}, $self->{bat}); + foreach my $d (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$rm) { + $self->close_directory($bat->{$d}, $p); + my ($dn) = ($d =~ m#^(.*?)/?(?:[^/]+)$#); + print "\tD+\t/$d/\n" unless $q; + $self->SUPER::delete_entry($d, $r, $bat->{$dn}, $p); + delete $bat->{$d}; + } +} + +sub open_or_add_dir { + my ($self, $full_path, $baton) = @_; + my $p = SVN::Pool->new; + my $t = $self->{ra}->check_path($full_path, $self->{r}, $p); + $p->clear; + if ($t == $SVN::Node::none) { + return $self->add_directory($full_path, $baton, + undef, -1, $self->{pool}); + } elsif ($t == $SVN::Node::dir) { + return $self->open_directory($full_path, $baton, + $self->{r}, $self->{pool}); + } + print STDERR "$full_path already exists in repository at ", + "r$self->{r} and it is not a directory (", + ($t == $SVN::Node::file ? 'file' : 'unknown'),"/$t)\n"; + exit 1; +} + +sub ensure_path { + my ($self, $path) = @_; + my $bat = $self->{bat}; + $path = $self->repo_path($path); + return $bat->{''} unless (length $path); + my @p = split m#/+#, $path; + my $c = shift @p; + $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''}); + while (@p) { + my $c0 = $c; + $c .= '/' . shift @p; + $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0}); + } + return $bat->{$c}; +} + +sub A { + my ($self, $m, $q) = @_; + my ($dir, $file) = split_path($m->{file_b}); + my $pbat = $self->ensure_path($dir); + my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, + undef, -1); + print "\tA\t$m->{file_b}\n" unless $q; + $self->chg_file($fbat, $m); + $self->close_file($fbat,undef,$self->{pool}); +} + +sub C { + my ($self, $m, $q) = @_; + my ($dir, $file) = split_path($m->{file_b}); + my $pbat = $self->ensure_path($dir); + my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, + $self->url_path($m->{file_a}), $self->{r}); + print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $q; + $self->chg_file($fbat, $m); + $self->close_file($fbat,undef,$self->{pool}); +} + +sub delete_entry { + my ($self, $path, $pbat) = @_; + my $rpath = $self->repo_path($path); + my ($dir, $file) = split_path($rpath); + $self->{rm}->{$dir} = 1; + $self->SUPER::delete_entry($rpath, $self->{r}, $pbat, $self->{pool}); +} + +sub R { + my ($self, $m, $q) = @_; + my ($dir, $file) = split_path($m->{file_b}); + my $pbat = $self->ensure_path($dir); + my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, + $self->url_path($m->{file_a}), $self->{r}); + print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $q; + $self->chg_file($fbat, $m); + $self->close_file($fbat,undef,$self->{pool}); + + ($dir, $file) = split_path($m->{file_a}); + $pbat = $self->ensure_path($dir); + $self->delete_entry($m->{file_a}, $pbat); +} + +sub M { + my ($self, $m, $q) = @_; + my ($dir, $file) = split_path($m->{file_b}); + my $pbat = $self->ensure_path($dir); + my $fbat = $self->open_file($self->repo_path($m->{file_b}), + $pbat,$self->{r},$self->{pool}); + print "\t$m->{chg}\t$m->{file_b}\n" unless $q; + $self->chg_file($fbat, $m); + $self->close_file($fbat,undef,$self->{pool}); +} + +sub T { shift->M(@_) } + +sub change_file_prop { + my ($self, $fbat, $pname, $pval) = @_; + $self->SUPER::change_file_prop($fbat, $pname, $pval, $self->{pool}); +} + +sub chg_file { + my ($self, $fbat, $m) = @_; + if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) { + $self->change_file_prop($fbat,'svn:executable','*'); + } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { + $self->change_file_prop($fbat,'svn:executable',undef); + } + my $fh = IO::File->new_tmpfile or croak $!; + if ($m->{mode_b} =~ /^120/) { + print $fh 'link ' or croak $!; + $self->change_file_prop($fbat,'svn:special','*'); + } elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) { + $self->change_file_prop($fbat,'svn:special',undef); + } + defined(my $pid = fork) or croak $!; + if (!$pid) { + open STDOUT, '>&', $fh or croak $!; + exec qw/git-cat-file blob/, $m->{sha1_b} or croak $!; + } + waitpid $pid, 0; + croak $? if $?; + $fh->flush == 0 or croak $!; + seek $fh, 0, 0 or croak $!; + + my $md5 = Digest::MD5->new; + $md5->addfile($fh) or croak $!; + seek $fh, 0, 0 or croak $!; + + my $exp = $md5->hexdigest; + my $atd = $self->apply_textdelta($fbat, undef, $self->{pool}); + my $got = SVN::TxDelta::send_stream($fh, @$atd, $self->{pool}); + die "Checksum mismatch\nexpected: $exp\ngot: $got\n" if ($got ne $exp); + + close $fh or croak $!; +} + +sub D { + my ($self, $m, $q) = @_; + my ($dir, $file) = split_path($m->{file_b}); + my $pbat = $self->ensure_path($dir); + print "\tD\t$m->{file_b}\n" unless $q; + $self->delete_entry($m->{file_b}, $pbat); +} + +sub close_edit { + my ($self) = @_; + my ($p,$bat) = ($self->{pool}, $self->{bat}); + foreach (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$bat) { + $self->close_directory($bat->{$_}, $p); + } + $self->SUPER::close_edit($p); + $p->clear; +} + +sub abort_edit { + my ($self) = @_; + $self->SUPER::abort_edit($self->{pool}); + $self->{pool}->clear; +} + +__END__ + +Data structures: + +$svn_log hashref (as returned by svn_log_raw) +{ + fh => file handle of the log file, + state => state of the log file parser (sep/msg/rev/msg_start...) +} + +$log_msg hashref as returned by next_log_entry($svn_log) +{ + msg => 'whitespace-formatted log entry +', # trailing newline is preserved + revision => '8', # integer + date => '2004-02-24T17:01:44.108345Z', # commit date + author => 'committer name' +}; + + +@mods = array of diff-index line hashes, each element represents one line + of diff-index output + +diff-index line ($m hash) +{ + mode_a => first column of diff-index output, no leading ':', + mode_b => second column of diff-index output, + sha1_b => sha1sum of the final blob, + chg => change type [MCRADT], + file_a => original file name of a file (iff chg is 'C' or 'R') + file_b => new/current file name of a file (any chg) +} +; + +# retval of read_url_paths{,_all}(); +$l_map = { + # repository root url + 'https://svn.musicpd.org' => { + # repository path # GIT_SVN_ID + 'mpd/trunk' => 'trunk', + 'mpd/tags/0.11.5' => 'tags/0.11.5', + }, +} + +Notes: + I don't trust the each() function on unless I created %hash myself + because the internal iterator may not have started at base. diff --git a/t/Makefile b/t/Makefile index 632c55f6d5..89835093fb 100644 --- a/t/Makefile +++ b/t/Makefile @@ -11,6 +11,7 @@ TAR ?= $(TAR) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) +TSVN = $(wildcard t91[0-9][0-9]-*.sh) ifdef NO_PYTHON GIT_TEST_OPTS += --no-python @@ -24,6 +25,15 @@ $(T): clean: rm -fr trash +# we can test NO_OPTIMIZE_COMMITS independently of LC_ALL +full-svn-test: + $(MAKE) $(TSVN) GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C + $(MAKE) $(TSVN) GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C + $(MAKE) $(TSVN) GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \ + LC_ALL=en_US.UTF-8 + $(MAKE) $(TSVN) GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \ + LC_ALL=en_US.UTF-8 + .PHONY: $(T) clean .NOTPARALLEL: diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh new file mode 100644 index 0000000000..450fee8997 --- /dev/null +++ b/t/lib-git-svn.sh @@ -0,0 +1,43 @@ +. ./test-lib.sh + +if test -n "$NO_SVN_TESTS" +then + test_expect_success 'skipping git-svn tests, NO_SVN_TESTS defined' : + test_done + exit +fi + +GIT_DIR=$PWD/.git +GIT_SVN_DIR=$GIT_DIR/svn/git-svn +SVN_TREE=$GIT_SVN_DIR/svn-tree + +svnadmin >/dev/null 2>&1 +if test $? != 1 +then + test_expect_success 'skipping git-svn tests, svnadmin not found' : + test_done + exit +fi + +svn >/dev/null 2>&1 +if test $? != 1 +then + test_expect_success 'skipping git-svn tests, svn not found' : + test_done + exit +fi + +svnrepo=$PWD/svnrepo + +set -e + +if svnadmin create --help | grep fs-type >/dev/null +then + svnadmin create --fs-type fsfs "$svnrepo" +else + svnadmin create "$svnrepo" +fi + +svnrepo="file://$svnrepo/test-git-svn" + + diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh new file mode 100755 index 0000000000..bf1d6381d9 --- /dev/null +++ b/t/t9100-git-svn-basic.sh @@ -0,0 +1,234 @@ +#!/bin/sh +# +# Copyright (c) 2006 Eric Wong +# + +test_description='git-svn basic tests' +GIT_SVN_LC_ALL=$LC_ALL + +case "$LC_ALL" in +*.UTF-8) + have_utf8=t + ;; +*) + have_utf8= + ;; +esac + +. ./lib-git-svn.sh + +echo 'define NO_SVN_TESTS to skip git-svn tests' + +mkdir import +cd import + +echo foo > foo +if test -z "$NO_SYMLINK" +then + ln -s foo foo.link +fi +mkdir -p dir/a/b/c/d/e +echo 'deep dir' > dir/a/b/c/d/e/file +mkdir -p bar +echo 'zzz' > bar/zzz +echo '#!/bin/sh' > exec.sh +chmod +x exec.sh +svn import -m 'import for git-svn' . "$svnrepo" >/dev/null + +cd .. +rm -rf import + +test_expect_success \ + 'initialize git-svn' \ + "git-svn init $svnrepo" + +test_expect_success \ + 'import an SVN revision into git' \ + 'git-svn fetch' + +test_expect_success "checkout from svn" "svn co $svnrepo $SVN_TREE" + +name='try a deep --rmdir with a commit' +git checkout -f -b mybranch remotes/git-svn +mv dir/a/b/c/d/e/file dir/file +cp dir/file file +git update-index --add --remove dir/a/b/c/d/e/file dir/file file +git commit -m "$name" + +test_expect_success "$name" \ + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch && + svn up $SVN_TREE && + test -d $SVN_TREE/dir && test ! -d $SVN_TREE/dir/a" + + +name='detect node change from file to directory #1' +mkdir dir/new_file +mv dir/file dir/new_file/file +mv dir/new_file dir/file +git update-index --remove dir/file +git update-index --add dir/file/file +git commit -m "$name" + +test_expect_failure "$name" \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch' \ + || true + + +name='detect node change from directory to file #1' +rm -rf dir $GIT_DIR/index +git checkout -f -b mybranch2 remotes/git-svn +mv bar/zzz zzz +rm -rf bar +mv zzz bar +git update-index --remove -- bar/zzz +git update-index --add -- bar +git commit -m "$name" + +test_expect_failure "$name" \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch2' \ + || true + + +name='detect node change from file to directory #2' +rm -f $GIT_DIR/index +git checkout -f -b mybranch3 remotes/git-svn +rm bar/zzz +git-update-index --remove bar/zzz +mkdir bar/zzz +echo yyy > bar/zzz/yyy +git-update-index --add bar/zzz/yyy +git commit -m "$name" + +test_expect_failure "$name" \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch3' \ + || true + + +name='detect node change from directory to file #2' +rm -f $GIT_DIR/index +git checkout -f -b mybranch4 remotes/git-svn +rm -rf dir +git update-index --remove -- dir/file +touch dir +echo asdf > dir +git update-index --add -- dir +git commit -m "$name" + +test_expect_failure "$name" \ + 'git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch4' \ + || true + + +name='remove executable bit from a file' +rm -f $GIT_DIR/index +git checkout -f -b mybranch5 remotes/git-svn +chmod -x exec.sh +git update-index exec.sh +git commit -m "$name" + +test_expect_success "$name" \ + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && + svn up $SVN_TREE && + test ! -x $SVN_TREE/exec.sh" + + +name='add executable bit back file' +chmod +x exec.sh +git update-index exec.sh +git commit -m "$name" + +test_expect_success "$name" \ + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && + svn up $SVN_TREE && + test -x $SVN_TREE/exec.sh" + + + +if test -z "$NO_SYMLINK" +then + name='executable file becomes a symlink to bar/zzz (file)' + rm exec.sh + ln -s bar/zzz exec.sh + git update-index exec.sh + git commit -m "$name" + + test_expect_success "$name" \ + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && + svn up $SVN_TREE && + test -L $SVN_TREE/exec.sh" + + name='new symlink is added to a file that was also just made executable' + chmod +x bar/zzz + ln -s bar/zzz exec-2.sh + git update-index --add bar/zzz exec-2.sh + git commit -m "$name" + + test_expect_success "$name" \ + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && + svn up $SVN_TREE && + test -x $SVN_TREE/bar/zzz && + test -L $SVN_TREE/exec-2.sh" + + name='modify a symlink to become a file' + git help > help || true + rm exec-2.sh + cp help exec-2.sh + git update-index exec-2.sh + git commit -m "$name" + + test_expect_success "$name" \ + "git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 && + svn up $SVN_TREE && + test -f $SVN_TREE/exec-2.sh && + test ! -L $SVN_TREE/exec-2.sh && + diff -u help $SVN_TREE/exec-2.sh" +fi + + +if test "$have_utf8" = t +then + name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL" + echo '# hello' >> exec-2.sh + git update-index exec-2.sh + git commit -m 'éï∏' + export LC_ALL="$GIT_SVN_LC_ALL" + test_expect_success "$name" "git-svn commit HEAD" + unset LC_ALL +else + echo "UTF-8 locale not set, test skipped ($GIT_SVN_LC_ALL)" +fi + +name='test fetch functionality (svn => git) with alternate GIT_SVN_ID' +GIT_SVN_ID=alt +export GIT_SVN_ID +test_expect_success "$name" \ + "git-svn init $svnrepo && git-svn fetch && + git-rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a && + git-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b && + diff -u a b" + +if test -n "$NO_SYMLINK" +then + test_done + exit 0 +fi + +name='check imported tree checksums expected tree checksums' +rm -f expected +if test "$have_utf8" = t +then + echo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected +fi +cat >> expected <<\EOF +tree 4b9af72bb861eaed053854ec502cf7df72618f0f +tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1 +tree 0b094cbff17168f24c302e297f55bfac65eb8bd3 +tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e +tree 56a30b966619b863674f5978696f4a3594f2fca9 +tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e +tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4 +EOF +test_expect_success "$name" "diff -u a expected" + +test_done + diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh new file mode 100755 index 0000000000..a5a235f100 --- /dev/null +++ b/t/t9101-git-svn-props.sh @@ -0,0 +1,126 @@ +#!/bin/sh +# +# Copyright (c) 2006 Eric Wong +# + +test_description='git-svn property tests' +. ./lib-git-svn.sh + +mkdir import + +a_crlf= +a_lf= +a_cr= +a_ne_crlf= +a_ne_lf= +a_ne_cr= +a_empty= +a_empty_lf= +a_empty_cr= +a_empty_crlf= + +cd import + cat >> kw.c <<\EOF +/* Somebody prematurely put a keyword into this file */ +/* $Id$ */ +EOF + + printf "Hello\r\nWorld\r\n" > crlf + a_crlf=`git-hash-object -w crlf` + printf "Hello\rWorld\r" > cr + a_cr=`git-hash-object -w cr` + printf "Hello\nWorld\n" > lf + a_lf=`git-hash-object -w lf` + + printf "Hello\r\nWorld" > ne_crlf + a_ne_crlf=`git-hash-object -w ne_crlf` + printf "Hello\nWorld" > ne_lf + a_ne_lf=`git-hash-object -w ne_lf` + printf "Hello\rWorld" > ne_cr + a_ne_cr=`git-hash-object -w ne_cr` + + touch empty + a_empty=`git-hash-object -w empty` + printf "\n" > empty_lf + a_empty_lf=`git-hash-object -w empty_lf` + printf "\r" > empty_cr + a_empty_cr=`git-hash-object -w empty_cr` + printf "\r\n" > empty_crlf + a_empty_crlf=`git-hash-object -w empty_crlf` + + svn import -m 'import for git-svn' . "$svnrepo" >/dev/null +cd .. + +rm -rf import +test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc" +test_expect_success 'setup some commits to svn' \ + 'cd test_wc && + echo Greetings >> kw.c && + svn commit -m "Not yet an Id" && + svn up && + echo Hello world >> kw.c && + svn commit -m "Modified file, but still not yet an Id" && + svn up && + svn propset svn:keywords Id kw.c && + svn commit -m "Propset Id" && + svn up && + cd ..' + +test_expect_success 'initialize git-svn' "git-svn init $svnrepo" +test_expect_success 'fetch revisions from svn' 'git-svn fetch' + +name='test svn:keywords ignoring' +test_expect_success "$name" \ + 'git checkout -b mybranch remotes/git-svn && + echo Hi again >> kw.c && + git commit -a -m "test keywoards ignoring" && + git-svn commit remotes/git-svn..mybranch && + git pull . remotes/git-svn' + +expect='/* $Id$ */' +got="`sed -ne 2p kw.c`" +test_expect_success 'raw $Id$ found in kw.c' "test '$expect' = '$got'" + +test_expect_success "propset CR on crlf files" \ + 'cd test_wc && + svn propset svn:eol-style CR empty && + svn propset svn:eol-style CR crlf && + svn propset svn:eol-style CR ne_crlf && + svn commit -m "propset CR on crlf files" && + svn up && + cd ..' + +test_expect_success 'fetch and pull latest from svn and checkout a new wc' \ + "git-svn fetch && + git pull . remotes/git-svn && + svn co $svnrepo new_wc" + +for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf +do + test_expect_success "Comparing $i" "cmp $i new_wc/$i" +done + + +cd test_wc + printf '$Id$\rHello\rWorld\r' > cr + printf '$Id$\rHello\rWorld' > ne_cr + a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git-hash-object --stdin` + a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git-hash-object --stdin` + test_expect_success 'Set CRLF on cr files' \ + 'svn propset svn:eol-style CRLF cr && + svn propset svn:eol-style CRLF ne_cr && + svn propset svn:keywords Id cr && + svn propset svn:keywords Id ne_cr && + svn commit -m "propset CRLF on cr files" && + svn up' +cd .. +test_expect_success 'fetch and pull latest from svn' \ + 'git-svn fetch && git pull . remotes/git-svn' + +b_cr="`git-hash-object cr`" +b_ne_cr="`git-hash-object ne_cr`" + +test_expect_success 'CRLF + $Id$' "test '$a_cr' = '$b_cr'" +test_expect_success 'CRLF + $Id$ (no newline)' "test '$a_ne_cr' = '$b_ne_cr'" + +test_done diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh new file mode 100755 index 0000000000..d693d183c8 --- /dev/null +++ b/t/t9102-git-svn-deep-rmdir.sh @@ -0,0 +1,29 @@ +test_description='git-svn rmdir' +. ./lib-git-svn.sh + +test_expect_success 'initialize repo' " + mkdir import && + cd import && + mkdir -p deeply/nested/directory/number/1 && + mkdir -p deeply/nested/directory/number/2 && + echo foo > deeply/nested/directory/number/1/file && + echo foo > deeply/nested/directory/number/2/another && + svn import -m 'import for git-svn' . $svnrepo && + cd .. + " + +test_expect_success 'mirror via git-svn' " + git-svn init $svnrepo && + git-svn fetch && + git checkout -f -b test-rmdir remotes/git-svn + " + +test_expect_success 'Try a commit on rmdir' " + git rm -f deeply/nested/directory/number/2/another && + git commit -a -m 'remove another' && + git-svn commit --rmdir HEAD && + svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1 + " + + +test_done diff --git a/t/t9103-git-svn-graft-branches.sh b/t/t9103-git-svn-graft-branches.sh new file mode 100755 index 0000000000..cc62d4ece8 --- /dev/null +++ b/t/t9103-git-svn-graft-branches.sh @@ -0,0 +1,63 @@ +test_description='git-svn graft-branches' +. ./lib-git-svn.sh + +test_expect_success 'initialize repo' " + mkdir import && + cd import && + mkdir -p trunk branches tags && + echo hello > trunk/readme && + svn import -m 'import for git-svn' . $svnrepo && + cd .. && + svn cp -m 'tag a' $svnrepo/trunk $svnrepo/tags/a && + svn cp -m 'branch a' $svnrepo/trunk $svnrepo/branches/a && + svn co $svnrepo wc && + cd wc && + echo feedme >> branches/a/readme && + svn commit -m hungry && + svn up && + cd trunk && + svn merge -r3:4 $svnrepo/branches/a && + svn commit -m 'merge with a' && + cd ../.. && + svn log -v $svnrepo && + git-svn init -i trunk $svnrepo/trunk && + git-svn init -i a $svnrepo/branches/a && + git-svn init -i tags/a $svnrepo/tags/a && + git-svn fetch -i tags/a && + git-svn fetch -i a && + git-svn fetch -i trunk + " + +r1=`git-rev-list remotes/trunk | tail -n1` +r2=`git-rev-list remotes/tags/a | tail -n1` +r3=`git-rev-list remotes/a | tail -n1` +r4=`git-rev-list remotes/a | head -n1` +r5=`git-rev-list remotes/trunk | head -n1` + +test_expect_success 'test graft-branches regexes and copies' " + test -n "$r1" && + test -n "$r2" && + test -n "$r3" && + test -n "$r4" && + test -n "$r5" && + git-svn graft-branches && + grep '^$r2 $r1' $GIT_DIR/info/grafts && + grep '^$r3 $r1' $GIT_DIR/info/grafts && + grep '^$r5 ' $GIT_DIR/info/grafts | grep '$r4' | grep '$r1' + " + +test_debug 'gitk --all & sleep 1' + +test_expect_success 'test graft-branches with tree-joins' " + rm $GIT_DIR/info/grafts && + git-svn graft-branches --no-default-regex --no-graft-copy -B && + grep '^$r3 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r2' && + grep '^$r2 $r1' $GIT_DIR/info/grafts && + grep '^$r5 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r4' + " + +# the result of this is kinda funky, we have a strange history and +# this is just a test :) +test_debug 'gitk --all &' + +test_done diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh new file mode 100755 index 0000000000..01488ff78a --- /dev/null +++ b/t/t9104-git-svn-follow-parent.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# +# Copyright (c) 2006 Eric Wong +# + +test_description='git-svn --follow-parent fetching' +. ./lib-git-svn.sh + +if test -n "$GIT_SVN_NO_LIB" && test "$GIT_SVN_NO_LIB" -ne 0 +then + echo 'Skipping: --follow-parent needs SVN libraries' + test_done + exit 0 +fi + +test_expect_success 'initialize repo' " + mkdir import && + cd import && + mkdir -p trunk && + echo hello > trunk/readme && + svn import -m 'initial' . $svnrepo && + cd .. && + svn co $svnrepo wc && + cd wc && + echo world >> trunk/readme && + svn commit -m 'another commit' && + svn up && + svn mv -m 'rename to thunk' trunk thunk && + svn up && + echo goodbye >> thunk/readme && + svn commit -m 'bye now' && + cd .. + " + +test_expect_success 'init and fetch --follow-parent a moved directory' " + git-svn init -i thunk $svnrepo/thunk && + git-svn fetch --follow-parent -i thunk && + git-rev-parse --verify refs/remotes/trunk && + test '$?' -eq '0' + " + +test_debug 'gitk --all &' + +test_done diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh new file mode 100755 index 0000000000..f994b72f80 --- /dev/null +++ b/t/t9105-git-svn-commit-diff.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# +# Copyright (c) 2006 Eric Wong +test_description='git-svn commit-diff' +. ./lib-git-svn.sh + +if test -n "$GIT_SVN_NO_LIB" && test "$GIT_SVN_NO_LIB" -ne 0 +then + echo 'Skipping: commit-diff needs SVN libraries' + test_done + exit 0 +fi + +test_expect_success 'initialize repo' " + mkdir import && + cd import && + echo hello > readme && + svn import -m 'initial' . $svnrepo && + cd .. && + echo hello > readme && + git update-index --add readme && + git commit -a -m 'initial' && + echo world >> readme && + git commit -a -m 'another' + " + +head=`git rev-parse --verify HEAD^0` +prev=`git rev-parse --verify HEAD^1` + +# the internals of the commit-diff command are the same as the regular +# commit, so only a basic test of functionality is needed since we've +# already tested commit extensively elsewhere + +test_expect_success 'test the commit-diff command' " + test -n '$prev' && test -n '$head' && + git-svn commit-diff '$prev' '$head' '$svnrepo' && + svn co $svnrepo wc && + cmp readme wc/readme + " + +test_done -- cgit v1.3-5-g9baa From 4b832e819de51bd2f32eb798cb648dc8d4064dbc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 7 Jul 2006 03:17:16 -0700 Subject: git-svn: migrate out of contrib (follow-up) Check for SVN::Core so test 910[45] don't fail if the user doesn't have those installed. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- t/lib-git-svn.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 't') diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index 450fee8997..29a1e72c61 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -11,8 +11,15 @@ GIT_DIR=$PWD/.git GIT_SVN_DIR=$GIT_DIR/svn/git-svn SVN_TREE=$GIT_SVN_DIR/svn-tree +perl -e 'use SVN::Core' >/dev/null 2>&1 +if test $? -ne 0 +then + echo 'Perl SVN libraries not found, tests requiring those will be skipped' + GIT_SVN_NO_LIB=1 +fi + svnadmin >/dev/null 2>&1 -if test $? != 1 +if test $? -ne 1 then test_expect_success 'skipping git-svn tests, svnadmin not found' : test_done @@ -20,7 +27,7 @@ then fi svn >/dev/null 2>&1 -if test $? != 1 +if test $? -ne 1 then test_expect_success 'skipping git-svn tests, svn not found' : test_done -- cgit v1.3-5-g9baa From cd6f207a445f96966eb119b874306dca291fcd22 Mon Sep 17 00:00:00 2001 From: A Large Angry SCM Date: Tue, 4 Jul 2006 17:35:20 -0700 Subject: Additional merge-base tests (revised) Signed-off-by: A Large Angry SCM --- t/t6010-merge-base.sh | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 't') diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh index 1dce123aec..b15920b852 100755 --- a/t/t6010-merge-base.sh +++ b/t/t6010-merge-base.sh @@ -44,6 +44,43 @@ A=$(doit 1 A $B) G=$(doit 7 G $B $E) H=$(doit 8 H $A $F) +# Setup for second test to demonstrate that relying on timestamps in a +# distributed SCM to provide a _consistent_ partial ordering of commits +# leads to insanity. +# +# Relative +# Structure timestamps +# +# PL PR +4 +4 +# / \/ \ / \/ \ +# L2 C2 R2 +3 -1 +3 +# | | | | | | +# L1 C1 R1 +2 -2 +2 +# | | | | | | +# L0 C0 R0 +1 -3 +1 +# \ | / \ | / +# S 0 +# +# The left and right chains of commits can be of any length and complexity as +# long as all of the timestamps are greater than that of S. + +S=$(doit 0 S) + +C0=$(doit -3 C0 $S) +C1=$(doit -2 C1 $C0) +C2=$(doit -1 C2 $C1) + +L0=$(doit 1 L0 $S) +L1=$(doit 2 L1 $L0) +L2=$(doit 3 L2 $L1) + +R0=$(doit 1 R0 $S) +R1=$(doit 2 R1 $R0) +R2=$(doit 3 R2 $R1) + +PL=$(doit 4 PL $L2 $C2) +PR=$(doit 4 PR $C2 $R2) + test_expect_success 'compute merge-base (single)' \ 'MB=$(git-merge-base G H) && expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/B"' @@ -56,4 +93,12 @@ test_expect_success 'compute merge-base with show-branch' \ 'MB=$(git-show-branch --merge-base G H) && expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/B"' +test_expect_success 'compute merge-base (single)' \ + 'MB=$(git-merge-base PL PR) && + expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/C2"' + +test_expect_success 'compute merge-base (all)' \ + 'MB=$(git-merge-base --all PL PR) && + expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/C2"' + test_done -- cgit v1.3-5-g9baa From 82e5a82fd73edb80a841f5fab1660e14b9b8f3ad Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Mon, 10 Jul 2006 01:50:18 -0400 Subject: Fix more typos, primarily in the code The only visible change is that git-blame doesn't understand "--compability" anymore, but it does accept "--compatibility" instead, which is already documented. Signed-off-by: Pavel Roskin Signed-off-by: Junio C Hamano --- Documentation/git-name-rev.txt | 2 +- blame.c | 20 ++++++++++---------- builtin-apply.c | 4 ++-- builtin-diff.c | 2 +- builtin-grep.c | 2 +- builtin-help.c | 2 +- builtin-push.c | 2 +- builtin-rm.c | 2 +- combine-diff.c | 2 +- compat/subprocess.py | 6 +++--- contrib/colordiff/colordiff.perl | 2 +- diff-delta.c | 6 +++--- fetch-clone.c | 4 ++-- git-am.sh | 2 +- git-applypatch.sh | 2 +- git-archimport.perl | 8 ++++---- git-commit.sh | 2 +- git-cvsexportcommit.perl | 4 ++-- git-instaweb.sh | 2 +- git-merge-one-file.sh | 2 +- git-merge-recursive.py | 2 +- git-push.sh | 2 +- git-quiltimport.sh | 2 +- git-send-email.perl | 2 +- git-svn.perl | 2 +- name-rev.c | 2 +- pack-objects.c | 4 ++-- ppc/sha1ppc.S | 2 +- sha1_file.c | 2 +- t/t5700-clone-reference.sh | 2 +- t/t5710-info-alternate.sh | 2 +- t/t6002-rev-list-bisect.sh | 2 +- t/t6021-merge-criss-cross.sh | 2 +- xdiff/xdiffi.c | 6 +++--- 34 files changed, 56 insertions(+), 56 deletions(-) (limited to 't') diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt index 39a1434a0e..43f8c2593d 100644 --- a/Documentation/git-name-rev.txt +++ b/Documentation/git-name-rev.txt @@ -26,7 +26,7 @@ OPTIONS List all commits reachable from all refs --stdin:: - Read from stdin, append "()" to all sha1's of name'able + Read from stdin, append "()" to all sha1's of nameable commits, and pass to stdout EXAMPLE diff --git a/blame.c b/blame.c index c86e2fd4b3..0a06026168 100644 --- a/blame.c +++ b/blame.c @@ -21,11 +21,11 @@ #define DEBUG 0 static const char blame_usage[] = "[-c] [-l] [-t] [-S ] [--] file [commit]\n" - " -c, --compability Use the same output mode as git-annotate (Default: off)\n" - " -l, --long Show long commit SHA1 (Default: off)\n" - " -t, --time Show raw timestamp (Default: off)\n" - " -S, --revs-file Use revisions from revs-file instead of calling git-rev-list\n" - " -h, --help This message"; + " -c, --compatibility Use the same output mode as git-annotate (Default: off)\n" + " -l, --long Show long commit SHA1 (Default: off)\n" + " -t, --time Show raw timestamp (Default: off)\n" + " -S, --revs-file Use revisions from revs-file instead of calling git-rev-list\n" + " -h, --help This message"; static struct commit **blame_lines; static int num_blame_lines; @@ -747,7 +747,7 @@ int main(int argc, const char **argv) const char *filename = NULL, *commit = NULL; char filename_buf[256]; int sha1_len = 8; - int compability = 0; + int compatibility = 0; int show_raw_time = 0; int options = 1; struct commit* start_commit; @@ -774,8 +774,8 @@ int main(int argc, const char **argv) sha1_len = 40; continue; } else if(!strcmp(argv[i], "-c") || - !strcmp(argv[i], "--compability")) { - compability = 1; + !strcmp(argv[i], "--compatibility")) { + compatibility = 1; continue; } else if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--time")) { @@ -784,7 +784,7 @@ int main(int argc, const char **argv) } else if(!strcmp(argv[i], "-S")) { if (i + 1 < argc && !read_ancestry(argv[i + 1], &sha1_p)) { - compability = 1; + compatibility = 1; i++; continue; } @@ -884,7 +884,7 @@ int main(int argc, const char **argv) u = c->util; get_commit_info(c, &ci); fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout); - if(compability) { + if(compatibility) { printf("\t(%10s\t%10s\t%d)", ci.author, format_time(ci.author_time, ci.author_tz, show_raw_time), diff --git a/builtin-apply.c b/builtin-apply.c index c3af48917c..1e5b846dd3 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -765,7 +765,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc continue; /* - * Make sure we don't find any unconnected patch fragmants. + * Make sure we don't find any unconnected patch fragments. * That's a sign that we didn't find a header, and that a * patch has become corrupted/broken up. */ @@ -990,7 +990,7 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch) * so one line can fit up to 13 groups that would decode * to 52 bytes max. The length byte 'A'-'Z' corresponds * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes. - * The end of binary is signalled with an empty line. + * The end of binary is signaled with an empty line. */ int llen, used; struct fragment *fragment; diff --git a/builtin-diff.c b/builtin-diff.c index 1df531ba28..ae901dd25e 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -176,7 +176,7 @@ static int builtin_diff_tree(struct rev_info *revs, usage(builtin_diff_usage); /* We saw two trees, ent[0] and ent[1]. - * if ent[1] is unintesting, they are swapped + * if ent[1] is uninteresting, they are swapped */ if (ent[1].item->flags & UNINTERESTING) swap = 1; diff --git a/builtin-grep.c b/builtin-grep.c index 743ca8c692..4c2f7dfe03 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -941,7 +941,7 @@ int cmd_grep(int argc, const char **argv, char **envp) * pattern, but then what follows it must be zero or more * valid refs up to the -- (if exists), and then existing * paths. If there is an explicit pattern, then the first - * unrecocnized non option is the beginning of the refs list + * unrecognized non option is the beginning of the refs list * that continues up to the -- (if exists), and then paths. */ diff --git a/builtin-help.c b/builtin-help.c index 7470faa566..335fe5fedc 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -12,7 +12,7 @@ static const char git_usage[] = "Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; -/* most gui terms set COLUMNS (although some don't export it) */ +/* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) { char *col_string = getenv("COLUMNS"); diff --git a/builtin-push.c b/builtin-push.c index 66b9407822..a8fac886f1 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -104,7 +104,7 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI]) if (n < MAX_URI) uri[n++] = strdup(s); else - error("more than %d URL's specified, ignoreing the rest", MAX_URI); + error("more than %d URL's specified, ignoring the rest", MAX_URI); } else if (is_refspec && !has_explicit_refspec) add_refspec(strdup(s)); diff --git a/builtin-rm.c b/builtin-rm.c index 875d8252fa..5deb811719 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -129,7 +129,7 @@ int cmd_rm(int argc, const char **argv, char **envp) * workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: - * by then we've already committed ourself and can't fail + * by then we've already committed ourselves and can't fail * in the middle) */ if (force) { diff --git a/combine-diff.c b/combine-diff.c index caffb926ea..1bc1484645 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -320,7 +320,7 @@ static int give_context(struct sline *sline, unsigned long cnt, int num_parent) unsigned long i; /* Two groups of interesting lines may have a short gap of - * unintersting lines. Connect such groups to give them a + * uninteresting lines. Connect such groups to give them a * bit of context. * * We first start from what the interesting() function says, diff --git a/compat/subprocess.py b/compat/subprocess.py index bbd26c7b0e..6474eab119 100644 --- a/compat/subprocess.py +++ b/compat/subprocess.py @@ -568,7 +568,7 @@ class Popen(object): # Windows methods # def _get_handles(self, stdin, stdout, stderr): - """Construct and return tupel with IO objects: + """Construct and return tuple with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite """ if stdin == None and stdout == None and stderr == None: @@ -635,7 +635,7 @@ class Popen(object): def _find_w9xpopen(self): - """Find and return absolut path to w9xpopen.exe""" + """Find and return absolute path to w9xpopen.exe""" w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), "w9xpopen.exe") if not os.path.exists(w9xpopen): @@ -812,7 +812,7 @@ class Popen(object): # POSIX methods # def _get_handles(self, stdin, stdout, stderr): - """Construct and return tupel with IO objects: + """Construct and return tuple with IO objects: p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite """ p2cread, p2cwrite = None, None diff --git a/contrib/colordiff/colordiff.perl b/contrib/colordiff/colordiff.perl index 5789cfb265..9566a765ef 100755 --- a/contrib/colordiff/colordiff.perl +++ b/contrib/colordiff/colordiff.perl @@ -110,7 +110,7 @@ foreach $config_file (@config_files) { } } -# colordiff specfic options here. Need to pre-declare if using variables +# colordiff specific options here. Need to pre-declare if using variables GetOptions( "no-banner" => sub { $show_banner = 0 }, "plain-text=s" => \&set_color, diff --git a/diff-delta.c b/diff-delta.c index 8b9172aa2e..7da9205a5d 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -148,7 +148,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) return NULL; /* Determine index hash size. Note that indexing skips the - first byte to allow for optimizing the rabin polynomial + first byte to allow for optimizing the Rabin's polynomial initialization in create_delta(). */ entries = (bufsize - 1) / RABIN_WINDOW; hsize = entries / 4; @@ -205,7 +205,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize) /* * Determine a limit on the number of entries in the same hash - * bucket. This guard us against patological data sets causing + * bucket. This guards us against pathological data sets causing * really bad hash distribution with most entries in the same hash * bucket that would bring us to O(m*n) computing costs (m and n * corresponding to reference and target buffer sizes). @@ -240,7 +240,7 @@ void free_delta_index(struct delta_index *index) /* * The maximum size for any opcode sequence, including the initial header - * plus rabin window plus biggest copy. + * plus Rabin window plus biggest copy. */ #define MAX_OP_SIZE (5 + 5 + 1 + RABIN_WINDOW + 7) diff --git a/fetch-clone.c b/fetch-clone.c index c16b0c481b..81d1371296 100644 --- a/fetch-clone.c +++ b/fetch-clone.c @@ -198,8 +198,8 @@ int receive_unpack_pack(int xd[2], const char *me, int quiet, int sideband) /* * A "binary msec" is a power-of-two-msec, aka 1/1024th of a second. - * Keeing the time in that format means that "bytes / msecs" means - * is the same as kB/s (modulo rounding). + * Keeping the time in that format means that "bytes / msecs" means + * the same as kB/s (modulo rounding). * * 1000512 is a magic number (usecs in a second, rounded up by half * of 1024, to make "rounding" come out right ;) diff --git a/git-am.sh b/git-am.sh index 679045a540..db9a20a811 100755 --- a/git-am.sh +++ b/git-am.sh @@ -77,7 +77,7 @@ fall_back_3way () { # This is not so wrong. Depending on which base we picked, # orig_tree may be wildly different from ours, but his_tree # has the same set of wildly different changes in parts the - # patch did not touch, so resolve ends up cancelling them, + # patch did not touch, so resolve ends up canceling them, # saying that we reverted all those changes. git-merge-resolve $orig_tree -- HEAD $his_tree || { diff --git a/git-applypatch.sh b/git-applypatch.sh index e4b09472e1..8df2aee4c2 100755 --- a/git-applypatch.sh +++ b/git-applypatch.sh @@ -182,7 +182,7 @@ git-apply --index "$PATCHFILE" || { # This is not so wrong. Depending on which base we picked, # orig_tree may be wildly different from ours, but his_tree # has the same set of wildly different changes in parts the - # patch did not touch, so resolve ends up cancelling them, + # patch did not touch, so resolve ends up canceling them, # saying that we reverted all those changes. if git-merge-resolve $orig_tree -- HEAD $his_tree diff --git a/git-archimport.perl b/git-archimport.perl index 740bc1fd52..ada60ec240 100755 --- a/git-archimport.perl +++ b/git-archimport.perl @@ -14,7 +14,7 @@ Imports a project from one or more Arch repositories. It will follow branches and repositories within the namespaces defined by the -parameters suppplied. If it cannot find the remote branch a merge comes from +parameters supplied. If it cannot find the remote branch a merge comes from it will just import it as a regular commit. If it can find it, it will mark it as a merge whenever possible. @@ -88,7 +88,7 @@ usage if $opt_h; # $arch_branches: # values associated with keys: # =1 - Arch version / git 'branch' detected via abrowse on a limit -# >1 - Arch version / git 'branch' of an auxilliary branch we've merged +# >1 - Arch version / git 'branch' of an auxiliary branch we've merged my %arch_branches = map { $_ => 1 } @ARGV; $ENV{'TMPDIR'} = $opt_t if $opt_t; # $ENV{TMPDIR} will affect tempdir() calls: @@ -667,7 +667,7 @@ sub apply_cset { if (`find $tmp/changeset/patches -type f -name '*.patch'`) { # this can be sped up considerably by doing # (find | xargs cat) | patch - # but that cna get mucked up by patches + # but that can get mucked up by patches # with missing trailing newlines or the standard # 'missing newline' flag in the patch - possibly # produced with an old/buggy diff. @@ -1026,7 +1026,7 @@ sub commitid2pset { } -# an alterative to `command` that allows input to be passed as an array +# an alternative to `command` that allows input to be passed as an array # to work around shell problems with weird characters in arguments sub safe_pipe_capture { my @output; diff --git a/git-commit.sh b/git-commit.sh index 08d786db2f..351d13cb1e 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -599,7 +599,7 @@ then GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` && test '' != "$GIT_AUTHOR_NAME" && test '' != "$GIT_AUTHOR_EMAIL" || - die "malformatted --author parameter" + die "malformed --author parameter" export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL elif test '' != "$use_commit" then diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index 5dcb2f9a8e..5d13a54194 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -179,7 +179,7 @@ my @bfiles = grep(m/^Binary/, safe_pipe_capture('git-diff-tree', '-p', $parent, @bfiles = map { chomp } @bfiles; foreach my $f (@bfiles) { # check that the file in cvs matches the "old" file - # extract the file to $tmpdir and comparre with cmp + # extract the file to $tmpdir and compare with cmp my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}"); chomp $tree; my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`; @@ -273,7 +273,7 @@ sub cleanupcvs { } } -# An alterative to `command` that allows input to be passed as an array +# An alternative to `command` that allows input to be passed as an array # to work around shell problems with weird characters in arguments # if the exec returns non-zero we die sub safe_pipe_capture { diff --git a/git-instaweb.sh b/git-instaweb.sh index 69aef3c20b..63b18b99f6 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -25,7 +25,7 @@ conf=$GIT_DIR/gitweb/httpd.conf # Defaults: -# if installed, it doens't need further configuration (module_path) +# if installed, it doesn't need further configuration (module_path) test -z "$httpd" && httpd='lighttpd -f' # probably the most popular browser among gitweb users diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 5619409f1c..fba4b0cb5f 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -8,7 +8,7 @@ # $2 - file in branch1 SHA1 (or empty) # $3 - file in branch2 SHA1 (or empty) # $4 - pathname in repository -# $5 - orignal file mode (or empty) +# $5 - original file mode (or empty) # $6 - file in branch1 mode (or empty) # $7 - file in branch2 mode (or empty) # diff --git a/git-merge-recursive.py b/git-merge-recursive.py index ce8a31fda0..4039435ce4 100755 --- a/git-merge-recursive.py +++ b/git-merge-recursive.py @@ -47,7 +47,7 @@ cacheOnly = False def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0, ancestor=None): '''Merge the commits h1 and h2, return the resulting virtual - commit object and a flag indicating the cleaness of the merge.''' + commit object and a flag indicating the cleanness of the merge.''' assert(isinstance(h1, Commit) and isinstance(h2, Commit)) global outputIndent diff --git a/git-push.sh b/git-push.sh index f10cadbf15..21775fc21a 100755 --- a/git-push.sh +++ b/git-push.sh @@ -63,7 +63,7 @@ esac shift ;# away the initial 'x' # $# is now 0 if there was no explicit refspec on the command line -# and there was no defalt refspec to push from remotes/ file. +# and there was no default refspec to push from remotes/ file. # we will let git-send-pack to do its "matching refs" thing. case "$remote" in diff --git a/git-quiltimport.sh b/git-quiltimport.sh index 86b51abd21..364baff806 100755 --- a/git-quiltimport.sh +++ b/git-quiltimport.sh @@ -49,7 +49,7 @@ if [ -n "$quilt_author" ] ; then quilt_author_email=$(expr "z$quilt_author" : '.*<\([^>]*\)') && test '' != "$quilt_author_name" && test '' != "$quilt_author_email" || - die "malformatted --author parameter" + die "malformed --author parameter" fi # Quilt patch directory diff --git a/git-send-email.perl b/git-send-email.perl index c9c1975b7f..d7f5dce489 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -361,7 +361,7 @@ Options: --smtp-server If set, specifies the outgoing SMTP server to use. Defaults to localhost. - --suppress-from Supress sending emails to yourself if your address + --suppress-from Suppress sending emails to yourself if your address appears in a From: line. --quiet Make git-send-email less verbose. One line per email should be diff --git a/git-svn.perl b/git-svn.perl index f04e269939..4530ffe42c 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2429,7 +2429,7 @@ sub extract_metadata { \s([a-f\d\-]+)$/x); if (!$rev || !$uuid || !$url) { # some of the original repositories I made had - # indentifiers like this: + # identifiers like this: ($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)\@([a-f\d\-]+)/); } return ($url, $rev, $uuid); diff --git a/name-rev.c b/name-rev.c index 6a23f2d8a2..083d067e17 100644 --- a/name-rev.c +++ b/name-rev.c @@ -5,7 +5,7 @@ #include "refs.h" static const char name_rev_usage[] = - "git-name-rev [--tags] ( --all | --stdin | commitish [commitish...] )\n"; + "git-name-rev [--tags] ( --all | --stdin | committish [committish...] )\n"; typedef struct rev_name { const char *tip_name; diff --git a/pack-objects.c b/pack-objects.c index b486ea528a..04a48b925b 100644 --- a/pack-objects.c +++ b/pack-objects.c @@ -28,7 +28,7 @@ struct object_entry { struct object_entry *delta; /* delta base object */ struct packed_git *in_pack; /* already in pack */ unsigned int in_pack_offset; - struct object_entry *delta_child; /* delitified objects who bases me */ + struct object_entry *delta_child; /* deltified objects who bases me */ struct object_entry *delta_sibling; /* other deltified objects who * uses the same base as me */ @@ -39,7 +39,7 @@ struct object_entry { }; /* - * Objects we are going to pack are colected in objects array (dynamically + * Objects we are going to pack are collected in objects array (dynamically * expanded). nr_objects & nr_alloc controls this array. They are stored * in the order we see -- typically rev-list --objects order that gives us * nice "minimum seek" order. diff --git a/ppc/sha1ppc.S b/ppc/sha1ppc.S index f591d98b3f..140cb53370 100644 --- a/ppc/sha1ppc.S +++ b/ppc/sha1ppc.S @@ -62,7 +62,7 @@ * computation of W[t+4]. * * The first 16 rounds use W values loaded directly from memory, while the - * remianing 64 use values computed from those first 16. We preload + * remaining 64 use values computed from those first 16. We preload * 4 values before starting, so there are three kinds of rounds: * - The first 12 (all f0) also load the W values from memory. * - The next 64 compute W(i+4) in parallel. 8*f0, 20*f1, 20*f2, 16*f1. diff --git a/sha1_file.c b/sha1_file.c index bc35808440..f7bb3a1c54 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1660,7 +1660,7 @@ int has_sha1_file(const unsigned char *sha1) /* * reads from fd as long as possible into a supplied buffer of size bytes. - * If neccessary the buffer's size is increased using realloc() + * If necessary the buffer's size is increased using realloc() * * returns 0 if anything went fine and -1 otherwise * diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index 916ee15ba1..dd9caad1c2 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -31,7 +31,7 @@ test_expect_success 'cloning with reference' \ cd "$base_dir" -test_expect_success 'existance of info/alternates' \ +test_expect_success 'existence of info/alternates' \ 'test `wc -l dmin) @@ -119,7 +119,7 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1, * We need to extent the diagonal "domain" by one. If the next * values exits the box boundaries we need to change it in the * opposite direction because (max - min) must be a power of two. - * Also we initialize the extenal K value to -1 so that we can + * Also we initialize the external K value to -1 so that we can * avoid extra conditions check inside the core loop. */ if (bmin > dmin) @@ -405,7 +405,7 @@ static int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { /* * This is the same of what GNU diff does. Move back and forward * change groups for a consistent and pretty diff output. This also - * helps in finding joineable change groups and reduce the diff size. + * helps in finding joinable change groups and reduce the diff size. */ for (ix = ixo = 0;;) { /* -- cgit v1.3-5-g9baa From a3a733e63bb8dfbd6921b8f405d652db1821d4fd Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Mon, 10 Jul 2006 22:48:47 -0400 Subject: Record the type of commit operation in the reflog. If committing a merge (.git/MERGE_HEAD exists), an initial tree (no HEAD) or using --amend to amend the prior commit then denote the subtype of commit in the reflog. This helps to distinguish amended or merge commits from normal commits. In the case of --amend the prior sha1 is probably the commit which is being thrown away in favor of the new commit. Since it is likely that the old commit doesn't have any ref pointing to it anymore it can be interesting to know why that the commit was replaced and orphaned. In the case of a merge the prior sha1 is probably the first parent of the new merge commit. Consequently having its prior sha1 in the reflog is slightly less interesting but its still informative to know the commit was the result of a merge which had to be completed by hand. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- git-commit.sh | 6 +++++- t/t1400-update-ref.sh | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 't') diff --git a/git-commit.sh b/git-commit.sh index 351d13cb1e..802dd7243e 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -635,9 +635,12 @@ fi PARENTS="-p HEAD" if test -z "$initial_commit" then + rloga='commit' if [ -f "$GIT_DIR/MERGE_HEAD" ]; then + rloga='commit (merge)' PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"` elif test -n "$amend"; then + rloga='commit (amend)' PARENTS=$(git-cat-file commit HEAD | sed -n -e '/^$/q' -e 's/^parent /-p /p') fi @@ -649,6 +652,7 @@ else fi PARENTS="" current= + rloga='commit (initial)' fi if test -z "$no_edit" @@ -724,7 +728,7 @@ then fi && commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) && rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) && - git-update-ref -m "commit: $rlogm" HEAD $commit $current && + git-update-ref -m "$rloga: $rlogm" HEAD $commit $current && rm -f -- "$GIT_DIR/MERGE_HEAD" && if test -f "$NEXT_INDEX" then diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index df3e993365..6a3515dd71 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -188,17 +188,30 @@ test_expect_success \ echo OTHER >F && GIT_AUTHOR_DATE="2005-05-26 23:41" \ GIT_COMMITTER_DATE="2005-05-26 23:41" git-commit -F M -a && - h_OTHER=$(git-rev-parse --verify HEAD) + h_OTHER=$(git-rev-parse --verify HEAD) && + echo FIXED >F && + EDITOR=true \ + GIT_AUTHOR_DATE="2005-05-26 23:44" \ + GIT_COMMITTER_DATE="2005-05-26 23:44" git-commit --amend && + h_FIXED=$(git-rev-parse --verify HEAD) && + echo TEST+FIXED >F && + echo Merged initial commit and a later commit. >M && + echo $h_TEST >.git/MERGE_HEAD && + GIT_AUTHOR_DATE="2005-05-26 23:45" \ + GIT_COMMITTER_DATE="2005-05-26 23:45" git-commit -F M && + h_MERGED=$(git-rev-parse --verify HEAD) rm -f M' cat >expect < 1117150200 +0000 commit: add +$Z $h_TEST $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 commit (initial): add $h_TEST $h_OTHER $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150860 +0000 commit: The other day this did not work. +$h_OTHER $h_FIXED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151040 +0000 commit (amend): The other day this did not work. +$h_FIXED $h_MERGED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151100 +0000 commit (merge): Merged initial commit and a later commit. EOF test_expect_success \ 'git-commit logged updates' \ 'diff expect .git/logs/$m' -unset h_TEST h_OTHER +unset h_TEST h_OTHER h_FIXED h_MERGED test_expect_success \ 'git-cat-file blob master:F (expect OTHER)' \ -- cgit v1.3-5-g9baa From 8ff99e7417fcbff67d2c31445671fa97e44c95e7 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 11 Jul 2006 12:01:54 -0700 Subject: tests: Set EDITOR=: and VISUAL=: globally This way we don't have to remember to set it for each test; and if we forget, we won't cause interactive editors to be spawned for non-interactive tests. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- t/annotate-tests.sh | 2 +- t/t1400-update-ref.sh | 1 - t/t4013-diff-various.sh | 2 +- t/test-lib.sh | 3 +++ 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 't') diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 1148b0257d..b6a2edd887 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -94,7 +94,7 @@ test_expect_success \ test_expect_success \ 'merge-setup part 4' \ 'echo "evil merge." >>file && - EDITOR=: VISUAL=: git commit -a --amend' + git commit -a --amend' test_expect_success \ 'Two lines blamed on A, one on B, two on B1, one on B2, one on A U Thor' \ diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 6a3515dd71..04fab26621 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -190,7 +190,6 @@ test_expect_success \ GIT_COMMITTER_DATE="2005-05-26 23:41" git-commit -F M -a && h_OTHER=$(git-rev-parse --verify HEAD) && echo FIXED >F && - EDITOR=true \ GIT_AUTHOR_DATE="2005-05-26 23:44" \ GIT_COMMITTER_DATE="2005-05-26 23:44" git-commit --amend && h_FIXED=$(git-rev-parse --verify HEAD) && diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 06837d1c7c..36658fb17d 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -70,7 +70,7 @@ test_expect_success setup ' for i in 1 2; do echo $i; done >>dir/sub && git update-index file0 dir/sub && - EDITOR=: VISUAL=: git commit --amend && + git commit --amend && git show-branch ' diff --git a/t/test-lib.sh b/t/test-lib.sh index 05f6e79560..b0d7990a66 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -9,6 +9,8 @@ LC_ALL=C PAGER=cat TZ=UTC export LANG LC_ALL PAGER TZ +EDITOR=: +VISUAL=: unset AUTHOR_DATE unset AUTHOR_EMAIL unset AUTHOR_NAME @@ -30,6 +32,7 @@ unset SHA1_FILE_DIRECTORIES unset SHA1_FILE_DIRECTORY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME +export EDITOR VISUAL # Each test should start with something like this, after copyright notices: # -- cgit v1.3-5-g9baa From 1d0361e806086f6076c221ff5bb40b73643e96c3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 12 Jul 2006 23:09:00 -0700 Subject: test-lib: unset GIT_TRACE Signed-off-by: Junio C Hamano --- t/test-lib.sh | 1 + 1 file changed, 1 insertion(+) (limited to 't') diff --git a/t/test-lib.sh b/t/test-lib.sh index 05f6e79560..c3d3984b33 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -26,6 +26,7 @@ unset GIT_DIR unset GIT_EXTERNAL_DIFF unset GIT_INDEX_FILE unset GIT_OBJECT_DIRECTORY +unset GIT_TRACE unset SHA1_FILE_DIRECTORIES unset SHA1_FILE_DIRECTORY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME -- cgit v1.3-5-g9baa From a40d384caca008c0334a35e9ac298f2eeb5decd2 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 13 Jul 2006 19:51:12 -0700 Subject: t4013 diff format tests update This changes one test commit in the sequence to have more than one lines of commit log. A few output formats (--pretty=email aka format-patch and --pretty=oneline) need to behave differently on single and multi-line log, and this change will help catching breakages. Signed-off-by: Junio C Hamano --- t/t4013-diff-various.sh | 5 ++++- ...diff.diff-tree_--cc_--patch-with-stat_--summary_master | 2 +- t/t4013/diff.diff-tree_--cc_--patch-with-stat_master | 2 +- t/t4013/diff.diff-tree_--cc_--stat_--summary_master | 2 +- t/t4013/diff.diff-tree_--cc_--stat_master | 2 +- t/t4013/diff.diff-tree_--cc_master | 2 +- t/t4013/diff.diff-tree_-c_--abbrev_master | 2 +- t/t4013/diff.diff-tree_-c_--stat_--summary_master | 2 +- t/t4013/diff.diff-tree_-c_--stat_master | 2 +- t/t4013/diff.diff-tree_-c_master | 2 +- t/t4013/diff.diff-tree_-p_-m_master | 4 ++-- .../diff.format-patch_--attach_--stdout_initial..master | 15 +++++++++------ .../diff.format-patch_--attach_--stdout_initial..master^ | 15 +++++++++------ t/t4013/diff.format-patch_--stdout_initial..master | 6 ++++-- t/t4013/diff.format-patch_--stdout_initial..master^ | 6 ++++-- .../diff.log_--patch-with-stat_--summary_master_--_dir_ | 10 ++++++---- t/t4013/diff.log_--patch-with-stat_master | 10 ++++++---- t/t4013/diff.log_--patch-with-stat_master_--_dir_ | 10 ++++++---- ...iff.log_--root_--cc_--patch-with-stat_--summary_master | 10 ++++++---- .../diff.log_--root_--patch-with-stat_--summary_master | 10 ++++++---- t/t4013/diff.log_--root_--patch-with-stat_master | 10 ++++++---- .../diff.log_--root_-c_--patch-with-stat_--summary_master | 10 ++++++---- t/t4013/diff.log_--root_-p_master | 10 ++++++---- t/t4013/diff.log_--root_master | 10 ++++++---- t/t4013/diff.log_-SF_-p_master | 2 +- t/t4013/diff.log_-SF_master | 2 +- t/t4013/diff.log_-p_master | 10 ++++++---- t/t4013/diff.log_master | 10 ++++++---- t/t4013/diff.show_master | 4 ++-- ...whatchanged_--patch-with-stat_--summary_master_--_dir_ | 6 ++++-- t/t4013/diff.whatchanged_--patch-with-stat_master | 6 ++++-- t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ | 6 ++++-- ...changed_--root_--cc_--patch-with-stat_--summary_master | 10 ++++++---- ....whatchanged_--root_--patch-with-stat_--summary_master | 6 ++++-- t/t4013/diff.whatchanged_--root_--patch-with-stat_master | 6 ++++-- ...atchanged_--root_-c_--patch-with-stat_--summary_master | 10 ++++++---- t/t4013/diff.whatchanged_--root_-p_master | 6 ++++-- t/t4013/diff.whatchanged_--root_master | 6 ++++-- t/t4013/diff.whatchanged_-SF_-p_master | 2 +- t/t4013/diff.whatchanged_-SF_master | 2 +- t/t4013/diff.whatchanged_-p_master | 6 ++++-- t/t4013/diff.whatchanged_master | 6 ++++-- 42 files changed, 161 insertions(+), 104 deletions(-) (limited to 't') diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 36658fb17d..b24c829f0f 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -7,6 +7,9 @@ test_description='Various diff formatting options' . ./test-lib.sh +LF=' +' + test_expect_success setup ' GIT_AUTHOR_DATE="2006-06-26 00:00:00 +0000" && @@ -31,7 +34,7 @@ test_expect_success setup ' for i in C D; do echo $i; done >>dir/sub && rm -f file2 && git update-index --remove file0 file2 dir/sub && - git commit -m Second && + git commit -m "Second${LF}${LF}This is the second commit." && GIT_AUTHOR_DATE="2006-06-26 00:02:00 +0000" && GIT_COMMITTER_DATE="2006-06-26 00:02:00 +0000" && diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master index 0ac9800913..3a9f78a09d 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --patch-with-stat --summary master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master index f6ecf76366..49f23b9215 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --patch-with-stat master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master index 712ffd2d89..cc6eb3b3d5 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --stat --summary master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master index 8d5bdc985a..fae7f33255 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_master @@ -1,5 +1,5 @@ $ git diff-tree --cc --stat master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_--cc_master b/t/t4013/diff.diff-tree_--cc_master index e57d943bdc..5ecb4e14ae 100644 --- a/t/t4013/diff.diff-tree_--cc_master +++ b/t/t4013/diff.diff-tree_--cc_master @@ -1,5 +1,5 @@ $ git diff-tree --cc master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --cc dir/sub index cead32e,7289e35..992913c --- a/dir/sub diff --git a/t/t4013/diff.diff-tree_-c_--abbrev_master b/t/t4013/diff.diff-tree_-c_--abbrev_master index 39d511a7cf..b8e4aa2530 100644 --- a/t/t4013/diff.diff-tree_-c_--abbrev_master +++ b/t/t4013/diff.diff-tree_-c_--abbrev_master @@ -1,5 +1,5 @@ $ git diff-tree -c --abbrev master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 ::100644 100644 100644 cead32e... 7289e35... 992913c... MM dir/sub ::100644 100644 100644 b414108... f4615da... 10a8a9f... MM file0 $ diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master index 2d239feb5d..ac9f641fb4 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master @@ -1,5 +1,5 @@ $ git diff-tree -c --stat --summary master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master index 226300b93c..c2fe6a98c5 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_master +++ b/t/t4013/diff.diff-tree_-c_--stat_master @@ -1,5 +1,5 @@ $ git diff-tree -c --stat master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.diff-tree_-c_master b/t/t4013/diff.diff-tree_-c_master index c258efe222..e2d2bb2611 100644 --- a/t/t4013/diff.diff-tree_-c_master +++ b/t/t4013/diff.diff-tree_-c_master @@ -1,5 +1,5 @@ $ git diff-tree -c master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 ::100644 100644 100644 cead32e925b1420c84c14cbf7cf755e7e45af8ad 7289e35bff32727c08dda207511bec138fdb9ea5 992913c5aa0a5476d10c49ed0f21fc0c6d1aedf3 MM dir/sub ::100644 100644 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 f4615da674c09df322d6ba8d6b21ecfb1b1ba510 10a8a9f3657f91a156b9f0184ed79a20adef9f7f MM file0 $ diff --git a/t/t4013/diff.diff-tree_-p_-m_master b/t/t4013/diff.diff-tree_-p_-m_master index 1be721560a..b60bea039d 100644 --- a/t/t4013/diff.diff-tree_-p_-m_master +++ b/t/t4013/diff.diff-tree_-p_-m_master @@ -1,5 +1,5 @@ $ git diff-tree -p -m master -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --git a/dir/sub b/dir/sub index cead32e..992913c 100644 --- a/dir/sub @@ -21,7 +21,7 @@ index b414108..10a8a9f 100644 +A +B +C -176b998f5d647cbd77a9d8acf4531e930754d16d +59d314ad6f356dd08601a4cd5e530381da3e3c64 diff --git a/dir/sub b/dir/sub index 7289e35..992913c 100644 --- a/dir/sub diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master index a89bbbbcfb..34af347d64 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -1,5 +1,5 @@ $ git format-patch --attach --stdout initial..master -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second @@ -11,6 +11,9 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -18,10 +21,10 @@ Content-Transfer-Encoding: 8bit 3 files changed, 5 insertions(+), 3 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -57,7 +60,7 @@ index 01e79c3..0000000 -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third @@ -75,10 +78,10 @@ Content-Transfer-Encoding: 8bit 2 files changed, 5 insertions(+), 0 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ index 4de9091a40..3d57510037 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -1,5 +1,5 @@ $ git format-patch --attach --stdout initial..master^ -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second @@ -11,6 +11,9 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -18,10 +21,10 @@ Content-Transfer-Encoding: 8bit 3 files changed, 5 insertions(+), 3 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="7952a93e09bf565b5592766a438b40cd81f4846f.diff" + filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff" diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 @@ -57,7 +60,7 @@ index 01e79c3..0000000 -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third @@ -75,10 +78,10 @@ Content-Transfer-Encoding: 8bit 2 files changed, 5 insertions(+), 0 deletions(-) --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/x-patch; - name="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + name="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" Content-Transfer-Encoding: 8bit Content-Disposition: inline; - filename="889b315013ef9f2e2f90aa0b054b267c8a557847.diff" + filename="9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0.diff" diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master index b7b4e7ca91..fe78b15309 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--stdout_initial..master @@ -1,8 +1,10 @@ $ git format-patch --stdout initial..master -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -42,7 +44,7 @@ index 01e79c3..0000000 g-i-t--v-e-r-s-i-o-n -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^ index e56dd98df3..4e87689507 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_initial..master^ @@ -1,8 +1,10 @@ $ git format-patch --stdout initial..master^ -From 7952a93e09bf565b5592766a438b40cd81f4846f Mon Sep 17 00:00:00 2001 +From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:01:00 +0000 Subject: [PATCH] Second + +This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ @@ -42,7 +44,7 @@ index 01e79c3..0000000 g-i-t--v-e-r-s-i-o-n -From 889b315013ef9f2e2f90aa0b054b267c8a557847 Mon Sep 17 00:00:00 2001 +From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ index cc5537697d..3ceb8e73c5 100644 --- a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ @@ -1,6 +1,6 @@ $ git log --patch-with-stat --summary master -- dir/ -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -25,7 +25,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -45,11 +45,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master index b97969dc98..43d77761f9 100644 --- a/t/t4013/diff.log_--patch-with-stat_master +++ b/t/t4013/diff.log_--patch-with-stat_master @@ -1,6 +1,6 @@ $ git log --patch-with-stat master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -48,7 +48,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -78,11 +78,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ index 71a6d0f853..5187a26816 100644 --- a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ @@ -1,6 +1,6 @@ $ git log --patch-with-stat master -- dir/ -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -25,7 +25,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -45,11 +45,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master index b652c6a823..c9640976a8 100644 --- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git log --root --cc --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master index b24a504759..ad050af55f 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git log --root --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -49,7 +49,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -80,11 +80,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master index 1e9bdc4c1c..628c6c03bc 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_master @@ -1,6 +1,6 @@ $ git log --root --patch-with-stat master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -48,7 +48,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -78,11 +78,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master index 3a155d288c..5d4e0f13b5 100644 --- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git log --root -c --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.log_--root_-p_master b/t/t4013/diff.log_--root_-p_master index 2296986ad1..217a2eb203 100644 --- a/t/t4013/diff.log_--root_-p_master +++ b/t/t4013/diff.log_--root_-p_master @@ -1,6 +1,6 @@ $ git log --root -p master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -43,7 +43,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -69,11 +69,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.log_--root_master b/t/t4013/diff.log_--root_master index 7554a468d1..e17ccfc234 100644 --- a/t/t4013/diff.log_--root_master +++ b/t/t4013/diff.log_--root_master @@ -1,6 +1,6 @@ $ git log --root master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -12,17 +12,19 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 Third -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. commit 444ac553ac7612cc88969031b02b3767fb8a353a Author: A U Thor diff --git a/t/t4013/diff.log_-SF_-p_master b/t/t4013/diff.log_-SF_-p_master index db2264c6e9..5e32438972 100644 --- a/t/t4013/diff.log_-SF_-p_master +++ b/t/t4013/diff.log_-SF_-p_master @@ -1,5 +1,5 @@ $ git log -SF -p master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-SF_master b/t/t4013/diff.log_-SF_master index f307b4d2a8..6162ed2018 100644 --- a/t/t4013/diff.log_-SF_master +++ b/t/t4013/diff.log_-SF_master @@ -1,5 +1,5 @@ $ git log -SF master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.log_-p_master b/t/t4013/diff.log_-p_master index e82a72f6f8..f8fefef2c3 100644 --- a/t/t4013/diff.log_-p_master +++ b/t/t4013/diff.log_-p_master @@ -1,6 +1,6 @@ $ git log -p master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -43,7 +43,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -69,11 +69,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.log_master b/t/t4013/diff.log_master index 7b86ed1f5d..e9d9e7b40a 100644 --- a/t/t4013/diff.log_master +++ b/t/t4013/diff.log_master @@ -1,6 +1,6 @@ $ git log master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -12,17 +12,19 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 Third -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. commit 444ac553ac7612cc88969031b02b3767fb8a353a Author: A U Thor diff --git a/t/t4013/diff.show_master b/t/t4013/diff.show_master index 3772a87e13..9e6e1f2710 100644 --- a/t/t4013/diff.show_master +++ b/t/t4013/diff.show_master @@ -1,6 +1,6 @@ $ git show master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ index 054513f312..6a467cccc1 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ @@ -18,7 +18,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -38,11 +38,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master index a89b573f45..1e1bbe1963 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master @@ -41,7 +41,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -71,11 +71,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ index b6d9752164..13789f169b 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ @@ -18,7 +18,7 @@ index 35d242b..7289e35 100644 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -38,11 +38,13 @@ index 8422d40..cead32e 100644 +E +F -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master index e9e17cdafb..5facf2543d 100644 --- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git whatchanged --root --cc --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master index f707bfa3a1..0291153587 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master @@ -42,7 +42,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -73,11 +73,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master index 61aca41711..9b0349cd55 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master @@ -41,7 +41,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -71,11 +71,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master index 596765e804..10f6767e49 100644 --- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master @@ -1,6 +1,6 @@ $ git whatchanged --root -c --patch-with-stat --summary master -commit 176b998f5d647cbd77a9d8acf4531e930754d16d -Merge: 889b315... c7a2ab9... +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 +Merge: 9a6d494... c7a2ab9... Author: A U Thor Date: Mon Jun 26 00:04:00 2006 +0000 @@ -81,7 +81,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -112,11 +112,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.whatchanged_--root_-p_master b/t/t4013/diff.whatchanged_--root_-p_master index b4cd05e576..ebf1f0661e 100644 --- a/t/t4013/diff.whatchanged_--root_-p_master +++ b/t/t4013/diff.whatchanged_--root_-p_master @@ -36,7 +36,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -62,11 +62,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.whatchanged_--root_master b/t/t4013/diff.whatchanged_--root_master index 011a22178f..a405cb6138 100644 --- a/t/t4013/diff.whatchanged_--root_master +++ b/t/t4013/diff.whatchanged_--root_master @@ -9,7 +9,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 :100644 100644 01e79c3... f4615da... M file0 :000000 100644 0000000... 7289e35... A file3 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -18,11 +18,13 @@ Date: Mon Jun 26 00:02:00 2006 +0000 :100644 100644 8422d40... cead32e... M dir/sub :000000 100644 0000000... b1e6722... A file1 -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. :100644 100644 35d242b... 8422d40... M dir/sub :100644 100644 01e79c3... b414108... M file0 diff --git a/t/t4013/diff.whatchanged_-SF_-p_master b/t/t4013/diff.whatchanged_-SF_-p_master index 6a76f4e604..f39da84822 100644 --- a/t/t4013/diff.whatchanged_-SF_-p_master +++ b/t/t4013/diff.whatchanged_-SF_-p_master @@ -1,5 +1,5 @@ $ git whatchanged -SF -p master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_-SF_master b/t/t4013/diff.whatchanged_-SF_master index a4fe6f8a39..0499321d0e 100644 --- a/t/t4013/diff.whatchanged_-SF_master +++ b/t/t4013/diff.whatchanged_-SF_master @@ -1,5 +1,5 @@ $ git whatchanged -SF master -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 diff --git a/t/t4013/diff.whatchanged_-p_master b/t/t4013/diff.whatchanged_-p_master index f9a4456725..f18d43209c 100644 --- a/t/t4013/diff.whatchanged_-p_master +++ b/t/t4013/diff.whatchanged_-p_master @@ -36,7 +36,7 @@ index 0000000..7289e35 +1 +2 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -62,11 +62,13 @@ index 0000000..b1e6722 +B +C -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.whatchanged_master b/t/t4013/diff.whatchanged_master index c22416c006..cd3bcc2c72 100644 --- a/t/t4013/diff.whatchanged_master +++ b/t/t4013/diff.whatchanged_master @@ -9,7 +9,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 :100644 100644 01e79c3... f4615da... M file0 :000000 100644 0000000... 7289e35... A file3 -commit 889b315013ef9f2e2f90aa0b054b267c8a557847 +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Author: A U Thor Date: Mon Jun 26 00:02:00 2006 +0000 @@ -18,11 +18,13 @@ Date: Mon Jun 26 00:02:00 2006 +0000 :100644 100644 8422d40... cead32e... M dir/sub :000000 100644 0000000... b1e6722... A file1 -commit 7952a93e09bf565b5592766a438b40cd81f4846f +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Author: A U Thor Date: Mon Jun 26 00:01:00 2006 +0000 Second + + This is the second commit. :100644 100644 35d242b... 8422d40... M dir/sub :100644 100644 01e79c3... b414108... M file0 -- cgit v1.3-5-g9baa From 855409296d74d3e53fdaa3cdefd1171e4c950fab Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 13 Jul 2006 21:39:13 -0700 Subject: Adjust t4013 tests to corrected format-patch. Signed-off-by: Junio C Hamano --- t/t4013/diff.format-patch_--attach_--stdout_initial..master | 2 ++ t/t4013/diff.format-patch_--attach_--stdout_initial..master^ | 1 + t/t4013/diff.format-patch_--attach_--stdout_initial..side | 1 + t/t4013/diff.format-patch_--stdout_initial..master | 2 ++ t/t4013/diff.format-patch_--stdout_initial..master^ | 1 + t/t4013/diff.format-patch_--stdout_initial..side | 1 + 6 files changed, 8 insertions(+) (limited to 't') diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master index 34af347d64..b4745e1001 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -72,6 +72,7 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file1 | 3 +++ @@ -119,6 +120,7 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ index 3d57510037..a9d1cd368b 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -72,6 +72,7 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file1 | 3 +++ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side index 3769fa6daf..57b9d0bdc1 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side @@ -11,6 +11,7 @@ This is a multi-part message in MIME format. --------------g-i-t--v-e-r-s-i-o-n Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit + --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master index fe78b15309..c33302e92f 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--stdout_initial..master @@ -48,6 +48,7 @@ From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third + --- dir/sub | 2 ++ file1 | 3 +++ @@ -80,6 +81,7 @@ From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side + --- dir/sub | 2 ++ file0 | 3 +++ diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^ index 4e87689507..03d0f9693c 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_initial..master^ @@ -48,6 +48,7 @@ From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:02:00 +0000 Subject: [PATCH] Third + --- dir/sub | 2 ++ file1 | 3 +++ diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side index e7ddbf4814..d10a46523b 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--stdout_initial..side @@ -3,6 +3,7 @@ From c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a Mon Sep 17 00:00:00 2001 From: A U Thor Date: Mon, 26 Jun 2006 00:03:00 +0000 Subject: [PATCH] Side + --- dir/sub | 2 ++ file0 | 3 +++ -- cgit v1.3-5-g9baa From 8641fb24ee3ab86bac62f88d31f6e92a9323f699 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 16 Jul 2006 03:38:40 -0700 Subject: typechange tests for git apply (currently failing) I've found that git apply is incapable of handling patches involving object type changes to the same path. Of course git itself is perfectly capable of making commits that generate these changes, as it only tracks trees states. It's just that the diffs between them are less useful if they can't be applied. Some of these are rare, but I've hit one of them (file becoming a symlink) recently in real-world usage, and was inspired to find more potential breakages :) I'm not sure when I'll have time to fix these myself and I'm not very familiar with the apply code. So if someone could get some or all of these cases working, they would be my hero :) Some of these are what I would refer to as corner-cases from hell. Most (if not all) other systems fail some of these. In fact, they aren't even capable of representing most of these changes in their histories; much less being able to handle patches to that effect. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- t/t4114-apply-typechange.sh | 105 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100755 t/t4114-apply-typechange.sh (limited to 't') diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh new file mode 100755 index 0000000000..ca81d72157 --- /dev/null +++ b/t/t4114-apply-typechange.sh @@ -0,0 +1,105 @@ +#!/bin/sh +# +# Copyright (c) 2006 Eric Wong +# + +test_description='git-apply should not get confused with type changes. + +' + +. ./test-lib.sh + +test_expect_success 'setup repository and commits' ' + echo "hello world" > foo && + echo "hi planet" > bar && + git update-index --add foo bar && + git commit -m initial && + git branch initial && + rm -f foo && + ln -s bar foo && + git update-index foo && + git commit -m "foo symlinked to bar" && + git branch foo-symlinked-to-bar && + rm -f foo && + echo "how far is the sun?" > foo && + git update-index foo && + git commit -m "foo back to file" && + git branch foo-back-to-file && + rm -f foo && + git update-index --remove foo && + mkdir foo && + echo "if only I knew" > foo/baz && + git update-index --add foo/baz && + git commit -m "foo becomes a directory" && + git branch "foo-becomes-a-directory" && + echo "hello world" > foo/baz && + git update-index foo/baz && + git commit -m "foo/baz is the original foo" && + git branch foo-baz-renamed-from-foo + ' + +test_expect_success 'file renamed from foo to foo/baz' ' + git checkout -f initial && + git diff-tree -M -p HEAD foo-baz-renamed-from-foo > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_expect_success 'file renamed from foo/baz to foo' ' + git checkout -f foo-baz-renamed-from-foo && + git diff-tree -M -p HEAD initial > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_expect_success 'directory becomes file' ' + git checkout -f foo-becomes-a-directory && + git diff-tree -p HEAD initial > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_expect_success 'file becomes directory' ' + git checkout -f initial && + git diff-tree -p HEAD foo-becomes-a-directory > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_expect_success 'file becomes symlink' ' + git checkout -f initial && + git diff-tree -p HEAD foo-symlinked-to-bar > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_expect_success 'symlink becomes file' ' + git checkout -f foo-symlinked-to-bar && + git diff-tree -p HEAD foo-back-to-file > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_expect_success 'symlink becomes directory' ' + git checkout -f foo-symlinked-to-bar && + git diff-tree -p HEAD foo-becomes-a-directory > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_expect_success 'directory becomes symlink' ' + git checkout -f foo-becomes-a-directory && + git diff-tree -p HEAD foo-symlinked-to-bar > patch && + git apply --index < patch + ' +test_debug 'cat patch' + + +test_done -- cgit v1.3-5-g9baa From 57c7d9a7756f9c0165d0aa003eb8a05c08cd9fae Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Tue, 25 Jul 2006 01:23:03 +0200 Subject: Trivial path optimization test Linus: get_pathspec() does turn '.' into an empty string (which is correct - git internally does _not_ ever understand the notion of "." as the current working directory), but it doesn't ever do the optimization of noticing that a pathspec that consists solely of an empty string is "equivalent" to an empty pathspec. The test is to ensure that this behaviour stays. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- t/t6004-rev-list-path-optim.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 t/t6004-rev-list-path-optim.sh (limited to 't') diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh new file mode 100755 index 0000000000..5182dbb158 --- /dev/null +++ b/t/t6004-rev-list-path-optim.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +test_description='git-rev-list trivial path optimization test' + +. ./test-lib.sh + +test_expect_success setup ' +echo Hello > a && +git add a && +git commit -m "Initial commit" a +' + +test_expect_success path-optimization ' + commit=$(echo "Unchanged tree" | git-commit-tree "HEAD^{tree}" -p HEAD) && + test $(git-rev-list $commit | wc -l) = 2 && + test $(git-rev-list $commit -- . | wc -l) = 1 +' + +test_done -- cgit v1.3-5-g9baa From afd222967c6abedcf75e28fe0e57cd5644f6c865 Mon Sep 17 00:00:00 2001 From: Josef Weidendorfer Date: Wed, 26 Jul 2006 15:44:08 +0200 Subject: Extend testing git-mv for renaming of subdirectories Signed-off-by: Josef Weidendorfer Signed-off-by: Junio C Hamano --- t/t7001-mv.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 't') diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 811a4797a5..d78c56a2eb 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -38,4 +38,25 @@ test_expect_success \ 'git-diff-tree -r -M --name-status HEAD^ HEAD | \ grep -E "^R100.+path1/COPYING.+path0/COPYING"' +test_expect_success \ + 'adding another file' \ + 'cp ../../README path0/README && + git-add path0/README && + git-commit -m add2 -a' + +test_expect_success \ + 'moving whole subdirectory' \ + 'git-mv path0 path2' + +test_expect_success \ + 'commiting the change' \ + 'git-commit -m dir-move -a' + +test_expect_success \ + 'checking the commit' \ + 'git-diff-tree -r -M --name-status HEAD^ HEAD | \ + grep -E "^R100.+path0/COPYING.+path2/COPYING" && + git-diff-tree -r -M --name-status HEAD^ HEAD | \ + grep -E "^R100.+path0/README.+path2/README"' + test_done -- cgit v1.3-5-g9baa From b7a036bb5f19d3b44443dcc319321663910250e8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 26 Jul 2006 11:01:07 -0700 Subject: t4112: simplify the test and remove unneeded working tree file. Signed-off-by: Junio C Hamano --- t/t4112-apply-renames.sh | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) (limited to 't') diff --git a/t/t4112-apply-renames.sh b/t/t4112-apply-renames.sh index a06f6956d5..69e9603c78 100755 --- a/t/t4112-apply-renames.sh +++ b/t/t4112-apply-renames.sh @@ -11,31 +11,7 @@ test_description='git-apply should not get confused with rename/copy. # setup -mkdir -p include/arch/x86_64/klibc klibc/arch/x86_64/include/klibc - -cat >include/arch/x86_64/klibc/archsetjmp.h <<\EOF -/* - * arch/x86_64/include/klibc/archsetjmp.h - */ - -#ifndef _KLIBC_ARCHSETJMP_H -#define _KLIBC_ARCHSETJMP_H - -struct __jmp_buf { - unsigned long __rbx; - unsigned long __rsp; - unsigned long __rbp; - unsigned long __r12; - unsigned long __r13; - unsigned long __r14; - unsigned long __r15; - unsigned long __rip; -}; - -typedef struct __jmp_buf jmp_buf[1]; - -#endif /* _SETJMP_H */ -EOF +mkdir -p klibc/arch/x86_64/include/klibc cat >klibc/arch/x86_64/include/klibc/archsetjmp.h <<\EOF /* @@ -139,7 +115,7 @@ rename to include/arch/m32r/klibc/archsetjmp.h +#endif /* _KLIBC_ARCHSETJMP_H */ EOF -find include klibc -type f -print | xargs git-update-index --add -- +find klibc -type f -print | xargs git-update-index --add -- test_expect_success 'check rename/copy patch' 'git-apply --check patch' -- cgit v1.3-5-g9baa From a1dad607fa5227c844c0f8ab180b811d23792c02 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 Jul 2006 19:41:05 +0200 Subject: t7001: add test for git-mv dir1 dir2/ If dir2 already exists, git-mv should move dir1 _into_dir2/. Noticed by Jon Smirl. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- t/t7001-mv.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 't') diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index d78c56a2eb..322eaadc73 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -59,4 +59,19 @@ test_expect_success \ git-diff-tree -r -M --name-status HEAD^ HEAD | \ grep -E "^R100.+path0/README.+path2/README"' +test_expect_success \ + 'moving whole subdirectory into subdirectory' \ + 'git-mv path2 path1' + +test_expect_success \ + 'commiting the change' \ + 'git-commit -m dir-move -a' + +test_expect_success \ + 'checking the commit' \ + 'git-diff-tree -r -M --name-status HEAD^ HEAD | \ + grep -E "^R100.+path2/COPYING.+path1/path2/COPYING" && + git-diff-tree -r -M --name-status HEAD^ HEAD | \ + grep -E "^R100.+path2/README.+path1/path2/README"' + test_done -- cgit v1.3-5-g9baa From ac64a722072bb348476a8a029de9a82073e07fba Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 26 Jul 2006 19:47:54 +0200 Subject: builtin git-mv: support moving directories This fixes the builtin mv for the test which Josef provided, and also fixes moving directories into existing directories, as noted by Jon Smirl. In case the destination exists, fail early (this cannot be overridden by -f). Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-mv.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- t/t7001-mv.sh | 4 +++ 2 files changed, 86 insertions(+), 5 deletions(-) (limited to 't') diff --git a/builtin-mv.c b/builtin-mv.c index 593ff9e434..42c2e39b21 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -42,6 +42,18 @@ static void show_list(const char *label, struct path_list *list) } } +static const char *add_slash(const char *path) +{ + int len = strlen(path); + if (path[len - 1] != '/') { + char *with_slash = xmalloc(len + 2); + memcpy(with_slash, path, len); + strcat(with_slash + len, "/"); + return with_slash; + } + return path; +} + static struct lock_file lock_file; int cmd_mv(int argc, const char **argv, char **envp) @@ -50,6 +62,7 @@ int cmd_mv(int argc, const char **argv, char **envp) int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; const char *prefix = setup_git_directory(); const char **source, **destination, **dest_path; + enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes; struct stat st; struct path_list overwritten = {NULL, 0, 0, 0}; struct path_list src_for_dst = {NULL, 0, 0, 0}; @@ -94,11 +107,14 @@ int cmd_mv(int argc, const char **argv, char **envp) usage(builtin_mv_usage); source = copy_pathspec(prefix, argv + i, count, 0); + modes = xcalloc(count, sizeof(enum update_mode)); dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0); - if (!lstat(dest_path[0], &st) && S_ISDIR(st.st_mode)) + if (!lstat(dest_path[0], &st) && + S_ISDIR(st.st_mode)) { + dest_path[0] = add_slash(dest_path[0]); destination = copy_pathspec(dest_path[0], argv + i, count, 1); - else { + } else { if (count != 1) usage(builtin_mv_usage); destination = dest_path; @@ -114,7 +130,64 @@ int cmd_mv(int argc, const char **argv, char **envp) if (lstat(source[i], &st) < 0) bad = "bad source"; - else if (lstat(destination[i], &st) == 0) { + + if (S_ISDIR(st.st_mode)) { + const char *dir = source[i], *dest_dir = destination[i]; + int first, last, len = strlen(dir); + + if (lstat(dest_dir, &st) == 0) { + bad = "cannot move directory over file"; + goto next; + } + + modes[i] = WORKING_DIRECTORY; + + first = cache_name_pos(source[i], len); + if (first >= 0) + die ("Huh? %s/ is in index?", dir); + + first = -1 - first; + for (last = first; last < active_nr; last++) { + const char *path = active_cache[last]->name; + if (strncmp(path, dir, len) || path[len] != '/') + break; + } + + if (last - first < 1) + bad = "source directory is empty"; + else if (!bad) { + int j, dst_len = strlen(dest_dir); + + if (last - first > 0) { + source = realloc(source, + (count + last - first) + * sizeof(char *)); + destination = realloc(destination, + (count + last - first) + * sizeof(char *)); + modes = realloc(modes, + (count + last - first) + * sizeof(enum update_mode)); + } + + dest_dir = add_slash(dest_dir); + + for (j = 0; j < last - first; j++) { + const char *path = + active_cache[first + j]->name; + source[count + j] = path; + destination[count + j] = + prefix_path(dest_dir, dst_len, + path + len); + modes[count + j] = INDEX; + } + count += last - first; + } + + goto next; + } + + if (!bad && lstat(destination[i], &st) == 0) { bad = "destination exists"; if (force) { /* @@ -147,6 +220,7 @@ int cmd_mv(int argc, const char **argv, char **envp) path_list_insert(destination[i], &src_for_dst); } +next: if (bad) { if (ignore_errors) { if (--count > 0) { @@ -157,7 +231,7 @@ int cmd_mv(int argc, const char **argv, char **envp) (count - i) * sizeof(char *)); } } else - die ("Error: %s, source=%s, destination=%s", + die ("%s, source=%s, destination=%s", bad, source[i], destination[i]); } } @@ -166,12 +240,15 @@ int cmd_mv(int argc, const char **argv, char **envp) if (show_only || verbose) printf("Renaming %s to %s\n", source[i], destination[i]); - if (!show_only && + if (!show_only && modes[i] != INDEX && rename(source[i], destination[i]) < 0 && !ignore_errors) die ("renaming %s failed: %s", source[i], strerror(errno)); + if (modes[i] == WORKING_DIRECTORY) + continue; + if (cache_name_pos(source[i], strlen(source[i])) >= 0) { path_list_insert(source[i], &deleted); diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 322eaadc73..900ca93cde 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -74,4 +74,8 @@ test_expect_success \ git-diff-tree -r -M --name-status HEAD^ HEAD | \ grep -E "^R100.+path2/README.+path1/path2/README"' +test_expect_failure \ + 'do not move directory over existing directory' \ + 'mkdir path0 && mkdir path0/path2 && git-mv path2 path0' + test_done -- cgit v1.3-5-g9baa From e5a94313c06b83e034179ca6092ea23343e48dec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 28 Jul 2006 17:46:11 +0200 Subject: Teach git-apply about '-R' Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-apply.c | 65 +++++++++++++++++++++++++++++++++++++++++-------- t/t4102-apply-rename.sh | 24 ++++++++++++++++-- 2 files changed, 77 insertions(+), 12 deletions(-) (limited to 't') diff --git a/builtin-apply.c b/builtin-apply.c index d924ac3d0a..6b38a8ad0d 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -120,7 +120,7 @@ struct fragment { struct patch { char *new_name, *old_name, *def_name; unsigned int old_mode, new_mode; - int is_rename, is_copy, is_new, is_delete, is_binary; + int is_rename, is_copy, is_new, is_delete, is_binary, is_reverse; #define BINARY_DELTA_DEFLATED 1 #define BINARY_LITERAL_DEFLATED 2 unsigned long deflate_origlen; @@ -1119,6 +1119,34 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch) return offset + hdrsize + patchsize; } +#define swap(a,b) myswap((a),(b),sizeof(a)) + +#define myswap(a, b, size) do { \ + unsigned char mytmp[size]; \ + memcpy(mytmp, &a, size); \ + memcpy(&a, &b, size); \ + memcpy(&b, mytmp, size); \ +} while (0) + +static void reverse_patches(struct patch *p) +{ + for (; p; p = p->next) { + struct fragment *frag = p->fragments; + + swap(p->new_name, p->old_name); + swap(p->new_mode, p->old_mode); + swap(p->is_new, p->is_delete); + swap(p->lines_added, p->lines_deleted); + swap(p->old_sha1_prefix, p->new_sha1_prefix); + + for (; frag; frag = frag->next) { + swap(frag->newpos, frag->oldpos); + swap(frag->newlines, frag->oldlines); + } + p->is_reverse = !p->is_reverse; + } +} + static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; static const char minuses[]= "----------------------------------------------------------------------"; @@ -1336,7 +1364,7 @@ static int apply_line(char *output, const char *patch, int plen) } static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, - int inaccurate_eof) + int reverse, int inaccurate_eof) { int match_beginning, match_end; char *buf = desc->buffer; @@ -1350,6 +1378,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int pos, lines; while (size > 0) { + char first; int len = linelen(patch, size); int plen; @@ -1366,16 +1395,23 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, plen = len-1; if (len < size && patch[len] == '\\') plen--; - switch (*patch) { + first = *patch; + if (reverse) { + if (first == '-') + first = '+'; + else if (first == '+') + first = '-'; + } + switch (first) { case ' ': case '-': memcpy(old + oldsize, patch + 1, plen); oldsize += plen; - if (*patch == '-') + if (first == '-') break; /* Fall-through for ' ' */ case '+': - if (*patch != '+' || !no_add) + if (first != '+' || !no_add) newsize += apply_line(new + newsize, patch, plen); break; @@ -1615,7 +1651,8 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch) return apply_binary(desc, patch); while (frag) { - if (apply_one_fragment(desc, frag, patch->inaccurate_eof) < 0) + if (apply_one_fragment(desc, frag, patch->is_reverse, + patch->inaccurate_eof) < 0) return error("patch failed: %s:%ld", name, frag->oldpos); frag = frag->next; @@ -2142,7 +2179,8 @@ static int use_patch(struct patch *p) return 1; } -static int apply_patch(int fd, const char *filename, int inaccurate_eof) +static int apply_patch(int fd, const char *filename, + int reverse, int inaccurate_eof) { unsigned long offset, size; char *buffer = read_patch_file(fd, &size); @@ -2162,6 +2200,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) nr = parse_chunk(buffer + offset, size, patch); if (nr < 0) break; + if (reverse) + reverse_patches(patch); if (use_patch(patch)) { patch_stats(patch); *listp = patch; @@ -2226,6 +2266,7 @@ int cmd_apply(int argc, const char **argv, char **envp) { int i; int read_stdin = 1; + int reverse = 0; int inaccurate_eof = 0; const char *whitespace_option = NULL; @@ -2236,7 +2277,7 @@ int cmd_apply(int argc, const char **argv, char **envp) int fd; if (!strcmp(arg, "-")) { - apply_patch(0, "", inaccurate_eof); + apply_patch(0, "", reverse, inaccurate_eof); read_stdin = 0; continue; } @@ -2313,6 +2354,10 @@ int cmd_apply(int argc, const char **argv, char **envp) parse_whitespace_option(arg + 13); continue; } + if (!strcmp(arg, "-R") || !strcmp(arg, "--reverse")) { + reverse = 1; + continue; + } if (!strcmp(arg, "--inaccurate-eof")) { inaccurate_eof = 1; continue; @@ -2333,12 +2378,12 @@ int cmd_apply(int argc, const char **argv, char **envp) usage(apply_usage); read_stdin = 0; set_default_whitespace_mode(whitespace_option); - apply_patch(fd, arg, inaccurate_eof); + apply_patch(fd, arg, reverse, inaccurate_eof); close(fd); } set_default_whitespace_mode(whitespace_option); if (read_stdin) - apply_patch(0, "", inaccurate_eof); + apply_patch(0, "", reverse, inaccurate_eof); if (whitespace_error) { if (squelch_whitespace_errors && squelch_whitespace_errors < whitespace_error) { diff --git a/t/t4102-apply-rename.sh b/t/t4102-apply-rename.sh index fbb508d389..22da6a00cc 100755 --- a/t/t4102-apply-rename.sh +++ b/t/t4102-apply-rename.sh @@ -13,8 +13,8 @@ test_description='git-apply handling copy/rename patch. cat >test-patch <<\EOF diff --git a/foo b/bar similarity index 47% -copy from foo -copy to bar +rename from foo +rename to bar --- a/foo +++ b/bar @@ -1 +1 @@ @@ -39,4 +39,24 @@ else 'test -f bar && ls -l bar | grep "^-..x......"' fi +test_expect_success 'apply reverse' \ + 'git-apply -R --index --stat --summary --apply test-patch && + test "$(cat foo)" = "This is foo"' + +cat >test-patch <<\EOF +diff --git a/foo b/bar +similarity index 47% +copy from foo +copy to bar +--- a/foo ++++ b/bar +@@ -1 +1 @@ +-This is foo ++This is bar +EOF + +test_expect_success 'apply copy' \ + 'git-apply --index --stat --summary --apply test-patch && + test "$(cat bar)" = "This is bar" -a "$(cat foo)" = "This is foo"' + test_done -- cgit v1.3-5-g9baa From 5afa69b415fd020d6dd36751bdcf45fdbf07dd4a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 28 Jul 2006 12:23:28 -0700 Subject: t4103: fix binary patch application test. The generated binary patch was _not_ binary -- earlier I made the --full-index flag to imply binary patch generation to the diff machinery, but later we made it independent from --binary (although the latter implies the former). Signed-off-by: Junio C Hamano --- t/t4103-apply-binary.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 't') diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index 00bd8b15c6..ff052699a2 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -35,8 +35,8 @@ git-commit -m 'Second Version' git-diff-tree -p master binary >B.diff git-diff-tree -p -C master binary >C.diff -git-diff-tree -p --full-index master binary >BF.diff -git-diff-tree -p --full-index -C master binary >CF.diff +git-diff-tree -p --binary master binary >BF.diff +git-diff-tree -p --binary -C master binary >CF.diff test_expect_success 'stat binary diff -- should not fail.' \ 'git-checkout master -- cgit v1.3-5-g9baa From 818f477c40fee62ab8ea5b493c51bb357f38957c Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Fri, 28 Jul 2006 23:44:51 -0400 Subject: Display an error from update-ref if target ref name is invalid. Alex Riesen (raa.lkml@gmail.com) recently observed that git branch would fail with no error message due to unexpected situations with regards to refs. For example, if .git/refs/heads/gu is a file but "git branch -b refs/heads/gu/fixa HEAD" was invoked by the user it would fail silently due to refs/heads/gu being a file and not a directory. This change adds a test for trying to create a ref within a directory that is actually currently a file, and adds error printing within the ref locking routine should the resolve operation fail. The error printing code probably belongs at this level of the library as other failures within the ref locking, writing and logging code are also currently at this level of the code. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- refs.c | 5 +++++ t/t1400-update-ref.sh | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 't') diff --git a/refs.c b/refs.c index 56db394459..02850b6908 100644 --- a/refs.c +++ b/refs.c @@ -294,6 +294,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *path, int plen, const unsigned char *old_sha1, int mustexist) { + const char *orig_path = path; struct ref_lock *lock; struct stat st; @@ -303,7 +304,11 @@ static struct ref_lock *lock_ref_sha1_basic(const char *path, plen = strlen(path) - plen; path = resolve_ref(path, lock->old_sha1, mustexist); if (!path) { + int last_errno = errno; + error("unable to resolve reference %s: %s", + orig_path, strerror(errno)); unlock_ref(lock); + errno = last_errno; return NULL; } lock->lk = xcalloc(1, sizeof(struct lock_file)); diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 04fab26621..ddc80bbeae 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -14,6 +14,8 @@ D=4444444444444444444444444444444444444444 E=5555555555555555555555555555555555555555 F=6666666666666666666666666666666666666666 m=refs/heads/master +n_dir=refs/heads/gu +n=$n_dir/fixes test_expect_success \ "create $m" \ @@ -25,6 +27,16 @@ test_expect_success \ test $B = $(cat .git/$m)' rm -f .git/$m +test_expect_success \ + "fail to create $n" \ + 'touch .git/$n_dir + git-update-ref $n $A >out 2>err + test $? = 1 && + test "" = "$(cat out)" && + grep "error: unable to resolve reference" err && + grep $n err' +rm -f .git/$n_dir out err + test_expect_success \ "create $m (by HEAD)" \ 'git-update-ref HEAD $A && -- cgit v1.3-5-g9baa From 1fd4da643cb829618bbe76ab37df7f1b4dafc656 Mon Sep 17 00:00:00 2001 From: Ramsay Allan Jones Date: Sat, 29 Jul 2006 17:20:41 +0100 Subject: Fix annotate test script; notice when git-annotate fails. The t8001-annotate.sh test claimed all tests pass, when in fact the git-annotate perl script failed to run! (prior to fixing the script to work with perl 5.5). Signed-off-by: Ramsay Allan Jones Signed-off-by: Junio C Hamano --- t/annotate-tests.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 't') diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index b6a2edd887..8baf2fef69 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -4,7 +4,8 @@ check_count () { head= case "$1" in -h) head="$2"; shift; shift ;; esac - $PROG file $head | perl -e ' + $PROG file $head >.result || return 1 + cat .result | perl -e ' my %expect = (@ARGV); my %count = (); while () { -- cgit v1.3-5-g9baa From 446c6faec69f7ac521b8b9fc2b1874731729032f Mon Sep 17 00:00:00 2001 From: Ramsay Allan Jones Date: Sat, 29 Jul 2006 18:15:47 +0100 Subject: New tests and en-passant modifications to mktag. These changes were originally part of the next patch, but have been split out since they were peripheral to the main purpose of that patch. - update comment describing the signature format to reflect the current code. - remove trailing \n in calls to error(), since a \n is already provided by error(). - remove redundant call to get_sha1_hex(). - call sha1_to_hex(sha1) to convert to ascii, rather than attempting to print the raw sha1. The new tests provide a regression suite to support the modifications to git-mktag in this and the next patch. Signed-off-by: Ramsay Allan Jones Signed-off-by: Junio C Hamano --- mktag.c | 35 ++++----- t/t3800-mktag.sh | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 17 deletions(-) create mode 100755 t/t3800-mktag.sh (limited to 't') diff --git a/mktag.c b/mktag.c index 27f4c4f041..fa4a9e6003 100644 --- a/mktag.c +++ b/mktag.c @@ -2,10 +2,11 @@ #include "tag.h" /* - * A signature file has a very simple fixed format: three lines - * of "object " + "type " + "tag ", - * followed by some free-form signature that git itself doesn't - * care about, but that can be verified with gpg or similar. + * A signature file has a very simple fixed format: four lines + * of "object " + "type " + "tag " + + * "tagger ", followed by a blank line, a free-form tag + * message and a signature block that git itself doesn't care about, + * but that can be verified with gpg or similar. * * The first three lines are guaranteed to be at least 63 bytes: * "object \n" is 48 bytes, "type tag\n" at 9 bytes is the @@ -46,45 +47,42 @@ static int verify_tag(char *buffer, unsigned long size) const char *object, *type_line, *tag_line, *tagger_line; if (size < 64) - return error("wanna fool me ? you obviously got the size wrong !\n"); + return error("wanna fool me ? you obviously got the size wrong !"); buffer[size] = 0; /* Verify object line */ object = buffer; if (memcmp(object, "object ", 7)) - return error("char%d: does not start with \"object \"\n", 0); + return error("char%d: does not start with \"object \"", 0); if (get_sha1_hex(object + 7, sha1)) - return error("char%d: could not get SHA1 hash\n", 7); + return error("char%d: could not get SHA1 hash", 7); /* Verify type line */ type_line = object + 48; if (memcmp(type_line - 1, "\ntype ", 6)) - return error("char%d: could not find \"\\ntype \"\n", 47); + return error("char%d: could not find \"\\ntype \"", 47); /* Verify tag-line */ tag_line = strchr(type_line, '\n'); if (!tag_line) - return error("char%td: could not find next \"\\n\"\n", type_line - buffer); + return error("char%td: could not find next \"\\n\"", type_line - buffer); tag_line++; if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n') - return error("char%td: no \"tag \" found\n", tag_line - buffer); + return error("char%td: no \"tag \" found", tag_line - buffer); /* Get the actual type */ typelen = tag_line - type_line - strlen("type \n"); if (typelen >= sizeof(type)) - return error("char%td: type too long\n", type_line+5 - buffer); + return error("char%td: type too long", type_line+5 - buffer); memcpy(type, type_line+5, typelen); type[typelen] = 0; /* Verify that the object matches */ - if (get_sha1_hex(object + 7, sha1)) - return error("char%d: could not get SHA1 hash but this is really odd since i got it before !\n", 7); - if (verify_object(sha1, type)) - return error("char%d: could not verify object %s\n", 7, sha1); + return error("char%d: could not verify object %s", 7, sha1_to_hex(sha1)); /* Verify the tag-name: we don't allow control characters or spaces in it */ tag_line += 4; @@ -94,14 +92,17 @@ static int verify_tag(char *buffer, unsigned long size) break; if (c > ' ') continue; - return error("char%td: could not verify tag name\n", tag_line - buffer); + return error("char%td: could not verify tag name", tag_line - buffer); } /* Verify the tagger line */ tagger_line = tag_line; if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n')) - return error("char%td: could not find \"tagger\"\n", tagger_line - buffer); + return error("char%td: could not find \"tagger\"", tagger_line - buffer); + + /* TODO: check for committer info + blank line? */ + /* Also, the minimum length is probably + "tagger .", or 63+8=71 */ /* The actual stuff afterwards we don't care about.. */ return 0; diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh new file mode 100755 index 0000000000..5b23b7769d --- /dev/null +++ b/t/t3800-mktag.sh @@ -0,0 +1,227 @@ +#!/bin/sh +# +# + +test_description='git-mktag: tag object verify test' + +. ./test-lib.sh + +########################################################### +# check the tag.sig file, expecting verify_tag() to fail, +# and checking that the error message matches the pattern +# given in the expect.pat file. + +check_verify_failure () { + test_expect_success \ + "$1" \ + 'git-mktag message || + egrep -q -f expect.pat message' +} + +########################################################### +# first create a commit, so we have a valid object/type +# for the tag. +echo Hello >A +git-update-index --add A +git-commit -m "Initial commit" +head=$(git-rev-parse --verify HEAD) + +############################################################ +# 1. length check + +cat >tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig +echo -n "type tagsssssssssssssssssssssssssssssss" >>tag.sig + +cat >expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <expect.pat <tag.sig <.git/refs/tags/mytag 2>message' + +############################################################ +# 14. check mytag + +test_expect_success \ + 'check mytag' \ + 'git-tag -l | grep mytag' + + +test_done -- cgit v1.3-5-g9baa From 822a7d507151e1d6310f52d5b05234d65db11a88 Mon Sep 17 00:00:00 2001 From: Ramsay Allan Jones Date: Sun, 30 Jul 2006 22:42:25 +0100 Subject: Remove cmd_usage() routine and re-organize the help/usage code. The cmd_usage() routine was causing warning messages due to a NULL format parameter being passed in three out of four calls. This is a problem if you want to compile with -Werror. A simple solution is to simply remove the GNU __attribute__ format pragma from the cmd_usage() declaration in the header file. The function interface was somewhat muddled anyway, so re-write the code to finesse the problem. [jc: this incidentally revealed that t9100 test assumed that the output from "git help" to be fixed in stone, but this patch lower-cases "Usage" to "usage". Update the test not to rely on "git help" output.] Signed-off-by: Ramsay Allan Jones Signed-off-by: Junio C Hamano --- builtin-help.c | 54 +++++++++++++++++++++--------------------------- builtin.h | 7 ++----- git.c | 7 +++++-- t/t9100-git-svn-basic.sh | 7 +++---- 4 files changed, 33 insertions(+), 42 deletions(-) (limited to 't') diff --git a/builtin-help.c b/builtin-help.c index bb0b03f1ae..fb731cc934 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -9,8 +9,6 @@ #include "exec_cmd.h" #include "common-cmds.h" -static const char git_usage[] = - "Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) @@ -178,31 +176,6 @@ static void list_common_cmds_help(void) puts("(use 'git help -a' to get a list of all installed git commands)"); } -void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) -{ - if (fmt) { - va_list ap; - - va_start(ap, fmt); - printf("git: "); - vprintf(fmt, ap); - va_end(ap); - putchar('\n'); - } - else - puts(git_usage); - - if (exec_path) { - putchar('\n'); - if (show_all) - list_commands(exec_path, "git-*"); - else - list_common_cmds_help(); - } - - exit(1); -} - static void show_man_page(const char *git_cmd) { const char *page; @@ -221,6 +194,13 @@ static void show_man_page(const char *git_cmd) execlp("man", "man", page, NULL); } +void help_unknown_cmd(const char *cmd) +{ + printf("git: '%s' is not a git-command\n\n", cmd); + list_common_cmds_help(); + exit(1); +} + int cmd_version(int argc, const char **argv, const char *prefix) { printf("git version %s\n", git_version_string); @@ -230,12 +210,24 @@ int cmd_version(int argc, const char **argv, const char *prefix) int cmd_help(int argc, const char **argv, const char *prefix) { const char *help_cmd = argc > 1 ? argv[1] : NULL; - if (!help_cmd) - cmd_usage(0, git_exec_path(), NULL); - else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) - cmd_usage(1, git_exec_path(), NULL); + const char *exec_path = git_exec_path(); + + if (!help_cmd) { + printf("usage: %s\n\n", git_usage_string); + list_common_cmds_help(); + exit(1); + } + + else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) { + printf("usage: %s\n\n", git_usage_string); + if(exec_path) + list_commands(exec_path, "git-*"); + exit(1); + } + else show_man_page(help_cmd); + return 0; } diff --git a/builtin.h b/builtin.h index 88c4d84712..f10d3b77c8 100644 --- a/builtin.h +++ b/builtin.h @@ -5,12 +5,9 @@ #include extern const char git_version_string[]; +extern const char git_usage_string[]; -void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__((__format__(__printf__, 3, 4), __noreturn__)) -#endif - ; +extern void help_unknown_cmd(const char *cmd); extern int cmd_help(int argc, const char **argv, const char *prefix); extern int cmd_version(int argc, const char **argv, const char *prefix); diff --git a/git.c b/git.c index d031eb9a18..110e82e9ac 100644 --- a/git.c +++ b/git.c @@ -15,6 +15,9 @@ #include "builtin.h" +const char git_usage_string[] = + "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; + static void prepend_to_path(const char *dir, int len) { const char *old_path = getenv("PATH"); @@ -78,7 +81,7 @@ static int handle_options(const char*** argv, int* argc) setenv("GIT_DIR", getcwd(git_dir, 1024), 1); } else { fprintf(stderr, "Unknown option: %s\n", cmd); - cmd_usage(0, NULL, NULL); + usage(git_usage_string); } (*argv)++; @@ -375,7 +378,7 @@ int main(int argc, const char **argv, char **envp) } if (errno == ENOENT) - cmd_usage(0, exec_path, "'%s' is not a git-command", cmd); + help_unknown_cmd(cmd); fprintf(stderr, "Failed to run command '%s': %s\n", cmd, strerror(errno)); diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index bf1d6381d9..34a3ccd31c 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -170,7 +170,7 @@ then test -L $SVN_TREE/exec-2.sh" name='modify a symlink to become a file' - git help > help || true + echo git help > help || true rm exec-2.sh cp help exec-2.sh git update-index exec-2.sh @@ -217,10 +217,10 @@ name='check imported tree checksums expected tree checksums' rm -f expected if test "$have_utf8" = t then - echo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected + echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected fi cat >> expected <<\EOF -tree 4b9af72bb861eaed053854ec502cf7df72618f0f +tree 83654bb36f019ae4fe77a0171f81075972087624 tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1 tree 0b094cbff17168f24c302e297f55bfac65eb8bd3 tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e @@ -231,4 +231,3 @@ EOF test_expect_success "$name" "diff -u a expected" test_done - -- cgit v1.3-5-g9baa From c43ce6d603c68f716f83f1da68cc4692202085e0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 3 Aug 2006 14:41:29 -0700 Subject: Add a couple of subdirectory tests. We still have too few of them, but we have to start from somewhere. The general rule is to make tests easy to debug when run with -v (notice use of seemingly useless echo everywhere in the new tests). Signed-off-by: Junio C Hamano --- t/t1003-read-tree-prefix.sh | 27 +++++++++++ t/t1020-subdirectory.sh | 109 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100755 t/t1003-read-tree-prefix.sh create mode 100755 t/t1020-subdirectory.sh (limited to 't') diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh new file mode 100755 index 0000000000..48ab117d75 --- /dev/null +++ b/t/t1003-read-tree-prefix.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='git-read-tree --prefix test. +' + +. ./test-lib.sh + +test_expect_success setup ' + echo hello >one && + git-update-index --add one && + tree=`git-write-tree` && + echo tree is $tree +' + +echo 'one +two/one' >expect + +test_expect_success 'read-tree --prefix' ' + git-read-tree --prefix=two/ $tree && + git-ls-files >actual && + cmp expect actual +' + +test_done diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh new file mode 100755 index 0000000000..4409b87f8d --- /dev/null +++ b/t/t1020-subdirectory.sh @@ -0,0 +1,109 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='Try various core-level commands in subdirectory. +' + +. ./test-lib.sh + +test_expect_success setup ' + long="a b c d e f g h i j k l m n o p q r s t u v w x y z" && + for c in $long; do echo $c; done >one && + mkdir dir && + for c in x y z $long a b c; do echo $c; done >dir/two && + cp one original.one && + cp dir/two original.two +' +HERE=`pwd` +LF=' +' + +test_expect_success 'update-index and ls-files' ' + cd $HERE && + git-update-index --add one && + case "`git-ls-files`" in + one) echo ok one ;; + *) echo bad one; exit 1 ;; + esac && + cd dir && + git-update-index --add two && + case "`git-ls-files`" in + two) echo ok two ;; + *) echo bad two; exit 1 ;; + esac && + cd .. && + case "`git-ls-files`" in + dir/two"$LF"one) echo ok both ;; + *) echo bad; exit 1 ;; + esac +' + +test_expect_success 'cat-file' ' + cd $HERE && + two=`git-ls-files -s dir/two` && + two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` && + echo "$two" && + git-cat-file -p "$two" >actual && + cmp dir/two actual && + cd dir && + git-cat-file -p "$two" >actual && + cmp two actual +' +rm -f actual dir/actual + +test_expect_success 'diff-files' ' + cd $HERE && + echo a >>one && + echo d >>dir/two && + case "`git-diff-files --name-only`" in + dir/two"$LF"one) echo ok top ;; + *) echo bad top; exit 1 ;; + esac && + # diff should not omit leading paths + cd dir && + case "`git-diff-files --name-only`" in + dir/two"$LF"one) echo ok subdir ;; + *) echo bad subdir; exit 1 ;; + esac && + case "`git-diff-files --name-only .`" in + dir/two) echo ok subdir limited ;; + *) echo bad subdir limited; exit 1 ;; + esac +' + +test_expect_success 'write-tree' ' + cd $HERE && + top=`git-write-tree` && + echo $top && + cd dir && + sub=`git-write-tree` && + echo $sub && + test "z$top" = "z$sub" +' + +test_expect_success 'checkout-index' ' + cd $HERE && + git-checkout-index -f -u one && + cmp one original.one && + cd dir && + git-checkout-index -f -u two && + cmp two ../original.two +' + +test_expect_success 'read-tree' ' + cd $HERE && + rm -f one dir/two && + tree=`git-write-tree` && + git-read-tree --reset -u "$tree" && + cmp one original.one && + cmp dir/two original.two && + cd dir && + rm -f two && + git-read-tree --reset -u "$tree" && + cmp two ../original.two && + cmp ../one ../original.one +' + +test_done -- cgit v1.3-5-g9baa From f25b79397c9775df9eeef3d59d0cc3b1f913bc60 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 4 Aug 2006 22:16:42 -0700 Subject: Fix "grep -w" We used to find the first match of the pattern and then if the match is not for the entire word, declared that the whole line does not match. But that is wrong. The command "git grep -w -e mmap" should find that a line "foo_mmap bar mmap baz" matches, by tring the second instance of pattern "mmap" on the same line. Problems an earlier round of "fix" had were pointed out by Morten Welinder, which have been incorporated in the t7002 tests. Signed-off-by: Junio C Hamano --- builtin-grep.c | 35 +++++++++++++++++------- t/t7002-grep.sh | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 10 deletions(-) create mode 100755 t/t7002-grep.sh (limited to 't') diff --git a/builtin-grep.c b/builtin-grep.c index 69b7c4862a..93b7e07b30 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -410,8 +410,10 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match) static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol) { int hit = 0; + int at_true_bol = 1; regmatch_t pmatch[10]; + again: if (!opt->fixed) { regex_t *exp = &p->regexp; hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), @@ -422,22 +424,35 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol } if (hit && opt->word_regexp) { - /* Match beginning must be either - * beginning of the line, or at word - * boundary (i.e. the last char must - * not be alnum or underscore). - */ if ((pmatch[0].rm_so < 0) || (eol - bol) <= pmatch[0].rm_so || (pmatch[0].rm_eo < 0) || (eol - bol) < pmatch[0].rm_eo) die("regexp returned nonsense"); - if (pmatch[0].rm_so != 0 && - word_char(bol[pmatch[0].rm_so-1])) - hit = 0; - if (pmatch[0].rm_eo != (eol-bol) && - word_char(bol[pmatch[0].rm_eo])) + + /* Match beginning must be either beginning of the + * line, or at word boundary (i.e. the last char must + * not be a word char). Similarly, match end must be + * either end of the line, or at word boundary + * (i.e. the next char must not be a word char). + */ + if ( ((pmatch[0].rm_so == 0 && at_true_bol) || + !word_char(bol[pmatch[0].rm_so-1])) && + ((pmatch[0].rm_eo == (eol-bol)) || + !word_char(bol[pmatch[0].rm_eo])) ) + ; + else hit = 0; + + if (!hit && pmatch[0].rm_so + bol + 1 < eol) { + /* There could be more than one match on the + * line, and the first match might not be + * strict word match. But later ones could be! + */ + bol = pmatch[0].rm_so + bol + 1; + at_true_bol = 0; + goto again; + } } return hit; } diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh new file mode 100755 index 0000000000..00a7d762ce --- /dev/null +++ b/t/t7002-grep.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# +# Copyright (c) 2006 Junio C Hamano +# + +test_description='git grep -w +' + +. ./test-lib.sh + +test_expect_success setup ' + { + echo foo mmap bar + echo foo_mmap bar + echo foo_mmap bar mmap + echo foo mmap bar_mmap + echo foo_mmap bar mmap baz + } >file && + echo x x xx x >x && + echo y yy >y && + echo zzz > z && + git add file x y z && + git commit -m initial +' + +for H in HEAD '' +do + case "$H" in + HEAD) HC='HEAD:' L='HEAD' ;; + '') HC= L='in working tree' ;; + esac + + test_expect_success "grep -w $L" ' + { + echo ${HC}file:1:foo mmap bar + echo ${HC}file:3:foo_mmap bar mmap + echo ${HC}file:4:foo mmap bar_mmap + echo ${HC}file:5:foo_mmap bar mmap baz + } >expected && + git grep -n -w -e mmap $H >actual && + diff expected actual + ' + + test_expect_success "grep -w $L (x)" ' + { + echo ${HC}x:1:x x xx x + } >expected && + git grep -n -w -e "x xx* x" $H >actual && + diff expected actual + ' + + test_expect_success "grep -w $L (y-1)" ' + { + echo ${HC}y:1:y yy + } >expected && + git grep -n -w -e "^y" $H >actual && + diff expected actual + ' + + test_expect_success "grep -w $L (y-2)" ' + : >expected && + if git grep -n -w -e "^y y" $H >actual + then + echo should not have matched + cat actual + false + else + diff expected actual + fi + ' + + test_expect_success "grep -w $L (z)" ' + : >expected && + if git grep -n -w -e "^z" $H >actual + then + echo should not have matched + cat actual + false + else + diff expected actual + fi + ' +done + +test_done -- cgit v1.3-5-g9baa