From e1a7c81f6a8c5a96a3d07632514f85d9470c3a82 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 18 Jul 2006 01:52:14 +1000 Subject: gitk: Minor cleanups Removed some unnecessary quotes and globals, updated copyright notice. Signed-off-by: Paul Mackerras --- gitk | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/gitk b/gitk index 7d540c1b05..7b86c1916a 100755 --- a/gitk +++ b/gitk @@ -2,7 +2,7 @@ # Tcl ignores the next line -*- tcl -*- \ exec wish "$0" -- "$@" -# Copyright (C) 2005 Paul Mackerras. All rights reserved. +# Copyright (C) 2005-2006 Paul Mackerras. All rights reserved. # This program is free software; it may be used, copied, modified # and distributed under the terms of the GNU General Public Licence, # either version 2, or (at your option) any later version. @@ -341,13 +341,13 @@ proc readrefs {} { set tag {} catch { set commit [exec git rev-parse "$id^0"] - if {"$commit" != "$id"} { + if {$commit != $id} { set tagids($name) $commit lappend idtags($commit) $name } } catch { - set tagcontents($name) [exec git cat-file tag "$id"] + set tagcontents($name) [exec git cat-file tag $id] } } elseif { $type == "heads" } { set headids($name) $id @@ -3263,8 +3263,7 @@ proc show_status {msg} { proc finishcommits {} { global commitidx phase curview - global canv mainfont ctext maincursor textcursor - global findinprogress pending_select + global pending_select if {$commitidx($curview) > 0} { drawrest @@ -3307,9 +3306,7 @@ proc notbusy {what} { } proc drawrest {} { - global numcommits global startmsecs - global canvy0 numcommits linespc global rowlaidout commitidx curview global pending_select @@ -3323,6 +3320,7 @@ proc drawrest {} { } set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}] + #global numcommits #puts "overall $drawmsecs ms for $numcommits commits" } -- cgit v1.2.1 From cec7bece83a42918457819b526c49c7d55f795c5 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 2 Aug 2006 09:38:10 +1000 Subject: gitk: Recompute ancestor/descendent heads/tags when rereading refs We weren't updating the desc_heads, desc_tags and anc_tags arrays when rereading the set of heads/tags/etc. The tricky thing to get right here is restarting the computation correctly when we are only half-way through it. Signed-off-by: Paul Mackerras --- gitk | 132 +++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 47 deletions(-) diff --git a/gitk b/gitk index 7b86c1916a..1f0a2e6ec6 100755 --- a/gitk +++ b/gitk @@ -4932,7 +4932,7 @@ proc domktag {} { proc redrawtags {id} { global canv linehtag commitrow idpos selectedline curview - global mainfont + global mainfont canvxmax if {![info exists commitrow($curview,$id)]} return drawcmitrow $commitrow($curview,$id) @@ -5020,8 +5020,9 @@ proc wrcomcan {} { # Stuff for finding nearby tags proc getallcommits {} { - global allcstart allcommits allcfd + global allcstart allcommits allcfd allids + set allids {} set fd [open [concat | git rev-list --all --topo-order --parents] r] set allcfd $fd fconfigure $fd -blocking 0 @@ -5105,10 +5106,52 @@ proc combine_atags {l1 l2} { return $res } +proc forward_pass {id children} { + global idtags desc_tags idheads desc_heads alldtags tagisdesc + + set dtags {} + set dheads {} + foreach child $children { + if {[info exists idtags($child)]} { + set ctags [list $child] + } else { + set ctags $desc_tags($child) + } + if {$dtags eq {}} { + set dtags $ctags + } elseif {$ctags ne $dtags} { + set dtags [combine_dtags $dtags $ctags] + } + set cheads $desc_heads($child) + if {$dheads eq {}} { + set dheads $cheads + } elseif {$cheads ne $dheads} { + set dheads [lsort -unique [concat $dheads $cheads]] + } + } + set desc_tags($id) $dtags + if {[info exists idtags($id)]} { + set adt $dtags + foreach tag $dtags { + set adt [concat $adt $alldtags($tag)] + } + set adt [lsort -unique $adt] + set alldtags($id) $adt + foreach tag $adt { + set tagisdesc($id,$tag) -1 + set tagisdesc($tag,$id) 1 + } + } + if {[info exists idheads($id)]} { + lappend dheads $id + } + set desc_heads($id) $dheads +} + proc getallclines {fd} { global allparents allchildren allcommits allcstart - global desc_tags anc_tags idtags alldtags tagisdesc allids - global desc_heads idheads + global desc_tags anc_tags idtags tagisdesc allids + global desc_heads idheads travindex while {[gets $fd line] >= 0} { set id [lindex $line 0] @@ -5123,43 +5166,7 @@ proc getallclines {fd} { } # compute nearest tagged descendents as we go # also compute descendent heads - set dtags {} - set dheads {} - foreach child $allchildren($id) { - if {[info exists idtags($child)]} { - set ctags [list $child] - } else { - set ctags $desc_tags($child) - } - if {$dtags eq {}} { - set dtags $ctags - } elseif {$ctags ne $dtags} { - set dtags [combine_dtags $dtags $ctags] - } - set cheads $desc_heads($child) - if {$dheads eq {}} { - set dheads $cheads - } elseif {$cheads ne $dheads} { - set dheads [lsort -unique [concat $dheads $cheads]] - } - } - set desc_tags($id) $dtags - if {[info exists idtags($id)]} { - set adt $dtags - foreach tag $dtags { - set adt [concat $adt $alldtags($tag)] - } - set adt [lsort -unique $adt] - set alldtags($id) $adt - foreach tag $adt { - set tagisdesc($id,$tag) -1 - set tagisdesc($tag,$id) 1 - } - } - if {[info exists idheads($id)]} { - lappend dheads $id - } - set desc_heads($id) $dheads + forward_pass $id $allchildren($id) if {[clock clicks -milliseconds] - $allcstart >= 50} { fileevent $fd readable {} after idle restartgetall $fd @@ -5167,7 +5174,9 @@ proc getallclines {fd} { } } if {[eof $fd]} { - after idle restartatags [llength $allids] + set travindex [llength $allids] + set allcommits "traversing" + after idle restartatags if {[catch {close $fd} err]} { error_popup "Error reading full commit graph: $err.\n\ Results may be incomplete." @@ -5176,10 +5185,11 @@ proc getallclines {fd} { } # walk backward through the tree and compute nearest tagged ancestors -proc restartatags {i} { - global allids allparents idtags anc_tags t0 +proc restartatags {} { + global allids allparents idtags anc_tags travindex set t0 [clock clicks -milliseconds] + set i $travindex while {[incr i -1] >= 0} { set id [lindex $allids $i] set atags {} @@ -5197,17 +5207,41 @@ proc restartatags {i} { } set anc_tags($id) $atags if {[clock clicks -milliseconds] - $t0 >= 50} { - after idle restartatags $i + set travindex $i + after idle restartatags return } } set allcommits "done" + set travindex 0 notbusy allcommits dispneartags } +proc changedrefs {} { + global desc_heads desc_tags anc_tags allcommits allids + global allchildren allparents idtags travindex + + if {![info exists allcommits]} return + catch {unset desc_heads} + catch {unset desc_tags} + catch {unset anc_tags} + catch {unset alldtags} + catch {unset tagisdesc} + foreach id $allids { + forward_pass $id $allchildren($id) + } + if {$allcommits ne "reading"} { + set travindex [llength $allids] + if {$allcommits ne "traversing"} { + set allcommits "traversing" + after idle restartatags + } + } +} + proc rereadrefs {} { - global idtags idheads idotherrefs + global idtags idheads idotherrefs mainhead set refids [concat [array names idtags] \ [array names idheads] [array names idotherrefs]] @@ -5216,12 +5250,16 @@ proc rereadrefs {} { set ref($id) [listrefs $id] } } + set oldmainhead $mainhead readrefs + changedrefs set refids [lsort -unique [concat $refids [array names idtags] \ [array names idheads] [array names idotherrefs]]] foreach id $refids { set v [listrefs $id] - if {![info exists ref($id)] || $ref($id) != $v} { + if {![info exists ref($id)] || $ref($id) != $v || + ($id eq $oldmainhead && $id ne $mainhead) || + ($id eq $mainhead && $id ne $oldmainhead)} { redrawtags $id } } -- cgit v1.2.1 From d6ac1a86e932fdb48705b9b1b6e2849aaea9ad24 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 2 Aug 2006 09:41:04 +1000 Subject: gitk: Add a row context-menu item for creating a new branch Signed-off-by: Paul Mackerras --- gitk | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/gitk b/gitk index 1f0a2e6ec6..61106f2d37 100755 --- a/gitk +++ b/gitk @@ -711,6 +711,7 @@ proc makewindow {} { $rowctxmenu add command -label "Make patch" -command mkpatch $rowctxmenu add command -label "Create tag" -command mktag $rowctxmenu add command -label "Write commit to file" -command writecommit + $rowctxmenu add command -label "Create new branch" -command mkbranch } # mouse-2 makes all windows scan vertically, but only the one @@ -5018,6 +5019,61 @@ proc wrcomcan {} { unset wrcomtop } +proc mkbranch {} { + global rowmenuid mkbrtop + + set top .makebranch + catch {destroy $top} + toplevel $top + label $top.title -text "Create new branch" + grid $top.title - -pady 10 + label $top.id -text "ID:" + entry $top.sha1 -width 40 -relief flat + $top.sha1 insert 0 $rowmenuid + $top.sha1 conf -state readonly + grid $top.id $top.sha1 -sticky w + label $top.nlab -text "Name:" + entry $top.name -width 40 + grid $top.nlab $top.name -sticky w + frame $top.buts + button $top.buts.go -text "Create" -command [list mkbrgo $top] + button $top.buts.can -text "Cancel" -command "catch {destroy $top}" + grid $top.buts.go $top.buts.can + grid columnconfigure $top.buts 0 -weight 1 -uniform a + grid columnconfigure $top.buts 1 -weight 1 -uniform a + grid $top.buts - -pady 10 -sticky ew + focus $top.name +} + +proc mkbrgo {top} { + global headids idheads + + set name [$top.name get] + set id [$top.sha1 get] + if {$name eq {}} { + error_popup "Please specify a name for the new branch" + return + } + catch {destroy $top} + nowbusy newbranch + update + if {[catch { + exec git branch $name $id + } err]} { + notbusy newbranch + error_popup $err + } else { + set headids($name) $id + if {![info exists idheads($id)]} { + addedhead $id + } + lappend idheads($id) $name + # XXX should update list of heads displayed for selected commit + notbusy newbranch + redrawtags $id + } +} + # Stuff for finding nearby tags proc getallcommits {} { global allcstart allcommits allcfd allids @@ -5218,6 +5274,30 @@ proc restartatags {} { dispneartags } +# update the desc_heads array for a new head just added +proc addedhead {hid} { + global desc_heads allparents + + set todo [list $hid] + while {$todo ne {}} { + set do [lindex $todo 0] + set todo [lrange $todo 1 end] + if {![info exists desc_heads($do)] || + [lsearch -exact $desc_heads($do) $hid] >= 0} continue + set oldheads $desc_heads($do) + lappend desc_heads($do) $hid + set heads $desc_heads($do) + while {1} { + set p $allparents($do) + if {[llength $p] != 1 || ![info exists desc_heads($p)] || + $desc_heads($p) ne $oldheads} break + set do $p + set desc_heads($do) $heads + } + set todo [concat $todo $p] + } +} + proc changedrefs {} { global desc_heads desc_tags anc_tags allcommits allids global allchildren allparents idtags travindex -- cgit v1.2.1 From 10299152ca10107a4570764286e129572ed2f3c3 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 2 Aug 2006 09:52:01 +1000 Subject: gitk: Add a context menu for heads This menu allows you to check out a branch and to delete a branch. If you ask to delete a branch that has commits that aren't on any other branch, gitk will prompt for confirmation before doing the deletion. Signed-off-by: Paul Mackerras --- gitk | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/gitk b/gitk index 61106f2d37..fc65cc0f24 100755 --- a/gitk +++ b/gitk @@ -384,6 +384,23 @@ proc error_popup msg { show_error $w $w $msg } +proc confirm_popup msg { + global confirm_ok + set confirm_ok 0 + set w .confirm + toplevel $w + wm transient $w . + message $w.m -text $msg -justify center -aspect 400 + pack $w.m -side top -fill x -padx 20 -pady 20 + button $w.ok -text OK -command "set confirm_ok 1; destroy $w" + pack $w.ok -side left -fill x + button $w.cancel -text Cancel -command "destroy $w" + pack $w.cancel -side right -fill x + bind $w "grab $w; focus $w" + tkwait window $w + return $confirm_ok +} + proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist global textfont mainfont uifont @@ -394,6 +411,7 @@ proc makewindow {} { global highlight_files gdttype global searchstring sstring global bgcolor fgcolor bglist fglist diffcolors + global headctxmenu menu .bar .bar add cascade -label "File" -menu .bar.file @@ -712,6 +730,13 @@ proc makewindow {} { $rowctxmenu add command -label "Create tag" -command mktag $rowctxmenu add command -label "Write commit to file" -command writecommit $rowctxmenu add command -label "Create new branch" -command mkbranch + + set headctxmenu .headctxmenu + menu $headctxmenu -tearoff 0 + $headctxmenu add command -label "Check out this branch" \ + -command cobranch + $headctxmenu add command -label "Remove this branch" \ + -command rmbranch } # mouse-2 makes all windows scan vertically, but only the one @@ -3237,6 +3262,8 @@ proc drawtags {id x xt y1} { -font $font -tags [list tag.$id text]] if {$ntags >= 0} { $canv bind $t <1> [list showtag $tag 1] + } elseif {$nheads >= 0} { + $canv bind $t [list headmenu %X %Y $id $tag] } } return $xt @@ -5074,6 +5101,73 @@ proc mkbrgo {top} { } } +# context menu for a head +proc headmenu {x y id head} { + global headmenuid headmenuhead headctxmenu + + set headmenuid $id + set headmenuhead $head + tk_popup $headctxmenu $x $y +} + +proc cobranch {} { + global headmenuid headmenuhead mainhead headids + + # check the tree is clean first?? + set oldmainhead $mainhead + nowbusy checkout + update + if {[catch { + exec git checkout $headmenuhead + } err]} { + notbusy checkout + error_popup $err + } else { + notbusy checkout + set maainhead $headmenuhead + if {[info exists headids($oldmainhead)]} { + redrawtags $headids($oldmainhead) + } + redrawtags $headmenuid + } +} + +proc rmbranch {} { + global desc_heads headmenuid headmenuhead mainhead + global headids idheads + + set head $headmenuhead + set id $headmenuid + if {$head eq $mainhead} { + error_popup "Cannot delete the currently checked-out branch" + return + } + if {$desc_heads($id) eq $id} { + # the stuff on this branch isn't on any other branch + if {![confirm_popup "The commits on branch $head aren't on any other\ + branch.\nReally delete branch $head?"]} return + } + nowbusy rmbranch + update + if {[catch {exec git branch -D $head} err]} { + notbusy rmbranch + error_popup $err + return + } + unset headids($head) + if {$idheads($id) eq $head} { + unset idheads($id) + removedhead $id + } else { + set i [lsearch -exact $idheads($id) $head] + if {$i >= 0} { + set idheads($id) [lreplace $idheads($id) $i $i] + } + } + redrawtags $id + notbusy rmbranch +} + # Stuff for finding nearby tags proc getallcommits {} { global allcstart allcommits allcfd allids @@ -5298,6 +5392,30 @@ proc addedhead {hid} { } } +# update the desc_heads array for a head just removed +proc removedhead {hid} { + global desc_heads allparents + + set todo [list $hid] + while {$todo ne {}} { + set do [lindex $todo 0] + set todo [lrange $todo 1 end] + if {![info exists desc_heads($do)]} continue + set i [lsearch -exact $desc_heads($do) $hid] + if {$i < 0} continue + set oldheads $desc_heads($do) + set heads [lreplace $desc_heads($do) $i $i] + while {1} { + set desc_heads($do) $heads + set p $allparents($do) + if {[llength $p] != 1 || ![info exists desc_heads($p)] || + $desc_heads($p) ne $oldheads} break + set do $p + } + set todo [concat $todo $p] + } +} + proc changedrefs {} { global desc_heads desc_tags anc_tags allcommits allids global allchildren allparents idtags travindex -- cgit v1.2.1 From 53cda8d97e6ee53cc8defa8c7226f0b3093eb12a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 2 Aug 2006 19:43:34 +1000 Subject: gitk: Fix a couple of buglets in the branch head menu items This fixes a silly typo (an extra a) and fixes the condition for asking for confirmation of removing a branch. Signed-off-by: Paul Mackerras --- gitk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index fc65cc0f24..596f605868 100755 --- a/gitk +++ b/gitk @@ -5124,7 +5124,7 @@ proc cobranch {} { error_popup $err } else { notbusy checkout - set maainhead $headmenuhead + set mainhead $headmenuhead if {[info exists headids($oldmainhead)]} { redrawtags $headids($oldmainhead) } @@ -5142,7 +5142,7 @@ proc rmbranch {} { error_popup "Cannot delete the currently checked-out branch" return } - if {$desc_heads($id) eq $id} { + if {$desc_heads($id) eq $id && $idheads($id) eq [list $head]} { # the stuff on this branch isn't on any other branch if {![confirm_popup "The commits on branch $head aren't on any other\ branch.\nReally delete branch $head?"]} return -- cgit v1.2.1 From ca6d8f58a15b9db621dd2b905a04d06bdff44bf8 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sun, 6 Aug 2006 21:08:05 +1000 Subject: gitk: Add a menu item for cherry-picking commits This does a git-cherry-pick -r to cherry-pick the commit that was right-clicked on to the head of the current branch. This would work better with some minor changes to the git-cherry-pick script. Along the way, this changes desc_heads to record the names of the descendent heads rather than their IDs. Signed-off-by: Paul Mackerras --- gitk | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 210 insertions(+), 43 deletions(-) diff --git a/gitk b/gitk index 596f605868..750a081073 100755 --- a/gitk +++ b/gitk @@ -730,6 +730,8 @@ proc makewindow {} { $rowctxmenu add command -label "Create tag" -command mktag $rowctxmenu add command -label "Write commit to file" -command writecommit $rowctxmenu add command -label "Create new branch" -command mkbranch + $rowctxmenu add command -label "Cherry-pick this commit" \ + -command cherrypick set headctxmenu .headctxmenu menu $headctxmenu -tearoff 0 @@ -3302,6 +3304,104 @@ proc finishcommits {} { catch {unset pending_select} } +# Inserting a new commit as the child of the commit on row $row. +# The new commit will be displayed on row $row and the commits +# on that row and below will move down one row. +proc insertrow {row newcmit} { + global displayorder parentlist childlist commitlisted + global commitrow curview rowidlist rowoffsets numcommits + global rowrangelist idrowranges rowlaidout rowoptim numcommits + global linesegends + + if {$row >= $numcommits} { + puts "oops, inserting new row $row but only have $numcommits rows" + return + } + set p [lindex $displayorder $row] + set displayorder [linsert $displayorder $row $newcmit] + set parentlist [linsert $parentlist $row $p] + set kids [lindex $childlist $row] + lappend kids $newcmit + lset childlist $row $kids + set childlist [linsert $childlist $row {}] + set l [llength $displayorder] + for {set r $row} {$r < $l} {incr r} { + set id [lindex $displayorder $r] + set commitrow($curview,$id) $r + } + + set idlist [lindex $rowidlist $row] + set offs [lindex $rowoffsets $row] + set newoffs {} + foreach x $idlist { + if {$x eq {} || ($x eq $p && [llength $kids] == 1)} { + lappend newoffs {} + } else { + lappend newoffs 0 + } + } + if {[llength $kids] == 1} { + set col [lsearch -exact $idlist $p] + lset idlist $col $newcmit + } else { + set col [llength $idlist] + lappend idlist $newcmit + lappend offs {} + lset rowoffsets $row $offs + } + set rowidlist [linsert $rowidlist $row $idlist] + set rowoffsets [linsert $rowoffsets [expr {$row+1}] $newoffs] + + set rowrangelist [linsert $rowrangelist $row {}] + set l [llength $rowrangelist] + for {set r 0} {$r < $l} {incr r} { + set ranges [lindex $rowrangelist $r] + if {$ranges ne {} && [lindex $ranges end] >= $row} { + set newranges {} + foreach x $ranges { + if {$x >= $row} { + lappend newranges [expr {$x + 1}] + } else { + lappend newranges $x + } + } + lset rowrangelist $r $newranges + } + } + if {[llength $kids] > 1} { + set rp1 [expr {$row + 1}] + set ranges [lindex $rowrangelist $rp1] + if {$ranges eq {}} { + set ranges [list $row $rp1] + } elseif {[lindex $ranges end-1] == $rp1} { + lset ranges end-1 $row + } + lset rowrangelist $rp1 $ranges + } + foreach id [array names idrowranges] { + set ranges $idrowranges($id) + if {$ranges ne {} && [lindex $ranges end] >= $row} { + set newranges {} + foreach x $ranges { + if {$x >= $row} { + lappend newranges [expr {$x + 1}] + } else { + lappend newranges $x + } + } + set idrowranges($id) $newranges + } + } + + set linesegends [linsert $linesegends $row {}] + + incr rowlaidout + incr rowoptim + incr numcommits + + redisplay +} + # Don't change the text pane cursor if it is currently the hand cursor, # showing that we are over a sha1 ID link. proc settextcursor {c} { @@ -3629,27 +3729,20 @@ proc viewnextline {dir} { # add a list of tag or branch names at position pos # returns the number of names inserted -proc appendrefs {pos l var} { - global ctext commitrow linknum curview idtags $var +proc appendrefs {pos tags var} { + global ctext commitrow linknum curview $var if {[catch {$ctext index $pos}]} { return 0 } - set tags {} - foreach id $l { - foreach tag [set $var\($id\)] { - lappend tags [concat $tag $id] - } - } - set tags [lsort -index 1 $tags] + set tags [lsort $tags] set sep {} foreach tag $tags { - set name [lindex $tag 0] - set id [lindex $tag 1] + set id [set $var\($tag\)] set lk link$linknum incr linknum $ctext insert $pos $sep - $ctext insert $pos $name $lk + $ctext insert $pos $tag $lk $ctext tag conf $lk -foreground blue if {[info exists commitrow($curview,$id)]} { $ctext tag bind $lk <1> \ @@ -3663,6 +3756,18 @@ proc appendrefs {pos l var} { return [llength $tags] } +proc taglist {ids} { + global idtags + + set tags {} + foreach id $ids { + foreach tag $idtags($id) { + lappend tags $tag + } + } + return $tags +} + # called when we have finished computing the nearby tags proc dispneartags {} { global selectedline currentid ctext anc_tags desc_tags showneartags @@ -3672,15 +3777,15 @@ proc dispneartags {} { set id $currentid $ctext conf -state normal if {[info exists desc_heads($id)]} { - if {[appendrefs branch $desc_heads($id) idheads] > 1} { + if {[appendrefs branch $desc_heads($id) headids] > 1} { $ctext insert "branch -2c" "es" } } if {[info exists anc_tags($id)]} { - appendrefs follows $anc_tags($id) idtags + appendrefs follows [taglist $anc_tags($id)] tagids } if {[info exists desc_tags($id)]} { - appendrefs precedes $desc_tags($id) idtags + appendrefs precedes [taglist $desc_tags($id)] tagids } $ctext conf -state disabled } @@ -3813,7 +3918,7 @@ proc selectline {l isnew} { $ctext mark set branch "end -1c" $ctext mark gravity branch left if {[info exists desc_heads($id)]} { - if {[appendrefs branch $desc_heads($id) idheads] > 1} { + if {[appendrefs branch $desc_heads($id) headids] > 1} { # turn "Branch" into "Branches" $ctext insert "branch -2c" "es" } @@ -3822,13 +3927,13 @@ proc selectline {l isnew} { $ctext mark set follows "end -1c" $ctext mark gravity follows left if {[info exists anc_tags($id)]} { - appendrefs follows $anc_tags($id) idtags + appendrefs follows [taglist $anc_tags($id)] tagids } $ctext insert end "\nPrecedes: " $ctext mark set precedes "end -1c" $ctext mark gravity precedes left if {[info exists desc_tags($id)]} { - appendrefs precedes $desc_tags($id) idtags + appendrefs precedes [taglist $desc_tags($id)] tagids } $ctext insert end "\n" } @@ -4489,6 +4594,7 @@ proc redisplay {} { drawvisible if {[info exists selectedline]} { selectline $selectedline 0 + allcanvs yview moveto [lindex $span 0] } } @@ -5090,17 +5196,57 @@ proc mkbrgo {top} { notbusy newbranch error_popup $err } else { - set headids($name) $id - if {![info exists idheads($id)]} { - addedhead $id - } - lappend idheads($id) $name + addedhead $id $name # XXX should update list of heads displayed for selected commit notbusy newbranch redrawtags $id } } +proc cherrypick {} { + global rowmenuid curview commitrow + global mainhead desc_heads anc_tags desc_tags allparents allchildren + + if {[info exists desc_heads($rowmenuid)] + && [lsearch -exact $desc_heads($rowmenuid) $mainhead] >= 0} { + set ok [confirm_popup "Commit [string range $rowmenuid 0 7] is already\ + included in branch $mainhead -- really re-apply it?"] + if {!$ok} return + } + nowbusy cherrypick + update + set oldhead [exec git rev-parse HEAD] + # Unfortunately git-cherry-pick writes stuff to stderr even when + # no error occurs, and exec takes that as an indication of error... + if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} { + notbusy cherrypick + error_popup $err + return + } + set newhead [exec git rev-parse HEAD] + if {$newhead eq $oldhead} { + notbusy cherrypick + error_popup "No changes committed" + return + } + set allparents($newhead) $oldhead + lappend allchildren($oldhead) $newhead + set desc_heads($newhead) $mainhead + if {[info exists anc_tags($oldhead)]} { + set anc_tags($newhead) $anc_tags($oldhead) + } + set desc_tags($newhead) {} + if {[info exists commitrow($curview,$oldhead)]} { + insertrow $commitrow($curview,$oldhead) $newhead + if {$mainhead ne {}} { + movedhead $newhead $mainhead + } + redrawtags $oldhead + redrawtags $newhead + } + notbusy cherrypick +} + # context menu for a head proc headmenu {x y id head} { global headmenuid headmenuhead headctxmenu @@ -5142,7 +5288,7 @@ proc rmbranch {} { error_popup "Cannot delete the currently checked-out branch" return } - if {$desc_heads($id) eq $id && $idheads($id) eq [list $head]} { + if {$desc_heads($id) eq $head} { # the stuff on this branch isn't on any other branch if {![confirm_popup "The commits on branch $head aren't on any other\ branch.\nReally delete branch $head?"]} return @@ -5154,16 +5300,7 @@ proc rmbranch {} { error_popup $err return } - unset headids($head) - if {$idheads($id) eq $head} { - unset idheads($id) - removedhead $id - } else { - set i [lsearch -exact $idheads($id) $head] - if {$i >= 0} { - set idheads($id) [lreplace $idheads($id) $i $i] - } - } + removedhead $id $head redrawtags $id notbusy rmbranch } @@ -5293,7 +5430,7 @@ proc forward_pass {id children} { } } if {[info exists idheads($id)]} { - lappend dheads $id + set dheads [concat $dheads $idheads($id)] } set desc_heads($id) $dheads } @@ -5301,7 +5438,7 @@ proc forward_pass {id children} { proc getallclines {fd} { global allparents allchildren allcommits allcstart global desc_tags anc_tags idtags tagisdesc allids - global desc_heads idheads travindex + global idheads travindex while {[gets $fd line] >= 0} { set id [lindex $line 0] @@ -5369,17 +5506,20 @@ proc restartatags {} { } # update the desc_heads array for a new head just added -proc addedhead {hid} { - global desc_heads allparents +proc addedhead {hid head} { + global desc_heads allparents headids idheads + + set headids($head) $hid + lappend idheads($hid) $head set todo [list $hid] while {$todo ne {}} { set do [lindex $todo 0] set todo [lrange $todo 1 end] if {![info exists desc_heads($do)] || - [lsearch -exact $desc_heads($do) $hid] >= 0} continue + [lsearch -exact $desc_heads($do) $head] >= 0} continue set oldheads $desc_heads($do) - lappend desc_heads($do) $hid + lappend desc_heads($do) $head set heads $desc_heads($do) while {1} { set p $allparents($do) @@ -5393,15 +5533,25 @@ proc addedhead {hid} { } # update the desc_heads array for a head just removed -proc removedhead {hid} { - global desc_heads allparents +proc removedhead {hid head} { + global desc_heads allparents headids idheads + + unset headids($head) + if {$idheads($hid) eq $head} { + unset idheads($hid) + } else { + set i [lsearch -exact $idheads($hid) $head] + if {$i >= 0} { + set idheads($hid) [lreplace $idheads($hid) $i $i] + } + } set todo [list $hid] while {$todo ne {}} { set do [lindex $todo 0] set todo [lrange $todo 1 end] if {![info exists desc_heads($do)]} continue - set i [lsearch -exact $desc_heads($do) $hid] + set i [lsearch -exact $desc_heads($do) $head] if {$i < 0} continue set oldheads $desc_heads($do) set heads [lreplace $desc_heads($do) $i $i] @@ -5416,6 +5566,23 @@ proc removedhead {hid} { } } +# update things for a head moved to a child of its previous location +proc movedhead {id name} { + global headids idheads + + set oldid $headids($name) + set headids($name) $id + if {$idheads($oldid) eq $name} { + unset idheads($oldid) + } else { + set i [lsearch -exact $idheads($oldid) $name] + if {$i >= 0} { + set idheads($oldid) [lreplace $idheads($oldid) $i $i] + } + } + lappend idheads($id) $name +} + proc changedrefs {} { global desc_heads desc_tags anc_tags allcommits allids global allchildren allparents idtags travindex -- cgit v1.2.1 From ceadfe90c64b293a653bcbbce83283d2665d7cf9 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 8 Aug 2006 20:55:36 +1000 Subject: gitk: Update preceding/following tag info when creating a tag Signed-off-by: Paul Mackerras --- gitk | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/gitk b/gitk index 750a081073..0f35227250 100755 --- a/gitk +++ b/gitk @@ -5062,6 +5062,7 @@ proc domktag {} { set tagids($tag) $id lappend idtags($id) $tag redrawtags $id + addedtag $id } proc redrawtags {id} { @@ -5505,6 +5506,82 @@ proc restartatags {} { dispneartags } +# update the desc_tags and anc_tags arrays for a new tag just added +proc addedtag {id} { + global desc_tags anc_tags allparents allchildren allcommits + global idtags tagisdesc alldtags + + if {![info exists desc_tags($id)]} return + set adt $desc_tags($id) + foreach t $desc_tags($id) { + set adt [concat $adt $alldtags($t)] + } + set adt [lsort -unique $adt] + set alldtags($id) $adt + foreach t $adt { + set tagisdesc($id,$t) -1 + set tagisdesc($t,$id) 1 + } + if {[info exists anc_tags($id)]} { + set todo $anc_tags($id) + while {$todo ne {}} { + set do [lindex $todo 0] + set todo [lrange $todo 1 end] + if {[info exists tagisdesc($id,$do)]} continue + set tagisdesc($do,$id) -1 + set tagisdesc($id,$do) 1 + if {[info exists anc_tags($do)]} { + set todo [concat $todo $anc_tags($do)] + } + } + } + + set lastold $desc_tags($id) + set lastnew [list $id] + set nup 0 + set nch 0 + set todo $allparents($id) + while {$todo ne {}} { + set do [lindex $todo 0] + set todo [lrange $todo 1 end] + if {![info exists desc_tags($do)]} continue + if {$desc_tags($do) ne $lastold} { + set lastold $desc_tags($do) + set lastnew [combine_dtags $lastold [list $id]] + incr nch + } + if {$lastold eq $lastnew} continue + set desc_tags($do) $lastnew + incr nup + if {![info exists idtags($do)]} { + set todo [concat $todo $allparents($do)] + } + } + + if {![info exists anc_tags($id)]} return + set lastold $anc_tags($id) + set lastnew [list $id] + set nup 0 + set nch 0 + set todo $allchildren($id) + while {$todo ne {}} { + set do [lindex $todo 0] + set todo [lrange $todo 1 end] + if {![info exists anc_tags($do)]} continue + if {$anc_tags($do) ne $lastold} { + set lastold $anc_tags($do) + set lastnew [combine_atags $lastold [list $id]] + incr nch + } + if {$lastold eq $lastnew} continue + set anc_tags($do) $lastnew + incr nup + if {![info exists idtags($do)]} { + set todo [concat $todo $allchildren($do)] + } + } +} + # update the desc_heads array for a new head just added proc addedhead {hid head} { global desc_heads allparents headids idheads -- cgit v1.2.1 From d1e46756d312f65613863a41c256d852fcde330c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 16 Aug 2006 20:02:32 +1000 Subject: gitk: Improve responsiveness while reading and layout out the graph This restructures layoutmore so that it can take a time limit and do limited amounts of graph layout and graph optimization, and return 1 if it exceeded the time limit before finishing everything it could do. Also getcommitlines reads at most half a megabyte each time, to limit the time it spends parsing the commits to about a tenth of a second. Also got rid of the unused ncmupdate variable while I was at it. Signed-off-by: Paul Mackerras --- gitk | 58 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/gitk b/gitk index 0f35227250..b66ccca4da 100755 --- a/gitk +++ b/gitk @@ -17,13 +17,12 @@ proc gitdir {} { } proc start_rev_list {view} { - global startmsecs nextupdate ncmupdate + global startmsecs nextupdate global commfd leftover tclencoding datemode global viewargs viewfiles commitidx set startmsecs [clock clicks -milliseconds] set nextupdate [expr {$startmsecs + 100}] - set ncmupdate 1 set commitidx($view) 0 set args $viewargs($view) if {$viewfiles($view) ne {}} { @@ -79,7 +78,7 @@ proc getcommitlines {fd view} { global parentlist childlist children curview hlview global vparentlist vchildlist vdisporder vcmitlisted - set stuff [read $fd] + set stuff [read $fd 500000] if {$stuff == {}} { if {![eof $fd]} return global viewname @@ -185,7 +184,7 @@ proc getcommitlines {fd view} { } if {$gotsome} { if {$view == $curview} { - layoutmore + while {[layoutmore $nextupdate]} doupdate } elseif {[info exists hlview] && $view == $hlview} { vhighlightmore } @@ -196,20 +195,13 @@ proc getcommitlines {fd view} { } proc doupdate {} { - global commfd nextupdate numcommits ncmupdate + global commfd nextupdate numcommits foreach v [array names commfd] { fileevent $commfd($v) readable {} } update set nextupdate [expr {[clock clicks -milliseconds] + 100}] - if {$numcommits < 100} { - set ncmupdate [expr {$numcommits + 1}] - } elseif {$numcommits < 10000} { - set ncmupdate [expr {$numcommits + 10}] - } else { - set ncmupdate [expr {$numcommits + 100}] - } foreach v [array names commfd] { set fd $commfd($v) fileevent $fd readable [list getcommitlines $fd $v] @@ -1697,7 +1689,7 @@ proc showview {n} { show_status "Reading commits..." } if {[info exists commfd($n)]} { - layoutmore + layoutmore {} } else { finishcommits } @@ -2378,20 +2370,38 @@ proc visiblerows {} { return [list $r0 $r1] } -proc layoutmore {} { +proc layoutmore {tmax} { global rowlaidout rowoptim commitidx numcommits optim_delay global uparrowlen curview - set row $rowlaidout - set rowlaidout [layoutrows $row $commitidx($curview) 0] - set orow [expr {$rowlaidout - $uparrowlen - 1}] - if {$orow > $rowoptim} { - optimize_rows $rowoptim 0 $orow - set rowoptim $orow - } - set canshow [expr {$rowoptim - $optim_delay}] - if {$canshow > $numcommits} { - showstuff $canshow + while {1} { + if {$rowoptim - $optim_delay > $numcommits} { + showstuff [expr {$rowoptim - $optim_delay}] + } elseif {$rowlaidout - $uparrowlen - 1 > $rowoptim} { + set nr [expr {$rowlaidout - $uparrowlen - 1 - $rowoptim}] + if {$nr > 100} { + set nr 100 + } + optimize_rows $rowoptim 0 [expr {$rowoptim + $nr}] + incr rowoptim $nr + } elseif {$commitidx($curview) > $rowlaidout} { + set nr [expr {$commitidx($curview) - $rowlaidout}] + # may need to increase this threshold if uparrowlen or + # mingaplen are increased... + if {$nr > 150} { + set nr 150 + } + set row $rowlaidout + set rowlaidout [layoutrows $row [expr {$row + $nr}] 0] + if {$rowlaidout == $row} { + return 0 + } + } else { + return 0 + } + if {$tmax ne {} && [clock clicks -milliseconds] >= $tmax} { + return 1 + } } } -- cgit v1.2.1 From 561d038ab8adb2bab5ba368b88e620be18c4811b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 28 Aug 2006 22:41:09 +1000 Subject: gitk: Fix some bugs in the new cherry-picking code When inserting the new commit row for the cherry-picked commit, we weren't advancing the selected line (if there is one), and we weren't updating commitlisted properly. --- gitk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gitk b/gitk index b66ccca4da..ebbeac63aa 100755 --- a/gitk +++ b/gitk @@ -3314,14 +3314,14 @@ proc finishcommits {} { catch {unset pending_select} } -# Inserting a new commit as the child of the commit on row $row. +# Insert a new commit as the child of the commit on row $row. # The new commit will be displayed on row $row and the commits # on that row and below will move down one row. proc insertrow {row newcmit} { global displayorder parentlist childlist commitlisted global commitrow curview rowidlist rowoffsets numcommits global rowrangelist idrowranges rowlaidout rowoptim numcommits - global linesegends + global linesegends selectedline if {$row >= $numcommits} { puts "oops, inserting new row $row but only have $numcommits rows" @@ -3334,6 +3334,7 @@ proc insertrow {row newcmit} { lappend kids $newcmit lset childlist $row $kids set childlist [linsert $childlist $row {}] + set commitlisted [linsert $commitlisted $row 1] set l [llength $displayorder] for {set r $row} {$r < $l} {incr r} { set id [lindex $displayorder $r] @@ -3409,6 +3410,9 @@ proc insertrow {row newcmit} { incr rowoptim incr numcommits + if {[info exists selectedline] && $selectedline >= $row} { + incr selectedline + } redisplay } -- cgit v1.2.1 From ef1186228d39af29c109785fa752e3866c79a6b3 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Fri, 1 Sep 2006 01:15:38 +0200 Subject: git(7): move gitk(1) to the list of porcelain commands Signed-off-by: Jonas Fonseca Signed-off-by: Junio C Hamano --- Documentation/git.txt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index a9c87e38da..76b41c8e34 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -303,6 +303,9 @@ gitlink:git-format-patch[1]:: gitlink:git-grep[1]:: Print lines matching a pattern. +gitlink:gitk[1]:: + The git repository browser. + gitlink:git-log[1]:: Shows commit logs. @@ -483,13 +486,6 @@ gitlink:git-stripspace[1]:: Filter out empty lines. -Commands not yet documented ---------------------------- - -gitlink:gitk[1]:: - The gitk repository browser. - - Configuration Mechanism ----------------------- -- cgit v1.2.1 From 2d7320d0b09d7a9aab4e5dbc5458f37bfb6ce9f5 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Fri, 1 Sep 2006 00:32:39 +0200 Subject: Use xmalloc instead of malloc Signed-off-by: Jonas Fonseca Signed-off-by: Junio C Hamano --- builtin-fmt-merge-msg.c | 6 +++--- builtin-repo-config.c | 4 ++-- config.c | 4 ++-- git.c | 2 +- help.c | 2 +- merge-recursive.c | 6 +++--- mktag.c | 2 +- send-pack.c | 4 ++-- sha1_file.c | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index 76d22b47ba..ed59e77e19 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -140,14 +140,14 @@ static int handle_line(char *line) if (!strcmp(".", src) || !strcmp(src, origin)) { int len = strlen(origin); if (origin[0] == '\'' && origin[len - 1] == '\'') { - char *new_origin = malloc(len - 1); + char *new_origin = xmalloc(len - 1); memcpy(new_origin, origin + 1, len - 2); new_origin[len - 1] = 0; origin = new_origin; } else origin = strdup(origin); } else { - char *new_origin = malloc(strlen(origin) + strlen(src) + 5); + char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5); sprintf(new_origin, "%s of %s", origin, src); origin = new_origin; } @@ -214,7 +214,7 @@ static void shortlog(const char *name, unsigned char *sha1, if (eol) { int len = eol - bol; - oneline = malloc(len + 1); + oneline = xmalloc(len + 1); memcpy(oneline, bol, len); oneline[len] = 0; } else diff --git a/builtin-repo-config.c b/builtin-repo-config.c index 6560cf1c2d..a1756c8580 100644 --- a/builtin-repo-config.c +++ b/builtin-repo-config.c @@ -84,7 +84,7 @@ static int get_value(const char* key_, const char* regex_) *tl = tolower(*tl); if (use_key_regexp) { - key_regexp = (regex_t*)malloc(sizeof(regex_t)); + key_regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { fprintf(stderr, "Invalid key pattern: %s\n", key_); goto free_strings; @@ -97,7 +97,7 @@ static int get_value(const char* key_, const char* regex_) regex_++; } - regexp = (regex_t*)malloc(sizeof(regex_t)); + regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(regexp, regex_, REG_EXTENDED)) { fprintf(stderr, "Invalid pattern: %s\n", regex_); goto free_strings; diff --git a/config.c b/config.c index d9f2b787b9..c0897cc807 100644 --- a/config.c +++ b/config.c @@ -565,7 +565,7 @@ int git_config_set_multivar(const char* key, const char* value, /* * Validate the key and while at it, lower case it for matching. */ - store.key = (char*)malloc(strlen(key)+1); + store.key = xmalloc(strlen(key) + 1); dot = 0; for (i = 0; key[i]; i++) { unsigned char c = key[i]; @@ -633,7 +633,7 @@ int git_config_set_multivar(const char* key, const char* value, } else store.do_not_match = 0; - store.value_regex = (regex_t*)malloc(sizeof(regex_t)); + store.value_regex = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(store.value_regex, value_regex, REG_EXTENDED)) { fprintf(stderr, "Invalid pattern: %s\n", diff --git a/git.c b/git.c index bd07289d71..05871ad42c 100644 --- a/git.c +++ b/git.c @@ -29,7 +29,7 @@ static void prepend_to_path(const char *dir, int len) path_len = len + strlen(old_path) + 1; - path = malloc(path_len + 1); + path = xmalloc(path_len + 1); memcpy(path, dir, len); path[len] = ':'; diff --git a/help.c b/help.c index 9ecdefdb03..0824c25226 100644 --- a/help.c +++ b/help.c @@ -184,7 +184,7 @@ static void show_man_page(const char *git_cmd) page = git_cmd; else { int page_len = strlen(git_cmd) + 4; - char *p = malloc(page_len + 1); + char *p = xmalloc(page_len + 1); strcpy(p, "git-"); strcpy(p + 4, git_cmd); p[page_len] = 0; diff --git a/merge-recursive.c b/merge-recursive.c index 39a1eae894..48b2763de6 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -283,7 +283,7 @@ static int save_files_dirs(const unsigned char *sha1, unsigned int mode, int stage) { int len = strlen(path); - char *newpath = malloc(baselen + len + 1); + char *newpath = xmalloc(baselen + len + 1); memcpy(newpath, base, baselen); memcpy(newpath + baselen, path, len); newpath[baselen + len] = '\0'; @@ -455,7 +455,7 @@ static int remove_path(const char *name) if (ret) return ret; len = strlen(name); - dirs = malloc(len+1); + dirs = xmalloc(len+1); memcpy(dirs, name, len); dirs[len] = '\0'; while ((slash = strrchr(name, '/'))) { @@ -572,7 +572,7 @@ void update_file_flags(const unsigned char *sha, flush_buffer(fd, buf, size); close(fd); } else if (S_ISLNK(mode)) { - char *lnk = malloc(size + 1); + char *lnk = xmalloc(size + 1); memcpy(lnk, buf, size); lnk[size] = '\0'; mkdir_p(path, 0777); diff --git a/mktag.c b/mktag.c index be23e589fb..3448a5dde7 100644 --- a/mktag.c +++ b/mktag.c @@ -119,7 +119,7 @@ static int verify_tag(char *buffer, unsigned long size) int main(int argc, char **argv) { unsigned long size = 4096; - char *buffer = malloc(size); + char *buffer = xmalloc(size); unsigned char result_sha1[20]; if (argc != 1) diff --git a/send-pack.c b/send-pack.c index fd79a61923..ac4501d341 100644 --- a/send-pack.c +++ b/send-pack.c @@ -53,7 +53,7 @@ static void exec_rev_list(struct ref *refs) if (900 < i) die("git-rev-list environment overflow"); if (!is_zero_sha1(ref->new_sha1)) { - char *buf = malloc(100); + char *buf = xmalloc(100); args[i++] = buf; snprintf(buf, 50, "%s", sha1_to_hex(ref->new_sha1)); buf += 50; @@ -75,7 +75,7 @@ static void exec_rev_list(struct ref *refs) if (is_zero_sha1(ref->new_sha1) && !is_zero_sha1(ref->old_sha1) && has_sha1_file(ref->old_sha1)) { - char *buf = malloc(42); + char *buf = xmalloc(42); args[i++] = buf; snprintf(buf, 42, "^%s", sha1_to_hex(ref->old_sha1)); } diff --git a/sha1_file.c b/sha1_file.c index 46272b5916..af2bf72bab 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1756,7 +1756,7 @@ int read_pipe(int fd, char** return_buf, unsigned long* return_size) int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object) { unsigned long size = 4096; - char *buf = malloc(size); + char *buf = xmalloc(size); int ret; unsigned char hdr[50]; int hdrlen; -- cgit v1.2.1 From 95676853b2dc5d610a6f917aac37cbb12c57fcd2 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Fri, 1 Sep 2006 00:31:08 +0200 Subject: Include config.mak.autogen in the doc Makefile ... to install documentation relative to the path set with configure's --prefix option. Signed-off-by: Jonas Fonseca Signed-off-by: Junio C Hamano --- Documentation/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/Makefile b/Documentation/Makefile index 0d9ffb4ad9..ed8b886802 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -33,6 +33,8 @@ man7dir=$(mandir)/man7 INSTALL?=install +-include ../config.mak.autogen + # # Please note that there is a minor bug in asciidoc. # The version after 6.0.3 _will_ include the patch found here: -- cgit v1.2.1 From 1d3fc68ae711b3f46aea02f8d819423cf8780b7d Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Fri, 1 Sep 2006 09:13:32 +0530 Subject: gitweb: Fix git_blame Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 0984e85623..57ffa25070 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2251,7 +2251,8 @@ sub git_blame2 { my $fd; my $ftype; - if (!gitweb_check_feature('blame')) { + my ($have_blame) = gitweb_check_feature('blame'); + if (!$have_blame) { die_error('403 Permission denied', "Permission denied"); } die_error('404 Not Found', "File name not defined") if (!$file_name); @@ -2320,7 +2321,8 @@ HTML sub git_blame { my $fd; - if (!gitweb_check_feature('blame')) { + my ($have_blame) = gitweb_check_feature('blame'); + if (!$have_blame) { die_error('403 Permission denied', "Permission denied"); } die_error('404 Not Found', "File name not defined") if (!$file_name); @@ -2494,7 +2496,7 @@ sub git_blob { die_error(undef, "No file name defined"); } } - my $have_blame = gitweb_check_feature('blame'); + my ($have_blame) = gitweb_check_feature('blame'); open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or die_error(undef, "Couldn't cat $file_name, $hash"); my $mimetype = blob_mimetype($fd, $file_name); @@ -2570,7 +2572,7 @@ sub git_tree { my $ref = format_ref_marker($refs, $hash_base); git_header_html(); my $base = ""; - my $have_blame = gitweb_check_feature('blame'); + my ($have_blame) = gitweb_check_feature('blame'); if (defined $hash_base && (my %co = parse_commit($hash_base))) { git_print_page_nav('tree','', $hash_base); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); -- cgit v1.2.1 From 839837b953c613c1649b9e36ec2f01da759d87e3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 1 Sep 2006 00:17:47 -0700 Subject: Constness tightening for move/link_temp_to_file() Signed-off-by: Junio C Hamano --- cache.h | 2 +- sha1_file.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cache.h b/cache.h index 03d9dd0488..7257c4c53d 100644 --- a/cache.h +++ b/cache.h @@ -257,7 +257,7 @@ extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned l extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer, size_t bufsize, size_t *bufposn); extern int write_sha1_to_fd(int fd, const unsigned char *sha1); -extern int move_temp_to_file(const char *tmpfile, char *filename); +extern int move_temp_to_file(const char *tmpfile, const char *filename); extern int has_sha1_pack(const unsigned char *sha1); extern int has_sha1_file(const unsigned char *sha1); diff --git a/sha1_file.c b/sha1_file.c index af2bf72bab..ce90e200cb 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1348,7 +1348,7 @@ char *write_sha1_file_prepare(void *buf, * * Returns the errno on failure, 0 on success. */ -static int link_temp_to_file(const char *tmpfile, char *filename) +static int link_temp_to_file(const char *tmpfile, const char *filename) { int ret; char *dir; @@ -1381,7 +1381,7 @@ static int link_temp_to_file(const char *tmpfile, char *filename) /* * Move the just written object into its final resting place */ -int move_temp_to_file(const char *tmpfile, char *filename) +int move_temp_to_file(const char *tmpfile, const char *filename) { int ret = link_temp_to_file(tmpfile, filename); -- cgit v1.2.1 From 8c02eee29e116355474250a5e9270db6034c60de Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Fri, 1 Sep 2006 00:37:15 +0200 Subject: git-rev-list(1): group options; reformat; document more options Signed-off-by: Jonas Fonseca Signed-off-by: Junio C Hamano --- Documentation/git-rev-list.txt | 254 ++++++++++++++++++++++++++++++----------- 1 file changed, 188 insertions(+), 66 deletions(-) diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index a446a6b5a2..3c4c2fbfb9 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -27,111 +27,233 @@ SYNOPSIS DESCRIPTION ----------- + Lists commit objects in reverse chronological order starting at the given commit(s), taking ancestry relationship into account. This is useful to produce human-readable log output. -Commits which are stated with a preceding '{caret}' cause listing to stop at -that point. Their parents are implied. "git-rev-list foo bar {caret}baz" thus +Commits which are stated with a preceding '{caret}' cause listing to +stop at that point. Their parents are implied. Thus the following +command: + +----------------------------------------------------------------------- + $ git-rev-list foo bar ^baz +----------------------------------------------------------------------- + means "list all the commits which are included in 'foo' and 'bar', but not in 'baz'". -A special notation .. can be used as a -short-hand for {caret} . +A special notation "''..''" can be used as a +short-hand for "{caret}'' ''". For example, either of +the following may be used interchangeably: -Another special notation is ... which is useful for -merges. The resulting set of commits is the symmetric difference +----------------------------------------------------------------------- + $ git-rev-list origin..HEAD + $ git-rev-list HEAD ^origin +----------------------------------------------------------------------- + +Another special notation is "''...''" which is useful +for merges. The resulting set of commits is the symmetric difference between the two operands. The following two commands are equivalent: ------------- -$ git-rev-list A B --not $(git-merge-base --all A B) -$ git-rev-list A...B ------------- +----------------------------------------------------------------------- + $ git-rev-list A B --not $(git-merge-base --all A B) + $ git-rev-list A...B +----------------------------------------------------------------------- + +gitlink:git-rev-list[1] is a very essential git program, since it +provides the ability to build and traverse commit ancestry graphs. For +this reason, it has a lot of different options that enables it to be +used by commands as different as gitlink:git-bisect[1] and +gitlink:git-repack[1]. OPTIONS ------- ---pretty:: - Print the contents of the commit changesets in human-readable form. + +Commit Formatting +~~~~~~~~~~~~~~~~~ + +Using these options, gitlink:git-rev-list[1] will act similar to the +more specialized family of commit log tools: gitlink:git-log[1], +gitlink:git-show[1], and gitlink:git-whatchanged[1] + +--pretty[='']:: + + Pretty print the contents of the commit logs in a given format, + where '' can be one of 'raw', 'medium', 'short', 'full', + and 'oneline'. When left out the format default to 'medium'. + +--relative-date:: + + Show dates relative to the current time, e.g. "2 hours ago". + Only takes effect for dates shown in human-readable format, such + as when using "--pretty". --header:: - Print the contents of the commit in raw-format; each - record is separated with a NUL character. + + Print the contents of the commit in raw-format; each record is + separated with a NUL character. --parents:: + Print the parents of the commit. ---objects:: - Print the object IDs of any object referenced by the listed commits. - 'git-rev-list --objects foo ^bar' thus means "send me all object IDs - which I need to download if I have the commit object 'bar', but - not 'foo'". +Diff Formatting +~~~~~~~~~~~~~~~ ---objects-edge:: - Similar to `--objects`, but also print the IDs of - excluded commits prefixed with a `-` character. This is - used by `git-pack-objects` to build 'thin' pack, which - records objects in deltified form based on objects - contained in these excluded commits to reduce network - traffic. +Below are listed options that control the formatting of diff output. +Some of them are specific to gitlink:git-rev-list[1], however other diff +options may be given. See gitlink:git-diff-files[1] for more options. ---unpacked:: - Only useful with `--objects`; print the object IDs that - are not in packs. +-c:: + + This flag changes the way a merge commit is displayed. It shows + the differences from each of the parents to the merge result + simultaneously instead of showing pairwise diff between a parent + and the result one at a time. Furthermore, it lists only files + which were modified from all parents. + +--cc:: + + This flag implies the '-c' options and further compresses the + patch output by omitting hunks that show differences from only + one parent, or show the same change from all but one parent for + an Octopus merge. + +-r:: + + Show recursive diffs. + +-t:: + + Show the tree objects in the diff output. This implies '-r'. + +Commit Limiting +~~~~~~~~~~~~~~~ + +Besides specifying a range of commits that should be listed using the +special notations explained in the description, additional commit +limiting may be applied. + +-- + +-n 'number', --max-count='number':: ---bisect:: - Limit output to the one commit object which is roughly halfway - between the included and excluded commits. Thus, if 'git-rev-list - --bisect foo {caret}bar {caret}baz' outputs 'midpoint', the output - of 'git-rev-list foo {caret}midpoint' and 'git-rev-list midpoint - {caret}bar {caret}baz' would be of roughly the same length. - Finding the change - which introduces a regression is thus reduced to a binary search: - repeatedly generate and test new 'midpoint's until the commit chain - is of length one. - ---max-count:: Limit the number of commits output. ---max-age=timestamp, --min-age=timestamp:: - Limit the commits output to specified time range. +--since='date', --after='date':: + + Show commits more recent than a specific date. + +--until='date', --before='date':: ---sparse:: - When optional paths are given, the command outputs only - the commits that changes at least one of them, and also - ignores merges that do not touch the given paths. This - flag makes the command output all eligible commits - (still subject to count and age limitation), but apply - merge simplification nevertheless. + Show commits older than a specific date. + +--max-age='timestamp', --min-age='timestamp':: + + Limit the commits output to specified time range. --remove-empty:: + Stop when a given path disappears from the tree. --no-merges:: + Do not print commits with more than one parent. --not:: - Reverses the meaning of the '{caret}' prefix (or lack - thereof) for all following revision specifiers, up to - the next `--not`. + + Reverses the meaning of the '{caret}' prefix (or lack thereof) + for all following revision specifiers, up to the next '--not'. --all:: - Pretend as if all the refs in `$GIT_DIR/refs/` are - listed on the command line as . ---topo-order:: - By default, the commits are shown in reverse - chronological order. This option makes them appear in - topological order (i.e. descendant commits are shown - before their parents). + Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the + command line as ''. --merge:: + After a failed merge, show refs that touch files having a conflict and don't exist on all heads to merge. ---relative-date:: - Show dates relative to the current time, e.g. "2 hours ago". - Only takes effect for dates shown in human-readable format, - such as when using "--pretty". +--boundary:: + + Output uninteresting commits at the boundary, which are usually + not shown. + +--dense, --sparse:: + +When optional paths are given, the default behaviour ('--dense') is to +only output commits that changes at least one of them, and also ignore +merges that do not touch the given paths. + +Use the '--sparse' flag to makes the command output all eligible commits +(still subject to count and age limitation), but apply merge +simplification nevertheless. + +--bisect:: + +Limit output to the one commit object which is roughly halfway between +the included and excluded commits. Thus, if + +----------------------------------------------------------------------- + $ git-rev-list --bisect foo ^bar ^baz +----------------------------------------------------------------------- + +outputs 'midpoint', the output of the two commands + +----------------------------------------------------------------------- + $ git-rev-list foo ^midpoint + $ git-rev-list midpoint ^bar ^baz +----------------------------------------------------------------------- + +would be of roughly the same length. Finding the change which +introduces a regression is thus reduced to a binary search: repeatedly +generate and test new 'midpoint's until the commit chain is of length +one. + +-- + +Commit Ordering +~~~~~~~~~~~~~~~ + +By default, the commits are shown in reverse chronological order. + +--topo-order:: + + This option makes them appear in topological order (i.e. + descendant commits are shown before their parents). + +--date-order:: + + This option is similar to '--topo-order' in the sense that no + parent comes before all of its children, but otherwise things + are still ordered in the commit timestamp order. + +Object Traversal +~~~~~~~~~~~~~~~~ + +These options are mostly targeted for packing of git repositories. + +--objects:: + + Print the object IDs of any object referenced by the listed + commits. 'git-rev-list --objects foo ^bar' thus means "send me + all object IDs which I need to download if I have the commit + object 'bar', but not 'foo'". + +--objects-edge:: + + Similar to '--objects', but also print the IDs of excluded + commits prefixed with a "-" character. This is used by + gitlink:git-pack-objects[1] to build "thin" pack, which records + objects in deltified form based on objects contained in these + excluded commits to reduce network traffic. + +--unpacked:: + + Only useful with '--objects'; print the object IDs that are not + in packs. Author ------ @@ -139,9 +261,9 @@ Written by Linus Torvalds Documentation -------------- -Documentation by David Greaves, Junio C Hamano and the git-list . +Documentation by David Greaves, Junio C Hamano, Jonas Fonseca +and the git-list . GIT --- Part of the gitlink:git[7] suite - -- cgit v1.2.1 From af04b1271090801b277938836dcb7a39fc059721 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 1 Sep 2006 10:49:29 +0200 Subject: fmt-merge-msg: fix off-by-one bug Thanks to the recent malloc()->xmalloc() change, and XMALLOC_POISON, this bug was found. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-fmt-merge-msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index ed59e77e19..432963db90 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -142,7 +142,7 @@ static int handle_line(char *line) if (origin[0] == '\'' && origin[len - 1] == '\'') { char *new_origin = xmalloc(len - 1); memcpy(new_origin, origin + 1, len - 2); - new_origin[len - 1] = 0; + new_origin[len - 2] = 0; origin = new_origin; } else origin = strdup(origin); -- cgit v1.2.1 From 501524e938aee0b9691fe7fb1abf5eb17a23132f Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Fri, 1 Sep 2006 22:42:59 +0400 Subject: Documentation: Fix howto/revert-branch-rebase.html generation The rule for howto/*.html used "$?", which expands to the list of all newer prerequisites, including asciidoc.conf added by another rule. "$<" should be used instead. Signed-off-by: Sergey Vlasov Signed-off-by: Junio C Hamano --- Documentation/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Makefile b/Documentation/Makefile index ed8b886802..c00f5f62b7 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -107,7 +107,7 @@ WEBDOC_DEST = /pub/software/scm/git/docs $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt rm -f $@+ $@ - sed -e '1,/^$$/d' $? | asciidoc -b xhtml11 - >$@+ + sed -e '1,/^$$/d' $< | asciidoc -b xhtml11 - >$@+ mv $@+ $@ install-webdoc : html -- cgit v1.2.1 From ad1ed5ee896ba5d7f89bc04c7441b1532efb9853 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 1 Sep 2006 15:17:01 -0700 Subject: consolidate two copies of new style object header parsing code. Also while we are at it, remove redundant typename[] array from unpack_sha1_header. The only reason it is different from the type_names[] array in object.c module is that this code cares about the subset of object types that are valid in a loose object, so prepare a separate array of boolean that tells us which types are valid, and share the name translation with the others. Signed-off-by: Junio C Hamano --- sha1_file.c | 85 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/sha1_file.c b/sha1_file.c index ce90e200cb..76f66e6a85 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -711,17 +711,39 @@ int legacy_loose_object(unsigned char *map) return 0; } -static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) +static unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep) { + unsigned shift; unsigned char c; - unsigned int bits; unsigned long size; - static const char *typename[8] = { - NULL, /* OBJ_EXT */ - "commit", "tree", "blob", "tag", - NULL, NULL, NULL + unsigned long used = 0; + + c = buf[used++]; + *type = (c >> 4) & 7; + size = c & 15; + shift = 4; + while (c & 0x80) { + if (len <= used) + return 0; + if (sizeof(long) * 8 <= shift) + return 0; + c = buf[used++]; + size += (c & 0x7f) << shift; + shift += 7; + } + *sizep = size; + return used; +} + +static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) +{ + unsigned long size, used; + static const char valid_loose_object_type[8] = { + 0, /* OBJ_EXT */ + 1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */ + 0, /* "delta" and others are invalid in a loose object */ }; - const char *type; + enum object_type type; /* Get the data stream */ memset(stream, 0, sizeof(*stream)); @@ -735,22 +757,11 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon return inflate(stream, 0); } - c = *map++; - mapsize--; - type = typename[(c >> 4) & 7]; - if (!type) + used = unpack_object_header_gently(map, mapsize, &type, &size); + if (!used || !valid_loose_object_type[type]) return -1; - - bits = 4; - size = c & 0xf; - while ((c & 0x80)) { - if (bits >= 8*sizeof(long)) - return -1; - c = *map++; - size += (c & 0x7f) << bits; - bits += 7; - mapsize--; - } + map += used; + mapsize -= used; /* Set up the stream for the rest.. */ stream->next_in = map; @@ -758,7 +769,8 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon inflateInit(stream); /* And generate the fake traditional header */ - stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", type, size); + stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", + type_names[type], size); return 0; } @@ -916,25 +928,18 @@ static int packed_delta_info(unsigned char *base_sha1, static unsigned long unpack_object_header(struct packed_git *p, unsigned long offset, enum object_type *type, unsigned long *sizep) { - unsigned shift; - unsigned char c; - unsigned long size; + unsigned long used; - if (offset >= p->pack_size) + if (p->pack_size <= offset) die("object offset outside of pack file"); - c = *((unsigned char *)p->pack_base + offset++); - *type = (c >> 4) & 7; - size = c & 15; - shift = 4; - while (c & 0x80) { - if (offset >= p->pack_size) - die("object offset outside of pack file"); - c = *((unsigned char *)p->pack_base + offset++); - size += (c & 0x7f) << shift; - shift += 7; - } - *sizep = size; - return offset; + + used = unpack_object_header_gently((unsigned char *)p->pack_base + + offset, + p->pack_size - offset, type, sizep); + if (!used) + die("object offset outside of pack file"); + + return offset + used; } int check_reuse_pack_delta(struct packed_git *p, unsigned long offset, -- cgit v1.2.1 From 9befac470b4cfad529032dbcffcb71242ec71f91 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sat, 2 Sep 2006 00:16:31 -0400 Subject: Replace uses of strdup with xstrdup. Like xmalloc and xrealloc xstrdup dies with a useful message if the native strdup() implementation returns NULL rather than a valid pointer. I just tried to use xstrdup in new code and found it to be missing. However I expected it to be present as xmalloc and xrealloc are already commonly used throughout the code. [jc: removed the part that deals with last_XXX, which I am finding more and more dubious these days.] Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- blame.c | 2 +- builtin-apply.c | 2 +- builtin-fmt-merge-msg.c | 22 +++++++++++----------- builtin-grep.c | 2 +- builtin-name-rev.c | 2 +- builtin-prune.c | 2 +- builtin-push.c | 10 +++++----- builtin-repo-config.c | 6 +++--- builtin-rev-list.c | 4 ++-- builtin-rm.c | 2 +- builtin-show-branch.c | 6 +++--- builtin-symbolic-ref.c | 4 ++-- builtin-tar-tree.c | 2 +- builtin-upload-tar.c | 2 +- builtin-zip-tree.c | 4 ++-- config.c | 8 ++++---- connect.c | 6 +++--- diff.c | 4 ++-- environment.c | 2 +- fetch.c | 4 ++-- fsck-objects.c | 2 +- git-compat-util.h | 8 ++++++++ git.c | 2 +- http-fetch.c | 2 +- http-push.c | 6 +++--- imap-send.c | 12 ++++++------ merge-file.c | 2 +- merge-recursive.c | 14 +++++++------- merge-tree.c | 4 ++-- path-list.c | 2 +- refs.c | 4 ++-- server-info.c | 2 +- sha1_file.c | 2 +- sha1_name.c | 2 +- 34 files changed, 84 insertions(+), 76 deletions(-) diff --git a/blame.c b/blame.c index 8968046b00..8cfd5d94c7 100644 --- a/blame.c +++ b/blame.c @@ -617,7 +617,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit) if (new_name) { struct util_info* putil = get_util(p); if (!putil->pathname) - putil->pathname = strdup(new_name); + putil->pathname = xstrdup(new_name); } else { *pp = parent->next; continue; diff --git a/builtin-apply.c b/builtin-apply.c index 1a1deaf78c..872c8005a2 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2449,7 +2449,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) static int git_apply_config(const char *var, const char *value) { if (!strcmp(var, "apply.whitespace")) { - apply_default_whitespace = strdup(value); + apply_default_whitespace = xstrdup(value); return 0; } return git_default_config(var, value); diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index 432963db90..c407c033e7 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -111,29 +111,29 @@ static int handle_line(char *line) i = find_in_list(&srcs, src); if (i < 0) { i = srcs.nr; - append_to_list(&srcs, strdup(src), + append_to_list(&srcs, xstrdup(src), xcalloc(1, sizeof(struct src_data))); } src_data = srcs.payload[i]; if (pulling_head) { - origin = strdup(src); + origin = xstrdup(src); src_data->head_status |= 1; } else if (!strncmp(line, "branch ", 7)) { - origin = strdup(line + 7); + origin = xstrdup(line + 7); append_to_list(&src_data->branch, origin, NULL); src_data->head_status |= 2; } else if (!strncmp(line, "tag ", 4)) { origin = line; - append_to_list(&src_data->tag, strdup(origin + 4), NULL); + append_to_list(&src_data->tag, xstrdup(origin + 4), NULL); src_data->head_status |= 2; } else if (!strncmp(line, "remote branch ", 14)) { - origin = strdup(line + 14); + origin = xstrdup(line + 14); append_to_list(&src_data->r_branch, origin, NULL); src_data->head_status |= 2; } else { - origin = strdup(src); - append_to_list(&src_data->generic, strdup(line), NULL); + origin = xstrdup(src); + append_to_list(&src_data->generic, xstrdup(line), NULL); src_data->head_status |= 2; } @@ -145,7 +145,7 @@ static int handle_line(char *line) new_origin[len - 2] = 0; origin = new_origin; } else - origin = strdup(origin); + origin = xstrdup(origin); } else { char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5); sprintf(new_origin, "%s of %s", origin, src); @@ -203,7 +203,7 @@ static void shortlog(const char *name, unsigned char *sha1, bol = strstr(commit->buffer, "\n\n"); if (!bol) { - append_to_list(&subjects, strdup(sha1_to_hex( + append_to_list(&subjects, xstrdup(sha1_to_hex( commit->object.sha1)), NULL); continue; @@ -218,7 +218,7 @@ static void shortlog(const char *name, unsigned char *sha1, memcpy(oneline, bol, len); oneline[len] = 0; } else - oneline = strdup(bol); + oneline = xstrdup(bol); append_to_list(&subjects, oneline, NULL); } @@ -277,7 +277,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) usage(fmt_merge_msg_usage); /* get current branch */ - head = strdup(git_path("HEAD")); + head = xstrdup(git_path("HEAD")); current_branch = resolve_ref(head, head_sha1, 1); current_branch += strlen(head) - 4; free((char *)head); diff --git a/builtin-grep.c b/builtin-grep.c index 8213ce2402..6430f6d79e 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -1048,7 +1048,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) /* ignore empty line like grep does */ if (!buf[0]) continue; - add_pattern(&opt, strdup(buf), argv[1], ++lno, + add_pattern(&opt, xstrdup(buf), argv[1], ++lno, GREP_PATTERN); } fclose(patterns); diff --git a/builtin-name-rev.c b/builtin-name-rev.c index d44e782c99..52886b69b0 100644 --- a/builtin-name-rev.c +++ b/builtin-name-rev.c @@ -100,7 +100,7 @@ static int name_ref(const char *path, const unsigned char *sha1) else if (!strncmp(path, "refs/", 5)) path = path + 5; - name_rev(commit, strdup(path), 0, 0, deref); + name_rev(commit, xstrdup(path), 0, 0, deref); } return 0; } diff --git a/builtin-prune.c b/builtin-prune.c index fc885ce55b..6228c7907b 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -106,7 +106,7 @@ static void process_tree(struct tree *tree, obj->flags |= SEEN; if (parse_tree(tree) < 0) die("bad tree object %s", sha1_to_hex(obj->sha1)); - name = strdup(name); + name = xstrdup(name); add_object(obj, p, path, name); me.up = path; me.elem = name; diff --git a/builtin-push.c b/builtin-push.c index ada8338cc1..c43f2566d5 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -33,7 +33,7 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1) ref += 5; if (!strncmp(ref, "tags/", 5)) - add_refspec(strdup(ref)); + add_refspec(xstrdup(ref)); return 0; } @@ -100,12 +100,12 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI]) if (!is_refspec) { if (n < MAX_URI) - uri[n++] = strdup(s); + uri[n++] = xstrdup(s); else error("more than %d URL's specified, ignoring the rest", MAX_URI); } else if (is_refspec && !has_explicit_refspec) - add_refspec(strdup(s)); + add_refspec(xstrdup(s)); } fclose(f); if (!n) @@ -125,13 +125,13 @@ static int get_remote_config(const char* key, const char* value) !strncmp(key + 7, config_repo, config_repo_len)) { if (!strcmp(key + 7 + config_repo_len, ".url")) { if (config_current_uri < MAX_URI) - config_uri[config_current_uri++] = strdup(value); + config_uri[config_current_uri++] = xstrdup(value); else error("more than %d URL's specified, ignoring the rest", MAX_URI); } else if (config_get_refspecs && !strcmp(key + 7 + config_repo_len, ".push")) - add_refspec(strdup(value)); + add_refspec(xstrdup(value)); } return 0; } diff --git a/builtin-repo-config.c b/builtin-repo-config.c index a1756c8580..9cf12d32e5 100644 --- a/builtin-repo-config.c +++ b/builtin-repo-config.c @@ -72,12 +72,12 @@ static int get_value(const char* key_, const char* regex_) const char *home = getenv("HOME"); local = getenv("GIT_CONFIG_LOCAL"); if (!local) - local = repo_config = strdup(git_path("config")); + local = repo_config = xstrdup(git_path("config")); if (home) - global = strdup(mkpath("%s/.gitconfig", home)); + global = xstrdup(mkpath("%s/.gitconfig", home)); } - key = strdup(key_); + key = xstrdup(key_); for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl) *tl = tolower(*tl); for (tl=key; *tl && *tl != '.'; ++tl) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 402af8e1b5..8437454fbe 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -109,7 +109,7 @@ static void process_blob(struct blob *blob, if (obj->flags & (UNINTERESTING | SEEN)) return; obj->flags |= SEEN; - name = strdup(name); + name = xstrdup(name); add_object(obj, p, path, name); } @@ -130,7 +130,7 @@ static void process_tree(struct tree *tree, if (parse_tree(tree) < 0) die("bad tree object %s", sha1_to_hex(obj->sha1)); obj->flags |= SEEN; - name = strdup(name); + name = xstrdup(name); add_object(obj, p, path, name); me.up = path; me.elem = name; diff --git a/builtin-rm.c b/builtin-rm.c index 593d86744c..33d04bd015 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -32,7 +32,7 @@ static int remove_file(const char *name) ret = unlink(name); if (!ret && (slash = strrchr(name, '/'))) { - char *n = strdup(name); + char *n = xstrdup(name); do { n[slash - name] = 0; name = n; diff --git a/builtin-show-branch.c b/builtin-show-branch.c index d7de18ec0b..578c9fafd0 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -163,7 +163,7 @@ static void name_commits(struct commit_list *list, en += sprintf(en, "^"); else en += sprintf(en, "^%d", nth); - name_commit(p, strdup(newname), 0); + name_commit(p, xstrdup(newname), 0); i++; name_first_parent_chain(p); } @@ -364,7 +364,7 @@ static int append_ref(const char *refname, const unsigned char *sha1) refname, MAX_REVS); return 0; } - ref_name[ref_name_cnt++] = strdup(refname); + ref_name[ref_name_cnt++] = xstrdup(refname); ref_name[ref_name_cnt] = NULL; return 0; } @@ -521,7 +521,7 @@ static int git_show_branch_config(const char *var, const char *value) default_alloc = default_alloc * 3 / 2 + 20; default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc); } - default_arg[default_num++] = strdup(value); + default_arg[default_num++] = xstrdup(value); default_arg[default_num] = NULL; return 0; } diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c index b4ec6f28ed..1d3a5e229a 100644 --- a/builtin-symbolic-ref.c +++ b/builtin-symbolic-ref.c @@ -7,7 +7,7 @@ static const char git_symbolic_ref_usage[] = static void check_symref(const char *HEAD) { unsigned char sha1[20]; - const char *git_HEAD = strdup(git_path("%s", HEAD)); + const char *git_HEAD = xstrdup(git_path("%s", HEAD)); const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 0); if (git_refs_heads_master) { /* we want to strip the .git/ part */ @@ -26,7 +26,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) check_symref(argv[1]); break; case 3: - create_symref(strdup(git_path("%s", argv[1])), argv[2]); + create_symref(xstrdup(git_path("%s", argv[1])), argv[2]); break; default: usage(git_symbolic_ref_usage); diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index 61a413590d..fa666f78c5 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -351,7 +351,7 @@ static int remote_tar(int argc, const char **argv) usage(tar_tree_usage); /* --remote= */ - url = strdup(argv[1]+9); + url = xstrdup(argv[1]+9); pid = git_connect(fd, url, exec); if (pid < 0) return 1; diff --git a/builtin-upload-tar.c b/builtin-upload-tar.c index 7b401bbb77..06a945a4b1 100644 --- a/builtin-upload-tar.c +++ b/builtin-upload-tar.c @@ -53,7 +53,7 @@ int cmd_upload_tar(int argc, const char **argv, const char *prefix) return nak("expected (optional) base"); if (buf[len-1] == '\n') buf[--len] = 0; - base = strdup(buf + 5); + base = xstrdup(buf + 5); len = packet_read_line(0, buf, sizeof(buf)); } if (len) diff --git a/builtin-zip-tree.c b/builtin-zip-tree.c index a5b834d360..1c1f6830c1 100644 --- a/builtin-zip-tree.c +++ b/builtin-zip-tree.c @@ -311,11 +311,11 @@ int cmd_zip_tree(int argc, const char **argv, const char *prefix) switch (argc) { case 3: - base = strdup(argv[2]); + base = xstrdup(argv[2]); baselen = strlen(base); break; case 2: - base = strdup(""); + base = xstrdup(""); baselen = 0; break; default: diff --git a/config.c b/config.c index c0897cc807..e8f0caf7cf 100644 --- a/config.c +++ b/config.c @@ -350,11 +350,11 @@ int git_config(config_fn_t fn) home = getenv("HOME"); filename = getenv("GIT_CONFIG_LOCAL"); if (!filename) - filename = repo_config = strdup(git_path("config")); + filename = repo_config = xstrdup(git_path("config")); } if (home) { - char *user_config = strdup(mkpath("%s/.gitconfig", home)); + char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) ret = git_config_from_file(fn, user_config); free(user_config); @@ -545,8 +545,8 @@ int git_config_set_multivar(const char* key, const char* value, if (!config_filename) config_filename = git_path("config"); } - config_filename = strdup(config_filename); - lock_file = strdup(mkpath("%s.lock", config_filename)); + config_filename = xstrdup(config_filename); + lock_file = xstrdup(mkpath("%s.lock", config_filename)); /* * Since "key" actually contains the section name and the real diff --git a/connect.c b/connect.c index e501ccce25..06ef387649 100644 --- a/connect.c +++ b/connect.c @@ -69,7 +69,7 @@ struct ref **get_remote_heads(int in, struct ref **list, if (len != name_len + 41) { if (server_capabilities) free(server_capabilities); - server_capabilities = strdup(name + name_len + 1); + server_capabilities = xstrdup(name + name_len + 1); } if (!check_ref(name, name_len, flags)) @@ -661,7 +661,7 @@ int git_connect(int fd[2], char *url, const char *prog) if (path[1] == '~') path++; else { - path = strdup(ptr); + path = xstrdup(ptr); free_path = 1; } @@ -672,7 +672,7 @@ int git_connect(int fd[2], char *url, const char *prog) /* These underlying connection commands die() if they * cannot connect. */ - char *target_host = strdup(host); + char *target_host = xstrdup(host); if (git_use_proxy(host)) git_proxy_connect(fd, host); else diff --git a/diff.c b/diff.c index 70699fd8c4..9dcbda3117 100644 --- a/diff.c +++ b/diff.c @@ -216,7 +216,7 @@ static char *quote_one(const char *str) return NULL; needlen = quote_c_style(str, NULL, NULL, 0); if (!needlen) - return strdup(str); + return xstrdup(str); xp = xmalloc(needlen + 1); quote_c_style(str, xp, NULL, 0); return xp; @@ -658,7 +658,7 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat, x->is_renamed = 1; } else - x->name = strdup(name_a); + x->name = xstrdup(name_a); return x; } diff --git a/environment.c b/environment.c index 5fae9ac305..84d870ca4e 100644 --- a/environment.c +++ b/environment.c @@ -47,7 +47,7 @@ static void setup_git_env(void) } git_graft_file = getenv(GRAFT_ENVIRONMENT); if (!git_graft_file) - git_graft_file = strdup(git_path("info/grafts")); + git_graft_file = xstrdup(git_path("info/grafts")); } const char *get_git_dir(void) diff --git a/fetch.c b/fetch.c index 7d3812c406..34df8d37d7 100644 --- a/fetch.c +++ b/fetch.c @@ -234,8 +234,8 @@ int pull_targets_stdin(char ***target, const char ***write_ref) *target = xrealloc(*target, targets_alloc * sizeof(**target)); *write_ref = xrealloc(*write_ref, targets_alloc * sizeof(**write_ref)); } - (*target)[targets] = strdup(tg_one); - (*write_ref)[targets] = rf_one ? strdup(rf_one) : NULL; + (*target)[targets] = xstrdup(tg_one); + (*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL; targets++; } return targets; diff --git a/fsck-objects.c b/fsck-objects.c index 24286de15d..4d994f3fc8 100644 --- a/fsck-objects.c +++ b/fsck-objects.c @@ -458,7 +458,7 @@ static void fsck_object_dir(const char *path) static int fsck_head_link(void) { unsigned char sha1[20]; - const char *git_HEAD = strdup(git_path("HEAD")); + const char *git_HEAD = xstrdup(git_path("HEAD")); const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1); int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */ diff --git a/git-compat-util.h b/git-compat-util.h index 91f2b0d3f0..552b8ec23a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -84,6 +84,14 @@ extern char *gitstrcasestr(const char *haystack, const char *needle); extern size_t gitstrlcpy(char *, const char *, size_t); #endif +static inline char* xstrdup(const char *str) +{ + char *ret = strdup(str); + if (!ret) + die("Out of memory, strdup failed"); + return ret; +} + static inline void *xmalloc(size_t size) { void *ret = malloc(size); diff --git a/git.c b/git.c index 05871ad42c..9bb21ede8f 100644 --- a/git.c +++ b/git.c @@ -97,7 +97,7 @@ static char *alias_string; static int git_alias_config(const char *var, const char *value) { if (!strncmp(var, "alias.", 6) && !strcmp(var + 6, alias_command)) { - alias_string = strdup(value); + alias_string = xstrdup(value); } return 0; } diff --git a/http-fetch.c b/http-fetch.c index 6806f3678c..fac17607b4 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -787,7 +787,7 @@ static int remote_ls(struct alt_base *repo, const char *path, int flags, ls.flags = flags; ls.repo = repo; - ls.path = strdup(path); + ls.path = xstrdup(path); ls.dentry_name = NULL; ls.dentry_flags = 0; ls.userData = userData; diff --git a/http-push.c b/http-push.c index 7814666d8d..670ff007be 100644 --- a/http-push.c +++ b/http-push.c @@ -1539,7 +1539,7 @@ static void remote_ls(const char *path, int flags, struct remote_ls_ctx ls; ls.flags = flags; - ls.path = strdup(path); + ls.path = xstrdup(path); ls.dentry_name = NULL; ls.dentry_flags = 0; ls.userData = userData; @@ -1738,7 +1738,7 @@ static struct object_list **process_tree(struct tree *tree, die("bad tree object %s", sha1_to_hex(obj->sha1)); obj->flags |= SEEN; - name = strdup(name); + name = xstrdup(name); p = add_one_object(obj, p); me.up = path; me.elem = name; @@ -2467,7 +2467,7 @@ int main(int argc, char **argv) /* Set up revision info for this refspec */ commit_argc = 3; - new_sha1_hex = strdup(sha1_to_hex(ref->new_sha1)); + new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1)); old_sha1_hex = NULL; commit_argv[1] = "--objects"; commit_argv[2] = new_sha1_hex; diff --git a/imap-send.c b/imap-send.c index 65c71c602d..8ed0f0aa6f 100644 --- a/imap-send.c +++ b/imap-send.c @@ -1032,7 +1032,7 @@ imap_open_store( imap_server_conf_t *srvc ) * getpass() returns a pointer to a static buffer. make a copy * for long term storage. */ - srvc->pass = strdup( arg ); + srvc->pass = xstrdup( arg ); } if (CAP(NOLOGIN)) { fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host ); @@ -1288,7 +1288,7 @@ git_imap_config(const char *key, const char *val) key += sizeof imap_key - 1; if (!strcmp( "folder", key )) { - imap_folder = strdup( val ); + imap_folder = xstrdup( val ); } else if (!strcmp( "host", key )) { { if (!strncmp( "imap:", val, 5 )) @@ -1298,16 +1298,16 @@ git_imap_config(const char *key, const char *val) } if (!strncmp( "//", val, 2 )) val += 2; - server.host = strdup( val ); + server.host = xstrdup( val ); } else if (!strcmp( "user", key )) - server.user = strdup( val ); + server.user = xstrdup( val ); else if (!strcmp( "pass", key )) - server.pass = strdup( val ); + server.pass = xstrdup( val ); else if (!strcmp( "port", key )) server.port = git_config_int( key, val ); else if (!strcmp( "tunnel", key )) - server.tunnel = strdup( val ); + server.tunnel = xstrdup( val ); return 0; } diff --git a/merge-file.c b/merge-file.c index f32c653825..fc9b148993 100644 --- a/merge-file.c +++ b/merge-file.c @@ -21,7 +21,7 @@ static const char *write_temp_file(mmfile_t *f) fd = mkstemp(filename); if (fd < 0) return NULL; - filename = strdup(filename); + filename = xstrdup(filename); if (f->size != xwrite(fd, f->ptr, f->size)) { rm_temp_file(filename); return NULL; diff --git a/merge-recursive.c b/merge-recursive.c index 48b2763de6..611cd95cf5 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -513,8 +513,8 @@ static char *unique_path(const char *path, const char *branch) static int mkdir_p(const char *path, unsigned long mode) { - /* path points to cache entries, so strdup before messing with it */ - char *buf = strdup(path); + /* path points to cache entries, so xstrdup before messing with it */ + char *buf = xstrdup(path); int result = safe_create_leading_directories(buf); free(buf); return result; @@ -668,9 +668,9 @@ static struct merge_file_info merge_file(struct diff_filespec *o, git_unpack_file(a->sha1, src1); git_unpack_file(b->sha1, src2); - argv[2] = la = strdup(mkpath("%s/%s", branch1, a->path)); - argv[6] = lb = strdup(mkpath("%s/%s", branch2, b->path)); - argv[4] = lo = strdup(mkpath("orig/%s", o->path)); + argv[2] = la = xstrdup(mkpath("%s/%s", branch1, a->path)); + argv[6] = lb = xstrdup(mkpath("%s/%s", branch2, b->path)); + argv[4] = lo = xstrdup(mkpath("orig/%s", o->path)); argv[7] = src1; argv[8] = orig; argv[9] = src2, @@ -1314,9 +1314,9 @@ int main(int argc, char *argv[]) original_index_file = getenv("GIT_INDEX_FILE"); if (!original_index_file) - original_index_file = strdup(git_path("index")); + original_index_file = xstrdup(git_path("index")); - temporary_index_file = strdup(git_path("mrg-rcrsv-tmp-idx")); + temporary_index_file = xstrdup(git_path("mrg-rcrsv-tmp-idx")); if (argc < 4) die("Usage: %s ... -- ...\n", argv[0]); diff --git a/merge-tree.c b/merge-tree.c index c2e9a867ed..60df758c41 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -177,7 +177,7 @@ static void resolve(const char *base, struct name_entry *branch1, struct name_en if (!branch1) return; - path = strdup(mkpath("%s%s", base, result->path)); + path = xstrdup(mkpath("%s%s", base, result->path)); orig = create_entry(2, branch1->mode, branch1->sha1, path); final = create_entry(0, result->mode, result->sha1, path); @@ -233,7 +233,7 @@ static struct merge_list *link_entry(unsigned stage, const char *base, struct na if (entry) path = entry->path; else - path = strdup(mkpath("%s%s", base, n->path)); + path = xstrdup(mkpath("%s%s", base, n->path)); link = create_entry(stage, n->mode, n->sha1, path); link->link = entry; return link; diff --git a/path-list.c b/path-list.c index b1ee72d1dc..0c332dc7b5 100644 --- a/path-list.c +++ b/path-list.c @@ -45,7 +45,7 @@ static int add_entry(struct path_list *list, const char *path) (list->nr - index) * sizeof(struct path_list_item)); list->items[index].path = list->strdup_paths ? - strdup(path) : (char *)path; + xstrdup(path) : (char *)path; list->items[index].util = NULL; list->nr++; diff --git a/refs.c b/refs.c index aab14fc107..5e653141ce 100644 --- a/refs.c +++ b/refs.c @@ -313,8 +313,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *path, } lock->lk = xcalloc(1, sizeof(struct lock_file)); - lock->ref_file = strdup(path); - lock->log_file = strdup(git_path("logs/%s", lock->ref_file + plen)); + lock->ref_file = xstrdup(path); + lock->log_file = xstrdup(git_path("logs/%s", lock->ref_file + plen)); lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT; if (safe_create_leading_directories(lock->ref_file)) diff --git a/server-info.c b/server-info.c index 7df628f2b2..2fb8f57103 100644 --- a/server-info.c +++ b/server-info.c @@ -23,7 +23,7 @@ static int add_info_ref(const char *path, const unsigned char *sha1) static int update_info_refs(int force) { - char *path0 = strdup(git_path("info/refs")); + char *path0 = xstrdup(git_path("info/refs")); int len = strlen(path0); char *path1 = xmalloc(len + 2); diff --git a/sha1_file.c b/sha1_file.c index 76f66e6a85..4ef98053f8 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -115,7 +115,7 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1) /* * NOTE! This returns a statically allocated buffer, so you have to be - * careful about using it. Do a "strdup()" if you need to save the + * careful about using it. Do a "xstrdup()" if you need to save the * filename. * * Also note that this returns the location for creating. Reading diff --git a/sha1_name.c b/sha1_name.c index 3f6b77ccfa..1fbc443805 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -279,7 +279,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) pathname = resolve_ref(git_path(*p, len, str), this_result, 1); if (pathname) { if (!refs_found++) - real_path = strdup(pathname); + real_path = xstrdup(pathname); if (!warn_ambiguous_refs) break; } -- cgit v1.2.1 From 6ce4e61f1be690681f6494eb5ca26540c2316f81 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sat, 2 Sep 2006 18:23:48 +0200 Subject: Trace into a file or an open fd and refactor tracing code. If GIT_TRACE is set to an absolute path (starting with a '/' character), we interpret this as a file path and we trace into it. Also if GIT_TRACE is set to an integer value greater than 1 and lower than 10, we interpret this as an open fd value and we trace into it. Note that this behavior is not compatible with the previous one. We also trace whole messages using one write(2) call to make sure messages from processes do net get mixed up in the middle. This patch makes it possible to get trace information when running "make test". Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Makefile | 2 +- cache.h | 6 +++ exec_cmd.c | 18 +------ git.c | 25 ++-------- imap-send.c | 25 ---------- quote.c | 32 +++++++++++++ quote.h | 1 + t/test-lib.sh | 10 +++- trace.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ write_or_die.c | 25 ++++++++++ 10 files changed, 229 insertions(+), 64 deletions(-) create mode 100644 trace.c diff --git a/Makefile b/Makefile index 05bd77f967..a639cdfcfb 100644 --- a/Makefile +++ b/Makefile @@ -249,7 +249,7 @@ LIB_OBJS = \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ - write_or_die.o \ + write_or_die.o trace.o \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) BUILTIN_OBJS = \ diff --git a/cache.h b/cache.h index 7257c4c53d..195908fc34 100644 --- a/cache.h +++ b/cache.h @@ -398,6 +398,7 @@ extern char git_commit_encoding[MAX_ENCODING_LENGTH]; extern int copy_fd(int ifd, int ofd); extern void write_or_die(int fd, const void *buf, size_t count); +extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); /* Finish off pack transfer receiving end */ extern int receive_unpack_pack(int fd[2], const char *me, int quiet, int); @@ -423,4 +424,9 @@ extern struct commit *alloc_commit_node(void); extern struct tag *alloc_tag_node(void); extern void alloc_report(void); +/* trace.c */ +extern int nfvasprintf(char **str, const char *fmt, va_list va); +extern void trace_printf(const char *format, ...); +extern void trace_argv_printf(const char **argv, int count, const char *format, ...); + #endif /* CACHE_H */ diff --git a/exec_cmd.c b/exec_cmd.c index e30936d72c..5d6a1247b4 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -97,26 +97,12 @@ int execv_git_cmd(const char **argv) tmp = argv[0]; argv[0] = git_command; - if (getenv("GIT_TRACE")) { - const char **p = argv; - fputs("trace: exec:", stderr); - while (*p) { - fputc(' ', stderr); - sq_quote_print(stderr, *p); - ++p; - } - putc('\n', stderr); - fflush(stderr); - } + trace_argv_printf(argv, -1, "trace: exec:"); /* execve() can only ever return if it fails */ execve(git_command, (char **)argv, environ); - if (getenv("GIT_TRACE")) { - fprintf(stderr, "trace: exec failed: %s\n", - strerror(errno)); - fflush(stderr); - } + trace_printf("trace: exec failed: %s\n", strerror(errno)); argv[0] = tmp; } diff --git a/git.c b/git.c index 9bb21ede8f..1d00111819 100644 --- a/git.c +++ b/git.c @@ -179,17 +179,9 @@ static int handle_alias(int *argcp, const char ***argv) if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); - if (getenv("GIT_TRACE")) { - int i; - fprintf(stderr, "trace: alias expansion: %s =>", - alias_command); - for (i = 0; i < count; ++i) { - fputc(' ', stderr); - sq_quote_print(stderr, new_argv[i]); - } - fputc('\n', stderr); - fflush(stderr); - } + trace_argv_printf(new_argv, count, + "trace: alias expansion: %s =>", + alias_command); new_argv = xrealloc(new_argv, sizeof(char*) * (count + *argcp + 1)); @@ -292,16 +284,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) prefix = setup_git_directory(); if (p->option & USE_PAGER) setup_pager(); - if (getenv("GIT_TRACE")) { - int j; - fprintf(stderr, "trace: built-in: git"); - for (j = 0; j < argc; ++j) { - fputc(' ', stderr); - sq_quote_print(stderr, argv[j]); - } - putc('\n', stderr); - fflush(stderr); - } + trace_argv_printf(argv, argc, "trace: built-in: git"); exit(p->fn(argc, argv, prefix)); } diff --git a/imap-send.c b/imap-send.c index 8ed0f0aa6f..362e474374 100644 --- a/imap-send.c +++ b/imap-send.c @@ -110,7 +110,6 @@ static char *next_arg( char ** ); static void free_generic_messages( message_t * ); -static int nfvasprintf( char **str, const char *fmt, va_list va ); static int nfsnprintf( char *buf, int blen, const char *fmt, ... ); @@ -371,21 +370,6 @@ free_generic_messages( message_t *msgs ) } } -static int -git_vasprintf( char **strp, const char *fmt, va_list ap ) -{ - int len; - char tmp[1024]; - - if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap )) < 0 || !(*strp = xmalloc( len + 1 ))) - return -1; - if (len >= (int)sizeof(tmp)) - vsprintf( *strp, fmt, ap ); - else - memcpy( *strp, tmp, len + 1 ); - return len; -} - static int nfsnprintf( char *buf, int blen, const char *fmt, ... ) { @@ -399,15 +383,6 @@ nfsnprintf( char *buf, int blen, const char *fmt, ... ) return ret; } -static int -nfvasprintf( char **str, const char *fmt, va_list va ) -{ - int ret = git_vasprintf( str, fmt, va ); - if (ret < 0) - die( "Fatal: Out of memory\n"); - return ret; -} - static struct { unsigned char i, j, s[256]; } rs; diff --git a/quote.c b/quote.c index e220dcc280..a38786c177 100644 --- a/quote.c +++ b/quote.c @@ -74,6 +74,38 @@ char *sq_quote(const char *src) return buf; } +char *sq_quote_argv(const char** argv, int count) +{ + char *buf, *to; + int i; + size_t len = 0; + + /* Count argv if needed. */ + if (count < 0) { + for (count = 0; argv[count]; count++) + ; /* just counting */ + } + + /* Special case: no argv. */ + if (!count) + return xcalloc(1,1); + + /* Get destination buffer length. */ + for (i = 0; i < count; i++) + len += sq_quote_buf(NULL, 0, argv[i]) + 1; + + /* Alloc destination buffer. */ + to = buf = xmalloc(len + 1); + + /* Copy into destination buffer. */ + for (i = 0; i < count; ++i) { + *to++ = ' '; + to += sq_quote_buf(to, len, argv[i]); + } + + return buf; +} + char *sq_dequote(char *arg) { char *dst = arg; diff --git a/quote.h b/quote.h index fc5481e78a..a6c4611c25 100644 --- a/quote.h +++ b/quote.h @@ -31,6 +31,7 @@ extern char *sq_quote(const char *src); extern void sq_quote_print(FILE *stream, const char *src); extern size_t sq_quote_buf(char *dst, size_t n, const char *src); +extern char *sq_quote_argv(const char** argv, int count); /* This unwraps what sq_quote() produces in place, but returns * NULL if the input does not look like what sq_quote would have diff --git a/t/test-lib.sh b/t/test-lib.sh index 470a909891..e2629339d4 100755 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -28,13 +28,21 @@ unset GIT_DIR unset GIT_EXTERNAL_DIFF unset GIT_INDEX_FILE unset GIT_OBJECT_DIRECTORY -unset GIT_TRACE unset SHA1_FILE_DIRECTORIES unset SHA1_FILE_DIRECTORY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR VISUAL +case $(echo $GIT_TRACE |tr [A-Z] [a-z]) in + 1|2|true) + echo "* warning: Some tests will not work if GIT_TRACE" \ + "is set as to trace on STDERR ! *" + echo "* warning: Please set GIT_TRACE to something" \ + "other than 1, 2 or true ! *" + ;; +esac + # Each test should start with something like this, after copyright notices: # # test_description='Description of this test... diff --git a/trace.c b/trace.c new file mode 100644 index 0000000000..ce01c34749 --- /dev/null +++ b/trace.c @@ -0,0 +1,149 @@ +/* + * GIT - The information manager from hell + * + * Copyright (C) 2000-2002 Michael R. Elkins + * Copyright (C) 2002-2004 Oswald Buddenhagen + * Copyright (C) 2004 Theodore Y. Ts'o + * Copyright (C) 2006 Mike McCormack + * Copyright (C) 2006 Christian Couder + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "cache.h" +#include "quote.h" + +/* Stolen from "imap-send.c". */ +static int git_vasprintf(char **strp, const char *fmt, va_list ap) +{ + int len; + char tmp[1024]; + + if ((len = vsnprintf(tmp, sizeof(tmp), fmt, ap)) < 0 || + !(*strp = xmalloc(len + 1))) + return -1; + if (len >= (int)sizeof(tmp)) + vsprintf(*strp, fmt, ap); + else + memcpy(*strp, tmp, len + 1); + return len; +} + +/* Stolen from "imap-send.c". */ +int nfvasprintf(char **str, const char *fmt, va_list va) +{ + int ret = git_vasprintf(str, fmt, va); + if (ret < 0) + die("Fatal: Out of memory\n"); + return ret; +} + +/* Get a trace file descriptor from GIT_TRACE env variable. */ +static int get_trace_fd(int *need_close) +{ + char *trace = getenv("GIT_TRACE"); + + if (!trace || !strcmp(trace, "0") || !strcasecmp(trace," false")) + return 0; + if (!strcmp(trace, "1") || !strcasecmp(trace, "true")) + return STDERR_FILENO; + if (strlen(trace) == 1 && isdigit(*trace)) + return atoi(trace); + if (*trace == '/') { + int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666); + if (fd == -1) { + fprintf(stderr, + "Could not open '%s' for tracing: %s\n" + "Defaulting to tracing on stderr...\n", + trace, strerror(errno)); + return STDERR_FILENO; + } + *need_close = 1; + return fd; + } + + fprintf(stderr, "What does '%s' for GIT_TRACE means ?\n", trace); + fprintf(stderr, "If you want to trace into a file, " + "then please set GIT_TRACE to an absolute pathname " + "(starting with /).\n"); + fprintf(stderr, "Defaulting to tracing on stderr...\n"); + + return STDERR_FILENO; +} + +static const char err_msg[] = "Could not trace into fd given by " + "GIT_TRACE environment variable"; + +void trace_printf(const char *format, ...) +{ + char *trace_str; + va_list rest; + int need_close = 0; + int fd = get_trace_fd(&need_close); + + if (!fd) + return; + + va_start(rest, format); + nfvasprintf(&trace_str, format, rest); + va_end(rest); + + write_or_whine(fd, trace_str, strlen(trace_str), err_msg); + + free(trace_str); + + if (need_close) + close(fd); +} + +void trace_argv_printf(const char **argv, int count, const char *format, ...) +{ + char *argv_str, *format_str, *trace_str; + size_t argv_len, format_len, trace_len; + va_list rest; + int need_close = 0; + int fd = get_trace_fd(&need_close); + + if (!fd) + return; + + /* Get the argv string. */ + argv_str = sq_quote_argv(argv, count); + argv_len = strlen(argv_str); + + /* Get the formated string. */ + va_start(rest, format); + nfvasprintf(&format_str, format, rest); + va_end(rest); + + /* Allocate buffer for trace string. */ + format_len = strlen(format_str); + trace_len = argv_len + format_len + 1; /* + 1 for \n */ + trace_str = xmalloc(trace_len + 1); + + /* Copy everything into the trace string. */ + strncpy(trace_str, format_str, format_len); + strncpy(trace_str + format_len, argv_str, argv_len); + strcpy(trace_str + trace_len - 1, "\n"); + + write_or_whine(fd, trace_str, trace_len, err_msg); + + free(argv_str); + free(format_str); + free(trace_str); + + if (need_close) + close(fd); +} diff --git a/write_or_die.c b/write_or_die.c index ab4cb8a69c..bfe4eeb649 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -18,3 +18,28 @@ void write_or_die(int fd, const void *buf, size_t count) p += written; } } + +int write_or_whine(int fd, const void *buf, size_t count, const char *msg) +{ + const char *p = buf; + ssize_t written; + + while (count > 0) { + written = xwrite(fd, p, count); + if (written == 0) { + fprintf(stderr, "%s: disk full?\n", msg); + return 0; + } + else if (written < 0) { + if (errno == EPIPE) + exit(0); + fprintf(stderr, "%s: write error (%s)\n", + msg, strerror(errno)); + return 0; + } + count -= written; + p += written; + } + + return 1; +} -- cgit v1.2.1