Merge branch 'stable'

* stable:
  Automatically install Gerrit Code Review's commit-msg hook
  Fail sync when encountering "N commits behind."
  Check that we are not overwriting a local repository when syncing.
  Honor url.insteadOf when setting up SSH control master connection
  sync: Fix split call on malformed email addresses
  Fixing project renaming bug.

Conflicts:
	hooks/commit-msg
	project.py
	subcmds/sync.py

Change-Id: I5eaf8fef8cbe4a95d124368112293a9ca64325bf
diff --git a/git_config.py b/git_config.py
index b628821..4a42c04 100644
--- a/git_config.py
+++ b/git_config.py
@@ -461,8 +461,30 @@
                      self._Get('fetch', all=True))
     self._review_protocol = None
 
+  def _InsteadOf(self):
+    globCfg = GitConfig.ForUser()
+    urlList = globCfg.GetSubSections('url')
+    longest = ""
+    longestUrl = ""
+
+    for url in urlList:
+      key = "url." + url + ".insteadOf"
+      insteadOfList = globCfg.GetString(key, all=True)
+
+      for insteadOf in insteadOfList:
+        if self.url.startswith(insteadOf) \
+        and len(insteadOf) > len(longest):
+          longest = insteadOf
+          longestUrl = url
+
+    if len(longest) == 0:
+      return self.url
+
+    return self.url.replace(longest, longestUrl, 1)
+
   def PreConnectFetch(self):
-    return _preconnect(self.url)
+    connectionUrl = self._InsteadOf()
+    return _preconnect(connectionUrl)
 
   @property
   def ReviewProtocol(self):
diff --git a/hooks/commit-msg b/hooks/commit-msg
index fd76c07..712921c 100755
--- a/hooks/commit-msg
+++ b/hooks/commit-msg
@@ -1,23 +1,24 @@
 #!/bin/sh
-# From Gerrit Code Review v2.0.19.1-4-g21d307b
+# From Gerrit Code Review 2.1.2-rc2-33-g7e30c72
 #
 # Part of Gerrit Code Review (http://code.google.com/p/gerrit/)
 #
 # Copyright (C) 2009 The Android Open Source Project
-# 
+#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-# 
+#
 # http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-# 
+#
 
+CHANGE_ID_AFTER="Bug|Issue"
 MSG="$1"
 
 # Check for, and add if missing, a unique Change-Id
@@ -42,22 +43,43 @@
 	fi
 
 	id=$(_gen_ChangeId)
-	out="$MSG.OUT"
-	ftt="$MSG.FTT"
-	sed -e  '2,${
-			/^[A-Za-z][A-Za-z0-9-]*: /,$d
-		}' <"$MSG" >"$out"
-	sed -ne '2,${
-			/^[A-Za-z][A-Za-z0-9-]*: /,$p
-		}' <"$MSG" >"$ftt"
-	if ! test -s "$ftt"
-	then
-		echo >>"$out"
-	fi
-	echo "Change-Id: I$id" >>"$out"
-	cat "$ftt" >>"$out"
-	mv -f "$out" "$MSG"
-	rm -f "$out" "$ftt"
+	perl -e '
+		$MSG = shift;
+		$id = shift;
+		$CHANGE_ID_AFTER = shift;
+
+		undef $/;
+		open(I, $MSG); $_ = <I>; close I;
+		s|^diff --git a/.*||ms;
+		s|^#.*$||mg;
+		exit unless $_;
+
+		@message = split /\n/;
+		$haveFooter = 0;
+		$startFooter = @message;
+		for($line = @message - 1; $line >= 0; $line--) {
+			$_ = $message[$line];
+
+			($haveFooter++, next) if /^[a-zA-Z0-9-]+:/;
+			next if /^[ []/;
+			$startFooter = $line if ($haveFooter && /^\r?$/);
+			last;
+		}
+
+		@footer = @message[$startFooter+1..@message];
+		@message = @message[0..$startFooter];
+		push(@footer, "") unless @footer;
+
+		for ($line = 0; $line < @footer; $line++) {
+			$_ = $footer[$line];
+			next if /^($CHANGE_ID_AFTER):/i;
+			last;
+		}
+		splice(@footer, $line, 0, "Change-Id: I$id");
+
+		$_ = join("\n", @message, @footer);
+		open(O, ">$MSG"); print O; close O;
+	' "$MSG" "$id" "$CHANGE_ID_AFTER"
 }
 _gen_ChangeIdInput() {
 	echo "tree $(git write-tree)"
diff --git a/project.py b/project.py
index 89f94f2..5a143a7 100644
--- a/project.py
+++ b/project.py
@@ -706,10 +706,9 @@
           # commits are not yet merged upstream.  We do not want
           # to rewrite the published commits so we punt.
           #
-          syncbuf.info(self,
-                       "branch %s is published but is now %d commits behind",
-                       branch.name,
-                       len(upstream_gain))
+          syncbuf.fail(self,
+                       "branch %s is published (but not merged) and is now %d commits behind"
+                       % (branch.name, len(upstream_gain)))
         return
       elif pub == head:
         # All published commits are merged, and thus we are a
@@ -728,7 +727,7 @@
     last_mine = None
     cnt_mine = 0
     for commit in local_changes:
-      commit_id, committer_email = commit.split(' ', 2)
+      commit_id, committer_email = commit.split(' ', 1)
       if committer_email == self.UserEmail:
         last_mine = commit_id
         cnt_mine += 1
@@ -1132,7 +1131,10 @@
         dst = os.path.join(dotgit, name)
         if relink:
           os.remove(dst)
-        os.symlink(relpath(src, dst), dst)
+        if os.path.islink(dst) or not os.path.exists(dst):
+          os.symlink(relpath(src, dst), dst)
+        else:
+          raise GitError('cannot overwrite a local work tree')
       except OSError, e:
         if e.errno == errno.EPERM:
           raise GitError('filesystem must support symlinks')
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 5fc834d..d89c2b8 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -111,7 +111,6 @@
     pm = Progress('Fetching projects', len(projects))
     for project in projects:
       pm.update()
-
       if project.Sync_NetworkHalf():
         fetched.add(project.gitdir)
       else:
@@ -194,6 +193,15 @@
     if opt.repo_upgraded:
       _PostRepoUpgrade(self.manifest)
 
+    if not opt.local_only:
+      mp.Sync_NetworkHalf()
+
+    if mp.HasChanges:
+      syncbuf = SyncBuffer(mp.config)
+      mp.Sync_LocalHalf(syncbuf)
+      if not syncbuf.Finish():
+        sys.exit(1)
+      self.manifest._Unload()
     all = self.GetProjects(args, missing_ok=True)
 
     if not opt.local_only:
@@ -201,7 +209,6 @@
       now = time.time()
       if (24 * 60 * 60) <= (now - rp.LastFetch):
         to_fetch.append(rp)
-      to_fetch.append(mp)
       to_fetch.extend(all)
 
       fetched = self._Fetch(to_fetch)