From c3e43938839752b48ff3a36862ae59f1cd1e630d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Tue, 28 Nov 2006 22:49:17 +0100 Subject: [PATCH 01/10] shortlog: remove range check Don't force the user to specify more than one revision parameter, thus making git-shortlog behave more like git-log. 'git-shortlog master' will now produce the expected results; the other end of the range simply is the (oldest) root commit. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- builtin-shortlog.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/builtin-shortlog.c b/builtin-shortlog.c index b5b13dee3b..f1124e261b 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -298,9 +298,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) if (!access(".mailmap", R_OK)) read_mailmap(".mailmap"); - if (rev.pending.nr == 1) - die ("Need a range!"); - else if (rev.pending.nr == 0) + if (rev.pending.nr == 0) read_from_stdin(&list); else get_from_rev(&rev, &list); From dad73c0bb9f33323ec1aacf560a6263f1d85f81a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 28 Nov 2006 14:06:05 -0800 Subject: [PATCH 02/10] git-svn: error out when the SVN connection fails during a fetch finish_report does seem to return a useful value indicating success or failure, so we'll just set a flag when close_edit is called (it is not called on failures, nor is abort_edit) and check the flag before proceeding. Thanks to Pazu for pointing this out. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/git-svn.perl b/git-svn.perl index 9b86d91266..cefa7b021d 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2939,6 +2939,9 @@ sub libsvn_fetch_delta { $reporter->set_path('', $last_rev, 0, @lock, $pool); $reporter->finish_report($pool); $pool->clear; + unless ($ed->{git_commit_ok}) { + die "SVN connection failed somewhere...\n"; + } libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]); } @@ -3193,6 +3196,9 @@ sub libsvn_new_tree { $reporter->set_path('', $rev, 1, @lock, $pool); $reporter->finish_report($pool); $pool->clear; + unless ($ed->{git_commit_ok}) { + die "SVN connection failed somewhere...\n"; + } } else { open my $gui, '| git-update-index -z --index-info' or croak $!; libsvn_traverse($gui, '', $SVN->{svn_path}, $rev); @@ -3506,7 +3512,8 @@ sub abort_edit { sub close_edit { my $self = shift; - close $self->{gui} or croak; + close $self->{gui} or croak $!; + $self->{git_commit_ok} = 1; $self->SUPER::close_edit(@_); } From 0864e3ba12ed946f0082297530584a77e2a7097b Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 28 Nov 2006 02:50:17 -0800 Subject: [PATCH 03/10] git-svn: fix output reporting from the delta fetcher There was nothing printed in the code originally because I left out a pair of parentheses. Nevertheless, the affected code has been replaced with a more efficient version that respects the -q flag as well as requiring less bandwidth. We save some bandwidth by not requesting changed paths information when calling get_log() since we're using the delta fetcher. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index cefa7b021d..c3ad5ec603 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1152,7 +1152,7 @@ sub graft_file_copy_lib { while (1) { my $pool = SVN::Pool->new; libsvn_get_log(libsvn_dup_ra($SVN), [$path], - $min, $max, 0, 1, 1, + $min, $max, 0, 2, 1, sub { libsvn_graft_file_copies($grafts, $tree_paths, $path, @_); @@ -2906,7 +2906,7 @@ sub libsvn_log_entry { } sub process_rm { - my ($gui, $last_commit, $f) = @_; + my ($gui, $last_commit, $f, $q) = @_; # remove entire directories. if (safe_qx('git-ls-tree',$last_commit,'--',$f) =~ /^040000 tree/) { defined(my $pid = open my $ls, '-|') or croak $!; @@ -2917,10 +2917,13 @@ sub process_rm { local $/ = "\0"; while (<$ls>) { print $gui '0 ',0 x 40,"\t",$_ or croak $!; + print "\tD\t$_\n" unless $q; } + print "\tD\t$f/\n" unless $q; close $ls or croak $?; } else { print $gui '0 ',0 x 40,"\t",$f,"\0" or croak $!; + print "\tD\t$f\n" unless $q; } } @@ -2931,8 +2934,7 @@ sub libsvn_fetch { sub libsvn_fetch_delta { my ($last_commit, $paths, $rev, $author, $date, $msg) = @_; my $pool = SVN::Pool->new; - my $ed = SVN::Git::Fetcher->new({ c => $last_commit, ra => $SVN, - paths => $paths }); + my $ed = SVN::Git::Fetcher->new({ c => $last_commit, q => $_q }); my $reporter = $SVN->do_update($rev, '', 1, $ed, $pool); my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : (); my (undef, $last_rev, undef) = cmt_metadata($last_commit); @@ -2959,8 +2961,7 @@ sub libsvn_fetch_full { $f =~ s#^/##; } if ($m =~ /^[DR]$/) { - print "\t$m\t$f\n" unless $_q; - process_rm($gui, $last_commit, $f); + process_rm($gui, $last_commit, $f, $_q); next if $m eq 'D'; # 'R' can be file replacements, too, right? } @@ -3101,7 +3102,7 @@ sub revisions_eq { # 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); + 0, 0, 1, sub {$nr++}, $pool); $pool->clear; } else { my ($url, undef) = repo_path_split($SVN_URL); @@ -3177,6 +3178,7 @@ sub libsvn_find_parent_branch { sub libsvn_get_log { my ($ra, @args) = @_; + $args[4]-- if $args[4] && $_xfer_delta && ! $_follow_parent; if ($SVN::Core::VERSION le '1.2.0') { splice(@args, 3, 1); } @@ -3190,7 +3192,7 @@ sub libsvn_new_tree { my ($paths, $rev, $author, $date, $msg) = @_; if ($_xfer_delta) { my $pool = SVN::Pool->new; - my $ed = SVN::Git::Fetcher->new({paths => $paths, ra => $SVN}); + my $ed = SVN::Git::Fetcher->new({q => $_q}); my $reporter = $SVN->do_update($rev, '', 1, $ed, $pool); my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : (); $reporter->set_path('', $rev, 1, @lock, $pool); @@ -3388,20 +3390,14 @@ sub new { open my $gui, '| git-update-index -z --index-info' or croak $!; $self->{gui} = $gui; $self->{c} = $git_svn->{c} if exists $git_svn->{c}; - if (my $p = $git_svn->{paths} && $git_svn->{ra}) { - my $s = $git_svn->{ra}->{svn_path}; - $s = length $s ? qr#^/\Q$s\E/# : qr#^/#; - $self->{paths} = { map { my $x = $_; - $x =~ s/$s//; - $x => $p->{$_} } keys %$p }; - } + $self->{q} = $git_svn->{q}; require Digest::MD5; $self; } sub delete_entry { my ($self, $path, $rev, $pb) = @_; - process_rm($self->{gui}, $self->{c}, $path); + process_rm($self->{gui}, $self->{c}, $path, $self->{q}); undef; } @@ -3410,13 +3406,13 @@ sub open_file { my ($mode, $blob) = (safe_qx('git-ls-tree',$self->{c},'--',$path) =~ /^(\d{6}) blob ([a-f\d]{40})\t/); { path => $path, mode_a => $mode, mode_b => $mode, blob => $blob, - pool => SVN::Pool->new }; + pool => SVN::Pool->new, action => 'M' }; } sub add_file { my ($self, $path, $pb, $cp_path, $cp_rev) = @_; { path => $path, mode_a => 100644, mode_b => 100644, - pool => SVN::Pool->new }; + pool => SVN::Pool->new, action => 'A' }; } sub change_file_prop { @@ -3499,8 +3495,7 @@ sub close_file { $fb->{pool}->clear; my $gui = $self->{gui}; print $gui "$fb->{mode_b} $hash\t$path\0" or croak $!; - print "\t", $self->{paths}->{$path}->action, - "\t$path\n" if defined $self->{paths}->{$path}; + print "\t$fb->{action}\t$path\n" if $fb->{action} && ! $self->{q}; undef; } From 4548e855e4600a0f76329cf4f0dd9e8d17d66b08 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 28 Nov 2006 12:12:08 -0500 Subject: [PATCH 04/10] Teach bash how to complete long options for git-commit. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d8ae4d7886..be978cf3d3 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -398,6 +398,20 @@ _git_cherry_pick () esac } +_git_commit () +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + --*) + COMPREPLY=($(compgen -W " + --all --author= --signoff --verify --no-verify + --edit --amend --include --only + " -- "$cur")) + return + esac + COMPREPLY=() +} + _git_diff () { __git_complete_file @@ -768,6 +782,7 @@ _git () cat-file) _git_cat_file ;; checkout) _git_checkout ;; cherry-pick) _git_cherry_pick ;; + commit) _git_commit ;; diff) _git_diff ;; diff-tree) _git_diff_tree ;; fetch) _git_fetch ;; @@ -804,6 +819,7 @@ complete -o default -F _git_branch git-branch complete -o default -o nospace -F _git_cat_file git-cat-file complete -o default -F _git_checkout git-checkout complete -o default -F _git_cherry_pick git-cherry-pick +complete -o default -F _git_commit git-commit complete -o default -o nospace -F _git_diff git-diff complete -o default -F _git_diff_tree git-diff-tree complete -o default -o nospace -F _git_fetch git-fetch From 67ffa1142585742601011440a17528ef841bbf44 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 28 Nov 2006 12:12:26 -0500 Subject: [PATCH 05/10] Fix broken bash completion of local refs. Commit 35e65ecc broke completion of local refs, e.g. "git pull . fo" no longer would complete to "foo". Instead it printed out an internal git error ("fatal: Not a git repository: '.'"). The break occurred when I tried to improve performance by switching from git-peek-remote to git-for-each-ref. Apparently git-peek-remote will drop into directory "$1/.git" (where $1 is its first parameter) if it is given a repository with a working directory. This allowed the bash completion code to work properly even though it was not handing over the true repository directory. So now we do a stat in bash to see if we need to add "/.git" to the path string before running any command with --git-dir. I also tried to optimize away two "git rev-parse --git-dir" invocations in common cases like "git log fo" as typically the user is in the top level directory of their project and therefore the .git subdirectory is in the current working directory. This should make a difference on systems where fork+exec might take a little while. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 37 +++++++++++++------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index be978cf3d3..447ec20467 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -34,7 +34,19 @@ __gitdir () { - echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}" + if [ -z "$1" ]; then + if [ -n "$__git_dir" ]; then + echo "$__git_dir" + elif [ -d .git ]; then + echo .git + else + git rev-parse --git-dir 2>/dev/null + fi + elif [ -d "$1/.git" ]; then + echo "$1/.git" + else + echo "$1" + fi } __git_ps1 () @@ -51,7 +63,7 @@ __git_ps1 () __git_heads () { - local cmd i is_hash=y dir="${1:-$(__gitdir)}" + local cmd i is_hash=y dir="$(__gitdir "$1")" if [ -d "$dir" ]; then for i in $(git --git-dir="$dir" \ for-each-ref --format='%(refname)' \ @@ -60,7 +72,7 @@ __git_heads () done return fi - for i in $(git-ls-remote "$dir" 2>/dev/null); do + for i in $(git-ls-remote "$1" 2>/dev/null); do case "$is_hash,$i" in y,*) is_hash=n ;; n,*^{}) is_hash=y ;; @@ -72,7 +84,7 @@ __git_heads () __git_refs () { - local cmd i is_hash=y dir="${1:-$(__gitdir)}" + local cmd i is_hash=y dir="$(__gitdir "$1")" if [ -d "$dir" ]; then if [ -e "$dir/HEAD" ]; then echo HEAD; fi for i in $(git --git-dir="$dir" \ @@ -101,20 +113,9 @@ __git_refs () __git_refs2 () { - local cmd i is_hash=y dir="${1:-$(__gitdir)}" - if [ -d "$dir" ]; then - cmd=git-peek-remote - else - cmd=git-ls-remote - fi - for i in $($cmd "$dir" 2>/dev/null); do - case "$is_hash,$i" in - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;; - n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;; - n,*) is_hash=y; echo "$i:$i" ;; - esac + local i + for i in $(__git_refs "$1"); do + echo "$i:$i" done } From d5cc2de9ff57d2f6734f6e6e34addc2fae1b5b0e Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Tue, 28 Nov 2006 11:27:39 +0100 Subject: [PATCH 06/10] ident.c: Trim hint printed when gecos is empty. Also remove asterisks for readability, and suggest use of git-config for easy cut & pasting. Signed-off-by: Han-Wen Nienhuys Signed-off-by: Junio C Hamano --- ident.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ident.c b/ident.c index efec97ffd0..e415fd3588 100644 --- a/ident.c +++ b/ident.c @@ -158,12 +158,17 @@ static int copy(char *buf, int size, int offset, const char *src) static const char au_env[] = "GIT_AUTHOR_NAME"; static const char co_env[] = "GIT_COMMITTER_NAME"; static const char *env_hint = -"\n*** Environment problem:\n" +"\n" "*** Your name cannot be determined from your system services (gecos).\n" -"*** You would need to set %s and %s\n" -"*** environment variables; otherwise you won't be able to perform\n" -"*** certain operations because of \"empty ident\" errors.\n" -"*** Alternatively, you can use user.name configuration variable.\n\n"; +"\n" +"Run\n" +"\n" +" git repo-config user.email \"you@email.com\"\n" +" git repo-config user.name \"Your Name\"\n" +"\n" +"To set the identity in this repository.\n" +"Add --global to set your account\'s default\n" +"\n"; static const char *get_ident(const char *name, const char *email, const char *date_str, int error_on_no_name) From 9aca025849d417b04b49fead126c915f6ca47526 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 28 Nov 2006 18:51:40 -0800 Subject: [PATCH 07/10] git-svn: color support for the log command * match LESS environment settings to those in pager.c * parse diff.color and pager.color settings in the config file, and pass --color to git-log * --color and --pager= settings are supported Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 67 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index c3ad5ec603..d8d8716d38 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -60,6 +60,7 @@ nag_lib() unless $_use_lib; 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 $_esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; 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, @@ -68,7 +69,8 @@ my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit, $_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit, $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m, $_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive, - $_username, $_config_dir, $_no_auth_cache, $_xfer_delta); + $_username, $_config_dir, $_no_auth_cache, $_xfer_delta, + $_pager, $_color); my (@_branch_from, %tree_map, %users, %rusers, %equiv); my ($_svn_co_url_revs, $_svn_pg_peg_revs); my @repo_path_split_cache; @@ -135,6 +137,8 @@ my %cmd = ( 'show-commit' => \$_show_commit, 'non-recursive' => \$_non_recursive, 'authors-file|A=s' => \$_authors, + 'color' => \$_color, + 'pager=s' => \$_pager, } ], 'commit-diff' => [ \&commit_diff, 'Commit a diff between two trees', { 'message|m=s' => \$_message, @@ -759,16 +763,17 @@ sub show_log { } } + config_pager(); 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(); + run_pager(); my (@k, $c, $d); while (<$log>) { - if (/^commit ($sha1_short)/o) { + if (/^${_esc_color}commit ($sha1_short)/o) { my $cmt = $1; if ($c && cmt_showable($c) && $c->{r} != $r_last) { $r_last = $c->{r}; @@ -777,25 +782,25 @@ sub show_log { } $d = undef; $c = { c => $cmt }; - } elsif (/^author (.+) (\d+) ([\-\+]?\d+)$/) { + } elsif (/^${_esc_color}author (.+) (\d+) ([\-\+]?\d+)$/) { get_author_info($c, $1, $2, $3); - } elsif (/^(?:tree|parent|committer) /) { + } elsif (/^${_esc_color}(?:tree|parent|committer) /) { # ignore - } elsif (/^:\d{6} \d{6} $sha1_short/o) { + } elsif (/^${_esc_color}:\d{6} \d{6} $sha1_short/o) { push @{$c->{raw}}, $_; - } elsif (/^[ACRMDT]\t/) { + } elsif (/^${_esc_color}[ACRMDT]\t/) { # we could add $SVN->{svn_path} here, but that requires # remote access at the moment (repo_path_split)... - s#^([ACRMDT])\t# $1 #; + s#^(${_esc_color})([ACRMDT])\t#$1 $2 #; push @{$c->{changed}}, $_; - } elsif (/^diff /) { + } elsif (/^${_esc_color}diff /) { $d = 1; push @{$c->{diff}}, $_; } elsif ($d) { push @{$c->{diff}}, $_; - } elsif (/^ (git-svn-id:.+)$/) { + } elsif (/^${_esc_color} (git-svn-id:.+)$/) { ($c->{url}, $c->{r}, undef) = extract_metadata($1); - } elsif (s/^ //) { + } elsif (s/^${_esc_color} //) { push @{$c->{l}}, $_; } } @@ -901,12 +906,30 @@ sub cmt_showable { return defined $c->{r}; } +sub log_use_color { + return 1 if $_color; + my $dc; + chomp($dc = `git-repo-config --get diff.color`); + if ($dc eq 'auto') { + if (-t *STDOUT || (defined $_pager && + `git-repo-config --bool --get pager.color` !~ /^false/)) { + return ($ENV{TERM} && $ENV{TERM} ne 'dumb'); + } + return 0; + } + return 0 if $dc eq 'never'; + return 1 if $dc eq 'always'; + chomp($dc = `git-repo-config --bool --get diff.color`); + $dc eq 'true'; +} + 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, '-r' unless $_non_recursive; push @cmd, qw/--raw --name-status/ if $_verbose; + push @cmd, '--color' if log_use_color(); return @cmd unless defined $r_max; if ($r_max == $r_min) { push @cmd, '--max-count=1'; @@ -2533,14 +2556,18 @@ sub tz_to_s_offset { 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; +# adapted from pager.c +sub config_pager { + $_pager ||= $ENV{GIT_PAGER} || $ENV{PAGER}; + if (!defined $_pager) { + $_pager = 'less'; + } elsif (length $_pager == 0 || $_pager eq 'cat') { + $_pager = undef; } +} + +sub run_pager { + return unless -t *STDOUT; pipe my $rfd, my $wfd or return; defined(my $pid = fork) or croak $!; if (!$pid) { @@ -2548,8 +2575,8 @@ sub setup_pager { # translated to Perl from pager.c return; } open STDIN, '<&', $rfd or croak $!; - $ENV{LESS} ||= '-S'; - exec $pager or croak "Can't run pager: $!\n";; + $ENV{LESS} ||= 'FRSX'; + exec $_pager or croak "Can't run pager: $! ($_pager)\n"; } sub get_author_info { From 4511c899e64cbda934ba864c359a2a7a04909264 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 28 Nov 2006 18:51:41 -0800 Subject: [PATCH 08/10] git-svn: documentation updates Eliminate 'commit' from some places and plug 'dcommit' more. Also update the section --id (GIT_SVN_ID) usage since we have multi-init/multi-fetch now. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- Documentation/git-svn.txt | 40 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index a764d1f8ee..a45067e164 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -49,7 +49,7 @@ 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' +remotes/git-svn and work on that branch. Use the 'dcommit' command (see below) to write git commits back to remotes/git-svn. @@ -274,7 +274,7 @@ ADVANCED OPTIONS -b:: --branch :: -Used with 'fetch' or 'commit'. +Used with 'fetch', 'dcommit' or 'commit'. This can be used to join arbitrary git branches to remotes/git-svn on new commits where the tree object is equivalent. @@ -368,7 +368,7 @@ SVN was very wrong. Basic Examples ~~~~~~~~~~~~~~ -Tracking and contributing to an Subversion managed-project: +Tracking and contributing to a Subversion-managed project: ------------------------------------------------------------------------ # Initialize a repo (like git init-db): @@ -377,10 +377,9 @@ Tracking and contributing to an Subversion managed-project: 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 +# Do some work, and then commit your new changes to SVN, as well as +# automatically updating your working HEAD: + git-svn dcommit # Something is committed to SVN, rebase the latest into your branch: git-svn fetch && git rebase remotes/git-svn # Append svn:ignore settings to the default git exclude file: @@ -404,26 +403,24 @@ which can lead to merge commits reversing previous commits in SVN. 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 original signal is weak. +with Subversion is cumbersome as a result. git-svn does not do +automated merge/branch tracking by default and leaves it entirely up to +the user on the git side. [[tracking-multiple-repos]] 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/svn/git-svn directory -and instead do all of its work in $GIT_DIR/svn/$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. +SVN repositories via one git repository. Simply use the --id/-i flag or +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/svn/git-svn directory and instead do all of its work in +$GIT_DIR/svn/$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. [[fetch-args]] ADDITIONAL FETCH ARGUMENTS @@ -486,7 +483,8 @@ If you are not using the SVN::* Perl libraries and 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'. +probably just to rm -rf $GIT_DIR/git-svn/tree and run 'rebuild'. You +can avoid this problem entirely by using 'dcommit'. We ignore all SVN properties except svn:executable. Too difficult to map them since we rely heavily on git write-tree being _exactly_ the From 1ca7558dd838e82f6f6b8611b981654fa4ecde2b Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 28 Nov 2006 18:51:42 -0800 Subject: [PATCH 09/10] git-svn: fix multi-init After the bugfix to connect to repositories where the user has limited read permissions, multi-init was broken due to our SVN::Ra connection being limited to working in a subdirectory; so we now create a new Ra connection for init-ing branches and another for tags Along with that fix, allow the user to use the command-line option flags for multi-init (--revision being the most notable; but also --no-auth-cache, --config-dir, --username (for passing to SVN), and --shared/--template for passing to git-init-db Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index d8d8716d38..3891122d73 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -124,7 +124,12 @@ my %cmd = ( 'no-graft-copy' => \$_no_graft_copy } ], 'multi-init' => [ \&multi_init, 'Initialize multiple trees (like git-svnimport)', - { %multi_opts, %fc_opts } ], + { %multi_opts, %init_opts, + 'revision|r=i' => \$_revision, + 'username=s' => \$_username, + 'config-dir=s' => \$_config_dir, + 'no-auth-cache' => \$_no_auth_cache, + } ], 'multi-fetch' => [ \&multi_fetch, 'Fetch multiple trees (like git-svnimport)', \%fc_opts ], @@ -3316,11 +3321,11 @@ sub libsvn_commit_cb { sub libsvn_ls_fullurl { my $fullurl = shift; - $SVN ||= libsvn_connect($fullurl); + my $ra = libsvn_connect($fullurl); my @ret; my $pool = SVN::Pool->new; - my ($dirent, undef, undef) = $SVN->get_dir($SVN->{svn_path}, - $SVN->get_latest_revnum, $pool); + my $r = defined $_revision ? $_revision : $ra->get_latest_revnum; + my ($dirent, undef, undef) = $ra->get_dir('', $r, $pool); foreach my $d (keys %$dirent) { if ($dirent->{$d}->kind == $SVN::Node::dir) { push @ret, "$d/"; # add '/' for compat with cli svn From ab3bb800b46cf66249ead9e13c22cbc48d790c9a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 28 Nov 2006 22:29:18 -0800 Subject: [PATCH 10/10] git blame -C: fix output format tweaks when crossing file boundary. We used to get the case that more than two paths came from the same commit wrong when computing the output width and deciding to turn on --show-name option automatically. When we find that lines that came from a path that is different from what we started digging from, we should always turn --show-name on, and we should count the name length for all files involved. Signed-off-by: Junio C Hamano --- builtin-blame.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/builtin-blame.c b/builtin-blame.c index 066dee743e..53fed4501a 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -1435,14 +1435,14 @@ static void find_alignment(struct scoreboard *sb, int *option) struct commit_info ci; int num; + if (strcmp(suspect->path, sb->path)) + *option |= OUTPUT_SHOW_NAME; + num = strlen(suspect->path); + if (longest_file < num) + longest_file = num; if (!(suspect->commit->object.flags & METAINFO_SHOWN)) { suspect->commit->object.flags |= METAINFO_SHOWN; get_commit_info(suspect->commit, &ci, 1); - if (strcmp(suspect->path, sb->path)) - *option |= OUTPUT_SHOW_NAME; - num = strlen(suspect->path); - if (longest_file < num) - longest_file = num; num = strlen(ci.author); if (longest_author < num) longest_author = num;