Skip to content

Commit

Permalink
git svn dcommit: new option --interactive.
Browse files Browse the repository at this point in the history
Allow the user to check the patch set before it is commited to SVN. It is
then possible to accept/discard one patch, accept all, or quit.

This interactive mode is similar with 'git send email' behaviour. However,
'git svn dcommit' returns as soon as one patch is discarded.
Part of the code was taken from git-send-email.perl (see 'ask' function)

Tests several combinations of potential answers to
'git svn dcommit --interactive'. For each of them, test whether patches
were commited to SVN or not.

Thanks-to Eric Wong <normalperson@yhbt.net> for the initial idea.

Acked-by: Eric Wong <normalperson@yhbt.net>
Signed-off-by: Frédéric Heitzmann <frederic.heitzmann@gmail.com>
  • Loading branch information
Frédéric Heitzmann authored and Eric Wong committed Oct 16, 2011
1 parent 2883969 commit afd7f1e
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 1 deletion.
8 changes: 8 additions & 0 deletions Documentation/git-svn.txt
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@ svn:mergeinfo property in the SVN repository when possible. Currently, this can
only be done when dcommitting non-fast-forward merges where all parents but the
first have already been pushed into SVN.

--interactive;;
Ask the user to confirm that a patch set should actually be sent to SVN.
For each patch, one may answer "yes" (accept this patch), "no" (discard this
patch), "all" (accept all patches), or "quit".
+
'git svn dcommit' returns immediately if answer if "no" or "quit", without
commiting anything to SVN.

'branch'::
Create a branch in the SVN repository.

Expand Down
75 changes: 74 additions & 1 deletion git-svn.perl
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ BEGIN
$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
$_merge, $_strategy, $_dry_run, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
$_git_format, $_commit_url, $_tag, $_merge_info);
$_git_format, $_commit_url, $_tag, $_merge_info, $_interactive);
$Git::SVN::_follow_parent = 1;
$SVN::Git::Fetcher::_placeholder_filename = ".gitignore";
$_q ||= 0;
Expand Down Expand Up @@ -163,6 +163,7 @@ BEGIN
'revision|r=i' => \$_revision,
'no-rebase' => \$_no_rebase,
'mergeinfo=s' => \$_merge_info,
'interactive|i' => \$_interactive,
%cmt_opts, %fc_opts } ],
branch => [ \&cmd_branch,
'Create a branch in the SVN repository',
Expand Down Expand Up @@ -256,6 +257,27 @@ BEGIN
{} ],
);

use Term::ReadLine;
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;

my $term = eval {
$ENV{"GIT_SVN_NOTTY"}
? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
: new Term::ReadLine 'git-svn';
};
if ($@) {
$term = new FakeTerm "$@: going non-interactive";
}

my $cmd;
for (my $i = 0; $i < @ARGV; $i++) {
if (defined $cmd{$ARGV[$i]}) {
Expand Down Expand Up @@ -366,6 +388,36 @@ sub version {
exit 0;
}
sub ask {
my ($prompt, %arg) = @_;
my $valid_re = $arg{valid_re};
my $default = $arg{default};
my $resp;
my $i = 0;
if ( !( defined($term->IN)
&& defined( fileno($term->IN) )
&& defined( $term->OUT )
&& defined( fileno($term->OUT) ) ) ){
return defined($default) ? $default : undef;
}
while ($i++ < 10) {
$resp = $term->readline($prompt);
if (!defined $resp) { # EOF
print "\n";
return defined $default ? $default : undef;
}
if ($resp eq '' and defined $default) {
return $default;
}
if (!defined $valid_re or $resp =~ /$valid_re/) {
return $resp;
}
}
return undef;
}

sub do_git_init_db {
unless (-d $ENV{GIT_DIR}) {
my @init_db = ('init');
Expand Down Expand Up @@ -746,6 +798,27 @@ sub cmd_dcommit {
"If these changes depend on each other, re-running ",
"without --no-rebase may be required."
}

if (defined $_interactive){
my $ask_default = "y";
foreach my $d (@$linear_refs){
my ($fh, $ctx) = command_output_pipe(qw(show --summary), "$d");
while (<$fh>){
print $_;
}
command_close_pipe($fh, $ctx);
$_ = ask("Commit this patch to SVN? ([y]es (default)|[n]o|[q]uit|[a]ll): ",
valid_re => qr/^(?:yes|y|no|n|quit|q|all|a)/i,
default => $ask_default);
die "Commit this patch reply required" unless defined $_;
if (/^[nq]/i) {
exit(0);
} elsif (/^a/i) {
last;
}
}
}

my $expect_url = $url;

my $push_merge_info = eval {
Expand Down
64 changes: 64 additions & 0 deletions t/t9162-git-svn-dcommit-interactive.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/bin/sh
#
# Copyright (c) 2011 Frédéric Heitzmann

test_description='git svn dcommit --interactive series'
. ./lib-git-svn.sh

test_expect_success 'initialize repo' '
svn_cmd mkdir -m"mkdir test-interactive" "$svnrepo/test-interactive" &&
git svn clone "$svnrepo/test-interactive" test-interactive &&
cd test-interactive &&
touch foo && git add foo && git commit -m"foo: first commit" &&
git svn dcommit
'

test_expect_success 'answers: y [\n] yes' '
(
echo "change #1" >> foo && git commit -a -m"change #1" &&
echo "change #2" >> foo && git commit -a -m"change #2" &&
echo "change #3" >> foo && git commit -a -m"change #3" &&
( echo "y
y" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
test $(git rev-parse HEAD) = $(git rev-parse remotes/git-svn)
)
'

test_expect_success 'answers: yes yes no' '
(
echo "change #1" >> foo && git commit -a -m"change #1" &&
echo "change #2" >> foo && git commit -a -m"change #2" &&
echo "change #3" >> foo && git commit -a -m"change #3" &&
( echo "yes
yes
no" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
test $(git rev-parse HEAD^^^) = $(git rev-parse remotes/git-svn) &&
git reset --hard remotes/git-svn
)
'

test_expect_success 'answers: yes quit' '
(
echo "change #1" >> foo && git commit -a -m"change #1" &&
echo "change #2" >> foo && git commit -a -m"change #2" &&
echo "change #3" >> foo && git commit -a -m"change #3" &&
( echo "yes
quit" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
test $(git rev-parse HEAD^^^) = $(git rev-parse remotes/git-svn) &&
git reset --hard remotes/git-svn
)
'

test_expect_success 'answers: all' '
(
echo "change #1" >> foo && git commit -a -m"change #1" &&
echo "change #2" >> foo && git commit -a -m"change #2" &&
echo "change #3" >> foo && git commit -a -m"change #3" &&
( echo "all" | GIT_SVN_NOTTY=1 git svn dcommit --interactive ) &&
test $(git rev-parse HEAD) = $(git rev-parse remotes/git-svn) &&
git reset --hard remotes/git-svn
)
'

test_done

0 comments on commit afd7f1e

Please sign in to comment.