Merge "Merge branch 'stable-2.11'"
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index b082339..ff252f7 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -907,7 +907,7 @@
 * xref:category_forge_author[`Forge Author Identity`] to 'refs/heads/*'
 * link:config-labels.html#label_Code-Review[`Label: Code-Review`] with range '-2' to '+2' for 'refs/heads/*'
 * link:config-labels.html#label_Verified[`Label: Verified`] with range '-1' to '+1' for 'refs/heads/*'
-* xref:category_submit[`Submit`]
+* xref:category_submit[`Submit`] on 'refs/heads/*'
 
 If the project is small or the developers are seasoned it might make
 sense to give them the freedom to push commits directly to a branch.
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 45a2664..dab0f5e 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -502,15 +502,17 @@
 * y, year, years (`1 year` is treated as `365 days`)
 
 +
+--
 If a unit suffix is not specified, `seconds` is assumed.  If 0 is
 supplied, the maximum age is infinite and items are never purged
 except when the cache is full.
-+
+
 Default is `0`, meaning store forever with no expire, except:
-+
+
 * `"adv_bases"`: default is `10 minutes`
 * `"ldap_groups"`: default is `1 hour`
 * `"web_sessions"`: default is `12 hours`
+--
 
 [[cache.name.memoryLimit]]cache.<name>.memoryLimit::
 +
@@ -735,9 +737,11 @@
 * h, hr, hour, hours
 
 +
+--
 If a unit suffix is not specified, `milliseconds` is assumed.
-+
+
 Default is 5 seconds.
+--
 
 [[cache.diff_intraline.timeout]]cache.diff_intraline.timeout::
 +
@@ -758,9 +762,11 @@
 * h, hr, hour, hours
 
 +
+--
 If a unit suffix is not specified, `milliseconds` is assumed.
-+
+
 Default is 5 seconds.
+--
 
 [[cache.diff_intraline.enabled]]cache.diff_intraline.enabled::
 +
@@ -1345,12 +1351,14 @@
 * h, hr, hour, hours
 
 +
+--
 If a unit suffix is not specified, `milliseconds` is assumed.
-+
+
 Default is `30 seconds`.
-+
+
 This setting only applies if
 <<database.connectionPool,database.connectionPool>> is true.
+--
 
 [[database.dataSourceInterceptorClass]]database.dataSourceInterceptorClass::
 
@@ -1947,10 +1955,12 @@
 'https://' is the proper URL back to the server.
 
 +
+--
 If multiple values are supplied, the daemon will listen on all
 of them.
-+
+
 By default, http://*:8080.
+--
 
 [[httpd.reuseAddress]]httpd.reuseAddress::
 +
@@ -2078,11 +2088,13 @@
 * y, year, years (`1 year` is treated as `365 days`)
 
 +
+--
 If a unit suffix is not specified, `minutes` is assumed.  If 0
 is supplied, the maximum age is infinite and connections will not
 abort until the client disconnects.
-+
+
 By default, 5 minutes.
+--
 
 [[httpd.filterClass]]httpd.filterClass::
 +
@@ -3082,15 +3094,17 @@
 * 'hostname':'port' (for example `review.example.com:29418`)
 * 'IPv4':'port' (for example `10.0.0.1:29418`)
 * ['IPv6']:'port' (for example `[ff02::1]:29418`)
-* *:'port' (for example `*:29418`)
+* +*:'port'+ (for example `+*:29418+`)
 
 +
+--
 If multiple values are supplied, the daemon will listen on all
 of them.
-+
+
 To disable the internal SSHD, set listenAddress to `off`.
-+
+
 By default, *:29418.
+--
 
 [[sshd.advertisedAddress]]sshd.advertisedAddress::
 +
@@ -3099,16 +3113,18 @@
 redirector is being used, making Gerrit appear to answer on port
 22. The following forms may be used to specify an address.  In any
 form, `:'port'` may be omitted to use the default SSH port of 22.
-+
+
 * 'hostname':'port' (for example `review.example.com:22`)
 * 'IPv4':'port' (for example `10.0.0.1:29418`)
 * ['IPv6']:'port' (for example `[ff02::1]:29418`)
 
 +
+--
 If multiple values are supplied, the daemon will advertise all
 of them.
-+
+
 By default, sshd.listenAddress.
+--
 
 [[sshd.tcpKeepAlive]]sshd.tcpKeepAlive::
 +
diff --git a/Documentation/config-plugins.txt b/Documentation/config-plugins.txt
index 6ba85e0..3887ff3 100644
--- a/Documentation/config-plugins.txt
+++ b/Documentation/config-plugins.txt
@@ -39,6 +39,7 @@
 The core plugins are developed and maintained by the Gerrit maintainers
 and the Gerrit community.
 
+[[commit-message-length-validator]]
 === commit-message-length-validator
 
 This plugin checks the length of a commit’s commit message subject and
@@ -52,6 +53,7 @@
 link:https://gerrit.googlesource.com/plugins/commit-message-length-validator/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[cookbook-plugin]]
 === cookbook-plugin
 
 Sample plugin to demonstrate features of Gerrit's plugin API.
@@ -61,6 +63,7 @@
 link:https://gerrit.googlesource.com/plugins/cookbook-plugin/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[download-commands]]
 === download-commands
 
 This plugin defines commands for downloading changes in different
@@ -73,6 +76,7 @@
 link:https://gerrit.googlesource.com/plugins/download-commands/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[replication]]
 === replication
 
 This plugin can automatically push any changes Gerrit Code Review makes
@@ -87,6 +91,7 @@
 link:https://gerrit.googlesource.com/plugins/replication/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[reviewnotes]]
 === reviewnotes
 
 Stores review information for Gerrit changes in the `refs/notes/review`
@@ -97,6 +102,7 @@
 link:https://gerrit.googlesource.com/plugins/reviewnotes/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[singleusergroup]]
 === singleusergroup
 
 This plugin provides a group per user. This is useful to assign access
@@ -121,6 +127,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/?filter=plugins%252F[
 gerrit-review].
 
+[[admin-console]]
 === admin-console
 
 Plugin to provide administrator-only functionality, intended to
@@ -133,6 +140,7 @@
 link:https://gerrit.googlesource.com/plugins/admin-console/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[avatars-external]]
 === avatars/external
 
 This plugin allows to use an external url to load the avatar images
@@ -145,6 +153,7 @@
 link:https://gerrit.googlesource.com/plugins/avatars/external/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[avatars-gravatar]]
 === avatars/gravatar
 
 Plugin to display user icons from Gravatar.
@@ -152,6 +161,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/avatars/gravatar[
 Project]
 
+[[branch-network]]
 === branch-network
 
 This plugin allows the rendering of Git repository branch network in a
@@ -166,6 +176,7 @@
 link:https://gerrit.googlesource.com/plugins/branch-network/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[changemessage]]
 === changemessage
 
 This plugin allows to display a static info message on the change screen.
@@ -177,6 +188,7 @@
 link:https://gerrit.googlesource.com/plugins/changemessage/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[codenvy]]
 === codenvy
 
 Plugin to allow to edit code on-line on either an existing branch or an
@@ -186,6 +198,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/codenvy[
 Project]
 
+[[delete-project]]
 === delete-project
 
 Provides the ability to delete a project.
@@ -195,6 +208,7 @@
 link:https://gerrit.googlesource.com/plugins/delete-project/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[egit]]
 === egit
 
 This plugin provides extensions for easier usage with EGit.
@@ -208,6 +222,7 @@
 link:https://gerrit.googlesource.com/plugins/egit/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[force-draft]]
 === force-draft
 
 Provides an ssh command to force a change or patch set to draft status.
@@ -217,6 +232,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/force-draft[
 Project]
 
+[[gitblit]]
 === gitblit
 
 GitBlit code-viewer plugin with SSO and Security Access Control.
@@ -224,6 +240,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/gitblit[
 Project]
 
+[[github]]
 === github
 
 Plugin to integrate with GitHub: replication, pull-request to Change-Sets
@@ -231,6 +248,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/github[
 Project]
 
+[[gitiles]]
 === gitiles
 
 Plugin running Gitiles alongside a Gerrit server.
@@ -238,6 +256,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/gitiles[
 Project]
 
+[[imagare]]
 === imagare
 
 The imagare plugin allows Gerrit users to upload and share images.
@@ -249,6 +268,33 @@
 link:https://gerrit.googlesource.com/plugins/imagare/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[importer]]
+=== importer
+
+The importer plugin allows to import projects from one Gerrit server
+into another Gerrit server.
+
+Projects can be imported while both source and target Gerrit server
+are online. There is no downtime required.
+
+The git repository and all changes of the project, including approvals
+and review comments, are imported. Historic timestamps are preserved.
+
+Project imports can be resumed. This means a project team can continue
+to work in the source system while the import to the target system is
+done. By resuming the import the project in the target system can be
+updated with the missing delta.
+
+The importer plugin can also be used to copy a project within one Gerrit
+server, and in combination with the link:#delete-project[delete-project]
+plugin it can be used to rename a project.
+
+link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/importer[
+Project] |
+link:https://gerrit.googlesource.com/plugins/importer/+doc/master/src/main/resources/Documentation/about.md[
+Documentation]
+
+[[its-plugins]]
 === Issue Tracker System Plugins
 
 Plugins to integrate with issue tracker systems (ITS), that (based
@@ -266,6 +312,7 @@
 link:https://gerrit.googlesource.com/plugins/its-base/+doc/master/src/main/resources/Documentation/config.md[
 its-base Configuration]
 
+[[its-bugzilla]]
 ==== its-bugzilla
 
 Plugin to integrate with Bugzilla.
@@ -275,6 +322,7 @@
 link:https://gerrit.googlesource.com/plugins/its-bugzilla/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[its-jira]]
 ==== its-jira
 
 Plugin to integrate with Jira.
@@ -284,6 +332,7 @@
 link:https://gerrit.googlesource.com/plugins/its-jira/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[its-rtc]]
 ==== its-rtc
 
 Plugin to integrate with IBM Rational Team Concert (RTC).
@@ -293,6 +342,7 @@
 link:https://gerrit.googlesource.com/plugins/its-rtc/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[javamelody]]
 === javamelody
 
 This plugin allows to monitor the Gerrit server.
@@ -307,6 +357,7 @@
 https://gerrit.googlesource.com/plugins/javamelody/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[menuextender]]
 === menuextender
 
 The menuextender plugin allows Gerrit administrators to configure
@@ -319,6 +370,7 @@
 link:https://gerrit.googlesource.com/plugins/menuextender/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[motd]]
 === motd
 
 This plugin can output messages to clients when pulling/fetching/cloning
@@ -334,8 +386,8 @@
 link:https://gerrit.googlesource.com/plugins/motd/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[oauth-authentication-provider]]
 === OAuth authentication provider
-
 This plugin enables Gerrit to use OAuth2 protocol for authentication.
 Two different OAuth providers are supported:
 
@@ -345,6 +397,7 @@
 https://github.com/davido/gerrit-oauth-provider[Project] |
 https://github.com/davido/gerrit-oauth-provider/wiki/Getting-Started[Configuration]
 
+[[project-download-commands]]
 === project-download-commands
 
 This plugin adds support for project specific download commands.
@@ -360,6 +413,7 @@
 link:https://gerrit.googlesource.com/plugins/project-download-commands/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[quota]]
 === quota
 
 This plugin allows to enforce quotas in Gerrit.
@@ -375,6 +429,7 @@
 link:https://gerrit.googlesource.com/plugins/quota/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[reviewers]]
 === reviewers
 
 A plugin that allows adding default reviewers to a change.
@@ -386,6 +441,7 @@
 link:https://gerrit.googlesource.com/plugins/reviewers/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[reviewers-by-blame]]
 === reviewers-by-blame
 
 A plugin that allows automatically adding reviewers to a change from
@@ -401,6 +457,7 @@
 link:https://gerrit.googlesource.com/plugins/reviewers-by-blame/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[groovy-provider]]
 === scripting/groovy-provider
 
 This plugin provides a Groovy runtime environment for Gerrit plugins in Groovy.
@@ -410,6 +467,7 @@
 link:https://gerrit.googlesource.com/plugins/scripting/groovy-provider/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[scala-provider]]
 === scripting/scala-provider
 
 This plugin provides a Scala runtime environment for Gerrit plugins in Scala.
@@ -419,6 +477,7 @@
 link:https://gerrit.googlesource.com/plugins/scripting/scala-provider/+doc/master/src/main/resources/Documentation/about.md[
 Documentation]
 
+[[server-config]]
 === server-config
 
 This plugin enables access (download and upload) to the server config
@@ -430,6 +489,7 @@
 link:https://gerrit-review.googlesource.com/#/admin/projects/plugins/scripting/server-config[
 Project]
 
+[[serviceuser]]
 === serviceuser
 
 This plugin allows to create service users in Gerrit.
@@ -446,6 +506,7 @@
 link:https://gerrit.googlesource.com/plugins/serviceuser/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[uploadvalidator]]
 === uploadvalidator
 
 This plugin allows to configure upload validations per project.
@@ -461,6 +522,7 @@
 link:https://gerrit.googlesource.com/plugins/uploadvalidator/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[websession-flatfile]]
 === websession-flatfile
 
 This plugin replaces the built-in Gerrit H2 based websession cache with
@@ -475,6 +537,7 @@
 link:https://gerrit.googlesource.com/plugins/websession-flatfile/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[wip]]
 === wip
 
 This plugin adds a new button that allows a change owner to set a
@@ -492,6 +555,7 @@
 link:https://gerrit.googlesource.com/plugins/wip/+doc/master/src/main/resources/Documentation/config.md[
 Configuration]
 
+[[x-docs]]
 === x-docs
 
 This plugin serves project documentation as HTML pages.
diff --git a/Documentation/dev-buck.txt b/Documentation/dev-buck.txt
index f0668f1..89cd849 100644
--- a/Documentation/dev-buck.txt
+++ b/Documentation/dev-buck.txt
@@ -12,7 +12,7 @@
 Clone the git and build it:
 
 ----
-  git clone https://gerrit.googlesource.com/buck
+  git clone https://github.com/facebook/buck
   cd buck
   git checkout $(cat ../gerrit/.buckversion)
   ant
diff --git a/Documentation/intro-project-owner.txt b/Documentation/intro-project-owner.txt
index b2fce88..eb3c4fb 100644
--- a/Documentation/intro-project-owner.txt
+++ b/Documentation/intro-project-owner.txt
@@ -765,6 +765,14 @@
 . link:#import-history[import the history of the old project]
 . link:#project-deletion[delete the old project]
 
+Please note that a drawback of this workaround is that the whole review
+history (changes, review comments) is lost.
+
+Alternatively, you can use the
+link:https://gerrit.googlesource.com/plugins/importer/[importer] plugin
+to copy the project _including the review history_, and then
+link:#project-deletion[delete the old project].
+
 GERRIT
 ------
 Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/user-inline-edit.txt b/Documentation/user-inline-edit.txt
index 10f97fe..5ad6b39f 100644
--- a/Documentation/user-inline-edit.txt
+++ b/Documentation/user-inline-edit.txt
@@ -45,7 +45,9 @@
 the 'Add...' button at the top of the file list.
 
 Files can be removed from the change, or restored, by clicking the icon to the
-left of the file name.
+left of the file name. Reverting a file in the change is also supported and is
+achieved in two steps: remove file from the change and restore the file in the
+change.
 
 To switch from edit mode back to review mode, click the 'Done Editing' button.
 
diff --git a/ReleaseNotes/ReleaseNotes-2.10.3.1.txt b/ReleaseNotes/ReleaseNotes-2.10.3.1.txt
new file mode 100644
index 0000000..2b90a6d
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.3.1.txt
@@ -0,0 +1,11 @@
+Release notes for Gerrit 2.10.3.1
+=================================
+
+There are no schema changes from link:ReleaseNotes-2.10.3.html[2.10.3].
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.1.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.1.war]
+
+The 2.10.3 release packaged wrong version of the core plugins due to a bug
+in our buck build scripts. This version fixes this issue.
diff --git a/ReleaseNotes/ReleaseNotes-2.10.3.txt b/ReleaseNotes/ReleaseNotes-2.10.3.txt
new file mode 100644
index 0000000..578a1ae
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.10.3.txt
@@ -0,0 +1,124 @@
+Release notes for Gerrit 2.10.3
+===============================
+
+Download:
+link:https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.war[
+https://gerrit-releases.storage.googleapis.com/gerrit-2.10.3.war]
+
+Important Notes
+---------------
+
+*WARNING:* There are no schema changes from
+link:ReleaseNotes-2.10.2.html[2.10.2], but Bouncycastle was upgraded to 1.51.
+It is therefore important to upgrade the site with the `init` program, rather
+than only copying the .war file over the existing one.
+
+*WARNING:* When upgrading from version 2.8.4 or older with a site that uses
+Bouncy Castle Crypto, new versions of the libraries will be downloaded. The old
+libraries should be manually removed from site's `lib` folder to prevent the
+startup failure described in
+link:https://code.google.com/p/gerrit/issues/detail?id=3084[Issue 3084].
+
+It is recommended to run the `init` program in interactive mode. Warnings will
+be suppressed in batch mode.
+
+----
+  java -jar gerrit.war init -d site_path
+----
+
+New Features
+------------
+
+* Support hybrid OpenID and OAuth2 authentication
++
+OpenID auth scheme is aware of optional OAuth2 plugin-based authentication.
+This feature is considered to be experimental and hasn't reached full feature set yet.
+Particularly, linking of user identities accross protocol boundaries and even from
+one OAuth2 identity to another OAuth2 identity wasn't implemented yet.
+
+Configuration
+~~~~~~~~~~~~~
+
+* Allow to configure
+link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.10.3/config-gerrit.html#sshd.rekeyBytesLimit[
+SSHD rekey parameters].
+
+SSH
+---
+
+* Update SSHD to 0.14.0.
++
+This fixes link:https://issues.apache.org/jira/browse/SSHD-348[SSHD-348] which
+was causing ssh threads allocated to stream-events clients to get stuck.
++
+Also update SSHD Mina to 2.0.8 and Bouncycastle to 1.51.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=2797[Issue 2797]:
+Add support for ECDSA based public key authentication.
+
+Bug Fixes
+---------
+
+* Prevent wrong content type for CSS files.
++
+The mime-util library contains two content type mappings for .css files:
+`application/x-pointplus` and `text/css`.  Unfortunately, using the wrong one
+will result in most browsers discarding the file as a CSS file.  Ensure we only
+use the correct type for CSS files.
+
+* link:https://code.google.com/p/gerrit/issues/detail?id=3289[Issue 3289]:
+Prevent NullPointerException in Gitweb servlet.
+
+Replication plugin
+~~~~~~~~~~~~~~~~~~
+
+* Set connection timeout to 120 seconds for SSH remote operations.
++
+The creation of a missing Git, before starting replication, is a blocking
+operation. By setting a timeout, we ensure the operation does not get stuck
+forever, essentially blocking all future remote git creation operations.
+
+OAuth extension point
+~~~~~~~~~~~~~~~~~~~~~
+
+* Respect servlet context path in URL for login token
++
+On sites with non empty context path, first redirect was broken and ended up
+with 404 Not found.
+
+* Invalidate OAuth session after web_sessions cache expiration
++
+After web session cache expiration there is no way to re-sign-in into Gerrit.
+
+Daemon
+~~~~~~
+
+* Print proper names for tasks in output of `show-queue` command.
++
+Some tasks were not displayed with the proper name.
+
+Web UI
+~~~~~~
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=3044[Issue 3044]:
+Remove stripping `#` in login redirect.
+
+SSH
+~~~
+
+* Prevent double authentication for the same public key.
+
+
+Performance
+-----------
+
+* Improved performance when creating a new branch on a repository with a large
+number of changes.
+
+
+Upgrades
+--------
+
+* Update Bouncycastle to 1.51.
+
+* Update SSHD to 0.14.0.
diff --git a/ReleaseNotes/ReleaseNotes-2.11.txt b/ReleaseNotes/ReleaseNotes-2.11.txt
index 49b1317..3bc6c96 100644
--- a/ReleaseNotes/ReleaseNotes-2.11.txt
+++ b/ReleaseNotes/ReleaseNotes-2.11.txt
@@ -8,8 +8,9 @@
 https://gerrit-releases.storage.googleapis.com/gerrit-2.11.war]
 
 Gerrit 2.11 includes the bug fixes done with
-link:ReleaseNotes-2.10.1.html[Gerrit 2.10.1] and
-link:ReleaseNotes-2.10.2.html[Gerrit 2.10.2].
+link:ReleaseNotes-2.10.1.html[Gerrit 2.10.1],
+link:ReleaseNotes-2.10.2.html[Gerrit 2.10.2] and
+link:ReleaseNotes-2.10.3.html[Gerrit 2.10.3].
 These bug fixes are *not* listed in these release notes.
 
 
@@ -20,9 +21,38 @@
 *WARNING:* This release contains schema changes.  To upgrade:
 ----
   java -jar gerrit.war init -d site_path
+----
+
+Gerrit 2.11 requires a secondary index, which can be created offline
+by running the `reindex` program:
+
+----
   java -jar gerrit.war reindex -d site_path
 ----
 
