diff --git a/Documentation/RelNotes-1.5.1.3.txt b/Documentation/RelNotes-1.5.1.3.txt
new file mode 100644
index 0000000000..9a4b069ccc
--- /dev/null
+++ b/Documentation/RelNotes-1.5.1.3.txt
@@ -0,0 +1,38 @@
+GIT v1.5.1.3 Release Notes (draft)
+==========================
+
+Fixes since v1.5.1.2
+--------------------
+
+* Bugfixes
+
+  - git-add tried to optimize by finding common leading
+    directories across its arguments but botched, causing very
+    confused behaviour.
+
+  - unofficial rpm.spec file shipped with git was letting
+    ETC_GITCONFIG set to /usr/etc/gitconfig.  Tweak the official
+    Makefile to make it harder for distro people to make the
+    same mistake, by setting the variable to /etc/gitconfig if
+    prefix is set to /usr.
+
+  - git-svn inconsistently stripped away username from the URL
+    only when svnsync_props was in use.
+
+  - git-send-email was not quoting recipient names that have
+    period '.' in them.  Also it did not allow overriding
+    envelope sender, which made it impossible to send patches to
+    certain subscriber-only lists.
+
+  - built-in write_tree() routine had a sequence that renamed a
+    file that is still open, which some systems did not like.
+
+  - when memory is very tight, sliding mmap code to read
+    packfiles incorrectly closed the fd that was still being
+    used to read the pack.
+
+---
+exec >/var/tmp/1
+O=v1.5.1.2-23-gbf7af11
+echo O=`git describe refs/heads/maint`
+git shortlog --no-merges $O..refs/heads/maint
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 682313e95d..795db873fc 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -85,6 +85,15 @@ The --cc option must be repeated for each user you want on the cc list.
 	Do not add the From: address to the cc: list, if it shows up in a From:
 	line.
 
