diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 7cc7fafc1d7..493cac22dbe 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -9,37 +9,46 @@ git-format-patch - Prepare patches for e-mail submission
 SYNOPSIS
 --------
 [verse]
-'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--attach] [-s] [-c]
-		 [--diff-options] <his> [<mine>]
+'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--attach]
+	           [-s | --signoff] [--diff-options] [--start-number <n>]
+		   <since>[..<until>]
 
 DESCRIPTION
 -----------
-Prepare each commit with its patch since <mine> head forked from
-<his> head, one file per patch formatted to resemble UNIX mailbox
-format, for e-mail submission or use with gitlink:git-am[1].
+
+Prepare each commit between <since> and <until> with its patch in
+one file per commit, formatted to resemble UNIX mailbox format.
+If ..<until> is not specified, the head of the current working
+tree is implied.
+
+The output of this command is convenient for e-mail submission or
+for use with gitlink:git-am[1].
 
 Each output file is numbered sequentially from 1, and uses the
-first line of the commit message (massaged for pathname safety)
-as the filename.
+first line of the commit message (massaged for pathname safety) as
+the filename. The names of the output files are printed to standard
+output, unless the --stdout option is specified.
 
-When -o is specified, output files are created in <dir>; otherwise
-they are created in the current working directory.  This option
-is ignored if --stdout is specified.
+If -o is specified, output files are created in <dir>.  Otherwise
+they are created in the current working directory.
 
-When -n is specified, instead of "[PATCH] Subject", the first
-line is formatted as "[PATCH N/M] Subject", unless you have only
-one patch.
+If -n is specified, instead of "[PATCH] Subject", the first line
+is formatted as "[PATCH n/m] Subject".
 
 
 OPTIONS
 -------
 -o|--output-directory <dir>::
 	Use <dir> to store the resulting files, instead of the
-	current working directory.
+	current working directory. This option is ignored if
+	--stdout is specified.
 
 -n|--numbered::
 	Name output in '[PATCH n/m]' format.
 
+--start-number <n>::
+	Start numbering the patches at <n> instead of 1.
+
 -k|--keep-subject::
 	Do not strip/add '[PATCH]' from the first line of the
 	commit log message.
@@ -48,17 +57,9 @@ OPTIONS
 	Add `Signed-off-by:` line to the commit message, using
 	the committer identity of yourself.
 
--c|--check::
-        Display suspicious lines in the patch.  The definition
-        of 'suspicious lines' is currently the lines that has
-        trailing whitespaces, and the lines whose indentation
-        has a SP character immediately followed by a TAB
-        character.
-
 --stdout::
-	This flag generates the mbox formatted output to the
-	standard output, instead of saving them into a file per
-	patch and implies --mbox.
+	Print all commits to the standard output in mbox format,
+	instead of creating a file for each one.
 
 --attach::
 	Create attachments instead of inlining patches.
@@ -82,18 +83,18 @@ git-format-patch -k --stdout R1..R2 | git-am -3 -k::
 	cherry-pick them.
 
 git-format-patch origin::
-	Extract commits the current branch accumulated since it
-	pulled from origin the last time in a patch form for
-	e-mail submission.
+	Extract all commits which are in the current branch but
+	not in the origin branch.  For each commit a separate file
+	is created in the current directory.
 
 git-format-patch -M -B origin::
-	The same as the previous one, except detect and handle
-	renames and complete rewrites intelligently to produce
-	renaming patch.  A renaming patch reduces the amount of
-	text output, and generally makes it easier to review
-	it.  Note that the "patch" program does not understand
-	renaming patch well, so use it only when you know the
-	recipient uses git to apply your patch.
+	The same as the previous one.  Additionally, it detects
+	and handles renames and complete rewrites intelligently to
+	produce a renaming patch.  A renaming patch reduces the
+	amount of text output, and generally makes it easier to
+	review it.  Note that the "patch" program does not
+	understand renaming patches, so use it only when you know
+	the recipient uses git to apply your patch.
 
 
 See Also
diff --git a/git-commit.sh b/git-commit.sh
index 1983d458282..15482d21b31 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -260,20 +260,41 @@ do
   -m|--m|--me|--mes|--mess|--messa|--messag|--message)
       case "$#" in 1) usage ;; esac
       shift
-      log_given=t$log_given
-      log_message="$1"
+      log_given=m$log_given
+      if test "$log_message" = ''
+      then
+          log_message="$1"
+      else
+          log_message="$log_message
+
+$1"
+      fi
       no_edit=t
       shift
       ;;
   -m*)
-      log_given=t$log_given
-      log_message=`expr "$1" : '-m\(.*\)'`
+      log_given=m$log_given
+      if test "$log_message" = ''
+      then
+          log_message=`expr "$1" : '-m\(.*\)'`
+      else
+          log_message="$log_message
+
+`expr "$1" : '-m\(.*\)'`"
+      fi
       no_edit=t
       shift
       ;;
   --m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-      log_given=t$log_given
-      log_message=`expr "$1" : '-[^=]*=\(.*\)'`
+      log_given=m$log_given
+      if test "$log_message" = ''
+      then
+          log_message=`expr "$1" : '-[^=]*=\(.*\)'`
+      else
+          log_message="$log_message
+
+`expr "$1" : '-[^=]*=\(.*\)'`"
+      fi
       no_edit=t
       shift
       ;;
@@ -378,7 +399,9 @@ esac
 
 case "$log_given" in
 tt*)
-  die "Only one of -c/-C/-F/-m can be used." ;;
+  die "Only one of -c/-C/-F can be used." ;;
+*tm*|*mt*)
+  die "Option -m cannot be combined with -c/-C/-F." ;;
 esac
 
 case "$#,$also,$only,$amend" in
diff --git a/git-send-email.perl b/git-send-email.perl
index 0e368fff0cd..ed1d89b3f73 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -21,7 +21,6 @@ use warnings;
 use Term::ReadLine;
 use Getopt::Long;
 use Data::Dumper;
-use Net::SMTP;
 
 # most mail servers generate the Date: header, but not all...
 $ENV{LC_ALL} = 'C';