+If the site that is upgraded already has a secondary index, the
+secondary index can be upgraded online. This is important for large
+sites since running the `reindex` program can take a long time and
+contributes significantly to the downtime that is required for the
+upgrade.
+
+Gerrit 2.11 supports online reindexing only from the index version `11`
+which is the index version of Gerrit 2.10. This means if you come from
+an older release it makes sense to first upgrade to 2.10 and then do
+the upgrade to 2.11 so that you can profit from online reindexing.
+
+In case you are upgrading from 2.10 it is *important* to check *before*
+the upgrade to 2.11 that the index version of your Gerrit 2.10 site is
+`11`. You can check the index version in
+`$site_path/index/gerrit_index.config`. Your Gerrit 2.10 site may run
+with an older index version (e.g. if online reindexing to index version
+`11` is still running or if online reindexing to version `11` has
+failed). In this case you first need to successfully migrate your index
+version of your Gerrit 2.10 site to `11` and only then start with the
+2.11 upgrade. If you start the 2.11 upgrade when the schema version of
+your Gerrit 2.10 site is older than `11`, online reindexing is no longer
+possible and you need to reindex offline by using the `reindex` program.
+
 *WARNING:* Upgrading to 2.11.x requires the server be first upgraded to 2.8 (or
 2.9) and then to 2.11.x. If you are upgrading from 2.8.x or later, you may ignore
 this warning and upgrade directly to 2.11.x.
@@ -118,8 +148,6 @@
 
 * Show the parent commit's subject as a tooltip.
 
-* Decorate abandoned changes in the 'Related Changes' list with a dark red dot.
-
 * link:http://code.google.com/p/gerrit/issues/detail?id=2541[Issue 2541],
 link:http://code.google.com/p/gerrit/issues/detail?id=2974[Issue 2974]:
 Allow the 'Reply' button's
@@ -367,10 +395,6 @@
 link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#container.daemonOpt[
 options to pass to the daemon].
 
-* Allow to configure
-link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/config-gerrit.html#sshd.rekeyBytesLimit[
-SSHD rekey parameters].
-
 Daemon
 ~~~~~~
 
@@ -395,9 +419,6 @@
 SSH
 ~~~
 
-* link:https://code.google.com/p/gerrit/issues/detail?id=2797[Issue 2797]:
-Add support for ECDSA based public key authentication.
-
 * Add new commands
 link:https://gerrit-documentation.storage.googleapis.com/Documentation/2.11/cmd-logging-ls-level.html[
 `logging ls-level`] and
@@ -542,16 +563,6 @@
 Due to link:https://github.com/google/guice/issues/745[Guice issue 745], cloning
 of a repository with a space in its name was impossible.
 
-* Print proper names for tasks in output of `show-queue` command.
-+
-Some tasks were not displayed with the proper name.
-
-
-SSH
-~~~
-
-* Prevent double authentication for the same public key.
-
 
 Secondary Index / Search
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -600,19 +611,15 @@
 Web UI
 ~~~~~~
 
-* link:http://code.google.com/p/gerrit/issues/detail?id=3044[Issue 3044]:
-Remove stripping `#` in login redirect.
+Change List
+^^^^^^^^^^^
+
+* link:http://code.google.com/p/gerrit/issues/detail?id=3304[Issue 3304]:
+Always show a tooltip on the label column entries.
 
 Change Screen
 ^^^^^^^^^^^^^
 
-* link:http://code.google.com/p/gerrit/issues/detail?id=2894[Issue 2894]:
-Link to change screen for merged or abandoned changes in the 'Related Changes'
-list.
-+
-For changes in the 'Related Changes' tab that are closed the link was
-bringing the user to GitWeb, and not as expected to the change screen.
-
 * link:http://code.google.com/p/gerrit/issues/detail?id=3147[Issue 3147]:
 Allow to disable muting of common path prefixes in the file list.
 +
@@ -843,8 +850,6 @@
 
 * Update ASM to 5.0.3.
 
-* Update Bouncycastle to 1.51.
-
 * Update CodeMirror to 4.10.0-6-gd0a2dda.
 
 * Update Guava to 18.0.
@@ -866,5 +871,3 @@
 * Update Parboiled to 1.1.7.
 
 * Update Pegdown to 1.4.2.
-
-* Update SSHD to 0.14.0.
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt
index 1c4c2be..99db8fb 100644
--- a/ReleaseNotes/index.txt
+++ b/ReleaseNotes/index.txt
@@ -9,6 +9,8 @@
 [[2_10]]
 Version 2.10.x
 --------------
+* link:ReleaseNotes-2.10.3.1.html[2.10.3.1]
+* link:ReleaseNotes-2.10.3.html[2.10.3]
 * link:ReleaseNotes-2.10.2.html[2.10.2]
 * link:ReleaseNotes-2.10.1.html[2.10.1]
 * link:ReleaseNotes-2.10.html[2.10]
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestResponse.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestResponse.java
index 73dc1f0..6c7dbfe 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestResponse.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestResponse.java
@@ -19,6 +19,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.nio.charset.StandardCharsets;
 
 public class RestResponse extends HttpResponse {
 
@@ -29,7 +30,9 @@
   @Override
   public Reader getReader() throws IllegalStateException, IOException {
     if (reader == null && response.getEntity() != null) {
-      reader = new InputStreamReader(response.getEntity().getContent());
+      reader =
+          new InputStreamReader(response.getEntity().getContent(),
+              StandardCharsets.UTF_8);
       reader.skip(JSON_MAGIC.length);
     }
     return reader;
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
index 016a8be..4007e32 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/edit/ChangeEditIT.java
@@ -72,6 +72,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.Date;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicLong;
@@ -658,21 +659,21 @@
   private String newChange(PersonIdent ident) throws Exception {
     PushOneCommit push =
         pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME,
-            new String(CONTENT_OLD));
+            new String(CONTENT_OLD, StandardCharsets.UTF_8));
     return push.to("refs/for/master").getChangeId();
   }
 
   private String amendChange(PersonIdent ident, String changeId) throws Exception {
     PushOneCommit push =
         pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME2,
-            new String(CONTENT_NEW2), changeId);
+            new String(CONTENT_NEW2, StandardCharsets.UTF_8), changeId);
     return push.to("refs/for/master").getChangeId();
   }
 
   private String newChange2(PersonIdent ident) throws Exception {
     PushOneCommit push =
         pushFactory.create(db, ident, testRepo, PushOneCommit.SUBJECT, FILE_NAME,
-            new String(CONTENT_OLD));
+            new String(CONTENT_OLD, StandardCharsets.UTF_8));
     return push.rm("refs/for/master").getChangeId();
   }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
index 1c57d38..6867bab 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPreferencesScreen.java
@@ -210,6 +210,7 @@
     e.listenTo(legacycidInChangeTable);
     e.listenTo(muteCommonPathPrefixes);
     e.listenTo(diffView);
+    e.listenTo(reviewCategoryStrategy);
   }
 
   @Override
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
index 37b90c4..532f8f7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.java
@@ -130,7 +130,10 @@
 
     a2b(actions, "cherrypick", cherrypick);
     a2b(actions, "rebase", rebase);
-
+    if (rebase.isVisible()) {
+      // it is the rebase button in RebaseDialog that the server wants to disable
+      rebase.setEnabled(true);
+    }
     RevisionInfo revInfo = changeInfo.revision(revision);
     for (String id : filterNonCore(actions)) {
       add(new ActionButton(changeInfo, revInfo, actions.get(id)));
@@ -176,7 +179,16 @@
 
   @UiHandler("rebase")
   void onRebase(@SuppressWarnings("unused") ClickEvent e) {
-    RebaseAction.call(rebase, project, changeInfo.branch(), changeId, revision);
+    boolean enabled = true;
+    RevisionInfo revInfo = changeInfo.revision(revision);
+    if (revInfo.has_actions()) {
+        NativeMap<ActionInfo> actions = revInfo.actions();
+        if (actions.containsKey("rebase")) {
+          enabled = actions.get("rebase").enabled();
+        }
+    }
+    RebaseAction.call(rebase, project, changeInfo.branch(), changeId, revision,
+        enabled);
   }
 
   @UiHandler("submit")
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
index 5c44a14..3a3ffe2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileAction.java
@@ -28,16 +28,18 @@
   private final RevisionInfo revision;
   private final ChangeScreen.Style style;
   private final Widget addButton;
+  private final FileTable files;
 
   private AddFileBox addBox;
   private PopupPanel popup;
 
   AddFileAction(Change.Id changeId, RevisionInfo revision,
-      ChangeScreen.Style style, Widget addButton) {
+      ChangeScreen.Style style, Widget addButton, FileTable files) {
     this.changeId = changeId;
     this.revision = revision;
     this.style = style;
     this.addButton = addButton;
+    this.files = files;
   }
 
   public void onEdit() {
@@ -46,8 +48,9 @@
       return;
     }
 
+    files.unregisterKeys();
     if (addBox == null) {
-      addBox = new AddFileBox(changeId, revision);
+      addBox = new AddFileBox(changeId, revision, files);
     }
     addBox.clearPath();
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
index 82fe806..09de2c8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/AddFileBox.java
@@ -41,6 +41,7 @@
 
   private final Change.Id changeId;
   private final RevisionInfo revision;
+  private final FileTable fileTable;
 
   @UiField Button open;
   @UiField Button cancel;
@@ -48,9 +49,10 @@
   @UiField(provided = true)
   RemoteSuggestBox path;
 
-  AddFileBox(Change.Id changeId, RevisionInfo revision) {
+  AddFileBox(Change.Id changeId, RevisionInfo revision, FileTable files) {
     this.changeId = changeId;
     this.revision = revision;
+    this.fileTable = files;
 
     path = new RemoteSuggestBox(new PathSuggestOracle(changeId, revision));
     path.addSelectionHandler(new SelectionHandler<String>() {
@@ -63,6 +65,7 @@
       @Override
       public void onClose(CloseEvent<RemoteSuggestBox> event) {
         hide();
+        fileTable.registerKeys();
       }
     });
 
@@ -92,6 +95,7 @@
   @UiHandler("cancel")
   void onCancel(@SuppressWarnings("unused") ClickEvent e) {
     hide();
+    fileTable.registerKeys();
   }
 
   private void hide() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
index 4568882..d153771 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen.java
@@ -435,7 +435,7 @@
         reviewMode.setVisible(!editMode.isVisible());
         addFileAction = new AddFileAction(
             changeId, info.revision(revision),
-            style, addFile);
+            style, addFile, files);
         deleteFileAction = new DeleteFileAction(
             changeId, info.revision(revision),
             style, addFile);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
index 4bdd17f..93db1a7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.java
@@ -19,11 +19,13 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.GitwebLink;
 import com.google.gerrit.client.WebLinkInfo;
+import com.google.gerrit.client.actions.ActionInfo;
 import com.google.gerrit.client.account.AccountInfo;
 import com.google.gerrit.client.changes.ChangeInfo;
 import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
 import com.google.gerrit.client.changes.ChangeInfo.GitPerson;
 import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
+import com.google.gerrit.client.rpc.NativeMap;
 import com.google.gerrit.client.rpc.Natives;
 import com.google.gerrit.client.ui.CommentLinkProcessor;
 import com.google.gerrit.client.ui.InlineHyperlink;
@@ -46,6 +48,7 @@
 import com.google.gwt.user.client.ui.HTMLPanel;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.UIObject;
 import com.google.gwtexpui.clippy.client.CopyableLabel;
 import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
@@ -77,6 +80,7 @@
   @UiField HTML text;
   @UiField ScrollPanel scroll;
   @UiField Button more;
+  @UiField Element parentNotCurrentText;
   private boolean expanded;
 
   CommitBox() {
@@ -121,7 +125,19 @@
     if (revInfo.commit().parents().length() > 1) {
       mergeCommit.setVisible(true);
     }
+
     setParents(change.project(), revInfo.commit().parents());
+
+    // display the orange ball if parent has moved on (not current)
+    boolean parentNotCurrent = false;
+    if (revInfo.has_actions()) {
+      NativeMap<ActionInfo> actions = revInfo.actions();
+      if (actions.containsKey("rebase")) {
+        parentNotCurrent = actions.get("rebase").enabled();
+      }
+    }
+    UIObject.setVisible(parentNotCurrentText, parentNotCurrent);
+    parentNotCurrentText.setInnerText(parentNotCurrent ? "\u25CF" : "");
   }
 
   private void setWebLinks(ChangeInfo change, String revision,
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
index 5b7fb89..93312fa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/CommitBox.ui.xml
@@ -68,7 +68,7 @@
       padding: 0;
       width: 560px;
     }
-    .header th { width: 70px; }
+    .header th { width: 72px; }
     .header td { white-space: nowrap; }
     .date { width: 132px; }
 
@@ -106,6 +106,16 @@
       height: 16px !important;
       vertical-align: bottom;
     }
+
+    .parent {
+      margin-right: 3px;
+      float: left;
+    }
+    .parentNotCurrent {
+      color: #FFA62F;   <!-- orange -->
+      font-weight: bold;
+    }
+
   </ui:style>
   <g:HTMLPanel>
     <g:ScrollPanel styleName='{style.scroll}' ui:field='scroll'>
@@ -163,7 +173,15 @@
         </td>
       </tr>
       <tr ui:field='firstParent' style='display: none'>
-        <th><ui:msg>Parent(s)</ui:msg></th>
+        <th>
+          <div class='{style.parent}'>
+            <ui:msg>Parent(s)</ui:msg>
+          </div>
+          <div ui:field='parentNotCurrentText'
+              title='Not current - rebase possible'
+              class='{style.parentNotCurrent}'
+              style='display: none' aria-hidden='true'/>
+        </th>
         <td>
           <g:FlowPanel ui:field='parentCommits'/>
         </td>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
index fc62c46..2947be8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/FileTable.java
@@ -224,6 +224,14 @@
     }
   }
 
+  void unregisterKeys() {
+    register = false;
+
+    if (table != null) {
+      table.setRegisterKeys(false);
+    }
+  }
+
   void registerKeys() {
     register = true;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RebaseAction.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RebaseAction.java
index ffe9627..790198b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RebaseAction.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RebaseAction.java
@@ -27,10 +27,10 @@
 
 class RebaseAction {
   static void call(final Button b, final String project, final String branch,
-      final Change.Id id, final String revision) {
+      final Change.Id id, final String revision, final boolean enabled) {
     b.setEnabled(false);
 
-    new RebaseDialog(project, branch, id) {
+    new RebaseDialog(project, branch, id, enabled) {
       @Override
       public void onSend() {
         ChangeApi.rebase(id.get(), revision, getBase(), new GerritCallback<ChangeInfo>() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
index 5c49661..efaa7c2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.java
@@ -167,6 +167,7 @@
 
   String buttonRebaseChangeSend();
   String rebaseConfirmMessage();
+  String rebaseNotPossibleMessage();
   String rebasePlaceholderMessage();
   String rebaseTitle();
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
index 200f3e3..40c6d24 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeConstants.properties
@@ -153,6 +153,7 @@
 
 buttonRebaseChangeSend = Rebase
 rebaseConfirmMessage = Change parent revision
+rebaseNotPossibleMessage = Change is already up to date
 rebasePlaceholderMessage = (subject, change number, or leave empty)
 rebaseTitle = Code Review - Rebase Change
 
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 50ec3dd..8b71448 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
@@ -253,9 +253,6 @@
     }
     col++;
 
-    boolean displayInfo = Gerrit.isSignedIn() && Gerrit.getUserAccount()
-        .getGeneralPreferences().isShowInfoInReviewCategory();
-
     for (int idx = 0; idx < labelNames.size(); idx++, col++) {
       String name = labelNames.get(idx);
 
@@ -276,7 +273,7 @@
         user = label.rejected().name();
         info = getReviewCategoryDisplayInfo(reviewCategoryStrategy,
             label.rejected());
-        if (displayInfo && info != null) {
+        if (info != null) {
           FlowPanel panel = new FlowPanel();
           panel.add(new Image(Gerrit.RESOURCES.redNot()));
           panel.add(new InlineLabel(info));
@@ -288,7 +285,7 @@
         user = label.approved().name();
         info = getReviewCategoryDisplayInfo(reviewCategoryStrategy,
             label.approved());
-        if (displayInfo && info != null) {
+        if (info != null) {
           FlowPanel panel = new FlowPanel();
           panel.add(new Image(Gerrit.RESOURCES.greenCheck()));
           panel.add(new InlineLabel(info));
@@ -301,7 +298,7 @@
         info = getReviewCategoryDisplayInfo(reviewCategoryStrategy,
             label.disliked());
         String vstr = String.valueOf(label._value());
-        if (displayInfo && info != null) {
+        if (info != null) {
           vstr = vstr + " " + info;
         }
         fmt.addStyleName(row, col, Gerrit.RESOURCES.css().negscore());
@@ -311,7 +308,7 @@
         info = getReviewCategoryDisplayInfo(reviewCategoryStrategy,
             label.recommended());
         String vstr = "+" + label._value();
-        if (displayInfo && info != null) {
+        if (info != null) {
           vstr = vstr + " " + info;
         }
         fmt.addStyleName(row, col, Gerrit.RESOURCES.css().posscore());
@@ -322,8 +319,7 @@
       }
       fmt.addStyleName(row, col, Gerrit.RESOURCES.css().singleLine());
 
-      if ((!displayInfo || reviewCategoryStrategy == ReviewCategoryStrategy.ABBREV)
-          && user != null) {
+      if (user != null) {
         // Some web browsers ignore the embedded newline; some like it;
         // so we include a space before the newline to accommodate both.
         fmt.getElement(row, col).setTitle(name + " \nby " + user);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
index 0e19e46..dd36657 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/editor/EditScreen.java
@@ -347,7 +347,7 @@
   private void initEditor(HttpResponse<NativeString> file) {
     ModeInfo mode = null;
     String content = "";
-    if (file != null) {
+    if (file != null && file.getResult() != null) {
       content = file.getResult().asString();
       if (prefs.syntaxHighlighting()) {
         mode = ModeInfo.findMode(file.getContentType(), path);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
index 6b96604..5f47d98 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RebaseDialog.java
@@ -36,10 +36,12 @@
   private final SuggestBox base;
   private final CheckBox cb;
   private List<ChangeInfo> changes;
+  private final boolean sendEnabled;
 
   public RebaseDialog(final String project, final String branch,
-      final Change.Id changeId) {
+      final Change.Id changeId, final boolean sendEnabled) {
     super(Util.C.rebaseTitle(), null);
+    this.sendEnabled = sendEnabled;
     sendButton.setText(Util.C.buttonRebaseChangeSend());
 
     // create the suggestion box
@@ -63,7 +65,6 @@
         done.onSuggestionsReady(request, new Response(suggestions));
       }
     });
-    base.setEnabled(false);
     base.getElement().setAttribute("placeholder",
         Util.C.rebasePlaceholderMessage());
     base.setStyleName(Gerrit.RESOURCES.css().rebaseSuggestBox());
@@ -81,13 +82,11 @@
                 @Override
                 public void onSuccess(ChangeList result) {
                   changes = Natives.asList(result);
-                  base.setEnabled(true);
-                  base.setFocus(true);
+                  updateControls(true);
                 }
               });
         } else {
-          base.setEnabled(false);
-          sendButton.setFocus(true);
+          updateControls(false);
         }
       }
     });
@@ -102,7 +101,26 @@
   public void center() {
     super.center();
     GlobalKey.dialog(this);
-    sendButton.setFocus(true);
+    updateControls(false);
+  }
+
+  private void updateControls(boolean changeParentEnabled) {
+    if (changeParentEnabled) {
+      sendButton.setTitle(null);
+      sendButton.setEnabled(true);
+      base.setEnabled(true);
+      base.setFocus(true);
+    } else {
+      base.setEnabled(false);
+      sendButton.setEnabled(sendEnabled);
+      if (sendEnabled) {
+        sendButton.setTitle(null);
+        sendButton.setFocus(true);
+      } else {
+        sendButton.setTitle(Util.C.rebaseNotPossibleMessage());
+        cancelButton.setFocus(true);
+      }
+    }
   }
 
   public String getBase() {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
index 84a048a..86debdd 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/UrlModule.java
@@ -71,7 +71,8 @@
     }
     serve("/cat/*").with(CatServlet.class);
 
-    if (authConfig.getAuthType() != AuthType.OAUTH) {
+    if (authConfig.getAuthType() != AuthType.OAUTH &&
+        authConfig.getAuthType() != AuthType.OPENID) {
       serve("/logout").with(HttpLogoutServlet.class);
       serve("/signout").with(HttpLogoutServlet.class);
     }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
index fd8d3b4..15150cf 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java
@@ -363,15 +363,18 @@
     }
 
     final Map<String, String> params = getParameters(req);
-    if (deniedActions.contains(params.get("a"))) {
-      rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
-      return;
-    }
+    String a = params.get("a");
+    if (a != null) {
+      if (deniedActions.contains(a)) {
+        rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
+        return;
+      }
 
-    if (params.get("a").equals(PROJECT_LIST_ACTION)) {
-      rsp.sendRedirect(req.getContextPath() + "/#" + PageLinks.ADMIN_PROJECTS
-          + "?filter=" + Url.encode(params.get("pf") + "/"));
-      return;
+      if (a.equals(PROJECT_LIST_ACTION)) {
+        rsp.sendRedirect(req.getContextPath() + "/#" + PageLinks.ADMIN_PROJECTS
+            + "?filter=" + Url.encode(params.get("pf") + "/"));
+        return;
+      }
     }
 
     String name = params.get("p");
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
index fd26837..405a861 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
@@ -583,6 +583,9 @@
       if ("application/octet-stream".equals(contentType)
           && entry.getName().endsWith(".js")) {
         contentType = "application/javascript";
+      } else if ("application/x-pointplus".equals(contentType)
+          && entry.getName().endsWith(".css")) {
+        contentType = "text/css";
       }
     }
 
diff --git a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
index 8ffbbe6..739dffe 100644
--- a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
+++ b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
@@ -22,6 +22,8 @@
 import com.google.gerrit.extensions.auth.oauth.OAuthUserInfo;
 import com.google.gerrit.extensions.auth.oauth.OAuthVerifier;
 import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.httpd.CanonicalWebUrl;
 import com.google.gerrit.httpd.WebSession;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountException;
@@ -36,8 +38,6 @@
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 
@@ -53,17 +53,20 @@
   private final String state;
   private final DynamicItem<WebSession> webSession;
   private final AccountManager accountManager;
+  private final CanonicalWebUrl urlProvider;
   private OAuthServiceProvider serviceProvider;
   private OAuthToken token;
   private OAuthUserInfo user;
-  private String redirectUrl;
+  private String redirectToken;
 
   @Inject
   OAuthSession(DynamicItem<WebSession> webSession,
-      AccountManager accountManager) {
+      AccountManager accountManager,
+      CanonicalWebUrl urlProvider) {
     this.state = generateRandomState();
     this.webSession = webSession;
     this.accountManager = accountManager;
+    this.urlProvider = urlProvider;
   }
 
   boolean isLoggedIn() {
@@ -95,7 +98,7 @@
 
       if (isLoggedIn()) {
         log.debug("Login-SUCCESS " + this);
-        authenticateAndRedirect(response);
+        authenticateAndRedirect(request, response);
         return true;
       } else {
         response.sendError(SC_UNAUTHORIZED);
@@ -103,15 +106,22 @@
       }
     } else {
       log.debug("Login-PHASE1 " + this);
-      redirectUrl = request.getRequestURI();
+      redirectToken = request.getRequestURI();
+      // We are here in content of filter.
+      // Due to this Jetty limitation:
+      // https://bz.apache.org/bugzilla/show_bug.cgi?id=28323
+      // we cannot use LoginUrlToken.getToken() method,
+      // because it relies on getPathInfo() and it is always null here.
+      redirectToken = redirectToken.substring(
+          request.getContextPath().length());
       response.sendRedirect(oauth.getAuthorizationUrl() +
           "&state=" + state);
       return false;
     }
   }
 
-  private void authenticateAndRedirect(HttpServletResponse rsp)
-      throws IOException {
+  private void authenticateAndRedirect(HttpServletRequest req,
+      HttpServletResponse rsp) throws IOException {
     com.google.gerrit.server.account.AuthRequest areq =
         new com.google.gerrit.server.account.AuthRequest(user.getExternalId());
     AuthResult arsp;
@@ -164,16 +174,17 @@
     }
 
     webSession.get().login(arsp, true);
-    String suffix = redirectUrl.substring(
+    String suffix = redirectToken.substring(
         OAuthWebFilter.GERRIT_LOGIN.length() + 1);
-    suffix = URLDecoder.decode(suffix, StandardCharsets.UTF_8.name());
-    rsp.sendRedirect(suffix);
+    StringBuilder rdr = new StringBuilder(urlProvider.get(req));
+    rdr.append(Url.decode(suffix));
+    rsp.sendRedirect(rdr.toString());
   }
 
   void logout() {
     token = null;
     user = null;
-    redirectUrl = null;
+    redirectToken = null;
     serviceProvider = null;
   }
 
diff --git a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java
index 2965613..4021c57 100644
--- a/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java
+++ b/gerrit-oauth/src/main/java/com/google/gerrit/httpd/auth/oauth/OAuthWebFilter.java
@@ -89,18 +89,22 @@
       FilterChain chain) throws IOException, ServletException {
     HttpServletRequest httpRequest = (HttpServletRequest) request;
     HttpSession httpSession = ((HttpServletRequest) request).getSession(false);
+    OAuthSession oauthSession = oauthSessionProvider.get();
     if (currentUserProvider.get().isIdentifiedUser()) {
       if (httpSession != null) {
         httpSession.invalidate();
       }
       chain.doFilter(request, response);
       return;
+    } else {
+      if (oauthSession.isLoggedIn()) {
+        oauthSession.logout();
+      }
     }
 
     HttpServletResponse httpResponse = (HttpServletResponse) response;
 
     String provider = httpRequest.getParameter("provider");
-    OAuthSession oauthSession = oauthSessionProvider.get();
     OAuthServiceProvider service = ssoProvider == null
         ? oauthSession.getServiceProvider()
         : ssoProvider;
diff --git a/gerrit-openid/BUCK b/gerrit-openid/BUCK
index 8761d34..78abce8 100644
--- a/gerrit-openid/BUCK
+++ b/gerrit-openid/BUCK
@@ -12,6 +12,7 @@
     '//gerrit-server:server',
     '//lib:guava',
     '//lib:gwtorm',
+    '//lib/commons:codec',
     '//lib/guice:guice',
     '//lib/guice:guice-servlet',
     '//lib/jgit:jgit',
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
index 435bfa7..bef165b 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
@@ -22,11 +22,14 @@
 import com.google.gerrit.common.Nullable;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.auth.openid.OpenIdUrls;
+import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
+import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.extensions.restapi.Url;
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.httpd.LoginUrlToken;
 import com.google.gerrit.httpd.template.SiteHeaderFooter;
 import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.GerritServerConfig;
@@ -61,10 +64,13 @@
 
   private final ImmutableSet<String> suggestProviders;
   private final Provider<String> urlProvider;
+  private final Provider<OAuthSessionOverOpenID> oauthSessionProvider;
   private final OpenIdServiceImpl impl;
   private final int maxRedirectUrlLength;
   private final String ssoUrl;
   private final SiteHeaderFooter header;
+  private final Provider<CurrentUser> currentUserProvider;
+  private final DynamicMap<OAuthServiceProvider> oauthServiceProviders;
 
   @Inject
   LoginForm(
@@ -72,13 +78,19 @@
       @GerritServerConfig Config config,
       AuthConfig authConfig,
       OpenIdServiceImpl impl,
-      SiteHeaderFooter header) {
+      SiteHeaderFooter header,
+      Provider<OAuthSessionOverOpenID> oauthSessionProvider,
+      Provider<CurrentUser> currentUserProvider,
+      DynamicMap<OAuthServiceProvider> oauthServiceProviders) {
     this.urlProvider = urlProvider;
     this.impl = impl;
     this.header = header;
     this.maxRedirectUrlLength = config.getInt(
         "openid", "maxRedirectUrlLength",
         10);
+    this.oauthSessionProvider = oauthSessionProvider;
+    this.currentUserProvider = currentUserProvider;
+    this.oauthServiceProviders = oauthServiceProviders;
 
     if (urlProvider == null || Strings.isNullOrEmpty(urlProvider.get())) {
       log.error("gerrit.canonicalWebUrl must be set in gerrit.config");
@@ -152,7 +164,23 @@
       mode = SignInMode.SIGN_IN;
     }
 
-    discover(req, res, link, id, remember, token, mode);
+    OAuthServiceProvider oauthProvider = lookupOAuthServiceProvider(id);
+
+    if (oauthProvider == null) {
+      discover(req, res, link, id, remember, token, mode);
+    } else {
+      OAuthSessionOverOpenID oauthSession = oauthSessionProvider.get();
+      if (!currentUserProvider.get().isIdentifiedUser()
+          && oauthSession.isLoggedIn()) {
+        oauthSession.logout();
+      }
+      if ((isGerritLogin(req)
+          || oauthSession.isOAuthFinal(req))
+          && !oauthSession.isLoggedIn()) {
+        oauthSession.setServiceProvider(oauthProvider);
+        oauthSession.login(req, res, oauthProvider);
+      }
+    }
   }
 
   private void discover(HttpServletRequest req, HttpServletResponse res,
@@ -267,6 +295,20 @@
       }
       a.setAttribute("href", u.toString());
     }
+
+    // OAuth: Add plugin based providers
+    Element providers = HtmlDomUtil.find(doc, "providers");
+    Set<String> plugins = oauthServiceProviders.plugins();
+    for (String pluginName : plugins) {
+      Map<String, Provider<OAuthServiceProvider>> m =
+          oauthServiceProviders.byPlugin(pluginName);
+        for (Map.Entry<String, Provider<OAuthServiceProvider>> e
+            : m.entrySet()) {
+          addProvider(providers, pluginName, e.getKey(),
+              e.getValue().get().getName());
+        }
+    }
+
     sendHtml(res, doc);
   }
 
@@ -285,6 +327,38 @@
     }
   }
 
+  private static void addProvider(Element form, String pluginName,
+      String id, String serviceName) {
+    Element div = form.getOwnerDocument().createElement("div");
+    div.setAttribute("id", id);
+    Element hyperlink = form.getOwnerDocument().createElement("a");
+    hyperlink.setAttribute("href", String.format("?id=%s_%s",
+        pluginName, id));
+    hyperlink.setTextContent(serviceName +
+        " (" + pluginName + " plugin)");
+    div.appendChild(hyperlink);
+    form.appendChild(div);
+  }
+
+  private OAuthServiceProvider lookupOAuthServiceProvider(String providerId) {
+    if (providerId.startsWith("http://")) {
+      providerId = providerId.substring("http://".length());
+    }
+    Set<String> plugins = oauthServiceProviders.plugins();
+    for (String pluginName : plugins) {
+      Map<String, Provider<OAuthServiceProvider>> m =
+          oauthServiceProviders.byPlugin(pluginName);
+        for (Map.Entry<String, Provider<OAuthServiceProvider>> e
+            : m.entrySet()) {
+          if (providerId.equals(
+              String.format("%s_%s", pluginName, e.getKey()))) {
+            return e.getValue().get();
+          }
+        }
+    }
+    return null;
+  }
+
   private static String getLastId(HttpServletRequest req) {
     Cookie[] cookies = req.getCookies();
     if (cookies != null) {
@@ -296,4 +370,9 @@
     }
     return null;
   }
+
+  private static boolean isGerritLogin(HttpServletRequest request) {
+    return request.getRequestURI().indexOf(
+        OAuthSessionOverOpenID.GERRIT_LOGIN) >= 0;
+  }
 }
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthOverOpenIDLogoutServlet.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthOverOpenIDLogoutServlet.java
new file mode 100644
index 0000000..9dbff03
--- /dev/null
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthOverOpenIDLogoutServlet.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2015 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.httpd.auth.openid;
+
+import com.google.gerrit.audit.AuditService;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.httpd.HttpLogoutServlet;
+import com.google.gerrit.httpd.WebSession;
+import com.google.gerrit.server.config.AuthConfig;
+import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Singleton
+class OAuthOverOpenIDLogoutServlet extends HttpLogoutServlet {
+  private static final long serialVersionUID = 1L;
+
+  private final Provider<OAuthSessionOverOpenID> oauthSession;
+
+  @Inject
+  OAuthOverOpenIDLogoutServlet(AuthConfig authConfig,
+      DynamicItem<WebSession> webSession,
+      @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+      AuditService audit,
+      Provider<OAuthSessionOverOpenID> oauthSession) {
+    super(authConfig, webSession, urlProvider, audit);
+    this.oauthSession = oauthSession;
+  }
+
+  @Override
+  protected void doLogout(HttpServletRequest req, HttpServletResponse rsp)
+      throws IOException {
+    super.doLogout(req, rsp);
+    oauthSession.get().logout();
+  }
+}
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
new file mode 100644
index 0000000..a02f52d
--- /dev/null
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
@@ -0,0 +1,216 @@
+// Copyright (C) 2015 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.httpd.auth.openid;
+
+import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
+import com.google.gerrit.extensions.auth.oauth.OAuthToken;
+import com.google.gerrit.extensions.auth.oauth.OAuthUserInfo;
+import com.google.gerrit.extensions.auth.oauth.OAuthVerifier;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.httpd.CanonicalWebUrl;
+import com.google.gerrit.httpd.LoginUrlToken;
+import com.google.gerrit.httpd.WebSession;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.server.account.AccountException;
+import com.google.gerrit.server.account.AccountManager;
+import com.google.gerrit.server.account.AuthResult;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.servlet.SessionScoped;
+
+import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/** OAuth protocol implementation */
+@SessionScoped
+class OAuthSessionOverOpenID {
+  static final String GERRIT_LOGIN = "/login";
+  private static final Logger log = LoggerFactory.getLogger(
+      OAuthSessionOverOpenID.class);
+  private static final SecureRandom randomState = newRandomGenerator();
+  private final String state;
+  private final DynamicItem<WebSession> webSession;
+  private final AccountManager accountManager;
+  private final CanonicalWebUrl urlProvider;
+  private OAuthServiceProvider serviceProvider;
+  private OAuthToken token;
+  private OAuthUserInfo user;
+  private String redirectToken;
+
+  @Inject
+  OAuthSessionOverOpenID(DynamicItem<WebSession> webSession,
+      AccountManager accountManager,
+      CanonicalWebUrl urlProvider) {
+    this.state = generateRandomState();
+    this.webSession = webSession;
+    this.accountManager = accountManager;
+    this.urlProvider = urlProvider;
+  }
+
+  boolean isLoggedIn() {
+    return token != null && user != null;
+  }
+
+  boolean isOAuthFinal(HttpServletRequest request) {
+    return Strings.emptyToNull(request.getParameter("code")) != null;
+  }
+
+  boolean login(HttpServletRequest request, HttpServletResponse response,
+      OAuthServiceProvider oauth) throws IOException {
+    if (isLoggedIn()) {
+      return true;
+    }
+
+    log.debug("Login " + this);
+
+    if (isOAuthFinal(request)) {
+      if (!checkState(request)) {
+        response.sendError(HttpServletResponse.SC_NOT_FOUND);
+        return false;
+      }
+
+      log.debug("Login-Retrieve-User " + this);
+      token = oauth.getAccessToken(new OAuthVerifier(request.getParameter("code")));
+
+      user = oauth.getUserInfo(token);
+
+      if (isLoggedIn()) {
+        log.debug("Login-SUCCESS " + this);
+        authenticateAndRedirect(request, response);
+        return true;
+      } else {
+        response.sendError(SC_UNAUTHORIZED);
+        return false;
+      }
+    } else {
+      log.debug("Login-PHASE1 " + this);
+      redirectToken = LoginUrlToken.getToken(request);
+      response.sendRedirect(oauth.getAuthorizationUrl() +
+          "&state=" + state);
+      return false;
+    }
+  }
+
+  private void authenticateAndRedirect(HttpServletRequest req,
+      HttpServletResponse rsp) throws IOException {
+    com.google.gerrit.server.account.AuthRequest areq =
+        new com.google.gerrit.server.account.AuthRequest(user.getExternalId());
+    AuthResult arsp = null;
+    try {
+      String claimedIdentifier = user.getClaimedIdentity();
+      Account.Id actualId = accountManager.lookup(user.getExternalId());
+      if (!Strings.isNullOrEmpty(claimedIdentifier)) {
+        Account.Id claimedId = accountManager.lookup(claimedIdentifier);
+        if (claimedId != null && actualId != null) {
+          if (claimedId.equals(actualId)) {
+            // Both link to the same account, that's what we expected.
+          } else {
+            // This is (for now) a fatal error. There are two records
+            // for what might be the same user.
+            //
+            log.error("OAuth accounts disagree over user identity:\n"
+                + "  Claimed ID: " + claimedId + " is " + claimedIdentifier
+                + "\n" + "  Delgate ID: " + actualId + " is "
+                + user.getExternalId());
+            rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
+            return;
+          }
+        } else if (claimedId != null && actualId == null) {
+          // Claimed account already exists: link to it.
+          //
+          try {
+            accountManager.link(claimedId, areq);
+          } catch (OrmException e) {
+            log.error("Cannot link: " +  user.getExternalId()
+                + " to user identity:\n"
+                + "  Claimed ID: " + claimedId + " is " + claimedIdentifier);
+            rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
+            return;
+          }
+        }
+      }
+      areq.setUserName(user.getUserName());
+      areq.setEmailAddress(user.getEmailAddress());
+      areq.setDisplayName(user.getDisplayName());
+      arsp = accountManager.authenticate(areq);
+    } catch (AccountException e) {
+      log.error("Unable to authenticate user \"" + user + "\"", e);
+      rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
+      return;
+    }
+
+    webSession.get().login(arsp, true);
+    StringBuilder rdr = new StringBuilder(urlProvider.get(req));
+    rdr.append(Url.decode(redirectToken));
+    rsp.sendRedirect(rdr.toString());
+  }
+
+  void logout() {
+    token = null;
+    user = null;
+    redirectToken = null;
+    serviceProvider = null;
+  }
+
+  private boolean checkState(ServletRequest request) {
+    String s = Strings.nullToEmpty(request.getParameter("state"));
+    if (!s.equals(state)) {
+      log.error("Illegal request state '" + s + "' on OAuthProtocol " + this);
+      return false;
+    }
+    return true;
+  }
+
+  private static SecureRandom newRandomGenerator() {
+    try {
+      return SecureRandom.getInstance("SHA1PRNG");
+    } catch (NoSuchAlgorithmException e) {
+      throw new IllegalArgumentException(
+          "No SecureRandom available for GitHub authentication", e);
+    }
+  }
+
+  private static String generateRandomState() {
+    byte[] state = new byte[32];
+    randomState.nextBytes(state);
+    return Base64.encodeBase64URLSafeString(state);
+  }
+
+  @Override
+  public String toString() {
+    return "OAuthSession [token=" + token + ", user=" + user + "]";
+  }
+
+  public void setServiceProvider(OAuthServiceProvider provider) {
+    this.serviceProvider = provider;
+  }
+
+  public OAuthServiceProvider getServiceProvider() {
+    return serviceProvider;
+  }
+}
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java
new file mode 100644
index 0000000..7766e69
--- /dev/null
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthWebFilterOverOpenID.java
@@ -0,0 +1,115 @@
+// Copyright (C) 2015 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.httpd.auth.openid;
+
+import com.google.common.collect.Iterables;
+import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.server.CurrentUser;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+import java.io.IOException;
+import java.util.SortedMap;
+import java.util.SortedSet;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+
+/** OAuth web filter uses active OAuth session to perform OAuth requests */
+@Singleton
+class OAuthWebFilterOverOpenID implements Filter {
+  static final String GERRIT_LOGIN = "/login";
+
+  private final Provider<CurrentUser> currentUserProvider;
+  private final Provider<OAuthSessionOverOpenID> oauthSessionProvider;
+  private final DynamicMap<OAuthServiceProvider> oauthServiceProviders;
+  private OAuthServiceProvider ssoProvider;
+
+  @Inject
+  OAuthWebFilterOverOpenID(Provider<CurrentUser> currentUserProvider,
+      DynamicMap<OAuthServiceProvider> oauthServiceProviders,
+      Provider<OAuthSessionOverOpenID> oauthSessionProvider) {
+    this.currentUserProvider = currentUserProvider;
+    this.oauthServiceProviders = oauthServiceProviders;
+    this.oauthSessionProvider = oauthSessionProvider;
+  }
+
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+    pickSSOServiceProvider();
+  }
+
+  @Override
+  public void destroy() {
+  }
+
+  @Override
+  public void doFilter(ServletRequest request, ServletResponse response,
+      FilterChain chain) throws IOException, ServletException {
+    HttpServletRequest httpRequest = (HttpServletRequest) request;
+    HttpSession httpSession = ((HttpServletRequest) request).getSession(false);
+    if (currentUserProvider.get().isIdentifiedUser()) {
+      if (httpSession != null) {
+        httpSession.invalidate();
+      }
+      chain.doFilter(request, response);
+      return;
+    }
+
+    HttpServletResponse httpResponse = (HttpServletResponse) response;
+
+    OAuthSessionOverOpenID oauthSession = oauthSessionProvider.get();
+    OAuthServiceProvider service = ssoProvider == null
+        ? oauthSession.getServiceProvider()
+        : ssoProvider;
+
+    if ((isGerritLogin(httpRequest)
+        || oauthSession.isOAuthFinal(httpRequest))
+        && !oauthSession.isLoggedIn()) {
+        if (service == null) {
+          throw new IllegalStateException("service is unknown");
+        }
+        oauthSession.setServiceProvider(service);
+        oauthSession.login(httpRequest, httpResponse, service);
+    } else {
+      chain.doFilter(httpRequest, response);
+    }
+  }
+
+  private void pickSSOServiceProvider() {
+    SortedSet<String> plugins = oauthServiceProviders.plugins();
+    if (plugins.size() == 1) {
+      SortedMap<String, Provider<OAuthServiceProvider>> services =
+          oauthServiceProviders.byPlugin(Iterables.getOnlyElement(plugins));
+      if (services.size() == 1) {
+        ssoProvider = Iterables.getOnlyElement(services.values()).get();
+      }
+    }
+  }
+
+  private static boolean isGerritLogin(HttpServletRequest request) {
+    return request.getRequestURI().indexOf(GERRIT_LOGIN) >= 0;
+  }
+}
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java
index c87a0cf..ace0c53 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdModule.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.httpd.auth.openid;
 
+import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
+import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.inject.servlet.ServletModule;
 
 /** Servlets related to OpenID authentication. */
@@ -21,9 +23,12 @@
   @Override
   protected void configureServlets() {
     serve("/login", "/login/*").with(LoginForm.class);
+    serve("/logout").with(OAuthOverOpenIDLogoutServlet.class);
+    filter("/oauth").through(OAuthWebFilterOverOpenID.class);
     serve("/" + OpenIdServiceImpl.RETURN_URL).with(OpenIdLoginServlet.class);
     serve("/" + XrdsServlet.LOCATION).with(XrdsServlet.class);
     filter("/").through(XrdsFilter.class);
     bind(OpenIdServiceImpl.class);
+    DynamicMap.mapOf(binder(), OAuthServiceProvider.class);
   }
 }
diff --git a/gerrit-openid/src/main/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html b/gerrit-openid/src/main/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html
index 1e2c510..07e09f5 100644
--- a/gerrit-openid/src/main/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html
+++ b/gerrit-openid/src/main/resources/com/google/gerrit/httpd/auth/openid/LoginForm.html
@@ -16,9 +16,19 @@
       #logo_box {
         padding-left: 160px;
       }
-      #logo_img {
+      #logo_oauth {
+        width: 96px;
+        height: 96px;
+        display: inline-block;
+        margin-bottom: 20px;
+        background: url('data:image/png;base64,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') no-repeat 0px 0px;
+      }
+      #logo_openid {
         width: 200px;
         height: 80px;
+        display: inline-block;
+        margin-left: 100px;
+        margin-bottom: 28px;
         background: url('data:image/png;base64,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') no-repeat 0px 0px;
       }
       #f_openid {