+--dry-run::
+	Do everything except actually send the emails.
+
+--envelope-sender::
+	Specify the envelope sender used to send the emails.
+	This is useful if your default address is not the address that is
+	subscribed to a list. If you use the sendmail binary, you must have
+	suitable privileges for the -f parameter.
+
 --to::
 	Specify the primary recipient of the emails generated.
 	Generally, this will be the upstream maintainer of the
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index c88bbd1b9b..391de53972 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -36,8 +36,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
 			die("git-write-tree: error building trees");
 		if (0 <= newfd) {
 			if (!write_cache(newfd, active_cache, active_nr)
-					&& !close(newfd))
+					&& !close(newfd)) {
 				commit_lock_file(lock_file);
+				newfd = -1;
+			}
 		}
 		/* Not being able to write is fine -- we are only interested
 		 * in updating the cache-tree part, and if the next caller
@@ -55,6 +57,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
 	else
 		hashcpy(sha1, active_cache_tree->sha1);
 
+	if (0 <= newfd)
+		close(newfd);
 	rollback_lock_file(lock_file);
 
 	return 0;
diff --git a/git-compat-util.h b/git-compat-util.h
index 0b6d74d4d7..2c84016ac9 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -164,13 +164,13 @@ extern size_t gitstrlcpy(char *, const char *, size_t);
 extern uintmax_t gitstrtoumax(const char *, char **, int);
 #endif
 
-extern void release_pack_memory(size_t);
+extern void release_pack_memory(size_t, int);
 
 static inline char* xstrdup(const char *str)
 {
 	char *ret = strdup(str);
 	if (!ret) {
-		release_pack_memory(strlen(str) + 1);
+		release_pack_memory(strlen(str) + 1, -1);
 		ret = strdup(str);
 		if (!ret)
 			die("Out of memory, strdup failed");
@@ -184,7 +184,7 @@ static inline void *xmalloc(size_t size)
 	if (!ret && !size)
 		ret = malloc(1);
 	if (!ret) {
-		release_pack_memory(size);
+		release_pack_memory(size, -1);
 		ret = malloc(size);
 		if (!ret && !size)
 			ret = malloc(1);
@@ -203,7 +203,7 @@ static inline void *xrealloc(void *ptr, size_t size)
 	if (!ret && !size)
 		ret = realloc(ptr, 1);
 	if (!ret) {
-		release_pack_memory(size);
+		release_pack_memory(size, -1);
 		ret = realloc(ptr, size);
 		if (!ret && !size)
 			ret = realloc(ptr, 1);
@@ -219,7 +219,7 @@ static inline void *xcalloc(size_t nmemb, size_t size)
 	if (!ret && (!nmemb || !size))
 		ret = calloc(1, 1);
 	if (!ret) {
-		release_pack_memory(nmemb * size);
+		release_pack_memory(nmemb * size, -1);
 		ret = calloc(nmemb, size);
 		if (!ret && (!nmemb || !size))
 			ret = calloc(1, 1);
@@ -236,7 +236,7 @@ static inline void *xmmap(void *start, size_t length,
 	if (ret == MAP_FAILED) {
 		if (!length)
 			return NULL;
-		release_pack_memory(length);
+		release_pack_memory(length, fd);
 		ret = mmap(start, length, prot, flags, fd, offset);
 		if (ret == MAP_FAILED)
 			die("Out of memory? mmap failed: %s", strerror(errno));
diff --git a/git-send-email.perl b/git-send-email.perl
index d6b15480dc..a6e3e02619 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -77,6 +77,10 @@ Options:
    --quiet	  Make git-send-email less verbose.  One line per email
                   should be all that is output.
 
+   --dry-run	  Do everything except actually send the emails.
+
+   --envelope-sender	Specify the envelope sender used to send the emails.
+
 EOT
 	exit(1);
 }
@@ -137,6 +141,7 @@ my (@to,@cc,@initial_cc,@bcclist,@xh,
 my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc,
 	$dry_run) = (1, 0, 0, 0, 0);
 my $smtp_server;
+my $envelope_sender;
 
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@@ -175,6 +180,7 @@ my $rc = GetOptions("from=s" => \$from,
 		    "suppress-from" => \$suppress_from,
 		    "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc,
 		    "dry-run" => \$dry_run,
+		    "envelope-sender=s" => \$envelope_sender,
 	 );
 
 unless ($rc) {
@@ -268,6 +274,7 @@ sub expand_aliases {
 }
 
 @to = expand_aliases(@to);
+@to = (map { sanitize_address_rfc822($_) } @to);
 @initial_cc = expand_aliases(@initial_cc);
 @bcclist = expand_aliases(@bcclist);
 
@@ -377,7 +384,7 @@ if (@files) {
 }
 
 # Variables we set as part of the loop over files
-our ($message_id, $cc, %mail, $subject, $reply_to, $references, $message);
+our ($message_id, %mail, $subject, $reply_to, $references, $message);
 
 sub extract_valid_address {
 	my $address = shift;
@@ -418,7 +425,6 @@ sub make_message_id
 
 
 
-$cc = "";
 $time = time - scalar $#files;
 
 sub unquote_rfc2047 {
@@ -430,26 +436,37 @@ sub unquote_rfc2047 {
 	return "$_";
 }
 
+# If an address contains a . in the name portion, the name must be quoted.
+sub sanitize_address_rfc822
+{
+	my ($recipient) = @_;
+	my ($recipient_name) = ($recipient =~ /^(.*?)\s+</);
+	if ($recipient_name && $recipient_name =~ /\./ && $recipient_name !~ /^".*"$/) {
+		my ($name, $addr) = ($recipient =~ /^(.*?)(\s+<.*)/);
+		$recipient = "\"$name\"$addr";
+	}
+	return $recipient;
+}
+
 sub send_message
 {
 	my @recipients = unique_email_list(@to);
+	@cc = (map { sanitize_address_rfc822($_) } @cc);
 	my $to = join (",\n\t", @recipients);
 	@recipients = unique_email_list(@recipients,@cc,@bcclist);
+	@recipients = (map { extract_valid_address($_) } @recipients);
 	my $date = format_2822_time($time++);
 	my $gitversion = '@@GIT_VERSION@@';
 	if ($gitversion =~ m/..GIT_VERSION../) {
 	    $gitversion = Git::version();
 	}
 
-	my ($author_name) = ($from =~ /^(.*?)\s+</);
-	if ($author_name && $author_name =~ /\./ && $author_name !~ /^".*"$/) {
-		my ($name, $addr) = ($from =~ /^(.*?)(\s+<.*)/);
-		$from = "\"$name\"$addr";
-	}
+	my $cc = join(", ", unique_email_list(@cc));
 	my $ccline = "";
 	if ($cc ne '') {
 		$ccline = "\nCc: $cc";
 	}
+	$from = sanitize_address_rfc822($from);
 	my $header = "From: $from
 To: $to${ccline}
 Subject: $subject
@@ -466,22 +483,27 @@ X-Mailer: git-send-email $gitversion
 		$header .= join("\n", @xh) . "\n";
 	}
 
+	my @sendmail_parameters = ('-i', @recipients);
+	my $raw_from = $from;
+	$raw_from = $envelope_sender if (defined $envelope_sender);
+	$raw_from = extract_valid_address($raw_from);
+	unshift (@sendmail_parameters,
+			'-f', $raw_from) if(defined $envelope_sender);
+
 	if ($dry_run) {
 		# We don't want to send the email.
 	} elsif ($smtp_server =~ m#^/#) {
 		my $pid = open my $sm, '|-';
 		defined $pid or die $!;
 		if (!$pid) {
-			exec($smtp_server,'-i',
-			     map { extract_valid_address($_) }
-			     @recipients) or die $!;
+			exec($smtp_server, @sendmail_parameters) or die $!;
 		}
 		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->mail( $raw_from ) or die $smtp->message;
 		$smtp->to( @recipients ) or die $smtp->message;
 		$smtp->data or die $smtp->message;
 		$smtp->datasend("$header\n$message") or die $smtp->message;
@@ -489,13 +511,15 @@ X-Mailer: git-send-email $gitversion
 		$smtp->ok or die "Failed to send $subject\n".$smtp->message;
 	}
 	if ($quiet) {
-		printf "Sent %s\n", $subject;
+		printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
 	} else {
-		print "OK. Log says:\nDate: $date\n";
-		if ($smtp) {
+		print (($dry_run ? "Dry-" : "")."OK. Log says:\nDate: $date\n");
+		if ($smtp_server !~ m#^/#) {
 			print "Server: $smtp_server\n";
+			print "MAIL FROM:<$raw_from>\n";
+			print "RCPT TO:".join(',',(map { "<$_>" } @recipients))."\n";
 		} else {
-			print "Sendmail: $smtp_server\n";
+			print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
 		}
 		print "From: $from\nSubject: $subject\nCc: $cc\nTo: $to\n\n";
 		if ($smtp) {
@@ -590,7 +614,6 @@ foreach my $t (@files) {
 		$message = "From: $author_not_sender\n\n$message";
 	}
 
-	$cc = join(", ", unique_email_list(@cc));
 
 	send_message();
 
diff --git a/git-svn.perl b/git-svn.perl
index 077d6b3a13..7b5f8ab3be 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -771,19 +771,19 @@ sub cmt_metadata {
 sub working_head_info {
 	my ($head, $refs) = @_;
 	my ($fh, $ctx) = command_output_pipe('rev-list', $head);
-	while (<$fh>) {
-		chomp;
-		my ($url, $rev, $uuid) = cmt_metadata($_);
+	while (my $hash = <$fh>) {
+		chomp($hash);
+		my ($url, $rev, $uuid) = cmt_metadata($hash);
 		if (defined $url && defined $rev) {
 			if (my $gs = Git::SVN->find_by_url($url)) {
 				my $c = $gs->rev_db_get($rev);
-				if ($c && $c eq $_) {
+				if ($c && $c eq $hash) {
 					close $fh; # break the pipe
 					return ($url, $rev, $uuid, $gs);
 				}
 			}
 		}
-		unshift @$refs, $_ if $refs;
+		unshift @$refs, $hash if $refs;
 	}
 	command_close_pipe($fh, $ctx);
 	(undef, undef, undef, undef);
@@ -1064,7 +1064,10 @@ sub init_remote_config {
 
 sub find_by_url { # repos_root and, path are optional
 	my ($class, $full_url, $repos_root, $path) = @_;
+
 	return undef unless defined $full_url;
+	remove_username($full_url);
+	remove_username($repos_root) if defined $repos_root;
 	my $remotes = read_all_remotes();
 	if (defined $full_url && defined $repos_root && !defined $path) {
 		$path = $full_url;
@@ -1072,6 +1075,7 @@ sub find_by_url { # repos_root and, path are optional
 	}
 	foreach my $repo_id (keys %$remotes) {
 		my $u = $remotes->{$repo_id}->{url} or next;
+		remove_username($u);
 		next if defined $repos_root && $repos_root ne $u;
 
 		my $fetch = $remotes->{$repo_id}->{fetch} || {};
diff --git a/sha1_file.c b/sha1_file.c
index 06426640ea..32244d704e 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -549,7 +549,7 @@ static void scan_windows(struct packed_git *p,
 	}
 }
 
-static int unuse_one_window(struct packed_git *current)
+static int unuse_one_window(struct packed_git *current, int keep_fd)
 {
 	struct packed_git *p, *lru_p = NULL;
 	struct pack_window *lru_w = NULL, *lru_l = NULL;
@@ -565,7 +565,7 @@ static int unuse_one_window(struct packed_git *current)
 			lru_l->next = lru_w->next;
 		else {
 			lru_p->windows = lru_w->next;
-			if (!lru_p->windows && lru_p != current) {
+			if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
 				close(lru_p->pack_fd);
 				lru_p->pack_fd = -1;
 			}
@@ -577,10 +577,10 @@ static int unuse_one_window(struct packed_git *current)
 	return 0;
 }
 
-void release_pack_memory(size_t need)
+void release_pack_memory(size_t need, int fd)
 {
 	size_t cur = pack_mapped;
-	while (need >= (cur - pack_mapped) && unuse_one_window(NULL))
+	while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
 		; /* nothing */
 }
 
@@ -713,7 +713,7 @@ unsigned char* use_pack(struct packed_git *p,
 			win->len = (size_t)len;
 			pack_mapped += win->len;
 			while (packed_git_limit < pack_mapped
-				&& unuse_one_window(p))
+				&& unuse_one_window(p, p->pack_fd))
 				; /* nothing */
 			win->base = xmmap(NULL, win->len,
 				PROT_READ, MAP_PRIVATE,