Merge "Permit plugins to implement AllRequestFilter"
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 5522239..4c64dfe 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -76,6 +76,7 @@
 	@$(ASCIIDOC) -a toc \
 		-a data-uri \
 		-a 'revision=$(REVISION)' \
+		-a 'newline=\n' \
 		-b xhtml11 \
 		-f asciidoc.conf \
 		$(ASCIIDOC_EXTRA) \
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 23f6e72..7027562 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -452,6 +452,9 @@
 to projects in Gerrit. It can give permission to abandon a specific
 change to a given ref.
 
+This also grants the permission to restore a change if the change
+can be uploaded.
+
 [[category_create]]
 Create reference
 ~~~~~~~~~~~~~~~~
diff --git a/Documentation/cmd-cherry-pick.txt b/Documentation/cmd-cherry-pick.txt
index 568c872..d051a9a 100644
--- a/Documentation/cmd-cherry-pick.txt
+++ b/Documentation/cmd-cherry-pick.txt
@@ -39,7 +39,7 @@
 ====
   $ scp -p -P 29418 john.doe@review.example.com:bin/gerrit-cherry-pick ~/bin/
 
-  $ curl http://review.example.com/tools/bin/gerrit-cherry-pick
+  $ curl -o ~/bin/gerrit-cherry-pick http://review.example.com/tools/bin/gerrit-cherry-pick
 ====
 
 GERRIT
diff --git a/Documentation/cmd-create-group.txt b/Documentation/cmd-create-group.txt
index 8d404ec..8dc6dcc 100644
--- a/Documentation/cmd-create-group.txt
+++ b/Documentation/cmd-create-group.txt
@@ -9,8 +9,8 @@
 --------
 [verse]
 'ssh' -p <port> <host> 'gerrit create-group'
-  [--owner <GROUP>]
-  [--description <DESC>]
+  [--owner <GROUP> | -o <GROUP>]
+  [--description <DESC> | -d <DESC>]
   [--member <USERNAME>]
   [--group <GROUP>]
   [--visible-to-all]
diff --git a/Documentation/cmd-create-project.txt b/Documentation/cmd-create-project.txt
index 02aa078..d0e56fd 100644
--- a/Documentation/cmd-create-project.txt
+++ b/Documentation/cmd-create-project.txt
@@ -14,7 +14,7 @@
   [--suggest-parents | -S ]
   [--permissions-only]
   [--description <DESC> | -d <DESC>]
-  [--submit-type <TYPE> |  -t <TYPE>]
+  [--submit-type <TYPE> | -t <TYPE>]
   [--use-contributor-agreements | --ca]
   [--use-signed-off-by | --so]
   [--use-content-merge]
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index 4c0560e..c4f222b 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -12,8 +12,8 @@
   $ scp -p -P 29418 john.doe@review.example.com:bin/gerrit-cherry-pick ~/bin/
   $ scp -p -P 29418 john.doe@review.example.com:hooks/commit-msg .git/hooks/
 
-  $ curl http://review.example.com/tools/bin/gerrit-cherry-pick
-  $ curl http://review.example.com/tools/hooks/commit-msg
+  $ curl -o ~/bin/gerrit-cherry-pick http://review.example.com/tools/bin/gerrit-cherry-pick
+  $ curl -o .git/hooks/commit-msg http://review.example.com/tools/hooks/commit-msg
 
 For more details on how to determine the correct SSH port number,
 see link:user-upload.html#test_ssh[Testing Your SSH Connection].
diff --git a/Documentation/cmd-ls-groups.txt b/Documentation/cmd-ls-groups.txt
index a50657b..306bb92 100644
--- a/Documentation/cmd-ls-groups.txt
+++ b/Documentation/cmd-ls-groups.txt
@@ -9,10 +9,11 @@
 --------
 [verse]
 'ssh' -p <port> <host> 'gerrit ls-groups'
-  [--project <NAME>]
-  [--user <NAME>]
+  [--project <NAME> | -p <NAME>]
+  [--user <NAME> | -u <NAME>]
   [--visible-to-all]
-  [--type {internal | ldap | system}]
+  [--type {internal | system}]
+  [--verbose | -v]
 
 DESCRIPTION
 -----------
diff --git a/Documentation/cmd-ls-projects.txt b/Documentation/cmd-ls-projects.txt
index 25cd9a9..d7d5aa5 100644
--- a/Documentation/cmd-ls-projects.txt
+++ b/Documentation/cmd-ls-projects.txt
@@ -10,8 +10,12 @@
 [verse]
 'ssh' -p <port> <host> 'gerrit ls-projects'
   [--show-branch <BRANCH> ...]
-  [--tree]
+  [--description | -d]
+  [--tree | -t]
   [--type {code | permissions | all}]
+  [--format {text | json | json_compact}]
+  [--all]
+  [--limit <N>]
 
 DESCRIPTION
 -----------
@@ -42,7 +46,7 @@
 	whole project is not shown.
 
 --description::
---d::
+-d::
 	Allows listing of projects together with their respective
 	description.
 +
diff --git a/Documentation/cmd-receive-pack.txt b/Documentation/cmd-receive-pack.txt
index 7e5ca09..68f686d 100644
--- a/Documentation/cmd-receive-pack.txt
+++ b/Documentation/cmd-receive-pack.txt
@@ -8,7 +8,10 @@
 SYNOPSIS
 --------
 [verse]
-'git receive-pack' [--reviewer <address>] [--cc <address>] <project>
+'git receive-pack'
+  [--reviewer <address> | --re <address>]
+  [--cc <address>]
+  <project>
 
 DESCRIPTION
 -----------
diff --git a/Documentation/cmd-review.txt b/Documentation/cmd-review.txt
index ac613e5..fdb5273 100644
--- a/Documentation/cmd-review.txt
+++ b/Documentation/cmd-review.txt
@@ -9,10 +9,10 @@
 --------
 [verse]
 'ssh' -p <port> <host> 'gerrit review'
-  [--project <PROJECT>]
-  [--message <MESSAGE>]
+  [--project <PROJECT> | -p <PROJECT>]
+  [--message <MESSAGE> | -m <MESSAGE>]
   [--force-message]
-  [--submit]
+  [--submit | -s]
   [--abandon | --restore]
   [--publish]
   [--delete]
@@ -52,7 +52,7 @@
 
 --force-message::
 	Option which allows Gerrit to publish the --message, even
