git-svn: "git worktree" awareness

git-svn internals were previously not aware of repository layout differences for users of the "git worktree" command. Introduce this awareness by using "git rev-parse --git-path" instead of relying on outdated uses of GIT_DIR and friends. Thanks-to: Duy Nguyen <pclouds@gmail.com> Reported-by: Mathieu Arnold <mat@freebsd.org> Signed-off-by: Eric Wong <e@80x24.org>

Eric Wong committed Oct 14, 2016 at 00:27 UTC 112423eb905cf28c9445781a7647ba590d597ab3
3 files changed +42 -28
git-svn.perl
+5 -4
@@ -1700,7 +1700,7 @@ sub cmd_gc {
1700 "files will not be compressed.\n";
1701 }
1702 File::Find::find({ wanted => \&gc_directory, no_chdir => 1},
1703 - "$ENV{GIT_DIR}/svn");
1703 + Git::SVN::svn_dir());
1704 }
1705
1706 ########################### utility functions #########################
@@ -1734,7 +1734,7 @@ sub post_fetch_checkout {
1734 return unless verify_ref('HEAD^0');
1735
1736 return if $ENV{GIT_DIR} !~ m#^(?:.*/)?\.git$#;
1737 - my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
1737 + my $index = command_oneline(qw(rev-parse --git-path index));
1738 return if -f $index;
1739
1740 return if command_oneline(qw/rev-parse --is-inside-work-tree/) eq 'false';
@@ -1836,8 +1836,9 @@ sub get_tree_from_treeish {
1836 sub get_commit_entry {
1837 my ($treeish) = shift;
1838 my %log_entry = ( log => '', tree => get_tree_from_treeish($treeish) );
1839 - my $commit_editmsg = "$ENV{GIT_DIR}/COMMIT_EDITMSG";
1840 - my $commit_msg = "$ENV{GIT_DIR}/COMMIT_MSG";
1839 + my @git_path = qw(rev-parse --git-path);
1840 + my $commit_editmsg = command_oneline(@git_path, 'COMMIT_EDITMSG');
1841 + my $commit_msg = command_oneline(@git_path, 'COMMIT_MSG');
1842 open my $log_fh, '>', $commit_editmsg or croak $!;
1843
1844 my $type = command_oneline(qw/cat-file -t/, $treeish);
perl/Git/SVN.pm
+15 -9
@@ -807,10 +807,15 @@ sub get_fetch_range {
807 (++$min, $max);
808 }
809
810 +sub svn_dir {
811 + command_oneline(qw(rev-parse --git-path svn));
812 +}
813 +
814 sub tmp_config {
815 my (@args) = @_;
812 - my $old_def_config = "$ENV{GIT_DIR}/svn/config";
813 - my $config = "$ENV{GIT_DIR}/svn/.metadata";
816 + my $svn_dir = svn_dir();
817 + my $old_def_config = "$svn_dir/config";
818 + my $config = "$svn_dir/.metadata";
819 if (! -f $config && -f $old_def_config) {
820 rename $old_def_config, $config or
821 die "Failed rename $old_def_config => $config: $!\n";
@@ -1671,7 +1676,7 @@ sub tie_for_persistent_memoization {
1676 return if $memoized;
1677 $memoized = 1;
1678
1674 - my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
1679 + my $cache_path = svn_dir() . '/.caches/';
1680 mkpath([$cache_path]) unless -d $cache_path;
1681
1682 my %lookup_svn_merge_cache;
@@ -1712,7 +1717,7 @@ sub tie_for_persistent_memoization {
1717 sub clear_memoized_mergeinfo_caches {
1718 die "Only call this method in non-memoized context" if ($memoized);
1719
1715 - my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
1720 + my $cache_path = svn_dir() . '/.caches/';
1721 return unless -d $cache_path;
1722
1723 for my $cache_file (("$cache_path/lookup_svn_merge",
@@ -2446,12 +2451,13 @@ sub _new {
2451 "refs/remotes/$prefix$default_ref_id";
2452 }
2453 $_[1] = $repo_id;
2449 - my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
2454 + my $svn_dir = svn_dir();
2455 + my $dir = "$svn_dir/$ref_id";
2456
2451 - # Older repos imported by us used $GIT_DIR/svn/foo instead of
2452 - # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
2457 + # Older repos imported by us used $svn_dir/foo instead of
2458 + # $svn_dir/refs/remotes/foo when tracking refs/remotes/foo
2459 if ($ref_id =~ m{^refs/remotes/(.+)}) {
2454 - my $old_dir = "$ENV{GIT_DIR}/svn/$1";
2460 + my $old_dir = "$svn_dir/$1";
2461 if (-d $old_dir && ! -d $dir) {
2462 $dir = $old_dir;
2463 }
@@ -2461,7 +2467,7 @@ sub _new {
2467 mkpath([$dir]);
2468 my $obj = bless {
2469 ref_id => $ref_id, dir => $dir, index => "$dir/index",
2464 - config => "$ENV{GIT_DIR}/svn/config",
2470 + config => "$svn_dir/config",
2471 map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
2472
2473 # Ensure it gets canonicalized
perl/Git/SVN/Migration.pm
+22 -15
@@ -44,7 +44,9 @@ use Git qw(
44 command_noisy
45 command_output_pipe
46 command_close_pipe
47 + command_oneline
48 );
49 +use Git::SVN;
50
51 sub migrate_from_v0 {
52 my $git_dir = $ENV{GIT_DIR};
@@ -55,7 +57,9 @@ sub migrate_from_v0 {
57 chomp;
58 my ($id, $orig_ref) = ($_, $_);
59 next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
58 - next unless -f "$git_dir/$id/info/url";
60 + my $info_url = command_oneline(qw(rev-parse --git-path),
61 + "$id/info/url");
62 + next unless -f $info_url;
63 my $new_ref = "refs/remotes/$id";
64 if (::verify_ref("$new_ref^0")) {
65 print STDERR "W: $orig_ref is probably an old ",
@@ -82,7 +86,7 @@ sub migrate_from_v1 {
86 my $git_dir = $ENV{GIT_DIR};
87 my $migrated = 0;
88 return $migrated unless -d $git_dir;
85 - my $svn_dir = "$git_dir/svn";
89 + my $svn_dir = Git::SVN::svn_dir();
90
91 # just in case somebody used 'svn' as their $id at some point...
92 return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
@@ -97,27 +101,28 @@ sub migrate_from_v1 {
101 my $x = $_;
102 next unless $x =~ s#^refs/remotes/##;
103 chomp $x;
100 - next unless -f "$git_dir/$x/info/url";
101 - my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
104 + my $info_url = command_oneline(qw(rev-parse --git-path),
105 + "$x/info/url");
106 + next unless -f $info_url;
107 + my $u = eval { ::file_to_s($info_url) };
108 next unless $u;
103 - my $dn = dirname("$git_dir/svn/$x");
109 + my $dn = dirname("$svn_dir/$x");
110 mkpath([$dn]) unless -d $dn;
111 if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
106 - mkpath(["$git_dir/svn/svn"]);
112 + mkpath(["$svn_dir/svn"]);
113 print STDERR " - $git_dir/$x/info => ",
108 - "$git_dir/svn/$x/info\n";
109 - rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
114 + "$svn_dir/$x/info\n";
115 + rename "$git_dir/$x/info", "$svn_dir/$x/info" or
116 croak "$!: $x";
117 # don't worry too much about these, they probably
118 # don't exist with repos this old (save for index,
119 # and we can easily regenerate that)
120 foreach my $f (qw/unhandled.log index .rev_db/) {
115 - rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
121 + rename "$git_dir/$x/$f", "$svn_dir/$x/$f";
122 }
123 } else {
118 - print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
119 - rename "$git_dir/$x", "$git_dir/svn/$x" or
120 - croak "$!: $x";
124 + print STDERR " - $git_dir/$x => $svn_dir/$x\n";
125 + rename "$git_dir/$x", "$svn_dir/$x" or croak "$!: $x";
126 }
127 $migrated++;
128 }
@@ -139,9 +144,10 @@ sub read_old_urls {
144 push @dir, $_;
145 }
146 }
147 + my $svn_dir = Git::SVN::svn_dir();
148 foreach (@dir) {
149 my $x = $_;
144 - $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
150 + $x =~ s!^\Q$svn_dir\E/!!o;
151 read_old_urls($l_map, $x, $_);
152 }
153 }
@@ -150,7 +156,7 @@ sub migrate_from_v2 {
156 my @cfg = command(qw/config -l/);
157 return if grep /^svn-remote\..+\.url=/, @cfg;
158 my %l_map;
153 - read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
159 + read_old_urls(\%l_map, '', Git::SVN::svn_dir());
160 my $migrated = 0;
161
162 require Git::SVN;
@@ -239,7 +245,8 @@ sub minimize_connections {
245 }
246 }
247 if (@emptied) {
242 - my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
248 + my $file = $ENV{GIT_CONFIG} ||
249 + command_oneline(qw(rev-parse --git-path config));
250 print STDERR <<EOF;
251 The following [svn-remote] sections in your config file ($file) are empty
252 and can be safely removed: