From 80573baec4a6211fc9a01d83690c0d73015cfbdc Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Mon, 19 Mar 2007 16:55:57 +0100 Subject: [PATCH 01/60] cvsserver: Introduce new state variable 'method' $state->{method} contains the CVS access method used, either 'ext' or 'pserver' Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 68aa75255e..e9d489bc30 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -91,7 +91,9 @@ $log->debug("Temporary directory is '$TEMP_DIR'"); # if we are called with a pserver argument, # deal with the authentication cat before entering the # main loop +$state->{method} = 'ext'; if (@ARGV && $ARGV[0] eq 'pserver') { + $state->{method} = 'pserver'; my $line = ; chomp $line; unless( $line eq 'BEGIN AUTH REQUEST') { die "E Do not understand $line - expecting BEGIN AUTH REQUEST\n"; @@ -1026,7 +1028,7 @@ sub req_ci $log->info("req_ci : " . ( defined($data) ? $data : "[NULL]" )); - if ( @ARGV && $ARGV[0] eq 'pserver') + if ( $state->{method} eq 'pserver') { print "error 1 pserver access cannot commit\n"; exit; From 92a39a14d00fdfe6868bacf86cbf933a2cc6be93 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Mon, 19 Mar 2007 16:55:58 +0100 Subject: [PATCH 02/60] cvsserver: Handle three part keys in git config correctly This is intended to be used in the form gitcvs.. but this patch doesn't introduce any users yet. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index e9d489bc30..4edb796019 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -183,8 +183,12 @@ sub req_Root } foreach my $line ( @gitvars ) { - next unless ( $line =~ /^(.*?)\.(.*?)=(.*)$/ ); - $cfg->{$1}{$2} = $3; + next unless ( $line =~ /^(.*?)\.(.*?)(?:\.(.*?))?=(.*)$/ ); + unless ($3) { + $cfg->{$1}{$2} = $4; + } else { + $cfg->{$1}{$2}{$3} = $4; + } } unless ( defined ( $cfg->{gitcvs}{enabled} ) and $cfg->{gitcvs}{enabled} =~ /^\s*(1|true|yes)\s*$/i ) From d55820ced668477e07be7d9488c7965906a61b54 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Mon, 19 Mar 2007 16:55:59 +0100 Subject: [PATCH 03/60] cvsserver: Allow to override the configuration per access method Allow to override the gitcvs.enabled and gitcvs.logfile configuration variables for each access method (i.e. "ext" or "pserver") in the form gitcvs.. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- Documentation/git-cvsserver.txt | 12 ++++++++++++ git-cvsserver.perl | 10 +++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index 1c6f6a7e27..f00e6d87e8 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -68,6 +68,18 @@ Note: you need to ensure each user that is going to invoke git-cvsserver has write access to the log file and to the git repository. When offering anon access via pserver, this means that the nobody user should have write access to at least the sqlite database at the root of the repository. + +Both configuration variables can also be overriden for a specific method of +access. Valid method names are "ext" (for SSH access) and "pserver". The +following example configuration would disable pserver access while still +allowing access over SSH. +------ + [gitcvs] + enabled=0 + + [gitcvs "ext"] + enabled=1 +------ -- 3. On the client machine you need to set the following variables. CVSROOT should be set as per normal, but the directory should point at the diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 4edb796019..5d2b6f3575 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -191,7 +191,10 @@ sub req_Root } } - unless ( defined ( $cfg->{gitcvs}{enabled} ) and $cfg->{gitcvs}{enabled} =~ /^\s*(1|true|yes)\s*$/i ) + unless ( ($cfg->{gitcvs}{$state->{method}}{enabled} + and $cfg->{gitcvs}{$state->{method}}{enabled} =~ /^\s*(1|true|yes)\s*$/i) + or ($cfg->{gitcvs}{enabled} + and $cfg->{gitcvs}{enabled} =~ /^\s*(1|true|yes)\s*$/i) ) { print "E GITCVS emulation needs to be enabled on this repo\n"; print "E the repo config file needs a [gitcvs] section added, and the parameter 'enabled' set to 1\n"; @@ -200,9 +203,10 @@ sub req_Root return 0; } - if ( defined ( $cfg->{gitcvs}{logfile} ) ) + my $logfile = $cfg->{gitcvs}{$state->{method}}{logfile} || $cfg->{gitcvs}{logfile}; + if ( $logfile ) { - $log->setfile($cfg->{gitcvs}{logfile}); + $log->setfile($logfile); } else { $log->nofile(); } From eb1780d480c2c57c58024692055a6ee33074a95f Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Mon, 19 Mar 2007 16:56:00 +0100 Subject: [PATCH 04/60] cvsserver: Make the database backend configurable Make all the different parts of the database backend connection configurable. This adds the following string configuration variables: - gitcvs.dbdriver - gitcvs.dbname - gitcvs.dbuser - gitcvs.dbpass The default values emulate the current behavior exactly for backwards compatibility. All configuration variables can also be specified for a specific access method (i.e. in the form gitcvs..) The dbdriver/dbuser/dbpass variables are added for completness. No other backend than SQLite is tested yet. The dbname variable on the other hand is useful with this backend already (to not discriminate against other possible backends it was not splitted in dbdir and dbfile). Both dbname and dbuser support dynamic variable substitution where the available variables are: %m -- the CVS 'module' (i.e. GIT 'head') worked on %a -- CVS access method used (i.e. 'ext' or 'pserver') %u -- User name of the user invoking git-cvsserver %G -- .git directory name %g -- .git directory name, mangled to be used in a filename, currently this substitutes all chars except for [\w.-] with '_' Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 5d2b6f3575..6d10aa3343 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2141,19 +2141,33 @@ sub new bless $self, $class; - $self->{dbdir} = $config . "/"; - die "Database dir '$self->{dbdir}' isn't a directory" unless ( defined($self->{dbdir}) and -d $self->{dbdir} ); - $self->{module} = $module; - $self->{file} = $self->{dbdir} . "/gitcvs.$module.sqlite"; - $self->{git_path} = $config . "/"; $self->{log} = $log; die "Git repo '$self->{git_path}' doesn't exist" unless ( -d $self->{git_path} ); - $self->{dbh} = DBI->connect("dbi:SQLite:dbname=" . $self->{file},"",""); + $self->{dbdriver} = $cfg->{gitcvs}{$state->{method}}{dbdriver} || + $cfg->{gitcvs}{dbdriver} || "dbi:SQLite"; + $self->{dbname} = $cfg->{gitcvs}{$state->{method}}{dbname} || + $cfg->{gitcvs}{dbname} || "%Ggitcvs.%m.sqlite"; + $self->{dbuser} = $cfg->{gitcvs}{$state->{method}}{dbuser} || + $cfg->{gitcvs}{dbuser} || ""; + $self->{dbpass} = $cfg->{gitcvs}{$state->{method}}{dbpass} || + $cfg->{gitcvs}{dbpass} || ""; + my %mapping = ( m => $module, + a => $state->{method}, + u => getlogin || getpwuid($<) || $<, + G => $self->{git_path}, + g => mangle_dirname($self->{git_path}), + ); + $self->{dbname} =~ s/%([mauGg])/$mapping{$1}/eg; + $self->{dbuser} =~ s/%([mauGg])/$mapping{$1}/eg; + + $self->{dbh} = DBI->connect("$self->{dbdriver}:dbname=$self->{dbname}", + $self->{dbuser}, + $self->{dbpass}); $self->{tables} = {}; foreach my $table ( $self->{dbh}->tables ) @@ -2857,5 +2871,19 @@ sub safe_pipe_capture { return wantarray ? @output : join('',@output); } +=head2 mangle_dirname + +create a string from a directory name that is suitable to use as +part of a filename, mainly by converting all chars except \w.- to _ + +=cut +sub mangle_dirname { + my $dirname = shift; + return unless defined $dirname; + + $dirname =~ s/[^\w.-]/_/g; + + return $dirname; +} 1; From 920a449af5a6b4ecbf01a5a4e3bc4894ad302634 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Mon, 19 Mar 2007 16:56:01 +0100 Subject: [PATCH 05/60] cvsserver: Abort if connect to database fails Currently all calls to the database backend make no error checking or handling at all. At least abort if the connection to the database failed since there is really no way we could do anything useful after that. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 6d10aa3343..941a91bcac 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2168,6 +2168,7 @@ sub new $self->{dbh} = DBI->connect("$self->{dbdriver}:dbname=$self->{dbname}", $self->{dbuser}, $self->{dbpass}); + die "Error connecting to database\n" unless defined $self->{dbh}; $self->{tables} = {}; foreach my $table ( $self->{dbh}->tables ) From 0cf611a300fbbbd12827f9defb9cbcc934a3b1d6 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Sat, 31 Mar 2007 15:57:47 +0200 Subject: [PATCH 06/60] cvsserver: Use DBI->table_info instead of DBI->tables DBI->table_info is portable across different DBD backends, DBI->tables is not. Limit the output to objects of type TABLE. Signed-off-by: Junio C Hamano Signed-off-by: Frank Lichtenheld --- git-cvsserver.perl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 941a91bcac..5532ae7a31 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2171,10 +2171,8 @@ sub new die "Error connecting to database\n" unless defined $self->{dbh}; $self->{tables} = {}; - foreach my $table ( $self->{dbh}->tables ) + foreach my $table ( keys %{$self->{dbh}->table_info(undef,undef,undef,'TABLE')->fetchall_hashref('TABLE_NAME')} ) { - $table =~ s/^"//; - $table =~ s/"$//; $self->{tables}{$table} = 1; } From e2a1bc67d321a0c03737179f331c39a52e7049d7 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Wed, 4 Apr 2007 11:31:49 -0400 Subject: [PATCH 07/60] Allow wish interpreter to be defined with TCLTK_PATH Makefile got one external option: - TCLTK_PATH: the path to the Tcl/Tk interpreter. Users (or build wrappers) may set this variable to the location of the wish executable. Signed-off-by: Eygene Ryabinkin Signed-off-by: Shawn O. Pearce --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index b82789ead6..2316b24e00 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,8 @@ ifndef V QUIET_BUILT_IN = @echo ' ' BUILTIN $@; endif +TCLTK_PATH ?= wish + ifeq ($(findstring $(MAKEFLAGS),s),s) QUIET_GEN = QUIET_BUILT_IN = @@ -55,6 +57,7 @@ all:: $(ALL_PROGRAMS) install: all $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' + sed -i .bak -e'1,3s|^exec .* "$$0"|exec '"$(TCLTK_PATH)"' "$$0"|' git-gui && rm git-gui.bak $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) From 3cf0bad830c93176acc6e6436da42e1936bb2282 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Tue, 27 Mar 2007 14:29:08 +0400 Subject: [PATCH 08/60] Teach git-gui to use the user-defined UI font everywhere. Some parts of git-gui were not respecting the default GUI font. Most of them were catched and fixed. Signed-off-by: Eygene Ryabinkin Signed-off-by: Shawn O. Pearce --- git-gui.sh | 64 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index 60e79ca1b0..8157184381 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -242,6 +242,8 @@ proc error_popup {msg} { if {[reponame] ne {}} { append title " ([reponame])" } + option add *Dialog.msg.font font_ui + option add *Button.font font_ui set cmd [list tk_messageBox \ -icon error \ -type ok \ @@ -258,6 +260,8 @@ proc warn_popup {msg} { if {[reponame] ne {}} { append title " ([reponame])" } + option add *Dialog.msg.font font_ui + option add *Button.font font_ui set cmd [list tk_messageBox \ -icon warning \ -type ok \ @@ -274,6 +278,8 @@ proc info_popup {msg {parent .}} { if {[reponame] ne {}} { append title " ([reponame])" } + option add *Dialog.msg.font font_ui + option add *Button.font font_ui tk_messageBox \ -parent $parent \ -icon info \ @@ -287,6 +293,8 @@ proc ask_popup {msg} { if {[reponame] ne {}} { append title " ([reponame])" } + option add *Dialog.msg.font font_ui + option add *Button.font font_ui return [tk_messageBox \ -parent . \ -icon question \ @@ -2116,7 +2124,10 @@ proc do_create_branch {} { -value head \ -variable create_branch_revtype \ -font font_ui - eval tk_optionMenu $w.from.head_m create_branch_head $all_heads + set lbranchm [eval tk_optionMenu $w.from.head_m create_branch_head \ + $all_heads] + $lbranchm configure -font font_ui + $w.from.head_m configure -font font_ui grid $w.from.head_r $w.from.head_m -sticky w set all_trackings [all_tracking_branches] if {$all_trackings ne {}} { @@ -2126,9 +2137,11 @@ proc do_create_branch {} { -value tracking \ -variable create_branch_revtype \ -font font_ui - eval tk_optionMenu $w.from.tracking_m \ + set tbranchm [eval tk_optionMenu $w.from.tracking_m \ create_branch_trackinghead \ - $all_trackings + $all_trackings] + $tbranchm configure -font font_ui + $w.from.tracking_m configure -font font_ui grid $w.from.tracking_r $w.from.tracking_m -sticky w } set all_tags [load_all_tags] @@ -2139,9 +2152,11 @@ proc do_create_branch {} { -value tag \ -variable create_branch_revtype \ -font font_ui - eval tk_optionMenu $w.from.tag_m \ + set tagsm [eval tk_optionMenu $w.from.tag_m \ create_branch_tag \ - $all_tags + $all_tags] + $tagsm configure -font font_ui + $w.from.tag_m configure -font font_ui grid $w.from.tag_r $w.from.tag_m -sticky w } radiobutton $w.from.exp_r \ @@ -2335,7 +2350,11 @@ proc do_delete_branch {} { -value head \ -variable delete_branch_checktype \ -font font_ui - eval tk_optionMenu $w.validate.head_m delete_branch_head $all_heads + set mergedlocalm [eval tk_optionMenu $w.validate.head_m \ + delete_branch_head \ + $all_heads] + $mergedlocalm configure -font font_ui + $w.validate.head_m configure -font font_ui grid $w.validate.head_r $w.validate.head_m -sticky w set all_trackings [all_tracking_branches] if {$all_trackings ne {}} { @@ -2345,9 +2364,11 @@ proc do_delete_branch {} { -value tracking \ -variable delete_branch_checktype \ -font font_ui - eval tk_optionMenu $w.validate.tracking_m \ + set mergedtrackm [eval tk_optionMenu $w.validate.tracking_m \ delete_branch_trackinghead \ - $all_trackings + $all_trackings] + $mergedtrackm configure -font font_ui + $w.validate.tracking_m configure -font font_ui grid $w.validate.tracking_r $w.validate.tracking_m -sticky w } radiobutton $w.validate.always_r \ @@ -2721,7 +2742,10 @@ proc do_push_anywhere {} { -value remote \ -variable push_urltype \ -font font_ui - eval tk_optionMenu $w.dest.remote_m push_remote $all_remotes + set remmenu [eval tk_optionMenu $w.dest.remote_m push_remote \ + $all_remotes] + $remmenu configure -font font_ui + $w.dest.remote_m configure -font font_ui grid $w.dest.remote_r $w.dest.remote_m -sticky w if {[lsearch -sorted -exact $all_remotes origin] != -1} { set push_remote origin @@ -4686,9 +4710,11 @@ proc do_options {} { frame $w.global.$name label $w.global.$name.l -text "$text:" -font font_ui pack $w.global.$name.l -side left -anchor w -fill x - eval tk_optionMenu $w.global.$name.family \ + set fontmenu [eval tk_optionMenu $w.global.$name.family \ global_config_new(gui.$font^^family) \ - $all_fonts + $all_fonts] + $w.global.$name.family configure -font font_ui + $fontmenu configure -font font_ui spinbox $w.global.$name.size \ -textvariable global_config_new(gui.$font^^size) \ -from 2 -to 80 -increment 1 \ @@ -5083,18 +5109,18 @@ set ui_comm {} # -- Menu Bar # menu .mbar -tearoff 0 -.mbar add cascade -label Repository -menu .mbar.repository -.mbar add cascade -label Edit -menu .mbar.edit +.mbar add cascade -label Repository -menu .mbar.repository -font font_ui +.mbar add cascade -label Edit -menu .mbar.edit -font font_ui if {[is_enabled branch]} { - .mbar add cascade -label Branch -menu .mbar.branch + .mbar add cascade -label Branch -menu .mbar.branch -font font_ui } if {[is_enabled multicommit] || [is_enabled singlecommit]} { - .mbar add cascade -label Commit -menu .mbar.commit + .mbar add cascade -label Commit -menu .mbar.commit -font font_ui } if {[is_enabled transport]} { - .mbar add cascade -label Merge -menu .mbar.merge - .mbar add cascade -label Fetch -menu .mbar.fetch - .mbar add cascade -label Push -menu .mbar.push + .mbar add cascade -label Merge -menu .mbar.merge -font font_ui + .mbar add cascade -label Fetch -menu .mbar.fetch -font font_ui + .mbar add cascade -label Push -menu .mbar.push -font font_ui } . configure -menu .mbar @@ -5370,7 +5396,7 @@ if {[is_MacOSX]} { # -- Help Menu # -.mbar add cascade -label Help -menu .mbar.help +.mbar add cascade -label Help -menu .mbar.help -font font_ui menu .mbar.help if {![is_MacOSX]} { From df0cd69558b826a0f43420ecc808557656961f62 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Tue, 27 Mar 2007 14:31:02 +0400 Subject: [PATCH 09/60] Improve look-and-feel of the git-gui tool. Made the default buttons on the dialog active and focused upon the dialog appearence. Bound 'Escape' and 'Return' keys to the dialog dismissal where it was appropriate: mainly for dialogs with only one button and no editable fields, but on console output dialogs as well. Signed-off-by: Eygene Ryabinkin Signed-off-by: Shawn O. Pearce --- git-gui.sh | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index 8157184381..6e55bd45fd 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -2705,10 +2705,12 @@ proc do_push_anywhere {} { frame $w.buttons button $w.buttons.create -text Push \ -font font_ui \ + -default active \ -command [list start_push_anywhere_action $w] pack $w.buttons.create -side right button $w.buttons.cancel -text {Cancel} \ -font font_ui \ + -default normal \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 @@ -2799,7 +2801,7 @@ proc do_push_anywhere {} { set push_thin 0 set push_tags 0 - bind $w "grab $w" + bind $w "grab $w; focus $w.buttons.create" bind $w "destroy $w" wm title $w "[appname] ([reponame]): Push" tkwait window $w @@ -4131,6 +4133,7 @@ proc console_done {args} { if {[winfo exists $w]} { $w.m.s conf -background green -text {Success} $w.ok conf -state normal + focus $w.ok } } else { if {![winfo exists $w]} { @@ -4138,6 +4141,7 @@ proc console_done {args} { } $w.m.s conf -background red -text {Error: Command Failed} $w.ok conf -state normal + focus $w.ok } array unset console_cr $w @@ -4205,9 +4209,11 @@ proc do_stats {} { frame $w.buttons -border 1 button $w.buttons.close -text Close \ -font font_ui \ + -default active \ -command [list destroy $w] button $w.buttons.gc -text {Compress Database} \ -font font_ui \ + -default normal \ -command "destroy $w;do_gc" pack $w.buttons.close -side right pack $w.buttons.gc -side left @@ -4236,7 +4242,7 @@ proc do_stats {} { } pack $w.stat -pady 10 -padx 10 - bind $w "grab $w; focus $w" + bind $w "grab $w; focus $w.buttons.close" bind $w [list destroy $w] bind $w [list destroy $w] wm title $w "[appname] ([reponame]): Database Statistics" @@ -4533,6 +4539,7 @@ proc do_about {} { frame $w.buttons button $w.buttons.close -text {Close} \ -font font_ui \ + -default active \ -command [list destroy $w] pack $w.buttons.close -side right pack $w.buttons -side bottom -fill x -pady 10 -padx 10 @@ -4578,8 +4585,9 @@ $copyright" \ clipboard append -format STRING -type STRING -- \[$w.vers cget -text\] " - bind $w "grab $w; focus $w" + bind $w "grab $w; focus $w.buttons.close" bind $w "destroy $w" + bind $w "destroy $w" bind_button3 $w.vers "tk_popup $w.ctxm %X %Y; grab $w; focus $w" wm title $w "About [appname]" tkwait window $w @@ -4616,14 +4624,17 @@ proc do_options {} { frame $w.buttons button $w.buttons.restore -text {Restore Defaults} \ -font font_ui \ + -default normal \ -command do_restore_defaults pack $w.buttons.restore -side left button $w.buttons.save -text Save \ -font font_ui \ + -default active \ -command [list do_save_config $w] pack $w.buttons.save -side right button $w.buttons.cancel -text {Cancel} \ -font font_ui \ + -default normal \ -command [list destroy $w] pack $w.buttons.cancel -side right -padx 5 pack $w.buttons -side bottom -fill x -pady 10 -padx 10 @@ -4726,7 +4737,7 @@ proc do_options {} { pack $w.global.$name -side top -anchor w -fill x } - bind $w "grab $w; focus $w" + bind $w "grab $w; focus $w.buttons.save" bind $w "destroy $w" wm title $w "[appname] ([reponame]): Options" tkwait window $w From 53a291a435a173a18969011753104f8ab41234c8 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Tue, 27 Mar 2007 14:31:55 +0400 Subject: [PATCH 10/60] Do not break git-gui messages into multiple lines. Many git-gui messages were broken into a multiple lines to make good paragraph width. Unfortunately in reality it breaks the paragraph width completely, because the dialog window width does not coincide with the paragraph width created by the current font. Tcl/Tk's standard dialog boxes are breaking the long lines automatically, so it is better to make long lines and let the interpreter do the job. Signed-off-by: Eygene Ryabinkin Signed-off-by: Shawn O. Pearce --- git-gui.sh | 64 +++++++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 46 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index 6e55bd45fd..6439bee6ac 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -735,12 +735,9 @@ proc handle_empty_diff {} { [short_path $path] has no changes. -The modification date of this file was updated -by another application, but the content within -the file was not changed. +The modification date of this file was updated by another application, but the content within the file was not changed. -A rescan will be automatically started to find -other files which may have the same state." +A rescan will be automatically started to find other files which may have the same state." clear_diff display_file $path __ @@ -1041,8 +1038,7 @@ proc load_last_commit {} { if {[llength $PARENT] == 0} { error_popup {There is nothing to amend. -You are about to create the initial commit. -There is no commit before this to amend. +You are about to create the initial commit. There is no commit before this to amend. } return } @@ -1051,10 +1047,7 @@ There is no commit before this to amend. if {$curType eq {merge}} { error_popup {Cannot amend while merging. -You are currently in the middle of a merge that -has not been fully completed. You cannot amend -the prior commit unless you first abort the -current merge activity. +You are currently in the middle of a merge that has not been fully completed. You cannot amend the prior commit unless you first abort the current merge activity. } return } @@ -1144,9 +1137,7 @@ proc commit_tree {} { } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { info_popup {Last scanned state does not match repository state. -Another Git program has modified this repository -since the last scan. A rescan must be performed -before another commit can be created. +Another Git program has modified this repository since the last scan. A rescan must be performed before another commit can be created. The rescan will be automatically started now. } @@ -1167,8 +1158,7 @@ The rescan will be automatically started now. U? { error_popup "Unmerged files cannot be committed. -File [short_path $path] has merge conflicts. -You must resolve them and add the file before committing. +File [short_path $path] has merge conflicts. You must resolve them and add the file before committing. " unlock_index return @@ -1284,8 +1274,7 @@ proc commit_committree {fd_wt curHEAD msg} { if {$tree_id eq $old_tree} { info_popup {No changes to commit. -No files were modified by this commit and it -was not a merge commit. +No files were modified by this commit and it was not a merge commit. A rescan will be automatically started now. } @@ -2403,9 +2392,7 @@ proc switch_branch {new_branch} { } elseif {$commit_type ne $curType || $HEAD ne $curHEAD} { info_popup {Last scanned state does not match repository state. -Another Git program has modified this repository -since the last scan. A rescan must be performed -before the current branch can be changed. +Another Git program has modified this repository since the last scan. A rescan must be performed before the current branch can be changed. The rescan will be automatically started now. } @@ -2496,12 +2483,9 @@ Staying on branch '$current_branch'." if {[catch {git symbolic-ref HEAD "refs/heads/$new_branch"} err]} { error_popup "Failed to set current branch. -This working directory is only partially switched. -We successfully updated your files, but failed to -update an internal Git file. +This working directory is only partially switched. We successfully updated your files, but failed to update an internal Git file. -This should not have occurred. [appname] will now -close and give up. +This should not have occurred. [appname] will now close and give up. $err" do_quit @@ -2817,8 +2801,7 @@ proc can_merge {} { if {[string match amend* $commit_type]} { info_popup {Cannot merge while amending. -You must finish amending this commit before -starting any type of merge. +You must finish amending this commit before starting any type of merge. } return 0 } @@ -2832,9 +2815,7 @@ starting any type of merge. if {$commit_type ne $curType || $HEAD ne $curHEAD} { info_popup {Last scanned state does not match repository state. -Another Git program has modified this repository -since the last scan. A rescan must be performed -before a merge can be performed. +Another Git program has modified this repository since the last scan. A rescan must be performed before a merge can be performed. The rescan will be automatically started now. } @@ -2853,9 +2834,7 @@ The rescan will be automatically started now. File [short_path $path] has merge conflicts. -You must resolve them, add the file, and commit to -complete the current merge. Only then can you -begin another merge. +You must resolve them, add the file, and commit to complete the current merge. Only then can you begin another merge. " unlock_index return 0 @@ -2865,9 +2844,7 @@ begin another merge. File [short_path $path] is modified. -You should complete the current commit before -starting a merge. Doing so will help you abort -a failed merge, should the need arise. +You should complete the current commit before starting a merge. Doing so will help you abort a failed merge, should the need arise. " unlock_index return 0 @@ -2943,13 +2920,11 @@ proc finish_merge {revcnt w ok} { Your merge of $revcnt branches has failed. -There are file-level conflicts between the -branches which must be resolved manually. +There are file-level conflicts between the branches which must be resolved manually. The working directory will now be reset. -You can attempt this merge again -by merging only one branch at a time." $w +You can attempt this merge again by merging only one branch at a time." $w set fd [open "| git read-tree --reset -u HEAD" r] fconfigure $fd -blocking 0 -translation binary @@ -3062,8 +3037,7 @@ You must finish amending this commit. if {[ask_popup "Abort $op? -Aborting the current $op will cause -*ALL* uncommitted changes to be lost. +Aborting the current $op will cause *ALL* uncommitted changes to be lost. Continue with aborting the current $op?"] eq {yes}} { set fd [open "| git read-tree --reset -u HEAD" r] @@ -6069,9 +6043,7 @@ if {[is_enabled multicommit]} { if {[ask_popup \ "This repository currently has $objects_current loose objects. -To maintain optimal performance it is strongly -recommended that you compress the database -when more than $object_limit loose objects exist. +To maintain optimal performance it is strongly recommended that you compress the database when more than $object_limit loose objects exist. Compress the database now?"] eq yes} { do_gc From 4372da3441561b3852c0bf466304f1e4f3c06b3f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 4 Apr 2007 11:45:33 -0400 Subject: [PATCH 11/60] Always bind the return key to the default button If a dialog/window has a default button registered not every platform associates the return key with that button, but all users do. We have to register the binding of the return key ourselves to make sure the user's expectations of pressing return will activate the default button are met. Signed-off-by: Shawn O. Pearce --- git-gui.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/git-gui.sh b/git-gui.sh index 6439bee6ac..882b90723d 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -2787,6 +2787,7 @@ proc do_push_anywhere {} { bind $w "grab $w; focus $w.buttons.create" bind $w "destroy $w" + bind $w [list start_push_anywhere_action $w] wm title $w "[appname] ([reponame]): Push" tkwait window $w } @@ -4713,6 +4714,7 @@ proc do_options {} { bind $w "grab $w; focus $w.buttons.save" bind $w "destroy $w" + bind $w [list do_save_config $w] wm title $w "[appname] ([reponame]): Options" tkwait window $w } From f6f2aa39ef97cae03c71ecfecc334f0df60d7920 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 4 Apr 2007 12:08:46 -0400 Subject: [PATCH 12/60] git-gui: Brown paper bag fix division by 0 in blame If we generate a blame status string before we have obtained any annotation data at all from the input file, or if the input file is empty, our total_lines will be 0. This causes a division by 0 error when we blindly divide by the 0 to compute the total percentage of lines loaded. Instead we should report 0% done. Signed-off-by: Shawn O. Pearce --- git-gui.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index 60e79ca1b0..7cbc977ea2 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -3604,12 +3604,14 @@ proc read_blame_incremental {fd w w_load w_cmit w_line w_file} { proc blame_incremental_status {w} { global blame_status blame_data + set have $blame_data($w,blame_lines) + set total $blame_data($w,total_lines) + set pdone 0 + if {$total} {set pdone [expr {100 * $have / $total}]} + set blame_status($w) [format \ "Loading annotations... %i of %i lines annotated (%2i%%)" \ - $blame_data($w,blame_lines) \ - $blame_data($w,total_lines) \ - [expr {100 * $blame_data($w,blame_lines) - / $blame_data($w,total_lines)}]] + $have $total $pdone] } proc blame_click {w w_cmit w_line w_file cur_w pos} { From 473937ed44c112e5d3ced52ab3f9a9e53eccc272 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Sat, 7 Apr 2007 16:58:09 +0200 Subject: [PATCH 13/60] cvsserver: Corrections to the database backend configuration Don't include the scheme name in gitcvs.dbdriver, it is always 'dbi' anyway. Don't allow ':' in driver names nor ';' in database names for sanity reasons. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 5532ae7a31..7fe7949b39 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -2149,7 +2149,7 @@ sub new die "Git repo '$self->{git_path}' doesn't exist" unless ( -d $self->{git_path} ); $self->{dbdriver} = $cfg->{gitcvs}{$state->{method}}{dbdriver} || - $cfg->{gitcvs}{dbdriver} || "dbi:SQLite"; + $cfg->{gitcvs}{dbdriver} || "SQLite"; $self->{dbname} = $cfg->{gitcvs}{$state->{method}}{dbname} || $cfg->{gitcvs}{dbname} || "%Ggitcvs.%m.sqlite"; $self->{dbuser} = $cfg->{gitcvs}{$state->{method}}{dbuser} || @@ -2165,7 +2165,9 @@ sub new $self->{dbname} =~ s/%([mauGg])/$mapping{$1}/eg; $self->{dbuser} =~ s/%([mauGg])/$mapping{$1}/eg; - $self->{dbh} = DBI->connect("$self->{dbdriver}:dbname=$self->{dbname}", + die "Invalid char ':' in dbdriver" if $self->{dbdriver} =~ /:/; + die "Invalid char ';' in dbname" if $self->{dbname} =~ /;/; + $self->{dbh} = DBI->connect("dbi:$self->{dbdriver}:dbname=$self->{dbname}", $self->{dbuser}, $self->{dbpass}); die "Error connecting to database\n" unless defined $self->{dbh}; From febe7dcc088020366bbc601a219a1d6c30ced0c2 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Sat, 7 Apr 2007 16:58:10 +0200 Subject: [PATCH 14/60] cvsserver: Add asciidoc documentation for new database backend configuration Documents the new configuration variables and the variable substitution mechanism. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- Documentation/git-cvsserver.txt | 87 +++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 4 deletions(-) diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index f00e6d87e8..6a5fcfddb3 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -65,11 +65,12 @@ env variable, you can rename git-cvsserver to cvs. ------ Note: you need to ensure each user that is going to invoke git-cvsserver has -write access to the log file and to the git repository. When offering anon -access via pserver, this means that the nobody user should have write access -to at least the sqlite database at the root of the repository. +write access to the log file and to the database (see +<>. If you want to offer write access over +SSH, the users of course also need write access to the git repository itself. -Both configuration variables can also be overriden for a specific method of +[[configaccessmethod]] +All configuration variables can also be overriden for a specific method of access. Valid method names are "ext" (for SSH access) and "pserver". The following example configuration would disable pserver access while still allowing access over SSH. @@ -105,6 +106,84 @@ Example: cvs co -d project-master master ------ +[[dbbackend]] +Database Backend +---------------- + +git-cvsserver uses one database per git head (i.e. CVS module) to +store information about the repository for faster access. The +database doesn't contain any persitent data and can be completly +regenerated from the git repository at any time. The database +needs to be updated (i.e. written to) after every commit. That +means that even if you offer only read access (e.g. by using +the pserver method), git-cvsserver should have write access to +the database to work reliably (otherwise you need to make sure +that the database if up-to-date all the time git-cvsserver is run). + +By default it uses SQLite databases in the git directory, named +`gitcvs..sqlite`. Note that the SQLite backend creates +temporary files in the same directory as the database file on +write so it might not be enough to grant the users using +git-cvsserver write access to the database file without granting +them also write access to the directory. + +You can configure the database backend with the following +configuration variables: + +Configuring database backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +git-cvsserver uses the Perl DBI module. Please also read +its documentation if changing these variables, especially +about `DBI->connect()`. + +gitcvs.dbname:: + Database name. The exact meaning depends on the + used database driver, for SQLite this is a filename. + Supports variable substitution (see below). May + not contain semicolons (`;`). + Default: '%Ggitcvs.%m.sqlite' + +gitcvs.dbdriver:: + Used DBI driver. You can specify any available driver + for this here, but it might not work. cvsserver is tested + with 'DBD::SQLite', reported to work with + 'DBD::Pg', and reported *not* to work with 'DBD::mysql'. + Please regard this as an experimental feature. May not + contain double colons (`:`). + Default: 'SQLite' + +gitcvs.dbuser:: + Database user. Only useful if setting `dbdriver`, since + SQLite has no concept of database users. Supports variable + substitution (see below). + +gitcvs.dbpass:: + Database password. Only useful if setting `dbdriver`, since + SQLite has no concept of database passwords. + +All variables can also be set per access method, see <>. + +Variable substitution +^^^^^^^^^^^^^^^^^^^^^ +In `dbdriver` and `dbuser` you can use the following variables: + +%G:: + git directory name +%g:: + git directory name, where all characters except for + alpha-numeric ones, `.`, and `-` are replaced with + `_` (this should make it easier to use the directory + name in a filename if wanted) +%m:: + CVS module/git head name +%a:: + access method (one of "ext" or "pserver") +%u:: + Name of the user running git-cvsserver. + If no name can be determined, the + numeric uid is used. + Eclipse CVS Client Notes ------------------------ From 3714e7c8950681b440508244a1fcf5899a1b0966 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 22 Dec 2006 22:15:59 +0100 Subject: [PATCH 15/60] Use print_wrapped_text() in shortlog Some oneline descriptions are just too long. In shortlog, it looks much nicer when they are wrapped. Since print_wrapped_text() is UTF-8 aware, it also works with those descriptions. [jc: with minimum fixes] Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-shortlog.c | 11 +++++++--- t/t4201-shortlog.sh | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 t/t4201-shortlog.sh diff --git a/builtin-shortlog.c b/builtin-shortlog.c index 29343aefc8..2cdd528967 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -4,6 +4,7 @@ #include "diff.h" #include "path-list.h" #include "revision.h" +#include "utf8.h" static const char shortlog_usage[] = "git-shortlog [-n] [-s] [... ]"; @@ -323,9 +324,13 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) printf("%s: %d\n", list.items[i].path, onelines->nr); } else { printf("%s (%d):\n", list.items[i].path, onelines->nr); - for (j = onelines->nr - 1; j >= 0; j--) - printf(" %s\n", onelines->items[j].path); - printf("\n"); + for (j = onelines->nr - 1; j >= 0; j--) { + int col = print_wrapped_text(onelines->items[j].path, + 6, 9, 76); + if (col != 76) + putchar('\n'); + } + putchar('\n'); } onelines->strdup_paths = 1; diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh new file mode 100644 index 0000000000..ab8a0888f6 --- /dev/null +++ b/t/t4201-shortlog.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# +# Copyright (c) 2006 Johannes E. Schindelin +# + +test_description='git-shortlog +' + +. ./test-lib.sh + +echo 1 > a1 +git add a1 +tree=$(git write-tree) +commit=$((echo "Test"; echo) | git commit-tree $tree) +git update-ref HEAD $commit + +echo 2 > a1 +git commit -m "This is a very, very long first line for the commit message to see if it is wrapped correctly" a1 + +# test if the wrapping is still valid when replacing all i's by treble clefs. +echo 3 > a1 +git commit -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\360\235\204\236')" a1 + +# now fsck up the utf8 +git repo-config i18n.commitencoding non-utf-8 +echo 4 > a1 +git commit -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\370\235\204\236')" a1 + +echo 5 > a1 +git commit -m "a 12 34 56 78" a1 + +git shortlog HEAD > out + +cat > expect << EOF +A U Thor (5): + Test + This is a very, very long first line for the commit message to see if + it is wrapped correctly + Th๐„žs ๐„žs a very, very long f๐„žrst l๐„žne for the comm๐„žt message to see ๐„žf + ๐„žt ๐„žs wrapped correctly + Th๘„žs ๘„žs a very, very long f๘„žrst l๘„žne for the comm๘„žt + message to see ๘„žf ๘„žt ๘„žs wrapped correctly + a 12 34 + 56 78 + +EOF + +test_expect_success 'shortlog wrapping' 'diff -u expect out' + +test_done From 3d711d97a0db41633a5137e47358cf503b91b074 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 8 Apr 2007 01:28:00 -0700 Subject: [PATCH 16/60] shortlog -w: make wrap-line behaviour optional. Signed-off-by: Junio C Hamano --- builtin-shortlog.c | 70 ++++++++++++++++++++++++++++++++++++++++++--- t/t4201-shortlog.sh | 2 +- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/builtin-shortlog.c b/builtin-shortlog.c index 2cdd528967..3f93498bb7 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -277,11 +277,64 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list) } +static int parse_uint(char const **arg, int comma) +{ + unsigned long ul; + int ret; + char *endp; + + ul = strtoul(*arg, &endp, 10); + if (endp != *arg && *endp && *endp != comma) + return -1; + ret = (int) ul; + if (ret != ul) + return -1; + *arg = endp; + if (**arg) + (*arg)++; + return ret; +} + +static const char wrap_arg_usage[] = "-w[[,[,]]]"; +#define DEFAULT_WRAPLEN 76 +#define DEFAULT_INDENT1 6 +#define DEFAULT_INDENT2 9 + +static void parse_wrap_args(const char *arg, int *in1, int *in2, int *wrap) +{ + arg += 2; /* skip -w */ + + *wrap = parse_uint(&arg, ','); + if (*wrap < 0) + die(wrap_arg_usage); + *in1 = parse_uint(&arg, ','); + if (*in1 < 0) + die(wrap_arg_usage); + *in2 = parse_uint(&arg, '\0'); + if (*in2 < 0) + die(wrap_arg_usage); + + if (!*wrap) + *wrap = DEFAULT_WRAPLEN; + if (!*in1) + *in1 = DEFAULT_INDENT1; + if (!*in2) + *in2 = DEFAULT_INDENT2; + if (*wrap && + ((*in1 && *wrap <= *in1) || + (*in2 && *wrap <= *in2))) + die(wrap_arg_usage); +} + int cmd_shortlog(int argc, const char **argv, const char *prefix) { struct rev_info rev; struct path_list list = { NULL, 0, 0, 1 }; int i, j, sort_by_number = 0, summary = 0; + int wrap_lines = 0; + int wrap = DEFAULT_WRAPLEN; + int in1 = DEFAULT_INDENT1; + int in2 = DEFAULT_INDENT2; /* since -n is a shadowed rev argument, parse our args first */ while (argc > 1) { @@ -290,6 +343,10 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "-s") || !strcmp(argv[1], "--summary")) summary = 1; + else if (!prefixcmp(argv[1], "-w")) { + wrap_lines = 1; + parse_wrap_args(argv[1], &in1, &in2, &wrap); + } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) usage(shortlog_usage); else @@ -325,10 +382,15 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) } else { printf("%s (%d):\n", list.items[i].path, onelines->nr); for (j = onelines->nr - 1; j >= 0; j--) { - int col = print_wrapped_text(onelines->items[j].path, - 6, 9, 76); - if (col != 76) - putchar('\n'); + const char *msg = onelines->items[j].path; + + if (wrap_lines) { + int col = print_wrapped_text(msg, in1, in2, wrap); + if (col != wrap) + putchar('\n'); + } + else + printf(" %s\n", msg); } putchar('\n'); } diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index ab8a0888f6..321429c8fa 100644 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -29,7 +29,7 @@ git commit -m "$(echo "This is a very, very long first line for the commit messa echo 5 > a1 git commit -m "a 12 34 56 78" a1 -git shortlog HEAD > out +git shortlog -w HEAD > out cat > expect << EOF A U Thor (5): From ea4b52a86f6b6b8e5aef8e47fb557f37422512bf Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 7 Apr 2007 05:42:01 -0700 Subject: [PATCH 17/60] t1000: fix case table. Case #10 is not handled with unpack-trees.c:threeway_merge() internally, unless under the agressive rule, and it is not a bug. As the test expects, ND (one side did not do anything, other side deleted) case was meant to be handled by the caller's policy (e.g. git-merge-one-file or git-merge-recursive). Signed-off-by: Junio C Hamano --- t/t1000-read-tree-m-3way.sh | 2 +- unpack-trees.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh index e26a36cf0f..de4e5eb61f 100755 --- a/t/t1000-read-tree-m-3way.sh +++ b/t/t1000-read-tree-m-3way.sh @@ -184,7 +184,7 @@ checked. 9 exists O!=A missing no merge must match A and be up-to-date, if exists. ------------------------------------------------------------------ - 10 exists O==A missing remove ditto + 10 exists O==A missing no merge must match A ------------------------------------------------------------------ 11 exists O!=A O!=B no merge must match A and be A!=B up-to-date, if exists. diff --git a/unpack-trees.c b/unpack-trees.c index a0b676903a..2a58b7fa28 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -786,7 +786,7 @@ int threeway_merge(struct cache_entry **stages, o->nontrivial_merge = 1; - /* #2, #3, #4, #6, #7, #9, #11. */ + /* #2, #3, #4, #6, #7, #9, #10, #11. */ count = 0; if (!head_match || !remote_match) { for (i = 1; i < o->head_idx; i++) { From 4c4caafc9cef1031beb46babe9adfdcc03f3cd52 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 7 Apr 2007 05:49:19 -0700 Subject: [PATCH 18/60] Treat D/F conflict entry more carefully in unpack-trees.c::threeway_merge() This fixes three buglets in threeway_merge() regarding D/F conflict entries. * After finishing with path D and handling path D/F, some stages have D/F conflict entry which are obviously non-NULL. For the purpose of determining if the path D/F is missing in the ancestor, they should not be taken into account. * D/F conflict entry is a marker to say "this stage does _not_ have the path", so do not send them to keep_entry(). Signed-off-by: Junio C Hamano --- unpack-trees.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/unpack-trees.c b/unpack-trees.c index 2a58b7fa28..5139481358 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -665,7 +665,6 @@ int threeway_merge(struct cache_entry **stages, int count; int head_match = 0; int remote_match = 0; - const char *path = NULL; int df_conflict_head = 0; int df_conflict_remote = 0; @@ -675,13 +674,10 @@ int threeway_merge(struct cache_entry **stages, int i; for (i = 1; i < o->head_idx; i++) { - if (!stages[i]) + if (!stages[i] || stages[i] == o->df_conflict_entry) any_anc_missing = 1; - else { - if (!path) - path = stages[i]->name; + else no_anc_exists = 0; - } } index = stages[0]; @@ -697,13 +693,6 @@ int threeway_merge(struct cache_entry **stages, remote = NULL; } - if (!path && index) - path = index->name; - if (!path && head) - path = head->name; - if (!path && remote) - path = remote->name; - /* First, if there's a #16 situation, note that to prevent #13 * and #14. */ @@ -755,6 +744,23 @@ int threeway_merge(struct cache_entry **stages, if (o->aggressive) { int head_deleted = !head && !df_conflict_head; int remote_deleted = !remote && !df_conflict_remote; + const char *path = NULL; + + if (index) + path = index->name; + else if (head) + path = head->name; + else if (remote) + path = remote->name; + else { + for (i = 1; i < o->head_idx; i++) { + if (stages[i] && stages[i] != o->df_conflict_entry) { + path = stages[i]->name; + break; + } + } + } + /* * Deleted in both. * Deleted in one and unchanged in the other. @@ -790,7 +796,7 @@ int threeway_merge(struct cache_entry **stages, count = 0; if (!head_match || !remote_match) { for (i = 1; i < o->head_idx; i++) { - if (stages[i]) { + if (stages[i] && stages[i] != o->df_conflict_entry) { keep_entry(stages[i], o); count++; break; From ac7f0f436e4f45d616ca509f5163fddab104516b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 7 Apr 2007 05:52:57 -0700 Subject: [PATCH 19/60] merge-recursive: do not barf on "to be removed" entries. When update-trees::threeway_merge() decides that a path that exists in the current index (and HEAD) is to be removed, it leaves a stage 0 entry whose mode bits are set to 0. The code mistook it as "this stage wants the blob here", and proceeded to call update_file_flags() which ended up trying to put the mode=0 entry in the index, got very confused, and ended up barfing with "do not know what to do with 000000". Since threeway_merge() does not handle case #10 (one side removes while the other side does not do anything), this is not a problem while we refuse to merge branches that have D/F conflicts, but when we start resolving them, we would need to be able to remove cache entries, and at that point it starts to matter. Signed-off-by: Junio C Hamano --- merge-recursive.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 3096594b3e..0e259566e6 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1018,9 +1018,9 @@ static int process_renames(struct path_list *a_renames, return clean_merge; } -static unsigned char *has_sha(const unsigned char *sha) +static unsigned char *stage_sha(const unsigned char *sha, unsigned mode) { - return is_null_sha1(sha) ? NULL: (unsigned char *)sha; + return (is_null_sha1(sha) || mode == 0) ? NULL: (unsigned char *)sha; } /* Per entry merge function */ @@ -1033,12 +1033,12 @@ static int process_entry(const char *path, struct stage_data *entry, print_index_entry("\tpath: ", entry); */ int clean_merge = 1; - unsigned char *o_sha = has_sha(entry->stages[1].sha); - unsigned char *a_sha = has_sha(entry->stages[2].sha); - unsigned char *b_sha = has_sha(entry->stages[3].sha); unsigned o_mode = entry->stages[1].mode; unsigned a_mode = entry->stages[2].mode; unsigned b_mode = entry->stages[3].mode; + unsigned char *o_sha = stage_sha(entry->stages[1].sha, o_mode); + unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode); + unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode); if (o_sha && (!a_sha || !b_sha)) { /* Case A: Deleted in one */ @@ -1139,6 +1139,12 @@ static int process_entry(const char *path, struct stage_data *entry, update_file_flags(mfi.sha, mfi.mode, path, 0 /* update_cache */, 1 /* update_working_directory */); } + } else if (!o_sha && !a_sha && !b_sha) { + /* + * this entry was deleted altogether. a_mode == 0 means + * we had that path and want to actively remove it. + */ + remove_file(1, path, !a_mode); } else die("Fatal merge failure, shouldn't happen."); From 4d50895a390658bf1b9a9385dbc0b9f90b48c803 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 7 Apr 2007 06:41:13 -0700 Subject: [PATCH 20/60] merge-recursive: handle D/F conflict case more carefully. When a path D that originally was blob in the ancestor was modified on our branch while it was removed on the other branch, we keep stages 1 and 2, and leave our version in the working tree. If the other branch created a path D/F, however, that path can cleanly be resolved in the index (after all, the ancestor nor we do not have it and only the other side added), but it cannot be checked out. The issue is the same when the other branch had D and we had renamed it to D/F, or the ancestor had D/F instead of D (so there are four combinations). Do not stop the merge, but leave both D and D/F paths in the index so that the user can clear things up. Signed-off-by: Junio C Hamano --- merge-recursive.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 0e259566e6..595b0226ac 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -596,9 +596,31 @@ static void update_file_flags(const unsigned char *sha, if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) { int fd; - if (mkdir_p(path, 0777)) - die("failed to create path %s: %s", path, strerror(errno)); - unlink(path); + int status; + const char *msg = "failed to create path '%s'%s"; + + status = mkdir_p(path, 0777); + if (status) { + if (status == -3) { + /* something else exists */ + error(msg, path, ": perhaps a D/F conflict?"); + update_wd = 0; + goto update_index; + } + die(msg, path, ""); + } + if (unlink(path)) { + if (errno == EISDIR) { + /* something else exists */ + error(msg, path, ": perhaps a D/F conflict?"); + update_wd = 0; + goto update_index; + } + if (errno != ENOENT) + die("failed to unlink %s " + "in preparation to update: %s", + path, strerror(errno)); + } if (mode & 0100) mode = 0777; else @@ -620,6 +642,7 @@ static void update_file_flags(const unsigned char *sha, die("do not know what to do with %06o %s '%s'", mode, sha1_to_hex(sha), path); } + update_index: if (update_cache) add_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD); } From 885b98107547fe3f6d17ca0af0578e040f7600d0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 7 Apr 2007 07:17:35 -0700 Subject: [PATCH 21/60] t3030: merge-recursive backend test. We have fairly extensive coverage of read-tree 3-way machinery, and many Porcelain-ish tests use git-merge front-end tests, but we did not have good basic test for merge-recursive, which made it very hard to hack on it. I used this during the recent work to teach D/F conflicts to merge-recursive. Signed-off-by: Junio C Hamano --- t/t3030-merge-recursive.sh | 528 +++++++++++++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100755 t/t3030-merge-recursive.sh diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh new file mode 100755 index 0000000000..aef92b9b92 --- /dev/null +++ b/t/t3030-merge-recursive.sh @@ -0,0 +1,528 @@ +#!/bin/sh + +test_description='merge-recursive backend test' + +. ./test-lib.sh + +test_expect_success 'setup 1' ' + + echo hello >a && + o0=$(git hash-object a) && + cp a b && + cp a A && + mkdir d && + cp a d/e && + + test_tick && + git add a b A d/e && + git commit -m initial && + c0=$(git rev-parse --verify HEAD) && + git branch side && + git branch df-1 && + git branch df-2 && + git branch df-3 && + git branch remove && + + echo hello >>a && + cp a d/e && + o1=$(git hash-object a) && + + git add a d/e && + + test_tick && + git commit -m "master modifies a and d/e" && + c1=$(git rev-parse --verify HEAD) && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o1 a" + echo "100644 blob $o0 b" + echo "100644 blob $o1 d/e" + echo "100644 $o0 0 A" + echo "100644 $o1 0 a" + echo "100644 $o0 0 b" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual +' + +test_expect_success 'setup 2' ' + + rm -rf [Aabd] && + git checkout side && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o0 a" + echo "100644 blob $o0 b" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o0 0 a" + echo "100644 $o0 0 b" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual && + + echo goodbye >>a && + o2=$(git hash-object a) && + + git add a && + + test_tick && + git commit -m "side modifies a" && + c2=$(git rev-parse --verify HEAD) && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o2 a" + echo "100644 blob $o0 b" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o2 0 a" + echo "100644 $o0 0 b" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual +' + +test_expect_success 'setup 3' ' + + rm -rf [Aabd] && + git checkout df-1 && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o0 a" + echo "100644 blob $o0 b" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o0 0 a" + echo "100644 $o0 0 b" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual && + + rm -f b && mkdir b && echo df-1 >b/c && git add b/c && + o3=$(git hash-object b/c) && + + test_tick && + git commit -m "df-1 makes b/c" && + c3=$(git rev-parse --verify HEAD) && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o0 a" + echo "100644 blob $o3 b/c" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o0 0 a" + echo "100644 $o3 0 b/c" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual +' + +test_expect_success 'setup 4' ' + + rm -rf [Aabd] && + git checkout df-2 && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o0 a" + echo "100644 blob $o0 b" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o0 0 a" + echo "100644 $o0 0 b" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual && + + rm -f a && mkdir a && echo df-2 >a/c && git add a/c && + o4=$(git hash-object a/c) && + + test_tick && + git commit -m "df-2 makes a/c" && + c4=$(git rev-parse --verify HEAD) && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o4 a/c" + echo "100644 blob $o0 b" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o4 0 a/c" + echo "100644 $o0 0 b" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual +' + +test_expect_success 'setup 5' ' + + rm -rf [Aabd] && + git checkout remove && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o0 a" + echo "100644 blob $o0 b" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o0 0 a" + echo "100644 $o0 0 b" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual && + + rm -f b && + echo remove-conflict >a && + + git add a && + git rm b && + o5=$(git hash-object a) && + + test_tick && + git commit -m "remove removes b and modifies a" && + c5=$(git rev-parse --verify HEAD) && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o5 a" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o5 0 a" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'setup 6' ' + + rm -rf [Aabd] && + git checkout df-3 && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o0 a" + echo "100644 blob $o0 b" + echo "100644 blob $o0 d/e" + echo "100644 $o0 0 A" + echo "100644 $o0 0 a" + echo "100644 $o0 0 b" + echo "100644 $o0 0 d/e" + ) >expected && + git diff -u expected actual && + + rm -fr d && echo df-3 >d && git add d && + o6=$(git hash-object d) && + + test_tick && + git commit -m "df-3 makes d" && + c6=$(git rev-parse --verify HEAD) && + ( git ls-tree -r HEAD ; git ls-files -s ) >actual && + ( + echo "100644 blob $o0 A" + echo "100644 blob $o0 a" + echo "100644 blob $o0 b" + echo "100644 blob $o6 d" + echo "100644 $o0 0 A" + echo "100644 $o0 0 a" + echo "100644 $o0 0 b" + echo "100644 $o6 0 d" + ) >expected && + git diff -u expected actual +' + +test_expect_success 'merge-recursive simple' ' + + rm -fr [Aabd] && + git checkout -f "$c2" && + + git-merge-recursive "$c0" -- "$c2" "$c1" + status=$? + case "$status" in + 1) + : happy + ;; + *) + echo >&2 "why status $status!!!" + false + ;; + esac +' + +test_expect_success 'merge-recursive result' ' + + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o0 1 a" + echo "100644 $o2 2 a" + echo "100644 $o1 3 a" + echo "100644 $o0 0 b" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'merge-recursive remove conflict' ' + + rm -fr [Aabd] && + git checkout -f "$c1" && + + git-merge-recursive "$c0" -- "$c1" "$c5" + status=$? + case "$status" in + 1) + : happy + ;; + *) + echo >&2 "why status $status!!!" + false + ;; + esac +' + +test_expect_success 'merge-recursive remove conflict' ' + + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o0 1 a" + echo "100644 $o1 2 a" + echo "100644 $o5 3 a" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'merge-recursive d/f simple' ' + rm -fr [Aabd] && + git reset --hard && + git checkout -f "$c1" && + + git-merge-recursive "$c0" -- "$c1" "$c3" +' + +test_expect_success 'merge-recursive result' ' + + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o1 0 a" + echo "100644 $o3 0 b/c" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'merge-recursive d/f conflict' ' + + rm -fr [Aabd] && + git reset --hard && + git checkout -f "$c1" && + + git-merge-recursive "$c0" -- "$c1" "$c4" + status=$? + case "$status" in + 1) + : happy + ;; + *) + echo >&2 "why status $status!!!" + false + ;; + esac +' + +test_expect_success 'merge-recursive d/f conflict result' ' + + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o0 1 a" + echo "100644 $o1 2 a" + echo "100644 $o4 0 a/c" + echo "100644 $o0 0 b" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'merge-recursive d/f conflict the other way' ' + + rm -fr [Aabd] && + git reset --hard && + git checkout -f "$c4" && + + git-merge-recursive "$c0" -- "$c4" "$c1" + status=$? + case "$status" in + 1) + : happy + ;; + *) + echo >&2 "why status $status!!!" + false + ;; + esac +' + +test_expect_success 'merge-recursive d/f conflict result the other way' ' + + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o0 1 a" + echo "100644 $o1 3 a" + echo "100644 $o4 0 a/c" + echo "100644 $o0 0 b" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'merge-recursive d/f conflict' ' + + rm -fr [Aabd] && + git reset --hard && + git checkout -f "$c1" && + + git-merge-recursive "$c0" -- "$c1" "$c6" + status=$? + case "$status" in + 1) + : happy + ;; + *) + echo >&2 "why status $status!!!" + false + ;; + esac +' + +test_expect_success 'merge-recursive d/f conflict result' ' + + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o1 0 a" + echo "100644 $o0 0 b" + echo "100644 $o6 3 d" + echo "100644 $o0 1 d/e" + echo "100644 $o1 2 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'merge-recursive d/f conflict' ' + + rm -fr [Aabd] && + git reset --hard && + git checkout -f "$c6" && + + git-merge-recursive "$c0" -- "$c6" "$c1" + status=$? + case "$status" in + 1) + : happy + ;; + *) + echo >&2 "why status $status!!!" + false + ;; + esac +' + +test_expect_success 'merge-recursive d/f conflict result' ' + + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o1 0 a" + echo "100644 $o0 0 b" + echo "100644 $o6 2 d" + echo "100644 $o0 1 d/e" + echo "100644 $o1 3 d/e" + ) >expected && + git diff -u expected actual + +' + +test_expect_success 'reset and 3-way merge' ' + + git reset --hard "$c2" && + git read-tree -m "$c0" "$c2" "$c1" + +' + +test_expect_success 'reset and bind merge' ' + + git reset --hard master && + git read-tree --prefix=M/ master && + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o0 0 M/A" + echo "100644 $o1 0 M/a" + echo "100644 $o0 0 M/b" + echo "100644 $o1 0 M/d/e" + echo "100644 $o1 0 a" + echo "100644 $o0 0 b" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual && + + git read-tree --prefix=a1/ master && + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o0 0 M/A" + echo "100644 $o1 0 M/a" + echo "100644 $o0 0 M/b" + echo "100644 $o1 0 M/d/e" + echo "100644 $o1 0 a" + echo "100644 $o0 0 a1/A" + echo "100644 $o1 0 a1/a" + echo "100644 $o0 0 a1/b" + echo "100644 $o1 0 a1/d/e" + echo "100644 $o0 0 b" + echo "100644 $o1 0 d/e" + ) >expected && + git diff -u expected actual + + git read-tree --prefix=z/ master && + git ls-files -s >actual && + ( + echo "100644 $o0 0 A" + echo "100644 $o0 0 M/A" + echo "100644 $o1 0 M/a" + echo "100644 $o0 0 M/b" + echo "100644 $o1 0 M/d/e" + echo "100644 $o1 0 a" + echo "100644 $o0 0 a1/A" + echo "100644 $o1 0 a1/a" + echo "100644 $o0 0 a1/b" + echo "100644 $o1 0 a1/d/e" + echo "100644 $o0 0 b" + echo "100644 $o1 0 d/e" + echo "100644 $o0 0 z/A" + echo "100644 $o1 0 z/a" + echo "100644 $o0 0 z/b" + echo "100644 $o1 0 z/d/e" + ) >expected && + git diff -u expected actual + +' + +test_done + From 4db0c8dec5c009cbbb61135a321a48278e668a25 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Thu, 12 Apr 2007 00:51:33 +0200 Subject: [PATCH 22/60] cvsserver: Allow to "add" a removed file CVS allows you to add a removed file (where the removal is not yet committed) which will cause the server to send the latest revision of the file and to delete the "removed" status. Copy this behaviour. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 7fe7949b39..d5674caaad 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -360,12 +360,52 @@ sub req_add argsplit("add"); + my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); + $updater->update(); + + argsfromdir($updater); + my $addcount = 0; foreach my $filename ( @{$state->{args}} ) { $filename = filecleanup($filename); + my $meta = $updater->getmeta($filename); + my $wrev = revparse($filename); + + if ($wrev && $meta && ($wrev < 0)) + { + # previously removed file, add back + $log->info("added file $filename was previously removed, send 1.$meta->{revision}"); + + print "MT +updated\n"; + print "MT text U \n"; + print "MT fname $filename\n"; + print "MT newline\n"; + print "MT -updated\n"; + + unless ( $state->{globaloptions}{-n} ) + { + my ( $filepart, $dirpart ) = filenamesplit($filename,1); + + print "Created $dirpart\n"; + print $state->{CVSROOT} . "/$state->{module}/$filename\n"; + + # this is an "entries" line + my $kopts = kopts_from_path($filepart); + $log->debug("/$filepart/1.$meta->{revision}//$kopts/"); + print "/$filepart/1.$meta->{revision}//$kopts/\n"; + # permissions + $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}"); + print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n"; + # transmit file + transmitfile($meta->{filehash}); + } + + next; + } + unless ( defined ( $state->{entries}{$filename}{modified_filename} ) ) { print "E cvs add: nothing known about `$filename'\n"; From 0f76a543e398b116882a49fc115273988cc9eb29 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Thu, 12 Apr 2007 16:43:36 +0200 Subject: [PATCH 23/60] cvsserver: Reword documentation on necessity of write access Reworded the section about git-cvsserver needing to update the database. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- Documentation/git-cvsserver.txt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index 6a5fcfddb3..535214c4fd 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -114,8 +114,14 @@ git-cvsserver uses one database per git head (i.e. CVS module) to store information about the repository for faster access. The database doesn't contain any persitent data and can be completly regenerated from the git repository at any time. The database -needs to be updated (i.e. written to) after every commit. That -means that even if you offer only read access (e.g. by using +needs to be updated (i.e. written to) after every commit. + +If the commit is done directly by using git (as opposed to +using git-cvsserver) the update will need to happen on the +next repository access by git-cvsserver, independent of +access method and requested operation. + +That means that even if you offer only read access (e.g. by using the pserver method), git-cvsserver should have write access to the database to work reliably (otherwise you need to make sure that the database if up-to-date all the time git-cvsserver is run). @@ -125,7 +131,7 @@ By default it uses SQLite databases in the git directory, named temporary files in the same directory as the database file on write so it might not be enough to grant the users using git-cvsserver write access to the database file without granting -them also write access to the directory. +them write access to the directory, too. You can configure the database backend with the following configuration variables: From b2475703d8c95b39e9a05b4d5638452bacfc2a8b Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Thu, 12 Apr 2007 16:54:28 +0200 Subject: [PATCH 24/60] cvsserver: Document the GIT branches -> CVS modules mapping more prominently Add a note about the branches -> modules mapping to LIMITATIONS because I really think it should be noted there and not just at the end of the installation step-by-step HOWTO. I used "git branches" there and changed "heads" to "branches" in my section about database configuration. I'm reluctant to replace all occourences of "head" with "branch" though because you always have to say "git branch" because CVS also has the concept of branches. You can say "head" though, because there is no such concept in CVS. In all the existing occourences of head other than the one I changed I think "head" flows better in the text. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- Documentation/git-cvsserver.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index 535214c4fd..1cd00aa076 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -31,6 +31,10 @@ over pserver for anonymous CVS access. CVS clients cannot tag, branch or perform GIT merges. +git-cvsserver maps GIT branches to CVS modules. This is very different +from what most CVS users would expect since in CVS modules usually represent +one or more directories. + INSTALLATION ------------ From 047528680e783046b89bb6b220a7576d74c538d0 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Fri, 13 Apr 2007 18:13:42 +0200 Subject: [PATCH 25/60] config.txt: Add gitcvs.db* variables Adds documentation for gitcvs.{dbname,dbdriver,dbuser,dbpass} Texts are mostly taken from git-cvsserver.txt whith some adaptions so that they make more sense out of the context of the original man page. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- Documentation/config.txt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Documentation/config.txt b/Documentation/config.txt index cf1e040381..d0d284f3e0 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -408,6 +408,33 @@ gitcvs.logfile:: Path to a log file where the cvs pserver interface well... logs various stuff. See gitlink:git-cvsserver[1]. +gitcvs.dbname:: + Database used by git-cvsserver to cache revision information + derived from the git repository. The exact meaning depends on the + used database driver, for SQLite (which is the default driver) this + is a filename. Supports variable substitution (see + gitlink:git-cvsserver[1] for details). May not contain semicolons (`;`). + Default: '%Ggitcvs.%m.sqlite' + +gitcvs.dbdriver:: + Used Perl DBI driver. You can specify any available driver + for this here, but it might not work. git-cvsserver is tested + with 'DBD::SQLite', reported to work with 'DBD::Pg', and + reported *not* to work with 'DBD::mysql'. Experimental feature. + May not contain double colons (`:`). Default: 'SQLite'. + See gitlink:git-cvsserver[1]. + +gitcvs.dbuser, gitcvs.dbpass:: + Database user and password. Only useful if setting 'gitcvs.dbdriver', + since SQLite has no concept of database users and/or passwords. + 'gitcvs.dbuser' supports variable substitution (see + gitlink:git-cvsserver[1] for details). + +All gitcvs variables except for 'gitcvs.allbinary' can also specifed +as 'gitcvs..' (where 'access_method' is one +of "ext" and "pserver") to make them apply only for the given access +method. + http.sslVerify:: Whether to verify the SSL certificate when fetching or pushing over HTTPS. Can be overridden by the 'GIT_SSL_NO_VERIFY' environment From 19c821487b28f56180290aa7d1f30e6bd5316225 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 14 Apr 2007 15:10:48 -0400 Subject: [PATCH 26/60] git-gui: Display the directory basename in the title By showing the basename of the directory very early in the title bar I can more easily locate a particular git-gui session when I have 8 open at once and my Windows taskbar is overflowing with items. Signed-off-by: Shawn O. Pearce --- git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui.sh b/git-gui.sh index ef5960cdaf..94067cc5f7 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -5968,7 +5968,7 @@ unset i set file_lists($ui_index) [list] set file_lists($ui_workdir) [list] -wm title . "[appname] ([file normalize [file dirname [gitdir]]])" +wm title . "[appname] ([reponame]) [file normalize [file dirname [gitdir]]]" focus -force $ui_comm # -- Warn the user about environmental problems. Cygwin's Tcl From a59b276e18f3d4a548caf549e05188cb1bd3a709 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 16 Apr 2007 16:03:15 -0700 Subject: [PATCH 27/60] Add a generic "object decorator" interface, and make object refs use it This allows you to add an arbitrary "decoration" of your choice to any object. It's a space- and time-efficient way to add information to arbitrary objects, especially if most objects probably do not have the decoration. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- Makefile | 4 +-- decorate.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ decorate.h | 18 +++++++++++ object-refs.c | 69 ++++----------------------------------- object.h | 1 - 5 files changed, 116 insertions(+), 65 deletions(-) create mode 100644 decorate.c create mode 100644 decorate.h diff --git a/Makefile b/Makefile index b8e6030940..251fc31fc0 100644 --- a/Makefile +++ b/Makefile @@ -283,7 +283,7 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - utf8.h reflog-walk.h patch-ids.h + utf8.h reflog-walk.h patch-ids.h decorate.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@ -305,7 +305,7 @@ LIB_OBJS = \ write_or_die.o trace.o list-objects.o grep.o match-trees.o \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \ color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \ - convert.o + convert.o decorate.o BUILTIN_OBJS = \ builtin-add.o \ diff --git a/decorate.c b/decorate.c new file mode 100644 index 0000000000..396b41311a --- /dev/null +++ b/decorate.c @@ -0,0 +1,89 @@ +/* + * decorate.c - decorate a git object with some arbitrary + * data. + */ +#include "cache.h" +#include "object.h" +#include "decorate.h" + +static unsigned int hash_obj(struct object *obj, unsigned int n) +{ + unsigned int hash = *(unsigned int *)obj->sha1; + return hash % n; +} + +static void *insert_decoration(struct decoration *n, struct object *base, void *decoration) +{ + int size = n->size; + struct object_decoration *hash = n->hash; + int j = hash_obj(base, size); + + while (hash[j].base) { + if (hash[j].base == base) { + void *old = hash[j].decoration; + hash[j].decoration = decoration; + return old; + } + j++; + if (++j >= size) + j = 0; + } + hash[j].base = base; + hash[j].decoration = decoration; + n->nr++; + return NULL; +} + +static void grow_decoration(struct decoration *n) +{ + int i; + int old_size = n->size; + struct object_decoration *old_hash; + + old_size = n->size; + old_hash = n->hash; + + n->size = (old_size + 1000) * 3 / 2; + n->hash = xcalloc(n->size, sizeof(struct object_decoration)); + n->nr = 0; + + for (i = 0; i < old_size; i++) { + struct object *base = old_hash[i].base; + void *decoration = old_hash[i].decoration; + + if (!base) + continue; + insert_decoration(n, base, decoration); + } + free(old_hash); +} + +/* Add a decoration pointer, return any old one */ +void *add_decoration(struct decoration *n, struct object *obj, void *decoration) +{ + int nr = n->nr + 1; + + if (nr > n->size * 2 / 3) + grow_decoration(n); + return insert_decoration(n, obj, decoration); +} + +/* Lookup a decoration pointer */ +void *lookup_decoration(struct decoration *n, struct object *obj) +{ + int j; + + /* nothing to lookup */ + if (!n->size) + return NULL; + j = hash_obj(obj, n->size); + for (;;) { + struct object_decoration *ref = n->hash + j; + if (ref->base == obj) + return ref->decoration; + if (!ref->base) + return NULL; + if (++j == n->size) + j = 0; + } +} diff --git a/decorate.h b/decorate.h new file mode 100644 index 0000000000..1fa4ad9beb --- /dev/null +++ b/decorate.h @@ -0,0 +1,18 @@ +#ifndef DECORATE_H +#define DECORATE_H + +struct object_decoration { + struct object *base; + void *decoration; +}; + +struct decoration { + const char *name; + unsigned int size, nr; + struct object_decoration *hash; +}; + +extern void *add_decoration(struct decoration *n, struct object *obj, void *decoration); +extern void *lookup_decoration(struct decoration *n, struct object *obj); + +#endif diff --git a/object-refs.c b/object-refs.c index 98ea10005a..022e8d841c 100644 --- a/object-refs.c +++ b/object-refs.c @@ -1,75 +1,20 @@ #include "cache.h" #include "object.h" +#include "decorate.h" int track_object_refs = 0; -static unsigned int refs_hash_size, nr_object_refs; -static struct object_refs **refs_hash; +static struct decoration ref_decorate; -static unsigned int hash_obj(struct object *obj, unsigned int n) +struct object_refs *lookup_object_refs(struct object *base) { - unsigned int hash = *(unsigned int *)obj->sha1; - return hash % n; + return lookup_decoration(&ref_decorate, base); } -static void insert_ref_hash(struct object_refs *ref, struct object_refs **hash, unsigned int size) +static void add_object_refs(struct object *obj, struct object_refs *refs) { - int j = hash_obj(ref->base, size); - - while (hash[j]) { - j++; - if (j >= size) - j = 0; - } - hash[j] = ref; -} - -static void grow_refs_hash(void) -{ - int i; - int new_hash_size = (refs_hash_size + 1000) * 3 / 2; - struct object_refs **new_hash; - - new_hash = xcalloc(new_hash_size, sizeof(struct object_refs *)); - for (i = 0; i < refs_hash_size; i++) { - struct object_refs *ref = refs_hash[i]; - if (!ref) - continue; - insert_ref_hash(ref, new_hash, new_hash_size); - } - free(refs_hash); - refs_hash = new_hash; - refs_hash_size = new_hash_size; -} - -static void add_object_refs(struct object *obj, struct object_refs *ref) -{ - int nr = nr_object_refs + 1; - - if (nr > refs_hash_size * 2 / 3) - grow_refs_hash(); - ref->base = obj; - insert_ref_hash(ref, refs_hash, refs_hash_size); - nr_object_refs = nr; -} - -struct object_refs *lookup_object_refs(struct object *obj) -{ - struct object_refs *ref; - int j; - - /* nothing to lookup */ - if (!refs_hash_size) - return NULL; - j = hash_obj(obj, refs_hash_size); - while ((ref = refs_hash[j]) != NULL) { - if (ref->base == obj) - break; - j++; - if (j >= refs_hash_size) - j = 0; - } - return ref; + if (add_decoration(&ref_decorate, obj, refs)) + die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1)); } struct object_refs *alloc_object_refs(unsigned count) diff --git a/object.h b/object.h index bdbf0facd4..bdbbc1889c 100644 --- a/object.h +++ b/object.h @@ -8,7 +8,6 @@ struct object_list { struct object_refs { unsigned count; - struct object *base; struct object *ref[FLEX_ARRAY]; /* more */ }; From ca135e7acc06f7d24ead732d2a1a531428da7135 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 16 Apr 2007 16:05:10 -0700 Subject: [PATCH 28/60] Add support for "commit name decorations" to log family of commands This adds "--decorate" as a log option, which prints out the ref names of any commits that are shown. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-log.c | 34 ++++++++++++++++++++++++++++++++-- commit.h | 8 ++++++++ log-tree.c | 21 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 469949457f..38bf52f100 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -13,16 +13,43 @@ #include "tag.h" #include "reflog-walk.h" #include "patch-ids.h" +#include "refs.h" static int default_show_root = 1; /* this is in builtin-diff.c */ void add_head(struct rev_info *revs); +static void add_name_decoration(const char *prefix, const char *name, struct object *obj) +{ + int plen = strlen(prefix); + int nlen = strlen(name); + struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen); + memcpy(res->name, prefix, plen); + memcpy(res->name + plen, name, nlen + 1); + res->next = add_decoration(&name_decoration, obj, res); +} + +static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data) +{ + struct object *obj = parse_object(sha1); + if (!obj) + return 0; + add_name_decoration("", refname, obj); + while (obj->type == OBJ_TAG) { + obj = ((struct tag *)obj)->tagged; + if (!obj) + break; + add_name_decoration("tag: ", refname, obj); + } + return 0; +} + static void cmd_log_init(int argc, const char **argv, const char *prefix, struct rev_info *rev) { int i; + int decorate = 0; rev->abbrev = DEFAULT_ABBREV; rev->commit_format = CMIT_FMT_DEFAULT; @@ -39,8 +66,11 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, git_log_output_encoding = xstrdup(arg); else git_log_output_encoding = ""; - } - else + } else if (!strcmp(arg, "--decorate")) { + if (!decorate) + for_each_ref(add_ref_decoration, NULL); + decorate = 1; + } else die("unrecognized argument: %s", arg); } } diff --git a/commit.h b/commit.h index 83507a07e4..59de17eff8 100644 --- a/commit.h +++ b/commit.h @@ -3,6 +3,7 @@ #include "object.h" #include "tree.h" +#include "decorate.h" struct commit_list { struct commit *item; @@ -21,6 +22,13 @@ struct commit { extern int save_commit_buffer; extern const char *commit_type; +/* While we can decorate any object with a name, it's only used for commits.. */ +extern struct decoration name_decoration; +struct name_decoration { + struct name_decoration *next; + char name[1]; +}; + struct commit *lookup_commit(const unsigned char *sha1); struct commit *lookup_commit_reference(const unsigned char *sha1); struct commit *lookup_commit_reference_gently(const unsigned char *sha1, diff --git a/log-tree.c b/log-tree.c index dad5513230..300b733560 100644 --- a/log-tree.c +++ b/log-tree.c @@ -4,6 +4,8 @@ #include "log-tree.h" #include "reflog-walk.h" +struct decoration name_decoration = { "object names" }; + static void show_parents(struct commit *commit, int abbrev) { struct commit_list *p; @@ -13,6 +15,23 @@ static void show_parents(struct commit *commit, int abbrev) } } +static void show_decorations(struct commit *commit) +{ + const char *prefix; + struct name_decoration *decoration; + + decoration = lookup_decoration(&name_decoration, &commit->object); + if (!decoration) + return; + prefix = " ("; + while (decoration) { + printf("%s%s", prefix, decoration->name); + prefix = ", "; + decoration = decoration->next; + } + putchar(')'); +} + /* * Search for "^[-A-Za-z]+: [^@]+@" pattern. It usually matches * Signed-off-by: and Acked-by: lines. @@ -136,6 +155,7 @@ void show_log(struct rev_info *opt, const char *sep) fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout); if (opt->parents) show_parents(commit, abbrev_commit); + show_decorations(commit); putchar(opt->diffopt.line_termination); return; } @@ -240,6 +260,7 @@ void show_log(struct rev_info *opt, const char *sep) printf(" (from %s)", diff_unique_abbrev(parent->object.sha1, abbrev_commit)); + show_decorations(commit); printf("%s", diff_get_color(opt->diffopt.color_diff, DIFF_RESET)); putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n'); From f06a6a493a14ae632cdd3d04af04301769f4ef71 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 16 Apr 2007 16:51:47 -0700 Subject: [PATCH 29/60] send-email: do not leave an empty CC: line if no cc is present. Signed-off-by: Junio C Hamano --- git-send-email.perl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index 1278fcba46..d6b15480dc 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -446,9 +446,12 @@ sub send_message my ($name, $addr) = ($from =~ /^(.*?)(\s+<.*)/); $from = "\"$name\"$addr"; } + my $ccline = ""; + if ($cc ne '') { + $ccline = "\nCc: $cc"; + } my $header = "From: $from -To: $to -Cc: $cc +To: $to${ccline} Subject: $subject Date: $date Message-Id: $message_id From 238128d88885b5d0f5a3e28d392362a9b267a03f Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Fri, 13 Apr 2007 22:13:10 +0200 Subject: [PATCH 30/60] Fix t4201: accidental arithmetic expansion instead of embedded subshell. It actually breaks here (dash as /bin/sh): t4201-shortlog.sh: 27: Syntax error: Missing '))' FATAL: Unexpected exit with code 2 Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- t/t4201-shortlog.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 321429c8fa..c27e39cb6f 100644 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -11,7 +11,7 @@ test_description='git-shortlog echo 1 > a1 git add a1 tree=$(git write-tree) -commit=$((echo "Test"; echo) | git commit-tree $tree) +commit=$( (echo "Test"; echo) | git commit-tree $tree ) git update-ref HEAD $commit echo 2 > a1 From 4848509a970e5c805a06fdba12c3377472308443 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Fri, 13 Apr 2007 22:13:51 +0200 Subject: [PATCH 31/60] Fix permissions on test scripts Make every test executable. Remove exec-attribute from included shell files, they can't used standalone anyway. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- t/diff-lib.sh | 0 t/lib-read-tree-m-3way.sh | 0 t/t4201-shortlog.sh | 0 t/t6023-merge-file.sh | 0 t/t6024-recursive-merge.sh | 0 t/t6025-merge-symlinks.sh | 0 t/test-lib.sh | 0 7 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 t/diff-lib.sh mode change 100755 => 100644 t/lib-read-tree-m-3way.sh mode change 100644 => 100755 t/t4201-shortlog.sh mode change 100644 => 100755 t/t6023-merge-file.sh mode change 100644 => 100755 t/t6024-recursive-merge.sh mode change 100644 => 100755 t/t6025-merge-symlinks.sh mode change 100755 => 100644 t/test-lib.sh diff --git a/t/diff-lib.sh b/t/diff-lib.sh old mode 100755 new mode 100644 diff --git a/t/lib-read-tree-m-3way.sh b/t/lib-read-tree-m-3way.sh old mode 100755 new mode 100644 diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh old mode 100644 new mode 100755 diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh old mode 100644 new mode 100755 diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh old mode 100644 new mode 100755 diff --git a/t/t6025-merge-symlinks.sh b/t/t6025-merge-symlinks.sh old mode 100644 new mode 100755 diff --git a/t/test-lib.sh b/t/test-lib.sh old mode 100755 new mode 100644 From b8652b4de0e9b386f9a93fbfb1dac06df230cd0a Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Tue, 17 Apr 2007 06:40:50 +0200 Subject: [PATCH 32/60] Bisect: simplify "bisect start" logging. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- git-bisect.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/git-bisect.sh b/git-bisect.sh index 85c374e21e..1cd456173d 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -116,10 +116,7 @@ bisect_start() { done sq "$@" >"$GIT_DIR/BISECT_NAMES" - { - printf "git-bisect start" - echo "$orig_args" - } >>"$GIT_DIR/BISECT_LOG" + echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" bisect_auto_next } From f948792990f82a35bf0c98510e7511ef8acb9cd3 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Tue, 17 Apr 2007 06:51:48 +0200 Subject: [PATCH 33/60] Bisect: rename "t/t6030-bisect-run.sh" to "t/t6030-bisect-porcelain.sh". [jc: also fix 0a5280a9 that incorrectly changed the title of one test.] Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- t/{t6030-bisect-run.sh => t6030-bisect-porcelain.sh} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename t/{t6030-bisect-run.sh => t6030-bisect-porcelain.sh} (97%) diff --git a/t/t6030-bisect-run.sh b/t/t6030-bisect-porcelain.sh similarity index 97% rename from t/t6030-bisect-run.sh rename to t/t6030-bisect-porcelain.sh index de3123522a..13e9379236 100755 --- a/t/t6030-bisect-run.sh +++ b/t/t6030-bisect-porcelain.sh @@ -46,7 +46,7 @@ test_expect_success 'bisect starts with only one bad' ' git bisect next ' -test_expect_success 'bisect starts with only one good' ' +test_expect_success 'bisect does not start with only one good' ' git bisect reset && git bisect start && git bisect good $HASH1 || return 1 From bb1faf0d5bc53b193bbe25e7425458c8eb85efa3 Mon Sep 17 00:00:00 2001 From: Steven Grimm Date: Mon, 16 Apr 2007 00:53:24 -0700 Subject: [PATCH 34/60] Add --ignore-unmatch option to exit with zero status when no files are removed. Signed-off-by: Steven Grimm Signed-off-by: Junio C Hamano --- Documentation/git-rm.txt | 5 ++++- builtin-rm.c | 21 +++++++++++++++++---- t/t3600-rm.sh | 4 ++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt index b051ccb6d6..a65f24a0f6 100644 --- a/Documentation/git-rm.txt +++ b/Documentation/git-rm.txt @@ -7,7 +7,7 @@ git-rm - Remove files from the working tree and from the index SYNOPSIS -------- -'git-rm' [-f] [-n] [-r] [--cached] [--] ... +'git-rm' [-f] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] ... DESCRIPTION ----------- @@ -47,6 +47,9 @@ OPTIONS the paths only from the index, leaving working tree files. +\--ignore-unmatch:: + Exit with a zero status even if no files matched. + \--quiet:: git-rm normally outputs one line (in the form of an "rm" command) for each file removed. This option suppresses that output. diff --git a/builtin-rm.c b/builtin-rm.c index b77b058e38..4a0bd93c8b 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -10,7 +10,7 @@ #include "tree-walk.h" static const char builtin_rm_usage[] = -"git-rm [-f] [-n] [-r] [--cached] [--quiet] [--] ..."; +"git-rm [-f] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] ..."; static struct { int nr, alloc; @@ -105,6 +105,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) { int i, newfd; int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0; + int ignore_unmatch = 0; const char **pathspec; char *seen; @@ -134,6 +135,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix) recursive = 1; else if (!strcmp(arg, "--quiet")) quiet = 1; + else if (!strcmp(arg, "--ignore-unmatch")) + ignore_unmatch = 1; else usage(builtin_rm_usage); } @@ -155,14 +158,24 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (pathspec) { const char *match; + int seen_any = 0; for (i = 0; (match = pathspec[i]) != NULL ; i++) { - if (!seen[i]) - die("pathspec '%s' did not match any files", - match); + if (!seen[i]) { + if (!ignore_unmatch) { + die("pathspec '%s' did not match any files", + match); + } + } + else { + seen_any = 1; + } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die("not removing '%s' recursively without -r", *match ? match : "."); } + + if (! seen_any) + exit(0); } /* diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index da9da92180..0a97b75288 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -84,6 +84,10 @@ test_expect_success \ 'When the rm in "git-rm -f" fails, it should not remove the file from the index' \ 'git-ls-files --error-unmatch baz' +test_expect_success 'Remove nonexistent file with --ignore-unmatch' ' + git rm --ignore-unmatch nonexistent +' + test_expect_success '"rm" command printed' ' echo frotz > test-file && git add test-file && From d627de6b13138257dac3fcb4d7778d8afdcab974 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 15 Apr 2007 03:01:29 -0700 Subject: [PATCH 35/60] git-svn: respect lower bound of -r/--revision when following parent When an explicit --revision argument is specified, do not fetch past the specified range into the beginning of history. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/git-svn.perl b/git-svn.perl index ac44f60b81..7ebd07b793 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1682,7 +1682,10 @@ sub find_parent_branch { } my ($r0, $parent) = $gs->find_rev_before($r, 1); if (!defined $r0 || !defined $parent) { - $gs->fetch(0, $r); + my ($base, $head) = parse_revision_argument(0, $r); + if ($base <= $r) { + $gs->fetch($base, $r); + } ($r0, $parent) = $gs->last_rev_commit; } if (defined $r0 && defined $parent) { From c284914a7c6646ddf999d3df7924b10f06ac6979 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 17 Apr 2007 02:41:43 -0700 Subject: [PATCH 36/60] git-svn: quiet some warnings when run only with --version/--help These are harmless but annoying. They were introduced in 512b620bd9fef7f170562ecad835e37479f051ce Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index 7ebd07b793..4d3c453bf2 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -168,14 +168,14 @@ for (my $i = 0; $i < @ARGV; $i++) { my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd); read_repo_config(\%opts); -Getopt::Long::Configure('pass_through') if $cmd eq 'log'; +Getopt::Long::Configure('pass_through') if ($cmd && $cmd eq 'log'); my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version, 'minimize-connections' => \$Git::SVN::Migration::_minimize, 'id|i=s' => \$Git::SVN::default_ref_id, 'svn-remote|remote|R=s' => sub { $Git::SVN::no_reuse_existing = 1; $Git::SVN::default_repo_id = $_[1] }); -exit 1 if (!$rv && $cmd ne 'log'); +exit 1 if (!$rv && $cmd && $cmd ne 'log'); usage(0) if $_help; version() if $_version; From 69dd97a430d3deebbcade1d38c53110342440890 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 17 Apr 2007 13:15:56 -0400 Subject: [PATCH 37/60] Revert "Allow wish interpreter to be defined with TCLTK_PATH" This reverts commit e2a1bc67d321a0c03737179f331c39a52e7049d7. Junio rightly pointed out this patch doesn't handle the `make install` target very well: Junio C Hamano writes: > You should never generate new files in the source tree from > 'install' target. Otherwise, the usual pattern of "make" as > yourself and then "make install" as root would not work from a > "root-to-nobody-squashing" NFS mounted source tree to local > filesystem. You should know better than accepting such a patch. --- Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile b/Makefile index 2316b24e00..b82789ead6 100644 --- a/Makefile +++ b/Makefile @@ -28,8 +28,6 @@ ifndef V QUIET_BUILT_IN = @echo ' ' BUILTIN $@; endif -TCLTK_PATH ?= wish - ifeq ($(findstring $(MAKEFLAGS),s),s) QUIET_GEN = QUIET_BUILT_IN = @@ -57,7 +55,6 @@ all:: $(ALL_PROGRAMS) install: all $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' - sed -i .bak -e'1,3s|^exec .* "$$0"|exec '"$(TCLTK_PATH)"' "$$0"|' git-gui && rm git-gui.bak $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) From 845d377b2880a0c5d74f785244469ab1ac815bde Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 17 Apr 2007 03:31:47 -0700 Subject: [PATCH 38/60] git-gui: Honor TCLTK_PATH if supplied Mimick what we do for gitk. Since you do have a source file, git-gui.sh, which is separate from the target, it should be much easier in git-gui's Makefile. Signed-off-by: Junio C Hamano Signed-off-by: Shawn O. Pearce --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index b82789ead6..b29d7d1e68 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,8 @@ ifndef V QUIET_BUILT_IN = @echo ' ' BUILTIN $@; endif +TCLTK_PATH ?= wish + ifeq ($(findstring $(MAKEFLAGS),s),s) QUIET_GEN = QUIET_BUILT_IN = @@ -36,10 +38,12 @@ endif DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) +TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)rm -f $@ $@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ + -e 's|^exec wish "$$0"|exec $(subst |,'\|',$(TCLTK_PATH_SQ)) "$$0"|' \ -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \ $@.sh >$@+ && \ chmod +x $@+ && \ From ab6029415b7e8acbc1beff7363c74bb94c3f0d9d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 17 Apr 2007 17:32:23 -0700 Subject: [PATCH 39/60] Start preparing for 1.5.1.2 --- Documentation/RelNotes-1.5.1.2.txt | 37 ++++++++++++++++++++++++++++++ RelNotes | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 Documentation/RelNotes-1.5.1.2.txt diff --git a/Documentation/RelNotes-1.5.1.2.txt b/Documentation/RelNotes-1.5.1.2.txt new file mode 100644 index 0000000000..f58268f6be --- /dev/null +++ b/Documentation/RelNotes-1.5.1.2.txt @@ -0,0 +1,37 @@ +GIT v1.5.1.2 Release Notes (draft) +========================== + +Fixes since v1.5.1.1 +-------------------- + +* Bugfixes + + - "git diff a/ b/" incorrectly fell in "diff between two + filesystem objects" codepath, when the user most likely + wanted to limit the extent of output to two tracked + directories. + + - git-quiltimport had the same bug as we fixed for + git-applymbox in v1.5.1.1 -- it gave an alarming "did not + have any patch" message (but did not actually fail and was + harmless). + + - various git-svn fixes. + + - Sample update hook incorrectly always refused requests to + delete branches through push. + + - git-blame on a very long working tree path had buffer + overrun problem. + +* Documentation updates + + - Various documentation updates from J. Bruce Fields, Frank + Lichtenheld, Alex Riesen and others. Andrew Ruder started a + war on undocumented options. + +--- +exec >/var/tmp/1 +O=v1.5.1.1-31-g0220f1e +echo O=`git describe refs/heads/maint` +git shortlog --no-merges $O..refs/heads/maint diff --git a/RelNotes b/RelNotes index 59e7391e0f..09f5a7413c 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes-1.5.1.1.txt \ No newline at end of file +Documentation/RelNotes-1.5.1.2.txt \ No newline at end of file From 2c7801bdd194f33879d32bd109031ee3bf7eb632 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 17 Apr 2007 18:03:00 -0700 Subject: [PATCH 40/60] Update draft release notes for 1.5.2 with accumulated changes. Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.2.txt | 45 +++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes-1.5.2.txt b/Documentation/RelNotes-1.5.2.txt index 2e3c7bc4f1..d93da608c7 100644 --- a/Documentation/RelNotes-1.5.2.txt +++ b/Documentation/RelNotes-1.5.2.txt @@ -9,6 +9,14 @@ Updates since v1.5.1 - "git bisect start" can optionally take a single bad commit and zero or more good commits on the command line. + - "git shortlog" can optionally be told to wrap its output. + + - "subtree" merge strategy allows another project to be merged in as + your subdirectory. + + - "git format-patch" learned a new --subject-prefix= + option, to override the built-in "[PATCH]". + * Updated behavior of existing commands. - "git diff --stat" shows size of preimage and postimage blobs @@ -27,6 +35,12 @@ Updates since v1.5.1 the root commit). We used to refuse to operate without a good and a bad commit. + - "git push", when pushing into more than one repository, does + not stop at the first error. + + - "git archive" does not insist you to give --format parameter + anymore; it defaults to "tar". + * Builds - git-p4import has never been installed; now there is an @@ -55,8 +69,30 @@ The following are all in v1.5.1.x series, unless otherwise noted. * Documentation updates + - Various documentation updates from J. Bruce Fields, Frank + Lichtenheld, Alex Riesen and others. Andrew Ruder started a + war on undocumented options. + * Bugfixes + - "git diff a/ b/" incorrectly fell in "diff between two + filesystem objects" codepath, when the user most likely + wanted to limit the extent of output to two tracked + directories. + + - git-quiltimport had the same bug as we fixed for + git-applymbox in v1.5.1.1 -- it gave an alarming "did not + have any patch" message (but did not actually fail and was + harmless). + + - various git-svn fixes. + + - Sample update hook incorrectly always refused requests to + delete branches through push. + + - git-blame on a very long working tree path had buffer + overrun problem. + - Switching branches with "git checkout" refused to work when a path changes from a file to a directory between the current branch and the new branch, in order not to lose @@ -67,10 +103,17 @@ The following are all in v1.5.1.x series, unless otherwise noted. been backported to 1.5.1.x series, as it is rather an intrusive change. + - Merging branches that have a file in one and a directory in + another at the same path used to get quite confused. We + handle such a case a bit more carefully, even though that is + still left as a conflict for the user to sort out. This + will not be backported to 1.5.1.x series, as it is rather an + intrusive change. + * Performance Tweaks -- exec >/var/tmp/1 -O=v1.5.1-91-g640ee0d +O=v1.5.1.1-158-g86da9de echo O=`git describe refs/heads/master` git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint From 1401f46bb42d1eb6225a5e08543c06a5b18fd3b7 Mon Sep 17 00:00:00 2001 From: Carlos Rica Date: Wed, 18 Apr 2007 05:34:34 +0200 Subject: [PATCH 41/60] Use const qualifier for 'sha1' parameter in delete_ref function delete_ref function does not change the 'sha1' parameter. Non-const pointer causes a compiler warning if you call to the function using a const argument. Signed-off-by: Carlos Rica Signed-off-by: Junio C Hamano --- cache.h | 2 +- refs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cache.h b/cache.h index 1904131f27..7cedda684f 100644 --- a/cache.h +++ b/cache.h @@ -213,7 +213,7 @@ struct lock_file { extern int hold_lock_file_for_update(struct lock_file *, const char *path, int); extern int commit_lock_file(struct lock_file *); extern void rollback_lock_file(struct lock_file *); -extern int delete_ref(const char *, unsigned char *sha1); +extern int delete_ref(const char *, const unsigned char *sha1); /* Environment bits from configuration mechanism */ extern int use_legacy_headers; diff --git a/refs.c b/refs.c index d2b7b7fb56..d7be2841c5 100644 --- a/refs.c +++ b/refs.c @@ -705,7 +705,7 @@ static int repack_without_ref(const char *refname) return commit_lock_file(&packlock); } -int delete_ref(const char *refname, unsigned char *sha1) +int delete_ref(const char *refname, const unsigned char *sha1) { struct ref_lock *lock; int err, i, ret = 0, flag = 0; From 0c1ec5a1f769021ebe96dfff493c561921dbba52 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 18 Apr 2007 00:17:33 -0700 Subject: [PATCH 42/60] git-svn: don't allow globs to match regular files git only tracks the histories of full directories, not that of individual files. Sometimes, SVN users will place[1] a regular file in the directory designated for subdirectories of branches or tags. Thanks to jrockway on #git for pointing this out. [1] mistakenly or otherwise, such as a README Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.1.1.txt | 4 ++++ git-svn.perl | 2 ++ 2 files changed, 6 insertions(+) diff --git a/Documentation/RelNotes-1.5.1.1.txt b/Documentation/RelNotes-1.5.1.1.txt index 3054b5a3f0..91471213bd 100644 --- a/Documentation/RelNotes-1.5.1.1.txt +++ b/Documentation/RelNotes-1.5.1.1.txt @@ -59,3 +59,7 @@ Fixes since v1.5.1 - git-svn dcommit and rebase was confused by patches that were merged from another branch that is managed by git-svn. + + - git-svn used to get confused when globbing remote branch/tag + spec (e.g. "branches = proj/branches/*:refs/remotes/origin/*") + is used and there was a plain file that matched the glob. diff --git a/git-svn.perl b/git-svn.perl index 4d3c453bf2..efc4c88a4e 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3162,6 +3162,8 @@ sub match_globs { my $p = $1; my $pathname = $g->{path}->full_path($p); next if $exists->{$pathname}; + next if ($self->check_path($pathname, $r) != + $SVN::Node::dir); $exists->{$pathname} = Git::SVN->init( $self->{url}, $pathname, undef, $g->{ref}->full_path($p), 1); From 0afa7644f2f3543a033d327468ab97d7581f9d13 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 18 Apr 2007 23:58:56 +0200 Subject: [PATCH 43/60] Fix overwriting of files when applying contextually independent diffs Noticed by applying two diffs of different contexts to the same file. The check for existence of a file was wrong: the test assumed it was a directory and reset the errno (twice: directly and by calling lstat). So if an entry existed and was _not_ a directory no attempt was made to rename into it, because the errno (expected by renaming code) was already reset to 0. This resulted in error: fatal: unable to write file file mode 100644 For Linux, removing "errno = 0" is enough, as lstat wont modify errno if it was successful. The behavior should not be depended upon, though, so modify the "if" as well. The test simulates this situation. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-apply.c | 3 +-- t/t4121-apply-diffs.sh | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100755 t/t4121-apply-diffs.sh diff --git a/builtin-apply.c b/builtin-apply.c index a5d612655f..db52722455 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2416,8 +2416,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned * used to be. */ struct stat st; - errno = 0; - if (!lstat(path, &st) && S_ISDIR(st.st_mode) && !rmdir(path)) + if (!lstat(path, &st) && (!S_ISDIR(st.st_mode) || !rmdir(path))) errno = EEXIST; } diff --git a/t/t4121-apply-diffs.sh b/t/t4121-apply-diffs.sh new file mode 100755 index 0000000000..2b2f1eda21 --- /dev/null +++ b/t/t4121-apply-diffs.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +test_description='git-apply for contextually independent diffs' +. ./test-lib.sh + +echo '1 +2 +3 +4 +5 +6 +7 +8' >file + +test_expect_success 'setup' \ + 'git add file && + git commit -q -m 1 && + git checkout -b test && + mv file file.tmp && + echo 0 >file && + cat file.tmp >>file && + rm file.tmp && + git commit -a -q -m 2 && + echo 9 >>file && + git commit -a -q -m 3 && + git checkout master' + +test_expect_success \ + 'check if contextually independent diffs for the same file apply' \ + '( git diff test~2 test~1; git diff test~1 test~0 )| git apply' + +test_done + From 0ad64fd0b8d073e0c73836858a54f693c9191918 Mon Sep 17 00:00:00 2001 From: Frank Lichtenheld Date: Thu, 19 Apr 2007 00:10:22 +0200 Subject: [PATCH 44/60] git-shortlog: Fix two formatting errors in asciidoc documentation First use [verse] in the SYNOPSIS so that the line break actually shows. Secondly drop the quotes around '.mailmap' since this exposes a bug in our toolchain (didn't bother enough yet to find out wether it is asciidoc's fault or that of the XSL templates) that leads to the dot not getting escaped correctly in the roff output and thereby swallowing the line. Signed-off-by: Frank Lichtenheld Signed-off-by: Junio C Hamano --- Documentation/git-shortlog.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index b0df92e819..1c8c55ef6e 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -7,6 +7,7 @@ git-shortlog - Summarize 'git log' output SYNOPSIS -------- +[verse] git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] git-shortlog [-n|--number] [-s|--summary] [...] @@ -33,7 +34,8 @@ OPTIONS FILES ----- -'.mailmap':: + +.mailmap:: If this file exists, it will be used for mapping author email addresses to a real author name. One mapping per line, first the author name followed by the email address enclosed by From 9f1beb7140584b3eb803cc9a69cbced528209f6e Mon Sep 17 00:00:00 2001 From: Sam Vilain Date: Thu, 19 Apr 2007 11:51:21 +1200 Subject: [PATCH 45/60] git-tar-tree: complete deprecation conversion message The syntax for git-archive is different; warn about it in the deprecation message on the manual page. Signed-off-by: Junio C Hamano --- Documentation/git-tar-tree.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-tar-tree.txt b/Documentation/git-tar-tree.txt index 595940524e..7bde73b1b8 100644 --- a/Documentation/git-tar-tree.txt +++ b/Documentation/git-tar-tree.txt @@ -13,7 +13,7 @@ SYNOPSIS DESCRIPTION ----------- THIS COMMAND IS DEPRECATED. Use `git-archive` with `--format=tar` -option instead. +option instead (and move the argument to `--prefix=base/`). Creates a tar archive containing the tree structure for the named tree. When is specified it is added as a leading path to the files in the From 6e6db39afc305e1205a4d2dcf34680bfa80bfc24 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Thu, 19 Apr 2007 03:08:15 +0100 Subject: [PATCH 46/60] fix up strtoul_ui error handling Two scanf() calls were converted to strtoul_ui() but the return values were not updated to match. scanf() returns the number of matched "values" which for this usage is 1 on success. strtoul_ui() return 0 on success. Update these call sites to match. Signed-off-by: Andy Whitcroft Signed-off-by: Junio C Hamano --- builtin-update-index.c | 2 +- convert-objects.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-update-index.c b/builtin-update-index.c index 6ed61ebc57..8659800eec 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -551,7 +551,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (i+3 >= argc) die("git-update-index: --cacheinfo "); - if ((strtoul_ui(argv[i+1], 8, &mode) != 1) || + if (strtoul_ui(argv[i+1], 8, &mode) || get_sha1_hex(argv[i+2], sha1) || add_cacheinfo(mode, sha1, argv[i+3], 0)) die("git-update-index: --cacheinfo" diff --git a/convert-objects.c b/convert-objects.c index cf03bcfe5a..cefbcebdca 100644 --- a/convert-objects.c +++ b/convert-objects.c @@ -88,7 +88,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base unsigned int mode; char *slash, *origpath; - if (!path || strtoul_ui(buffer, 8, &mode) != 1) + if (!path || strtoul_ui(buffer, 8, &mode)) die("bad tree conversion"); mode = convert_mode(mode); path++; From 27c8f8cda42b9e47dc18e94152b28472488bef1c Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 18 Apr 2007 22:03:14 -0500 Subject: [PATCH 47/60] Update git-archive documentation Documentation/git-archive.txt: Document -v/--verbose option. Add -l as short form of --list. Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-archive.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index 493474b2ee..59dfabed23 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -32,9 +32,12 @@ OPTIONS --format=:: Format of the resulting archive: 'tar', 'zip'... ---list:: +--list, -l:: Show all available formats. +--verbose, -v:: + Report progress to stderr. + --prefix=/:: Prepend / to each filename in the archive. From 6b04600a34a89241e7b1eb344667c8146a5dc99e Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 18 Apr 2007 22:03:26 -0500 Subject: [PATCH 48/60] Update git-cherry-pick documentation Documentation/git-cherry-pick.txt: Remove --replay as it is not handled by the code (-r is however). Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-cherry-pick.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 3149d08da8..68bba98260 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -38,7 +38,7 @@ OPTIONS development branch), adding this information can be useful. --r|--replay:: +-r:: It used to be that the command defaulted to do `-x` described above, and `-r` was to disable it. Now the default is not to do `-x` so this option is a no-op. From c91ee2714ecd01594cf2feef57157098dc486590 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 18 Apr 2007 22:03:31 -0500 Subject: [PATCH 49/60] Fix unmatched emphasis tag in git-tutorial In asciidoc 7.1.2 and prior there is no obvious way to get: 'add'ing to emphasize only the "add", instead it treats the first apostrophe as the beginning of an emphasis, and the second apostrophe as a regular apostrophe and makes the rest of the line an emphasis since there is no closing apostrophe. In the newer asciidoc you can do it pretty easily with __add__ing but I'm not sure it would be best to make that a prereq for something as silly as this. Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/tutorial.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt index 129c5c5f5b..e978562d6e 100644 --- a/Documentation/tutorial.txt +++ b/Documentation/tutorial.txt @@ -111,7 +111,7 @@ make it real. Note: don't forget to 'add' a file again if you modified it after the first 'add' and before 'commit'. Otherwise only the previous added state of that file will be committed. This is because git tracks -content, so what you're really 'add'ing to the commit is the *content* +content, so what you're really 'adding' to the commit is the *content* of the file in the state it is in when you 'add' it. 2) By using 'git commit -a' directly From 9bc20aa73152784ee758f6432e20820e581c9412 Mon Sep 17 00:00:00 2001 From: Andrew Ruder Date: Wed, 18 Apr 2007 22:03:37 -0500 Subject: [PATCH 50/60] Update git-config documentation Documentation/git-config.txt: Added documentation for --system Documentation/builtin-config.c: Added --system to the short usage Signed-off-by: Andrew Ruder Signed-off-by: Junio C Hamano --- Documentation/git-config.txt | 24 ++++++++++++++---------- builtin-config.c | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index c759efb7fc..280ef2058c 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -9,16 +9,16 @@ git-config - Get and set repository or global options SYNOPSIS -------- [verse] -'git-config' [--global] [type] name [value [value_regex]] -'git-config' [--global] [type] --add name value -'git-config' [--global] [type] --replace-all name [value [value_regex]] -'git-config' [--global] [type] --get name [value_regex] -'git-config' [--global] [type] --get-all name [value_regex] -'git-config' [--global] [type] --unset name [value_regex] -'git-config' [--global] [type] --unset-all name [value_regex] -'git-config' [--global] [type] --rename-section old_name new_name -'git-config' [--global] [type] --remove-section name -'git-config' [--global] -l | --list +'git-config' [--system | --global] [type] name [value [value_regex]] +'git-config' [--system | --global] [type] --add name value +'git-config' [--system | --global] [type] --replace-all name [value [value_regex]] +'git-config' [--system | --global] [type] --get name [value_regex] +'git-config' [--system | --global] [type] --get-all name [value_regex] +'git-config' [--system | --global] [type] --unset name [value_regex] +'git-config' [--system | --global] [type] --unset-all name [value_regex] +'git-config' [--system | --global] [type] --rename-section old_name new_name +'git-config' [--system | --global] [type] --remove-section name +'git-config' [--system | --global] -l | --list DESCRIPTION ----------- @@ -76,6 +76,10 @@ OPTIONS --global:: Use global ~/.gitconfig file rather than the repository .git/config. +--system:: + Use system-wide $(prefix)/etc/gitconfig rather than the repository + .git/config. + --remove-section:: Remove the given section from the configuration file. diff --git a/builtin-config.c b/builtin-config.c index dfa403b94b..b2515f7e65 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -2,7 +2,7 @@ #include "cache.h" static const char git_config_set_usage[] = -"git-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list"; +"git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list"; static char *key; static regex_t *key_regexp; From 851c603e9ca9d0954d89be1532d924a28ccb79fa Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 19 Apr 2007 22:48:21 -0700 Subject: [PATCH 51/60] Fix working directory errno handling when unlinking a directory Alex Riesen noticed that the case where a file replaced a directory entry in the working tree was broken on cygwin. It turns out that the code made some Linux-specific assumptions, and also ignored errors entirely for the case where the entry was a symlink rather than a file. This cleans it up by separating out the common case into a function of its own, so that both regular files and symlinks can share it, and by making the error handling more obvious (and not depend on any Linux-specific behaviour). Acked-by: Alex Riesen Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- merge-recursive.c | 54 +++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 595b0226ac..cea6c87717 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -574,6 +574,31 @@ static void flush_buffer(int fd, const char *buf, unsigned long size) } } +static int make_room_for_path(const char *path) +{ + int status; + const char *msg = "failed to create path '%s'%s"; + + status = mkdir_p(path, 0777); + if (status) { + if (status == -3) { + /* something else exists */ + error(msg, path, ": perhaps a D/F conflict?"); + return -1; + } + die(msg, path, ""); + } + + /* Successful unlink is good.. */ + if (!unlink(path)) + return 0; + /* .. and so is no existing file */ + if (errno == ENOENT) + return 0; + /* .. but not some other error (who really cares what?) */ + return error(msg, path, ": perhaps a D/F conflict?"); +} + static void update_file_flags(const unsigned char *sha, unsigned mode, const char *path, @@ -594,33 +619,12 @@ static void update_file_flags(const unsigned char *sha, if (type != OBJ_BLOB) die("blob expected for %s '%s'", sha1_to_hex(sha), path); + if (make_room_for_path(path) < 0) { + update_wd = 0; + goto update_index; + } if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) { int fd; - int status; - const char *msg = "failed to create path '%s'%s"; - - status = mkdir_p(path, 0777); - if (status) { - if (status == -3) { - /* something else exists */ - error(msg, path, ": perhaps a D/F conflict?"); - update_wd = 0; - goto update_index; - } - die(msg, path, ""); - } - if (unlink(path)) { - if (errno == EISDIR) { - /* something else exists */ - error(msg, path, ": perhaps a D/F conflict?"); - update_wd = 0; - goto update_index; - } - if (errno != ENOENT) - die("failed to unlink %s " - "in preparation to update: %s", - path, strerror(errno)); - } if (mode & 0100) mode = 0777; else From 9398e5aa1698cdb518f7118e6f6eeebbea7f5e58 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 20 Apr 2007 02:08:47 -0400 Subject: [PATCH 52/60] Contribute a fairly paranoid update hook I'm using a variant of this update hook in a corporate environment where we perform some validations of the commits and tags that are being pushed. The model is a "central repository" type setup, where users are given access to push to specific branches within the shared central repository. In this particular installation we run a specially patched git-receive-pack in setuid mode via SSH, allowing all writes into the repository as the repository owner, but only if this hook blesses it. One of the major checks we perform with this hook is that the 'committer' line of a commit, or the 'tagger' line of a new annotated tag actually correlates to the UNIX user who is performing the push. Users can falsify these lines on their local repositories, but the central repository that management trusts will reject all such forgery attempts. Of course 'author' lines are still allowed to be any value, as sometimes changes do come from other individuals. Another nice feature of this hook is the access control lists for all repositories on the system can also be stored and tracked in a supporting Git repository, which can also be access controlled by itself. This allows full auditing of who-had-what-when-and-why, thanks to git-blame's data mining capabilities. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- contrib/hooks/update-paranoid | 284 ++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 contrib/hooks/update-paranoid diff --git a/contrib/hooks/update-paranoid b/contrib/hooks/update-paranoid new file mode 100644 index 0000000000..5ee1835c80 --- /dev/null +++ b/contrib/hooks/update-paranoid @@ -0,0 +1,284 @@ +#!/usr/bin/perl + +use strict; +use File::Spec; + +$ENV{PATH} = '/opt/git/bin'; +my $acl_git = '/vcs/acls.git'; +my $acl_branch = 'refs/heads/master'; +my $debug = 0; + +=doc +Invoked as: update refname old-sha1 new-sha1 + +This script is run by git-receive-pack once for each ref that the +client is trying to modify. If we exit with a non-zero exit value +then the update for that particular ref is denied, but updates for +other refs in the same run of receive-pack may still be allowed. + +We are run after the objects have been uploaded, but before the +ref is actually modified. We take advantage of that fact when we +look for "new" commits and tags (the new objects won't show up in +`rev-list --all`). + +This script loads and parses the content of the config file +"users/$this_user.acl" from the $acl_branch commit of $acl_git ODB. +The acl file is a git-config style file, but uses a slightly more +restricted syntax as the Perl parser contained within this script +is not nearly as permissive as git-config. + +Example: + + [user] + committer = John Doe + committer = John R. Doe + + [repository "acls"] + allow = heads/master + allow = CDUR for heads/jd/ + allow = C for ^tags/v\\d+$ + +For all new commit or tag objects the committer (or tagger) line +within the object must exactly match one of the user.committer +values listed in the acl file ("HEAD:users/$this_user.acl"). + +For a branch to be modified an allow line within the matching +repository section must be matched for both the refname and the +opcode. + +Repository sections are matched on the basename of the repository +(after removing the .git suffix). + +The opcode abbrevations are: + + C: create new ref + D: delete existing ref + U: fast-forward existing ref (no commit loss) + R: rewind/rebase existing ref (commit loss) + +if no opcodes are listed before the "for" keyword then "U" (for +fast-forward update only) is assumed as this is the most common +usage. + +Refnames are matched by always assuming a prefix of "refs/". +This hook forbids pushing or deleting anything not under "refs/". + +Refnames that start with ^ are Perl regular expressions, and the ^ +is kept as part of the regexp. \\ is needed to get just one \, so +\\d expands to \d in Perl. The 3rd allow line above is an example. + +Refnames that don't start with ^ but that end with / are prefix +matches (2nd allow line above); all other refnames are strict +equality matches (1st allow line). + +Anything pushed to "heads/" (ok, really "refs/heads/") must be +a commit. Tags are not permitted here. + +Anything pushed to "tags/" (err, really "refs/tags/") must be an +annotated tag. Commits, blobs, trees, etc. are not permitted here. +Annotated tag signatures aren't checked, nor are they required. + +The special subrepository of 'info/new-commit-check' can +be created and used to allow users to push new commits and +tags from another local repository to this one, even if they +aren't the committer/tagger of those objects. In a nut shell +the info/new-commit-check directory is a Git repository whose +objects/info/alternates file lists this repository and all other +possible sources, and whose refs subdirectory contains symlinks +to this repository's refs subdirectory, and to all other possible +sources refs subdirectories. Yes, this means that you cannot +use packed-refs in those repositories as they won't be resolved +correctly. + +=cut + +my $git_dir = $ENV{GIT_DIR}; +my $new_commit_check = "$git_dir/info/new-commit-check"; +my $ref = $ARGV[0]; +my $old = $ARGV[1]; +my $new = $ARGV[2]; +my $new_type; +my ($this_user) = getpwuid $<; # REAL_USER_ID +my $repository_name; +my %user_committer; +my @allow_rules; + +sub deny ($) { + print STDERR "-Deny- $_[0]\n" if $debug; + print STDERR "\ndenied: $_[0]\n\n"; + exit 1; +} + +sub grant ($) { + print STDERR "-Grant- $_[0]\n" if $debug; + exit 0; +} + +sub info ($) { + print STDERR "-Info- $_[0]\n" if $debug; +} + +sub parse_config ($$) { + my ($data, $fn) = @_; + info "Loading $fn"; + open(I,'-|','git',"--git-dir=$acl_git",'cat-file','blob',$fn); + my $section = ''; + while () { + chomp; + if (/^\s*$/ || /^\s*#/) { + } elsif (/^\[([a-z]+)\]$/i) { + $section = $1; + } elsif (/^\[([a-z]+)\s+"(.*)"\]$/i) { + $section = "$1.$2"; + } elsif (/^\s*([a-z][a-z0-9]+)\s*=\s*(.*?)\s*$/i) { + push @{$data->{"$section.$1"}}, $2; + } else { + deny "bad config file line $. in $fn"; + } + } + close I; +} + +sub all_new_committers () { + local $ENV{GIT_DIR} = $git_dir; + $ENV{GIT_DIR} = $new_commit_check if -d $new_commit_check; + + info "Getting committers of new commits."; + my %used; + open(T,'-|','git','rev-list','--pretty=raw',$new,'--not','--all'); + while () { + next unless s/^committer //; + chop; + s/>.*$/>/; + info "Found $_." unless $used{$_}++; + } + close T; + info "No new commits." unless %used; + keys %used; +} + +sub all_new_taggers () { + my %exists; + open(T,'-|','git','for-each-ref','--format=%(objectname)','refs/tags'); + while () { + chop; + $exists{$_} = 1; + } + close T; + + info "Getting taggers of new tags."; + my %used; + my $obj = $new; + my $obj_type = $new_type; + while ($obj_type eq 'tag') { + last if $exists{$obj}; + $obj_type = ''; + open(T,'-|','git','cat-file','tag',$obj); + while () { + chop; + if (/^object ([a-z0-9]{40})$/) { + $obj = $1; + } elsif (/^type (.+)$/) { + $obj_type = $1; + } elsif (s/^tagger //) { + s/>.*$/>/; + info "Found $_." unless $used{$_}++; + last; + } + } + close T; + } + info "No new tags." unless %used; + keys %used; +} + +sub check_committers (@) { + my @bad; + foreach (@_) { push @bad, $_ unless $user_committer{$_}; } + if (@bad) { + print STDERR "\n"; + print STDERR "You are not $_.\n" foreach (sort @bad); + deny "You cannot push changes not committed by you."; + } +} + +sub git_value (@) { + open(T,'-|','git',@_); local $_ = ; chop; close T; + $_; +} + +deny "No GIT_DIR inherited from caller" unless $git_dir; +deny "Need a ref name" unless $ref; +deny "Refusing funny ref $ref" unless $ref =~ s,^refs/,,; +deny "Bad old value $old" unless $old =~ /^[a-z0-9]{40}$/; +deny "Bad new value $new" unless $new =~ /^[a-z0-9]{40}$/; +deny "Cannot determine who you are." unless $this_user; + +$repository_name = File::Spec->rel2abs($git_dir); +$repository_name =~ m,/([^/]+)(?:\.git|/\.git)$,; +$repository_name = $1; +info "Updating in '$repository_name'."; + +my $op; +if ($old =~ /^0{40}$/) { $op = 'C'; } +elsif ($new =~ /^0{40}$/) { $op = 'D'; } +else { $op = 'R'; } + +# This is really an update (fast-forward) if the +# merge base of $old and $new is $old. +# +$op = 'U' if ($op eq 'R' + && $ref =~ m,^heads/, + && $old eq git_value('merge-base',$old,$new)); + +# Load the user's ACL file. +{ + my %data = ('user.committer' => []); + parse_config(\%data, "$acl_branch:users/$this_user.acl"); + %user_committer = map {$_ => $_} @{$data{'user.committer'}}; + my $rules = $data{"repository.$repository_name.allow"} || []; + foreach (@$rules) { + if (/^([CDRU ]+)\s+for\s+([^\s]+)$/) { + my $ops = $1; + my $ref = $2; + $ops =~ s/ //g; + $ref =~ s/\\\\/\\/g; + push @allow_rules, [$ops, $ref]; + } elsif (/^for\s+([^\s]+)$/) { + # Mentioned, but nothing granted? + } elsif (/^[^\s]+$/) { + s/\\\\/\\/g; + push @allow_rules, ['U', $_]; + } + } +} + +if ($op ne 'D') { + $new_type = git_value('cat-file','-t',$new); + + if ($ref =~ m,^heads/,) { + deny "$ref must be a commit." unless $new_type eq 'commit'; + } elsif ($ref =~ m,^tags/,) { + deny "$ref must be an annotated tag." unless $new_type eq 'tag'; + } + + check_committers (all_new_committers); + check_committers (all_new_taggers) if $new_type eq 'tag'; +} + +info "$this_user wants $op for $ref"; +foreach my $acl_entry (@allow_rules) { + my ($acl_ops, $acl_n) = @$acl_entry; + next unless $acl_ops =~ /^[CDRU]+$/; # Uhh.... shouldn't happen. + next unless $acl_n; + next unless $op =~ /^[$acl_ops]$/; + + grant "Allowed by: $acl_ops for $acl_n" + if ( + ($acl_n eq $ref) + || ($acl_n =~ m,/$, && substr($ref,0,length $acl_n) eq $acl_n) + || ($acl_n =~ m,^\^, && $ref =~ m:$acl_n:) + ); +} +close A; +deny "You are not permitted to $op $ref"; From 413689d36f9b98c57bff9510ac4cdfb40e4ef9fc Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 19 Apr 2007 13:16:58 +0200 Subject: [PATCH 53/60] git.el: Add a commit description to the reflog. Add a description of the commit to the reflog using the first line of the log message, the same way the git-commit script does it. Signed-off-by: Alexandre Julliard Signed-off-by: Junio C Hamano --- contrib/emacs/git.el | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 2f9995ea39..f60017948f 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -345,9 +345,15 @@ and returns the process output as a string." (let ((str (git-call-process-env-string nil "symbolic-ref" ref))) (and str (car (split-string str "\n"))))) -(defun git-update-ref (ref val &optional oldval) +(defun git-update-ref (ref newval &optional oldval reason) "Update a reference by calling git-update-ref." - (apply #'git-call-process-env nil nil "update-ref" ref val (if oldval (list oldval)))) + (let ((args (and oldval (list oldval)))) + (push newval args) + (push ref args) + (when reason + (push reason args) + (push "-m" args)) + (eq 0 (apply #'git-call-process-env nil nil "update-ref" args)))) (defun git-read-tree (tree &optional index-file) "Read a tree into the index file." @@ -364,8 +370,10 @@ and returns the process output as a string." "Call git-commit-tree with buffer as input and return the resulting commit SHA1." (let ((author-name (git-get-committer-name)) (author-email (git-get-committer-email)) + (subject "commit (initial): ") author-date log-start log-end args coding-system-for-write) (when head + (setq subject "commit: ") (push "-p" args) (push head args)) (with-current-buffer buffer @@ -384,22 +392,29 @@ and returns the process output as a string." (goto-char (point-min)) (while (re-search-forward "^Parent: +\\([0-9a-f]+\\)" nil t) (unless (string-equal head (match-string 1)) + (setq subject "commit (merge): ") (push "-p" args) (push (match-string 1) args)))) (setq log-start (point-min))) (setq log-end (point-max)) + (goto-char log-start) + (when (re-search-forward ".*$" nil t) + (setq subject (concat subject (match-string 0)))) (setq coding-system-for-write buffer-file-coding-system)) - (git-get-string-sha1 - (with-output-to-string - (with-current-buffer standard-output - (let ((env `(("GIT_AUTHOR_NAME" . ,author-name) - ("GIT_AUTHOR_EMAIL" . ,author-email) - ("GIT_COMMITTER_NAME" . ,(git-get-committer-name)) - ("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email))))) - (when author-date (push `("GIT_AUTHOR_DATE" . ,author-date) env)) - (apply #'git-run-command-region - buffer log-start log-end env - "commit-tree" tree (nreverse args)))))))) + (let ((commit + (git-get-string-sha1 + (with-output-to-string + (with-current-buffer standard-output + (let ((env `(("GIT_AUTHOR_NAME" . ,author-name) + ("GIT_AUTHOR_EMAIL" . ,author-email) + ("GIT_COMMITTER_NAME" . ,(git-get-committer-name)) + ("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email))))) + (when author-date (push `("GIT_AUTHOR_DATE" . ,author-date) env)) + (apply #'git-run-command-region + buffer log-start log-end env + "commit-tree" tree (nreverse args)))))))) + (and (git-update-ref "HEAD" commit head subject) + commit)))) (defun git-empty-db-p () "Check if the git db is empty (no commit done yet)." @@ -662,7 +677,6 @@ and returns the process output as a string." (if (or (not (string-equal tree head-tree)) (yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? ")) (let ((commit (git-commit-tree buffer tree head))) - (git-update-ref "HEAD" commit head) (condition-case nil (delete-file ".git/MERGE_HEAD") (error nil)) (condition-case nil (delete-file ".git/MERGE_MSG") (error nil)) (with-current-buffer buffer (erase-buffer)) From 744747ef1d75c85fb3a1785cb08d36497128d3d3 Mon Sep 17 00:00:00 2001 From: Brian Gernhardt Date: Thu, 19 Apr 2007 00:51:06 -0400 Subject: [PATCH 54/60] Remove case-sensitive file in t3030-merge-recursive. Rename "A" to the unused "c" Signed-off-by: Brian Gernhardt Signed-off-by: Junio C Hamano --- t/t3030-merge-recursive.sh | 104 ++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index aef92b9b92..86ee2b0bd3 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -9,12 +9,12 @@ test_expect_success 'setup 1' ' echo hello >a && o0=$(git hash-object a) && cp a b && - cp a A && + cp a c && mkdir d && cp a d/e && test_tick && - git add a b A d/e && + git add a b c d/e && git commit -m initial && c0=$(git rev-parse --verify HEAD) && git branch side && @@ -34,13 +34,13 @@ test_expect_success 'setup 1' ' c1=$(git rev-parse --verify HEAD) && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o1 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o1 d/e" - echo "100644 $o0 0 A" echo "100644 $o1 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual @@ -48,17 +48,17 @@ test_expect_success 'setup 1' ' test_expect_success 'setup 2' ' - rm -rf [Aabd] && + rm -rf [abcd] && git checkout side && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o0 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o0 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual && @@ -73,13 +73,13 @@ test_expect_success 'setup 2' ' c2=$(git rev-parse --verify HEAD) && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o2 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o2 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual @@ -87,17 +87,17 @@ test_expect_success 'setup 2' ' test_expect_success 'setup 3' ' - rm -rf [Aabd] && + rm -rf [abcd] && git checkout df-1 && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o0 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o0 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual && @@ -110,13 +110,13 @@ test_expect_success 'setup 3' ' c3=$(git rev-parse --verify HEAD) && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o0 a" echo "100644 blob $o3 b/c" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o0 0 a" echo "100644 $o3 0 b/c" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual @@ -124,17 +124,17 @@ test_expect_success 'setup 3' ' test_expect_success 'setup 4' ' - rm -rf [Aabd] && + rm -rf [abcd] && git checkout df-2 && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o0 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o0 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual && @@ -147,13 +147,13 @@ test_expect_success 'setup 4' ' c4=$(git rev-parse --verify HEAD) && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o4 a/c" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o4 0 a/c" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual @@ -161,17 +161,17 @@ test_expect_success 'setup 4' ' test_expect_success 'setup 5' ' - rm -rf [Aabd] && + rm -rf [abcd] && git checkout remove && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o0 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o0 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual && @@ -188,11 +188,11 @@ test_expect_success 'setup 5' ' c5=$(git rev-parse --verify HEAD) && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o5 a" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o5 0 a" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual @@ -201,17 +201,17 @@ test_expect_success 'setup 5' ' test_expect_success 'setup 6' ' - rm -rf [Aabd] && + rm -rf [abcd] && git checkout df-3 && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o0 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o0 d/e" - echo "100644 $o0 0 A" echo "100644 $o0 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o0 0 d/e" ) >expected && git diff -u expected actual && @@ -224,13 +224,13 @@ test_expect_success 'setup 6' ' c6=$(git rev-parse --verify HEAD) && ( git ls-tree -r HEAD ; git ls-files -s ) >actual && ( - echo "100644 blob $o0 A" echo "100644 blob $o0 a" echo "100644 blob $o0 b" + echo "100644 blob $o0 c" echo "100644 blob $o6 d" - echo "100644 $o0 0 A" echo "100644 $o0 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o6 0 d" ) >expected && git diff -u expected actual @@ -238,7 +238,7 @@ test_expect_success 'setup 6' ' test_expect_success 'merge-recursive simple' ' - rm -fr [Aabd] && + rm -fr [abcd] && git checkout -f "$c2" && git-merge-recursive "$c0" -- "$c2" "$c1" @@ -258,11 +258,11 @@ test_expect_success 'merge-recursive result' ' git ls-files -s >actual && ( - echo "100644 $o0 0 A" echo "100644 $o0 1 a" echo "100644 $o2 2 a" echo "100644 $o1 3 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual @@ -271,7 +271,7 @@ test_expect_success 'merge-recursive result' ' test_expect_success 'merge-recursive remove conflict' ' - rm -fr [Aabd] && + rm -fr [abcd] && git checkout -f "$c1" && git-merge-recursive "$c0" -- "$c1" "$c5" @@ -291,10 +291,10 @@ test_expect_success 'merge-recursive remove conflict' ' git ls-files -s >actual && ( - echo "100644 $o0 0 A" echo "100644 $o0 1 a" echo "100644 $o1 2 a" echo "100644 $o5 3 a" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual @@ -302,7 +302,7 @@ test_expect_success 'merge-recursive remove conflict' ' ' test_expect_success 'merge-recursive d/f simple' ' - rm -fr [Aabd] && + rm -fr [abcd] && git reset --hard && git checkout -f "$c1" && @@ -313,9 +313,9 @@ test_expect_success 'merge-recursive result' ' git ls-files -s >actual && ( - echo "100644 $o0 0 A" echo "100644 $o1 0 a" echo "100644 $o3 0 b/c" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual @@ -324,7 +324,7 @@ test_expect_success 'merge-recursive result' ' test_expect_success 'merge-recursive d/f conflict' ' - rm -fr [Aabd] && + rm -fr [abcd] && git reset --hard && git checkout -f "$c1" && @@ -345,11 +345,11 @@ test_expect_success 'merge-recursive d/f conflict result' ' git ls-files -s >actual && ( - echo "100644 $o0 0 A" echo "100644 $o0 1 a" echo "100644 $o1 2 a" echo "100644 $o4 0 a/c" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual @@ -358,7 +358,7 @@ test_expect_success 'merge-recursive d/f conflict result' ' test_expect_success 'merge-recursive d/f conflict the other way' ' - rm -fr [Aabd] && + rm -fr [abcd] && git reset --hard && git checkout -f "$c4" && @@ -379,11 +379,11 @@ test_expect_success 'merge-recursive d/f conflict result the other way' ' git ls-files -s >actual && ( - echo "100644 $o0 0 A" echo "100644 $o0 1 a" echo "100644 $o1 3 a" echo "100644 $o4 0 a/c" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual @@ -392,7 +392,7 @@ test_expect_success 'merge-recursive d/f conflict result the other way' ' test_expect_success 'merge-recursive d/f conflict' ' - rm -fr [Aabd] && + rm -fr [abcd] && git reset --hard && git checkout -f "$c1" && @@ -413,9 +413,9 @@ test_expect_success 'merge-recursive d/f conflict result' ' git ls-files -s >actual && ( - echo "100644 $o0 0 A" echo "100644 $o1 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o6 3 d" echo "100644 $o0 1 d/e" echo "100644 $o1 2 d/e" @@ -426,7 +426,7 @@ test_expect_success 'merge-recursive d/f conflict result' ' test_expect_success 'merge-recursive d/f conflict' ' - rm -fr [Aabd] && + rm -fr [abcd] && git reset --hard && git checkout -f "$c6" && @@ -447,9 +447,9 @@ test_expect_success 'merge-recursive d/f conflict result' ' git ls-files -s >actual && ( - echo "100644 $o0 0 A" echo "100644 $o1 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o6 2 d" echo "100644 $o0 1 d/e" echo "100644 $o1 3 d/e" @@ -471,13 +471,13 @@ test_expect_success 'reset and bind merge' ' git read-tree --prefix=M/ master && git ls-files -s >actual && ( - echo "100644 $o0 0 A" - echo "100644 $o0 0 M/A" echo "100644 $o1 0 M/a" echo "100644 $o0 0 M/b" + echo "100644 $o0 0 M/c" echo "100644 $o1 0 M/d/e" echo "100644 $o1 0 a" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual && @@ -485,17 +485,17 @@ test_expect_success 'reset and bind merge' ' git read-tree --prefix=a1/ master && git ls-files -s >actual && ( - echo "100644 $o0 0 A" - echo "100644 $o0 0 M/A" echo "100644 $o1 0 M/a" echo "100644 $o0 0 M/b" + echo "100644 $o0 0 M/c" echo "100644 $o1 0 M/d/e" echo "100644 $o1 0 a" - echo "100644 $o0 0 a1/A" echo "100644 $o1 0 a1/a" echo "100644 $o0 0 a1/b" + echo "100644 $o0 0 a1/c" echo "100644 $o1 0 a1/d/e" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" ) >expected && git diff -u expected actual @@ -503,21 +503,21 @@ test_expect_success 'reset and bind merge' ' git read-tree --prefix=z/ master && git ls-files -s >actual && ( - echo "100644 $o0 0 A" - echo "100644 $o0 0 M/A" echo "100644 $o1 0 M/a" echo "100644 $o0 0 M/b" + echo "100644 $o0 0 M/c" echo "100644 $o1 0 M/d/e" echo "100644 $o1 0 a" - echo "100644 $o0 0 a1/A" echo "100644 $o1 0 a1/a" echo "100644 $o0 0 a1/b" + echo "100644 $o0 0 a1/c" echo "100644 $o1 0 a1/d/e" echo "100644 $o0 0 b" + echo "100644 $o0 0 c" echo "100644 $o1 0 d/e" - echo "100644 $o0 0 z/A" echo "100644 $o1 0 z/a" echo "100644 $o0 0 z/b" + echo "100644 $o0 0 z/c" echo "100644 $o1 0 z/d/e" ) >expected && git diff -u expected actual From ad57cbca61afc921349ddb9e884ceee5bf2322a8 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 20 Apr 2007 02:37:18 -0400 Subject: [PATCH 55/60] Kill the useless progress meter in merge-recursive The mess known as the progress meter in merge-recursive was my own fault; I put it in thinking that we might be spending a lot of time resolving unmerged entries in the index that were not handled by the simple 3-way index merge code. Turns out we don't really spend that much time there, so the progress meter was pretty much always jumping to "(n/n) 100%" as soon as the program started. That isn't a very good indication of progress. Since I don't have a great solution for how a progress meter should work here, I'm proposing we back it out entirely. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- merge-recursive.c | 65 +++-------------------------------------------- 1 file changed, 3 insertions(+), 62 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index cea6c87717..31e66e5ca3 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -95,11 +95,6 @@ static struct path_list current_directory_set = {NULL, 0, 0, 1}; static int call_depth = 0; static int verbosity = 2; static int buffer_output = 1; -static int do_progress = 1; -static unsigned last_percent; -static unsigned merged_cnt; -static unsigned total_cnt; -static volatile sig_atomic_t progress_update; static struct output_buffer *output_list, *output_end; static int show (int v) @@ -174,39 +169,6 @@ static void output_commit_title(struct commit *commit) } } -static void progress_interval(int signum) -{ - progress_update = 1; -} - -static void setup_progress_signal(void) -{ - struct sigaction sa; - struct itimerval v; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = progress_interval; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGALRM, &sa, NULL); - - v.it_interval.tv_sec = 1; - v.it_interval.tv_usec = 0; - v.it_value = v.it_interval; - setitimer(ITIMER_REAL, &v, NULL); -} - -static void display_progress() -{ - unsigned percent = total_cnt ? merged_cnt * 100 / total_cnt : 0; - if (progress_update || percent != last_percent) { - fprintf(stderr, "%4u%% (%u/%u) done\r", - percent, merged_cnt, total_cnt); - progress_update = 0; - last_percent = percent; - } -} - static struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh) { @@ -377,14 +339,11 @@ static struct path_list *get_unmerged(void) int i; unmerged->strdup_paths = 1; - total_cnt += active_nr; - for (i = 0; i < active_nr; i++, merged_cnt++) { + for (i = 0; i < active_nr; i++) { struct path_list_item *item; struct stage_data *e; struct cache_entry *ce = active_cache[i]; - if (do_progress) - display_progress(); if (!ce_stage(ce)) continue; @@ -1218,15 +1177,12 @@ static int merge_trees(struct tree *head, re_merge = get_renames(merge, common, head, merge, entries); clean = process_renames(re_head, re_merge, branch1, branch2); - total_cnt += entries->nr; - for (i = 0; i < entries->nr; i++, merged_cnt++) { + for (i = 0; i < entries->nr; i++) { const char *path = entries->items[i].path; struct stage_data *e = entries->items[i].util; if (!e->processed && !process_entry(path, e, branch1, branch2)) clean = 0; - if (do_progress) - display_progress(); } path_list_clear(re_merge, 0); @@ -1334,15 +1290,6 @@ static int merge(struct commit *h1, commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); } - if (!call_depth && do_progress) { - /* Make sure we end at 100% */ - if (!total_cnt) - total_cnt = 1; - merged_cnt = total_cnt; - progress_update = 1; - display_progress(); - fputc('\n', stderr); - } flush_output(); return clean; } @@ -1419,12 +1366,8 @@ int main(int argc, char *argv[]) } if (argc - i != 3) /* "--" "" "" */ die("Not handling anything other than two heads merge."); - if (verbosity >= 5) { + if (verbosity >= 5) buffer_output = 0; - do_progress = 0; - } - else - do_progress = isatty(1); branch1 = argv[++i]; branch2 = argv[++i]; @@ -1435,8 +1378,6 @@ int main(int argc, char *argv[]) branch1 = better_branch_name(branch1); branch2 = better_branch_name(branch2); - if (do_progress) - setup_progress_signal(); if (show(3)) printf("Merging %s with %s\n", branch1, branch2); From 2c9750cc8b902a55669183e05533207dd7ec71fd Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 19 Apr 2007 22:26:03 +0530 Subject: [PATCH 56/60] gitview: annotation support List files modifed as a part of the commit in the diff window Support annotation of the file listed in the diff window Support history browsing in the annotation window. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Junio C Hamano --- contrib/gitview/gitview | 260 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 256 insertions(+), 4 deletions(-) diff --git a/contrib/gitview/gitview b/contrib/gitview/gitview index 521b2fcd32..2d80e2bad2 100755 --- a/contrib/gitview/gitview +++ b/contrib/gitview/gitview @@ -10,7 +10,8 @@ GUI browser for git repository This program is based on bzrk by Scott James Remnant """ __copyright__ = "Copyright (C) 2006 Hewlett-Packard Development Company, L.P." -__author__ = "Aneesh Kumar K.V " +__copyright__ = "Copyright (C) 2007 Aneesh Kumar K.V 0): + # set at result_line + count-1 the sha1 as commit_sha1 + self.count = self.count - 1 + iter = self.model.iter_nth_child(None, self.result_line + self.count-1) + self.model.set(iter, 0, self.commit_sha1, 1, filename, 3, self.source_line) + + + def annotate(self, filename, commit_sha1, line_num): + # verify the commit_sha1 specified has this filename + + fp = os.popen("git ls-tree "+ commit_sha1 + " -- " + filename) + line = string.strip(fp.readline()) + if line == '': + # pop up the message the file is not there as a part of the commit + fp.close() + dialog = gtk.MessageDialog(parent=None, flags=0, + type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_CLOSE, + message_format=None) + dialog.set_markup("The file %s is not present in the parent commit %s" % (filename, commit_sha1)) + dialog.run() + dialog.destroy() + return + + fp.close() + + vpan = gtk.VPaned(); + self.window.add(vpan); + vpan.show() + + scrollwin = gtk.ScrolledWindow() + scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrollwin.set_shadow_type(gtk.SHADOW_IN) + vpan.pack1(scrollwin, True, True); + scrollwin.show() + + self.model = gtk.TreeStore(str, str, str, int) + self.treeview = gtk.TreeView(self.model) + self.treeview.set_rules_hint(True) + self.treeview.set_search_column(0) + self.treeview.connect("cursor-changed", self._treeview_cursor_cb) + self.treeview.connect("row-activated", self._treeview_row_activated) + scrollwin.add(self.treeview) + self.treeview.show() + + cell = gtk.CellRendererText() + cell.set_property("width-chars", 10) + cell.set_property("ellipsize", pango.ELLIPSIZE_END) + column = gtk.TreeViewColumn("Commit") + column.set_resizable(True) + column.pack_start(cell, expand=True) + column.add_attribute(cell, "text", 0) + self.treeview.append_column(column) + + cell = gtk.CellRendererText() + cell.set_property("width-chars", 20) + cell.set_property("ellipsize", pango.ELLIPSIZE_END) + column = gtk.TreeViewColumn("File Name") + column.set_resizable(True) + column.pack_start(cell, expand=True) + column.add_attribute(cell, "text", 1) + self.treeview.append_column(column) + + cell = gtk.CellRendererText() + cell.set_property("width-chars", 20) + cell.set_property("ellipsize", pango.ELLIPSIZE_END) + column = gtk.TreeViewColumn("Data") + column.set_resizable(True) + column.pack_start(cell, expand=True) + column.add_attribute(cell, "text", 2) + self.treeview.append_column(column) + + # The commit message window + scrollwin = gtk.ScrolledWindow() + scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrollwin.set_shadow_type(gtk.SHADOW_IN) + vpan.pack2(scrollwin, True, True); + scrollwin.show() + + commit_text = gtk.TextView() + self.commit_buffer = gtk.TextBuffer() + commit_text.set_buffer(self.commit_buffer) + scrollwin.add(commit_text) + commit_text.show() + + self.window.show() + + self.add_file_data(filename, commit_sha1, line_num) + + fp = os.popen("git blame --incremental -- " + filename + " " + commit_sha1) + flags = fcntl.fcntl(fp.fileno(), fcntl.F_GETFL) + fcntl.fcntl(fp.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK) + self.io_watch_tag = gobject.io_add_watch(fp, gobject.IO_IN, self.data_ready) + + class DiffWindow: """Diff window. This object represents and manages a single window containing the @@ -355,6 +537,7 @@ class DiffWindow: height = int(monitor.height * 0.66) self.window.set_default_size(width, height) + self.construct() def construct(self): @@ -371,10 +554,12 @@ class DiffWindow: vbox.pack_start(menu_bar, expand=False, fill=True) menu_bar.show() + hpan = gtk.HPaned() + scrollwin = gtk.ScrolledWindow() scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrollwin.set_shadow_type(gtk.SHADOW_IN) - vbox.pack_start(scrollwin, expand=True, fill=True) + hpan.pack1(scrollwin, True, True) scrollwin.show() if have_gtksourceview: @@ -388,11 +573,77 @@ class DiffWindow: self.buffer = gtk.TextBuffer() sourceview = gtk.TextView(self.buffer) + sourceview.set_editable(False) sourceview.modify_font(pango.FontDescription("Monospace")) scrollwin.add(sourceview) sourceview.show() + # The file hierarchy: a scrollable treeview + scrollwin = gtk.ScrolledWindow() + scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrollwin.set_shadow_type(gtk.SHADOW_IN) + scrollwin.set_size_request(20, -1) + hpan.pack2(scrollwin, True, True) + scrollwin.show() + + self.model = gtk.TreeStore(str, str, str) + self.treeview = gtk.TreeView(self.model) + self.treeview.set_search_column(1) + self.treeview.connect("cursor-changed", self._treeview_clicked) + scrollwin.add(self.treeview) + self.treeview.show() + + cell = gtk.CellRendererText() + cell.set_property("width-chars", 20) + column = gtk.TreeViewColumn("Select to annotate") + column.pack_start(cell, expand=True) + column.add_attribute(cell, "text", 0) + self.treeview.append_column(column) + + vbox.pack_start(hpan, expand=True, fill=True) + hpan.show() + + def _treeview_clicked(self, *args): + """Callback for when the treeview cursor changes.""" + (path, col) = self.treeview.get_cursor() + specific_file = self.model[path][1] + commit_sha1 = self.model[path][2] + if specific_file == None : + return + elif specific_file == "" : + specific_file = None + + window = AnnotateWindow(); + window.annotate(specific_file, commit_sha1, 1) + + + def commit_files(self, commit_sha1, parent_sha1): + self.model.clear() + add = self.model.append(None, [ "Added", None, None]) + dele = self.model.append(None, [ "Deleted", None, None]) + mod = self.model.append(None, [ "Modified", None, None]) + diff_tree = re.compile('^(:.{6}) (.{6}) (.{40}) (.{40}) (A|D|M)\s(.+)$') + fp = os.popen("git diff-tree -r --no-commit-id " + parent_sha1 + " " + commit_sha1) + while 1: + line = string.strip(fp.readline()) + if line == '': + break + m = diff_tree.match(line) + if not m: + continue + + attr = m.group(5) + filename = m.group(6) + if attr == "A": + self.model.append(add, [filename, filename, commit_sha1]) + elif attr == "D": + self.model.append(dele, [filename, filename, commit_sha1]) + elif attr == "M": + self.model.append(mod, [filename, filename, commit_sha1]) + fp.close() + + self.treeview.expand_all() def set_diff(self, commit_sha1, parent_sha1, encoding): """Set the differences showed by this window. @@ -406,6 +657,7 @@ class DiffWindow: fp = os.popen("git diff-tree -p " + parent_sha1 + " " + commit_sha1) self.buffer.set_text(unicode(fp.read(), encoding).encode('utf-8')) fp.close() + self.commit_files(commit_sha1, parent_sha1) self.window.show() def save_menu_response(self, widget, string): @@ -425,7 +677,7 @@ class DiffWindow: class GitView: """ This is the main class """ - version = "0.8" + version = "0.9" def __init__(self, with_diff=0): self.with_diff = with_diff @@ -590,7 +842,7 @@ class GitView: dialog = gtk.AboutDialog() dialog.set_name("Gitview") dialog.set_version(GitView.version) - dialog.set_authors(["Aneesh Kumar K.V "]) + dialog.set_authors(["Aneesh Kumar K.V "]) dialog.set_website("http://www.kernel.org/pub/software/scm/git/") dialog.set_copyright("Use and distribute under the terms of the GNU General Public License") dialog.set_wrap_license(True) From 928c210a47fb7e38c56744bb14570638e6c23d7f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 20 Apr 2007 17:25:27 -0700 Subject: [PATCH 57/60] git-clone: fix dumb protocol transport to clone from pack-pruned ref This forward-ports a fix from 2986c022 to git-clone. Signed-off-by: Junio C Hamano --- git-clone.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-clone.sh b/git-clone.sh index 513b574d13..cad5c0c088 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -60,7 +60,7 @@ Perhaps git-update-server-info needs to be run there?" else tname=$name fi - git-http-fetch $v -a -w "$tname" "$name" "$1" || exit 1 + git-http-fetch $v -a -w "$tname" "$sha1" "$1" || exit 1 done <"$clone_tmp/refs" rm -fr "$clone_tmp" http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" || From 2a1a3dce3333950d16f78caf34b3bb2ac46ab4d4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Apr 2007 18:30:06 -0700 Subject: [PATCH 58/60] Fix a copy-n-paste bug in the object decorator code. Duh. When I did the object decorator thing, I made the "loop over the hash" function use the same logic for updating the hash, ie made them use if (++j >= size) j = 0; for both the hash update for both "insert" and "lookup" HOWEVER. For some inexplicable reason I had an extraneous j++; in the insert path (probably just from the fact that the old code there used j++; if (j >= size) j = 0; and when I made them use the same logic I just didn't remove the old extraneous line properly. This fixes it. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- decorate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/decorate.c b/decorate.c index 396b41311a..23f6b0040f 100644 --- a/decorate.c +++ b/decorate.c @@ -24,7 +24,6 @@ static void *insert_decoration(struct decoration *n, struct object *base, void * hash[j].decoration = decoration; return old; } - j++; if (++j >= size) j = 0; } From 4a40cbd949d81863375a10e320f74c8fc595d05e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 21 Apr 2007 00:55:00 -0700 Subject: [PATCH 59/60] perl: install private Error.pm if the site version is older than our own bdash (on IRC) had a problem with Git.pm (via git-svn) when his site installation of Error.pm was older than the version we package. Signed-off-by: Eric Wong Signed-off-by: Junio C Hamano --- perl/Makefile.PL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perl/Makefile.PL b/perl/Makefile.PL index 9b117fd0d7..437516142c 100644 --- a/perl/Makefile.PL +++ b/perl/Makefile.PL @@ -13,7 +13,7 @@ my %pm = ('Git.pm' => '$(INST_LIBDIR)/Git.pm'); # We come with our own bundled Error.pm. It's not in the set of default # Perl modules so install it if it's not available on the system yet. eval { require Error }; -if ($@) { +if ($@ || $Error::VERSION < 0.15009) { $pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm'; } From 97317061c6799765c7f2f83d8e3f4f74df469793 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 21 Apr 2007 13:57:07 -0700 Subject: [PATCH 60/60] GIT 1.5.1.2 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.1.2.txt | 27 ++++++++++++++++++++------- GIT-VERSION-GEN | 2 +- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Documentation/RelNotes-1.5.1.2.txt b/Documentation/RelNotes-1.5.1.2.txt index f58268f6be..d88456306c 100644 --- a/Documentation/RelNotes-1.5.1.2.txt +++ b/Documentation/RelNotes-1.5.1.2.txt @@ -1,4 +1,4 @@ -GIT v1.5.1.2 Release Notes (draft) +GIT v1.5.1.2 Release Notes ========================== Fixes since v1.5.1.1 @@ -6,6 +6,11 @@ Fixes since v1.5.1.1 * Bugfixes + - "git clone" over http from a repository that has lost the + loose refs by running "git pack-refs" were broken (a code to + deal with this was added to "git fetch" in v1.5.0, but it + was missing from "git clone"). + - "git diff a/ b/" incorrectly fell in "diff between two filesystem objects" codepath, when the user most likely wanted to limit the extent of output to two tracked @@ -24,14 +29,22 @@ Fixes since v1.5.1.1 - git-blame on a very long working tree path had buffer overrun problem. + - git-apply did not like to be fed two patches in a row that created + and then modified the same file. + + - git-svn was confused when a non-project was stored directly under + trunk/, branches/ and tags/. + + - git-svn wants the Error.pm module that was at least as new + as what we ship as part of git; install ours in our private + installation location if the one on the system is older. + + - An earlier update to command line integer parameter parser was + botched and made 'update-index --cacheinfo' completely useless. + + * Documentation updates - Various documentation updates from J. Bruce Fields, Frank Lichtenheld, Alex Riesen and others. Andrew Ruder started a war on undocumented options. - ---- -exec >/var/tmp/1 -O=v1.5.1.1-31-g0220f1e -echo O=`git describe refs/heads/maint` -git shortlog --no-merges $O..refs/heads/maint diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 2325660ff4..41ee8b4ea2 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.5.1.1.GIT +DEF_VER=v1.5.1.2.GIT LF=' '