@@ -394,6 +393,7 @@ X-Mailer: git-send-email $gitversion
 		print $sm "$header\n$message";
 		close $sm or die $?;
 	} else {
+		require Net::SMTP;
 		$smtp ||= Net::SMTP->new( $smtp_server );
 		$smtp->mail( $from ) or die $smtp->message;
 		$smtp->to( @recipients ) or die $smtp->message;
diff --git a/gitk b/gitk
index 4aa57c01ce5..101cf9bd9ff 100755
--- a/gitk
+++ b/gitk
@@ -34,10 +34,10 @@ proc start_rev_list {view} {
 	set order "--date-order"
     }
     if {[catch {
-	set fd [open [concat | git-rev-list --header $order \
+	set fd [open [concat | git rev-list --header $order \
 			  --parents --boundary --default HEAD $args] r]
     } err]} {
-	puts stderr "Error executing git-rev-list: $err"
+	puts stderr "Error executing git rev-list: $err"
 	exit 1
     }
     set commfd($view) $fd
@@ -94,10 +94,10 @@ proc getcommitlines {fd view}  {
 	    }
 	    if {[string range $err 0 4] == "usage"} {
 		set err "Gitk: error reading commits$fv:\
-			bad arguments to git-rev-list."
+			bad arguments to git rev-list."
 		if {$viewname($view) eq "Command line"} {
 		    append err \
-			"  (Note: arguments to gitk are passed to git-rev-list\
+			"  (Note: arguments to gitk are passed to git rev-list\
 			 to allow selection of commits to be displayed.)"
 		}
 	    } else {
@@ -148,7 +148,7 @@ proc getcommitlines {fd view}  {
 	    if {[string length $shortcmit] > 80} {
 		set shortcmit "[string range $shortcmit 0 80]..."
 	    }
-	    error_popup "Can't parse git-rev-list output: {$shortcmit}"
+	    error_popup "Can't parse git rev-list output: {$shortcmit}"
 	    exit 1
 	}
 	set id [lindex $ids 0]
@@ -217,7 +217,7 @@ proc doupdate {} {
 }
 
 proc readcommit {id} {
-    if {[catch {set contents [exec git-cat-file commit $id]}]} return
+    if {[catch {set contents [exec git cat-file commit $id]}]} return
     parsecommit $id $contents 0
 }
 
@@ -276,8 +276,8 @@ proc parsecommit {id contents listed} {
 	set headline $comment
     }
     if {!$listed} {
-	# git-rev-list indents the comment by 4 spaces;
-	# if we got this via git-cat-file, add the indentation
+	# git rev-list indents the comment by 4 spaces;
+	# if we got this via git cat-file, add the indentation
 	set newcomment {}
 	foreach line [split $comment "\n"] {
 	    append newcomment "    "
@@ -337,14 +337,14 @@ proc readrefs {} {
 	    set type {}
 	    set tag {}
 	    catch {
-		set commit [exec git-rev-parse "$id^0"]
+		set commit [exec git rev-parse "$id^0"]
 		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
@@ -357,21 +357,21 @@ proc readrefs {} {
     close $refd
 }
 
-proc show_error {w msg} {
+proc show_error {w top msg} {
     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 "destroy $w"
+    button $w.ok -text OK -command "destroy $top"
     pack $w.ok -side bottom -fill x
-    bind $w <Visibility> "grab $w; focus $w"
-    bind $w <Key-Return> "destroy $w"
-    tkwait window $w
+    bind $top <Visibility> "grab $top; focus $top"
+    bind $top <Key-Return> "destroy $top"
+    tkwait window $top
 }
 
 proc error_popup msg {
     set w .error
     toplevel $w
     wm transient $w .
-    show_error $w $msg
+    show_error $w $w $msg
 }
 
 proc makewindow {} {
@@ -380,7 +380,7 @@ proc makewindow {} {
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
-    global rowctxmenu mergemax
+    global rowctxmenu mergemax wrapcomment
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
@@ -527,6 +527,7 @@ proc makewindow {} {
     pack $ctext -side left -fill both -expand 1
     .ctop.cdet add .ctop.cdet.left
 
+    $ctext tag conf comment -wrap $wrapcomment
     $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
     $ctext tag conf hunksep -fore blue
     $ctext tag conf d0 -fore red
@@ -696,7 +697,7 @@ proc savestuff {w} {
     global stuffsaved findmergefiles maxgraphpct
     global maxwidth
     global viewname viewfiles viewargs viewperm nextviewnum
-    global cmitmode
+    global cmitmode wrapcomment
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
@@ -709,6 +710,7 @@ proc savestuff {w} {
 	puts $f [list set maxgraphpct $maxgraphpct]
 	puts $f [list set maxwidth $maxwidth]
 	puts $f [list set cmitmode $cmitmode]
+	puts $f [list set wrapcomment $wrapcomment]
 	puts $f "set geometry(width) [winfo width .ctop]"
 	puts $f "set geometry(height) [winfo height .ctop]"
 	puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
@@ -1285,7 +1287,7 @@ proc vieweditor {top n title} {
     checkbutton $top.perm -text "Remember this view" -variable newviewperm($n)
     grid $top.perm - -pady 5 -sticky w
     message $top.al -aspect 1000 -font $uifont \
-	-text "Commits to include (arguments to git-rev-list):"
+	-text "Commits to include (arguments to git rev-list):"
     grid $top.al - -sticky w -pady 5
     entry $top.args -width 50 -textvariable newviewargs($n) \
 	-background white
@@ -2939,7 +2941,7 @@ proc findpatches {} {
     }
 
     if {[catch {
-	set f [open [list | git-diff-tree --stdin -s -r -S$findstring \
+	set f [open [list | git diff-tree --stdin -s -r -S$findstring \
 			 << $inputids] r]
     } err]} {
 	error_popup "Error starting search process: $err"
@@ -2971,7 +2973,7 @@ proc readfindproc {} {
 	return
     }
     if {![regexp {^[0-9a-f]{40}} $line id]} {
-	error_popup "Can't parse git-diff-tree output: $line"
+	error_popup "Can't parse git diff-tree output: $line"
 	stopfindproc
 	return
     }
@@ -3036,10 +3038,10 @@ proc findfiles {} {
 	if {$l == $findstartline} break
     }
 
-    # start off a git-diff-tree process if needed
+    # start off a git diff-tree process if needed
     if {$diffsneeded ne {}} {
 	if {[catch {
-	    set df [open [list | git-diff-tree -r --stdin << $diffsneeded] r]
+	    set df [open [list | git diff-tree -r --stdin << $diffsneeded] r]
 	} err ]} {
 	    error_popup "Error starting search process: $err"
 	    return
@@ -3069,7 +3071,7 @@ proc readfilediffs {df} {
 	    if {[catch {close $df} err]} {
 		stopfindproc
 		bell
-		error_popup "Error in git-diff-tree: $err"
+		error_popup "Error in git diff-tree: $err"
 	    } elseif {[info exists findid]} {
 		set id $findid
 		stopfindproc
@@ -3096,7 +3098,7 @@ proc donefilediff {} {
     if {[info exists fdiffid]} {
 	while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffid
 	       && $fdiffpos < [llength $fdiffsneeded]} {
-	    # git-diff-tree doesn't output anything for a commit
+	    # git diff-tree doesn't output anything for a commit
 	    # which doesn't change anything
 	    set nullid [lindex $fdiffsneeded $fdiffpos]
 	    set treediffs($nullid) {}
@@ -3213,8 +3215,11 @@ proc selcanvline {w x y} {
 
 proc commit_descriptor {p} {
     global commitinfo
+    if {![info exists commitinfo($p)]} {
+	getcommit $p
+    }
     set l "..."
-    if {[info exists commitinfo($p)]} {
+    if {[llength $commitinfo($p)] > 1} {
 	set l [lindex $commitinfo($p) 0]
     }
     return "$p ($l)"
@@ -3222,11 +3227,11 @@ proc commit_descriptor {p} {
 
 # append some text to the ctext widget, and make any SHA1 ID
 # that we know about be a clickable link.
-proc appendwithlinks {text} {
+proc appendwithlinks {text tags} {
     global ctext commitrow linknum curview
 
     set start [$ctext index "end - 1c"]
-    $ctext insert end $text
+    $ctext insert end $text $tags
     $ctext insert end "\n"
     set links [regexp -indices -all -inline {[0-9a-f]{40}} $text]
     foreach l $links {
@@ -3354,7 +3359,7 @@ proc selectline {l isnew} {
 	$ctext insert end "\n"
     }
  
-    set comment {}
+    set headers {}
     set olds [lindex $parentlist $l]
     if {[llength $olds] > 1} {
 	set np 0
@@ -3365,23 +3370,22 @@ proc selectline {l isnew} {
 		set tag m$np
 	    }
 	    $ctext insert end "Parent: " $tag
-	    appendwithlinks [commit_descriptor $p]
+	    appendwithlinks [commit_descriptor $p] {}
 	    incr np
 	}
     } else {
 	foreach p $olds {
-	    append comment "Parent: [commit_descriptor $p]\n"
+	    append headers "Parent: [commit_descriptor $p]\n"
 	}
     }
 
     foreach c [lindex $childlist $l] {
-	append comment "Child:  [commit_descriptor $c]\n"
+	append headers "Child:  [commit_descriptor $c]\n"
     }
-    append comment "\n"
-    append comment [lindex $info 5]
 
     # make anything that looks like a SHA1 ID be a clickable link
-    appendwithlinks $comment
+    appendwithlinks $headers {}
+    appendwithlinks [lindex $info 5] {comment}
 
     $ctext tag delete Comments
     $ctext tag remove found 1.0 end
@@ -3426,6 +3430,7 @@ proc selnextpage {dir} {
 	set lpp 1
     }
     allcanvs yview scroll [expr {$dir * $lpp}] units
+    drawvisible
     if {![info exists selectedline]} return
     set l [expr {$selectedline + $dir * $lpp}]
     if {$l < 0} {
@@ -3521,7 +3526,7 @@ proc gettree {id} {
     catch {unset diffmergeid}
     if {![info exists treefilelist($id)]} {
 	if {![info exists treepending]} {
-	    if {[catch {set gtf [open [concat | git-ls-tree -r $id] r]}]} {
+	    if {[catch {set gtf [open [concat | git ls-tree -r $id] r]}]} {
 		return
 	    }
 	    set treepending $id
@@ -3569,7 +3574,7 @@ proc showfile {f} {
 	return
     }
     set blob [lindex $treeidlist($diffids) $i]
-    if {[catch {set bf [open [concat | git-cat-file blob $blob] r]} err]} {
+    if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
 	puts "oops, error reading blob $blob: $err"
 	return
     }
@@ -3611,7 +3616,7 @@ proc mergediff {id l} {
     set diffids $id
     # this doesn't seem to actually affect anything...
     set env(GIT_DIFF_OPTS) $diffopts
-    set cmd [concat | git-diff-tree --no-commit-id --cc $id]
+    set cmd [concat | git diff-tree --no-commit-id --cc $id]
     if {[catch {set mdf [open $cmd r]} err]} {
 	error_popup "Error getting merge diffs: $err"
 	return
@@ -3723,7 +3728,7 @@ proc gettreediffs {ids} {
     set treepending $ids
     set treediff {}
     if {[catch \
-	 {set gdtf [open [concat | git-diff-tree --no-commit-id -r $ids] r]} \
+	 {set gdtf [open [concat | git diff-tree --no-commit-id -r $ids] r]} \
 	]} return
     fconfigure $gdtf -blocking 0
     fileevent $gdtf readable [list gettreediffline $gdtf $ids]
@@ -3759,7 +3764,7 @@ proc getblobdiffs {ids} {
     global nextupdate diffinhdr treediffs
 
     set env(GIT_DIFF_OPTS) $diffopts
-    set cmd [concat | git-diff-tree --no-commit-id -r -p -C $ids]
+    set cmd [concat | git diff-tree --no-commit-id -r -p -C $ids]
     if {[catch {set bdf [open $cmd r]} err]} {
 	puts "error getting diffs: $err"
 	return
@@ -4296,7 +4301,7 @@ proc mkpatchgo {} {
     set oldid [$patchtop.fromsha1 get]
     set newid [$patchtop.tosha1 get]
     set fname [$patchtop.fname get]
-    if {[catch {exec git-diff-tree -p $oldid $newid >$fname &} err]} {
+    if {[catch {exec git diff-tree -p $oldid $newid >$fname &} err]} {
 	error_popup "Error creating patch: $err"
     }
     catch {destroy $patchtop}
@@ -4504,7 +4509,7 @@ proc showtag {tag isnew} {
     } else {
 	set text "Tag: $tag\nId:  $tagids($tag)"
     }
-    appendwithlinks $text
+    appendwithlinks $text {}
     $ctext conf -state disabled
     init_flist {}
 }
@@ -4863,11 +4868,11 @@ proc tcl_encoding {enc} {
 # defaults...
 set datemode 0
 set diffopts "-U 5 -p"
-set wrcomcmd "git-diff-tree --stdin -p --pretty"
+set wrcomcmd "git diff-tree --stdin -p --pretty"
 
 set gitencoding {}
 catch {
-    set gitencoding [exec git-repo-config --get i18n.commitencoding]
+    set gitencoding [exec git repo-config --get i18n.commitencoding]
 }
 if {$gitencoding == ""} {
     set gitencoding "utf-8"
@@ -4890,6 +4895,7 @@ set downarrowlen 7
 set mingaplen 30
 set flistmode "flat"
 set cmitmode "patch"
+set wrapcomment "none"
 
 set colors {green red blue magenta darkgrey brown orange}
 
@@ -4911,7 +4917,7 @@ foreach arg $argv {
 # check that we can find a .git directory somewhere...
 set gitdir [gitdir]
 if {![file isdirectory $gitdir]} {
-    show_error . "Cannot find the git directory \"$gitdir\"."
+    show_error {} . "Cannot find the git directory \"$gitdir\"."
     exit 1
 }
 
@@ -4922,7 +4928,7 @@ if {$i >= 0} {
     set revtreeargs [lrange $revtreeargs 0 [expr {$i - 1}]]
 } elseif {$revtreeargs ne {}} {
     if {[catch {
-	set f [eval exec git-rev-parse --no-revs --no-flags $revtreeargs]
+	set f [eval exec git rev-parse --no-revs --no-flags $revtreeargs]
 	set cmdline_files [split $f "\n"]
 	set n [llength $cmdline_files]
 	set revtreeargs [lrange $revtreeargs 0 end-$n]
@@ -4931,9 +4937,9 @@ if {$i >= 0} {
 	# so look for "fatal:".
 	set i [string first "fatal:" $err]
 	if {$i > 0} {
-	    set err [string range [expr {$i + 6}] end]
+	    set err [string range $err [expr {$i + 6}] end]
 	}
-	show_error . "Bad arguments to gitk:\n$err"
+	show_error {} . "Bad arguments to gitk:\n$err"
 	exit 1
     }
 }
diff --git a/http-fetch.c b/http-fetch.c
index 861644b27ee..178f1ee311d 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -1269,10 +1269,10 @@ int main(int argc, char **argv)
 	if (pull(commit_id))
 		rc = 1;
 
-	curl_slist_free_all(no_pragma_header);
-
 	http_cleanup();
 
+	curl_slist_free_all(no_pragma_header);
+
 	if (corrupt_object_found) {
 		fprintf(stderr,
 "Some loose object were found to be corrupt, but they might be just\n"
diff --git a/http.c b/http.c
index 0cb42a85d14..146cf7bf36d 100644
--- a/http.c
+++ b/http.c
@@ -25,7 +25,6 @@ long curl_low_speed_limit = -1;
 long curl_low_speed_time = -1;
 
 struct curl_slist *pragma_header;
-struct curl_slist *no_range_header;
 
 struct active_request_slot *active_queue_head = NULL;
 
@@ -208,7 +207,6 @@ void http_init(void)
 	curl_global_init(CURL_GLOBAL_ALL);
 
 	pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
-	no_range_header = curl_slist_append(no_range_header, "Range:");
 
 #ifdef USE_CURL_MULTI
 	{
@@ -344,9 +342,14 @@ struct active_request_slot *get_active_slot(void)
 	slot->finished = NULL;
 	slot->callback_data = NULL;
 	slot->callback_func = NULL;
+	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
-	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_range_header);
 	curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
+	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
+	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
+	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
+	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
+	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 
 	return slot;
 }
diff --git a/sha1_file.c b/sha1_file.c
index f77c18934af..aea0f40d57a 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -617,6 +617,12 @@ static void prepare_packed_git_one(char *objdir, int local)
 
 		/* we have .idx.  Is it a file we can map? */
 		strcpy(path + len, de->d_name);
+		for (p = packed_git; p; p = p->next) {
+			if (!memcmp(path, p->pack_name, len + namelen - 4))
+				break;
+		}
+		if (p)
+			continue;
 		p = add_packed_git(path, len + namelen, local);
 		if (!p)
 			continue;
@@ -626,12 +632,12 @@ static void prepare_packed_git_one(char *objdir, int local)
 	closedir(dir);
 }
 
+static int prepare_packed_git_run_once = 0;
 void prepare_packed_git(void)
 {
-	static int run_once = 0;
 	struct alternate_object_database *alt;
 
-	if (run_once)
+	if (prepare_packed_git_run_once)
 		return;
 	prepare_packed_git_one(get_object_directory(), 1);
 	prepare_alt_odb();
@@ -640,7 +646,13 @@ void prepare_packed_git(void)
 		prepare_packed_git_one(alt->base, 0);
 		alt->name[-1] = '/';
 	}
-	run_once = 1;
+	prepare_packed_git_run_once = 1;
+}
+
+static void reprepare_packed_git(void)
+{
+	prepare_packed_git_run_once = 0;
+	prepare_packed_git();
 }
 
 int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long size, const char *type)
@@ -1212,9 +1224,12 @@ int sha1_object_info(const unsigned char *sha1, char *type, unsigned long *sizep
 	if (!map) {
 		struct pack_entry e;
 
-		if (!find_pack_entry(sha1, &e))
-			return error("unable to find %s", sha1_to_hex(sha1));
-		return packed_object_info(&e, type, sizep);
+		if (find_pack_entry(sha1, &e))
+			return packed_object_info(&e, type, sizep);
+		reprepare_packed_git();
+		if (find_pack_entry(sha1, &e))
+			return packed_object_info(&e, type, sizep);
+		return error("unable to find %s", sha1_to_hex(sha1));
 	}
 	if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
 		status = error("unable to unpack %s header",
@@ -1256,6 +1271,9 @@ void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size
 		munmap(map, mapsize);
 		return buf;
 	}
+	reprepare_packed_git();
+	if (find_pack_entry(sha1, &e))
+		return read_packed_sha1(sha1, type, size);
 	return NULL;
 }