@@ -36,7 +46,7 @@
       <h1>Sign In to Gerrit Code Review at <span id="hostName">example.com</span></h1>
       <form method="POST" action="#" id="login_form">
         <input type="hidden" name="link" id="f_link" value="1" />
-        <div id="logo_box"><div id="logo_img"></div></div>
+        <div id="logo_box"><div id="logo_oauth"></div><div id="logo_openid"></div></div>
         <div id="error_message">Invalid OpenID identifier.</div>
         <div>
           <input type="text"
@@ -57,6 +67,9 @@
           <a href="../" id="cancel_link">Cancel</a>
         </div>
 
+        <div id="providers">
+        </div>
+
         <div id="provider_launchpad">
           <img height="16" width="16" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAHKSURBVCiRjZI9SFtRGIafc5tiVFCkhUxKBAcLYoPWwE0GEUPBwc0f1MHFoWLBiKABobWtBh2kacFYwUUQRXBoB3EJCVUvyBVrIB1UskTawUGFQOoP5h6H3ki8deg7vuc853zvxyuklORLDUc9QH9nZeAL0AGM+1v0cywSOVANR8uBaaALOOysDLwCYsAp8AaY97fo2RyoqOFooRqOvgUOTMiqJ8AsEA9tuH13IFkcQD1QZHpbQE+bPXEADAK5MSsA1/p+1SMAoTbF9oAh2WYUAcWbz5tThiQE1EsI7VxVzMWvHe2lGWP1RaqgWyKe1g5vjyhAHfBdrCmuWG1zqSHRAS9gFxBQC451/+PdhbqUPSYR00JSAmDLy+IE7ICwZHRkbBQKqMo3lQeW8V/KB5PAMSAtd06Kb7iQf8/vgXuA9/2V9nN7dCKjCNyABlxKmPqx7HQvDjX0HX29bBLIUSlIA4gNT9Bpw/gMtJqPaYD/2evJX5FgTQcwDpQBaeCD8+XZx8aZZFaxYZyYv/4xQS+wFAnWVAOfTAgzRrxxJpkFUHza2IVPG3sHVAMrD+zhFBgAXL0JPZIzhbXkEe+kB+j/nf52V/LexL8lvwVTCpkwGXEEfAAAAABJRU5ErkJggg=="/>
           <a href="?id=https://login.launchpad.net/%2Bopenid" id="id_launchpad">Sign in with a Launchpad ID</a>
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
index 432e293..1719a7e 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RefNames.java
@@ -86,6 +86,36 @@
     return r.toString();
   }
 
+  /**
+   * Returns reference for this change edit with sharded user and change number:
+   * refs/users/UU/UUUU/edit-CCCC/P.
+   *
+   * @param accountId account id
+   * @param changeId change number
+   * @param psId patch set number
+   * @return reference for this change edit
+   */
+  public static String refsEdit(Account.Id accountId, Change.Id changeId,
+      PatchSet.Id psId) {
+    return refsEditPrefix(accountId, changeId) + psId.get();
+  }
+
+  /**
+   * Returns reference prefix for this change edit with sharded user and
+   * change number: refs/users/UU/UUUU/edit-CCCC/.
+   *
+   * @param accountId account id
+   * @param changeId change number
+   * @return reference prefix for this change edit
+   */
+  public static String refsEditPrefix(Account.Id accountId, Change.Id changeId) {
+    return new StringBuilder(refsUsers(accountId))
+      .append("/edit-")
+      .append(changeId.get())
+      .append("/")
+      .toString();
+  }
+
   private RefNames() {
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java
index 023173e..df6b76e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ActionJson.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.extensions.webui.PrivateInternals_UiActionDescription;
 import com.google.gerrit.extensions.webui.UiAction;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.changedetail.RebaseChange;
 import com.google.gerrit.server.extensions.webui.UiActions;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.inject.Inject;
@@ -36,13 +37,16 @@
 public class ActionJson {
   private final Revisions revisions;
   private final DynamicMap<RestView<ChangeResource>> changeViews;
+  private final RebaseChange rebaseChange;
 
   @Inject
   ActionJson(
       Revisions revisions,
-      DynamicMap<RestView<ChangeResource>> changeViews) {
+      DynamicMap<RestView<ChangeResource>> changeViews,
+      RebaseChange rebaseChange) {
     this.revisions = revisions;
     this.changeViews = changeViews;
+    this.rebaseChange = rebaseChange;
   }
 
   public Map<String, ActionInfo> format(RevisionResource rsrc) {
@@ -69,7 +73,7 @@
     Provider<CurrentUser> userProvider = Providers.of(ctl.getCurrentUser());
     for (UiAction.Description d : UiActions.from(
         changeViews,
-        new ChangeResource(ctl),
+        new ChangeResource(ctl, rebaseChange),
         userProvider)) {
       out.put(d.getId(), new ActionInfo(d));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index 2accdb8..367ec2c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -92,6 +92,7 @@
 import com.google.gerrit.server.PatchLineCommentsUtil;
 import com.google.gerrit.server.WebLinks;
 import com.google.gerrit.server.account.AccountLoader;
+import com.google.gerrit.server.changedetail.RebaseChange;
 import com.google.gerrit.server.git.LabelNormalizer;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.patch.PatchListNotAvailableException;
@@ -142,6 +143,7 @@
   private final PatchLineCommentsUtil plcUtil;
   private final Provider<ConsistencyChecker> checkerProvider;
   private final ActionJson actionJson;
+  private final RebaseChange rebaseChange;
 
   private AccountLoader accountLoader;
   private FixInput fix;
@@ -163,7 +165,8 @@
       ChangeMessagesUtil cmUtil,
       PatchLineCommentsUtil plcUtil,
       Provider<ConsistencyChecker> checkerProvider,
-      ActionJson actionJson) {
+      ActionJson actionJson,
+      RebaseChange rebaseChange) {
     this.db = db;
     this.labelNormalizer = ln;
     this.userProvider = user;
@@ -180,6 +183,7 @@
     this.plcUtil = plcUtil;
     this.checkerProvider = checkerProvider;
     this.actionJson = actionJson;
+    this.rebaseChange = rebaseChange;
     options = EnumSet.noneOf(ListChangesOption.class);
   }
 
@@ -890,7 +894,7 @@
         && userProvider.get().isIdentifiedUser()) {
 
       actionJson.addRevisionActions(out,
-          new RevisionResource(new ChangeResource(ctl), in));
+          new RevisionResource(new ChangeResource(ctl, rebaseChange), in));
     }
 
     if (has(DRAFT_COMMENTS)
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
index 1555cdd..b3757b7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeResource.java
@@ -23,6 +23,7 @@
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.changedetail.RebaseChange;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.ProjectState;
@@ -36,13 +37,16 @@
       new TypeLiteral<RestView<ChangeResource>>() {};
 
   private final ChangeControl control;
+  private final RebaseChange rebaseChange;
 
-  public ChangeResource(ChangeControl control) {
+  public ChangeResource(ChangeControl control, RebaseChange rebaseChange) {
     this.control = control;
+    this.rebaseChange = rebaseChange;
   }
 
   protected ChangeResource(ChangeResource copy) {
     this.control = copy.control;
+    this.rebaseChange = copy.rebaseChange;
   }
 
   public ChangeControl getControl() {
@@ -65,7 +69,8 @@
       .putInt(getChange().getRowVersion())
       .putInt(user.isIdentifiedUser()
           ? ((IdentifiedUser) user).getAccountId().get()
-          : 0);
+          : 0)
+      .putBoolean(rebaseChange != null && rebaseChange.canRebase(this));
     byte[] buf = new byte[20];
     ObjectId noteId;
     try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
index 1648a5d..42f16a3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangesCollection.java
@@ -26,6 +26,7 @@
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.changedetail.RebaseChange;
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
@@ -49,6 +50,7 @@
   private final ChangeUtil changeUtil;
   private final CreateChange createChange;
   private final ChangeIndexer changeIndexer;
+  private final RebaseChange rebaseChange;
 
   @Inject
   ChangesCollection(
@@ -58,7 +60,8 @@
       DynamicMap<RestView<ChangeResource>> views,
       ChangeUtil changeUtil,
       CreateChange createChange,
-      ChangeIndexer changeIndexer) {
+      ChangeIndexer changeIndexer,
+      RebaseChange rebaseChange) {
     this.user = user;
     this.changeControlFactory = changeControlFactory;
     this.queryFactory = queryFactory;
@@ -66,6 +69,7 @@
     this.changeUtil = changeUtil;
     this.createChange = createChange;
     this.changeIndexer = changeIndexer;
+    this.rebaseChange = rebaseChange;
   }
 
   @Override
@@ -102,7 +106,7 @@
     } catch (NoSuchChangeException e) {
       throw new ResourceNotFoundException(id);
     }
-    return new ChangeResource(control);
+    return new ChangeResource(control, rebaseChange);
   }
 
   public ChangeResource parse(Change.Id id)
@@ -112,7 +116,7 @@
   }
 
   public ChangeResource parse(ChangeControl control) {
-    return new ChangeResource(control);
+    return new ChangeResource(control, rebaseChange);
   }
 
   @SuppressWarnings("unchecked")
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java
index cd57a3e..9818d1b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetRevisionActions.java
@@ -21,6 +21,7 @@
 import com.google.gerrit.extensions.restapi.ETagView;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.changedetail.RebaseChange;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