-	when the labels could not be applied due to change being
+	when the labels could not be applied due to the change being
 	closed).
 +
 Used by some scripts/CI-systems, where the results (or links
@@ -69,11 +69,11 @@
 	complete listing of supported approval categories and values.
 
 --abandon::
-	Abandon the specified patch set(s).
+	Abandon the specified change(s).
 	(option is mutually exclusive with --submit and --restore)
 
 --restore::
-	Restore the specified abandoned patch set(s).
+	Restore the specified abandoned change(s).
 	(option is mutually exclusive with --abandon)
 
 --submit::
diff --git a/Documentation/cmd-set-project.txt b/Documentation/cmd-set-project.txt
index c4b9b4f..059f063 100644
--- a/Documentation/cmd-set-project.txt
+++ b/Documentation/cmd-set-project.txt
@@ -10,7 +10,7 @@
 [verse]
 'ssh' -p <port> <host> 'gerrit set-project'
   [--description <DESC> | -d <DESC>]
-  [--submit-type <TYPE> |  -t <TYPE>]
+  [--submit-type <TYPE> | -t <TYPE>]
   [--use|no-contributor-agreements | --ca|nca]
   [--use|no-signed-off-by | --so|nso]
   [--use|no-content-merge]
diff --git a/Documentation/cmd-set-reviewers.txt b/Documentation/cmd-set-reviewers.txt
index 9e08e39..32fd35e 100644
--- a/Documentation/cmd-set-reviewers.txt
+++ b/Documentation/cmd-set-reviewers.txt
@@ -9,9 +9,9 @@
 --------
 [verse]
 'ssh' -p <port> <host> 'gerrit set-reviewers'
-  [--project <PROJECT>]
-  [--add REVIEWER ...]
-  [--remove REVIEWER ...]
+  [--project <PROJECT> | -p <PROJECT>]
+  [--add <REVIEWER> ... | -a <REVIEWER> ...]
+  [--remove <REVIEWER> ... | -r <REVIEWER> ...]
   [--]
   {COMMIT | CHANGE-ID}...
 
diff --git a/Documentation/cmd-show-connections.txt b/Documentation/cmd-show-connections.txt
index b5d41bd..8404a97 100644
--- a/Documentation/cmd-show-connections.txt
+++ b/Documentation/cmd-show-connections.txt
@@ -8,7 +8,7 @@
 SYNOPSIS
 --------
 [verse]
-'ssh' -p <port> <host> 'gerrit show-connections' [-n]
+'ssh' -p <port> <host> 'gerrit show-connections' [--numeric | -n]
 
 DESCRIPTION
 -----------
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index cb70254..8610dba 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -88,6 +88,12 @@
 provider chosen by the end-user.  For more information see
 http://openid.net/[openid.net].
 +
+* `OpenID_SSO`
++
+Supports OpenID from a single provider.  There is no registration
+link, and the "Sign In" link sends the user directly to the provider's
+SSO entry point.
++
 * `HTTP`
 +
 Gerrit relies upon data presented in the HTTP request.  This includes
@@ -229,6 +235,13 @@
 +
 Default is 12 hours.
 
+[[auth.openIdSsoUrl]]auth.openIdSsoUrl::
++
+The SSO entry point URL.  Only used if `auth.type` was set to
+OpenID_SSO.
++
+The "Sign In" link will send users directly to this URL.
+
 [[auth.httpHeader]]auth.httpHeader::
 +
 HTTP header to trust the username from, or unset to select HTTP basic
@@ -2237,6 +2250,31 @@
 +
 By default a shade of yellow, `FFFFCC`.
 
+[[theme.changeTableOutdatedColor]]theme.changeTableOutdatedColor::
++
+Background color used for patch outdated messages.  The value must be
+a valid HTML hex color code, or standard color name.
++
+By default a shade of red, `FF0000`.
+
+[[theme.tableOddRowColor]]theme.tableOddRowColor::
++
+Background color for tables such as lists of open reviews for odd
+rows.  This is so you can have a different color for odd and even
+rows of the table.  The value must be a valid HTML hex color code,
+or standard color name.
++
+By default transparent.
+
+[[theme.tableEvenRowColor]]theme.tableEvenRowColor::
++
+Background color for tables such as lists of open reviews for even
+rows.  This is so you can have a different color for odd and even
+rows of the table.  The value must be a valid HTML hex color code,
+or standard color name.
++
+By default transparent.
+
 A different theme may be used for signed-in vs. signed-out user status
 by using the "signed-in" and "signed-out" theme sections. Variables
 not specified in a section are inherited from the default theme.
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 586ae07..e6c332e 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -1,6 +1,12 @@
 Gerrit Code Review - Plugin Development
 =======================================
 
+The Gerrit server functionality can be extended by installing plugins.
+This page describes how plugins for Gerrit can be developed.
+
+Depending on how tightly the extension code is coupled with the Gerrit
+server code, there is a distinction between `plugins` and `extensions`.
+
 A plugin in Gerrit is tightly coupled code that runs in the same
 JVM as Gerrit. It has full access to all server internals. Plugins
 are tightly coupled to a specific major.minor server version and
@@ -9,8 +15,8 @@
 
 An extension in Gerrit runs inside of the same JVM as Gerrit
 in the same way as a plugin, but has limited visibility to the
-server's internals. The limited visiblity reduces the extension's
-dependencies, enabling it to be compatiable across a wider range
+server's internals. The limited visibility reduces the extension's
+dependencies, enabling it to be compatible across a wider range
 of server versions.
 
 Most of this documentation refers to either type as a plugin.
@@ -18,7 +24,7 @@
 Requirements
 ------------
 
-To start development, clone the sample maven project:
+To start development, clone the sample Maven project:
 
 ----
 $ git clone https://gerrit.googlesource.com/plugins/helloworld
@@ -160,7 +166,7 @@
 ====
 
 If no Guice modules are declared in the manifest, SSH commands may
-use auto-registration by providing an @Export annotatation:
+use auto-registration by providing an @Export annotation:
 
 ====
   import com.google.gerrit.extensions.annotations.Export;
@@ -192,7 +198,7 @@
 by PrintHello class will be available to users as:
 
 ----
-$ ssh -P 29418 review.example.com helloworld print
+$ ssh -p 29418 review.example.com helloworld print
 ----
 
 HTTP Servlets
@@ -260,6 +266,27 @@
 if the file name ends with `.md`. Gerrit will automatically convert
 Markdown to HTML if accessed with extension `.html`.
 
+Within the Markdown documentation files macros can be used that allow
+to write documentation with reasonably accurate examples that adjust
+automatically based on the installation.
+
+The following macros are supported:
+
+[width="40%",options="header"]
+|===================================================
+|Macro       | Replacement
+|@PLUGIN@    | name of the plugin
+|@URL@       | Gerrit Web URL
+|@SSH_HOST@  | SSH Host
+|@SSH_PORT@  | SSH Port
+|===================================================
+
+The macros will be replaced when the documentation files are rendered
+from Markdown to HTML.
+
+Macros that start with `\` such as `\@KEEP@` will render as `@KEEP@`
+even if there is an expansion for `KEEP` in the future.
+
 Automatic Index
 ~~~~~~~~~~~~~~~
 
@@ -312,7 +339,7 @@
   the plugin from this location to its own site path.
 +
 ----
-$ ssh -P 29418 localhost gerrit plugin install -n name $(pwd)/my-plugin.jar
+$ ssh -p 29418 localhost gerrit plugin install -n name $(pwd)/my-plugin.jar
 ----
 
 * Valid URL, including any HTTP or FTP site reachable by the
@@ -320,14 +347,14 @@
   its own site path.
 +
 ----
-$ ssh -P 29418 localhost gerrit plugin install -n name http://build-server/output/our-plugin.jar
+$ ssh -p 29418 localhost gerrit plugin install -n name http://build-server/output/our-plugin.jar
 ----
 
 * As piped input to the plugin install command. The server will
   copy input until EOF, and save a copy under its own site path.
 +
 ----
-$ ssh -P 29418 localhost gerrit plugin install -n name - <target/name-0.1.jar
+$ ssh -p 29418 localhost gerrit plugin install -n name - <target/name-0.1.jar
 ----
 
 Plugins can also be copied directly into the server's
diff --git a/Documentation/error-change-closed.txt b/Documentation/error-change-closed.txt
index 74e7c48..3244fb3 100644
--- a/Documentation/error-change-closed.txt
+++ b/Documentation/error-change-closed.txt
@@ -1,8 +1,11 @@
 change ... closed
 =================
 
-With this error message Gerrit rejects to push a commit to a change
-that is already closed.
+With this error message Gerrit rejects to push a commit or submit a
+review label (approval) to a change that is already closed.
+
+When Pushing a Commit
+---------------------
 
 This error occurs if you are trying to push a commit that contains
 the Change-Id of a closed change in its commit message. A change can
@@ -24,6 +27,14 @@
 'Restore Change' button). Afterwards the push should succeed and a
 new patch set for this change will be created.
 
+When Submitting a Review Label
+------------------------------
+
+This error occurs if you are trying to submit a review label (approval) using
+the link:cmd-review.html[ssh review command] after the change has been closed.
+A change can be closed because it was submitted and merged, because it was abandoned,
+or because the patchset to which you are submitting the review has been replaced
+by a newer patchset.
 
 GERRIT
 ------
diff --git a/Documentation/error-messages.txt b/Documentation/error-messages.txt
index 4b62795..c9df883 100644
--- a/Documentation/error-messages.txt
+++ b/Documentation/error-messages.txt
@@ -15,7 +15,9 @@
 * link:error-change-not-found.html[change ... not found]
 * link:error-contains-banned-commit.html[contains banned commit ...]
 * link:error-has-duplicates.html[... has duplicates]
+* link:error-invalid-author.html[invalid author]
 * link:error-invalid-changeid-line.html[invalid Change-Id line format in commit message]
+* link:error-invalid-committer.html[invalid committer]
 * link:error-missing-changeid.html[missing Change-Id in commit message]
 * link:error-multiple-changeid-lines.html[multiple Change-Id lines in commit message]
 * link:error-no-changes-made.html[no changes made]
@@ -33,8 +35,6 @@
 * link:error-squash-commits-first.html[squash commits first]
 * link:error-upload-denied.html[Upload denied for project \'...']
 * link:error-not-allowed-to-upload-merges.html[you are not allowed to upload merges]
-* link:error-invalid-author.html[invalid author]
-* link:error-invalid-committer.html[invalid committer]
 
 
 General Hints
diff --git a/Documentation/index.txt b/Documentation/index.txt
index 2b53772..c99d26c 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -48,6 +48,7 @@
 * link:dev-readme.html[Developer Setup]
 * link:dev-eclipse.html[Eclipse Setup]
 * link:dev-contributing.html[Contributing to Gerrit]
+* link:dev-plugins.html[Developing Plugins]
 * link:dev-design.html[System Design]
 * link:i18n-readme.html[i18n Support]
 * link:dev-release.html[Developer Release]
diff --git a/Documentation/user-changeid.txt b/Documentation/user-changeid.txt
index 409bb32..a3015e1 100644
--- a/Documentation/user-changeid.txt
+++ b/Documentation/user-changeid.txt
@@ -46,11 +46,13 @@
 Gerrit Code Review provides a standard 'commit-msg' hook which
 can be installed in the local Git repository to automatically
 create and insert a unique Change-Id line during `git commit`.
-To install the hook, copy it from Gerrit's daemon:
+To install the hook, copy it from Gerrit's daemon by executing
+one of the following commands while being in the root directory
+of the local Git repository:
 
   $ scp -p -P 29418 john.doe@review.example.com:hooks/commit-msg .git/hooks/
 
-  $ curl http://review.example.com/tools/hooks/commit-msg
+  $ curl -o .git/hooks/commit-msg http://review.example.com/tools/hooks/commit-msg
 
 For more details, see link:cmd-hook-commit-msg.html[commit-msg].
 
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt
index 5f8de28..2e4865f 100644
--- a/ReleaseNotes/index.txt
+++ b/ReleaseNotes/index.txt
@@ -11,26 +11,26 @@
 [[2_3]]
 Version 2.3.x
 -------------
-* link:ReleaseNotes-2.3.html[2.3]
 * link:ReleaseNotes-2.3.1.html[2.3.1]
+* link:ReleaseNotes-2.3.html[2.3]
 
 [[2_2]]
 Version 2.2.x
 -------------
-* link:ReleaseNotes-2.2.2.html[2.2.2],
-* link:ReleaseNotes-2.2.2.2.html[2.2.2.2],
-* link:ReleaseNotes-2.2.2.1.html[2.2.2.1],
-* link:ReleaseNotes-2.2.1.html[2.2.1],
+* link:ReleaseNotes-2.2.2.2.html[2.2.2.2]
+* link:ReleaseNotes-2.2.2.1.html[2.2.2.1]
+* link:ReleaseNotes-2.2.2.html[2.2.2]
+* link:ReleaseNotes-2.2.1.html[2.2.1]
 * link:ReleaseNotes-2.2.0.html[2.2.0]
 
 [[2_1]]
 Version 2.1.x
 -------------
-* link:ReleaseNotes-2.1.8.html[2.1.8],
-* link:ReleaseNotes-2.1.7.2.html[2.1.7.2],
-* link:ReleaseNotes-2.1.7.html[2.1.7],
-* link:ReleaseNotes-2.1.6.html[2.1.6],
-  link:ReleaseNotes-2.1.6.1.html[2.1.6.1]
+* link:ReleaseNotes-2.1.8.html[2.1.8]
+* link:ReleaseNotes-2.1.7.2.html[2.1.7.2]
+* link:ReleaseNotes-2.1.7.html[2.1.7]
+* link:ReleaseNotes-2.1.6.1.html[2.1.6.1]
+* link:ReleaseNotes-2.1.6.html[2.1.6]
 * link:ReleaseNotes-2.1.5.html[2.1.5]
 * link:ReleaseNotes-2.1.4.html[2.1.4]
 * link:ReleaseNotes-2.1.3.html[2.1.3]
@@ -40,31 +40,31 @@
 * link:ReleaseNotes-2.1.2.2.html[2.1.2.2]
 * link:ReleaseNotes-2.1.2.1.html[2.1.2.1]
 * link:ReleaseNotes-2.1.2.html[2.1.2]
-* link:ReleaseNotes-2.1.1.html[2.1.1],
-  link:ReleaseNotes-2.1.1.html[2.1.1.1]
+* link:ReleaseNotes-2.1.1.html[2.1.1.1]
+* link:ReleaseNotes-2.1.1.html[2.1.1]
 * link:ReleaseNotes-2.1.html[2.1]
 
 [[2_0]]
 Version 2.0.x
 -------------
-* link:ReleaseNotes-2.0.24.html[2.0.24],
-  link:ReleaseNotes-2.0.24.html[2.0.24.1],
-  link:ReleaseNotes-2.0.24.html[2.0.24.2]
+* link:ReleaseNotes-2.0.24.html[2.0.24.2]
+* link:ReleaseNotes-2.0.24.html[2.0.24.1]
+* link:ReleaseNotes-2.0.24.html[2.0.24]
 * link:ReleaseNotes-2.0.23.html[2.0.23]
 * link:ReleaseNotes-2.0.22.html[2.0.22]
 * link:ReleaseNotes-2.0.21.html[2.0.21]
 * link:ReleaseNotes-2.0.20.html[2.0.20]
-* link:ReleaseNotes-2.0.19.html[2.0.19],
-  link:ReleaseNotes-2.0.19.html[2.0.19.1],
-  link:ReleaseNotes-2.0.19.html[2.0.19.2]
+* link:ReleaseNotes-2.0.19.html[2.0.19.2]
+* link:ReleaseNotes-2.0.19.html[2.0.19.1]
+* link:ReleaseNotes-2.0.19.html[2.0.19]
 * link:ReleaseNotes-2.0.18.html[2.0.18]
 * link:ReleaseNotes-2.0.17.html[2.0.17]
 * link:ReleaseNotes-2.0.16.html[2.0.16]
 * link:ReleaseNotes-2.0.15.html[2.0.15]
-* link:ReleaseNotes-2.0.14.html[2.0.14],
-  link:ReleaseNotes-2.0.14.html[2.0.14.1]
-* link:ReleaseNotes-2.0.13.html[2.0.13],
-  link:ReleaseNotes-2.0.13.html[2.0.13.1]
+* link:ReleaseNotes-2.0.14.html[2.0.14.1]
+* link:ReleaseNotes-2.0.14.html[2.0.14]
+* link:ReleaseNotes-2.0.13.html[2.0.13.1]
+* link:ReleaseNotes-2.0.13.html[2.0.13]
 * link:ReleaseNotes-2.0.12.html[2.0.12]
 * link:ReleaseNotes-2.0.11.html[2.0.11]
 * link:ReleaseNotes-2.0.10.html[2.0.10]
diff --git a/gerrit-antlr/.settings/org.eclipse.core.resources.prefs b/gerrit-antlr/.settings/org.eclipse.core.resources.prefs
index 589908f..e9441bb 100644
--- a/gerrit-antlr/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-antlr/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:35 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-cache-h2/.settings/org.eclipse.core.resources.prefs b/gerrit-cache-h2/.settings/org.eclipse.core.resources.prefs
index fc11c3f..f9fe345 100644
--- a/gerrit-cache-h2/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-cache-h2/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/test/java=UTF-8
diff --git a/gerrit-common/.settings/org.eclipse.core.resources.prefs b/gerrit-common/.settings/org.eclipse.core.resources.prefs
index fc11c3f..f9fe345 100644
--- a/gerrit-common/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-common/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/test/java=UTF-8
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
index 07a8534..89de3b4 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
@@ -28,6 +28,7 @@
 public class GerritConfig implements Cloneable {
   protected String registerUrl;
   protected String httpPasswordUrl;
+  protected String openIdSsoUrl;
   protected List<OpenIdProviderPattern> allowedOpenIDs;
 
   protected GitwebConfig gitweb;
@@ -72,6 +73,14 @@
     httpPasswordUrl = url;
   }
 
+  public String getOpenIdSsoUrl() {
+      return openIdSsoUrl;
+  }
+
+  public void setOpenIdSsoUrl(final String u) {
+    openIdSsoUrl = u;
+  }
+
   public List<OpenIdProviderPattern> getAllowedOpenIDs() {
     return allowedOpenIDs;
   }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
index c3d3f1e..f991f4c 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
@@ -31,5 +31,8 @@
     public String textColor;
     public String trimColor;
     public String selectionColor;
+    public String changeTableOutdatedColor;
+    public String tableOddRowColor;
+    public String tableEvenRowColor;
   }
 }
diff --git a/gerrit-extension-api/.settings/org.eclipse.core.resources.prefs b/gerrit-extension-api/.settings/org.eclipse.core.resources.prefs
index fc11c3f..f9fe345 100644
--- a/gerrit-extension-api/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-extension-api/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/test/java=UTF-8
diff --git a/gerrit-gwtdebug/.settings/org.eclipse.core.resources.prefs b/gerrit-gwtdebug/.settings/org.eclipse.core.resources.prefs
index 36e1448..e9441bb 100644
--- a/gerrit-gwtdebug/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-gwtdebug/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:38 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-gwtui/.settings/org.eclipse.core.resources.prefs b/gerrit-gwtui/.settings/org.eclipse.core.resources.prefs
index c780f44..e9441bb 100644
--- a/gerrit-gwtui/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-gwtui/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index fcc2db1..267419f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -18,6 +18,7 @@
 
 import com.google.gerrit.client.account.AccountCapabilities;
 import com.google.gerrit.client.auth.openid.OpenIdSignInDialog;
+import com.google.gerrit.client.auth.openid.OpenIdSsoPanel;
 import com.google.gerrit.client.auth.userpass.UserPassSignInDialog;
 import com.google.gerrit.client.changes.ChangeConstants;
 import com.google.gerrit.client.changes.ChangeListScreen;
@@ -258,6 +259,13 @@
         Location.assign(selfRedirect("/become"));
         break;
 
+      case OPENID_SSO:
+        final RootPanel gBody = RootPanel.get("gerrit_body");
+        OpenIdSsoPanel singleSignOnPanel = new OpenIdSsoPanel();
+        gBody.add(singleSignOnPanel);
+        singleSignOnPanel.authenticate(SignInMode.SIGN_IN, token);
+        break;
+
       case OPENID:
         new OpenIdSignInDialog(SignInMode.SIGN_IN, token, null).center();
         break;
@@ -627,6 +635,14 @@
           });
           break;
 
+        case OPENID_SSO:
+          menuRight.addItem(C.menuSignIn(), new Command() {
+            public void execute() {
+              doSignIn(History.getToken());
+            }
+          });
+          break;
+
         case LDAP:
         case LDAP_BIND:
         case CUSTOM_EXTENSION:
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
index 8d4a767..d38015c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchedProjectsScreen.java
@@ -15,12 +15,11 @@
 package com.google.gerrit.client.account;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.projects.ProjectMap;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
 import com.google.gerrit.client.ui.HintTextBox;
+import com.google.gerrit.client.ui.ProjectListPopup;
 import com.google.gerrit.client.ui.ProjectNameSuggestOracle;
-import com.google.gerrit.client.ui.ProjectsTable;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.AccountProjectWatchInfo;
 import com.google.gwt.event.dom.client.ClickEvent;
@@ -30,19 +29,13 @@
 import com.google.gwt.event.dom.client.KeyPressHandler;
 import com.google.gwt.event.logical.shared.SelectionEvent;
 import com.google.gwt.event.logical.shared.SelectionHandler;
-import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.ScrollPanel;
 import com.google.gwt.user.client.ui.SuggestBox;
 import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
 import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.HidePopupPanelCommand;
-import com.google.gwtexpui.user.client.PluginSafeDialogBox;
 
 import java.util.List;
 
@@ -53,15 +46,10 @@
   private HintTextBox filterTxt;
   private MyWatchesTable watchesTab;
   private Button browse;
-  private PluginSafeDialogBox popup;
-  private Button close;
-  private ProjectsTable projectsTab;
   private Button delSel;
-  private PopupPanel.PositionCallback popupPosition;
   private boolean submitOnSelection;
-  private boolean firstPopupLoad = true;
-  private boolean popingUp;
-  private ScrollPanel sp;
+  private Grid grid;
+  private ProjectListPopup projectsPopup;
 
   @Override
   protected void onInitUI() {
@@ -69,7 +57,7 @@
     createWidgets();
 
     /* top table */
-    final Grid grid = new Grid(2, 2);
+    grid = new Grid(2, 2);
     grid.setStyleName(Gerrit.RESOURCES.css().infoBlock());
     grid.setText(0, 0, Util.C.watchedProjectName());
     grid.setWidget(0, 1, nameTxt);
@@ -98,41 +86,22 @@
 
 
     /* popup */
-    final FlowPanel pfp = new FlowPanel();
-    sp = new ScrollPanel(projectsTab);
-    sp.setSize("100%", "100%");
-    pfp.add(sp);
-    pfp.add(close);
-    popup.setWidget(pfp);
-    popup.setHeight("100%");
-    popupPosition = new PopupPanel.PositionCallback() {
+    projectsPopup = new ProjectListPopup() {
+      @Override
+      protected void onMovePointerTo(String projectName) {
+        // prevent user input from being overwritten by simply poping up
+        if (!projectsPopup.isPopingUp() || "".equals(nameBox.getText())) {
+          nameBox.setText(projectName);
+        }
+      }
 
-      public void setPosition(int offsetWidth, int offsetHeight) {
-        int top = grid.getAbsoluteTop() - 50; // under page header
-        // Try to place it to the right of everything else, but not
-        // right justified
-        int left =
-            5 + Math.max(grid.getAbsoluteLeft() + grid.getOffsetWidth(),
-                watchesTab.getAbsoluteLeft() + watchesTab.getOffsetWidth());
-        if (top + offsetHeight > Window.getClientHeight()) {
-          top = Window.getClientHeight() - offsetHeight;
-        }
-        if (left + offsetWidth > Window.getClientWidth()) {
-          left = Window.getClientWidth() - offsetWidth;
-        }
-
-        if (top < 0) {
-          sp.setHeight((sp.getOffsetHeight() + top) + "px");
-          top = 0;
-        }
-        if (left < 0) {
-          sp.setWidth((sp.getOffsetWidth() + left) + "px");
-          left = 0;
-        }
-
-        popup.setPopupPosition(left, top);
+      @Override
+      protected void openRow(String projectName) {
+        nameBox.setText(projectName);
+        doAddNew();
       }
     };
+    projectsPopup.initPopup(Util.C.projects(), PageLinks.SETTINGS_PROJECTS);
   }
 
   protected void createWidgets() {
@@ -185,49 +154,18 @@
       }
     });
 
-    projectsTab = new ProjectsTable() {
-      {
-        keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.projectListOpen()));
-        keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER,
-                                                      Util.C.projectListOpen()));
-      }
-
-      @Override
-      protected void movePointerTo(final int row, final boolean scroll) {
-        super.movePointerTo(row, scroll);
-
-        // prevent user input from being overwritten by simply poping up
-        if (! popingUp || "".equals(nameBox.getText()) ) {
-          nameBox.setText(getRowItem(row).name());
-        }
-      }
-
-      @Override
-      protected void onOpenRow(final int row) {
-        super.onOpenRow(row);
-        nameBox.setText(getRowItem(row).name());
-        doAddNew();
-      }
-    };
-    projectsTab.setSavePointerId(PageLinks.SETTINGS_PROJECTS);
-
-    close = new Button(Util.C.projectsClose());
-    close.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(final ClickEvent event) {
-        closePopup();
-      }
-    });
-
-    popup = new PluginSafeDialogBox();
-    popup.setModal(false);
-    popup.setText(Util.C.projects());
-
     browse = new Button(Util.C.buttonBrowseProjects());
     browse.addClickHandler(new ClickHandler() {
       @Override
       public void onClick(final ClickEvent event) {
-        displayPopup();
+        int top = grid.getAbsoluteTop() - 50; // under page header
+        // Try to place it to the right of everything else, but not
+        // right justified
+        int left =
+            5 + Math.max(grid.getAbsoluteLeft() + grid.getOffsetWidth(),
+                watchesTab.getAbsoluteLeft() + watchesTab.getOffsetWidth());
+        projectsPopup.setPreferredCoordinates(top, left);
+        projectsPopup.displayPopup();
       }
     });
 
@@ -251,27 +189,7 @@
   @Override
   protected void onUnload() {
     super.onUnload();
-    closePopup();
-  }
-
-  protected void displayPopup() {
-    popingUp = true;
-    if (firstPopupLoad) { // For sizing/positioning, delay display until loaded
-      populateProjects();
-    } else {
-      popup.setPopupPositionAndShow(popupPosition);
-
-      GlobalKey.dialog(popup);
-      GlobalKey.addApplication(popup, new HidePopupPanelCommand(0,
-          KeyCodes.KEY_ESCAPE, popup));
-      projectsTab.setRegisterKeys(true);
-      projectsTab.finishDisplay();
-      popingUp = false;
-    }
-  }
-
-  protected void closePopup() {
-    popup.hide();
+    projectsPopup.closePopup();
   }
 
   protected void doAddNew() {
@@ -321,17 +239,4 @@
       }
     });
   }
-
-  protected void populateProjects() {
-    ProjectMap.all(new GerritCallback<ProjectMap>() {
-      @Override
-      public void onSuccess(final ProjectMap result) {
-        projectsTab.display(result);
-        if (firstPopupLoad) { // Display was delayed until table was loaded
-          firstPopupLoad = false;
-          displayPopup();
-        }
-      }
-    });
-  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index 49bb5dc3..a9ad519 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -48,6 +48,8 @@
   String suggestedGroupLabel();
   String parentSuggestions();
 
+  String buttonBrowseProjects();
+  String projects();
   String headingGroupUUID();
   String headingOwner();
   String headingDescription();
@@ -106,9 +108,11 @@
 
   String plugins();
   String pluginTabInstalled();
+  String pluginDisabled();
 
   String columnPluginName();
   String columnPluginVersion();
+  String columnPluginStatus();
 
   String noGroupSelected();
   String errorNoMatchingGroups();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index 89fc195..e20d544 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -17,6 +17,8 @@
 buttonSaveChanges = Save Changes
 checkBoxEmptyCommit = Create initial empty commit
 checkBoxPermissionsOnly = Only serve as parent for other projects
+buttonBrowseProjects = Browse
+projects = All projects
 useContentMerge = Automatically resolve conflicts
 useContributorAgreements = Require a valid contributor agreement to upload
 useSignedOffBy = Require <a href="http://gerrit.googlecode.com/svn/documentation/2.0/user-signedoffby.html#Signed-off-by" target="_blank"><code>Signed-off-by</code></a> in commit message
@@ -86,8 +88,10 @@
 
 plugins = Plugins
 pluginTabInstalled = Installed
+pluginDisabled = Disabled
 columnPluginName = Plugin Name
 columnPluginVersion = Version
+columnPluginStatus = Status
 
 noGroupSelected = (No group selected)
 errorNoMatchingGroups = No Matching Groups
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
index 43558be..b4950d8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
@@ -14,16 +14,22 @@
 
 package com.google.gerrit.client.admin;
 
+import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT;
+
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.ErrorDialog;
 import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.NotFoundScreen;
+import com.google.gerrit.client.account.AccountCapabilities;
 import com.google.gerrit.client.projects.ProjectInfo;
 import com.google.gerrit.client.projects.ProjectMap;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.HintTextBox;
+import com.google.gerrit.client.ui.ProjectListPopup;
 import com.google.gerrit.client.ui.ProjectNameSuggestOracle;
 import com.google.gerrit.client.ui.ProjectsTable;
 import com.google.gerrit.client.ui.Screen;
+import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
@@ -41,13 +47,16 @@
 import com.google.gwtjsonrpc.common.VoidResult;
 
 public class CreateProjectScreen extends Screen {
+  private Grid grid;
   private NpTextBox project;
   private Button create;
+  private Button browse;
   private HintTextBox parent;
   private SuggestBox sugestParent;
   private CheckBox emptyCommit;
   private CheckBox permissionsOnly;
   private ProjectsTable suggestedParentsTab;
+  private ProjectListPopup projectsPopup;
 
   public CreateProjectScreen() {
     super();
@@ -57,7 +66,22 @@
   @Override
   protected void onLoad() {
     super.onLoad();
-    display();
+    AccountCapabilities.all(new GerritCallback<AccountCapabilities>() {
+      @Override
+      public void onSuccess(AccountCapabilities ac) {
+        if (ac.canPerform(CREATE_PROJECT)) {
+          display();
+        } else {
+          Gerrit.display(PageLinks.ADMIN_CREATE_PROJECT, new NotFoundScreen());
+        }
+      }
+    }, CREATE_PROJECT);
+  }
+
+  @Override
+  protected void onUnload() {
+    super.onUnload();
+    projectsPopup.closePopup();
   }
 
   @Override
@@ -65,6 +89,18 @@
     super.onInitUI();
     setPageTitle(Util.C.createProjectTitle());
     addCreateProjectPanel();
+
+    /* popup */
+    projectsPopup = new ProjectListPopup() {
+      @Override
+      protected void onMovePointerTo(String projectName) {
+        // prevent user input from being overwritten by simply poping up
+        if (!projectsPopup.isPopingUp() || "".equals(sugestParent.getText())) {
+          sugestParent.setText(projectName);
+        }
+      }
+    };
+    projectsPopup.initPopup(Util.C.projects(), PageLinks.ADMIN_PROJECTS);
   }
 
   private void addCreateProjectPanel() {
@@ -82,12 +118,11 @@
     fp.add(emptyCommit);
     fp.add(permissionsOnly);
     fp.add(create);
-    VerticalPanel vp=new VerticalPanel();
+    VerticalPanel vp = new VerticalPanel();
     vp.add(fp);
     initSuggestedParents();
     vp.add(suggestedParentsTab);
     add(vp);
-
   }
 
   private void initCreateTxt() {
@@ -111,6 +146,23 @@
         doCreateProject();
       }
     });
+
+    browse = new Button(Util.C.buttonBrowseProjects());
+    browse.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(final ClickEvent event) {
+        int top = grid.getAbsoluteTop() - 50; // under page header
+        // Try to place it to the right of everything else, but not
+        // right justified
+        int left =
+            5 + Math.max(
+                grid.getAbsoluteLeft() + grid.getOffsetWidth(),
+                suggestedParentsTab.getAbsoluteLeft()
+                    + suggestedParentsTab.getOffsetWidth());
+        projectsPopup.setPreferredCoordinates(top, left);
+        projectsPopup.displayPopup();
+      }
+    });
   }
 
   private void initParentBox() {
@@ -145,26 +197,26 @@
     };
     suggestedParentsTab.setVisible(false);
 
-    ProjectMap.permissions(new GerritCallback<ProjectMap>() {
-          @Override
-          public void onSuccess(ProjectMap list) {
-            if (!list.isEmpty()) {
-              suggestedParentsTab.setVisible(true);
-              suggestedParentsTab.display(list);
-              suggestedParentsTab.finishDisplay();
-            }
-          }
-        });
+    ProjectMap.parentCandidates(new GerritCallback<ProjectMap>() {
+      @Override
+      public void onSuccess(ProjectMap list) {
+        if (!list.isEmpty()) {
+          suggestedParentsTab.setVisible(true);
+          suggestedParentsTab.display(list);
+          suggestedParentsTab.finishDisplay();
+        }
+      }
+    });
   }
 
   private void addGrid(final VerticalPanel fp) {
-    final Grid grid = new Grid(2, 2);
+    grid = new Grid(2, 3);
     grid.setStyleName(Gerrit.RESOURCES.css().infoBlock());
     grid.setText(0, 0, Util.C.columnProjectName() + ":");
     grid.setWidget(0, 1, project);
     grid.setText(1, 0, Util.C.headingParentProjectName() + ":");
     grid.setWidget(1, 1, sugestParent);
-
+    grid.setWidget(1, 2, browse);
     fp.add(grid);
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java
index 814ae51..3948b35 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PluginListScreen.java
@@ -60,10 +60,12 @@
     PluginTable() {
       table.setText(0, 1, Util.C.columnPluginName());
       table.setText(0, 2, Util.C.columnPluginVersion());
+      table.setText(0, 3, Util.C.columnPluginStatus());
 
       final FlexCellFormatter fmt = table.getFlexCellFormatter();
       fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().dataHeader());
       fmt.addStyleName(0, 2, Gerrit.RESOURCES.css().dataHeader());
+      fmt.addStyleName(0, 3, Gerrit.RESOURCES.css().dataHeader());
     }
 
     void display(final PluginMap plugins) {
@@ -80,16 +82,24 @@
     }
 
     void populate(final int row, final PluginInfo plugin) {
-      table.setWidget(
-          row,
-          1,
-          new Anchor(plugin.name(), Gerrit.selfRedirect("/plugins/"
-              + plugin.name() + "/")));
+      if (plugin.isDisabled()) {
+        table.setText(row, 1, plugin.name());
+      } else {
+        table.setWidget(
+            row,
+            1,
+            new Anchor(plugin.name(), Gerrit.selfRedirect("/plugins/"
+                + plugin.name() + "/")));
+      }
       table.setText(row, 2, plugin.version());
+      if (plugin.isDisabled()) {
+        table.setText(row, 3, Util.C.pluginDisabled());
+      }
 
       final FlexCellFormatter fmt = table.getFlexCellFormatter();
       fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().dataCell());
       fmt.addStyleName(row, 2, Gerrit.RESOURCES.css().dataCell());
+      fmt.addStyleName(row, 3, Gerrit.RESOURCES.css().dataCell());
 
       setRowItem(row, plugin);
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/auth/openid/OpenIdSsoPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/auth/openid/OpenIdSsoPanel.java
new file mode 100644
index 0000000..3dd54a7
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/auth/openid/OpenIdSsoPanel.java
@@ -0,0 +1,70 @@
+// Copyright (C) 2012 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.
+
+package com.google.gerrit.client.auth.openid;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.ui.SmallHeading;
+import com.google.gerrit.common.auth.SignInMode;
+import com.google.gerrit.common.auth.openid.DiscoveryResult;
+import com.google.gerrit.common.auth.openid.OpenIdUrls;
+import com.google.gwt.dom.client.FormElement;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.Hidden;
+
+import java.util.Map;
+
+public class OpenIdSsoPanel extends FlowPanel {
+  private final FormPanel redirectForm;
+  private final FlowPanel redirectBody;
+  private final String ssoUrl;
+
+  public OpenIdSsoPanel() {
+    super();
+    redirectBody = new FlowPanel();
+    redirectBody.setVisible(false);
+    redirectForm = new FormPanel();
+    redirectForm.add(redirectBody);
+
+    add(redirectForm);
+
+    ssoUrl = Gerrit.getConfig().getOpenIdSsoUrl();
+  }
+
+  public void authenticate(SignInMode requestedMode, final String token) {
+    OpenIdUtil.SVC.discover(ssoUrl, requestedMode, /* remember */ false, token,
+        new GerritCallback<DiscoveryResult>() {
+          public void onSuccess(final DiscoveryResult result) {
+            onDiscovery(result);
+          }
+        });
+  }
+
+  private void onDiscovery(final DiscoveryResult result) {
+    switch (result.status) {
+      case VALID:
+        redirectForm.setMethod(FormPanel.METHOD_POST);
+        redirectForm.setAction(result.providerUrl);
+        redirectBody.clear();
+        for (final Map.Entry<String, String> e : result.providerArgs.entrySet()) {
+          redirectBody.add(new Hidden(e.getKey(), e.getValue()));
+        }
+        FormElement.as(redirectForm.getElement()).setTarget("_top");
+        redirectForm.submit();
+        break;
+    }
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
index 44a49a8..97bb4ca 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable.java
@@ -202,10 +202,7 @@
     }
     table.setWidget(row, C_ID, new TableChangeLink(idstr, c));
 
-    String s = c.getSubject();
-    if (s.length() > 80) {
-      s = s.substring(0, 80);
-    }
+    String s = Util.cropSubject(c.getSubject());
     if (c.getStatus() != null && c.getStatus() != Change.Status.NEW) {
       s += " (" + c.getStatus().name() + ")";
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java
index fc2b418..0dd0b0f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeTable2.java
@@ -200,10 +200,7 @@
     }
     table.setWidget(row, C_ID, new TableChangeLink(c.id_abbreviated(), c));
 
-    String subject = c.subject();
-    if (subject.length() > 80) {
-      subject = subject.substring(0, 80);
-    }
+    String subject = Util.cropSubject(c.subject());
     Change.Status status = c.status();
     if (status != Change.Status.NEW) {
       subject += " (" + Util.toLongString(status) + ")";
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
index 00baf28..ca8aedf 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
@@ -424,7 +424,8 @@
       parentsTable.setWidget(row, 0, new InlineLabel(parent.id.get()));
       ptfmt.addStyleName(row, 0, Gerrit.RESOURCES.css().noborder());
       ptfmt.addStyleName(row, 0, Gerrit.RESOURCES.css().monospace());
-      parentsTable.setWidget(row, 1, new InlineLabel(parent.shortMessage));
+      parentsTable.setWidget(row, 1,
+          new InlineLabel(Util.cropSubject(parent.shortMessage)));
       ptfmt.addStyleName(row, 1, Gerrit.RESOURCES.css().noborder());
       row++;
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
index 7177525..b228cf2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
@@ -50,6 +50,28 @@
 import java.util.List;
 
 public class PatchTable extends Composite {
+  public interface PatchValidator {
+    /**
+     * Returns true if patch is valid
+     *
+     * @param patch
+     * @return
+     */
+    boolean isValid(Patch patch);
+  }
+
+  public final PatchValidator PREFERENCE_VALIDATOR =
+      new PatchValidator() {
+        @Override
+        public boolean isValid(Patch patch) {
+          return !((listenablePrefs.get().isSkipDeleted()
+              && patch.getChangeType().equals(ChangeType.DELETED))
+              || (listenablePrefs.get().isSkipUncommented()
+              && patch.getCommentCount() == 0));
+        }
+
+      };
+
   private final FlowPanel myBody;
   private PatchSetDetail detail;
   private Command onLoadCommand;
@@ -176,29 +198,32 @@
   /**
    * @return a link to the previous file in this patch set, or null.
    */
-  public InlineHyperlink getPreviousPatchLink(int index, PatchScreen.Type patchType) {
-    for(index--; index > -1; index--) {
-      InlineHyperlink link = createLink(index, patchType, SafeHtml.asis(Util.C
-          .prevPatchLinkIcon()), null);
-      if (link != null) {
-        return link;
-      }
+  public InlineHyperlink getPreviousPatchLink(int index,
+      PatchScreen.Type patchType) {
+    int previousPatchIndex = getPreviousPatch(index, PREFERENCE_VALIDATOR);
+    if (previousPatchIndex < 0) {
+      return null;
     }
-    return null;
+    InlineHyperlink link =
+        createLink(previousPatchIndex, patchType,
+            SafeHtml.asis(Util.C.prevPatchLinkIcon()), null);
+
+    return link;
   }
 
   /**
    * @return a link to the next file in this patch set, or null.
    */
   public InlineHyperlink getNextPatchLink(int index, PatchScreen.Type patchType) {
-    for(index++; index < patchList.size(); index++) {
-      InlineHyperlink link = createLink(index, patchType, null, SafeHtml.asis(Util.C
-          .nextPatchLinkIcon()));
-      if (link != null) {
-        return link;
-      }
+    int nextPatchIndex = getNextPatch(index, false, PREFERENCE_VALIDATOR);
+    if (nextPatchIndex < 0) {
+      return null;
     }
-    return null;
+    InlineHyperlink link =
+        createLink(nextPatchIndex, patchType, null,
+            SafeHtml.asis(Util.C.nextPatchLinkIcon()));
+
+    return link;
   }
 
   /**
@@ -208,16 +233,9 @@
    * @param before A string to display at the beginning of the href text
    * @param after A string to display at the end of the href text
    */
-  private PatchLink createLink(int index, PatchScreen.Type patchType,
+  public PatchLink createLink(int index, PatchScreen.Type patchType,
       SafeHtml before, SafeHtml after) {
     Patch patch = patchList.get(index);
-    if (( listenablePrefs.get().isSkipDeleted() &&
-          patch.getChangeType().equals(ChangeType.DELETED) )
-        ||
-        ( listenablePrefs.get().isSkipUncommented() &&
-          patch.getCommentCount() == 0 ) ) {
-      return null;
-    }
 
     Key thisKey = patch.getKey();
     PatchLink link;
@@ -814,4 +832,75 @@
       return System.currentTimeMillis() - start > 200;
     }
   }
+
+
+  /**
+   * Gets the next patch
+   *
+   * @param currentIndex
+   * @param validators
+   * @param loopAround loops back around to the front and traverses if this is
+   *        true
+   * @return
+   */
+  public int getNextPatch(int currentIndex, boolean loopAround,
+      PatchValidator... validators) {
+    return getNextPatchHelper(currentIndex, loopAround, detail.getPatches()
+        .size(), validators);
+  }
+
+  /**
+   * Helper function for getNextPatch
+   *
+   * @param currentIndex
+   * @param validators
+   * @param loopAround
+   * @param maxIndex will only traverse up to this index
+   * @return
+   */
+  private int getNextPatchHelper(int currentIndex, boolean loopAround,
+      int maxIndex, PatchValidator... validators) {
+    for (int i = currentIndex + 1; i < maxIndex; i++) {
+      Patch patch = detail.getPatches().get(i);
+      if (patch != null && patchIsValid(patch, validators)) {
+        return i;
+      }
+    }
+
+    if (loopAround) {
+      return getNextPatchHelper(-1, false, currentIndex, validators);
+    }
+
+    return -1;
+  }
+
+  /**
+   * @return the index to the previous patch
+   */
+  public int getPreviousPatch(int currentIndex, PatchValidator... validators) {
+    for (int i = currentIndex - 1; i >= 0; i--) {
+      Patch patch = detail.getPatches().get(i);
+      if (patch != null && patchIsValid(patch, validators)) {
+        return i;
+      }
+    }
+
+    return -1;
+  }
+
+  /**
+   * Helper function that returns whether a patch is valid or not
+   *
+   * @param patch
+   * @param validators
+   * @return whether the patch is valid based on the validators
+   */
+  private boolean patchIsValid(Patch patch, PatchValidator... validators) {
+    for (PatchValidator v : validators) {
+      if (!v.isValid(patch)) {
+        return false;
+      }
+    }
+    return true;
+  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
index e84cac8..590ad87 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
@@ -30,6 +30,10 @@
   public static final ChangeListService LIST_SVC;
   public static final ChangeManageService MANAGE_SVC;
 
+  private static final int SUBJECT_MAX_LENGTH = 80;
+  private static final String SUBJECT_CROP_APPENDIX = "...";
+  private static final int SUBJECT_CROP_RANGE = 10;
+
   static {
     DETAIL_SVC = GWT.create(ChangeDetailService.class);
     JsonUtil.bind(DETAIL_SVC, "rpc/ChangeDetailService");
@@ -60,4 +64,40 @@
         return status.name();
     }
   }
+
+  /**
+   * Crops the given change subject if needed so that it has at most
+   * {@link #SUBJECT_MAX_LENGTH} characters.
+   *
+   * If the given subject is not longer than {@link #SUBJECT_MAX_LENGTH}
+   * characters it is returned unchanged.
+   *
+   * If the length of the given subject exceeds {@link #SUBJECT_MAX_LENGTH}
+   * characters it is cropped. In this case {@link #SUBJECT_CROP_APPENDIX} is
+   * appended to the cropped subject, the cropped subject including the appendix
+   * has at most {@link #SUBJECT_MAX_LENGTH} characters.
+   *
+   * If cropping is needed, the subject will be cropped after the last space
+   * character that is found within the last {@link #SUBJECT_CROP_RANGE}
+   * characters of the potentially visible characters. If no such space is
+   * found, the subject will be cropped so that the cropped subject including
+   * the appendix has exactly {@link #SUBJECT_MAX_LENGTH} characters.
+   *
+   * @return the subject, cropped if needed
+   */
+  @SuppressWarnings("deprecation")
+  public static String cropSubject(final String subject) {
+    if (subject.length() > SUBJECT_MAX_LENGTH) {
+      final int maxLength = SUBJECT_MAX_LENGTH - SUBJECT_CROP_APPENDIX.length();
+      for (int cropPosition = maxLength; cropPosition > maxLength - SUBJECT_CROP_RANGE; cropPosition--) {
+        // Character.isWhitespace(char) can't be used because this method is not supported by GWT,
+        // see https://developers.google.com/web-toolkit/doc/1.6/RefJreEmulation#Package_java_lang
+        if (Character.isSpace(subject.charAt(cropPosition - 1))) {
+          return subject.substring(0, cropPosition) + SUBJECT_CROP_APPENDIX;
+        }
+      }
+      return subject.substring(0, maxLength) + SUBJECT_CROP_APPENDIX;
+    }
+    return subject;
+  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 3789c6a..446b71d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -43,7 +43,9 @@
 @eval textColor com.google.gerrit.client.Gerrit.getTheme().textColor;
 @eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
 @eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
-
+@eval changeTableOutdatedColor com.google.gerrit.client.Gerrit.getTheme().changeTableOutdatedColor;
+@eval tableOddRowColor com.google.gerrit.client.Gerrit.getTheme().tableOddRowColor;
+@eval tableEvenRowColor com.google.gerrit.client.Gerrit.getTheme().tableEvenRowColor;
 
 @sprite .greenCheckClass {
   gwt-image: "greenCheck";
@@ -411,8 +413,16 @@
   border-spacing: 0;
 }
 
+.changeTable tr:nth-child\(even\) {
+  background: tableEvenRowColor;
+}
+
+.changeTable tr:nth-child\(odd\) {
+  background: tableOddRowColor;
+}
+
 .changeTable .outdated {
-  background: red;
+  background: changeTableOutdatedColor;
 }
 
 .changeTable .iconCell {
@@ -482,7 +492,6 @@
 
 .accountDashboard.changeTable tr {
   color: #444444;
-  background: #F6F6F6;
 }
 .accountDashboard.changeTable tr a {
   color: #444444;
@@ -492,13 +501,12 @@
 .accountDashboard.changeTable .needsReview a {
   font-weight: bold;
   color: textColor;
-  background: backgroundColor;
 }
 
 .changeTable .activeRow,
 .accountDashboard.changeTable .activeRow,
 .accountDashboard.changeTable .activeRow a {
-  background: selectionColor;
+  background: selectionColor !important;
 }
 
 .changeTable .cID {
@@ -1042,6 +1050,10 @@
   display: table;
 }
 
+.sideBySideScreenSideBySideTable .fileLine {
+  width: 50%;
+}
+
 .sideBySideScreenLinkTable {
   width: 100%;
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
index fd34729..70dcf75 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
@@ -31,6 +31,7 @@
   String patchHeaderPatchSet();
   String patchHeaderOld();
   String patchHeaderNew();
+  String patchSet();
 
   String patchHistoryTitle();
   String disabledOnLargeFiles();
@@ -60,7 +61,8 @@
   String previousFileHelp();
   String nextFileHelp();
 
-  String reviewed();
+  String reviewedAnd();
+  String next();
   String download();
 
   String buttonReplyDone();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
index 23090a2..694ccb4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
@@ -15,6 +15,7 @@
 patchHeaderOld = Old Version
 patchHeaderNew = New Version
 patchHistoryTitle = Patch History
+patchSet = Patch Set
 disabledOnLargeFiles = Disabled on very large source files.
 intralineFailure = Intraline difference not available due to server error.
 illegalNumberOfColumns = The number of columns cannot be zero or negative
@@ -42,7 +43,8 @@
 previousFileHelp = Previous file
 nextFileHelp = Next file
 
-reviewed = Reviewed
+reviewedAnd = Reviewed &
+next = next
 download = (Download)
 
 fileTypeSymlink = Type: Symbolic Link
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
index 77d8659..0976a9d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
@@ -20,10 +20,13 @@
 import com.google.gerrit.client.RpcStatus;
 import com.google.gerrit.client.changes.CommitMessageBlock;
 import com.google.gerrit.client.changes.PatchTable;
+import com.google.gerrit.client.changes.PatchTable.PatchValidator;
 import com.google.gerrit.client.changes.Util;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
+import com.google.gerrit.client.ui.ChangeLink;
 import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
+import com.google.gerrit.client.ui.PatchLink;
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchSetDetail;
@@ -34,17 +37,22 @@
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.CheckBox;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
+import com.google.gwtexpui.safehtml.client.SafeHtml;
+import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 import com.google.gwtjsonrpc.common.VoidResult;
 
 public abstract class PatchScreen extends Screen implements
@@ -102,10 +110,12 @@
   protected PatchScriptSettingsPanel settingsPanel;
   protected TopView topView;
 
-  private CheckBox reviewed;
+  private CheckBox reviewedCheckBox;
+  private FlowPanel reviewedPanel;
   private HistoryTable historyTable;
   private FlowPanel topPanel;
   private FlowPanel contentPanel;
+  private PatchTableHeader header;
   private Label noDifference;
   private AbstractPatchContentTable contentTable;
   private CommitMessageBlock commitMessageBlock;
@@ -143,15 +153,6 @@
     idSideB = id.getParentKey();
     this.patchIndex = patchIndex;
 
-    reviewed = new CheckBox(Util.C.reviewed());
-    reviewed.addValueChangeHandler(
-        new ValueChangeHandler<Boolean>() {
-          @Override
-          public void onValueChange(ValueChangeEvent<Boolean> event) {
-            setReviewedByCurrentUser(event.getValue());
-          }
-        });
-
     prefs = fileList != null ? fileList.getPreferences() :
                                new ListenableAccountDiffPreference();
     if (Gerrit.isSignedIn()) {
@@ -165,9 +166,75 @@
           }
         });
 
+    reviewedPanel = new FlowPanel();
     settingsPanel = new PatchScriptSettingsPanel(prefs);
   }
 
+  private void populateReviewedPanel(){
+    reviewedPanel.clear();
+
+    reviewedCheckBox = new CheckBox(PatchUtil.C.reviewedAnd() + " ");
+    reviewedCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+      @Override
+      public void onValueChange(ValueChangeEvent<Boolean> event) {
+        setReviewedByCurrentUser(event.getValue());
+      }
+    });
+
+    reviewedPanel.add(reviewedCheckBox);
+    reviewedPanel.add(getReviewedAnchor());
+  }
+
+  private Anchor getReviewedAnchor() {
+    SafeHtmlBuilder text = new SafeHtmlBuilder();
+    text.append(PatchUtil.C.next());
+    text.append(SafeHtml.asis(Util.C.nextPatchLinkIcon()));
+
+    Anchor reviewedAnchor = new Anchor("");
+    SafeHtml.set(reviewedAnchor, text);
+
+    reviewedAnchor.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        setReviewedByCurrentUser(true);
+      }
+    });
+
+    final PatchValidator unreviewedValidator = new PatchValidator() {
+      public boolean isValid(Patch patch) {
+        return !patch.isReviewedByCurrentUser();
+      }
+    };
+
+    int nextUnreviewedPatchIndex =
+        fileList.getNextPatch(patchIndex, true, unreviewedValidator,
+            fileList.PREFERENCE_VALIDATOR);
+
+    if (nextUnreviewedPatchIndex > -1) {
+      // Create invisible patch link to change page
+      final PatchLink reviewedLink =
+          fileList.createLink(nextUnreviewedPatchIndex, getPatchScreenType(),
+              null, null);
+      reviewedLink.setText("");
+      reviewedAnchor.addClickHandler(new ClickHandler() {
+        @Override
+        public void onClick(ClickEvent event) {
+          reviewedLink.go();
+        }
+      });
+    } else {
+      final ChangeLink upLink = new ChangeLink("", patchKey.getParentKey());
+      reviewedAnchor.addClickHandler(new ClickHandler() {
+        @Override
+        public void onClick(ClickEvent event) {
+          upLink.go();
+        }
+      });
+    }
+
+    return reviewedAnchor;
+  }
+
   @Override
   public void notifyDraftDelta(int delta) {
     lastScript = null;
@@ -180,9 +247,9 @@
 
   private void update(AccountDiffPreference dp) {
     // Did the user just turn on auto-review?
-    if (!reviewed.getValue() && prefs.getOld().isManualReview()
+    if (!reviewedCheckBox.getValue() && prefs.getOld().isManualReview()
         && !dp.isManualReview()) {
-      reviewed.setValue(true);
+      reviewedCheckBox.setValue(true);
       setReviewedByCurrentUser(true);
     }
 
@@ -236,7 +303,7 @@
     super.onInitUI();
 
     if (Gerrit.isSignedIn()) {
-      setTitleFarEast(reviewed);
+      setTitleFarEast(reviewedPanel);
     }
 
     keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
@@ -250,6 +317,8 @@
     topPanel = new FlowPanel();
     add(topPanel);
 
+    header = new PatchTableHeader(getPatchScreenType());
+
     noDifference = new Label(PatchUtil.C.noDifference());
     noDifference.setStyleName(Gerrit.RESOURCES.css().patchNoDifference());
     noDifference.setVisible(false);
@@ -264,6 +333,7 @@
     contentPanel = new FlowPanel();
     contentPanel.setStyleName(Gerrit.RESOURCES.css()
         .sideBySideScreenSideBySideTable());
+    contentPanel.add(header);
     contentPanel.add(noDifference);
     contentPanel.add(contentTable);
     add(contentPanel);
@@ -369,6 +439,7 @@
     final int rpcseq = ++rpcSequence;
     lastScript = null;
     settingsPanel.setEnabled(false);
+    populateReviewedPanel();
     if (isFirst && fileList != null) {
       fileList.movePointerTo(patchKey);
     }
@@ -439,6 +510,8 @@
       setToken(Dispatcher.toPatchUnified(idSideA, patchKey));
     }
 
+    header.display(patchSetDetail, script, patchKey, idSideA, idSideB);
+
     if (hasDifferences) {
       contentTable.display(patchKey, idSideA, idSideB, script);
       contentTable.display(script.getCommentDetail(), script.isExpandAllComments());
@@ -468,7 +541,7 @@
           }
         }
       }
-      reviewed.setValue(isReviewed);
+      reviewedCheckBox.setValue(isReviewed);
     }
 
     intralineFailure = isFirst && script.hasIntralineFailure();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
new file mode 100644
index 0000000..5dd4e1f
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.java
@@ -0,0 +1,169 @@
+// Copyright (C) 2012 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.
+
+package com.google.gerrit.client.patches;
+
+import com.google.gerrit.client.Dispatcher;
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.common.data.PatchSetDetail;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.SpanElement;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.resources.client.CssResource;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.Anchor;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwtorm.client.KeyUtil;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class PatchSetSelectBox extends Composite {
+  interface Binder extends UiBinder<HTMLPanel, PatchSetSelectBox> {
+  }
+
+  private static Binder uiBinder = GWT.create(Binder.class);
+
+  interface BoxStyle extends CssResource {
+    String selected();
+
+    String hidden();
+  }
+
+  public enum Side {
+    A, B
+  }
+
+  PatchScript script;
+  Patch.Key patchKey;
+  PatchSet.Id idSideA;
+  PatchSet.Id idSideB;
+  PatchSet.Id idActive;
+  Side side;
+  PatchScreen.Type screenType;
+  List<Anchor> links;
+
+  @UiField
+  HTMLPanel linkPanel;
+
+  @UiField
+  BoxStyle style;
+
+  @UiField
+  SpanElement sideMarker;
+
+  public PatchSetSelectBox(Side side, final PatchScreen.Type type) {
+    this.side = side;
+    this.screenType = type;
+
+    initWidget(uiBinder.createAndBindUi(this));
+  }
+
+  public void display(final PatchSetDetail detail, final PatchScript script, Patch.Key key,
+      PatchSet.Id idSideA, PatchSet.Id idSideB) {
+    this.script = script;
+    this.patchKey = key;
+    this.idSideA = idSideA;
+    this.idSideB = idSideB;
+    this.idActive = (side == Side.A) ? idSideA : idSideB;
+    this.links = new LinkedList<Anchor>();
+
+    if (screenType == PatchScreen.Type.UNIFIED) {
+      sideMarker.setInnerText((side == Side.A) ? "(-)" : "(+)");
+    }
+
+    if (detail.getInfo().getParents().size() > 1) {
+      addLink(PatchUtil.C.patchBaseAutoMerge(), null);
+    } else {
+      addLink(PatchUtil.C.patchBase(), null);
+    }
+
+    if (side == Side.B) {
+      links.get(0).setStyleName(style.hidden());
+    }
+
+    for (Patch patch : script.getHistory()) {
+      PatchSet.Id psId = patch.getKey().getParentKey();
+      addLink(Integer.toString(psId.get()), psId);
+    }
+
+    if (idActive == null && side == Side.A) {
+      links.get(0).setStyleName(style.selected());
+    } else {
+      links.get(idActive.get()).setStyleName(style.selected());
+    }
+
+    Anchor downloadLink = getDownloadLink();
+    if (downloadLink != null) {
+      linkPanel.add(new Label(" - "));
+      linkPanel.add(downloadLink);
+    }
+  }
+
+  private void addLink(String label, final PatchSet.Id id) {
+    final Anchor anchor = new Anchor(label);
+    anchor.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        if (side == Side.A) {
+          idSideA = id;
+        } else {
+          idSideB = id;
+        }
+
+        Patch.Key keySideB = new Patch.Key(idSideB, patchKey.get());
+
+        switch (screenType) {
+          case SIDE_BY_SIDE:
+            Gerrit.display(Dispatcher.toPatchSideBySide(idSideA, keySideB));
+            break;
+          case UNIFIED:
+            Gerrit.display(Dispatcher.toPatchUnified(idSideA, keySideB));
+            break;
+        }
+      }
+
+    });
+
+    links.add(anchor);
+    linkPanel.add(anchor);
+  }
+
+  private Anchor getDownloadLink() {
+    boolean isCommitMessage = Patch.COMMIT_MSG.equals(script.getNewName());
+
+    if (isCommitMessage || (side == Side.A && 0 >= script.getA().size())
+        || (side == Side.B && 0 >= script.getB().size())) {
+      return null;
+    }
+
+    Patch.Key key =
+        (idSideA == null) ? patchKey : (new Patch.Key(idSideA, patchKey.get()));
+
+    String sideURL = (side == Side.A) ? "1" : "0";
+    final String base = GWT.getHostPageBaseURL() + "cat/";
+
+    final Anchor anchor = new Anchor(PatchUtil.C.download());
+    anchor.setHref(base + KeyUtil.encode(key.toString()) + "^" + sideURL);
+
+    return anchor;
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
new file mode 100644
index 0000000..2c4bd5d
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchSetSelectBox.ui.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2012 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.
+-->
+
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+    xmlns:g='urn:import:com.google.gwt.user.client.ui'>
+
+
+  <ui:with field='res' type='com.google.gerrit.client.GerritResources'/>
+  <ui:with field='cons' type='com.google.gerrit.client.patches.PatchConstants'/>
+  <ui:style type='com.google.gerrit.client.patches.PatchSetSelectBox.BoxStyle'>
+    @eval selectionColor com.google.gerrit.client.Gerrit.getTheme().selectionColor;
+    @eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
+    @eval backgroundColor com.google.gerrit.client.Gerrit.getTheme().backgroundColor;
+
+    .wrapper {
+      width: 100%;
+    }
+
+    .patchSetLabel {
+      font-weight: bold;
+    }
+
+    .linkPanel > div {
+      display: inline-block;
+      padding: 3px;
+    }
+
+    .linkPanel {
+      font-size: 12px;
+    }
+
+    .linkPanel > a {
+      padding: 3px;
+      display: inline-block;
+      text-decoration: none;
+    }
+
+    .selected {
+      font-weight: bold;
+      background-color: selectionColor;
+    }
+
+    .sideMarker {
+      font-family: monospace;
+    }
+
+    .hidden {
+      visibility: hidden;
+    }
+  </ui:style>
+
+  <g:HTMLPanel styleName='wrapper'>
+    <g:HTMLPanel styleName='{style.linkPanel}' ui:field='linkPanel'><span class='{style.patchSetLabel}'><ui:text from="{cons.patchSet}" /></span> <span class='{style.sideMarker}' ui:field='sideMarker'></span>: </g:HTMLPanel>
+  </g:HTMLPanel>
+</ui:UiBinder>
+
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeader.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeader.java
new file mode 100644
index 0000000..3dd8908
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeader.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2012 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.
+
+package com.google.gerrit.client.patches;
+
+import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.common.data.PatchSetDetail;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiTemplate;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTMLPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+
+public class PatchTableHeader extends Composite {
+
+  @UiTemplate("PatchTableHeaderSideBySide.ui.xml")
+  interface SideBySideBinder extends UiBinder<HTMLPanel, PatchTableHeader> {
+  }
+
+  @UiTemplate("PatchTableHeaderUnified.ui.xml")
+  interface UnifiedBinder extends UiBinder<HTMLPanel, PatchTableHeader> {
+  }
+
+  private static SideBySideBinder uiBinderS = GWT.create(SideBySideBinder.class);
+  private static UnifiedBinder uiBinderU = GWT.create(UnifiedBinder.class);
+
+  @UiField
+  SimplePanel sideAPanel;
+
+  @UiField
+  SimplePanel sideBPanel;
+
+  PatchSetSelectBox listA;
+  PatchSetSelectBox listB;
+
+  public PatchTableHeader(PatchScreen.Type type) {
+    listA = new PatchSetSelectBox(PatchSetSelectBox.Side.A, type);
+    listB = new PatchSetSelectBox(PatchSetSelectBox.Side.B, type);
+
+    if (type == PatchScreen.Type.SIDE_BY_SIDE) {
+      initWidget(uiBinderS.createAndBindUi(this));
+    } else {
+      initWidget(uiBinderU.createAndBindUi(this));
+    }
+
+    sideAPanel.add(listA);
+    sideBPanel.add(listB);
+  }
+
+
+  public void display(final PatchSetDetail detail, PatchScript script, final Patch.Key patchKey,
+      final PatchSet.Id idSideA, final PatchSet.Id idSideB) {
+    listA.display(detail, script, patchKey, idSideA, idSideB);
+    listB.display(detail, script, patchKey, idSideA, idSideB);
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderSideBySide.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderSideBySide.ui.xml
new file mode 100644
index 0000000..424e6e5
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderSideBySide.ui.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2012 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.
+-->
+
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+    xmlns:g='urn:import:com.google.gwt.user.client.ui'>
+
+
+  <ui:style>
+    @eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
+
+    .wrapper {
+      width: 100%;
+      background-color: trimColor;
+      overflow: hidden;
+    }
+
+    .wrapper .box {
+      width: 100%;
+      text-align: center;
+    }
+
+    .leftWrapper {
+      width: 50%;
+      float: left;
+    }
+
+    .rightWrapper {
+      width: 50%;
+      overflow: hidden;
+    }
+
+    .leftBox {
+      float:left;
+    }
+
+    .rightBox {
+      float: right;
+    }
+  </ui:style>
+
+  <g:HTMLPanel styleName="{style.wrapper}">
+    <div class='{style.leftWrapper}'>
+      <g:SimplePanel addStyleNames='{style.box} {style.leftBox}' ui:field='sideAPanel'/>
+    </div>
+    <div class='{style.rightWrapper}'>
+      <g:SimplePanel addStyleNames='{style.box} {style.rightBox}' ui:field='sideBPanel'/>
+    </div>
+  </g:HTMLPanel>
+</ui:UiBinder>
+
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderUnified.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderUnified.ui.xml
new file mode 100644
index 0000000..e26e96a
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchTableHeaderUnified.ui.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (C) 2012 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.
+-->
+
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+    xmlns:g='urn:import:com.google.gwt.user.client.ui'>
+
+  <ui:style>
+    @eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
+
+    .wrapper {
+      width: 100%;
+      background-color: trimColor;
+    }
+
+    .wrapper .box {
+      width: 100%;
+      text-align: left;
+      margin-left: 3px;
+    }
+  </ui:style>
+
+  <g:HTMLPanel styleName="{style.wrapper}">
+    <g:SimplePanel addStyleNames='{style.box}' ui:field='sideAPanel'/>
+    <g:SimplePanel addStyleNames='{style.box}' ui:field='sideBPanel'/>
+  </g:HTMLPanel>
+</ui:UiBinder>
+
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
index 964ba4b..ec63a83 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
@@ -25,10 +25,7 @@
 import com.google.gerrit.common.data.PatchScript.FileMode;
 import com.google.gerrit.prettify.common.EditList;
 import com.google.gerrit.prettify.common.SparseHtmlFile;
-import com.google.gerrit.reviewdb.client.Patch;
-import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.ui.Anchor;
@@ -38,8 +35,6 @@
 import com.google.gwt.user.client.ui.InlineLabel;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
 import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
-import com.google.gwtorm.client.KeyUtil;
-
 import org.eclipse.jgit.diff.Edit;
 
 import java.util.ArrayList;
@@ -89,9 +84,6 @@
         script.getDiffPrefs().isIntralineDifference()
             && script.hasIntralineDifference();
 
-    appendHeader(script, nc);
-    lines.add(null);
-
     if (script.getFileModeA() != FileMode.FILE
         || script.getFileModeB() != FileMode.FILE) {
       openLine(nc);
@@ -262,71 +254,6 @@
     return row;
   }
 
-  private void appendHeader(PatchScript script, final SafeHtmlBuilder m) {
-    boolean isCommitMessage = Patch.COMMIT_MSG.equals(script.getNewName());
-
-    m.openTr();
-
-    m.openTd();
-    m.addStyleName(Gerrit.RESOURCES.css().iconCell());
-    m.addStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.closeTd();
-
-    m.openTd();
-    m.addStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.addStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.closeTd();
-
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.setAttribute("width", "50%");
-    if (script.getChangeType() == ChangeType.RENAMED
-        || script.getChangeType() == ChangeType.COPIED) {
-      m.append(script.getOldName());
-    } else {
-      m.append(PatchUtil.C.patchHeaderOld());
-    }
-    if (!isCommitMessage) {
-      m.br();
-      if (0 < script.getA().size()) {
-        if (idSideA == null) {
-          downloadLink(m, patchKey, "1");
-        } else {
-          downloadLink(m, new Patch.Key(idSideA, patchKey.get()), "0");
-        }
-      }
-    }
-    m.closeTd();
-
-    m.openTd();
-    m.setStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.setAttribute("width", "50%");
-    m.append(PatchUtil.C.patchHeaderNew());
-    if (!isCommitMessage) {
-      m.br();
-      if (0 < script.getB().size()) {
-        downloadLink(m, new Patch.Key(idSideB, patchKey.get()), "0");
-      }
-    }
-    m.closeTd();
-
-    m.openTd();
-    m.addStyleName(Gerrit.RESOURCES.css().fileColumnHeader());
-    m.addStyleName(Gerrit.RESOURCES.css().lineNumber());
-    m.closeTd();
-
-    m.closeTr();
-  }
-
-  private void downloadLink(final SafeHtmlBuilder m, final Patch.Key key,
-      final String side) {
-    final String base = GWT.getHostPageBaseURL() + "cat/";
-    m.openAnchor();
-    m.setAttribute("href", base + KeyUtil.encode(key.toString()) + "^" + side);
-    m.append(PatchUtil.C.download());
-    m.closeAnchor();
-  }
-
   private void appendSkipLine(final SafeHtmlBuilder m, final int skipCnt) {
     m.openTr();
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginInfo.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginInfo.java
index 454c97b..ace4a49 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginInfo.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginInfo.java
@@ -20,6 +20,8 @@
 
   public final native String name() /*-{ return this.name; }-*/;
   public final native String version() /*-{ return this.version; }-*/;
+  public final native boolean isDisabled()
+      /*-{ return this.disabled ? true : false; }-*/;
 
   protected PluginInfo() {
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginMap.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginMap.java
index 0f2ab4c..6eca206 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginMap.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/plugins/PluginMap.java
@@ -21,7 +21,7 @@
 /** Plugins available from {@code /plugins/}. */
 public class PluginMap extends NativeMap<PluginInfo> {
   public static void all(AsyncCallback<PluginMap> callback) {
-    new RestApi("/plugins/")
+    new RestApi("/plugins/").addParameterTrue("all")
         .send(NativeMap.copyKeysIntoChildren(callback));
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
index 55bb902..408919e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/projects/ProjectMap.java
@@ -37,6 +37,14 @@
         .send(NativeMap.copyKeysIntoChildren(callback));
   }
 
+  public static void parentCandidates(AsyncCallback<ProjectMap> callback) {
+    new RestApi("/projects/")
+        .addParameterRaw("type", "PARENT_CANDIDATES")
+        .addParameterTrue("all")
+        .addParameterTrue("d") // description
+        .send(NativeMap.copyKeysIntoChildren(callback));
+  }
+
   public static void suggest(String prefix, int limit, AsyncCallback<ProjectMap> cb) {
     new RestApi("/projects/" + URL.encode(prefix).replaceAll("[?]", "%3F"))
         .addParameterRaw("type", "ALL")
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
new file mode 100644
index 0000000..217ca5a
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectListPopup.java
@@ -0,0 +1,160 @@
+// Copyright (C) 2011 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.
+
+package com.google.gerrit.client.ui;
+
+import com.google.gerrit.client.account.Util;
+import com.google.gerrit.client.projects.ProjectMap;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwtexpui.globalkey.client.GlobalKey;
+import com.google.gwtexpui.globalkey.client.HidePopupPanelCommand;
+import com.google.gwtexpui.user.client.PluginSafeDialogBox;
+
+/** It creates a popup containing all the projects. */
+public class ProjectListPopup {
+  private ProjectsTable projectsTab;
+  private PluginSafeDialogBox popup;
+  private Button close;
+  private ScrollPanel sp;
+  private PopupPanel.PositionCallback popupPosition;
+  private int preferredTop;
+  private int preferredLeft;
+  private boolean popingUp;
+  private boolean firstPopupLoad = true;
+
+  public void initPopup(final String popupText, final String currentPageLink) {
+    createWidgets(popupText, currentPageLink);
+    final FlowPanel pfp = new FlowPanel();
+    sp = new ScrollPanel(projectsTab);
+    sp.setSize("100%", "100%");
+    pfp.add(sp);
+    pfp.add(close);
+    popup.setWidget(pfp);
+    popup.setHeight("100%");
+    popupPosition = getPositionCallback();
+  }
+
+  protected PopupPanel.PositionCallback getPositionCallback() {
+    return new PopupPanel.PositionCallback() {
+      @Override
+      public void setPosition(int offsetWidth, int offsetHeight) {
+        if (preferredTop + offsetHeight > Window.getClientWidth()) {
+          preferredTop = Window.getClientWidth() - offsetHeight;
+        }
+        if (preferredLeft + offsetWidth > Window.getClientWidth()) {
+          preferredLeft = Window.getClientWidth() - offsetWidth;
+        }
+
+        if (preferredTop < 0) {
+          sp.setHeight((sp.getOffsetHeight() + preferredTop) + "px");
+          preferredTop = 0;
+        }
+        if (preferredLeft < 0) {
+          sp.setWidth((sp.getOffsetWidth() + preferredLeft) + "px");
+          preferredLeft = 0;
+        }
+
+        popup.setPopupPosition(preferredLeft, preferredTop);
+      }
+    };
+  }
+
+  protected void onMovePointerTo(String projectName) {
+  }
+
+  protected void openRow(String projectName) {
+  }
+
+  public boolean isPopingUp() {
+    return popingUp;
+  }
+
+  private void createWidgets(final String popupText,
+      final String currentPageLink) {
+    projectsTab = new ProjectsTable() {
+      @Override
+      protected void movePointerTo(final int row, final boolean scroll) {
+        super.movePointerTo(row, scroll);
+        onMovePointerTo(getRowItem(row).name());
+      }
+
+      @Override
+      protected void onOpenRow(final int row) {
+        super.onOpenRow(row);
+        openRow(getRowItem(row).name());
+      }
+    };
+    projectsTab.setSavePointerId(currentPageLink);
+
+    close = new Button(Util.C.projectsClose());
+    close.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(final ClickEvent event) {
+        closePopup();
+      }
+    });
+
+    popup = new PluginSafeDialogBox();
+    popup.setModal(false);
+    popup.setText(popupText);
+  }
+
+  public void displayPopup() {
+    popingUp = true;
+    if (firstPopupLoad) { // For sizing/positioning, delay display until loaded
+      populateProjects();
+    } else {
+      popup.setPopupPositionAndShow(popupPosition);
+      GlobalKey.dialog(popup);
+      try {
+        GlobalKey.addApplication(popup, new HidePopupPanelCommand(0,
+            KeyCodes.KEY_ESCAPE, popup));
+      } catch (Throwable e) {
+      }
+      projectsTab.setRegisterKeys(true);
+      projectsTab.finishDisplay();
+      popingUp = false;
+    }
+  }
+
+  public void closePopup() {
+    popup.hide();
+  }
+
+  public void setPreferredCoordinates(final int top, final int left) {
+    this.preferredTop = top;
+    this.preferredLeft = left;
+  }
+
+  protected void populateProjects() {
+    ProjectMap.all(new GerritCallback<ProjectMap>() {
+      @Override
+      public void onSuccess(final ProjectMap result) {
+        projectsTab.display(result);
+        if (firstPopupLoad) { // Display was delayed until table was loaded
+          firstPopupLoad = false;
+          displayPopup();
+        }
+      }
+    });
+  }
+}
diff --git a/gerrit-httpd/.settings/org.eclipse.core.resources.prefs b/gerrit-httpd/.settings/org.eclipse.core.resources.prefs
index 9df523e..839d647 100644
--- a/gerrit-httpd/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-httpd/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
index f92f13d..72bb0c2 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
@@ -90,6 +90,10 @@
         config.setAllowedOpenIDs(authConfig.getAllowedOpenIDs());
         break;
 
+      case OPENID_SSO:
+        config.setOpenIdSsoUrl(authConfig.getOpenIdSsoUrl());
+        break;
+
       case LDAP:
       case LDAP_BIND:
         config.setRegisterUrl(cfg.getString("auth", null, "registerurl"));
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index 1c9c521..aea42f4 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -44,7 +44,6 @@
 import org.eclipse.jgit.http.server.resolver.AsIsFileService;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.storage.pack.PackConfig;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.UploadPack;
 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
@@ -177,19 +176,20 @@
   }
 
   static class UploadFactory implements UploadPackFactory<HttpServletRequest> {
-    private final PackConfig packConfig;
+    private final TransferConfig config;
     private final Provider<WebSession> session;
 
     @Inject
     UploadFactory(TransferConfig tc, Provider<WebSession> session) {
-      this.packConfig = tc.getPackConfig();
+      this.config = tc;
       this.session = session;
     }
 
     @Override
     public UploadPack create(HttpServletRequest req, Repository repo) {
       UploadPack up = new UploadPack(repo);
-      up.setPackConfig(packConfig);
+      up.setPackConfig(config.getPackConfig());
+      up.setTimeout(config.getTimeout());
       session.get().setAccessPath(AccessPath.GIT);
       return up;
     }
@@ -239,12 +239,14 @@
   static class ReceiveFactory implements ReceivePackFactory<HttpServletRequest> {
     private final AsyncReceiveCommits.Factory factory;
     private final Provider<WebSession> session;
+    private final TransferConfig config;
 
     @Inject
     ReceiveFactory(AsyncReceiveCommits.Factory factory,
-        Provider<WebSession> session) {
+        Provider<WebSession> session, TransferConfig config) {
       this.factory = factory;
       this.session = session;
+      this.config = config;
     }
 
     @Override
@@ -259,10 +261,13 @@
 
       final IdentifiedUser user = (IdentifiedUser) pc.getCurrentUser();
       final ReceiveCommits rc = factory.create(pc, db).getReceiveCommits();
-      rc.getReceivePack().setRefLogIdent(user.newRefLogIdent());
+      ReceivePack rp = rc.getReceivePack();
+      rp.setRefLogIdent(user.newRefLogIdent());
+      rp.setTimeout(config.getTimeout());
+      rp.setMaxObjectSizeLimit(config.getMaxObjectSizeLimit());
       req.setAttribute(ATT_RC, rc);
       session.get().setAccessPath(AccessPath.GIT);
-      return rc.getReceivePack();
+      return rp;
     }
   }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
index 0d14b79..1a48bb5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
@@ -108,6 +108,7 @@
         break;
 
       case OPENID:
+      case OPENID_SSO:
         // OpenID support is bound in WebAppInitializer and Daemon.
       case CUSTOM_EXTENSION:
         break;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ThemeFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ThemeFactory.java
index 68379d7..a2f4c99 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ThemeFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ThemeFactory.java
@@ -43,6 +43,9 @@
     theme.trimColor = color(name, "trimColor", "#D4E9A9");
     theme.selectionColor = color(name, "selectionColor", "#FFFFCC");
     theme.topMenuColor = color(name, "topMenuColor", theme.trimColor);
+    theme.changeTableOutdatedColor = color(name, "changeTableOutdatedColor", "#FF0000");
+    theme.tableOddRowColor = color(name, "tableOddRowColor", "transparent");
+    theme.tableEvenRowColor = color(name, "tableEvenRowColor", "transparent");
     return theme;
   }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
index c7b4c79..aca2e05 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
@@ -31,15 +31,20 @@
 import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit;
 import com.google.gerrit.reviewdb.client.AccountGroupMember;
 import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountException;
+import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.account.AccountResolver;
+import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.account.GroupBackend;
 import com.google.gerrit.server.account.GroupBackends;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.account.GroupControl;
 import com.google.gerrit.server.account.GroupIncludeCache;
+import com.google.gerrit.server.config.AuthConfig;
 import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwtjsonrpc.common.VoidResult;
 import com.google.gwtorm.server.OrmException;
@@ -54,6 +59,8 @@
     GroupAdminService {
   private final AccountCache accountCache;
   private final AccountResolver accountResolver;
+  private final AccountManager accountManager;
+  private final AuthType authType;
   private final GroupCache groupCache;
   private final GroupBackend groupBackend;
   private final GroupIncludeCache groupIncludeCache;
@@ -70,6 +77,8 @@
       final AccountCache accountCache,
       final GroupIncludeCache groupIncludeCache,
       final AccountResolver accountResolver,
+      final AccountManager accountManager,
+      final AuthConfig authConfig,
       final GroupCache groupCache,
       final GroupBackend groupBackend,
       final GroupControl.Factory groupControlFactory,
@@ -81,6 +90,8 @@
     this.accountCache = accountCache;
     this.groupIncludeCache = groupIncludeCache;
     this.accountResolver = accountResolver;
+    this.accountManager = accountManager;
+    this.authType = authConfig.getAuthType();
     this.groupCache = groupCache;
     this.groupBackend = groupBackend;
     this.groupControlFactory = groupControlFactory;
@@ -366,13 +377,38 @@
 
   private Account findAccount(final String nameOrEmail) throws OrmException,
       Failure {
-    final Account r = accountResolver.find(nameOrEmail);
+    Account r = accountResolver.find(nameOrEmail);
     if (r == null) {
-      throw new Failure(new NoSuchAccountException(nameOrEmail));
+      switch (authType) {
+        case HTTP_LDAP:
+        case CLIENT_SSL_CERT_LDAP:
+        case LDAP:
+          r = createAccountByLdap(nameOrEmail);
+          break;
+        default:
+      }
+      if (r == null) {
+        throw new Failure(new NoSuchAccountException(nameOrEmail));
+      }
     }
     return r;
   }
 
+  private Account createAccountByLdap(String user) {
+    if (!user.matches(Account.USER_NAME_PATTERN)) {
+      return null;
+    }
+
+    try {
+      final AuthRequest req = AuthRequest.forUser(user);
+      req.setSkipAuthentication(true);
+      return accountCache.get(accountManager.authenticate(req).getAccountId())
+          .getAccount();
+    } catch (AccountException e) {
+      return null;
+    }
+  }
+
   private AccountGroup findGroup(final String name) throws OrmException,
       Failure {
     final AccountGroup g = groupCache.get(new AccountGroup.NameKey(name));
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
index 09dc582..24faf9e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.httpd.rpc.account;
 
 import com.google.gerrit.common.data.GroupDetail;
+import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.httpd.rpc.Handler;
@@ -44,7 +45,7 @@
 
   @Override
   public GroupDetail call() throws OrmException, NameAlreadyUsedException,
-      NoSuchGroupException {
+      NoSuchGroupException, InvalidNameException {
     return performRenameGroupFactory.create().renameGroup(groupId, newName);
   }
 }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
index a929b6e..6660a3d 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.ProjectUtil;
 import com.google.gerrit.server.account.AccountInfoCacheFactory;
@@ -41,6 +42,7 @@
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.workflow.CategoryFunction;
 import com.google.gerrit.server.workflow.FunctionState;
 import com.google.gwtorm.server.OrmException;
@@ -252,6 +254,15 @@
     detail.setApprovals(ad.values());
   }
 
+  private boolean isReviewer(Change change) {
+    // Return true if the currently logged in user is a reviewer of the change.
+    try {
+      return control.isReviewer(db, new ChangeData(change));
+    } catch (OrmException e) {
+        return false;
+    }
+  }
+
   private void loadCurrentPatchSet() throws OrmException,
       NoSuchEntityException, PatchSetInfoNotAvailableException,
       NoSuchChangeException {
@@ -292,11 +303,21 @@
     final Map<Change.Id, Change> m =
         db.changes().toMap(db.changes().get(changesToGet));
 
+    final CurrentUser currentUser = control.getCurrentUser();
+    Account.Id currentUserId = null;
+    if (currentUser instanceof IdentifiedUser) {
+        currentUserId = ((IdentifiedUser) currentUser).getAccountId();
+    }
+
     final ArrayList<ChangeInfo> dependsOn = new ArrayList<ChangeInfo>();
     for (final Change.Id a : ancestorOrder) {
       final Change ac = m.get(a);
       if (ac != null && ac.getProject().equals(detail.getChange().getProject())) {
-        dependsOn.add(newChangeInfo(ac, ancestorPatchIds));
+        if (ac.getStatus().getCode() != Change.STATUS_DRAFT
+            || ac.getOwner().equals(currentUserId)
+            || isReviewer(ac)) {
+          dependsOn.add(newChangeInfo(ac, ancestorPatchIds));
+        }
       }
     }
 
@@ -304,7 +325,11 @@
     for (final PatchSet.Id a : descendants) {
       final Change ac = m.get(a.getParentKey());
       if (ac != null && ac.currentPatchSetId().equals(a)) {
-        neededBy.add(newChangeInfo(ac, null));
+        if (ac.getStatus().getCode() != Change.STATUS_DRAFT
+            || ac.getOwner().equals(currentUserId)
+            || isReviewer(ac)) {
+          neededBy.add(newChangeInfo(ac, null));
+        }
       }
     }
 
diff --git a/gerrit-launcher/.settings/org.eclipse.core.resources.prefs b/gerrit-launcher/.settings/org.eclipse.core.resources.prefs
index c780f44..e9441bb 100644
--- a/gerrit-launcher/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-launcher/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-main/.settings/org.eclipse.core.resources.prefs b/gerrit-main/.settings/org.eclipse.core.resources.prefs
index c780f44..e9441bb 100644
--- a/gerrit-main/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-main/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-openid/.settings/org.eclipse.core.resources.prefs b/gerrit-openid/.settings/org.eclipse.core.resources.prefs
index fc11c3f..f9fe345 100644
--- a/gerrit-openid/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-openid/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/test/java=UTF-8
diff --git a/gerrit-patch-commonsnet/.settings/org.eclipse.core.resources.prefs b/gerrit-patch-commonsnet/.settings/org.eclipse.core.resources.prefs
index 589908f..e9441bb 100644
--- a/gerrit-patch-commonsnet/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-patch-commonsnet/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:35 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-patch-jgit/.settings/org.eclipse.core.resources.prefs b/gerrit-patch-jgit/.settings/org.eclipse.core.resources.prefs
index 589908f..e9441bb 100644
--- a/gerrit-patch-jgit/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-patch-jgit/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:35 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-pgm/.settings/org.eclipse.core.resources.prefs b/gerrit-pgm/.settings/org.eclipse.core.resources.prefs
index 9df523e..839d647 100644
--- a/gerrit-pgm/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-pgm/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index 263b2b4..7d27482 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -369,7 +369,8 @@
     }
 
     AuthConfig authConfig = cfgInjector.getInstance(AuthConfig.class);
-    if (authConfig.getAuthType() == AuthType.OPENID) {
+    if (authConfig.getAuthType() == AuthType.OPENID ||
+        authConfig.getAuthType() == AuthType.OPENID_SSO) {
       modules.add(new OpenIdModule());
     }
     modules.add(sysInjector.getInstance(GetUserFilter.Module.class));
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java
index f100372..525360d 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.pgm.util.SiteProgram;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountCacheImpl;
@@ -35,6 +34,7 @@
 import com.google.gerrit.server.git.CreateCodeReviewNotes;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.LocalDiskRepositoryManager;
+import com.google.gerrit.server.git.NotesBranchUtil;
 import com.google.gerrit.server.schema.SchemaVersionCheck;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
@@ -44,7 +44,6 @@
 import com.google.inject.Scopes;
 
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.TextProgressMonitor;
 import org.eclipse.jgit.lib.ThreadSafeProgressMonitor;
@@ -104,6 +103,7 @@
           @Override
           protected void configure() {
             factory(CreateCodeReviewNotes.Factory.class);
+            factory(NotesBranchUtil.Factory.class);
           }
         });
         install(new LifecycleModule() {
@@ -172,21 +172,8 @@
     }
     try {
       CreateCodeReviewNotes notes = codeReviewNotesFactory.create(db, git);
-      try {
-        notes.loadBase();
-        for (Change change : changes) {
-          monitor.update(1);
-          PatchSet ps = db.patchSets().get(change.currentPatchSetId());
-          if (ps == null) {
-            continue;
-          }
-          notes.add(change, ObjectId.fromString(ps.getRevision().get()));
-        }
-        notes.commit("Exported prior reviews from Gerrit Code Review\n");
-        notes.updateRef();
-      } finally {
-        notes.release();
-      }
+      notes.create(changes, null,
+          "Exported prior reviews from Gerrit Code Review\n", monitor);
     } finally {
       git.close();
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
index 2d56453..95b8487f 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
@@ -141,12 +141,12 @@
       }
 
       final StringBuilder buf = new StringBuilder();
-      buf.append(why.getMessage());
-      why = why.getCause();
       while (why != null) {
-        buf.append("\n  caused by ");
-        buf.append(why.toString());
+        buf.append(why.getMessage());
         why = why.getCause();
+        if (why != null) {
+          buf.append("\n  caused by ");
+        }
       }
       throw die(buf.toString(), new RuntimeException("InitInjector failed", ce));
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java
index ee7c794..2d6db63 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/ProjectQoSFilter.java
@@ -97,7 +97,7 @@
     this.userProvider = userProvider;
     this.queue = queue;
     this.context = context;
-    this.maxWait = getTimeUnit(cfg, "httpd", null, "maxwait", 5, MINUTES);
+    this.maxWait = MINUTES.toMillis(getTimeUnit(cfg, "httpd", null, "maxwait", 5, MINUTES));
   }
 
   @Override
diff --git a/gerrit-plugin-archetype/.settings/org.eclipse.core.resources.prefs b/gerrit-plugin-archetype/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..abdea9ac
--- /dev/null
+++ b/gerrit-plugin-archetype/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding/<project>=UTF-8
diff --git a/gerrit-plugin-archetype/.settings/org.eclipse.jdt.core.prefs b/gerrit-plugin-archetype/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..470942d
--- /dev/null
+++ b/gerrit-plugin-archetype/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,269 @@
+#Thu Jul 28 11:02:36 PDT 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=16
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=0
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=0
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=2
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=true
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
index 88328be..ce8fa1a 100644
--- a/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
+++ b/gerrit-plugin-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -14,7 +14,7 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<archetype-descriptor name="com.sap.ldi.qi.itests">
+<archetype-descriptor name="Gerrit Plugin">
   <requiredProperties>
     <requiredProperty key="pluginName"/>
 
diff --git a/gerrit-prettify/.settings/org.eclipse.core.resources.prefs b/gerrit-prettify/.settings/org.eclipse.core.resources.prefs
index e7d6680..abdea9ac 100644
--- a/gerrit-prettify/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-prettify/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:35 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
diff --git a/gerrit-reviewdb/.settings/org.eclipse.core.resources.prefs b/gerrit-reviewdb/.settings/org.eclipse.core.resources.prefs
index e7d6680..abdea9ac 100644
--- a/gerrit-reviewdb/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-reviewdb/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:35 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
index 962426b..b615fc5 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
@@ -18,6 +18,9 @@
   /** Login relies upon the OpenID standard: {@link "http://openid.net/"} */
   OPENID,
 
+  /** Login relies upon the OpenID standard: {@link "http://openid.net/"} in Single Sign On mode */
+  OPENID_SSO,
+
   /**
    * Login relies upon the container/web server security.
    * <p>
diff --git a/gerrit-server/.settings/org.eclipse.core.resources.prefs b/gerrit-server/.settings/org.eclipse.core.resources.prefs
index 7d5f965..29abf99 100644
--- a/gerrit-server/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-server/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
index 79c047f..935a707 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
@@ -35,7 +35,7 @@
 import com.google.gerrit.server.events.ChangeAbandonedEvent;
 import com.google.gerrit.server.events.ChangeEvent;
 import com.google.gerrit.server.events.ChangeMergedEvent;
-import com.google.gerrit.server.events.ChangeRestoreEvent;
+import com.google.gerrit.server.events.ChangeRestoredEvent;
 import com.google.gerrit.server.events.CommentAddedEvent;
 import com.google.gerrit.server.events.DraftPublishedEvent;
 import com.google.gerrit.server.events.EventFactory;
@@ -111,7 +111,7 @@
     /** Filename of the change abandoned hook. */
     private final File changeAbandonedHook;
 
-    /** Filename of the change abandoned hook. */
+    /** Filename of the change restored hook. */
     private final File changeRestoredHook;
 
     /** Filename of the ref updated hook. */
@@ -339,9 +339,9 @@
         runHook(change.getProject(), changeAbandonedHook, args);
     }
 
-    public void doChangeRestoreHook(final Change change, final Account account,
+    public void doChangeRestoredHook(final Change change, final Account account,
           final String reason, final ReviewDb db) throws OrmException {
-        final ChangeRestoreEvent event = new ChangeRestoreEvent();
+        final ChangeRestoredEvent event = new ChangeRestoredEvent();
 
         event.change = eventFactory.asChangeAttribute(change);
         event.restorer = eventFactory.asAccountAttribute(account);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
index 0c86049..134057d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
@@ -61,7 +61,7 @@
    *
    * @param change The change itself.
    * @param patchSet The patchset this comment is related to.
-   * @param account The gerrit user who commited the change.
+   * @param account The gerrit user who added the comment.
    * @param comment The comment given.
    * @param approvals Map of Approval Categories and Scores
    * @throws OrmException
@@ -75,7 +75,7 @@
    * Fire the Change Merged Hook.
    *
    * @param change The change itself.
-   * @param account The gerrit user who commited the change.
+   * @param account The gerrit user who submitted the change.
    * @param patchSet The patchset that was merged.
    * @throws OrmException
    */
@@ -101,7 +101,7 @@
    * @param reason Reason for restoring the change.
    * @throws OrmException
    */
-  public void doChangeRestoreHook(Change change, Account account,
+  public void doChangeRestoredHook(Change change, Account account,
       String reason, ReviewDb db) throws OrmException;
 
   /**
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
index 357a8b9..f30f5ea 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
@@ -46,7 +46,7 @@
   }
 
   @Override
-  public void doChangeRestoreHook(Change change, Account account,
+  public void doChangeRestoredHook(Change change, Account account,
       String reason, ReviewDb db) {
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
index a0814f5..3868710 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
@@ -62,6 +62,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.util.Base64;
+import org.eclipse.jgit.util.ChangeIdUtil;
 import org.eclipse.jgit.util.NB;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -463,7 +464,11 @@
       revertCommit.setTreeId(parentToCommitToRevert.getTree());
       revertCommit.setAuthor(authorIdent);
       revertCommit.setCommitter(myIdent);
-      revertCommit.setMessage(message);
+
+      final ObjectId computedChangeId =
+          ChangeIdUtil.computeChangeId(parentToCommitToRevert.getTree(),
+              commitToRevert, authorIdent, myIdent, message);
+      revertCommit.setMessage(ChangeIdUtil.insertId(message, computedChangeId, true));
 
       final ObjectInserter oi = git.newObjectInserter();;
       ObjectId id;
@@ -474,7 +479,7 @@
         oi.release();
       }
 
-      Change.Key changeKey = new Change.Key("I" + id.name());
+      Change.Key changeKey = new Change.Key("I" + computedChangeId.name());
       final Change change =
           new Change(changeKey, new Change.Id(db.nextChangeId()),
               user.getAccountId(), db.changes().get(changeId).getDest());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
index 6db232a..4c72d49 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.account;
 
 import com.google.gerrit.common.data.GroupDetail;
+import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -60,7 +61,7 @@
 
   public GroupDetail renameGroup(final String groupName,
       final String newGroupName) throws OrmException, NameAlreadyUsedException,
-      NoSuchGroupException {
+      NoSuchGroupException, InvalidNameException {
     final AccountGroup.NameKey groupNameKey =
         new AccountGroup.NameKey(groupName);
     final AccountGroup group = groupCache.get(groupNameKey);
@@ -72,12 +73,15 @@
 
   public GroupDetail renameGroup(final AccountGroup.Id groupId,
       final String newName) throws OrmException, NameAlreadyUsedException,
-      NoSuchGroupException {
+      NoSuchGroupException, InvalidNameException {
     final GroupControl ctl = groupControlFactory.validateFor(groupId);
     final AccountGroup group = db.accountGroups().get(groupId);
     if (group == null || !ctl.isOwner()) {
       throw new NoSuchGroupException(groupId);
     }
+    if (newName.trim().isEmpty()) {
+      throw new InvalidNameException();
+    }
 
     final AccountGroup.NameKey old = group.getNameKey();
     final AccountGroup.NameKey key = new AccountGroup.NameKey(newName);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java
index 875ae06..53da2b6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java
@@ -149,8 +149,8 @@
 
     ChangeUtil.updatedChange(db, currentUser, updatedChange, cmsg,
                              restoredSenderFactory);
-    hooks.doChangeRestoreHook(updatedChange, currentUser.getAccount(),
-                              message, db);
+    hooks.doChangeRestoredHook(updatedChange, currentUser.getAccount(),
+                               message, db);
 
     return result;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
index 6f1096c..dc36988 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
@@ -39,6 +39,7 @@
   private final boolean userNameToLowerCase;
   private final boolean gitBasicAuth;
   private final String logoutUrl;
+  private final String openIdSsoUrl;
   private final List<OpenIdProviderPattern> trustedOpenIDs;
   private final List<OpenIdProviderPattern> allowedOpenIDs;
   private final String cookiePath;
@@ -53,6 +54,7 @@
     authType = toType(cfg);
     httpHeader = cfg.getString("auth", null, "httpheader");
     logoutUrl = cfg.getString("auth", null, "logouturl");
+    openIdSsoUrl = cfg.getString("auth", null, "openidssourl");
     trustedOpenIDs = toPatterns(cfg, "trustedOpenID");
     allowedOpenIDs = toPatterns(cfg, "allowedOpenID");
     cookiePath = cfg.getString("auth", null, "cookiepath");
@@ -111,6 +113,10 @@
     return logoutUrl;
   }
 
+  public String getOpenIdSsoUrl() {
+    return openIdSsoUrl;
+  }
+
   public String getCookiePath() {
     return cookiePath;
   }
@@ -161,6 +167,10 @@
         //
         return true;
 
+      case OPENID_SSO:
+        // There's only one provider in SSO mode, so it must be okay.
+        return true;
+
       case OPENID:
         // All identities must be trusted in order to trust the account.
         //
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
index 71676ad..ba54c56 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
@@ -35,6 +35,7 @@
 import com.google.gerrit.server.git.CreateCodeReviewNotes;
 import com.google.gerrit.server.git.MergeOp;
 import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.NotesBranchUtil;
 import com.google.gerrit.server.git.SubmoduleOp;
 import com.google.gerrit.server.mail.AbandonedSender;
 import com.google.gerrit.server.mail.AddReviewerSender;
@@ -82,6 +83,7 @@
     factory(SubmoduleOp.Factory.class);
     factory(MergeOp.Factory.class);
     factory(CreateCodeReviewNotes.Factory.class);
+    factory(NotesBranchUtil.Factory.class);
     install(new AsyncReceiveCommits.Module());
 
     // Not really per-request, but dammit, I don't know where else to
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeRestoreEvent.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeRestoredEvent.java
similarity index 93%
rename from gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeRestoreEvent.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeRestoredEvent.java
index 1a2922b..717e23c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeRestoreEvent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeRestoredEvent.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.events;
 
-public class ChangeRestoreEvent extends ChangeEvent {
+public class ChangeRestoredEvent extends ChangeEvent {
     public final String type = "change-restored";
     public ChangeAttribute change;
     public PatchSetAttribute patchSet;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommit.java
index 4bfee9c..da38573 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BanCommit.java
@@ -16,6 +16,7 @@
 
 import static com.google.gerrit.server.git.GitRepositoryManager.REF_REJECT_COMMITS;
 
+import com.google.common.base.Strings;
 import com.google.gerrit.common.errors.PermissionDeniedException;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
@@ -23,34 +24,25 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.lib.CommitBuilder;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.RefUpdate.Result;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.notes.Note;
 import org.eclipse.jgit.notes.NoteMap;
-import org.eclipse.jgit.notes.NoteMapMerger;
-import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.util.Date;
 import java.util.List;
 import java.util.TimeZone;
 
 public class BanCommit {
-
-  private static final int MAX_LOCK_FAILURE_CALLS = 10;
-  private static final int SLEEP_ON_LOCK_FAILURE_MS = 25;
-
   public interface Factory {
     BanCommit create();
   }
@@ -58,49 +50,37 @@
   private final Provider<IdentifiedUser> currentUser;
   private final GitRepositoryManager repoManager;
   private final PersonIdent gerritIdent;
+  private NotesBranchUtil.Factory notesBranchUtilFactory;
 
   @Inject
   BanCommit(final Provider<IdentifiedUser> currentUser,
       final GitRepositoryManager repoManager,
-      @GerritPersonIdent final PersonIdent gerritIdent) {
+      @GerritPersonIdent final PersonIdent gerritIdent,
+      final NotesBranchUtil.Factory notesBranchUtilFactory) {
     this.currentUser = currentUser;
     this.repoManager = repoManager;
     this.gerritIdent = gerritIdent;
+    this.notesBranchUtilFactory = notesBranchUtilFactory;
   }
 
   public BanCommitResult ban(final ProjectControl projectControl,
       final List<ObjectId> commitsToBan, final String reason)
       throws PermissionDeniedException, IOException,
-      InterruptedException, MergeException {
+      InterruptedException, MergeException, ConcurrentRefUpdateException {
     if (!projectControl.isOwner()) {
       throw new PermissionDeniedException(
           "No project owner: not permitted to ban commits");
     }
 
     final BanCommitResult result = new BanCommitResult();
-
-    final PersonIdent currentUserIdent = createPersonIdent();
+    NoteMap banCommitNotes = NoteMap.newEmptyMap();
+    // add a note for each banned commit to notes
     final Repository repo =
         repoManager.openRepository(projectControl.getProject().getNameKey());
     try {
       final RevWalk revWalk = new RevWalk(repo);
       final ObjectInserter inserter = repo.newObjectInserter();
       try {
-        NoteMap baseNoteMap = null;
-        RevCommit baseCommit = null;
-        final Ref notesBranch = repo.getRef(REF_REJECT_COMMITS);
-        if (notesBranch != null) {
-          baseCommit = revWalk.parseCommit(notesBranch.getObjectId());
-          baseNoteMap = NoteMap.read(revWalk.getObjectReader(), baseCommit);
-        }
-
-        final NoteMap ourNoteMap;
-        if (baseCommit != null) {
-          ourNoteMap = NoteMap.read(repo.newObjectReader(), baseCommit);
-        } else {
-          ourNoteMap = NoteMap.newEmptyMap();
-        }
-
         for (final ObjectId commitToBan : commitsToBan) {
           try {
             revWalk.parseCommit(commitToBan);
@@ -110,31 +90,22 @@
             result.notACommit(commitToBan, e.getMessage());
             continue;
           }
+          banCommitNotes.set(commitToBan, createNoteContent(reason, inserter));
+        }
+        inserter.flush();
+        NotesBranchUtil notesBranchUtil = notesBranchUtilFactory.create(repo);
+        NoteMap newlyCreated =
+            notesBranchUtil.commitNewNotes(banCommitNotes, REF_REJECT_COMMITS,
+                createPersonIdent(), buildCommitMessage(commitsToBan, reason));
 
-          final Note note = ourNoteMap.getNote(commitToBan);
-          if (note != null) {
-            result.commitAlreadyBanned(commitToBan);
-            continue;
+        for (Note n : banCommitNotes) {
+          if (newlyCreated.contains(n)) {
+            result.commitBanned(n);
+          } else {
+            result.commitAlreadyBanned(n);
           }
-
-          final String noteContent = reason != null ? reason : "";
-          final ObjectId noteContentId =
-              inserter
-                  .insert(Constants.OBJ_BLOB, noteContent.getBytes("UTF-8"));
-          ourNoteMap.set(commitToBan, noteContentId);
-          result.commitBanned(commitToBan);
         }
-
-        if (result.getNewlyBannedCommits().isEmpty()) {
-          return result;
-        }
-
-        final ObjectId ourCommit =
-            commit(ourNoteMap, inserter, currentUserIdent, baseCommit, result,
-                reason);
-
-        updateRef(repo, revWalk, inserter, ourNoteMap, ourCommit, baseNoteMap,
-            baseCommit);
+        return result;
       } finally {
         revWalk.release();
         inserter.release();
@@ -142,8 +113,15 @@
     } finally {
       repo.close();
     }
+  }
 
-    return result;
+  private ObjectId createNoteContent(String reason, ObjectInserter inserter)
+      throws UnsupportedEncodingException, IOException {
+    String noteContent = reason != null ? reason : "";
+    if (noteContent.length() > 0 && !noteContent.endsWith("\n")) {
+      noteContent = noteContent + "\n";
+    }
+    return inserter.insert(Constants.OBJ_BLOB, noteContent.getBytes("UTF-8"));
   }
 
   private PersonIdent createPersonIdent() {
@@ -152,35 +130,6 @@
     return currentUser.get().newCommitterIdent(now, tz);
   }
 
-  private static ObjectId commit(final NoteMap noteMap,
-      final ObjectInserter inserter, final PersonIdent personIdent,
-      final ObjectId baseCommit, final BanCommitResult result,
-      final String reason) throws IOException {
-    final String commitMsg =
-        buildCommitMessage(result.getNewlyBannedCommits(), reason);
-    if (baseCommit != null) {
-      return createCommit(noteMap, inserter, personIdent, commitMsg, baseCommit);
-    } else {
-      return createCommit(noteMap, inserter, personIdent, commitMsg);
-    }
-  }
-
-  private static ObjectId createCommit(final NoteMap noteMap,
-      final ObjectInserter inserter, final PersonIdent personIdent,
-      final String message, final ObjectId... parents) throws IOException {
-    final CommitBuilder b = new CommitBuilder();
-    b.setTreeId(noteMap.writeTree(inserter));
-    b.setAuthor(personIdent);
-    b.setCommitter(personIdent);
-    if (parents.length > 0) {
-      b.setParentIds(parents);
-    }
-    b.setMessage(message);
-    final ObjectId commitId = inserter.insert(b);
-    inserter.flush();
-    return commitId;
-  }
-
   private static String buildCommitMessage(final List<ObjectId> bannedCommits,
       final String reason) {
     final StringBuilder commitMsg = new StringBuilder();
@@ -205,61 +154,4 @@
     commitMsg.append(commitList);
     return commitMsg.toString();
   }
-
-  public void updateRef(final Repository repo, final RevWalk revWalk,
-      final ObjectInserter inserter, final NoteMap ourNoteMap,
-      final ObjectId oursCommit, final NoteMap baseNoteMap,
-      final ObjectId baseCommit) throws IOException, InterruptedException,
-      MissingObjectException, IncorrectObjectTypeException,
-      CorruptObjectException, MergeException {
-
-    int remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
-    RefUpdate refUpdate = createRefUpdate(repo, oursCommit, baseCommit);
-
-    for (;;) {
-      final Result result = refUpdate.update();
-
-      if (result == Result.LOCK_FAILURE) {
-        if (--remainingLockFailureCalls > 0) {
-          Thread.sleep(SLEEP_ON_LOCK_FAILURE_MS);
-        } else {
-          throw new MergeException("Failed to lock the ref: "
-              + REF_REJECT_COMMITS);
-        }
-
-      } else if (result == Result.REJECTED) {
-        final RevCommit theirsCommit =
-            revWalk.parseCommit(refUpdate.getOldObjectId());
-        final NoteMap theirNoteMap =
-            NoteMap.read(revWalk.getObjectReader(), theirsCommit);
-        final NoteMapMerger merger = new NoteMapMerger(repo);
-        final NoteMap merged =
-            merger.merge(baseNoteMap, ourNoteMap, theirNoteMap);
-        final ObjectId mergeCommit =
-            createCommit(merged, inserter, gerritIdent,
-                "Merged note commits\n", oursCommit, theirsCommit);
-        refUpdate = createRefUpdate(repo, mergeCommit, theirsCommit);
-        remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
-
-      } else if (result == Result.IO_FAILURE) {
-        throw new IOException(
-            "Couldn't create commit reject notes because of IO_FAILURE");
-      } else {
-        break;
-      }
-    }
-  }
-
-  private static RefUpdate createRefUpdate(final Repository repo,
-      final ObjectId newObjectId, final ObjectId expectedOldObjectId)
-      throws IOException {
-    RefUpdate refUpdate = repo.updateRef(REF_REJECT_COMMITS);
-    refUpdate.setNewObjectId(newObjectId);
-    if (expectedOldObjectId == null) {
-      refUpdate.setExpectedOldObjectId(ObjectId.zeroId());
-    } else {
-      refUpdate.setExpectedOldObjectId(expectedOldObjectId);
-    }
-    return refUpdate;
-  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java
index 6fea8f1..b067a49 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java
@@ -20,6 +20,7 @@
 import com.google.gerrit.common.data.ApprovalTypes;
 import com.google.gerrit.reviewdb.client.ApprovalCategory;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
@@ -31,23 +32,15 @@
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
-import org.eclipse.jgit.errors.CorruptObjectException;
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
 import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.ProgressMonitor;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.notes.Note;
 import org.eclipse.jgit.notes.NoteMap;
-import org.eclipse.jgit.notes.NoteMapMerger;
-import org.eclipse.jgit.notes.NoteMerger;
 import org.eclipse.jgit.revwalk.FooterKey;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -68,30 +61,22 @@
     CreateCodeReviewNotes create(ReviewDb reviewDb, Repository db);
   }
 
-  private static final int MAX_LOCK_FAILURE_CALLS = 10;
-  private static final int SLEEP_ON_LOCK_FAILURE_MS = 25;
   private static final FooterKey CHANGE_ID = new FooterKey("Change-Id");
 
-  private final ReviewDb schema;
-  private final PersonIdent gerritIdent;
   private final AccountCache accountCache;
   private final ApprovalTypes approvalTypes;
   private final String canonicalWebUrl;
   private final String anonymousCowardName;
+  private final ReviewDb schema;
   private final Repository db;
-  private final RevWalk revWalk;
-  private final ObjectInserter inserter;
-  private final ObjectReader reader;
 
-  private RevCommit baseCommit;
-  private NoteMap base;
-
-  private RevCommit oursCommit;
-  private NoteMap ours;
-
-  private List<CodeReviewCommit> commits;
   private PersonIdent author;
 
+  private RevWalk revWalk;
+  private ObjectInserter inserter;
+
+  private final NotesBranchUtil.Factory notesBranchUtilFactory;
+
   @Inject
   CreateCodeReviewNotes(
       @GerritPersonIdent final PersonIdent gerritIdent,
@@ -99,90 +84,87 @@
       final ApprovalTypes approvalTypes,
       final @Nullable @CanonicalWebUrl String canonicalWebUrl,
       final @AnonymousCowardName String anonymousCowardName,
+      final NotesBranchUtil.Factory notesBranchUtilFactory,
       final @Assisted  ReviewDb reviewDb,
       final @Assisted  Repository db) {
-    schema = reviewDb;
     this.author = gerritIdent;
-    this.gerritIdent = gerritIdent;
     this.accountCache = accountCache;
     this.approvalTypes = approvalTypes;
     this.canonicalWebUrl = canonicalWebUrl;
     this.anonymousCowardName = anonymousCowardName;
+    this.notesBranchUtilFactory = notesBranchUtilFactory;
+    schema = reviewDb;
     this.db = db;
-
-    revWalk = new RevWalk(db);
-    inserter = db.newObjectInserter();
-    reader = db.newObjectReader();
   }
 
   public void create(List<CodeReviewCommit> commits, PersonIdent author)
       throws CodeReviewNoteCreationException {
     try {
-      this.commits = commits;
-      this.author = author;
-      loadBase();
-      applyNotes();
-      updateRef();
+      revWalk = new RevWalk(db);
+      inserter = db.newObjectInserter();
+      if (author != null) {
+        this.author = author;
+      }
+
+      NoteMap notes = NoteMap.newEmptyMap();
+      StringBuilder message =
+          new StringBuilder("Update notes for submitted changes\n\n");
+      for (CodeReviewCommit c : commits) {
+        notes.set(c, createNoteContent(c.change, c));
+        message.append("* ").append(c.getShortMessage()).append("\n");
+      }
+
+      NotesBranchUtil notesBranchUtil = notesBranchUtilFactory.create(db);
+      notesBranchUtil.commitAllNotes(notes, REFS_NOTES_REVIEW, author,
+          message.toString());
     } catch (IOException e) {
       throw new CodeReviewNoteCreationException(e);
-    } catch (InterruptedException e) {
+    } catch (ConcurrentRefUpdateException e) {
       throw new CodeReviewNoteCreationException(e);
     } finally {
-      release();
+      revWalk.release();
+      inserter.release();
     }
   }
 
-  public void loadBase() throws IOException {
-    Ref notesBranch = db.getRef(REFS_NOTES_REVIEW);
-    if (notesBranch != null) {
-      baseCommit = revWalk.parseCommit(notesBranch.getObjectId());
-      base = NoteMap.read(revWalk.getObjectReader(), baseCommit);
-    }
-    if (baseCommit != null) {
-      ours = NoteMap.read(db.newObjectReader(), baseCommit);
-    } else {
-      ours = NoteMap.newEmptyMap();
+  public void create(List<Change> changes, PersonIdent author,
+      String commitMessage, ProgressMonitor monitor) throws OrmException,
+      IOException, CodeReviewNoteCreationException {
+    try {
+      revWalk = new RevWalk(db);
+      inserter = db.newObjectInserter();
+      if (author != null) {
+        this.author = author;
+      }
+      if (monitor == null) {
+        monitor = NullProgressMonitor.INSTANCE;
+      }
+
+      NoteMap notes = NoteMap.newEmptyMap();
+      for (Change c : changes) {
+        monitor.update(1);
+        PatchSet ps = schema.patchSets().get(c.currentPatchSetId());
+        ObjectId commitId = ObjectId.fromString(ps.getRevision().get());
+        notes.set(commitId, createNoteContent(c, commitId));
+      }
+
+      NotesBranchUtil notesBranchUtil = notesBranchUtilFactory.create(db);
+      notesBranchUtil.commitAllNotes(notes, REFS_NOTES_REVIEW, author,
+          commitMessage);
+    } catch (ConcurrentRefUpdateException e) {
+      throw new CodeReviewNoteCreationException(e);
+    } finally {
+      revWalk.release();
+      inserter.release();
     }
   }
 
-  private void applyNotes() throws IOException, CodeReviewNoteCreationException {
-    StringBuilder message =
-        new StringBuilder("Update notes for submitted changes\n\n");
-    for (CodeReviewCommit c : commits) {
-      add(c.change, c);
-      message.append("* ").append(c.getShortMessage()).append("\n");
-    }
-    commit(message.toString());
-  }
-
-  public void commit(String message) throws IOException {
-    if (baseCommit != null) {
-      oursCommit = createCommit(ours, author, message, baseCommit);
-    } else {
-      oursCommit = createCommit(ours, author, message);
-    }
-  }
-
-  public void add(Change change, ObjectId commit)
-      throws MissingObjectException, IncorrectObjectTypeException, IOException,
-      CodeReviewNoteCreationException {
+  private ObjectId createNoteContent(Change change, ObjectId commit)
+      throws CodeReviewNoteCreationException, IOException  {
     if (!(commit instanceof RevCommit)) {
       commit = revWalk.parseCommit(commit);
     }
-
-    RevCommit c = (RevCommit) commit;
-    ObjectId noteContent = createNoteContent(change, c);
-    if (ours.contains(c)) {
-      // merge the existing and the new note as if they are both new
-      // means: base == null
-      // there is not really a common ancestry for these two note revisions
-      // use the same NoteMerger that is used from the NoteMapMerger
-      NoteMerger noteMerger = new ReviewNoteMerger();
-      Note newNote = new Note(c, noteContent);
-      noteContent = noteMerger.merge(null, newNote, ours.getNote(c),
-          reader, inserter).getData();
-    }
-    ours.set(c, noteContent);
+    return createNoteContent(change, (RevCommit) commit);
   }
 
   private ObjectId createNoteContent(Change change, RevCommit commit)
@@ -227,83 +209,4 @@
       throw new CodeReviewNoteCreationException(commit, e);
     }
   }
-
-  public void updateRef() throws IOException, InterruptedException,
-      CodeReviewNoteCreationException, MissingObjectException,
-      IncorrectObjectTypeException, CorruptObjectException {
-    if (baseCommit != null && oursCommit.getTree().equals(baseCommit.getTree())) {
-      // If the trees are identical, there is no change in the notes.
-      // Avoid saving this commit as it has no new information.
-      return;
-    }
-
-    int remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
-    RefUpdate refUpdate = createRefUpdate(oursCommit, baseCommit);
-
-    for (;;) {
-      Result result = refUpdate.update();
-
-      if (result == Result.LOCK_FAILURE) {
-        if (--remainingLockFailureCalls > 0) {
-          Thread.sleep(SLEEP_ON_LOCK_FAILURE_MS);
-        } else {
-          throw new CodeReviewNoteCreationException(
-              "Failed to lock the ref: " + REFS_NOTES_REVIEW);
-        }
-
-      } else if (result == Result.REJECTED) {
-        RevCommit theirsCommit =
-            revWalk.parseCommit(refUpdate.getOldObjectId());
-        NoteMap theirs =
-            NoteMap.read(revWalk.getObjectReader(), theirsCommit);
-        NoteMapMerger merger = new NoteMapMerger(db);
-        NoteMap merged = merger.merge(base, ours, theirs);
-        RevCommit mergeCommit =
-            createCommit(merged, gerritIdent, "Merged note commits\n",
-                theirsCommit, oursCommit);
-        refUpdate = createRefUpdate(mergeCommit, theirsCommit);
-        remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
-
-      } else if (result == Result.IO_FAILURE) {
-        throw new CodeReviewNoteCreationException(
-            "Couldn't create code review notes because of IO_FAILURE");
-      } else {
-        break;
-      }
-    }
-  }
-
-  public void release() {
-    reader.release();
-    inserter.release();
-    revWalk.release();
-  }
-
-  private RevCommit createCommit(NoteMap map, PersonIdent author,
-      String message, RevCommit... parents) throws IOException {
-    CommitBuilder b = new CommitBuilder();
-    b.setTreeId(map.writeTree(inserter));
-    b.setAuthor(author != null ? author : gerritIdent);
-    b.setCommitter(gerritIdent);
-    if (parents.length > 0) {
-      b.setParentIds(parents);
-    }
-    b.setMessage(message);
-    ObjectId commitId = inserter.insert(b);
-    inserter.flush();
-    return revWalk.parseCommit(commitId);
-  }
-
-
-  private RefUpdate createRefUpdate(ObjectId newObjectId,
-      ObjectId expectedOldObjectId) throws IOException {
-    RefUpdate refUpdate = db.updateRef(REFS_NOTES_REVIEW);
-    refUpdate.setNewObjectId(newObjectId);
-    if (expectedOldObjectId == null) {
-      refUpdate.setExpectedOldObjectId(ObjectId.zeroId());
-    } else {
-      refUpdate.setExpectedOldObjectId(expectedOldObjectId);
-    }
-    return refUpdate;
-  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/NotesBranchUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/NotesBranchUtil.java
new file mode 100644
index 0000000..17cfea8
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/NotesBranchUtil.java
@@ -0,0 +1,271 @@
+// Copyright (C) 2012 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.
+
+package com.google.gerrit.server.git;
+
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.MergeStrategy;
+import org.eclipse.jgit.notes.Note;
+import org.eclipse.jgit.notes.NoteMap;
+import org.eclipse.jgit.notes.NoteMapMerger;
+import org.eclipse.jgit.notes.NoteMerger;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+import java.io.IOException;
+
+/**
+ * A utility class for updating a notes branch with automatic merge of note
+ * trees.
+ */
+public class NotesBranchUtil {
+  public interface Factory {
+    NotesBranchUtil create(Repository db);
+  }
+
+  private static final int MAX_LOCK_FAILURE_CALLS = 10;
+  private static final int SLEEP_ON_LOCK_FAILURE_MS = 25;
+
+  private PersonIdent gerritIdent;
+  private final Repository db;
+
+  private RevCommit baseCommit;
+  private NoteMap base;
+
+  private RevCommit oursCommit;
+  private NoteMap ours;
+
+  private RevWalk revWalk;
+  private ObjectInserter inserter;
+  private ObjectReader reader;
+  private boolean overwrite;
+
+  private ReviewNoteMerger noteMerger;
+
+  @Inject
+  public NotesBranchUtil(@GerritPersonIdent final PersonIdent gerritIdent,
+      @Assisted Repository db) {
+    this.gerritIdent = gerritIdent;
+    this.db = db;
+  }
+
+  /**
+   * Create a new commit in the <code>notesBranch</code> by updating existing
+   * or creating new notes from the <code>notes</code> map.
+   *
+   * @param notes map of notes
+   * @param notesBranch notes branch to update
+   * @param commitAuthor author of the commit in the notes branch
+   * @param commitMessage for the commit in the notes branch
+   * @throws IOException
+   * @throws ConcurrentRefUpdateException
+   */
+  public final void commitAllNotes(NoteMap notes, String notesBranch,
+      PersonIdent commitAuthor, String commitMessage) throws IOException,
+      ConcurrentRefUpdateException {
+    this.overwrite = true;
+    commitNotes(notes, notesBranch, commitAuthor, commitMessage);
+  }
+
+  /**
+   * Create a new commit in the <code>notesBranch</code> by creating not yet
+   * existing notes from the <code>notes</code> map. The notes from the
+   * <code>notes</code> map which already exist in the note-tree of the
+   * tip of the <code>notesBranch</code> will not be updated.
+   *
+   * @param notes map of notes
+   * @param notesBranch notes branch to update
+   * @param commitAuthor author of the commit in the notes branch
+   * @param commitMessage for the commit in the notes branch
+   * @return map with those notes from the <code>notes</code> that were newly
+   *         created
+   * @throws IOException
+   * @throws ConcurrentRefUpdateException
+   */
+  public final NoteMap commitNewNotes(NoteMap notes, String notesBranch,
+      PersonIdent commitAuthor, String commitMessage) throws IOException,
+      ConcurrentRefUpdateException {
+    this.overwrite = false;
+    commitNotes(notes, notesBranch, commitAuthor, commitMessage);
+    NoteMap newlyCreated = NoteMap.newEmptyMap();
+    for (Note n : notes) {
+      if (base == null || !base.contains(n)) {
+        newlyCreated.set(n, n.getData());
+      }
+    }
+    return newlyCreated;
+  }
+
+  private void commitNotes(NoteMap notes, String notesBranch,
+      PersonIdent commitAuthor, String commitMessage) throws IOException,
+      ConcurrentRefUpdateException {
+    try {
+      revWalk = new RevWalk(db);
+      inserter = db.newObjectInserter();
+      reader = db.newObjectReader();
+      loadBase(notesBranch);
+      if (overwrite) {
+        addAllNotes(notes);
+      } else {
+        addNewNotes(notes);
+      }
+      if (base != null) {
+        oursCommit = createCommit(ours, commitAuthor, commitMessage, baseCommit);
+      } else {
+        oursCommit = createCommit(ours, commitAuthor, commitMessage);
+      }
+      updateRef(notesBranch);
+    } finally {
+      revWalk.release();
+      inserter.release();
+      reader.release();
+    }
+  }
+
+  private void addNewNotes(NoteMap notes) throws IOException {
+    for (Note n : notes) {
+      if (! ours.contains(n)) {
+        ours.set(n, n.getData());
+      }
+    }
+  }
+
+  private void addAllNotes(NoteMap notes) throws IOException {
+    for (Note n : notes) {
+      if (ours.contains(n)) {
+        // Merge the existing and the new note as if they are both new,
+        // means: base == null
+        // There is no really a common ancestry for these two note revisions
+        ObjectId noteContent = getNoteMerger().merge(null, n, ours.getNote(n),
+            reader, inserter).getData();
+        ours.set(n, noteContent);
+      } else {
+        ours.set(n, n.getData());
+      }
+    }
+  }
+
+  private NoteMerger getNoteMerger() {
+    if (noteMerger == null) {
+      noteMerger = new ReviewNoteMerger();
+    }
+    return noteMerger;
+  }
+
+  private void loadBase(String notesBranch) throws IOException {
+    Ref branch = db.getRef(notesBranch);
+    if (branch != null) {
+      baseCommit = revWalk.parseCommit(branch.getObjectId());
+      base = NoteMap.read(revWalk.getObjectReader(), baseCommit);
+    }
+    if (baseCommit != null) {
+      ours = NoteMap.read(revWalk.getObjectReader(), baseCommit);
+    } else {
+      ours = NoteMap.newEmptyMap();
+    }
+  }
+
+  private RevCommit createCommit(NoteMap map, PersonIdent author,
+      String message, RevCommit... parents) throws IOException {
+    CommitBuilder b = new CommitBuilder();
+    b.setTreeId(map.writeTree(inserter));
+    b.setAuthor(author != null ? author : gerritIdent);
+    b.setCommitter(gerritIdent);
+    if (parents.length > 0) {
+      b.setParentIds(parents);
+    }
+    b.setMessage(message);
+    ObjectId commitId = inserter.insert(b);
+    inserter.flush();
+    return revWalk.parseCommit(commitId);
+  }
+
+  private void updateRef(String notesBranch) throws IOException,
+      MissingObjectException, IncorrectObjectTypeException,
+      CorruptObjectException, ConcurrentRefUpdateException {
+    if (baseCommit != null && oursCommit.getTree().equals(baseCommit.getTree())) {
+      // If the trees are identical, there is no change in the notes.
+      // Avoid saving this commit as it has no new information.
+      return;
+    }
+
+    int remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
+    RefUpdate refUpdate = createRefUpdate(notesBranch, oursCommit, baseCommit);
+
+    for (;;) {
+      Result result = refUpdate.update();
+
+      if (result == Result.LOCK_FAILURE) {
+        if (--remainingLockFailureCalls > 0) {
+          try {
+            Thread.sleep(SLEEP_ON_LOCK_FAILURE_MS);
+          } catch (InterruptedException e) {
+            // ignore
+          }
+        } else {
+          throw new ConcurrentRefUpdateException("Failed to lock the ref: "
+              + notesBranch, db.getRef(notesBranch), result);
+        }
+
+      } else if (result == Result.REJECTED) {
+        RevCommit theirsCommit =
+            revWalk.parseCommit(refUpdate.getOldObjectId());
+        NoteMap theirs =
+            NoteMap.read(revWalk.getObjectReader(), theirsCommit);
+        NoteMapMerger merger =
+            new NoteMapMerger(db, getNoteMerger(), MergeStrategy.RESOLVE);
+        NoteMap merged = merger.merge(base, ours, theirs);
+        RevCommit mergeCommit =
+            createCommit(merged, gerritIdent, "Merged note commits\n",
+                theirsCommit, oursCommit);
+        refUpdate = createRefUpdate(notesBranch, mergeCommit, theirsCommit);
+        remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
+
+      } else if (result == Result.IO_FAILURE) {
+        throw new IOException("Couldn't update " + notesBranch + ". "
+            + result.name());
+      } else {
+        break;
+      }
+    }
+  }
+
+  private RefUpdate createRefUpdate(String notesBranch, ObjectId newObjectId,
+      ObjectId expectedOldObjectId) throws IOException {
+    RefUpdate refUpdate = db.updateRef(notesBranch);
+    refUpdate.setNewObjectId(newObjectId);
+    if (expectedOldObjectId == null) {
+      refUpdate.setExpectedOldObjectId(ObjectId.zeroId());
+    } else {
+      refUpdate.setExpectedOldObjectId(expectedOldObjectId);
+    }
+    return refUpdate;
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
index dca47e0..b87af89 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ListPlugins.java
@@ -33,13 +33,16 @@
 import java.util.List;
 import java.util.Map;
 
-/** List projects visible to the calling user. */
+/** List the installed plugins. */
 public class ListPlugins {
   private final PluginLoader pluginLoader;
 
   @Option(name = "--format", metaVar = "FMT", usage = "Output display format")
   private OutputFormat format = OutputFormat.TEXT;
 
+  @Option(name = "--all", aliases = {"-a"}, usage = "List all plugins, including disabled plugins")
+  private boolean all;
+
   @Inject
   protected ListPlugins(PluginLoader pluginLoader) {
     this.pluginLoader = pluginLoader;
@@ -67,7 +70,7 @@
 
     Map<String, PluginInfo> output = Maps.newTreeMap();
 
-    List<Plugin> plugins = Lists.newArrayList(pluginLoader.getPlugins());
+    List<Plugin> plugins = Lists.newArrayList(pluginLoader.getPlugins(all));
     Collections.sort(plugins, new Comparator<Plugin>() {
       @Override
       public int compare(Plugin a, Plugin b) {
@@ -76,20 +79,22 @@
     });
 
     if (!format.isJson()) {
-      stdout.format("%-30s %-10s\n", "Name", "Version");
+      stdout.format("%-30s %-10s %-8s\n", "Name", "Version", "Status");
       stdout
-          .print("----------------------------------------------------------------------\n");
+          .print("-------------------------------------------------------------------------------\n");
     }
 
     for (Plugin p : plugins) {
       PluginInfo info = new PluginInfo();
       info.version = p.getVersion();
+      info.disabled = p.isDisabled() ? true : null;
 
       if (format.isJson()) {
         output.put(p.getName(), info);
       } else {
-        stdout.format("%-30s %-10s\n", p.getName(),
-            Strings.nullToEmpty(info.version));
+        stdout.format("%-30s %-10s %-8s\n", p.getName(),
+            Strings.nullToEmpty(info.version),
+            p.isDisabled() ? "DISABLED" : "");
       }
     }
 
@@ -103,5 +108,9 @@
 
   private static class PluginInfo {
     String version;
+    // disabled is only read via reflection when building the json output.  We
+    // do not want to show a compiler error that it isn't used.
+    @SuppressWarnings("unused")
+    Boolean disabled;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
index a3c363b..91ffbba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/Plugin.java
@@ -89,6 +89,7 @@
   private final File dataDir;
   private final ApiType apiType;
   private final ClassLoader classLoader;
+  private final boolean disabled;
   private Class<? extends Module> sysModule;
   private Class<? extends Module> sshModule;
   private Class<? extends Module> httpModule;
@@ -119,6 +120,7 @@
     this.dataDir = dataDir;
     this.apiType = apiType;
     this.classLoader = classLoader;
+    this.disabled = srcJar.getName().endsWith(".disabled");
     this.sysModule = sysModule;
     this.sshModule = sshModule;
     this.httpModule = httpModule;
@@ -165,6 +167,10 @@
     return snapshot.lastModified() != jar.lastModified();
   }
 
+  public boolean isDisabled() {
+    return disabled;
+  }
+
   public void start(PluginGuiceEnvironment env) throws Exception {
     Injector root = newRootInjector(env);
     manager = new LifecycleManager();
@@ -294,13 +300,15 @@
   }
 
   public void add(RegistrationHandle handle) {
-    if (handle instanceof ReloadableRegistrationHandle) {
-      if (reloadableHandles == null) {
-        reloadableHandles = Lists.newArrayList();
+    if (manager != null) {
+      if (handle instanceof ReloadableRegistrationHandle) {
+        if (reloadableHandles == null) {
+          reloadableHandles = Lists.newArrayList();
+        }
+        reloadableHandles.add((ReloadableRegistrationHandle<?>) handle);
       }
-      reloadableHandles.add((ReloadableRegistrationHandle<?>) handle);
+      manager.add(handle);
     }
-    manager.add(handle);
   }
 
   List<ReloadableRegistrationHandle<?>> getReloadableHandles() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
index 67d715f..76cee02 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -45,6 +45,7 @@
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
@@ -67,6 +68,7 @@
   private final PluginGuiceEnvironment env;
   private final ServerInformationImpl srvInfoImpl;
   private final ConcurrentMap<String, Plugin> running;
+  private final ConcurrentMap<String, Plugin> disabled;
   private final Map<String, FileSnapshot> broken;
   private final ReferenceQueue<ClassLoader> cleanupQueue;
   private final ConcurrentMap<CleanupHandle, Boolean> cleanupHandles;
@@ -85,6 +87,7 @@
     env = pe;
     srvInfoImpl = sii;
     running = Maps.newConcurrentMap();
+    disabled = Maps.newConcurrentMap();
     broken = Maps.newHashMap();
     cleanupQueue = new ReferenceQueue<ClassLoader>();
     cleanupHandles = Maps.newConcurrentMap();
@@ -100,8 +103,14 @@
     }
   }
 
-  public Iterable<Plugin> getPlugins() {
-    return running.values();
+  public Iterable<Plugin> getPlugins(boolean all) {
+    if (!all) {
+      return running.values();
+    } else {
+      ArrayList<Plugin> plugins = new ArrayList<Plugin>(running.values());
+      plugins.addAll(disabled.values());
+      return plugins;
+    }
   }
 
   public void installPluginFromStream(String name, InputStream in)
@@ -178,6 +187,15 @@
 
         active.stop();
         running.remove(name);
+        try {
+          FileSnapshot snapshot = FileSnapshot.save(off);
+          Plugin offPlugin = loadPlugin(name, off, snapshot);
+          disabled.put(name, offPlugin);
+        } catch (Throwable e) {
+          // This shouldn't happen, as the plugin was loaded earlier.
+          log.warn(String.format("Cannot load disabled plugin %s", name),
+              e.getCause());
+        }
       }
       cleanInBackground();
     }
@@ -205,6 +223,7 @@
         p.stop();
       }
       running.clear();
+      disabled.clear();
       broken.clear();
       if (cleanupHandles.size() > running.size()) {
         System.gc();
@@ -250,6 +269,7 @@
   public synchronized void rescan() {
     List<File> jars = scanJarsInPluginsDirectory();
     stopRemovedPlugins(jars);
+    dropRemovedDisabledPlugins(jars);
 
     for (File jar : jars) {
       String name = nameOf(jar);
@@ -292,14 +312,20 @@
         oldPlugin.stop();
         running.remove(name);
       }
-      newPlugin.start(env);
+      if (!newPlugin.isDisabled()) {
+        newPlugin.start(env);
+      }
       if (reload) {
         env.onReloadPlugin(oldPlugin, newPlugin);
         oldPlugin.stop();
-      } else {
+      } else if (!newPlugin.isDisabled()) {
         env.onStartPlugin(newPlugin);
       }
-      running.put(name, newPlugin);
+      if (!newPlugin.isDisabled()) {
+        running.put(name, newPlugin);
+      } else {
+        disabled.put(name, newPlugin);
+      }
       broken.remove(name);
     } catch (Throwable err) {
       broken.put(name, snapshot);
@@ -310,7 +336,9 @@
   private void stopRemovedPlugins(List<File> jars) {
     Set<String> unload = Sets.newHashSet(running.keySet());
     for (File jar : jars) {
-      unload.remove(nameOf(jar));
+      if (!jar.getName().endsWith(".disabled")) {
+        unload.remove(nameOf(jar));
+      }
     }
     for (String name : unload){
       log.info(String.format("Unloading plugin %s", name));
@@ -318,6 +346,18 @@
     }
   }
 
+  private void dropRemovedDisabledPlugins(List<File> jars) {
+    Set<String> unload = Sets.newHashSet(disabled.keySet());
+    for (File jar : jars) {
+      if (jar.getName().endsWith(".disabled")) {
+        unload.remove(nameOf(jar));
+      }
+    }
+    for (String name : unload) {
+      disabled.remove(name);
+    }
+  }
+
   synchronized int processPendingCleanups() {
     CleanupHandle h;
     while ((h = (CleanupHandle) cleanupQueue.poll()) != null) {
@@ -336,6 +376,9 @@
 
   private static String nameOf(File jar) {
     String name = jar.getName();
+    if (name.endsWith(".disabled")) {
+      name = name.substring(0, name.lastIndexOf('.'));
+    }
     int ext = name.lastIndexOf('.');
     return 0 < ext ? name.substring(0, ext) : name;
   }
@@ -430,7 +473,9 @@
     File[] matches = pluginsDir.listFiles(new FileFilter() {
       @Override
       public boolean accept(File pathname) {
-        return pathname.getName().endsWith(".jar") && pathname.isFile();
+        String n = pathname.getName();
+        return (n.endsWith(".jar") || n.endsWith(".jar.disabled"))
+            && pathname.isFile();
       }
     });
     if (matches == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
index 7387fd1..41f2aa6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
@@ -211,7 +211,8 @@
 
   /** Can this user restore this change? */
   public boolean canRestore() {
-    return canAbandon(); // Anyone who can abandon the change can restore it back
+    return canAbandon() // Anyone who can abandon the change can restore it back
+        && getRefControl().canUpload(); // as long as you can upload too
   }
 
   /** All value ranges of any allowed label permission. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
index 8b4e000..e5a11ca 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
@@ -40,8 +40,10 @@
 import java.io.PrintWriter;
 import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeMap;
 import java.util.TreeSet;
@@ -57,6 +59,12 @@
         return !PERMISSIONS.matches(git);
       }
     },
+    PARENT_CANDIDATES {
+      @Override
+      boolean matches(Repository git) {
+        return true;
+      }
+    },
     PERMISSIONS {
       @Override
       boolean matches(Repository git) throws IOException {
@@ -155,6 +163,7 @@
     int found = 0;
     Map<String, ProjectInfo> output = Maps.newTreeMap();
     Map<String, String> hiddenNames = Maps.newHashMap();
+    Set<String> rejected = new HashSet<String>();
 
     final TreeMap<Project.NameKey, ProjectNode> treeMap =
         new TreeMap<Project.NameKey, ProjectNode>();
@@ -166,84 +175,102 @@
           //
           continue;
         }
-
-        final ProjectControl pctl = e.controlFor(currentUser);
-        final boolean isVisible = pctl.isVisible() || (all && pctl.isOwner());
-        if (showTree && !format.isJson()) {
-          treeMap.put(projectName,
-              projectNodeFactory.create(pctl.getProject(), isVisible));
-          continue;
-        }
-
-        if (!isVisible && !(showTree && pctl.isOwner())) {
-          // Require the project itself to be visible to the user.
-          //
-          continue;
-        }
-
         ProjectInfo info = new ProjectInfo();
-        info.name = projectName.get();
-        if (showTree && format.isJson()) {
-          ProjectState parent = e.getParentState();
-          if (parent != null) {
-            ProjectControl parentCtrl = parent.controlFor(currentUser);
+        if (type == FilterType.PARENT_CANDIDATES) {
+          ProjectState parentState = e.getParentState();
+          if (parentState != null
+              && !output.keySet().contains(parentState.getProject().getName())
+              && !rejected.contains(parentState.getProject().getName())) {
+            ProjectControl parentCtrl = parentState.controlFor(currentUser);
             if (parentCtrl.isVisible() || parentCtrl.isOwner()) {
-              info.parent = parent.getProject().getName();
+              info.name = parentState.getProject().getName();
+              info.description = parentState.getProject().getDescription();
             } else {
-              info.parent = hiddenNames.get(parent.getProject().getName());
-              if (info.parent == null) {
-                info.parent = "?-" + (hiddenNames.size() + 1);
-                hiddenNames.put(parent.getProject().getName(), info.parent);
-              }
+              rejected.add(parentState.getProject().getName());
+              continue;
             }
+          } else {
+            continue;
           }
-        }
-        if (showDescription && !e.getProject().getDescription().isEmpty()) {
-          info.description = e.getProject().getDescription();
-        }
 
-        try {
-          if (showBranch != null) {
-            Repository git = repoManager.openRepository(projectName);
-            try {
-              if (!type.matches(git)) {
-                continue;
-              }
+        } else {
+          final ProjectControl pctl = e.controlFor(currentUser);
+          final boolean isVisible = pctl.isVisible() || (all && pctl.isOwner());
+          if (showTree && !format.isJson()) {
+            treeMap.put(projectName,
+                projectNodeFactory.create(pctl.getProject(), isVisible));
+            continue;
+          }
 
-              List<Ref> refs = getBranchRefs(projectName, pctl);
-              if (!hasValidRef(refs)) {
-               continue;
-              }
+          if (!isVisible && !(showTree && pctl.isOwner())) {
+            // Require the project itself to be visible to the user.
+            //
+            continue;
+          }
 
-              for (int i = 0; i < showBranch.size(); i++) {
-                Ref ref = refs.get(i);
-                if (ref != null && ref.getObjectId() != null) {
-                  if (info.branches == null) {
-                    info.branches = Maps.newLinkedHashMap();
-                  }
-                  info.branches.put(showBranch.get(i), ref.getObjectId().name());
+          info.name = projectName.get();
+          if (showTree && format.isJson()) {
+            ProjectState parent = e.getParentState();
+            if (parent != null) {
+              ProjectControl parentCtrl = parent.controlFor(currentUser);
+              if (parentCtrl.isVisible() || parentCtrl.isOwner()) {
+                info.parent = parent.getProject().getName();
+              } else {
+                info.parent = hiddenNames.get(parent.getProject().getName());
+                if (info.parent == null) {
+                  info.parent = "?-" + (hiddenNames.size() + 1);
+                  hiddenNames.put(parent.getProject().getName(), info.parent);
                 }
               }
-            } finally {
-              git.close();
-            }
-          } else if (!showTree && type != FilterType.ALL) {
-            Repository git = repoManager.openRepository(projectName);
-            try {
-              if (!type.matches(git)) {
-                continue;
-              }
-            } finally {
-              git.close();
             }
           }
+          if (showDescription && !e.getProject().getDescription().isEmpty()) {
+            info.description = e.getProject().getDescription();
+          }
 
-        } catch (RepositoryNotFoundException err) {
-          // If the Git repository is gone, the project doesn't actually exist anymore.
-          continue;
-        } catch (IOException err) {
-          log.warn("Unexpected error reading " + projectName, err);
-          continue;
+          try {
+            if (showBranch != null) {
+              Repository git = repoManager.openRepository(projectName);
+              try {
+                if (!type.matches(git)) {
+                  continue;
+                }
+
+                List<Ref> refs = getBranchRefs(projectName, pctl);
+                if (!hasValidRef(refs)) {
+                  continue;
+                }
+
+                for (int i = 0; i < showBranch.size(); i++) {
+                  Ref ref = refs.get(i);
+                  if (ref != null && ref.getObjectId() != null) {
+                    if (info.branches == null) {
+                      info.branches = Maps.newLinkedHashMap();
+                    }
+                    info.branches.put(showBranch.get(i), ref.getObjectId().name());
+                  }
+                }
+              } finally {
+                git.close();
+              }
+            } else if (!showTree && type != FilterType.ALL) {
+              Repository git = repoManager.openRepository(projectName);
+              try {
+                if (!type.matches(git)) {
+                  continue;
+                }
+              } finally {
+                git.close();
+              }
+            }
+
+          } catch (RepositoryNotFoundException err) {
+            // If the Git repository is gone, the project doesn't actually exist anymore.
+            continue;
+          } catch (IOException err) {
+            log.warn("Unexpected error reading " + projectName, err);
+            continue;
+          }
         }
 
         if (limit > 0 && ++found > limit) {
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm
index a67c38c..bb3c127 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/ChangeSubject.vm
@@ -32,6 +32,6 @@
 ## subject line for ALL emails related to changes.
 ##
 #macro(elipses $length $str)
-#if($str.length() > $length)${str.substring(0,$length)}...#else$str#end
+#if(($str.length()+3) > $length)${str.substring(0,$length)}...#else$str#end
 #end
 Change in $projectName.replaceAll('/.*/', '...')[$branch.shortName]: #elipses(60, $change.subject)
diff --git a/gerrit-sshd/.settings/org.eclipse.core.resources.prefs b/gerrit-sshd/.settings/org.eclipse.core.resources.prefs
index 0871ea8..839d647 100644
--- a/gerrit-sshd/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-sshd/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Tue May 15 09:21:12 PDT 2012
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
index 4350d1e..939d68a 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/BanCommitCommand.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
 import org.eclipse.jgit.lib.ObjectId;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
@@ -80,6 +81,8 @@
       throw die(e);
     } catch (InterruptedException e) {
       throw die(e);
+    } catch (ConcurrentRefUpdateException e) {
+      throw die(e);
     }
   }
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
index ad9733d..b9abc92 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.sshd.commands;
 
+import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.server.account.PerformRenameGroup;
@@ -39,6 +40,8 @@
       performRenameGroupFactory.create().renameGroup(groupName, newGroupName);
     } catch (OrmException e) {
       throw die(e);
+    } catch (InvalidNameException e) {
+      throw die(e);
     } catch (NameAlreadyUsedException e) {
       throw die(e);
     } catch (NoSuchGroupException e) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
index 8ce1e82..5ebb6c7 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
@@ -68,7 +68,8 @@
 
   private final Set<PatchSet.Id> patchSetIds = new HashSet<PatchSet.Id>();
 
-  @Argument(index = 0, required = true, multiValued = true, metaVar = "{COMMIT | CHANGE,PATCHSET}", usage = "patch to review")
+  @Argument(index = 0, required = true, multiValued = true, metaVar = "{COMMIT | CHANGE,PATCHSET}",
+      usage = "list of commits or patch sets to review")
   void addPatchSetId(final String token) {
     try {
       patchSetIds.addAll(parsePatchSetId(token));
@@ -79,29 +80,29 @@
     }
   }
 
-  @Option(name = "--project", aliases = "-p", usage = "project containing the patch set")
+  @Option(name = "--project", aliases = "-p", usage = "project containing the specified patch set(s)")
   private ProjectControl projectControl;
 
-  @Option(name = "--message", aliases = "-m", usage = "cover message to publish on change", metaVar = "MESSAGE")
+  @Option(name = "--message", aliases = "-m", usage = "cover message to publish on change(s)", metaVar = "MESSAGE")
   private String changeComment;
 
-  @Option(name = "--abandon", usage = "abandon the patch set")
+  @Option(name = "--abandon", usage = "abandon the specified change(s)")
   private boolean abandonChange;
 
-  @Option(name = "--restore", usage = "restore an abandoned the patch set")
+  @Option(name = "--restore", usage = "restore the specified abandoned change(s)")
   private boolean restoreChange;
 
-  @Option(name = "--submit", aliases = "-s", usage = "submit the patch set")
+  @Option(name = "--submit", aliases = "-s", usage = "submit the specified patch set(s)")
   private boolean submitChange;
 
   @Option(name = "--force-message", usage = "publish the message, "
-      + "even if the label score cannot be applied due to change being closed")
+      + "even if the label score cannot be applied due to the change being closed")
   private boolean forceMessage = false;
 
-  @Option(name = "--publish", usage = "publish a draft patch set")
+  @Option(name = "--publish", usage = "publish the specified draft patch set(s)")
   private boolean publishPatchSet;
 
-  @Option(name = "--delete", usage = "delete a draft patch set")
+  @Option(name = "--delete", usage = "delete the specified draft patch set(s)")
   private boolean deleteDraftPatchSet;
 
   @Inject
@@ -266,7 +267,7 @@
           errMsg += "rule error";
           break;
         case NOT_A_DRAFT:
-          errMsg += "change is not a draft";
+          errMsg += "change/patch set is not a draft";
           break;
         case GIT_ERROR:
           errMsg += "error writing change to git repository";
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/StreamEvents.java
old mode 100755
new mode 100644
diff --git a/gerrit-util-cli/.settings/org.eclipse.core.resources.prefs b/gerrit-util-cli/.settings/org.eclipse.core.resources.prefs
index c780f44..e9441bb 100644
--- a/gerrit-util-cli/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-util-cli/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:36 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-util-ssl/.settings/org.eclipse.core.resources.prefs b/gerrit-util-ssl/.settings/org.eclipse.core.resources.prefs
index 589908f..e9441bb 100644
--- a/gerrit-util-ssl/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-util-ssl/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:35 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding/<project>=UTF-8
diff --git a/gerrit-war/.settings/org.eclipse.core.resources.prefs b/gerrit-war/.settings/org.eclipse.core.resources.prefs
index d404b00..abdea9ac 100644
--- a/gerrit-war/.settings/org.eclipse.core.resources.prefs
+++ b/gerrit-war/.settings/org.eclipse.core.resources.prefs
@@ -1,4 +1,3 @@
-#Thu Jul 28 11:02:37 PDT 2011
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
 encoding//src/main/resources=UTF-8
diff --git a/pom.xml b/pom.xml
index e5f6fc5..d7b5988 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,12 +88,26 @@
     <module>gerrit-war</module>
 
     <module>gerrit-extension-api</module>
-    <module>gerrit-plugin-api</module>
-    <module>gerrit-plugin-archetype</module>
 
     <module>gerrit-gwtui</module>
   </modules>
 
+  <profiles>
+    <profile>
+      <id>all</id>
+      <modules>
+        <module>gerrit-plugin-api</module>
+        <module>gerrit-plugin-archetype</module>
+      </modules>
+    </profile>
+    <profile>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <id>no-plugins</id>
+    </profile>
+  </profiles>
+
   <licenses>
     <license>
       <name>Apache License, 2.0</name>
@@ -464,7 +478,7 @@
       <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
-        <version>12.0</version>
+        <version>12.0.1</version>
       </dependency>
 
       <dependency>
diff --git a/tools/release.sh b/tools/release.sh
index 4a872a1..79e6605 100755
--- a/tools/release.sh
+++ b/tools/release.sh
@@ -25,7 +25,7 @@
 fi
 
 ./tools/version.sh --release &&
-mvn clean package $include_docs
+mvn clean package $include_docs -P all
 rc=$?
 ./tools/version.sh --reset