diff --git a/Documentation/RelNotes/1.7.8.txt b/Documentation/RelNotes/1.7.8.txt index 5500db2b71..dcd2467427 100644 --- a/Documentation/RelNotes/1.7.8.txt +++ b/Documentation/RelNotes/1.7.8.txt @@ -4,6 +4,8 @@ Git v1.7.8 Release Notes (draft) Updates since v1.7.7 -------------------- + * Some git-svn and git-gui updates. + * The build procedure has been taught to take advantage of computed dependency automatically when the complier supports it. @@ -147,7 +149,7 @@ included in this release. --- exec >/var/tmp/1 -O=v1.7.7-289-gb73c683 +O=v1.7.7-324-g47d45a5 echo O=$(git describe --always master) git log --first-parent --oneline --reverse ^$O master echo diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index f977e8780b..34ee785064 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -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. diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index fd6a43d0a2..f8971603f7 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -854,6 +854,7 @@ set default_config(gui.fontdiff) [font configure font_diff] # TODO: this option should be added to the git-config documentation set default_config(gui.maxfilesdisplayed) 5000 set default_config(gui.usettk) 1 +set default_config(gui.warndetachedcommit) 1 set font_descs { {fontui font_ui {mc "Main Font"}} {fontdiff font_diff {mc "Diff/Console Font"}} @@ -1526,7 +1527,7 @@ proc run_prepare_commit_msg_hook {} { # prepare-commit-msg requires PREPARE_COMMIT_MSG exist. From git-gui # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an - # empty file but existant file. + # empty file but existent file. set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a] diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl index 61e358f960..691941e959 100644 --- a/git-gui/lib/blame.tcl +++ b/git-gui/lib/blame.tcl @@ -22,6 +22,7 @@ field w_asim ; # text column: annotations (simple computation) field w_file ; # text column: actual file data field w_cviewer ; # pane showing commit message field finder ; # find mini-dialog frame +field gotoline ; # line goto mini-dialog frame field status ; # status mega-widget instance field old_height ; # last known height of $w.file_pane @@ -231,6 +232,11 @@ constructor new {i_commit i_path i_jump} { -column [expr {[llength $w_columns] - 1}] \ ] + set gotoline [::linebar::new \ + $w.file_pane.out.lf $w_file \ + -column [expr {[llength $w_columns] - 1}] \ + ] + set w_cviewer $w.file_pane.cm.t text $w_cviewer \ -background white \ @@ -274,7 +280,11 @@ constructor new {i_commit i_path i_jump} { $w.ctxm add command \ -label [mc "Find Text..."] \ -accelerator F7 \ - -command [list searchbar::show $finder] + -command [cb _show_finder] + $w.ctxm add command \ + -label [mc "Goto Line..."] \ + -accelerator "Ctrl-G" \ + -command [cb _show_linebar] menu $w.ctxm.enc build_encoding_menu $w.ctxm.enc [cb _setencoding] $w.ctxm add cascade \ @@ -341,10 +351,13 @@ constructor new {i_commit i_path i_jump} { bind $w_cviewer "[list focus $w_file];break" bind $w_cviewer [list focus $w_cviewer] bind $w_file [cb _focus_search $w_file] - bind $top [list searchbar::show $finder] + bind $top [cb _show_finder] + bind $top [cb _show_finder] + bind $top [cb _show_finder] bind $top [list searchbar::hide $finder] bind $top [list searchbar::find_next $finder] bind $top [list searchbar::find_prev $finder] + bind $top [cb _show_linebar] catch { bind $top [list searchbar::find_prev $finder] } grid configure $w.header -sticky ew @@ -1298,9 +1311,9 @@ method _position_tooltip {} { set pos_y [expr {[winfo pointery .] + 10}] set g "${req_w}x${req_h}" - if {$pos_x >= 0} {append g +} + if {[tk windowingsystem] eq "win32" || $pos_x >= 0} {append g +} append g $pos_x - if {$pos_y >= 0} {append g +} + if {[tk windowingsystem] eq "win32" || $pos_y >= 0} {append g +} append g $pos_y wm geometry $tooltip_wm $g @@ -1336,4 +1349,14 @@ method _resize {new_height} { set old_height $new_height } +method _show_finder {} { + linebar::hide $gotoline + searchbar::show $finder +} + +method _show_linebar {} { + searchbar::hide $finder + linebar::show $gotoline +} + } diff --git a/git-gui/lib/choose_rev.tcl b/git-gui/lib/choose_rev.tcl index c12d5e1698..54c7957a66 100644 --- a/git-gui/lib/choose_rev.tcl +++ b/git-gui/lib/choose_rev.tcl @@ -610,9 +610,9 @@ method _position_tooltip {} { set pos_y [expr {[winfo pointery .] + 10}] set g "${req_w}x${req_h}" - if {$pos_x >= 0} {append g +} + if {[tk windowingsystem] eq "win32" || $pos_x >= 0} {append g +} append g $pos_x - if {$pos_y >= 0} {append g +} + if {[tk windowingsystem] eq "win32" || $pos_y >= 0} {append g +} append g $pos_y wm geometry $tooltip_wm $g diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl index 5ce46877bf..372bed9948 100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@ -260,8 +260,23 @@ proc commit_prehook_wait {fd_ph curHEAD msg_p} { } proc commit_commitmsg {curHEAD msg_p} { + global is_detached repo_config global pch_error + if {$is_detached && $repo_config(gui.warndetachedcommit)} { + set msg [mc "You are about to commit on a detached head.\ +This is a potentially dangerous thing to do because if you switch\ +to another branch you will loose your changes and it can be difficult\ +to retrieve them later from the reflog. You should probably cancel this\ +commit and create a new branch to continue.\n\ +\n\ +Do you really want to proceed with your Commit?"] + if {[ask_popup $msg] ne yes} { + unlock_index + return + } + } + # -- Run the commit-msg hook. # set fd_ph [githook_read commit-msg $msg_p] diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl index 5d7bbf23ed..e38b647b71 100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@ -356,12 +356,21 @@ proc do_add_all {} { global file_states set paths [list] + set unknown_paths [list] foreach path [array names file_states] { switch -glob -- [lindex $file_states($path) 0] { U? {continue} ?M - ?T - ?D {lappend paths $path} + ?O {lappend unknown_paths $path} + } + } + if {[llength $unknown_paths]} { + set reply [ask_popup [mc "There are unknown files do you also want +to stage those?"]] + if {$reply} { + set paths [concat $paths $unknown_paths] } } add_helper {Adding all changed files} $paths diff --git a/git-gui/lib/line.tcl b/git-gui/lib/line.tcl new file mode 100644 index 0000000000..c160012de6 --- /dev/null +++ b/git-gui/lib/line.tcl @@ -0,0 +1,81 @@ +# goto line number +# based on code from gitk, Copyright (C) Paul Mackerras + +class linebar { + +field w +field ctext + +field linenum {} + +constructor new {i_w i_text args} { + global use_ttk NS + set w $i_w + set ctext $i_text + + ${NS}::frame $w + ${NS}::label $w.l -text [mc "Goto Line:"] + entry $w.ent \ + -textvariable ${__this}::linenum \ + -background lightgreen \ + -validate key \ + -validatecommand [cb _validate %P] + ${NS}::button $w.bn -text [mc Go] -command [cb _goto] + + pack $w.l -side left + pack $w.bn -side right + pack $w.ent -side left -expand 1 -fill x + + eval grid conf $w -sticky we $args + grid remove $w + + trace add variable linenum write [cb _goto_cb] + bind $w.ent [cb _goto] + bind $w.ent [cb hide] + + bind $w [list delete_this $this] + return $this +} + +method show {} { + if {![visible $this]} { + grid $w + } + focus -force $w.ent +} + +method hide {} { + if {[visible $this]} { + $w.ent delete 0 end + focus $ctext + grid remove $w + } +} + +method visible {} { + return [winfo ismapped $w] +} + +method editor {} { + return $w.ent +} + +method _validate {P} { + # only accept numbers as input + string is integer $P +} + +method _goto_cb {name ix op} { + after idle [cb _goto 1] +} + +method _goto {{nohide {0}}} { + if {$linenum ne {}} { + $ctext see $linenum.0 + if {!$nohide} { + hide $this + } + } +} + +} diff --git a/git-gui/lib/search.tcl b/git-gui/lib/search.tcl index 7fdbf87bcd..ef3486f083 100644 --- a/git-gui/lib/search.tcl +++ b/git-gui/lib/search.tcl @@ -35,6 +35,8 @@ constructor new {i_w i_text args} { grid remove $w trace add variable searchstring write [cb _incrsearch_cb] + bind $w.ent [cb find_next] + bind $w.ent [cb find_prev] bind $w [list delete_this $this] return $this @@ -196,4 +198,4 @@ method scrolled {} { } } -} \ No newline at end of file +} diff --git a/git-gui/po/README b/git-gui/po/README index 595bbf5dee..0f5837d48e 100644 --- a/git-gui/po/README +++ b/git-gui/po/README @@ -18,28 +18,23 @@ specialized so-called "po file editors" (e.g. emacs po-mode, KBabel, poedit, GTranslator --- any of them would work well). Please install them. -You would then need to clone the git-gui internationalization project -repository, so that you can work on it: +You would then need to clone the git-gui project repository and create +a feature branch to begin working: - $ git clone mob@repo.or.cz:/srv/git/git-gui/git-gui-i18n.git/ - $ cd git-gui-i18n - $ git checkout --track -b mob origin/mob - $ git config remote.origin.push mob + $ git clone git://repo.or.cz/git-gui.git + $ cd git-gui.git + $ git checkout -b my-translation -The "git checkout" command creates a 'mob' branch from upstream's -corresponding branch and makes it your current branch. You will be -working on this branch. - -The "git config" command records in your repository configuration file -that you would push "mob" branch to the upstream when you say "git -push". +The "git checkout" command creates a new branch to keep your work +isolated and to make it simple to post your patch series when +completed. You will be working on this branch. 2. Starting a new language. -In the git-gui-i18n directory is a po/ subdirectory. It has a -handful files whose names end with ".po". Is there a file that has -messages in your language? +In the git-gui directory is a po/ subdirectory. It has a handful of +files whose names end with ".po". Is there a file that has messages +in your language? If you do not know what your language should be named, you need to find it. This currently follows ISO 639-1 two letter codes: @@ -149,15 +144,18 @@ There is a trick to test your translation without first installing: $ make $ LANG=af ./git-gui.sh -When you are satisfied with your translation, commit your changes, and -push it back to the 'mob' branch: +When you are satisfied with your translation, commit your changes then submit +your patch series to the maintainer and the Git mailing list: $ edit po/af.po ... be sure to update Last-Translator: and ... PO-Revision-Date: lines. $ git add po/af.po - $ git commit -m 'Started Afrikaans translation.' - $ git push + $ git commit -s -m 'git-gui: added Afrikaans translation.' + $ git send-email --to 'git@vger.kernel.org' \ + --cc 'Pat Thoyts ' \ + --subject 'git-gui: Afrikaans translation' \ + master.. 3. Updating your translation. @@ -169,6 +167,7 @@ itself was updated and there are new messages that need translation. In any case, make sure you are up-to-date before starting your work: + $ git checkout master $ git pull In the former case, you will edit po/af.po (again, replace "af" with diff --git a/git-gui/po/sv.po b/git-gui/po/sv.po index 8bd3c5d75f..24cc4e3675 100644 --- a/git-gui/po/sv.po +++ b/git-gui/po/sv.po @@ -1714,7 +1714,7 @@ msgstr "" #: lib/index.tcl:30 msgid "Continue" -msgstr "Forstätt" +msgstr "Fortsätt" #: lib/index.tcl:33 msgid "Unlock Index" diff --git a/git-svn.perl b/git-svn.perl index a0410f0554..b608bbf95a 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -87,14 +87,15 @@ my ($_stdin, $_help, $_edit, $_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; my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username, 'config-dir=s' => \$Git::SVN::Ra::config_dir, 'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache, - 'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex ); + 'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex, + 'ignore-refs=s' => \$Git::SVN::Ra::_ignore_refs_regex ); my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent, 'authors-file|A=s' => \$_authors, 'authors-prog=s' => \$_authors_prog, @@ -163,6 +164,7 @@ my %cmd = ( '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', @@ -256,6 +258,27 @@ my %cmd = ( {} ], ); +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]}) { @@ -366,6 +389,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'); @@ -388,9 +441,12 @@ sub do_git_init_db { command_noisy('config', "$pfx.$i", $icv{$i}); $set = $i; } - my $ignore_regex = \$SVN::Git::Fetcher::_ignore_regex; - command_noisy('config', "$pfx.ignore-paths", $$ignore_regex) - if defined $$ignore_regex; + my $ignore_paths_regex = \$SVN::Git::Fetcher::_ignore_regex; + command_noisy('config', "$pfx.ignore-paths", $$ignore_paths_regex) + if defined $$ignore_paths_regex; + my $ignore_refs_regex = \$Git::SVN::Ra::_ignore_refs_regex; + command_noisy('config', "$pfx.ignore-refs", $$ignore_refs_regex) + if defined $$ignore_refs_regex; if (defined $SVN::Git::Fetcher::_preserve_empty_dirs) { my $fname = \$SVN::Git::Fetcher::_placeholder_filename; @@ -746,6 +802,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 { @@ -2119,6 +2196,8 @@ sub read_all_remotes { $r->{$1}->{url} = $2; } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) { $r->{$1}->{pushurl} = $2; + } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) { + $r->{$1}->{ignore_refs_regex} = $2; } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) { my ($remote, $t, $local_ref, $remote_ref) = ($1, $2, $3, $4); @@ -2155,6 +2234,16 @@ sub read_all_remotes { } } keys %$r; + foreach my $remote (keys %$r) { + foreach ( grep { defined $_ } + map { $r->{$remote}->{$_} } qw(branches tags) ) { + foreach my $rs ( @$_ ) { + $rs->{ignore_refs_regex} = + $r->{$remote}->{ignore_refs_regex}; + } + } + } + $r; } @@ -5310,7 +5399,7 @@ sub apply_diff { } package Git::SVN::Ra; -use vars qw/@ISA $config_dir $_log_window_size/; +use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/; use strict; use warnings; my ($ra_invalid, $can_do_switch, %ignored_err, $RA); @@ -5768,6 +5857,17 @@ sub get_dir_globbed { @finalents; } +# return value: 0 -- don't ignore, 1 -- ignore +sub is_ref_ignored { + my ($g, $p) = @_; + my $refname = $g->{ref}->full_path($p); + return 1 if defined($g->{ignore_refs_regex}) && + $refname =~ m!$g->{ignore_refs_regex}!; + return 0 unless defined($_ignore_refs_regex); + return 1 if $refname =~ m!$_ignore_refs_regex!o; + return 0; +} + sub match_globs { my ($self, $exists, $paths, $globs, $r) = @_; @@ -5804,6 +5904,7 @@ sub match_globs { next unless /$g->{path}->{regex}/; my $p = $1; my $pathname = $g->{path}->full_path($p); + next if is_ref_ignored($g, $p); next if $exists->{$pathname}; next if ($self->check_path($pathname, $r) != $SVN::Node::dir); diff --git a/t/t9162-git-svn-dcommit-interactive.sh b/t/t9162-git-svn-dcommit-interactive.sh new file mode 100644 index 0000000000..e38d9fa37b --- /dev/null +++ b/t/t9162-git-svn-dcommit-interactive.sh @@ -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