@@ -39,14 +40,17 @@
   private final ActionJson delegate;
   private final Provider<InternalChangeQuery> queryProvider;
   private final Config config;
+  private final RebaseChange rebaseChange;
   @Inject
   GetRevisionActions(
       ActionJson delegate,
       Provider<InternalChangeQuery> queryProvider,
-      @GerritServerConfig Config config) {
+      @GerritServerConfig Config config,
+      RebaseChange rebaseChange) {
     this.delegate = delegate;
     this.queryProvider = queryProvider;
     this.config = config;
+    this.rebaseChange = rebaseChange;
   }
 
   @Override
@@ -65,7 +69,7 @@
     CurrentUser user = rsrc.getControl().getCurrentUser();
     try {
       for (ChangeData c : queryProvider.get().byTopicOpen(topic)) {
-        new ChangeResource(c.changeControl()).prepareETag(h, user);
+        new ChangeResource(c.changeControl(), rebaseChange).prepareETag(h, user);
       }
     } catch (OrmException e){
       throw new OrmRuntimeException(e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
index f2bda5b8..d330ec3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java
@@ -213,13 +213,19 @@
 
   @Override
   public UiAction.Description getDescription(RevisionResource resource) {
-    return new UiAction.Description()
+    UiAction.Description descr = new UiAction.Description()
       .setLabel("Rebase")
       .setTitle("Rebase onto tip of branch or parent change")
       .setVisible(resource.getChange().getStatus().isOpen()
           && resource.isCurrent()
           && resource.getControl().canRebase()
           && hasOneParent(resource.getPatchSet().getId()));
+    if (descr.isVisible()) {
+      // Disable the rebase button in the RebaseDialog if
+      // the change cannot be rebased.
+      descr.setEnabled(rebaseChange.get().canRebase(resource));
+    }
+    return descr;
   }
 
   public static class CurrentRevision implements
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
index 92f3c00..67e70c1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
@@ -22,11 +22,13 @@
 import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetAncestor;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.change.ChangeResource;
 import com.google.gerrit.server.change.PatchSetInserter;
 import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
 import com.google.gerrit.server.change.RevisionResource;
@@ -356,10 +358,21 @@
     return objectId;
   }
 
+  public boolean canRebase(ChangeResource r) {
+    Change c = r.getChange();
+    return canRebase(c.getProject(), c.currentPatchSetId(), c.getDest());
+  }
+
   public boolean canRebase(RevisionResource r) {
+    return canRebase(r.getChange().getProject(),
+        r.getPatchSet().getId(), r.getChange().getDest());
+  }
+
+  public boolean canRebase(Project.NameKey project,
+      PatchSet.Id patchSetId, Branch.NameKey branch) {
     Repository git;
     try {
-      git = gitManager.openRepository(r.getChange().getProject());
+      git = gitManager.openRepository(project);
     } catch (RepositoryNotFoundException err) {
       return false;
     } catch (IOException err) {
@@ -367,9 +380,9 @@
     }
     try {
       findBaseRevision(
-          r.getPatchSet().getId(),
+          patchSetId,
           db.get(),
-          r.getChange().getDest(),
+          branch,
           git,
           null,
           null,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEdit.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEdit.java
index f646ea5..b7bb360 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEdit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEdit.java
@@ -18,6 +18,7 @@
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.server.IdentifiedUser;
 
@@ -71,7 +72,7 @@
   }
 
   public String getRefName() {
-    return ChangeEditUtil.editRefName(user.getAccountId(), change.getId(),
+    return RefNames.refsEdit(user.getAccountId(), change.getId(),
         basePatchSet.getId());
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
index 7aa70db..70107c2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
@@ -16,8 +16,6 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-import static com.google.gerrit.server.edit.ChangeEditUtil.editRefName;
-import static com.google.gerrit.server.edit.ChangeEditUtil.editRefPrefix;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 
 import com.google.common.base.Strings;
@@ -30,6 +28,7 @@
 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.client.RefNames;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
@@ -116,7 +115,7 @@
     }
 
     IdentifiedUser me = (IdentifiedUser) currentUser.get();
-    String refPrefix = editRefPrefix(me.getAccountId(), change.getId());
+    String refPrefix = RefNames.refsEditPrefix(me.getAccountId(), change.getId());
 
     try (Repository repo = gitManager.openRepository(change.getProject())) {
       Map<String, Ref> refs = repo.getRefDatabase().getRefs(refPrefix);
@@ -126,7 +125,7 @@
 
       try (RevWalk rw = new RevWalk(repo)) {
         ObjectId revision = ObjectId.fromString(ps.getRevision().get());
-        String editRefName = editRefName(me.getAccountId(), change.getId(),
+        String editRefName = RefNames.refsEdit(me.getAccountId(), change.getId(),
             ps.getId());
         return update(repo, me, editRefName, rw, ObjectId.zeroId(), revision);
       }
@@ -152,7 +151,7 @@
 
     Change change = edit.getChange();
     IdentifiedUser me = (IdentifiedUser) currentUser.get();
-    String refName = editRefName(me.getAccountId(), change.getId(),
+    String refName = RefNames.refsEdit(me.getAccountId(), change.getId(),
         current.getId());
     try (Repository repo = gitManager.openRepository(change.getProject());
         RevWalk rw = new RevWalk(repo);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
index f24340f..79c6593 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gerrit.reviewdb.client.PatchSet;
@@ -110,7 +109,7 @@
   public Optional<ChangeEdit> byChange(Change change, IdentifiedUser user)
       throws IOException {
     try (Repository repo = gitManager.openRepository(change.getProject())) {
-      String editRefPrefix = editRefPrefix(user.getAccountId(), change.getId());
+      String editRefPrefix = RefNames.refsEditPrefix(user.getAccountId(), change.getId());
       Map<String, Ref> refs = repo.getRefDatabase().getRefs(editRefPrefix);
       if (refs.isEmpty()) {
         return Optional.absent();
@@ -190,34 +189,6 @@
     }
   }
 
-  /**
-   * Returns reference for this change edit with sharded user and change number:
-   * refs/users/UU/UUUU/edit-CCCC/P.
-   *
-   * @param accountId accout id
-   * @param changeId change number
-   * @param psId patch set number
-   * @return reference for this change edit
-   */
-  public static String editRefName(Account.Id accountId, Change.Id changeId,
-      PatchSet.Id psId) {
-    return editRefPrefix(accountId, changeId) + psId.get();
-  }
-
-  /**
-   * Returns reference prefix for this change edit with sharded user and
-   * change number: refs/users/UU/UUUU/edit-CCCC/.
-   *
-   * @param accountId accout id
-   * @param changeId change number
-   * @return reference prefix for this change edit
-   */
-  static String editRefPrefix(Account.Id accountId, Change.Id changeId) {
-    return String.format("%s/edit-%d/",
-        RefNames.refsUsers(accountId),
-        changeId.get());
-  }
-
   private RevCommit squashEdit(RevWalk rw, ObjectInserter inserter,
       RevCommit edit, PatchSet basePatchSet)
       throws IOException, ResourceConflictException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java
index 4d26e13..908fd0a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventTypes.java
@@ -40,15 +40,10 @@
   /** Register an event.
    *
    *  @param event The event to register.
-   *  @throws IllegalArgumentException if the event's type is already
    *  registered.
    **/
   public static void registerClass(Event event) {
     String type = event.getType();
-    if (typesByString.containsKey(type)) {
-      throw new IllegalArgumentException(
-          "Event type already registered: " + type);
-    }
     typesByString.put(type, event.getClass());
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
index d354801..0793d10 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommits.java
@@ -2007,7 +2007,7 @@
       cmd = new ReceiveCommand(
           ObjectId.zeroId(),
           newCommit,
-          ChangeEditUtil.editRefName(
+          RefNames.refsEdit(
               currentUser.getAccountId(),
               change.getId(),
               newPatchSet.getId()));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
index 9370ee6..cb94063 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateBranch.java
@@ -14,8 +14,7 @@
 
 package com.google.gerrit.server.project;
 
-import static org.eclipse.jgit.lib.RefDatabase.ALL;
-
+import com.google.common.collect.Iterables;
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.common.errors.InvalidRevisionException;
 import com.google.gerrit.extensions.api.projects.BranchInfo;
@@ -43,6 +42,7 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefDatabase;
 import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.ObjectWalk;
@@ -53,6 +53,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.util.Collections;
 
 public class CreateBranch implements RestModifyView<ProjectResource, Input> {
   private static final Logger log = LoggerFactory.getLogger(CreateBranch.class);
@@ -224,7 +225,15 @@
       } catch (IncorrectObjectTypeException err) {
         throw new InvalidRevisionException();
       }
-      for (final Ref r : repo.getRefDatabase().getRefs(ALL).values()) {
+      RefDatabase refDb = repo.getRefDatabase();
+      Iterable<Ref> refs = Iterables.concat(
+          refDb.getRefs(Constants.R_HEADS).values(),
+          refDb.getRefs(Constants.R_TAGS).values());
+      Ref rc = refDb.getRef(RefNames.REFS_CONFIG);
+      if (rc != null) {
+        refs = Iterables.concat(refs, Collections.singleton(rc));
+      }
+      for (Ref r : refs) {
         try {
           rw.markUninteresting(rw.parseAny(r.getObjectId()));
         } catch (MissingObjectException err) {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
index 721992f..0d81ee2 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/change/CommentsTest.java
@@ -299,8 +299,8 @@
     update.commit();
 
     ChangeControl ctl = stubChangeControl(change);
-    revRes1 = new RevisionResource(new ChangeResource(ctl), ps1);
-    revRes2 = new RevisionResource(new ChangeResource(ctl), ps2);
+    revRes1 = new RevisionResource(new ChangeResource(ctl, null), ps1);
+    revRes2 = new RevisionResource(new ChangeResource(ctl, null), ps2);
   }
 
   private ChangeControl stubChangeControl(Change c) throws OrmException {
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/edit/ChangeEditTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/edit/ChangeEditTest.java
index 426fb93..8c963bd 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/edit/ChangeEditTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/edit/ChangeEditTest.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.RefNames;
 
 import org.junit.Test;
 
@@ -28,7 +29,7 @@
     Account.Id accountId = new Account.Id(1000042);
     Change.Id changeId = new Change.Id(56414);
     PatchSet.Id psId = new PatchSet.Id(changeId, 50);
-    String refName = ChangeEditUtil.editRefName(accountId, changeId, psId);
+    String refName = RefNames.refsEdit(accountId, changeId, psId);
     assertEquals("refs/users/42/1000042/edit-56414/50", refName);
   }
 }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/events/EventTypesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/events/EventTypesTest.java
index 1073522..7eed35f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/events/EventTypesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/events/EventTypesTest.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.server.events;
 
 import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
@@ -26,12 +25,6 @@
     }
   }
 
-  public static class TestEvent2 extends Event {
-    public TestEvent2() {
-      super("test-event"); // Intentionally same as in TestEvent
-    }
-  }
-
   public static class AnotherTestEvent extends Event {
     public AnotherTestEvent() {
       super("another-test-event");
@@ -45,20 +38,6 @@
     assertThat(EventTypes.getClass("test-event")).isEqualTo(TestEvent.class);
     assertThat(EventTypes.getClass("another-test-event"))
       .isEqualTo(AnotherTestEvent.class);
-
-    try {
-      EventTypes.registerClass(new TestEvent());
-      fail("Expected IllegalArgumentException");
-    } catch (IllegalArgumentException e) {
-      assertThat(EventTypes.getClass("test-event")).isEqualTo(TestEvent.class);
-    }
-
-    try {
-      EventTypes.registerClass(new TestEvent2());
-      fail("Expected IllegalArgumentException");
-    } catch (IllegalArgumentException e) {
-      assertThat(EventTypes.getClass("test-event")).isEqualTo(TestEvent.class);
-    }
   }
 
   @Test