Merge 'v2.3.1'

* v2.3.1:
  Release notes for 2.3.1
  Release notes for 2.2.2.2
  Fix permissions bug caused by directly inheriting from All-Projects

Conflicts:
	gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java

Change-Id: Ic0282b03cd4736fc33558ecca02dd5e34686ea4a
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index d2078ab..8d89fa2 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -697,6 +697,21 @@
 is already restricted to the correct set of users.
 
 
+[[category_rebase]]
+Rebase
+~~~~~~
+
+This category permits users to rebase changes via the web UI by pushing
+the `Rebase Change` button.
+
+The change owner and submitters can always rebase changes in the web UI
+(even without having the `Rebase` access right assigned).
+
+Users without this access right who are able to upload new patch sets
+can still do the rebase locally and upload the rebased commit as a new
+patch set.
+
+
 [[category_submit]]
 Submit
 ~~~~~~
diff --git a/Documentation/cmd-ls-projects.txt b/Documentation/cmd-ls-projects.txt
index b6e67c4..7782aa8 100644
--- a/Documentation/cmd-ls-projects.txt
+++ b/Documentation/cmd-ls-projects.txt
@@ -57,6 +57,12 @@
 --type::
 	Display only projects of the specified type.  If not
 	specified, defaults to `code`. Supported types:
++
+--
+`code`:: Any project likely to contain user files.
+`permissions`:: Projects created with the `--permissions-only` flag.
+`all`:: Any type of project.
+--
 
 --all::
 	Display all projects that are accessible by the calling user
@@ -65,12 +71,6 @@
 	are owned by the calling user account (even if for these projects
 	the 'READ' access right is not assigned to the calling user
 	account).
-+
---
-`code`:: Any project likely to contain user files.
-`permissions`:: Projects created with the `--permissions-only` flag.
-`all`:: Any type of project.
---
 
 EXAMPLES
 --------
diff --git a/Documentation/cmd-query.txt b/Documentation/cmd-query.txt
index 1bd4862..253bed1 100644
--- a/Documentation/cmd-query.txt
+++ b/Documentation/cmd-query.txt
@@ -15,6 +15,7 @@
   [--files]
   [--comments]
   [--commit-message]
+  [--dependencies]
   [--]
   <query>
   [limit:<n>]
@@ -75,6 +76,10 @@
 --commit-message::
 	Include the full commit message in the change description.
 
+--dependencies::
+	Show information about patch sets which depend on, or are needed by,
+	each patch set.
+
 limit:<n>::
 	Maximum number of results to return.  This is actually a
 	query operator, and not a command line option.	If more
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 9fa7ee1..535aaa8 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -24,6 +24,27 @@
   diskbuffer = 10 m
 ----
 
+[[accounts]]Section accounts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+[[accounts.visibility]]accounts.visibility::
++
+Controls visibility of other users' dashboard pages and
+completion suggestions to web users.
++
+If `ALL`, all users are visible to all other users, even
+anonymous users.
++
+If `SAME_GROUP`, only users who are also members of a group the
+current user is a member of are visible.
++
+If `VISIBLE_GROUP`, only users who are members of at least one group
+that is visible to the current user are visible.
++
+If `NONE`, no users other than the current user are visible.
++
+Default is `ALL`.
+
 [[addreviewer]]Section addreviewer
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -826,6 +847,15 @@
 Default on JGit is false. Although potentially slower, it yields
 much more predictable behavior.
 
+[[core.asyncLoggingBufferSize]]core.asyncLoggingBufferSize::
++
+Size of the buffer to store logging events for asynchronous logging.
+Putting a larger value can protect threads from stalling when the
+AsyncAppender threads are not fast enough to consume the logging events
+from the buffer. It also protects from loosing log entries in this case.
++
+Default is 64 entries.
+
 [[database]]Section database
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1086,7 +1116,7 @@
 +
 Valid values are `gitweb`, `cgit`, `disabled` or `custom`.
 
-[[gitweb.type]]gitweb.revision::
+[[gitweb.revision]]gitweb.revision::
 +
 Optional pattern to use for constructing the gitweb URL when pointing
 at a specific commit when `custom` is used above.
@@ -1094,14 +1124,14 @@
 Valid replacements are `${project}` for the project name in Gerrit
 and `${commit}` for the SHA1 hash for the commit.
 
-[[gitweb.type]]gitweb.project::
+[[gitweb.project]]gitweb.project::
 +
 Optional pattern to use for constructing the gitweb URL when pointing
 at a specific project when `custom` is used above.
 +
 Valid replacements are `${project}` for the project name in Gerrit.
 
-[[gitweb.type]]gitweb.branch::
+[[gitweb.branch]]gitweb.branch::
 +
 Optional pattern to use for constructing the gitweb URL when pointing
 at a specific branch when `custom` is used above.
@@ -1109,6 +1139,16 @@
 Valid replacements are `${project}` for the project name in Gerrit
 and `${branch}` for the name of the branch.
 
+[[gitweb.filehistory]]gitweb.filehistory::
++
+Optional pattern to use for constructing the gitweb URL when pointing
+at the history of a file in a specific branch when `custom` is used
+above.
++
+Valid replacements are `${project}` for the project name in Gerrit,
+`${file}` for the file name and `${branch}` for the name of the
+branch.
+
 [[gitweb.linkname]]gitweb.linkname::
 +
 Optional setting for modifying the link name presented to the user
@@ -1654,7 +1694,8 @@
 This section is used to set who can execute the 'receive-pack' and
 to limit the maximum Git object size that 'receive-pack' will accept.
 'receive-pack' is what runs on the server during a user's push or
-repo upload command.
+repo upload command. It also contains some advanced options for tuning the
+behavior of Gerrit's 'receive-pack' mechanism.
 
 ----
 [receive]
@@ -1685,6 +1726,24 @@
 +
 Common unit suffixes of 'k', 'm', or 'g' are supported.
 
+[[receive.threadPoolSize]]receive.threadPoolSize::
++
+Maximum size of the thread pool in which the change data in received packs is
+processed.
++
+Defaults to the number of available CPUs according to the Java runtime.
+
+[[receive.timeout]]receive.timeout::
++
+Overall timeout on the time taken to process the change data in
+received packs. Only includes the time processing Gerrit changes
+and updating references, not the time to index the pack. Values can
+be specified using standard time unit abbreviations ('ms', 'sec',
+'min', etc.).
++
+Default is 2 minutes. If no unit is specified, millisconds
+is assumed.
+
 
 [[repository]]Section repository
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2013,19 +2072,20 @@
 
 [[suggest.accounts]]suggest.accounts::
 +
-If `ALL`, all matching user accounts will be offered as
-completion suggestions when adding a reviewer to a change,
-or a user to a group.
+If `true`, visible user accounts (according to the value of
+`accounts.visibility`) will be offered as completion suggestions
+when adding a reviewer to a change, or a user to a group.
 +
-If `SAME_GROUP`, only users who are also members of a group the
-current user is a member of will be offered.
+If `false`, account suggestion is disabled.
 +
-If `VISIBLE_GROUP`, only users who are members of at least one group
-that is visible to the current user will be offered.
+Older configurations may also have one of the `accounts.visibility`
+values for this field, including `OFF` as a synonym for `NONE`. If
+`accounts.visibility` is also set, that value overrides this one;
+otherwise, this value applies to both `suggest.accounts` and
+`accounts.visibility`.
 +
-If `OFF`, no account suggestions are given.
-+
-Default is `ALL`.
+New configurations should prefer the boolean value for this field
+and an enum value for `accounts.visibility`.
 
 [[theme]] Section theme
 ~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/dev-eclipse.txt b/Documentation/dev-eclipse.txt
index b37223c..e239a63 100644
--- a/Documentation/dev-eclipse.txt
+++ b/Documentation/dev-eclipse.txt
@@ -13,7 +13,7 @@
 
 Install the Maven Integration plugins:
 
-http://m2eclipse.codehaus.org/[m2eclipse]
+http://www.eclipse.org/m2e/download/[m2eclipse]
 
 
 [[Formatting]]
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 6a6ce16..3aafe8c 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -109,12 +109,9 @@
 [[branch]]
 branch:'BRANCH'::
 +
-Changes for 'BRANCH'.  The branch name is the short name shown
-in the web interface, without the traditional 'refs/heads/'
-prefix.  This operator is a shorthand for 'refs:'.  Searching for
-'branch:master' really means 'ref:refs/heads/master', and searching
-for 'branch:refs/heads/master' is the same as searching for
-'ref:refs/heads/refs/heads/master'.
+Changes for 'BRANCH'.  The branch name is either the short name shown
+in the web interface or the full name of the destination branch with
+the traditional 'refs/heads/' prefix.
 +
 If 'BRANCH' starts with `^` it matches branch names by regular
 expression patterns.  The
diff --git a/Documentation/user-upload.txt b/Documentation/user-upload.txt
index 2cd959b..8e05e72 100644
--- a/Documentation/user-upload.txt
+++ b/Documentation/user-upload.txt
@@ -342,17 +342,17 @@
 ~~~~~~~~~~~~~~~
 
 To replace changes, ensure Change-Id lines were created in the
-commit messages, and just use `repo upload` without the `--replace`
-command line flag.  Gerrit Code Review will automatically match
-the commits back to their original changes by taking advantage of
-their Change-Id lines.
+commit messages, and just use `repo upload`.
+Gerrit Code Review will automatically match the commits back to
+their original changes by taking advantage of their Change-Id lines.
 
 If Change-Id lines are not present in the commit messages, consider
 amending the message and copying the line from the change's page
 on the web.
 
 If Change-Id lines are not available, then the user must use the much
-more manual mapping technique offered by `repo upload --replace`.
+more <<manual_replacement_mapping,manual mapping technique>> offered
+by using `git push` to a specific `refs/changes/change#` reference.
 
 For more about Change-Ids, see link:user-changeid.html[Change-Id Lines].
 
diff --git a/ReleaseNotes/ReleaseNotes-2.4.1.txt b/ReleaseNotes/ReleaseNotes-2.4.1.txt
new file mode 100644
index 0000000..15dc1d3
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.4.1.txt
@@ -0,0 +1,55 @@
+Release notes for Gerrit 2.4.1
+==============================
+
+Gerrit 2.4.1 is now available:
+
+link:http://code.google.com/p/gerrit/downloads/detail?name=gerrit-2.4.1.war[http://code.google.com/p/gerrit/downloads/detail?name=gerrit-2.4.1.war]
+
+
+There are no schema changes from 2.4.  However, if upgrading from
+anything but 2.4, follow the upgrade procedure in the 2.4
+link:ReleaseNotes-2.4.html[ReleaseNotes].
+
+
+Bug Fixes
+---------
+* Catch all exceptions when async emailing
++
+This fixes email notification issues reported
+link:https://groups.google.com/group/repo-discuss/browse_thread/thread/dd157ebc55b962ef/652822d6fbe61e71[here].
+
+* Fixed cleanup of propagated SshScopes
++
+This improves error reporting in case of email notification errors.
+
+* issue 1394 Fix lookup of the 'Commit Message' file in patch set
++
+There is an assumption that the commit message is always first in the list of
+files of a patch set. However, there was another place in Gerrit code, which
+did binary search through the list of the files, without taking this assumption
+into account. In case when a patch set contained a file which lexicographically
+sorted before '/COMMIT_MSG' (like '.gitignore' for example) it could have
+happened that the commit message was not found and, as a side effect, it wasn't
+possible to review it.
+
+* issue 1162 Fix deadlock on destroy of CommandFactoryProvider
+
+* Honor the sendmail.smtpUser from gerrit.config on upgrade
++
+If sendmail.smtpUser was not present in the gerrit.config then don't set it in
+site upgrade.
+
+* issue 1420 Forge committer bypassed
++
+It was possible to forge committer even without having permission for that.
+This was a regression from 2.3.
+
+* Make sure the "Object too large..." error message is printed when an object
+larger than receive.maxObjectSizeLimit is rejected by Gerrit
+
+* Display proper error if file diff fails because content is too large
+
+* Get around a log4j bug that causes AsyncAppender-Dispatcher thread to die and
+block other threads
+** Make async logging buffer size configurable
+** Make logging events discardable, prevent NPE in AsyncAppender-Dispatcher thread
diff --git a/ReleaseNotes/ReleaseNotes-2.4.txt b/ReleaseNotes/ReleaseNotes-2.4.txt
new file mode 100644
index 0000000..82f3ed4
--- /dev/null
+++ b/ReleaseNotes/ReleaseNotes-2.4.txt
@@ -0,0 +1,257 @@
+Release notes for Gerrit 2.4
+============================
+
+Gerrit 2.4 is now available:
+
+link:http://code.google.com/p/gerrit/downloads/detail?name=gerrit-2.4.war[http://code.google.com/p/gerrit/downloads/detail?name=gerrit-2.4.war]
+
+Schema Change
+-------------
+*WARNING:* This release contains schema changes.  To upgrade:
+----
+  java -jar gerrit.war init -d site_path
+----
+
+*WARNING:* Upgrading to 2.4.x requires the server be first upgraded to 2.1.7 (or
+a later 2.1.x version), and then to 2.4.x.  If you are upgrading from 2.2.x.x or
+newer, you may ignore this warning and upgrade directly to 2.4.x.
+
+New Features
+------------
+
+Security
+~~~~~~~~
+
+* Restrict visibility to arbitrary user dashboards
++
+Administrators have some expectation when using the 'suggest.accounts'
+visibility restriction feature that users cannot get the names or
+email addresses for arbitrary accounts. In fact, because account IDs
+are sequential, it would be easy for an adversary to get personal
+information of all users on the server by requesting every user's
+dashboard.
++
+This includes changing the meaning of the 'suggest.accounts' config
+option to be a boolean indicating whether account suggestion should
+happen at all, which is now orthogonal to the account visibility
+restriction policy. We still recognize the old values for
+'suggest.accounts', with the slight behavior change that
+'suggest.accounts=OFF' now means that users cannot access the dashboards
+of any other users. Administrators who do not want this behavior can
+update their configuration.
+
+* Indicate that 'not found' may actually be a permission issue
+
+Web
+~~~
+
+* Add user preference to mark files reviewed automatically or manually
++
+Add a checkbox to the preferences header on the diff
+screen which allows a user to specify whether they
+want manual-reviewing enabled or disabled.  Previously,
+every file was auto marked reviewed when a user first
+displayed it.  The new manual mode prevents this auto
+marking and only marks a file reviewed when the user
+explicitly clicks on the reviewed checkbox.
+
+* Use 'Auto Merge' for merge commit's base comparison
++
+When reviewing a merge commit, the old wording in the version history dropdown
+of 'Base' doesn't really match Gerrit's behavior.  Updating this to use
+'Auto Merge' as suggested by Shawn Pearce on IRC.
+
+* issue 1035 Add rebase button to the change screen
++
+This change adds a rebase button along with the rest of
+the action buttons in the change page. When pressing the
+button, the most recent patch set will be rebased onto
+the tip of the destination branch or the latest patchset
+of the change we depend upon. A new patch set containing
+the rebased commit will be produced and added to the
+change.
++
+Rebasing of a change in web UI is restricted to change owner, submitter or
+those with the (new) 'rebase' permission.
+
+* Add a new permission 'rebase' to permit rebasing changes in the web UI
+
+* Make a user's dashboard visible if any of the changes are visible to the
+current user.
+
+* Change 'Loading ...' to say 'Working ...' as, often, there is more going on
+than just loading a response.
+
+Performance
+~~~~~~~~~~~
+
+* Asynchronously send email so it does not block the UI
+* Optimize queries for open/merged changes by project + branch
+
+Git
+~~~
+
+* Implement a multi-sub-task progress monitor for ReceiveCommits
+
+* Close corresponding change when pushing to 'refs/heads/*'
++
+Gerrit would not close the open changes with matching change-ids,
+when the user pushes commits directly to 'refs/heads/*'.
++
+This issue could be triggered for two reasons:
+
+. It is triggered when Gerrit detects no changes between the
+pushed commits and the current patchset on the open changes. This
+patch make sure that the matching open change is always closed when
+pushing to 'refs/heads/*', even if no visible changes is detected.
+
+. The same commit exists on another branch than the destination
+branch. This could trick gerrit into just "re-closing" the wrong
+change.
+
+* Run ReceiveCommits in a shared thread pool
++
+Since the work to ReceiveCommits may take a long, potentially unbounded
+amount of time, we would like to have it run in the background so it
+can be monitored for timeouts and cancelled, and have stalls reported
+to the user from the main thread.
+
+Search
+~~~~~~
+
+* Add the '--dependencies' option to the 'query' command.
++
+This option includes information about patch sets which depend on, or are
+needed by, each patch set.
+
+* Branch Operator: Support full branch names
++
+The search operator for branches required the provided value to be the
+short branch name that is shown in the web interface (without the
+'refs/heads/' prefix). Change the branch operator so that it also
+supports full branch names as value.
++
+It is intuive that searching with 'branch:master' and searching with
+'branch:refs/for/master' deliver the same result. So far
+'branch:refs/for/master' was the same as searching with
+'refs:refs/heads/refs/heads/master' which is unexpected for most users.
+
+* Add comment inclusion via '&comments=true' over HTTP
++
+With this change, we can fetch the comments on a patchset by sending a
+request to 'https://site/query?comments=true'
+
+Access Rights
+~~~~~~~~~~~~~
+
+* Added the 'emailReviewers' as a global capability.
++
+This replaces the 'emailOnlyAuthors' flag of account groups.
+
+Dev
+~~~
+
+* issue 1272 Add scripts to create release notes from git log
++
+These script generates a list of commits from git log between two given commits
+and outputs the asciidoc format containting list of commits subject and body.
+
+* Update URL for m2eclipse
++
+The project is now under the Eclipse Foundation umbrella.
+
+* Add missing ignore for m2e prefs in gerrit-ehcache
+
+* Add '--issues' and '--issue_numbers' options to the 'gitlog2asciidoc.py'
+
+Miscellaneous
+~~~~~~~~~~~~~
+
+* Remove perl from 'commit-msg' hook
++
+Removing perl from the commit-msg hook reduces the dependencies
+gerrit imposes on its users.
+
+* updating contrib 'trivial_rebase.py' for 2.2.2.1
+
+Upgrades
+--------
+
+* Updated to Guice 3.0.
+* Updated to gwtorm 1.4.
+* Update JGit to 1.3.0.201202151440-r.75-gff13648
+* Update to gwtjsonrpc 1.3
++
+The change also shrinks the built WAR from 38M to 23M
+by excluding the now unnecessary GWT server code.
+
+Bug Fixes
+---------
+
+* issue 904 Users who starred a change should receive all the emails about a change.
+
+* Fix: 'Diff All Side-by-Side' and 'Diff All Unified' buttons
++
+When pressing the 'Diff All Side-by-Side' or
+'Diff All Unified' button on the change screen, the
+opened browser windows/tabs shows diffs using "Base"
+as old version and the latest one as active patch set,
+regardless what has been set using the
+"Old Version History:" drop down menu and what is
+currently active patch set.
++
+Gerrit doesn't remember the base patch set in the URL,
+making it impossible to copy-and-paste the URL to
+co-workers to show them the same diff a user is
+looking at.
++
+This change fixes this behavior to make sure that
+the opened new browser windows shows diffs using the
+correct old patch set and active patch set.
+
+* Fix NPEs looking up groups by UUID in GroupCache
+
+* Fix default 'receive.timeout'
++
+This should be in milliseconds, not seconds. Set the default to be
+2 minutes in milliseconds and update the documentation to reflect
+that milliseconds are the default unit of time used here.
+
+* Fix 'development_become_any_account' redirects
+* issue 1299 Allow configuration of optional pattern for gitweb file history link
+* Use servlet context path during logout
+
+* issue 1353 Fix case check for project name so that symlinks work again
+* Fix merging of access sections
+* Fix inconsistent behaviour when replicating refs/meta/config
+* Fix duplicated results on status:open project:P branch:B
+
+Documentation
+-------------
+
+Access Rights
+~~~~~~~~~~~~~
+* Capabilities introduced
+* Kill and priority capabilities
+* Administrate server capability
+* Create account capability
+* Create group and project capability
+* Flush caches capability
+* Capability replication and view caches
+* Capability view conn. & queue
+* Example roles introduced
+* Developer example role
+* CI system example role
+* Integrator example role
+* Project owner example role
+* Administrator example role
+
+Miscellaneous
+~~~~~~~~~~~~~
+* User upload documentation: Replace changes
+* Add visible-to-all flag in the documentation for cmd-create-group
+* Add a contributing guideline for annotations
+* Add missing header for suggest.accounts documentation
+* Fix anchors for description of gitweb config parameters
+* Add missing section name to config-gerrit documentation
+* Fix documentation of ls-projects
diff --git a/ReleaseNotes/index.txt b/ReleaseNotes/index.txt
index 8abda42..07a2be8 100644
--- a/ReleaseNotes/index.txt
+++ b/ReleaseNotes/index.txt
@@ -1,6 +1,12 @@
 Gerrit Code Review - Release Notes
 ==================================
 
+[[2_4]]
+Version 2.4.x
+-------------
+* link:ReleaseNotes-2.4.1.html[2.4.1]
+* link:ReleaseNotes-2.4.html[2.4]
+
 [[2_3]]
 Version 2.3.x
 -------------
diff --git a/contrib/trivial_rebase.py b/contrib/trivial_rebase.py
index a5123a3..a514b4c 100755
--- a/contrib/trivial_rebase.py
+++ b/contrib/trivial_rebase.py
@@ -93,8 +93,8 @@
 
   Returns a list of approval dicts"""
   sql_query = ("\"SELECT value,account_id,category_id FROM patch_set_approvals "
-               "WHERE change_id = (SELECT change_id FROM changes WHERE "
-               "patch_set_id = %s AND change_key = \'%s\') AND value <> 0\""
+               "WHERE patch_set_id = %s AND change_id = (SELECT change_id FROM "
+               "changes WHERE change_key = \'%s\') AND value <> 0\""
                % ((patchset - 1), changeId))
   gsql_out = GsqlQuery(sql_query, server, port)
   approvals = []
diff --git a/gerrit-antlr/pom.xml b/gerrit-antlr/pom.xml
index efcc190..aa0d7fd 100644
--- a/gerrit-antlr/pom.xml
+++ b/gerrit-antlr/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-antlr</artifactId>
diff --git a/gerrit-common/pom.xml b/gerrit-common/pom.xml
index b4395be..e7933ea 100644
--- a/gerrit-common/pom.xml
+++ b/gerrit-common/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-common</artifactId>
diff --git a/gerrit-common/src/main/java/com/google/gerrit/Common.gwt.xml b/gerrit-common/src/main/java/com/google/gerrit/Common.gwt.xml
index 171ae8a..468b477 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/Common.gwt.xml
+++ b/gerrit-common/src/main/java/com/google/gerrit/Common.gwt.xml
@@ -14,7 +14,7 @@
  limitations under the License.
 -->
 <module>
-  <inherits name='com.google.gerrit.ReviewDB' />
+  <inherits name='com.google.gerrit.reviewdb.ReviewDB' />
   <inherits name='com.google.gwtjsonrpc.GWTJSONRPC'/>
   <source path='common' />
 </module>
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
index 23bef63..71df400 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/PageLinks.java
@@ -16,11 +16,11 @@
 
 import com.google.gerrit.common.data.AccountInfo;
 import com.google.gerrit.common.data.ChangeInfo;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Change.Status;
+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.Project;
+import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gwtorm.client.KeyUtil;
 
 public class PageLinks {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdProviderPattern.java b/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdProviderPattern.java
index 731d765..c80d3eb 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdProviderPattern.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdProviderPattern.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.auth.openid;
 
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 
 public class OpenIdProviderPattern {
   public static OpenIdProviderPattern create(String pattern) {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdService.java b/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdService.java
index 0a24cd5..0deba34 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/auth/openid/OpenIdService.java
@@ -15,11 +15,11 @@
 package com.google.gerrit.common.auth.openid;
 
 import com.google.gerrit.common.auth.SignInMode;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.AllowCrossSiteRequest;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.AllowCrossSiteRequest;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 @RpcImpl(version = Version.V2_0)
 public interface OpenIdService extends RemoteJsonService {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/LoginResult.java b/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/LoginResult.java
index 4a9ab66..e89cdd2 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/LoginResult.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/LoginResult.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.auth.userpass;
 
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 
 public class LoginResult {
   public boolean success;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/UserPassAuthService.java b/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/UserPassAuthService.java
index 5f39bc3..1d25a3d 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/UserPassAuthService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/auth/userpass/UserPassAuthService.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.common.auth.userpass;
 
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.AllowCrossSiteRequest;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.AllowCrossSiteRequest;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 @RpcImpl(version = Version.V2_0)
 public interface UserPassAuthService extends RemoteJsonService {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccessSection.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccessSection.java
index 12e504c..cd64b0a 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccessSection.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccessSection.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -23,40 +23,18 @@
 import java.util.Set;
 
 /** Portion of a {@link Project} describing access rules. */
-public class AccessSection implements Comparable<AccessSection> {
+public class AccessSection extends RefConfigSection implements
+    Comparable<AccessSection> {
   /** Special name given to the global capabilities; not a valid reference. */
   public static final String GLOBAL_CAPABILITIES = "GLOBAL_CAPABILITIES";
 
-  /** Pattern that matches all references in a project. */
-  public static final String ALL = "refs/*";
-
-  /** Pattern that matches all branches in a project. */
-  public static final String HEADS = "refs/heads/*";
-
-  /** Prefix that triggers a regular expression pattern. */
-  public static final String REGEX_PREFIX = "^";
-
-  /** @return true if the name is likely to be a valid access section name. */
-  public static boolean isAccessSection(String name) {
-    return name.startsWith("refs/") || name.startsWith("^refs/");
-  }
-
-  protected String name;
   protected List<Permission> permissions;
 
   protected AccessSection() {
   }
 
   public AccessSection(String refPattern) {
-    setName(refPattern);
-  }
-
-  public String getName() {
-    return name;
-  }
-
-  public void setName(String name) {
-    this.name = name;
+    super(refPattern);
   }
 
   public List<Permission> getPermissions() {
@@ -119,7 +97,7 @@
       if (dst != null) {
         dst.mergeFrom(src);
       } else {
-        permissions.add(dst);
+        permissions.add(src);
       }
     }
   }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountDashboardInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountDashboardInfo.java
index abcfe28..e24900b 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountDashboardInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountDashboardInfo.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java
index 39c5d9c..9a4d9fb 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfo.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 /** Summary information about an {@link Account}, for simple tabular displays. */
 public class AccountInfo {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfoCache.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfoCache.java
index cf5f20b..bc028e8 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfoCache.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountInfoCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountProjectWatchInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountProjectWatchInfo.java
index 89a50f1..581a09b 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountProjectWatchInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountProjectWatchInfo.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Project;
 
 public final class AccountProjectWatchInfo {
   protected AccountProjectWatch watch;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountSecurity.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountSecurity.java
index c9aa0fd..21aca69 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountSecurity.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountSecurity.java
@@ -15,17 +15,16 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.common.data.GroupDetail;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountSshKey;
-import com.google.gerrit.reviewdb.ContactInformation;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
+import com.google.gerrit.reviewdb.client.ContactInformation;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.List;
 import java.util.Set;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java
index e219074..7377d7e 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AccountService.java
@@ -15,15 +15,15 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.List;
 import java.util.Set;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/AgreementInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/AgreementInfo.java
index 7ae651e..0c6f6b7 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/AgreementInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/AgreementInfo.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountAgreement;
-import com.google.gerrit.reviewdb.AccountGroupAgreement;
-import com.google.gerrit.reviewdb.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.AccountAgreement;
+import com.google.gerrit.reviewdb.client.AccountGroupAgreement;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
 
 import java.util.List;
 import java.util.Map;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalDetail.java
index 318c60b..3d438f2 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalDetail.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 
 import java.sql.Timestamp;
 import java.util.ArrayList;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummary.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummary.java
index 57e8b71..19c9d67 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummary.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummary.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummarySet.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummarySet.java
index 57ee928..2b11085 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummarySet.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalSummarySet.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalType.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalType.java
index 7d03457..333b91c 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalType.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalType.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalTypes.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalTypes.java
index 0518010..b1e32d1 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalTypes.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ApprovalTypes.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java
index 809d462..74d1962 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetail.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -29,6 +29,7 @@
   protected boolean allowsAnonymous;
   protected boolean canAbandon;
   protected boolean canPublish;
+  protected boolean canRebase;
   protected boolean canRestore;
   protected boolean canRevert;
   protected boolean canDeleteDraft;
@@ -80,6 +81,14 @@
     canPublish = a;
   }
 
+  public boolean canRebase() {
+    return canRebase;
+  }
+
+  public void setCanRebase(final boolean a) {
+    canRebase = a;
+  }
+
   public boolean canRestore() {
     return canRestore;
   }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
index 2fbda21..8b43624 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeDetailService.java
@@ -15,13 +15,13 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 @RpcImpl(version = Version.V2_0)
 public interface ChangeDetailService extends RemoteJsonService {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java
index eac8a9e..391d615 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeInfo.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
 
 import java.sql.Timestamp;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeListService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeListService.java
index 5ff85e3..f646bc6 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeListService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeListService.java
@@ -15,13 +15,13 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.Set;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeManageService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeManageService.java
index b667877..872bddc 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeManageService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ChangeManageService.java
@@ -15,12 +15,12 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 @RpcImpl(version = Version.V2_0)
 public interface ChangeManageService extends RemoteJsonService {
@@ -44,4 +44,7 @@
 
   @SignInRequired
   void deleteDraftChange(PatchSet.Id patchSetId, AsyncCallback<VoidResult> callback);
+
+  @SignInRequired
+  void rebaseChange(PatchSet.Id patchSetId, AsyncCallback<ChangeDetail> callback);
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java
index 576e077..0e079b3 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/CommentDetail.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
index 5581c18..456ffb4 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java
@@ -15,10 +15,10 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.openid.OpenIdProviderPattern;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AuthType;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences.DownloadScheme;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
 import com.google.gwtexpui.safehtml.client.RegexFindReplace;
 
 import java.util.List;
@@ -29,7 +29,7 @@
   protected String httpPasswordUrl;
   protected List<OpenIdProviderPattern> allowedOpenIDs;
 
-  protected GitwebLink gitweb;
+  protected GitwebConfig gitweb;
   protected boolean useContributorAgreements;
   protected boolean useContactInfo;
   protected boolean allowRegisterNewEmail;
@@ -86,11 +86,11 @@
     downloadSchemes = s;
   }
 
-  public GitwebLink getGitwebLink() {
+  public GitwebConfig getGitwebLink() {
     return gitweb;
   }
 
-  public void setGitwebLink(final GitwebLink w) {
+  public void setGitwebLink(final GitwebConfig w) {
     gitweb = w;
   }
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GitwebConfig.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GitwebConfig.java
new file mode 100644
index 0000000..0503c60
--- /dev/null
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GitwebConfig.java
@@ -0,0 +1,29 @@
+// Copyright (C) 2008 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.common.data;
+
+/** Link to an external gitweb server. */
+public class GitwebConfig {
+  public String baseUrl;
+  public GitWebType type;
+
+  protected GitwebConfig() {
+  }
+
+  public GitwebConfig(final String base, final GitWebType gitWebType) {
+    baseUrl = base;
+    type = gitWebType;
+  }
+}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
index 2e46791..d3d2a4d 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GlobalCapability.java
@@ -39,6 +39,16 @@
   /** Can create any project on the server. */
   public static final String CREATE_PROJECT = "createProject";
 
+  /**
+   * Denotes who may email change reviewers.
+   * <p>
+   * This can be used to deny build bots from emailing reviewers and people who
+   * have starred the changed. Instead, only the authors of the change will be
+   * emailed. The allow rules are evaluated before deny rules, however the
+   * default is to allow emailing, if no explicit rule is matched.
+   */
+  public static final String EMAIL_REVIEWERS = "emailReviewers";
+
   /** Can flush any cache except the active web_sessions cache. */
   public static final String FLUSH_CACHES = "flushCaches";
 
@@ -71,6 +81,7 @@
     NAMES_LC.add(CREATE_ACCOUNT.toLowerCase());
     NAMES_LC.add(CREATE_GROUP.toLowerCase());
     NAMES_LC.add(CREATE_PROJECT.toLowerCase());
+    NAMES_LC.add(EMAIL_REVIEWERS.toLowerCase());
     NAMES_LC.add(FLUSH_CACHES.toLowerCase());
     NAMES_LC.add(KILL_TASK.toLowerCase());
     NAMES_LC.add(PRIORITY.toLowerCase());
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupAdminService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupAdminService.java
index 087f047..f385e27 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupAdminService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupAdminService.java
@@ -15,14 +15,14 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.List;
 import java.util.Set;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupDetail.java
index 69e535c..65723f7 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupDetail.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfo.java
index 55577f2..547a5f4 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfo.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 /** Summary information about an {@link AccountGroup}, for simple tabular displays. */
 public class GroupInfo {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfoCache.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfoCache.java
index 80d8756..6a5dd5c 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfoCache.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupInfoCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupList.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupList.java
index 9c79eb2..6352461 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupList.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupList.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.common.data.GroupDetail;
-
 import java.util.List;
 
 public class GroupList {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupOptions.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupOptions.java
index 82e0618..c6ed781 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupOptions.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupOptions.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 /**
  * Options for an {@link AccountGroup}.
@@ -22,22 +22,15 @@
 public class GroupOptions {
 
   private boolean visibleToAll;
-  private boolean emailOnlyAuthors;
 
   protected GroupOptions() {
   }
 
-  public GroupOptions(final boolean visibleToAll,
-       final boolean emailOnlyAuthors) {
+  public GroupOptions(final boolean visibleToAll) {
     this.visibleToAll = visibleToAll;
-    this.emailOnlyAuthors = emailOnlyAuthors;
   }
 
   public boolean isVisibleToAll() {
     return visibleToAll;
   }
-
-  public boolean isEmailOnlyAuthors() {
-    return emailOnlyAuthors;
-  }
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupReference.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupReference.java
index cd6e172..f05d1b9 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupReference.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GroupReference.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 /** Describes a group within a projects {@link AccessSection}s. */
 public class GroupReference implements Comparable<GroupReference> {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
index d90d68b..c3d3f1e 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/HostPageData.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 
 /** Data sent as part of the host page, to bootstrap the UI. */
 public class HostPageData {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ListBranchesResult.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ListBranchesResult.java
index 7341c47..1c830e9 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ListBranchesResult.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ListBranchesResult.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Branch;
+import com.google.gerrit.reviewdb.client.Branch;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
index c9be1d4..0191544 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchDetailService.java
@@ -15,19 +15,19 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Patch.Key;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Patch.Key;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.List;
 import java.util.Set;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
index 2214af9..2308b77 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchScript.java
@@ -14,16 +14,13 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.prettify.client.ClientSideFormatter;
 import com.google.gerrit.prettify.common.EditList;
-import com.google.gerrit.prettify.common.PrettyFormatter;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.prettify.common.SparseHtmlFile;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
-import com.google.gerrit.reviewdb.Patch.ChangeType;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 
 import org.eclipse.jgit.diff.Edit;
 
@@ -167,36 +164,6 @@
     return b;
   }
 
-  public SparseHtmlFile getSparseHtmlFileA() {
-    AccountDiffPreference dp = new AccountDiffPreference(diffPrefs);
-    dp.setShowWhitespaceErrors(false);
-
-    PrettyFormatter f = ClientSideFormatter.FACTORY.get();
-    f.setDiffPrefs(dp);
-    f.setFileName(a.getPath());
-    f.setEditFilter(PrettyFormatter.A);
-    f.setEditList(edits);
-    f.format(a);
-    return f;
-  }
-
-  public SparseHtmlFile getSparseHtmlFileB() {
-    AccountDiffPreference dp = new AccountDiffPreference(diffPrefs);
-
-    PrettyFormatter f = ClientSideFormatter.FACTORY.get();
-    f.setDiffPrefs(dp);
-    f.setFileName(b.getPath());
-    f.setEditFilter(PrettyFormatter.B);
-    f.setEditList(edits);
-
-    if (dp.isSyntaxHighlighting() && a.isWholeFile() && !b.isWholeFile()) {
-      f.format(b.apply(a, edits));
-    } else {
-      f.format(b);
-    }
-    return f;
-  }
-
   public List<Edit> getEdits() {
     return edits;
   }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetDetail.java
index 64e666e..a2debf2 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetDetail.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetPublishDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetPublishDetail.java
index 273f18d..075d558 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetPublishDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/PatchSetPublishDetail.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
index f818d7b..20261de 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/Permission.java
@@ -30,6 +30,7 @@
   public static final String PUSH_MERGE = "pushMerge";
   public static final String PUSH_TAG = "pushTag";
   public static final String READ = "read";
+  public static final String REBASE = "rebase";
   public static final String SUBMIT = "submit";
 
   private static final List<String> NAMES_LC;
@@ -47,6 +48,7 @@
     NAMES_LC.add(PUSH_MERGE.toLowerCase());
     NAMES_LC.add(PUSH_TAG.toLowerCase());
     NAMES_LC.add(LABEL.toLowerCase());
+    NAMES_LC.add(REBASE.toLowerCase());
     NAMES_LC.add(SUBMIT.toLowerCase());
 
     labelIndex = NAMES_LC.indexOf(Permission.LABEL);
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
index 2a80d52..f935c03 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAccess.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 import java.util.List;
 import java.util.Set;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
index 4d10a42..1b504b0 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectAdminService.java
@@ -15,13 +15,13 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.List;
 import java.util.Set;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectDetail.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectDetail.java
index 7d59c8b..1d88cf8 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectDetail.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectDetail.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 public class ProjectDetail {
   public Project project;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectInfo.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectInfo.java
index 8f22936..dfef806 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectInfo.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectInfo.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 public class ProjectInfo {
   protected Project.NameKey key;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectList.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectList.java
index 0da45b2..8511460 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectList.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ProjectList.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/RefConfigSection.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/RefConfigSection.java
new file mode 100644
index 0000000..490378e
--- /dev/null
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/RefConfigSection.java
@@ -0,0 +1,48 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.common.data;
+
+public abstract class RefConfigSection {
+  /** Pattern that matches all references in a project. */
+  public static final String ALL = "refs/*";
+
+  /** Pattern that matches all branches in a project. */
+  public static final String HEADS = "refs/heads/*";
+
+  /** Prefix that triggers a regular expression pattern. */
+  public static final String REGEX_PREFIX = "^";
+
+  /** @return true if the name is likely to be a valid reference section name. */
+  public static boolean isValid(String name) {
+    return name.startsWith("refs/") || name.startsWith("^refs/");
+  }
+
+  protected String name;
+
+  public RefConfigSection() {
+  }
+
+  public RefConfigSection(String name) {
+    setName(name);
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+}
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewResult.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewResult.java
index 9378526..001f9b4 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewResult.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ReviewResult.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
index 953ae99..5049ba4 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SubmitRecord.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java
index 12c8b60..85518b2 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SuggestService.java
@@ -14,12 +14,13 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.List;
 
@@ -35,13 +36,20 @@
       AsyncCallback<List<GroupReference>> callback);
 
   /**
+   * @see #suggestChangeReviewer(com.google.gerrit.reviewdb.client.Change.Id, String, int, AsyncCallback)
+   */
+  @Deprecated
+  void suggestReviewer(Project.NameKey project, String query, int limit,
+      AsyncCallback<List<ReviewerInfo>> callback);
+
+  /**
    * Suggests reviewers. A reviewer can be a user or a group. Inactive users,
    * the system groups {@link AccountGroup#ANONYMOUS_USERS} and
    * {@link AccountGroup#REGISTERED_USERS} and groups that have more than the
    * configured <code>addReviewer.maxAllowed</code> members are not suggested as
    * reviewers.
-   * @param project the project for which reviewers should be suggested
+   * @param changeId the change for which reviewers should be suggested
    */
-  void suggestReviewer(Project.NameKey project, String query, int limit,
+  void suggestChangeReviewer(Change.Id changeId, String query, int limit,
       AsyncCallback<List<ReviewerInfo>> callback);
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/SystemInfoService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/SystemInfoService.java
index b008ee7..78ccca1 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/SystemInfoService.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/SystemInfoService.java
@@ -15,13 +15,13 @@
 package com.google.gerrit.common.data;
 
 import com.google.gerrit.common.auth.SignInRequired;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.AllowCrossSiteRequest;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.AllowCrossSiteRequest;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 import java.util.List;
 
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/ToggleStarRequest.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/ToggleStarRequest.java
index 32178fb..c9ba72f 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/ToggleStarRequest.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/ToggleStarRequest.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.data;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 
 import java.util.HashSet;
 import java.util.Set;
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidNameException.java b/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidNameException.java
index 5eb6e3f..d975aef 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidNameException.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidNameException.java
@@ -23,4 +23,8 @@
   public InvalidNameException() {
     super(MESSAGE);
   }
+
+  public InvalidNameException(String invalidName) {
+    super(MESSAGE + ": " + invalidName);
+  }
 }
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidUserNameException.java b/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidUserNameException.java
index 55d490c..f1c35a8 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidUserNameException.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/errors/InvalidUserNameException.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.errors;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 /** Error indicating the SSH user name does not match {@link Account#USER_NAME_PATTERN} pattern. */
 public class InvalidUserNameException extends Exception {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/errors/NoSuchGroupException.java b/gerrit-common/src/main/java/com/google/gerrit/common/errors/NoSuchGroupException.java
index 179bc3a..ade0d98 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/errors/NoSuchGroupException.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/errors/NoSuchGroupException.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.common.errors;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 /** Indicates the account group does not exist. */
 public class NoSuchGroupException extends Exception {
diff --git a/gerrit-ehcache/.gitignore b/gerrit-ehcache/.gitignore
index 903c6c8..20251d4 100644
--- a/gerrit-ehcache/.gitignore
+++ b/gerrit-ehcache/.gitignore
@@ -1,4 +1,5 @@
 /target
 /.classpath
 /.project
+/.settings/org.eclipse.m2e.core.prefs
 /.settings/org.maven.ide.eclipse.prefs
diff --git a/gerrit-ehcache/pom.xml b/gerrit-ehcache/pom.xml
index 417a978..839c52b0 100644
--- a/gerrit-ehcache/pom.xml
+++ b/gerrit-ehcache/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-ehcache</artifactId>
diff --git a/gerrit-gwtdebug/pom.xml b/gerrit-gwtdebug/pom.xml
index 33b6851..734f645 100644
--- a/gerrit-gwtdebug/pom.xml
+++ b/gerrit-gwtdebug/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-gwtdebug</artifactId>
diff --git a/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
index 1834cdf..d23aa35 100644
--- a/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
+++ b/gerrit-gwtdebug/src/main/java/com/google/gerrit/gwtdebug/GerritDebugLauncher.java
@@ -23,11 +23,11 @@
 
 import org.mortbay.component.AbstractLifeCycle;
 import org.mortbay.jetty.AbstractConnector;
+import org.mortbay.jetty.HttpFields.Field;
 import org.mortbay.jetty.Request;
 import org.mortbay.jetty.RequestLog;
 import org.mortbay.jetty.Response;
 import org.mortbay.jetty.Server;
-import org.mortbay.jetty.HttpFields.Field;
 import org.mortbay.jetty.handler.RequestLogHandler;
 import org.mortbay.jetty.nio.SelectChannelConnector;
 import org.mortbay.jetty.webapp.WebAppClassLoader;
diff --git a/gerrit-gwtui/pom.xml b/gerrit-gwtui/pom.xml
index b09b8e3..f14daf6 100644
--- a/gerrit-gwtui/pom.xml
+++ b/gerrit-gwtui/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-gwtui</artifactId>
@@ -37,7 +37,6 @@
     <dependency>
       <groupId>com.google.gwt</groupId>
       <artifactId>gwt-user</artifactId>
-      <version>${gwtVersion}</version>
     </dependency>
 
     <dependency>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
index 2e8cd5e..3aee0e2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Dispatcher.java
@@ -68,12 +68,12 @@
 import com.google.gerrit.common.auth.SignInMode;
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.RunAsyncCallback;
 import com.google.gwt.user.client.Window;
@@ -81,20 +81,34 @@
 
 public class Dispatcher {
   public static String toPatchSideBySide(final Patch.Key id) {
-    return toPatch("", id);
+    return toPatch("", null, id);
+  }
+
+  public static String toPatchSideBySide(PatchSet.Id diffBase, Patch.Key id) {
+    return toPatch("", diffBase, id);
   }
 
   public static String toPatchUnified(final Patch.Key id) {
-    return toPatch("unified", id);
+    return toPatch("unified", null, id);
   }
 
-  private static String toPatch(String type, final Patch.Key id) {
+  public static String toPatchUnified(PatchSet.Id diffBase, Patch.Key id) {
+    return toPatch("unified", diffBase, id);
+  }
+
+  private static String toPatch(String type, PatchSet.Id diffBase, Patch.Key id) {
     PatchSet.Id ps = id.getParentKey();
     Change.Id c = ps.getParentKey();
-    if (type != null && !type.isEmpty()) {
-      type = "," + type;
+    StringBuilder p = new StringBuilder();
+    p.append("/c/").append(c).append("/");
+    if (diffBase != null) {
+      p.append(diffBase.get()).append("..");
     }
-    return "/c/" + c + "/" + ps.get() + "/" + KeyUtil.encode(id.get()) + type;
+    p.append(ps.get()).append("/").append(KeyUtil.encode(id.get()));
+    if (type != null && !type.isEmpty()) {
+      p.append(",").append(type);
+    }
+    return p.toString();
   }
 
   public static String toPatch(final PatchScreen.Type type, final Patch.Key id) {
@@ -387,10 +401,20 @@
       rest = "";
     }
 
-    PatchSet.Id ps = new PatchSet.Id(id, Integer.parseInt(psIdStr));
+    PatchSet.Id base;
+    PatchSet.Id ps;
+    int dotdot = psIdStr.indexOf("..");
+    if (1 <= dotdot) {
+      base = new PatchSet.Id(id, Integer.parseInt(psIdStr.substring(0, dotdot)));
+      ps = new PatchSet.Id(id, Integer.parseInt(psIdStr.substring(dotdot + 2)));
+    } else {
+      base = null;
+      ps = new PatchSet.Id(id, Integer.parseInt(psIdStr));
+    }
+
     if (!rest.isEmpty()) {
       Patch.Key p = new Patch.Key(ps, rest);
-      patch(token, p, 0, null, null, panel);
+      patch(token, base, p, 0, null, null, panel);
     } else {
       if (panel == null) {
         Gerrit.display(token, new ChangeScreen(ps));
@@ -415,24 +439,23 @@
     }.onSuccess();
   }
 
-  public static void patch(String token, final Patch.Key id,
-      final int patchIndex, final PatchSetDetail patchSetDetail,
-      final PatchTable patchTable, final PatchScreen.TopView topView) {
-    patch(token, id, patchIndex, patchSetDetail, patchTable, topView, null);
+  public static void patch(String token, PatchSet.Id base, Patch.Key id,
+      int patchIndex, PatchSetDetail patchSetDetail,
+      PatchTable patchTable, PatchScreen.TopView topView) {
+    patch(token, base, id, patchIndex, patchSetDetail, patchTable, topView, null);
   }
 
-  public static void patch(String token, final Patch.Key id,
-      final int patchIndex, final PatchSetDetail patchSetDetail,
-      final PatchTable patchTable, final String panelType) {
-    patch(token, id, patchIndex, patchSetDetail, patchTable,
+  public static void patch(String token, PatchSet.Id base, Patch.Key id,
+      int patchIndex, PatchSetDetail patchSetDetail,
+      PatchTable patchTable, String panelType) {
+    patch(token, base, id, patchIndex, patchSetDetail, patchTable,
         null, panelType);
   }
 
-  public static void patch(String token, final Patch.Key id,
+  public static void patch(String token, final PatchSet.Id baseId, final Patch.Key id,
       final int patchIndex, final PatchSetDetail patchSetDetail,
       final PatchTable patchTable, final PatchScreen.TopView topView,
       final String panelType) {
-
     final PatchScreen.TopView top =  topView == null ?
         Gerrit.getPatchScreenTopView() : topView;
 
@@ -455,7 +478,8 @@
                 patchIndex, //
                 patchSetDetail, //
                 patchTable, //
-                top //
+                top, //
+                baseId //
             );
           } else if ("unified".equals(panel)) {
             return new PatchScreen.Unified( //
@@ -463,7 +487,8 @@
                 patchIndex, //
                 patchSetDetail, //
                 patchTable, //
-                top //
+                top, //
+                baseId //
             );
           }
         }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
index 16a2d35..e578eae 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/FormatUtil.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.client;
 
 import com.google.gerrit.common.data.AccountInfo;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.i18n.client.DateTimeFormat;
 
 import java.util.Date;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
index c04167e..6dbfeee 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java
@@ -29,12 +29,13 @@
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.auth.SignInMode;
 import com.google.gerrit.common.data.GerritConfig;
+import com.google.gerrit.common.data.GitwebConfig;
 import com.google.gerrit.common.data.HostPageData;
 import com.google.gerrit.common.data.SystemInfoService;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JavaScriptObject;
@@ -53,10 +54,10 @@
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwt.user.client.ui.InlineLabel;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwtexpui.clippy.client.CopyableLabel;
 import com.google.gwtexpui.user.client.UserAgent;
 import com.google.gwtexpui.user.client.ViewSite;
@@ -211,6 +212,11 @@
     return myConfig;
   }
 
+  public static GitwebLink getGitwebLink() {
+    GitwebConfig gw = getConfig().getGitwebLink();
+    return gw != null ? new GitwebLink(gw) : null;
+  }
+
   /** Site theme information (site specific colors)/ */
   public static HostPageData.Theme getTheme() {
     return myTheme;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
index f2a3d3e..ee107d0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.java
@@ -81,7 +81,7 @@
   String searchHint();
   String searchButton();
 
-  String rpcStatusLoading();
+  String rpcStatusWorking();
 
   String sectionNavigation();
   String sectionActions();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
index 3880f59..41db3d5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritConstants.properties
@@ -25,7 +25,7 @@
 <p>To continue, please sign-in again.</p>
 
 notFoundTitle = Not Found
-notFoundBody = The page you requested was not found.
+notFoundBody = The page you requested was not found, or you do not have permission to view this page.
 nameAlreadyUsedBody = The name is already in use.
 noSuchAccountTitle = Code Review - Unknown User
 
@@ -64,7 +64,7 @@
 searchHint = Change #, SHA-1, tr:id, owner:email or reviewer:email
 searchButton = Search
 
-rpcStatusLoading = Loading ...
+rpcStatusWorking = Working ...
 
 sectionNavigation = Navigation
 sectionActions = Actions
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
index 70cfdbc..a8315d8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GerritCss.java
@@ -18,10 +18,6 @@
 
 public interface GerritCss extends CssResource {
   String greenCheckClass();
-  String abandonChangeDialog();
-  String abandonMessage();
-  String revertChangeDialog();
-  String revertMessage();
   String accountContactOnFile();
   String accountContactPrivacyDetails();
   String accountDashboard();
@@ -58,6 +54,8 @@
   String changeTypeCell();
   String changeid();
   String closedstate();
+  String commentedActionDialog();
+  String commentedActionMessage();
   String commentCell();
   String commentEditorPanel();
   String commentHolder();
@@ -124,7 +122,6 @@
   String groupNamePanel();
   String groupNameTextBox();
   String groupOptionsPanel();
-  String groupOptionsNotificationsDescriptionPanel();
   String groupOwnerPanel();
   String groupOwnerTextBox();
   String groupTypePanel();
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GitwebLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GitwebLink.java
similarity index 85%
rename from gerrit-common/src/main/java/com/google/gerrit/common/data/GitwebLink.java
rename to gerrit-gwtui/src/main/java/com/google/gerrit/client/GitwebLink.java
index 5ee1b6e..5f62a52 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GitwebLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/GitwebLink.java
@@ -12,11 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.common.data;
+package com.google.gerrit.client;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.common.data.GitWebType;
+import com.google.gerrit.common.data.ParameterizedString;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.http.client.URL;
 
 import java.util.HashMap;
@@ -28,12 +30,9 @@
 
   protected GitWebType type;
 
-  protected GitwebLink() {
-  }
-
-  public GitwebLink(final String base, final GitWebType gitWebType) {
-    baseUrl = base;
-    type = gitWebType;
+  public GitwebLink(com.google.gerrit.common.data.GitwebConfig link) {
+    baseUrl = link.baseUrl;
+    type = link.type;
   }
 
   public String getLinkName() {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/HostPageDataService.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/HostPageDataService.java
index accec0a..bd3d483 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/HostPageDataService.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/HostPageDataService.java
@@ -15,11 +15,11 @@
 package com.google.gerrit.client;
 
 import com.google.gerrit.common.data.HostPageData;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.HostPageCache;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
-import com.google.gwtjsonrpc.client.RpcImpl;
-import com.google.gwtjsonrpc.client.RpcImpl.Version;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.HostPageCache;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RpcImpl;
+import com.google.gwtjsonrpc.common.RpcImpl.Version;
 
 @RpcImpl(version = Version.V2_0)
 interface HostPageDataService extends RemoteJsonService {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/RpcStatus.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/RpcStatus.java
index 21c5154..76ce384 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/RpcStatus.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/RpcStatus.java
@@ -47,7 +47,7 @@
     p.add(r);
 
     loading = new InlineLabel();
-    loading.setText(Gerrit.C.rpcStatusLoading());
+    loading.setText(Gerrit.C.rpcStatusWorking());
     loading.setStyleName(Gerrit.RESOURCES.css().rpcStatus());
     loading.addStyleName(Gerrit.RESOURCES.css().rpcStatusLoading());
     loading.setVisible(false);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
index d1f1296..e3d8468 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/SearchPanel.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.client.changes.QueryScreen;
 import com.google.gerrit.client.ui.HintTextBox;
 import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyCodes;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java
index b7a00ad..4b8f0e2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelFull.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.ui.OnEditEnabler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ContactInformation;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ContactInformation;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.Label;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java
index 8c6ba2e..4e0b3b2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ContactPanelShort.java
@@ -18,27 +18,27 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.OnEditEnabler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ContactInformation;
-import com.google.gerrit.reviewdb.Account.FieldName;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gerrit.reviewdb.client.ContactInformation;
+import com.google.gerrit.reviewdb.client.Account.FieldName;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.i18n.client.LocaleInfo;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.ListBox;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
 import com.google.gwtexpui.user.client.AutoCenterDialogBox;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java
index 54de472..af619a8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyAgreementsScreen.java
@@ -21,10 +21,10 @@
 import com.google.gerrit.client.ui.Hyperlink;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.AgreementInfo;
-import com.google.gerrit.reviewdb.AbstractAgreement;
-import com.google.gerrit.reviewdb.AccountAgreement;
-import com.google.gerrit.reviewdb.AccountGroupAgreement;
-import com.google.gerrit.reviewdb.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.AbstractAgreement;
+import com.google.gerrit.reviewdb.client.AccountAgreement;
+import com.google.gerrit.reviewdb.client.AccountGroupAgreement;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
 import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
index f3816f2..899aa03 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyIdentitiesScreen.java
@@ -22,7 +22,7 @@
 import com.google.gerrit.client.ui.FancyFlexTable;
 import com.google.gerrit.common.auth.SignInMode;
 import com.google.gerrit.common.auth.openid.OpenIdUrls;
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java
index 65525eb..abb1f4d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyPasswordScreen.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.client.account;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_USERNAME;
 
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.i18n.client.LocaleInfo;
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 1415167..84e87aa 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
@@ -14,14 +14,14 @@
 
 package com.google.gerrit.client.account;
 
-import static com.google.gerrit.reviewdb.AccountGeneralPreferences.DEFAULT_PAGESIZE;
-import static com.google.gerrit.reviewdb.AccountGeneralPreferences.PAGESIZE_CHOICES;
+import static com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DEFAULT_PAGESIZE;
+import static com.google.gerrit.reviewdb.client.AccountGeneralPreferences.PAGESIZE_CHOICES;
 
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
 import com.google.gwt.event.dom.client.ClickEvent;
@@ -33,7 +33,7 @@
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.Date;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java
index 65c2590..165168d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyProfileScreen.java
@@ -17,7 +17,7 @@
 import static com.google.gerrit.client.FormatUtil.mediumFormat;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gwt.i18n.client.LocaleInfo;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java
index b3bd0cb..c158c2c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/MyWatchesTable.java
@@ -19,16 +19,16 @@
 import com.google.gerrit.client.ui.FancyFlexTable;
 import com.google.gerrit.client.ui.ProjectLink;
 import com.google.gerrit.common.data.AccountProjectWatchInfo;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change.Status;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.HashSet;
 import java.util.List;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/NewAgreementScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/NewAgreementScreen.java
index 30638da..154e2ce 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/NewAgreementScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/NewAgreementScreen.java
@@ -22,10 +22,10 @@
 import com.google.gerrit.client.ui.SmallHeading;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.AgreementInfo;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountAgreement;
-import com.google.gerrit.reviewdb.AccountGroupAgreement;
-import com.google.gerrit.reviewdb.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountAgreement;
+import com.google.gerrit.reviewdb.client.AccountGroupAgreement;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
@@ -34,7 +34,7 @@
 import com.google.gwt.http.client.RequestCallback;
 import com.google.gwt.http.client.RequestException;
 import com.google.gwt.http.client.Response;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.FormPanel;
@@ -45,7 +45,7 @@
 import com.google.gwt.user.client.ui.RadioButton;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.HashSet;
 import java.util.List;
@@ -250,7 +250,7 @@
     String url = cla.getAgreementUrl();
     if (url != null && url.length() > 0) {
       agreementGroup.setVisible(true);
-      agreementHtml.setText(Gerrit.C.rpcStatusLoading());
+      agreementHtml.setText(Gerrit.C.rpcStatusWorking());
       if (!url.startsWith("http:") && !url.startsWith("https:")) {
         url = GWT.getHostPageBaseURL() + url;
       }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java
index 605d7f3..084ea6f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/RegisterScreen.java
@@ -19,8 +19,8 @@
 import com.google.gerrit.client.ui.InlineHyperlink;
 import com.google.gerrit.client.ui.SmallHeading;
 import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Account.FieldName;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Account.FieldName;
 import com.google.gwt.i18n.client.LocaleInfo;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.FormPanel;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java
index c8a1485..73127f0 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/SshPanel.java
@@ -21,7 +21,7 @@
 import com.google.gerrit.client.ui.SmallHeading;
 import com.google.gerrit.common.data.SshHostKey;
 import com.google.gerrit.common.errors.InvalidSshKeyException;
-import com.google.gerrit.reviewdb.AccountSshKey;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
@@ -39,7 +39,7 @@
 import com.google.gwtexpui.clippy.client.CopyableLabel;
 import com.google.gwtexpui.globalkey.client.NpTextArea;
 import com.google.gwtjsonrpc.client.RemoteJsonException;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.Collections;
 import java.util.HashSet;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java
index 76bc212..0666bb3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/UsernameField.java
@@ -19,7 +19,7 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.OnEditEnabler;
 import com.google.gerrit.common.errors.InvalidUserNameException;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyCodes;
@@ -31,7 +31,7 @@
 import com.google.gwt.user.client.ui.TextBox;
 import com.google.gwtexpui.clippy.client.CopyableLabel;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 class UsernameField extends Composite {
   private CopyableLabel userNameLbl;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ValidateEmailScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ValidateEmailScreen.java
index 4e54e85..1164efc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ValidateEmailScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/ValidateEmailScreen.java
@@ -18,7 +18,7 @@
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
 import com.google.gerrit.client.ui.AccountScreen;
 import com.google.gerrit.common.PageLinks;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 public class ValidateEmailScreen extends AccountScreen {
   private final String magicToken;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
index f4257b5..72ac1a4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccessSectionEditor.java
@@ -19,6 +19,7 @@
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.ProjectAccess;
+import com.google.gerrit.common.data.RefConfigSection;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
@@ -122,7 +123,8 @@
   void onDeleteSection(ClickEvent event) {
     isDeleted = true;
 
-    if (name.isVisible() && AccessSection.isAccessSection(name.getValue())){
+    if (name.isVisible()
+        && RefConfigSection.isValid(name.getValue())) {
       deletedName.setInnerText(Util.M.deletedReference(name.getValue()));
 
     } else {
@@ -185,7 +187,7 @@
     name.setEnabled(!readOnly);
     deleteSection.setVisible(!readOnly);
 
-    if (AccessSection.isAccessSection(value.getName())) {
+    if (RefConfigSection.isValid(value.getName())) {
       name.setVisible(true);
       name.setIgnoreEditorValue(false);
       sectionType.setInnerText(Util.C.sectionTypeReference());
@@ -225,8 +227,9 @@
           perms.add(varName);
         }
       }
-    } else if (AccessSection.isAccessSection(value.getName())) {
-      for (ApprovalType t : Gerrit.getConfig().getApprovalTypes().getApprovalTypes()) {
+    } else if (RefConfigSection.isValid(value.getName())) {
+      for (ApprovalType t : Gerrit.getConfig().getApprovalTypes()
+          .getApprovalTypes()) {
         String varName = Permission.LABEL + t.getCategory().getLabelName();
         if (value.getPermission(varName) == null) {
           perms.add(varName);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
index 5ce90e7..936bfe5 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupInfoScreen.java
@@ -22,7 +22,7 @@
 import com.google.gerrit.client.ui.SmallHeading;
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.data.GroupOptions;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
 import com.google.gwt.event.dom.client.ClickEvent;
@@ -43,7 +43,7 @@
 import com.google.gwtexpui.clippy.client.CopyableLabel;
 import com.google.gwtexpui.globalkey.client.NpTextArea;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.List;
 
@@ -70,9 +70,7 @@
   private Button externalNameSearch;
   private Grid externalMatches;
 
-  private Panel groupOptionsPanel;
   private CheckBox visibleToAllCheckBox;
-  private CheckBox emailOnlyAuthors;
   private Button saveGroupOptions;
 
   public AccountGroupInfoScreen(final GroupDetail toShow, final String token) {
@@ -100,7 +98,6 @@
     externalNameFilter.setEnabled(canModify);
     externalNameSearch.setEnabled(canModify);
     visibleToAllCheckBox.setEnabled(canModify);
-    emailOnlyAuthors.setEnabled(canModify);
   }
 
   private void initUUID() {
@@ -207,20 +204,14 @@
   }
 
   private void initGroupOptions() {
-    groupOptionsPanel = new VerticalPanel();
-    groupOptionsPanel.setStyleName(Gerrit.RESOURCES.css().groupOptionsPanel());
-    groupOptionsPanel.add(new SmallHeading(Util.C.headingGroupOptions()));
-
-    visibleToAllCheckBox = new CheckBox(Util.C.isVisibleToAll());
-    groupOptionsPanel.add(visibleToAllCheckBox);
-
-    emailOnlyAuthors = new CheckBox(Util.C.emailOnlyAuthors());
+    final VerticalPanel groupOptionsPanel = new VerticalPanel();
 
     final VerticalPanel vp = new VerticalPanel();
-    vp.setStyleName(Gerrit.RESOURCES.css()
-        .groupOptionsNotificationsDescriptionPanel());
-    vp.add(new Label(Util.C.descriptionNotifications()));
-    vp.add(emailOnlyAuthors);
+    vp.setStyleName(Gerrit.RESOURCES.css().groupOptionsPanel());
+    vp.add(new SmallHeading(Util.C.headingGroupOptions()));
+
+    visibleToAllCheckBox = new CheckBox(Util.C.isVisibleToAll());
+    vp.add(visibleToAllCheckBox);
     groupOptionsPanel.add(vp);
 
     saveGroupOptions = new Button(Util.C.buttonSaveGroupOptions());
@@ -229,8 +220,7 @@
       @Override
       public void onClick(final ClickEvent event) {
         final GroupOptions groupOptions =
-            new GroupOptions(visibleToAllCheckBox.getValue(),
-              emailOnlyAuthors.getValue());
+            new GroupOptions(visibleToAllCheckBox.getValue());
         Util.GROUP_SVC.changeGroupOptions(getGroupId(), groupOptions,
             new GerritCallback<VoidResult>() {
               public void onSuccess(final VoidResult result) {
@@ -245,7 +235,6 @@
 
     final OnEditEnabler enabler = new OnEditEnabler(saveGroupOptions);
     enabler.listenTo(visibleToAllCheckBox);
-    enabler.listenTo(emailOnlyAuthors);
   }
 
   private void initGroupType() {
@@ -460,7 +449,6 @@
     descTxt.setText(group.getDescription());
 
     visibleToAllCheckBox.setValue(group.isVisibleToAll());
-    emailOnlyAuthors.setValue(group.isEmailOnlyAuthors());
 
     switch (group.getType()) {
       case LDAP:
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
index 4e13ab5..b5cca86 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupMembersScreen.java
@@ -27,10 +27,10 @@
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.data.GroupInfo;
 import com.google.gerrit.common.data.GroupInfoCache;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.ui.Button;
@@ -38,7 +38,7 @@
 import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Panel;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.HashSet;
 import java.util.List;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java
index 2c7f110..9ac6c9a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AccountGroupScreen.java
@@ -18,7 +18,7 @@
 
 import com.google.gerrit.client.ui.MenuScreen;
 import com.google.gerrit.common.data.GroupDetail;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 public abstract class AccountGroupScreen extends MenuScreen {
   public static final String INFO = "info";
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
index c928eb9..9250ca3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.java
@@ -44,8 +44,6 @@
   String requireChangeID();
   String headingGroupOptions();
   String isVisibleToAll();
-  String emailOnlyAuthors();
-  String descriptionNotifications();
   String buttonSaveGroupOptions();
   String suggestedGroupLabel();
   String parentSuggestions();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
index f2a8ad6..ef7b73d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/AdminConstants.properties
@@ -29,9 +29,6 @@
 parentSuggestions = Parent Suggestion
 columnProjectName = Project Name
 
-emailOnlyAuthors = Authors
-descriptionNotifications = Send email notifications about comments and actions by users in this group only to:
-
 headingGroupUUID = Group UUID
 headingOwner = Owners
 headingDescription = Description
@@ -103,6 +100,7 @@
 	pushMerge, \
 	pushTag, \
 	read, \
+	rebase, \
 	submit
 create = Create Reference
 forgeAuthor = Forge Author Identity
@@ -113,6 +111,7 @@
 pushMerge = Push Merge Commit
 pushTag = Push Annotated Tag
 read = Read
+rebase = Rebase
 submit = Submit
 
 refErrorEmpty = Reference must be supplied
@@ -128,6 +127,7 @@
   createAccount, \
   createGroup, \
   createProject, \
+  emailReviewers, \
   flushCaches, \
   killTask, \
   priority, \
@@ -140,6 +140,7 @@
 createAccount = Create Account
 createGroup = Create Group
 createProject = Create Project
+emailReviewers = Email Reviewers
 flushCaches = Flush Caches
 killTask = Kill Task
 priority = Priority
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
index 7f2ae07..0ce2d77 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/CreateProjectScreen.java
@@ -22,7 +22,7 @@
 import com.google.gerrit.client.ui.ProjectNameSuggestOracle;
 import com.google.gerrit.client.ui.ProjectsTable;
 import com.google.gerrit.client.ui.Screen;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyCodes;
@@ -36,7 +36,7 @@
 import com.google.gwt.user.client.ui.SuggestBox;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwtexpui.globalkey.client.NpTextBox;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.List;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
index f1d9ac1..9d62d34 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupListScreen.java
@@ -23,7 +23,7 @@
 import com.google.gerrit.client.ui.SmallHeading;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.GroupList;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gwt.event.dom.client.BlurEvent;
 import com.google.gwt.event.dom.client.BlurHandler;
 import com.google.gwt.event.dom.client.ClickEvent;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
index 7585f8a..7f73226 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/GroupTable.java
@@ -19,7 +19,7 @@
 import com.google.gerrit.client.ui.Hyperlink;
 import com.google.gerrit.client.ui.NavigationTable;
 import com.google.gerrit.common.data.GroupDetail;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyCodes;
@@ -32,6 +32,8 @@
 
 
 public class GroupTable extends NavigationTable<AccountGroup> {
+  private static final int NUM_COLS = 5;
+
   private final boolean enableLink;
 
   public GroupTable(final boolean enableLink) {
@@ -52,8 +54,7 @@
     table.setText(0, 2, Util.C.columnGroupDescription());
     table.setText(0, 3, Util.C.headingOwner());
     table.setText(0, 4, Util.C.columnGroupType());
-    table.setText(0, 5, Util.C.columnGroupNotifications());
-    table.setText(0, 6, Util.C.columnGroupVisibleToAll());
+    table.setText(0, 5, Util.C.columnGroupVisibleToAll());
     table.addClickHandler(new ClickHandler() {
       @Override
       public void onClick(ClickEvent event) {
@@ -66,12 +67,9 @@
     });
 
     final FlexCellFormatter fmt = table.getFlexCellFormatter();
-    fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().dataHeader());
-    fmt.addStyleName(0, 2, Gerrit.RESOURCES.css().dataHeader());
-    fmt.addStyleName(0, 3, Gerrit.RESOURCES.css().dataHeader());
-    fmt.addStyleName(0, 4, Gerrit.RESOURCES.css().dataHeader());
-    fmt.addStyleName(0, 5, Gerrit.RESOURCES.css().dataHeader());
-    fmt.addStyleName(0, 6, Gerrit.RESOURCES.css().dataHeader());
+    for (int i = 1; i <= NUM_COLS; i++) {
+      fmt.addStyleName(0, i, Gerrit.RESOURCES.css().dataHeader());
+    }
   }
 
   @Override
@@ -107,21 +105,15 @@
     table.setText(row, 2, k.getDescription());
     table.setText(row, 3, detail.ownerGroup.getName());
     table.setText(row, 4, k.getType().toString());
-    if (k.isEmailOnlyAuthors()) {
-      table.setWidget(row, 5, new Image(Gerrit.RESOURCES.greenCheck()));
-    }
     if (k.isVisibleToAll()) {
-      table.setWidget(row, 6, new Image(Gerrit.RESOURCES.greenCheck()));
+      table.setWidget(row, 5, new Image(Gerrit.RESOURCES.greenCheck()));
     }
 
     final FlexCellFormatter fmt = table.getFlexCellFormatter();
-    fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().dataCell());
     fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().groupName());
-    fmt.addStyleName(row, 2, Gerrit.RESOURCES.css().dataCell());
-    fmt.addStyleName(row, 3, Gerrit.RESOURCES.css().dataCell());
-    fmt.addStyleName(row, 4, Gerrit.RESOURCES.css().dataCell());
-    fmt.addStyleName(row, 5, Gerrit.RESOURCES.css().dataCell());
-    fmt.addStyleName(row, 6, Gerrit.RESOURCES.css().dataCell());
+    for (int i = 1; i <= NUM_COLS; i++) {
+      fmt.addStyleName(row, i, Gerrit.RESOURCES.css().dataCell());
+    }
 
     setRowItem(row, k);
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
index a11cd5c..d10afd1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/PermissionEditor.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.common.data.RefConfigSection;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
@@ -114,7 +115,8 @@
     rules = ListEditor.of(new RuleEditorSource());
 
     exclusiveGroup.setEnabled(!readOnly);
-    exclusiveGroup.setVisible(AccessSection.isAccessSection(section.getName()));
+    exclusiveGroup.setVisible(RefConfigSection
+        .isValid(section.getName()));
 
     if (readOnly) {
       addContainer.removeFromParent();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
index e6e11b0..e3bf555 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessEditor.java
@@ -16,12 +16,12 @@
 
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.GitwebLink;
 import com.google.gerrit.client.ui.Hyperlink;
 import com.google.gerrit.common.data.AccessSection;
-import com.google.gerrit.common.data.GitwebLink;
 import com.google.gerrit.common.data.ProjectAccess;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.DivElement;
 import com.google.gwt.dom.client.Style.Display;
@@ -110,7 +110,7 @@
       inheritsFrom.getStyle().setDisplay(Display.NONE);
     }
 
-    final GitwebLink c = Gerrit.getConfig().getGitwebLink();
+    final GitwebLink c = Gerrit.getGitwebLink();
     if (value.isConfigVisible() && c != null) {
       history.getStyle().setDisplay(Display.BLOCK);
       gitweb.setText(c.getLinkName());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
index fc864de..1ed919b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectAccessScreen.java
@@ -19,7 +19,7 @@
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.ProjectAccess;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.DivElement;
 import com.google.gwt.editor.client.SimpleBeanEditorDriver;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
index 7c51700..f3ecbb3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectBranchesScreen.java
@@ -17,16 +17,16 @@
 import com.google.gerrit.client.ConfirmationCallback;
 import com.google.gerrit.client.ConfirmationDialog;
 import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.GitwebLink;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.rpc.ScreenLoadCallback;
 import com.google.gerrit.client.ui.FancyFlexTable;
 import com.google.gerrit.client.ui.HintTextBox;
-import com.google.gerrit.common.data.GitwebLink;
 import com.google.gerrit.common.data.ListBranchesResult;
 import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.common.errors.InvalidRevisionException;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.event.dom.client.ClickEvent;
@@ -226,7 +226,7 @@
       fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().iconHeader());
       fmt.addStyleName(0, 2, Gerrit.RESOURCES.css().dataHeader());
       fmt.addStyleName(0, 3, Gerrit.RESOURCES.css().dataHeader());
-      if (Gerrit.getConfig().getGitwebLink() != null) {
+      if (Gerrit.getGitwebLink() != null) {
         fmt.addStyleName(0, 4, Gerrit.RESOURCES.css().dataHeader());
       }
     }
@@ -293,7 +293,7 @@
     }
 
     void populate(final int row, final Branch k) {
-      final GitwebLink c = Gerrit.getConfig().getGitwebLink();
+      final GitwebLink c = Gerrit.getGitwebLink();
 
       if (k.getCanDelete()) {
         table.setWidget(row, 1, new CheckBox());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
index a85fe0e..944a169 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectInfoScreen.java
@@ -20,8 +20,8 @@
 import com.google.gerrit.client.ui.OnEditEnabler;
 import com.google.gerrit.client.ui.SmallHeading;
 import com.google.gerrit.common.data.ProjectDetail;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.SubmitType;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.SubmitType;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
 import com.google.gwt.event.dom.client.ClickEvent;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
index d89676c..3599c3c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectListScreen.java
@@ -22,7 +22,7 @@
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.ProjectList;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.user.client.History;
 import com.google.gwt.user.client.ui.VerticalPanel;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectScreen.java
index 392f295..ccfe2e6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/ProjectScreen.java
@@ -18,7 +18,7 @@
 
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.ui.MenuScreen;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 public abstract class ProjectScreen extends MenuScreen {
   public static final String INFO = "info";
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java
index e07829e..6ff9bff 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/RangeBox.java
@@ -20,8 +20,8 @@
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.IntegerBox;
-import com.google.gwt.user.client.ui.ValueListBox;
 import com.google.gwt.user.client.ui.ValueBoxBase.TextAlignment;
+import com.google.gwt.user.client.ui.ValueListBox;
 
 import java.io.IOException;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/Util.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/Util.java
index e3bcab1..aa5b7b6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/Util.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/admin/Util.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.common.data.GroupAdminService;
 import com.google.gerrit.common.data.ProjectAdminService;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.core.client.GWT;
 import com.google.gwtjsonrpc.client.JsonUtil;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/auth/userpass/UserPassMessages.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/auth/userpass/UserPassMessages.java
index 2991dc9..ccdd1ec 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/auth/userpass/UserPassMessages.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/auth/userpass/UserPassMessages.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.client.auth.userpass;
 
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gwt.i18n.client.Messages;
 
 public interface UserPassMessages extends Messages {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
index f5f3245..1d881b6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/AccountDashboardScreen.java
@@ -22,7 +22,7 @@
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.AccountDashboardInfo;
 import com.google.gerrit.common.data.AccountInfo;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 
 public class AccountDashboardScreen extends Screen implements ChangeListScreen {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java
index d775bbc..09716cc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ApprovalTable.java
@@ -21,9 +21,9 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.patches.PatchUtil;
 import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.ReviewerSuggestOracle;
 import com.google.gerrit.client.ui.AccountDashboardLink;
 import com.google.gerrit.client.ui.AddMemberBox;
+import com.google.gerrit.client.ui.ReviewerSuggestOracle;
 import com.google.gerrit.common.data.AccountInfoCache;
 import com.google.gerrit.common.data.ApprovalDetail;
 import com.google.gerrit.common.data.ApprovalType;
@@ -31,9 +31,9 @@
 import com.google.gerrit.common.data.ChangeDetail;
 import com.google.gerrit.common.data.ReviewerResult;
 import com.google.gerrit.common.data.SubmitRecord;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.DOM;
@@ -134,13 +134,12 @@
   }
 
   void display(ChangeDetail detail) {
-    reviewerSuggestOracle.setProject(detail.getChange().getProject());
+    changeId = detail.getChange().getId();
+    reviewerSuggestOracle.setChange(changeId);
 
     List<String> columns = new ArrayList<String>();
     List<ApprovalDetail> rows = detail.getApprovals();
 
-    changeId = detail.getChange().getId();
-
     final Element missingList = missing.getElement();
     while (DOM.getChildCount(missingList) > 0) {
       DOM.removeChild(missingList, DOM.getChild(missingList, 0));
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeCache.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeCache.java
new file mode 100644
index 0000000..27f76f6
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeCache.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.changes;
+
+import com.google.gerrit.client.ui.ListenableValue;
+import com.google.gerrit.common.data.ChangeInfo;
+import com.google.gerrit.reviewdb.client.Change;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** A Cache to store common client side data by change */
+public class ChangeCache {
+  private static Map<Change.Id, ChangeCache> caches =
+    new HashMap<Change.Id, ChangeCache>();
+
+  public static ChangeCache get(Change.Id chg) {
+    ChangeCache cache = caches.get(chg);
+    if (cache == null) {
+      cache = new ChangeCache(chg);
+      caches.put(chg, cache);
+    }
+    return cache;
+  }
+
+  private Change.Id changeId;
+  private ChangeDetailCache detail;
+  private ListenableValue<ChangeInfo> info;
+  private StarCache starred;
+
+  protected ChangeCache(Change.Id chg) {
+    changeId = chg;
+  }
+
+  public Change.Id getChangeId() {
+    return changeId;
+  }
+
+  public ChangeDetailCache getChangeDetailCache() {
+    if (detail == null) {
+      detail = new ChangeDetailCache(changeId);
+    }
+    return detail;
+  }
+
+  public ListenableValue<ChangeInfo> getChangeInfoCache() {
+    if (info == null) {
+      info = new ListenableValue<ChangeInfo>();
+    }
+    return info;
+  }
+
+  public StarCache getStarCache() {
+    if (starred == null) {
+      starred = new StarCache(changeId);
+    }
+    return starred;
+  }
+}
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 3cddd2b..3372096 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
@@ -111,19 +111,20 @@
   String patchSetInfoParents();
   String initialCommit();
 
+  String buttonRebaseChange();
+
   String buttonRevertChangeBegin();
   String buttonRevertChangeSend();
-  String buttonRevertChangeCancel();
   String headingRevertMessage();
   String revertChangeTitle();
 
   String buttonAbandonChangeBegin();
   String buttonAbandonChangeSend();
-  String buttonAbandonChangeCancel();
   String headingAbandonMessage();
   String abandonChangeTitle();
   String oldVersionHistory();
   String baseDiffItem();
+  String autoMerge();
 
   String buttonReview();
   String buttonPublishCommentsSend();
@@ -134,7 +135,6 @@
 
   String buttonRestoreChangeBegin();
   String restoreChangeTitle();
-  String buttonRestoreChangeCancel();
   String headingRestoreMessage();
   String buttonRestoreChangeSend();
 
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 35991f4..ad70674 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
@@ -90,21 +90,21 @@
 
 buttonAbandonChangeBegin = Abandon Change
 buttonAbandonChangeSend = Abandon Change
-buttonAbandonChangeCancel = Cancel
 headingAbandonMessage = Abandon Message:
 abandonChangeTitle = Code Review - Abandon Change
 oldVersionHistory = Old Version History:
 baseDiffItem = Base
+autoMerge = Auto Merge
+
+buttonRebaseChange = Rebase Change
 
 buttonRevertChangeBegin = Revert Change
 buttonRevertChangeSend = Revert Change
-buttonRevertChangeCancel = Cancel
 headingRevertMessage = Revert Commit Message:
 revertChangeTitle = Code Review - Revert Merged Change
 
 buttonRestoreChangeBegin = Restore Change
 restoreChangeTitle = Code Review - Restore Change
-buttonRestoreChangeCancel = Cancel
 headingRestoreMessage = Restore Message:
 buttonRestoreChangeSend = Restore Change
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java
index 0532326..9282709 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDescriptionBlock.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.client.changes;
 
 import com.google.gerrit.common.data.AccountInfoCache;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.HorizontalPanel;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDetailCache.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDetailCache.java
new file mode 100644
index 0000000..bb28e11
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeDetailCache.java
@@ -0,0 +1,79 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.changes;
+
+import com.google.gerrit.client.ui.ListenableValue;
+import com.google.gerrit.common.data.ChangeDetail;
+import com.google.gerrit.reviewdb.client.Change;
+
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwt.user.client.ui.FocusWidget;
+
+public class ChangeDetailCache extends ListenableValue<ChangeDetail> {
+  public static class GerritCallback extends
+      com.google.gerrit.client.rpc.GerritCallback<ChangeDetail> {
+    @Override
+    public void onSuccess(ChangeDetail detail) {
+      setChangeDetail(detail);
+    }
+  }
+
+  /*
+   * GerritCallback which will re-enable a FocusWidget
+   * {@link com.google.gwt.user.client.ui.FocusWidget} if we are returning
+   * with a failed result.
+   *
+   * It is up to the caller to handle the original disabling of the Widget.
+   */
+  public static class GerritWidgetCallback extends GerritCallback {
+    private FocusWidget widget;
+
+    public GerritWidgetCallback(FocusWidget widget) {
+      this.widget = widget;
+    }
+
+    @Override
+    public void onFailure(Throwable caught) {
+      widget.setEnabled(true);
+      super.onFailure(caught);
+    }
+  }
+
+  public static class IgnoreErrorCallback implements AsyncCallback<ChangeDetail> {
+    @Override
+    public void onSuccess(ChangeDetail detail) {
+      setChangeDetail(detail);
+    }
+
+    @Override
+    public void onFailure(Throwable caught) {
+    }
+  }
+
+  public static void setChangeDetail(ChangeDetail detail) {
+    Change.Id chgId = detail.getChange().getId();
+    ChangeCache.get(chgId).getChangeDetailCache().set(detail);
+  }
+
+  private final Change.Id changeId;
+
+  public ChangeDetailCache(final Change.Id chg) {
+    changeId = chg;
+  }
+
+  public void refresh() {
+    Util.DETAIL_SVC.changeDetail(changeId, new GerritCallback());
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
index eb91180..f8373cc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeInfoBlock.java
@@ -22,8 +22,8 @@
 import com.google.gerrit.client.ui.ChangeLink;
 import com.google.gerrit.client.ui.ProjectLink;
 import com.google.gerrit.common.data.AccountInfoCache;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Grid;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
index 1b382a8..8d5e105 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeScreen.java
@@ -16,8 +16,6 @@
 
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.rpc.ScreenLoadCallback;
 import com.google.gerrit.client.ui.CommentPanel;
 import com.google.gerrit.client.ui.ComplexDisclosurePanel;
 import com.google.gerrit.client.ui.ExpandAllCommand;
@@ -28,17 +26,16 @@
 import com.google.gerrit.common.data.AccountInfoCache;
 import com.google.gerrit.common.data.ChangeDetail;
 import com.google.gerrit.common.data.ChangeInfo;
-import com.google.gerrit.common.data.ToggleStarRequest;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Change.Status;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gwt.event.dom.client.ChangeEvent;
 import com.google.gwt.event.dom.client.ChangeHandler;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.i18n.client.LocaleInfo;
 import com.google.gwt.user.client.ui.DisclosurePanel;
@@ -53,18 +50,19 @@
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
-import com.google.gwtjsonrpc.client.VoidResult;
 
 import java.sql.Timestamp;
 import java.util.List;
 
 
-public class ChangeScreen extends Screen {
+public class ChangeScreen extends Screen
+    implements ValueChangeHandler<ChangeDetail> {
   private final Change.Id changeId;
   private final PatchSet.Id openPatchSetId;
+  private ChangeDetailCache detailCache;
+  private StarCache starred;
 
   private Image starChange;
-  private boolean starred;
   private ChangeDescriptionBlock descriptionBlock;
   private ApprovalTable approvals;
 
@@ -130,7 +128,7 @@
   @Override
   protected void onLoad() {
     super.onLoad();
-    refresh();
+    detailCache.refresh();
   }
 
   @Override
@@ -156,33 +154,17 @@
     }
   }
 
-  public void refresh() {
-    Util.DETAIL_SVC.changeDetail(changeId,
-        new ScreenLoadCallback<ChangeDetail>(this) {
-          @Override
-          protected void preDisplay(final ChangeDetail r) {
-            display(r);
-          }
-
-          @Override
-          protected void postDisplay() {
-            patchSetsBlock.setRegisterKeys(true);
-          }
-        });
-  }
-
-  private void setStarred(final boolean s) {
-    if (s) {
-      starChange.setResource(Gerrit.RESOURCES.starFilled());
-    } else {
-      starChange.setResource(Gerrit.RESOURCES.starOpen());
-    }
-    starred = s;
-  }
-
   @Override
   protected void onInitUI() {
     super.onInitUI();
+
+    ChangeCache cache = ChangeCache.get(changeId);
+
+    detailCache = cache.getChangeDetailCache();
+    detailCache.addValueChangeHandler(this);
+
+    starred = cache.getStarCache();
+
     addStyleName(Gerrit.RESOURCES.css().changeScreen());
 
     keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
@@ -191,19 +173,12 @@
     keysNavigation.add(new ExpandCollapseDependencySectionKeyCommand(0, 'd', Util.C.expandCollapseDependencies()));
 
     if (Gerrit.isSignedIn()) {
-      keysAction.add(new StarKeyCommand(0, 's', Util.C.changeTableStar()));
+      keysAction.add(starred.new KeyCommand(0, 's', Util.C.changeTableStar()));
       keysAction.add(new PublishCommentsKeyCommand(0, 'r', Util.C
           .keyPublishComments()));
 
-      starChange = new Image(Gerrit.RESOURCES.starOpen());
+      starChange = starred.createStar();
       starChange.setStyleName(Gerrit.RESOURCES.css().changeScreenStarIcon());
-      starChange.setVisible(Gerrit.isSignedIn());
-      starChange.addClickHandler(new ClickHandler() {
-        @Override
-        public void onClick(final ClickEvent event) {
-          toggleStar();
-        }
-      });
       setTitleWest(starChange);
     }
 
@@ -250,7 +225,6 @@
         }
       }
     });
-    patchesList.addItem(Util.C.baseDiffItem());
 
     patchesGrid = new Grid(1, 2);
     patchesGrid.setStyleName(Gerrit.RESOURCES.css().selectPatchSetOldVersion());
@@ -258,7 +232,7 @@
     patchesGrid.setWidget(0, 1, patchesList);
     add(patchesGrid);
 
-    patchSetsBlock = new PatchSetsBlock(this);
+    patchSetsBlock = new PatchSetsBlock();
     add(patchSetsBlock);
 
     comments = new FlowPanel();
@@ -284,18 +258,16 @@
     setPageTitle(titleBuf.toString());
   }
 
-  void update(final ChangeDetail detail) {
-    display(detail);
-    patchSetsBlock.setRegisterKeys(true);
+  @Override
+  public void onValueChange(ValueChangeEvent<ChangeDetail> event) {
+    if (isAttached()) {
+      display(event.getValue());
+    }
   }
 
   private void display(final ChangeDetail detail) {
     displayTitle(detail.getChange().getKey(), detail.getChange().getSubject());
 
-    if (starChange != null) {
-      setStarred(detail.isStarred());
-    }
-
     if (Status.MERGED == detail.getChange().getStatus()) {
       includedInPanel.setVisible(true);
       includedInPanel.addOpenHandler(includedInTable);
@@ -312,6 +284,11 @@
     neededBy.display(detail.getNeededBy());
     approvals.display(detail);
 
+    if (detail.getCurrentPatchSetDetail().getInfo().getParents().size() > 1) {
+      patchesList.addItem(Util.C.autoMerge());
+    } else {
+      patchesList.addItem(Util.C.baseDiffItem());
+    }
     for (PatchSet pId : detail.getPatchSets()) {
       if (patchesList != null) {
         patchesList.addItem(Util.M.patchSetHeader(pId.getPatchSetId()), pId
@@ -344,10 +321,17 @@
     }
 
     dependenciesPanel.setOpen(depsOpen);
+
+    dependenciesPanel.getHeader().clear();
     if (outdated > 0) {
       dependenciesPanel.getHeader().add(new InlineLabel(
         Util.M.outdatedHeader(outdated)));
     }
+
+    if (!isCurrentView()) {
+      display();
+    }
+    patchSetsBlock.setRegisterKeys(true);
   }
 
   private void addComments(final ChangeDetail detail) {
@@ -417,24 +401,6 @@
     return menuBar;
   }
 
-  private void toggleStar() {
-    final boolean prior = starred;
-    setStarred(!prior);
-
-    final ToggleStarRequest req = new ToggleStarRequest();
-    req.toggle(changeId, starred);
-    Util.LIST_SVC.toggleStars(req, new GerritCallback<VoidResult>() {
-      public void onSuccess(final VoidResult result) {
-      }
-
-      @Override
-      public void onFailure(final Throwable caught) {
-        super.onFailure(caught);
-        setStarred(prior);
-      }
-    });
-  }
-
   public class UpToListKeyCommand extends KeyCommand {
     public UpToListKeyCommand(int mask, char key, String help) {
       super(mask, key, help);
@@ -457,17 +423,6 @@
     }
   }
 
-  public class StarKeyCommand extends NeedsSignInKeyCommand {
-    public StarKeyCommand(int mask, char key, String help) {
-      super(mask, key, help);
-    }
-
-    @Override
-    public void onKeyPress(final KeyPressEvent event) {
-      toggleStar();
-    }
-  }
-
   public class PublishCommentsKeyCommand extends NeedsSignInKeyCommand {
     public PublishCommentsKeyCommand(int mask, char key, String help) {
       super(mask, key, help);
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 3b71ee2..5a568f1 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
@@ -33,29 +33,25 @@
 import com.google.gerrit.common.data.ApprovalSummarySet;
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ChangeInfo;
-import com.google.gerrit.common.data.ToggleStarRequest;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyCodes;
 import com.google.gwt.event.dom.client.KeyPressEvent;
-import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
 import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTMLTable.Cell;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.InlineLabel;
 import com.google.gwt.user.client.ui.UIObject;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
-import com.google.gwt.user.client.ui.HTMLTable.Cell;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
-import com.google.gwtjsonrpc.client.VoidResult;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -136,7 +132,7 @@
           return;
         }
         if (cell.getCellIndex() == C_STAR) {
-          onStarClick(cell.getRowIndex());
+          // Don't do anything (handled by star itself).
         } else if (cell.getCellIndex() == C_OWNER) {
           // Don't do anything.
         } else if (getRowItem(cell.getRowIndex()) != null) {
@@ -149,23 +145,7 @@
   protected void onStarClick(final int row) {
     final ChangeInfo c = getRowItem(row);
     if (c != null && Gerrit.isSignedIn()) {
-      final boolean prior = c.isStarred();
-      c.setStarred(!prior);
-      setStar(row, c);
-
-      final ToggleStarRequest req = new ToggleStarRequest();
-      req.toggle(c.getId(), c.isStarred());
-      Util.LIST_SVC.toggleStars(req, new GerritCallback<VoidResult>() {
-        public void onSuccess(final VoidResult result) {
-        }
-
-        @Override
-        public void onFailure(final Throwable caught) {
-          super.onFailure(caught);
-          c.setStarred(prior);
-          setStar(row, c);
-        }
-      });
+       ChangeCache.get(c.getId()).getStarCache().toggleStar();
     }
   }
 
@@ -212,10 +192,13 @@
   }
 
   private void populateChangeRow(final int row, final ChangeInfo c) {
+    ChangeCache cache = ChangeCache.get(c.getId());
+    cache.getChangeInfoCache().set(c);
+
     final String idstr = c.getKey().abbreviate();
     table.setWidget(row, C_ARROW, null);
     if (Gerrit.isSignedIn()) {
-      setStar(row, c);
+      table.setWidget(row, C_STAR, cache.getStarCache().createStar());
     }
     table.setWidget(row, C_ID, new TableChangeLink(idstr, c));
 
@@ -229,7 +212,10 @@
     if (! c.isLatest()) {
       s += " [OUTDATED]";
       table.getRowFormatter().addStyleName(row, Gerrit.RESOURCES.css().outdated());
+    } else {
+      table.getRowFormatter().removeStyleName(row, Gerrit.RESOURCES.css().outdated());
     }
+
     table.setWidget(row, C_SUBJECT, new TableChangeLink(s, c));
     table.setWidget(row, C_OWNER, link(c.getOwner()));
     table.setWidget(row, C_PROJECT, new ProjectLink(c.getProject().getKey(), c
@@ -244,22 +230,6 @@
     return AccountDashboardLink.link(accountCache, id);
   }
 
-  private void setStar(final int row, final ChangeInfo c) {
-    final ImageResource star;
-    if (c.isStarred()) {
-      star = Gerrit.RESOURCES.starFilled();
-    } else {
-      star = Gerrit.RESOURCES.starOpen();
-    }
-
-    final Widget i = table.getWidget(row, C_STAR);
-    if (i instanceof Image) {
-      ((Image) i).setResource(star);
-    } else {
-      table.setWidget(row, C_STAR, new Image(star));
-    }
-  }
-
   public void addSection(final Section s) {
     assert s.parent == null;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentedChangeActionDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentedChangeActionDialog.java
deleted file mode 100644
index 01d6299..0000000
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/CommentedChangeActionDialog.java
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.client.changes;
-
-import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.client.ui.SmallHeading;
-import com.google.gerrit.common.data.ChangeDetail;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.logical.shared.CloseEvent;
-import com.google.gwt.event.logical.shared.CloseHandler;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwtexpui.globalkey.client.GlobalKey;
-import com.google.gwtexpui.globalkey.client.NpTextArea;
-import com.google.gwtexpui.user.client.AutoCenterDialogBox;
-
-public abstract class CommentedChangeActionDialog extends AutoCenterDialogBox implements CloseHandler<PopupPanel>{
-  private final FlowPanel panel;
-  private final NpTextArea message;
-  private final Button sendButton;
-  private final Button cancelButton;
-  private final PatchSet.Id psid;
-  private final AsyncCallback<ChangeDetail> callback;
-
-  private boolean buttonClicked = false;
-
-  public CommentedChangeActionDialog(final PatchSet.Id psi,
-      final AsyncCallback<ChangeDetail> callback, final String dialogTitle,
-      final String dialogHeading, final String buttonSend,
-      final String buttonCancel, final String dialogStyle,
-      final String messageStyle) {
-     this(psi, callback, dialogTitle, dialogHeading, buttonSend, buttonCancel, dialogStyle, messageStyle, null);
-  }
-
-  public CommentedChangeActionDialog(final PatchSet.Id psi,
-      final AsyncCallback<ChangeDetail> callback, final String dialogTitle,
-      final String dialogHeading, final String buttonSend,
-      final String buttonCancel, final String dialogStyle,
-      final String messageStyle, final String defaultMessage) {
-    super(/* auto hide */false, /* modal */true);
-    setGlassEnabled(true);
-
-    psid = psi;
-    this.callback = callback;
-    addStyleName(dialogStyle);
-    setText(dialogTitle);
-
-    panel = new FlowPanel();
-    add(panel);
-
-    panel.add(new SmallHeading(dialogHeading));
-
-    final FlowPanel mwrap = new FlowPanel();
-    mwrap.setStyleName(messageStyle);
-    panel.add(mwrap);
-
-    message = new NpTextArea();
-    message.setCharacterWidth(60);
-    message.setVisibleLines(10);
-    message.setText(defaultMessage);
-    DOM.setElementPropertyBoolean(message.getElement(), "spellcheck", true);
-    mwrap.add(message);
-
-    final FlowPanel buttonPanel = new FlowPanel();
-    panel.add(buttonPanel);
-    sendButton = new Button(buttonSend);
-    sendButton.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(final ClickEvent event) {
-        sendButton.setEnabled(false);
-        cancelButton.setEnabled(false);
-        onSend();
-      }
-    });
-    buttonPanel.add(sendButton);
-
-    cancelButton = new Button(buttonCancel);
-    DOM.setStyleAttribute(cancelButton.getElement(), "marginLeft", "300px");
-    cancelButton.addClickHandler(new ClickHandler() {
-      @Override
-      public void onClick(final ClickEvent event) {
-        buttonClicked = true;
-        if (callback != null) {
-          callback.onFailure(null);
-        }
-        hide();
-      }
-    });
-    buttonPanel.add(cancelButton);
-
-    addCloseHandler(this);
-  }
-
-  @Override
-  public void center() {
-    super.center();
-    GlobalKey.dialog(this);
-    message.setFocus(true);
-  }
-
-  @Override
-  public void onClose(CloseEvent<PopupPanel> event) {
-    if (!buttonClicked) {
-      // the dialog was closed without one of the buttons being pressed
-      // e.g. the user pressed ESC to close the dialog
-      if (callback != null) {
-        callback.onFailure(null);
-      }
-    }
-  }
-
-  public abstract void onSend();
-
-  public PatchSet.Id getPatchSetId() {
-    return psid;
-  }
-
-  public String getMessageText() {
-    return message.getText().trim();
-  }
-
-  public GerritCallback<ChangeDetail> createCallback() {
-    return new GerritCallback<ChangeDetail>(){
-      @Override
-      public void onSuccess(ChangeDetail result) {
-        buttonClicked = true;
-        if (callback != null) {
-          callback.onSuccess(result);
-        }
-        hide();
-      }
-
-      @Override
-      public void onFailure(Throwable caught) {
-        sendButton.setEnabled(true);
-        cancelButton.setEnabled(true);
-        super.onFailure(caught);
-      }
-    };
-  }
-}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandLink.java
index 53771a97..c095d4d 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandLink.java
@@ -15,14 +15,14 @@
 package com.google.gerrit.client.changes;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.ui.Accessibility;
 import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 abstract class DownloadCommandLink extends Anchor implements ClickHandler {
   final AccountGeneralPreferences.DownloadCommand cmdType;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandPanel.java
index 0affcfb..1516da1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadCommandPanel.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.client.changes;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences.DownloadCommand;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
 import com.google.gwt.user.client.ui.Accessibility;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Widget;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlLink.java
index 6e72e20..2afafaa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlLink.java
@@ -15,14 +15,14 @@
 package com.google.gerrit.client.changes;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.ui.Accessibility;
 import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 class DownloadUrlLink extends Anchor implements ClickHandler {
   final AccountGeneralPreferences.DownloadScheme urlType;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlPanel.java
index f4260e2..b3c9ebc 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/DownloadUrlPanel.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.client.changes;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.user.client.ui.Accessibility;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Widget;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/IncludedInTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/IncludedInTable.java
index 533999d..3a1ccde 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/IncludedInTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/IncludedInTable.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.common.data.IncludedInDetail;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gwt.event.logical.shared.OpenEvent;
 import com.google.gwt.event.logical.shared.OpenHandler;
 import com.google.gwt.user.client.ui.Composite;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
index 6ca102f..72300b2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PagedSingleListScreen.java
@@ -21,10 +21,10 @@
 import com.google.gerrit.client.ui.Screen;
 import com.google.gerrit.common.data.ChangeInfo;
 import com.google.gerrit.common.data.SingleListChangeInfo;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
 import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwt.user.client.History;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.ui.HorizontalPanel;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
index d3c3f76..81b4f14 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetComplexDisclosurePanel.java
@@ -17,57 +17,59 @@
 import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.FormatUtil;
 import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.GitwebLink;
 import com.google.gerrit.client.patches.PatchUtil;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.AccountDashboardLink;
+import com.google.gerrit.client.ui.CommentedActionDialog;
 import com.google.gerrit.client.ui.ComplexDisclosurePanel;
 import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.ChangeDetail;
-import com.google.gerrit.common.data.GitwebLink;
 import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences.DownloadCommand;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences.DownloadScheme;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.UserIdentity;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.UserIdentity;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadCommand;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.logical.shared.OpenEvent;
 import com.google.gwt.event.logical.shared.OpenHandler;
 import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.Anchor;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.DisclosurePanel;
 import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusWidget;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwt.user.client.ui.InlineLabel;
 import com.google.gwt.user.client.ui.Panel;
 import com.google.gwtexpui.clippy.client.CopyableLabel;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements OpenHandler<DisclosurePanel> {
+class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel
+    implements OpenHandler<DisclosurePanel> {
   private static final int R_AUTHOR = 0;
   private static final int R_COMMITTER = 1;
   private static final int R_PARENTS = 2;
   private static final int R_DOWNLOAD = 3;
   private static final int R_CNT = 4;
 
-  private final ChangeScreen changeScreen;
+  private final ChangeDetailCache detailCache;
   private final ChangeDetail changeDetail;
   private final PatchSet patchSet;
   private final FlowPanel body;
@@ -83,38 +85,22 @@
    * Creates a closed complex disclosure panel for a patch set.
    * The patch set details are loaded when the complex disclosure panel is opened.
    */
-  PatchSetComplexDisclosurePanel(final ChangeScreen parent, final ChangeDetail detail,
-      final PatchSet ps) {
-    this(parent, detail, ps, false);
-    addOpenHandler(this);
-  }
-
-  /**
-   * Creates an open complex disclosure panel for a patch set.
-   */
-  PatchSetComplexDisclosurePanel(final ChangeScreen parent, final ChangeDetail detail,
-      final PatchSetDetail psd) {
-    this(parent, detail, psd.getPatchSet(), true);
-    ensureLoaded(psd);
-  }
-
-  private PatchSetComplexDisclosurePanel(final ChangeScreen parent, final ChangeDetail detail,
-      final PatchSet ps, boolean isOpen) {
+  public PatchSetComplexDisclosurePanel(final PatchSet ps, boolean isOpen) {
     super(Util.M.patchSetHeader(ps.getPatchSetId()), isOpen);
-    changeScreen = parent;
-    changeDetail = detail;
+    detailCache = ChangeCache.get(ps.getId().getParentKey()).getChangeDetailCache();
+    changeDetail = detailCache.get();
     patchSet = ps;
+
     body = new FlowPanel();
     setContent(body);
 
-    final GitwebLink gw = Gerrit.getConfig().getGitwebLink();
-
+    final GitwebLink gw = Gerrit.getGitwebLink();
     final InlineLabel revtxt = new InlineLabel(ps.getRevision().get() + " ");
     revtxt.addStyleName(Gerrit.RESOURCES.css().patchSetRevision());
     getHeader().add(revtxt);
     if (gw != null) {
       final Anchor revlink =
-          new Anchor(gw.getLinkName(), false, gw.toRevision(detail.getChange()
+          new Anchor(gw.getLinkName(), false, gw.toRevision(changeDetail.getChange()
               .getProject(), ps));
       revlink.addStyleName(Gerrit.RESOURCES.css().patchSetLink());
       getHeader().add(revlink);
@@ -125,6 +111,12 @@
       draftLabel.addStyleName(Gerrit.RESOURCES.css().patchSetRevision());
       getHeader().add(draftLabel);
     }
+
+    if (isOpen) {
+      ensureLoaded(changeDetail.getCurrentPatchSetDetail());
+    } else {
+      addOpenHandler(this);
+    }
   }
 
   public void setDiffBaseId(PatchSet.Id diffBaseId) {
@@ -165,8 +157,7 @@
     if (!patchSet.getId().equals(diffBaseId)) {
       patchTable = new PatchTable();
       patchTable.setSavePointerId("PatchTable " + patchSet.getId());
-      patchTable.setPatchSetIdToCompareWith(diffBaseId);
-      patchTable.display(detail);
+      patchTable.display(diffBaseId, detail);
 
       actionsPanel = new FlowPanel();
       actionsPanel.setStyleName(Gerrit.RESOURCES.css().patchSetActions());
@@ -468,15 +459,22 @@
         @Override
         public void onClick(final ClickEvent event) {
           b.setEnabled(false);
-          new CommentedChangeActionDialog(patchSet.getId(), createCommentedCallback(b, true),
-              Util.C.revertChangeTitle(), Util.C.headingRevertMessage(),
-              Util.C.buttonRevertChangeSend(), Util.C.buttonRevertChangeCancel(),
-              Gerrit.RESOURCES.css().revertChangeDialog(), Gerrit.RESOURCES.css().revertMessage(),
-              Util.M.revertChangeDefaultMessage(detail.getInfo().getSubject(), detail.getPatchSet().getRevision().get())) {
-                public void onSend() {
-                  Util.MANAGE_SVC.revertChange(getPatchSetId() , getMessageText(), createCallback());
-                }
-              }.center();
+          new ActionDialog(b, true, Util.C.revertChangeTitle(),
+              Util.C.headingRevertMessage()) {
+            {
+              sendButton.setText(Util.C.buttonRevertChangeSend());
+              message.setText(Util.M.revertChangeDefaultMessage(
+                  detail.getInfo().getSubject(),
+                  detail.getPatchSet().getRevision().get())
+              );
+            }
+
+            @Override
+            public void onSend() {
+              Util.MANAGE_SVC.revertChange(patchSet.getId(), getMessageText(),
+                 createCallback());
+            }
+          }.center();
         }
       });
       actionsPanel.add(b);
@@ -488,14 +486,18 @@
         @Override
         public void onClick(final ClickEvent event) {
           b.setEnabled(false);
-          new CommentedChangeActionDialog(patchSet.getId(), createCommentedCallback(b, false),
-              Util.C.abandonChangeTitle(), Util.C.headingAbandonMessage(),
-              Util.C.buttonAbandonChangeSend(), Util.C.buttonAbandonChangeCancel(),
-              Gerrit.RESOURCES.css().abandonChangeDialog(), Gerrit.RESOURCES.css().abandonMessage()) {
-                public void onSend() {
-                  Util.MANAGE_SVC.abandonChange(getPatchSetId() , getMessageText(), createCallback());
-                }
-              }.center();
+          new ActionDialog(b, false, Util.C.abandonChangeTitle(),
+              Util.C.headingAbandonMessage()) {
+            {
+              sendButton.setText(Util.C.buttonAbandonChangeSend());
+            }
+
+            @Override
+            public void onSend() {
+              Util.MANAGE_SVC.abandonChange(patchSet.getId(), getMessageText(),
+                  createCallback());
+            }
+          }.center();
         }
       });
       actionsPanel.add(b);
@@ -531,14 +533,31 @@
         @Override
         public void onClick(final ClickEvent event) {
           b.setEnabled(false);
-          new CommentedChangeActionDialog(patchSet.getId(), createCommentedCallback(b, false),
-              Util.C.restoreChangeTitle(), Util.C.headingRestoreMessage(),
-              Util.C.buttonRestoreChangeSend(), Util.C.buttonRestoreChangeCancel(),
-              Gerrit.RESOURCES.css().abandonChangeDialog(), Gerrit.RESOURCES.css().abandonMessage()) {
-                public void onSend() {
-                  Util.MANAGE_SVC.restoreChange(getPatchSetId(), getMessageText(), createCallback());
-                }
-              }.center();
+          new ActionDialog(b, false, Util.C.restoreChangeTitle(),
+              Util.C.headingRestoreMessage()) {
+            {
+              sendButton.setText(Util.C.buttonRestoreChangeSend());
+            }
+
+            @Override
+            public void onSend() {
+              Util.MANAGE_SVC.restoreChange(patchSet.getId(), getMessageText(),
+                  createCallback());
+            }
+          }.center();
+        }
+      });
+      actionsPanel.add(b);
+    }
+
+    if (changeDetail.canRebase()) {
+      final Button b = new Button(Util.C.buttonRebaseChange());
+      b.addClickHandler(new ClickHandler() {
+        @Override
+        public void onClick(final ClickEvent event) {
+          b.setEnabled(false);
+          Util.MANAGE_SVC.rebaseChange(patchSet.getId(),
+              new ChangeDetailCache.GerritWidgetCallback(b));
         }
       });
       actionsPanel.add(b);
@@ -548,12 +567,10 @@
   private void populateDiffAllActions(final PatchSetDetail detail) {
     final Button diffAllSideBySide = new Button(Util.C.buttonDiffAllSideBySide());
     diffAllSideBySide.addClickHandler(new ClickHandler() {
-
       @Override
       public void onClick(ClickEvent event) {
         for (Patch p : detail.getPatches()) {
-          Window.open(Window.Location.getPath() + "#"
-              + Dispatcher.toPatchSideBySide(p.getKey()), "_blank", null);
+          openWindow(Dispatcher.toPatchSideBySide(diffBaseId, p.getKey()));
         }
       }
     });
@@ -561,18 +578,21 @@
 
     final Button diffAllUnified = new Button(Util.C.buttonDiffAllUnified());
     diffAllUnified.addClickHandler(new ClickHandler() {
-
       @Override
       public void onClick(ClickEvent event) {
         for (Patch p : detail.getPatches()) {
-          Window.open(Window.Location.getPath() + "#"
-              + Dispatcher.toPatchUnified(p.getKey()), "_blank", null);
+          openWindow(Dispatcher.toPatchUnified(diffBaseId, p.getKey()));
         }
       }
     });
     actionsPanel.add(diffAllUnified);
   }
 
+  private void openWindow(String token) {
+    String url = Window.Location.getPath() + "#" + token;
+    Window.open(url, "_blank", null);
+  }
+
   private void populateReviewAction() {
     final Button b = new Button(Util.C.buttonReview());
     b.addClickHandler(new ClickHandler() {
@@ -593,7 +613,7 @@
         Util.MANAGE_SVC.publish(patchSet.getId(),
             new GerritCallback<ChangeDetail>() {
               public void onSuccess(ChangeDetail result) {
-                changeScreen.update(result);
+                detailCache.set(result);
               }
 
               @Override
@@ -617,7 +637,7 @@
             new GerritCallback<ChangeDetail>() {
               public void onSuccess(final ChangeDetail result) {
                 if (result != null) {
-                  changeScreen.update(result);
+                  detailCache.set(result);
                 } else {
                   Gerrit.display(PageLinks.MINE);
                 }
@@ -646,18 +666,15 @@
         new GerritCallback<PatchSetDetail>() {
           @Override
           public void onSuccess(PatchSetDetail result) {
-
             if (patchSet.getId().equals(diffBaseId)) {
               patchTable.setVisible(false);
               actionsPanel.setVisible(false);
             } else {
-
               if (patchTable != null) {
                 patchTable.removeFromParent();
               }
               patchTable = new PatchTable();
-              patchTable.setPatchSetIdToCompareWith(diffBaseId);
-              patchTable.display(result);
+              patchTable.display(diffBaseId, result);
               body.add(patchTable);
 
               for (ClickHandler clickHandler : registeredClickHandler) {
@@ -713,7 +730,7 @@
         new SubmitFailureDialog(result, msg).center();
       }
     }
-    changeScreen.update(result);
+    detailCache.set(result);
   }
 
   public PatchSet getPatchSet() {
@@ -739,19 +756,24 @@
     }
   }
 
-  private AsyncCallback<ChangeDetail> createCommentedCallback(final Button b, final boolean redirect) {
-    return new AsyncCallback<ChangeDetail>() {
-      public void onSuccess(ChangeDetail result) {
-        if (redirect) {
-          Gerrit.display(PageLinks.toChange(result.getChange().getId()));
-        } else {
-          changeScreen.update(result);
-        }
-      }
+  private abstract class ActionDialog extends CommentedActionDialog<ChangeDetail> {
+    public ActionDialog(final FocusWidget enableOnFailure, final boolean redirect,
+        String dialogTitle, String dialogHeading) {
+      super(dialogTitle, dialogHeading, new ChangeDetailCache.IgnoreErrorCallback() {
+          @Override
+          public void onSuccess(ChangeDetail result) {
+            if (redirect) {
+              Gerrit.display(PageLinks.toChange(result.getChange().getId()));
+            } else {
+              super.onSuccess(result);
+            }
+          }
 
-      public void onFailure(Throwable caught) {
-        b.setEnabled(true);
-      }
-    };
+          @Override
+          public void onFailure(Throwable caught) {
+            enableOnFailure.setEnabled(true);
+          }
+        });
+    }
   }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
index e854cab..7e659a1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchSetsBlock.java
@@ -17,8 +17,8 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.ChangeDetail;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.KeyPressEvent;
@@ -43,11 +43,9 @@
  * that keyboard navigation to each changed file in all patch sets is possible.
  */
 public class PatchSetsBlock extends Composite {
-
   private final Map<PatchSet.Id, PatchSetComplexDisclosurePanel> patchSetPanels =
       new HashMap<PatchSet.Id, PatchSetComplexDisclosurePanel>();
 
-  private final ChangeScreen parent;
   private final FlowPanel body;
   private HandlerRegistration regNavigation;
 
@@ -65,8 +63,7 @@
   /** Patch sets on this change, in order. */
   private List<PatchSet> patchSets;
 
-  PatchSetsBlock(final ChangeScreen parent) {
-    this.parent = parent;
+  PatchSetsBlock() {
     body = new FlowPanel();
     initWidget(body);
   }
@@ -79,12 +76,6 @@
     currentPatchSetId = currps.getId();
     patchSets = detail.getPatchSets();
 
-    final List<PatchSet.Id> changePatchSets = new ArrayList<PatchSet.Id>();
-
-    for (final PatchSet ps : patchSets) {
-      changePatchSets.add(ps.getId());
-    }
-
     if (Gerrit.isSignedIn()) {
       final AccountGeneralPreferences p =
           Gerrit.getUserAccount().getGeneralPreferences();
@@ -96,19 +87,13 @@
     patchSetPanelsList = new ArrayList<PatchSetComplexDisclosurePanel>();
 
     for (final PatchSet ps : patchSets) {
-      final PatchSetComplexDisclosurePanel p;
-      if (ps == currps) {
-        p = new PatchSetComplexDisclosurePanel(parent, detail, detail
-            .getCurrentPatchSetDetail());
-        if (diffBaseId != null) {
-          p.setDiffBaseId(diffBaseId);
+      final PatchSetComplexDisclosurePanel p =
+          new PatchSetComplexDisclosurePanel(ps, ps == currps);
+      if (diffBaseId != null) {
+        p.setDiffBaseId(diffBaseId);
+        if (ps == currps) {
           p.refresh();
         }
-      } else {
-        p = new PatchSetComplexDisclosurePanel(parent, detail, ps);
-        if (diffBaseId != null) {
-          p.setDiffBaseId(diffBaseId);
-        }
       }
       add(p);
       patchSetPanelsList.add(p);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
index a028619..7177525 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
@@ -21,11 +21,11 @@
 import com.google.gerrit.client.ui.NavigationTable;
 import com.google.gerrit.client.ui.PatchLink;
 import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Patch.ChangeType;
-import com.google.gerrit.reviewdb.Patch.Key;
-import com.google.gerrit.reviewdb.Patch.PatchType;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Patch.ChangeType;
+import com.google.gerrit.reviewdb.client.Patch.Key;
+import com.google.gerrit.reviewdb.client.Patch.PatchType;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.RepeatingCommand;
@@ -55,6 +55,7 @@
   private Command onLoadCommand;
   private MyTable myTable;
   private String savePointerId;
+  private PatchSet.Id base;
   private List<Patch> patchList;
   private ListenableAccountDiffPreference listenablePrefs;
 
@@ -62,8 +63,6 @@
   private boolean active;
   private boolean registerKeys;
 
-  private PatchSet.Id patchSetIdToCompareWith;
-
   public PatchTable(ListenableAccountDiffPreference prefs) {
     listenablePrefs = prefs;
     myBody = new FlowPanel();
@@ -83,12 +82,13 @@
     return -1;
   }
 
-  public void display(PatchSetDetail detail) {
+  public void display(PatchSet.Id base, PatchSetDetail detail) {
+    this.base = base;
     this.detail = detail;
     this.patchList = detail.getPatches();
     myTable = null;
 
-    final DisplayCommand cmd = new DisplayCommand(patchList, patchSetIdToCompareWith);
+    final DisplayCommand cmd = new DisplayCommand(patchList, base);
     if (cmd.execute()) {
       cmd.initMeter();
       Scheduler.get().scheduleIncremental(cmd);
@@ -223,9 +223,9 @@
     PatchLink link;
     if (patchType == PatchScreen.Type.SIDE_BY_SIDE
         && patch.getPatchType() == Patch.PatchType.UNIFIED) {
-      link = new PatchLink.SideBySide("", thisKey, index, detail, this);
+      link = new PatchLink.SideBySide("", base, thisKey, index, detail, this);
     } else {
-      link = new PatchLink.Unified("", thisKey, index, detail, this);
+      link = new PatchLink.Unified("", base, thisKey, index, detail, this);
     }
     SafeHtmlBuilder text = new SafeHtmlBuilder();
     text.append(before);
@@ -275,14 +275,6 @@
     listenablePrefs = prefs;
   }
 
-  public PatchSet.Id getPatchSetIdToCompareWith() {
-    return patchSetIdToCompareWith;
-  }
-
-  public void setPatchSetIdToCompareWith(final PatchSet.Id psId) {
-    patchSetIdToCompareWith = psId;
-  }
-
   private class MyTable extends NavigationTable<Patch> {
     private static final int C_PATH = 2;
     private static final int C_DRAFT = 3;
@@ -381,13 +373,11 @@
 
       Widget nameCol;
       if (patch.getPatchType() == Patch.PatchType.UNIFIED) {
-        nameCol =
-            new PatchLink.SideBySide(getDisplayFileName(patch), patch.getKey(),
-                row - 1, detail, PatchTable.this);
+        nameCol = new PatchLink.SideBySide(getDisplayFileName(patch), base,
+            patch.getKey(), row - 1, detail, PatchTable.this);
       } else {
-        nameCol =
-            new PatchLink.Unified(getDisplayFileName(patch), patch.getKey(),
-                row - 1, detail, PatchTable.this);
+        nameCol = new PatchLink.Unified(getDisplayFileName(patch), base,
+            patch.getKey(), row - 1, detail, PatchTable.this);
       }
       if (patch.getSourceFileName() != null) {
         final String text;
@@ -409,16 +399,15 @@
 
       int C_UNIFIED = C_SIDEBYSIDE + 1;
       if (patch.getPatchType() == Patch.PatchType.UNIFIED) {
-        table.setWidget(row, C_SIDEBYSIDE, new PatchLink.SideBySide(Util.C
-            .patchTableDiffSideBySide(), patch.getKey(), row - 1, detail,
-            PatchTable.this));
-
+        table.setWidget(row, C_SIDEBYSIDE, new PatchLink.SideBySide(
+            Util.C.patchTableDiffSideBySide(), base, patch.getKey(), row - 1,
+            detail, PatchTable.this));
       } else if (patch.getPatchType() == Patch.PatchType.BINARY) {
         C_UNIFIED = C_SIDEBYSIDE + 2;
       }
-      table.setWidget(row, C_UNIFIED, new PatchLink.Unified(Util.C
-          .patchTableDiffUnified(), patch.getKey(), row - 1, detail,
-          PatchTable.this));
+      table.setWidget(row, C_UNIFIED, new PatchLink.Unified(
+          Util.C.patchTableDiffUnified(), base, patch.getKey(), row - 1,
+          detail, PatchTable.this));
     }
 
     void appendHeader(final SafeHtmlBuilder m) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
index 03ddfd0..0c08491 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PublishCommentScreen.java
@@ -29,25 +29,25 @@
 import com.google.gerrit.common.data.ChangeDetail;
 import com.google.gerrit.common.data.PatchSetPublishDetail;
 import com.google.gerrit.common.data.PermissionRange;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
 import com.google.gwt.user.client.ui.Panel;
 import com.google.gwt.user.client.ui.RadioButton;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
 import com.google.gwtexpui.globalkey.client.NpTextArea;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -297,8 +297,8 @@
           draftsPanel.add(panel);
           // Parent table can be null here since we are not showing any
           // next/previous links
-          panel.add(new PatchLink.SideBySide(PatchTable
-              .getDisplayFileName(patchKey), patchKey, 0, null, null));
+          panel.add(new PatchLink.SideBySide(
+              PatchTable.getDisplayFileName(patchKey), null, patchKey, 0, null, null));
           priorFile = fn;
         }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
index 5540a6d..cf9c526 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/QueryScreen.java
@@ -19,8 +19,8 @@
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.ChangeInfo;
 import com.google.gerrit.common.data.SingleListChangeInfo;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwtorm.client.KeyUtil;
 
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarCache.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarCache.java
new file mode 100644
index 0000000..d7624a6
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/StarCache.java
@@ -0,0 +1,139 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.changes;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.ui.NeedsSignInKeyCommand;
+import com.google.gerrit.common.data.ChangeDetail;
+import com.google.gerrit.common.data.ChangeInfo;
+import com.google.gerrit.common.data.ToggleStarRequest;
+import com.google.gerrit.reviewdb.client.Change;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.GwtEvent;
+import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.resources.client.ImageResource;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwtjsonrpc.common.VoidResult;
+
+public class StarCache implements HasValueChangeHandlers<Boolean> {
+  public class KeyCommand extends NeedsSignInKeyCommand {
+    public KeyCommand(int mask, char key, String help) {
+      super(mask, key, help);
+    }
+
+    @Override
+    public void onKeyPress(final KeyPressEvent event) {
+      StarCache.this.toggleStar();
+    }
+  }
+
+  ChangeCache cache;
+
+  private HandlerManager manager = new HandlerManager(this);
+
+  public StarCache(final Change.Id chg) {
+    cache = ChangeCache.get(chg);
+  }
+
+  public boolean get() {
+    ChangeDetail detail = cache.getChangeDetailCache().get();
+    if (detail != null) {
+      return detail.isStarred();
+    }
+    ChangeInfo info = cache.getChangeInfoCache().get();
+    if (info != null) {
+      return info.isStarred();
+    }
+    return false;
+  }
+
+  public void set(final boolean s) {
+    if (Gerrit.isSignedIn() && s != get()) {
+      final ToggleStarRequest req = new ToggleStarRequest();
+      req.toggle(cache.getChangeId(), s);
+
+      Util.LIST_SVC.toggleStars(req, new GerritCallback<VoidResult>() {
+        public void onSuccess(final VoidResult result) {
+          setStarred(s);
+          fireEvent(new ValueChangeEvent<Boolean>(s){});
+        }
+      });
+    }
+  }
+
+  private void setStarred(final boolean s) {
+    ChangeDetail detail = cache.getChangeDetailCache().get();
+    if (detail != null) {
+      detail.setStarred(s);
+    }
+    ChangeInfo info = cache.getChangeInfoCache().get();
+    if (info != null) {
+      info.setStarred(s);
+    }
+  }
+
+  public void toggleStar() {
+    set(!get());
+  }
+
+  @SuppressWarnings("unchecked")
+  public Image createStar() {
+    final Image star = new Image(getResource());
+    star.setVisible(Gerrit.isSignedIn());
+
+    star.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(final ClickEvent event) {
+        StarCache.this.toggleStar();
+      }
+    });
+
+    @SuppressWarnings("rawtypes")
+    ValueChangeHandler starUpdater = new ValueChangeHandler() {
+        @Override
+        public void onValueChange(ValueChangeEvent event) {
+          star.setResource(StarCache.this.getResource());
+        }
+      };
+
+    cache.getChangeDetailCache().addValueChangeHandler(starUpdater);
+    cache.getChangeInfoCache().addValueChangeHandler(starUpdater);
+
+    this.addValueChangeHandler(starUpdater);
+
+    return star;
+  }
+
+  private ImageResource getResource() {
+    return get() ? Gerrit.RESOURCES.starFilled() : Gerrit.RESOURCES.starOpen();
+  }
+
+  public void fireEvent(GwtEvent<?> event) {
+    manager.fireEvent(event);
+  }
+
+  public HandlerRegistration addValueChangeHandler(
+      ValueChangeHandler<Boolean> handler) {
+    return manager.addHandler(ValueChangeEvent.getType(), handler);
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitFailureDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitFailureDialog.java
index f9f6f99..bedfb74 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitFailureDialog.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/SubmitFailureDialog.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.client.ErrorDialog;
 import com.google.gerrit.common.data.ChangeDetail;
-import com.google.gerrit.reviewdb.ChangeMessage;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
 class SubmitFailureDialog extends ErrorDialog {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
index 3fe63ed..e84cac8 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/Util.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.common.data.ChangeDetailService;
 import com.google.gerrit.common.data.ChangeListService;
 import com.google.gerrit.common.data.ChangeManageService;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gwt.core.client.GWT;
 import com.google.gwtjsonrpc.client.JsonUtil;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 20837c4..1081e47 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -1209,7 +1209,6 @@
 
 
 /** PublishCommentsScreen **/
-
 .publishCommentsScreen .smallHeading {
   font-size: small;
   font-weight: bold;
@@ -1259,57 +1258,29 @@
 }
 
 
-/** AbandonChangeDialog **/
-
-.abandonChangeDialog .gwt-DisclosurePanel .header td {
+/** CommentedActionDialog **/
+.commentedActionDialog .gwt-DisclosurePanel .header td {
   font-weight: bold;
   white-space: nowrap;
 }
-
-.abandonChangeDialog .smallHeading {
+.commentedActionDialog .smallHeading {
   font-size: small;
   font-weight: bold;
   white-space: nowrap;
 }
-.abandonChangeDialog .abandonMessage {
+.commentedActionDialog .commentedActionMessage {
   margin-left: 10px;
   background: trimColor;
   padding: 5px 5px 5px 5px;
 }
-.abandonChangeDialog .abandonMessage textarea {
+.commentedActionDialog .commentedActionMessage textarea {
   font-size: small;
 }
-.abandonChangeDialog .gwt-Hyperlink {
+.commentedActionDialog .gwt-Hyperlink {
   white-space: nowrap;
   font-size: small;
 }
 
-/** RevertChangeDialog **/
-
-.revertChangeDialog .gwt-DisclosurePanel .header td {
-  font-weight: bold;
-  white-space: nowrap;
-}
-
-.revertChangeDialog .smallHeading {
-  font-size: small;
-  font-weight: bold;
-  white-space: nowrap;
-}
-.revertChangeDialog .revertMessage {
-  margin-left: 10px;
-  background: trimColor;
-  padding: 5px 5px 5px 5px;
-}
-.revertChangeDialog .revertMessage textarea {
-  font-size: small;
-}
-.revertChangeDialog .gwt-Hyperlink {
-  white-space: nowrap;
-  font-size: small;
-}
-
-
 /** PatchBrowserPopup **/
 .patchBrowserPopup {
   opacity: 0.90;
@@ -1339,10 +1310,6 @@
   margin-bottom: 2px;
 }
 .groupOptionsPanel {
-  margin-bottom: 3px;
-}
-.groupOptionsNotificationsDescriptionPanel {
-  margin-top: 5px;
   margin-bottom: 5px;
 }
 .groupOwnerPanel {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
index 396f1bf..8282caa 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/AbstractPatchContentTable.java
@@ -26,10 +26,14 @@
 import com.google.gerrit.common.data.AccountInfoCache;
 import com.google.gerrit.common.data.CommentDetail;
 import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.prettify.client.ClientSideFormatter;
+import com.google.gerrit.prettify.common.PrettyFormatter;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.prettify.common.SparseHtmlFile;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.event.dom.client.BlurEvent;
 import com.google.gwt.event.dom.client.BlurHandler;
 import com.google.gwt.event.dom.client.ClickEvent;
@@ -45,9 +49,9 @@
 import com.google.gwt.user.client.History;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Focusable;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwt.user.client.ui.UIObject;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
@@ -171,6 +175,36 @@
     render(s);
   }
 
+  protected SparseHtmlFile getSparseHtmlFileA(PatchScript s) {
+    AccountDiffPreference dp = new AccountDiffPreference(s.getDiffPrefs());
+    dp.setShowWhitespaceErrors(false);
+
+    PrettyFormatter f = ClientSideFormatter.FACTORY.get();
+    f.setDiffPrefs(dp);
+    f.setFileName(s.getA().getPath());
+    f.setEditFilter(PrettyFormatter.A);
+    f.setEditList(s.getEdits());
+    f.format(s.getA());
+    return f;
+  }
+
+  protected SparseHtmlFile getSparseHtmlFileB(PatchScript s) {
+    AccountDiffPreference dp = new AccountDiffPreference(s.getDiffPrefs());
+
+    PrettyFormatter f = ClientSideFormatter.FACTORY.get();
+    f.setDiffPrefs(dp);
+    f.setFileName(s.getB().getPath());
+    f.setEditFilter(PrettyFormatter.B);
+    f.setEditList(s.getEdits());
+
+    if (dp.isSyntaxHighlighting() && s.getA().isWholeFile() && !s.getB().isWholeFile()) {
+      f.format(s.getB().apply(s.getA(), s.getEdits()));
+    } else {
+      f.format(s.getB());
+    }
+    return f;
+  }
+
   protected abstract void render(PatchScript script);
 
   protected abstract void onInsertComment(PatchLine pl);
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
index 5df1e14..b0d825b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/CommentEditorPanel.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.CommentPanel;
-import com.google.gerrit.reviewdb.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.DoubleClickEvent;
@@ -26,11 +26,11 @@
 import com.google.gwt.event.dom.client.KeyDownEvent;
 import com.google.gwt.event.dom.client.KeyDownHandler;
 import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Widget;
 import com.google.gwtexpui.globalkey.client.NpTextArea;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.sql.Timestamp;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
index e35097e..cb54411 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/HistoryTable.java
@@ -14,11 +14,12 @@
 
 package com.google.gerrit.client.patches;
 
+import com.google.gerrit.client.Dispatcher;
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.Util;
 import com.google.gerrit.client.ui.FancyFlexTable;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
@@ -43,19 +44,28 @@
   }
 
   void onClick(final HistoryRadio b) {
+    PatchSet.Id sideA = screen.idSideA;
+    PatchSet.Id sideB = screen.idSideB;
     switch (b.file) {
       case 0:
-        screen.setSideA(b.patchSetId);
+        sideA = b.patchSetId;
         break;
       case 1:
-        screen.setSideB(b.patchSetId);
+        sideB = b.patchSetId;
         break;
       default:
         return;
     }
-
     enableAll(false);
-    screen.refresh(false);
+    Patch.Key k = new Patch.Key(sideB, screen.getPatchKey().get());
+    switch (screen.getPatchScreenType()) {
+      case SIDE_BY_SIDE:
+        Gerrit.display(Dispatcher.toPatchSideBySide(sideA, k));
+        break;
+      case UNIFIED:
+        Gerrit.display(Dispatcher.toPatchUnified(sideA, k));
+        break;
+    }
   }
 
   void enableAll(final boolean on) {
@@ -76,7 +86,11 @@
     table.setText(3, 0, Util.C.patchTableColumnComments());
     fmt.setStyleName(3, 0, Gerrit.RESOURCES.css().dataHeader());
 
-    table.setText(0, 1, PatchUtil.C.patchBase());
+    if (screen.getPatchSetDetail().getInfo().getParents().size() > 1) {
+      table.setText(0, 1, PatchUtil.C.patchBaseAutoMerge());
+    } else {
+      table.setText(0, 1, PatchUtil.C.patchBase());
+    }
     fmt.setStyleName(0, 1, Gerrit.RESOURCES.css().dataCell());
     fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().topMostCell());
     fmt.setStyleName(1, 1, Gerrit.RESOURCES.css().dataCell());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
index 6d42cc9..9f36342 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/NavLinks.java
@@ -19,12 +19,12 @@
 import com.google.gerrit.client.changes.Util;
 import com.google.gerrit.client.ui.ChangeLink;
 import com.google.gerrit.client.ui.InlineHyperlink;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.Grid;
-import com.google.gwt.user.client.ui.HasHorizontalAlignment;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchBrowserPopup.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchBrowserPopup.java
index e3fb1e9..9af1aa3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchBrowserPopup.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchBrowserPopup.java
@@ -17,15 +17,15 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.PatchTable;
 import com.google.gerrit.client.changes.Util;
-import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gwt.event.logical.shared.ResizeEvent;
 import com.google.gwt.event.logical.shared.ResizeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.ScrollPanel;
 import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+import com.google.gwt.user.client.ui.ScrollPanel;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.HidePopupPanelCommand;
 import com.google.gwtexpui.user.client.PluginSafeDialogBox;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
index 32f7096..fd34729 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.java
@@ -27,6 +27,7 @@
 
   String noDifference();
   String patchBase();
+  String patchBaseAutoMerge();
   String patchHeaderPatchSet();
   String patchHeaderOld();
   String patchHeaderNew();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
index f9f407e..6a1dbc1 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchConstants.properties
@@ -10,6 +10,7 @@
 
 noDifference = No Differences
 patchBase = Base
+patchBaseAutoMerge = Auto Merge
 patchHeaderPatchSet = Patch Set
 patchHeaderOld = Old Version
 patchHeaderNew = New Version
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
index 1671d6e..ffc8960 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
@@ -29,23 +29,23 @@
 import com.google.gerrit.common.data.PatchSetDetail;
 import com.google.gerrit.prettify.client.ClientSideFormatter;
 import com.google.gerrit.prettify.common.PrettyFactory;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.ui.CheckBox;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 public abstract class PatchScreen extends Screen implements
     CommentEditorContainer {
@@ -54,8 +54,8 @@
   public static class SideBySide extends PatchScreen {
     public SideBySide(final Patch.Key id, final int patchIndex,
         final PatchSetDetail patchSetDetail, final PatchTable patchTable,
-        final TopView topView) {
-      super(id, patchIndex, patchSetDetail, patchTable, topView);
+        final TopView topView, final PatchSet.Id baseId) {
+       super(id, patchIndex, patchSetDetail, patchTable, topView, baseId);
     }
 
     @Override
@@ -72,8 +72,8 @@
   public static class Unified extends PatchScreen {
     public Unified(final Patch.Key id, final int patchIndex,
         final PatchSetDetail patchSetDetail, final PatchTable patchTable,
-        final TopView topView) {
-      super(id, patchIndex, patchSetDetail, patchTable, topView);
+        final TopView topView, final PatchSet.Id baseId) {
+      super(id, patchIndex, patchSetDetail, patchTable, topView, baseId);
     }
 
     @Override
@@ -87,10 +87,6 @@
     }
   }
 
-  // Which patch set id's are being diff'ed
-  private static PatchSet.Id diffSideA = null;
-  private static PatchSet.Id diffSideB = null;
-
   /**
    * What should be displayed in the top of the screen
    */
@@ -137,20 +133,14 @@
 
   protected PatchScreen(final Patch.Key id, final int patchIndex,
       final PatchSetDetail detail, final PatchTable patchTable,
-      final TopView top) {
+      final TopView top, final PatchSet.Id baseId) {
     patchKey = id;
     patchSetDetail = detail;
     fileList = patchTable;
     topView = top;
 
-    if (patchTable != null) {
-      diffSideA = patchTable.getPatchSetIdToCompareWith();
-    } else {
-      diffSideA = null;
-    }
-
-    idSideA = diffSideA; // null here means we're diff'ing from the Base
-    idSideB = diffSideB != null ? diffSideB : id.getParentKey();
+    idSideA = baseId; // null here means we're diff'ing from the Base
+    idSideB = id.getParentKey();
     this.patchIndex = patchIndex;
 
     reviewed = new CheckBox(Util.C.reviewed());
@@ -189,6 +179,13 @@
   }
 
   private void update(AccountDiffPreference dp) {
+    // Did the user just turn on auto-review?
+    if (!reviewed.getValue() && prefs.getOld().isManualReview()
+        && !dp.isManualReview()) {
+      reviewed.setValue(true);
+      setReviewedByCurrentUser(true);
+    }
+
     if (lastScript != null && canReuse(dp, lastScript)) {
       lastScript.setDiffPrefs(dp);
       RpcStatus.INSTANCE.onRpcStart(null);
@@ -308,7 +305,7 @@
               patchSetDetail = result;
               if (fileList == null) {
                 fileList = new PatchTable(prefs);
-                fileList.display(result);
+                fileList.display(idSideA, result);
                 patchIndex = fileList.indexOf(patchKey);
               }
               refresh(true);
@@ -343,6 +340,10 @@
 
   public abstract PatchScreen.Type getPatchScreenType();
 
+  public PatchSet.Id getSideA() {
+    return idSideA;
+  }
+
   public Patch.Key getPatchKey() {
     return patchKey;
   }
@@ -431,7 +432,7 @@
       contentTable = new UnifiedDiffTable();
       contentTable.fileList = fileList;
       contentPanel.add(contentTable);
-      setToken(Dispatcher.toPatchUnified(patchKey));
+      setToken(Dispatcher.toPatchUnified(idSideA, patchKey));
     }
 
     if (hasDifferences) {
@@ -450,10 +451,20 @@
       bottomNav.display(patchIndex, getPatchScreenType(), fileList);
     }
 
-    // Mark this file reviewed as soon we display the diff screen
-    if (Gerrit.isSignedIn() && isFirst) {
-      reviewed.setValue(true);
-      setReviewedByCurrentUser(true /* reviewed */);
+    if (Gerrit.isSignedIn()) {
+      boolean isReviewed = false;
+      if (isFirst && !prefs.get().isManualReview()) {
+        isReviewed = true;
+        setReviewedByCurrentUser(isReviewed);
+      } else {
+        for (Patch p : patchSetDetail.getPatches()) {
+          if (p.getKey().equals(patchKey)) {
+            isReviewed = p.isReviewedByCurrentUser();
+            break;
+          }
+        }
+      }
+      reviewed.setValue(isReviewed);
     }
 
     intralineFailure = isFirst && script.hasIntralineFailure();
@@ -477,19 +488,6 @@
     contentTable.setRegisterKeys(isCurrentView() && showPatch);
   }
 
-  public void setSideA(PatchSet.Id patchSetId) {
-    idSideA = patchSetId;
-    diffSideA = patchSetId;
-    if (fileList != null) {
-      fileList.setPatchSetIdToCompareWith(patchSetId);
-    }
-  }
-
-  public void setSideB(PatchSet.Id patchSetId) {
-    idSideB = patchSetId;
-    diffSideB = patchSetId;
-  }
-
   public void setTopView(TopView tv) {
     topView = tv;
     topPanel.clear();
@@ -519,7 +517,7 @@
         Util.DETAIL_SVC.patchSetDetail(psid,
             new GerritCallback<PatchSetDetail>() {
               public void onSuccess(final PatchSetDetail result) {
-                fileList.display(result);
+                fileList.display(idSideA, result);
               }
             });
       }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
index df0fff5..871eb2b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.java
@@ -20,8 +20,8 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.client.ui.ListenableAccountDiffPreference;
 import com.google.gerrit.client.ui.NpIntTextBox;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.KeyCodes;
@@ -41,7 +41,7 @@
 import com.google.gwt.user.client.ui.HasWidgets;
 import com.google.gwt.user.client.ui.ListBox;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 public class PatchScriptSettingsPanel extends Composite implements
     HasValueChangeHandlers<AccountDiffPreference> {
@@ -79,6 +79,9 @@
   CheckBox showTabs;
 
   @UiField
+  CheckBox manualReview;
+
+  @UiField
   CheckBox skipDeleted;
 
   @UiField
@@ -212,6 +215,7 @@
     skipUncommented.setValue(dp.isSkipUncommented());
     expandAllComments.setValue(dp.isExpandAllComments());
     retainHeader.setValue(dp.isRetainHeader());
+    manualReview.setValue(dp.isManualReview());
   }
 
   @UiHandler("update")
@@ -243,6 +247,7 @@
     dp.setSkipUncommented(skipUncommented.getValue());
     dp.setExpandAllComments(expandAllComments.getValue());
     dp.setRetainHeader(retainHeader.getValue());
+    dp.setManualReview(manualReview.getValue());
 
     listenablePrefs.set(dp);
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
index e819ffa..2c7afff 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScriptSettingsPanel.ui.xml
@@ -147,20 +147,29 @@
       </g:CheckBox>
     </td>
 
+    <td valign='bottom' rowspan='2'>
+      <g:CheckBox
+          ui:field='manualReview'
+          text='Manual Review'
+          tabIndex='13'>
+        <ui:attribute name='text'/>
+      </g:CheckBox>
+    </td>
+
     <td rowspan='2'>
       <br/>
       <g:Button
           ui:field='update'
           text='Update'
           styleName='{style.updateButton}'
-          tabIndex='13'>
+          tabIndex='14'>
         <ui:attribute name='text'/>
       </g:Button>
       <g:Button
           ui:field='save'
           text='Save'
           styleName='{style.updateButton}'
-          tabIndex='14'>
+          tabIndex='15'>
         <ui:attribute name='text'/>
       </g:Button>
     </td>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
index 853cedc..6379e23 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
@@ -25,9 +25,9 @@
 import com.google.gerrit.common.data.PatchScript.FileMode;
 import com.google.gerrit.prettify.common.EditList;
 import com.google.gerrit.prettify.common.SparseHtmlFile;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.Patch.ChangeType;
-import com.google.gerrit.reviewdb.PatchLineComment;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
@@ -89,8 +89,8 @@
 
   @Override
   protected void render(final PatchScript script) {
-    a = script.getSparseHtmlFileA();
-    b = script.getSparseHtmlFileB();
+    a = getSparseHtmlFileA(script);
+    b = getSparseHtmlFileB(script);
     final ArrayList<Object> lines = new ArrayList<Object>();
     final SafeHtmlBuilder nc = new SafeHtmlBuilder();
     final boolean intraline =
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
index ef6a181..f0f619e 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UnifiedDiffTable.java
@@ -23,10 +23,10 @@
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.common.data.PatchScript.DisplayMethod;
 import com.google.gerrit.prettify.common.EditList;
-import com.google.gerrit.prettify.common.SparseHtmlFile;
 import com.google.gerrit.prettify.common.EditList.Hunk;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
+import com.google.gerrit.prettify.common.SparseHtmlFile;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
@@ -95,8 +95,8 @@
 
   @Override
   protected void render(final PatchScript script) {
-    final SparseHtmlFile a = script.getSparseHtmlFileA();
-    final SparseHtmlFile b = script.getSparseHtmlFileB();
+    final SparseHtmlFile a = getSparseHtmlFileA(script);
+    final SparseHtmlFile b = getSparseHtmlFileB(script);
     final SafeHtmlBuilder nc = new SafeHtmlBuilder();
 
     // Display the patch header
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UpToChangeCommand.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UpToChangeCommand.java
index 3faa998..72318dd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UpToChangeCommand.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/UpToChangeCommand.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.ChangeScreen;
 import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.event.dom.client.KeyPressEvent;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
index 1871bb7..98ae46f 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/GerritCallback.java
@@ -24,11 +24,11 @@
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.common.errors.NotSignedInException;
 import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwt.user.client.rpc.InvocationException;
-import com.google.gwtjsonrpc.client.JsonUtil;
 import com.google.gwtjsonrpc.client.RemoteJsonException;
 import com.google.gwtjsonrpc.client.ServerUnavailableException;
+import com.google.gwtjsonrpc.common.JsonConstants;
 
 /** Abstract callback handling generic error conditions automatically */
 public abstract class GerritCallback<T> implements AsyncCallback<T> {
@@ -70,7 +70,7 @@
 
   private static boolean isInvalidXSRF(final Throwable caught) {
     return caught instanceof InvocationException
-        && caught.getMessage().equals(JsonUtil.ERROR_INVALID_XSRF);
+        && caught.getMessage().equals(JsonConstants.ERROR_INVALID_XSRF);
   }
 
   private static boolean isNotSignedIn(final Throwable caught) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountDashboardLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountDashboardLink.java
index bd8a1ce..5233a6b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountDashboardLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountDashboardLink.java
@@ -20,7 +20,7 @@
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.AccountInfo;
 import com.google.gerrit.common.data.AccountInfoCache;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 /** Link to any user's account dashboard. */
 public class AccountDashboardLink extends InlineHyperlink {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java
index 5d8ee8b..885f53b 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/AccountGroupSuggestOracle.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.client.RpcStatus;
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.common.data.GroupReference;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gwt.user.client.ui.SuggestOracle;
 import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java
index 01d7d8b..fddae84 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/BranchLink.java
@@ -17,9 +17,9 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.QueryScreen;
 import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
 
 /** Link to the open changes of a project. */
 public class BranchLink extends InlineHyperlink {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java
index f022f7e..d708286 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ChangeLink.java
@@ -18,8 +18,8 @@
 import com.google.gerrit.client.changes.ChangeScreen;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.ChangeInfo;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.DOM;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentLinkProcessor.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentLinkProcessor.java
index f5ef2f4..a3c7a3c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentLinkProcessor.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentLinkProcessor.java
@@ -15,10 +15,10 @@
 package com.google.gerrit.client.ui;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwtexpui.safehtml.client.RegexFindReplace;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentPanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentPanel.java
index 249c70c..0cea2c7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentPanel.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentPanel.java
@@ -35,11 +35,11 @@
 import com.google.gwt.user.client.ui.FlexTable;
 import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwt.user.client.ui.HasHorizontalAlignment;
 import com.google.gwt.user.client.ui.InlineLabel;
 import com.google.gwt.user.client.ui.Panel;
 import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
 import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
new file mode 100644
index 0000000..26b61f5
--- /dev/null
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/CommentedActionDialog.java
@@ -0,0 +1,142 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.ui;
+
+import com.google.gerrit.client.Gerrit;
+import com.google.gerrit.client.rpc.GerritCallback;
+import com.google.gerrit.client.ui.SmallHeading;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.user.client.DOM;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwtexpui.globalkey.client.GlobalKey;
+import com.google.gwtexpui.globalkey.client.NpTextArea;
+import com.google.gwtexpui.user.client.AutoCenterDialogBox;
+
+public abstract class CommentedActionDialog<T> extends AutoCenterDialogBox
+    implements CloseHandler<PopupPanel> {
+  protected final FlowPanel panel;
+  protected final NpTextArea message;
+  protected final Button sendButton;
+  protected final Button cancelButton;
+  protected final FlowPanel buttonPanel;
+  protected AsyncCallback<T> callback;
+
+  protected boolean sent = false;
+
+  public CommentedActionDialog(final String title, final String heading,
+      AsyncCallback<T> callback) {
+    super(/* auto hide */false, /* modal */true);
+    this.callback = callback;
+
+    setGlassEnabled(true);
+    setText(title);
+
+    addStyleName(Gerrit.RESOURCES.css().commentedActionDialog());
+
+    message = new NpTextArea();
+    message.setCharacterWidth(60);
+    message.setVisibleLines(10);
+    DOM.setElementPropertyBoolean(message.getElement(), "spellcheck", true);
+
+    sendButton = new Button(Util.C.commentedActionButtonSend());
+    sendButton.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(final ClickEvent event) {
+        enableButtons(false);
+        onSend();
+      }
+    });
+
+    cancelButton = new Button(Util.C.commentedActionButtonCancel());
+    DOM.setStyleAttribute(cancelButton.getElement(), "marginLeft", "300px");
+    cancelButton.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(final ClickEvent event) {
+        hide();
+      }
+    });
+
+    final FlowPanel mwrap = new FlowPanel();
+    mwrap.setStyleName(Gerrit.RESOURCES.css().commentedActionMessage());
+    mwrap.add(message);
+
+    buttonPanel = new FlowPanel();
+    buttonPanel.add(sendButton);
+    buttonPanel.add(cancelButton);
+
+    panel = new FlowPanel();
+    panel.add(new SmallHeading(heading));
+    panel.add(mwrap);
+    panel.add(buttonPanel);
+    add(panel);
+
+    addCloseHandler(this);
+  }
+
+  public void enableButtons(boolean enable) {
+    sendButton.setEnabled(enable);
+    cancelButton.setEnabled(enable);
+  }
+
+  @Override
+  public void center() {
+    super.center();
+    GlobalKey.dialog(this);
+    message.setFocus(true);
+  }
+
+  @Override
+  public void onClose(CloseEvent<PopupPanel> event) {
+    if (!sent) {
+      // the dialog was closed without the send button being pressed
+      // e.g. the user pressed Cancel or ESC to close the dialog
+      if (callback != null) {
+        callback.onFailure(null);
+      }
+    }
+    sent = false;
+  }
+
+  public abstract void onSend();
+
+  public String getMessageText() {
+    return message.getText().trim();
+  }
+
+  public AsyncCallback<T> createCallback() {
+    return new GerritCallback<T>(){
+      @Override
+      public void onSuccess(T result) {
+        sent = true;
+        if (callback != null) {
+          callback.onSuccess(result);
+        }
+        hide();
+      }
+
+      @Override
+      public void onFailure(Throwable caught) {
+        enableButtons(true);
+        super.onFailure(caught);
+      }
+    };
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
index 3fca1b1..1edb8fd 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/FancyFlexTable.java
@@ -21,8 +21,8 @@
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.FlexTable;
-import com.google.gwt.user.client.ui.Widget;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
+import com.google.gwt.user.client.ui.Widget;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
 
 import java.util.Iterator;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HintTextBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HintTextBox.java
index 814fb1f..09550a6 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HintTextBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/HintTextBox.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.client.ui;
 
 import com.google.gerrit.client.Gerrit;
-
 import com.google.gwt.event.dom.client.BlurEvent;
 import com.google.gwt.event.dom.client.BlurHandler;
 import com.google.gwt.event.dom.client.FocusEvent;
@@ -24,10 +23,10 @@
 import com.google.gwt.event.dom.client.KeyDownEvent;
 import com.google.gwt.event.dom.client.KeyDownHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwtexpui.globalkey.client.NpTextBox;
 import com.google.gwt.user.client.ui.SuggestBox;
-import com.google.gwt.user.client.ui.Widget;
 import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.globalkey.client.NpTextBox;
 
 
 public class HintTextBox extends NpTextBox {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java
index 41de2cd..27bc107 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableAccountDiffPreference.java
@@ -17,11 +17,11 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.account.Util;
 import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gwtjsonrpc.common.VoidResult;
 
 public class ListenableAccountDiffPreference
-    extends ListenableValue<AccountDiffPreference> {
+    extends ListenableOldValue<AccountDiffPreference> {
 
   public ListenableAccountDiffPreference() {
     reset();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableOldValue.java
similarity index 63%
copy from gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.java
copy to gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableOldValue.java
index 8b13392..5c3e127 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ListenableOldValue.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 The Android Open Source Project
+// Copyright (C) 2012 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,12 +14,17 @@
 
 package com.google.gerrit.client.ui;
 
-import com.google.gwt.i18n.client.Constants;
+public class ListenableOldValue<T> extends ListenableValue<T> {
 
-public interface ProjectConstants extends Constants {
-  String projectName();
-  String projectDescription();
-  String projectListOpen();
-  String projectListPrev();
-  String projectListNext();
+  private T oldValue;
+
+  public T getOld() {
+    return oldValue;
+  }
+
+  public void set(final T value) {
+    oldValue = get();
+    super.set(value);
+    oldValue = null; // allow it to be gced before the next event
+  }
 }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java
index 0d45529..8d74bc3 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/NavigationTable.java
@@ -20,11 +20,11 @@
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 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.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java
index 5028540..f79dc51 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/PatchLink.java
@@ -18,9 +18,11 @@
 import com.google.gerrit.client.changes.PatchTable;
 import com.google.gerrit.client.patches.PatchScreen;
 import com.google.gerrit.common.data.PatchSetDetail;
-import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
 
 public class PatchLink extends InlineHyperlink {
+  protected PatchSet.Id base;
   protected Patch.Key patchKey;
   protected int patchIndex;
   protected PatchSetDetail patchSetDetail;
@@ -29,17 +31,19 @@
 
   /**
    * @param text The text of this link
+   * @param base optional base to compare against.
    * @param patchKey The key for this patch
    * @param patchIndex The index of the current patch in the patch set
    * @param historyToken The history token
    * @param patchSetDetail Detailed information about the patch set.
    * @param parentPatchTable The table used to display this link
    */
-  protected PatchLink(final String text, final Patch.Key patchKey,
-      final int patchIndex, final String historyToken,
-      final PatchSetDetail patchSetDetail, final PatchTable parentPatchTable,
-      final PatchScreen.TopView topView) {
+  protected PatchLink(String text, PatchSet.Id base, Patch.Key patchKey,
+      int patchIndex, String historyToken,
+      PatchSetDetail patchSetDetail, PatchTable parentPatchTable,
+      PatchScreen.TopView topView) {
     super(text, historyToken);
+    this.base = base;
     this.patchKey = patchKey;
     this.patchIndex = patchIndex;
     this.patchSetDetail = patchSetDetail;
@@ -53,9 +57,9 @@
    * @param type The type of the link to create (unified/side-by-side)
    * @param patchScreen The patchScreen to grab contents to link to from
    */
-  public PatchLink(final String text, final PatchScreen.Type type,
-      final PatchScreen patchScreen) {
+  public PatchLink(String text, PatchScreen.Type type, PatchScreen patchScreen) {
     this(text, //
+        patchScreen.getSideA(), //
         patchScreen.getPatchKey(), //
         patchScreen.getPatchIndex(), //
         Dispatcher.toPatch(type, patchScreen.getPatchKey()), //
@@ -69,6 +73,7 @@
   public void go() {
     Dispatcher.patch( //
         getTargetHistoryToken(), //
+        base, //
         patchKey, //
         patchIndex, //
         patchSetDetail, //
@@ -78,19 +83,21 @@
   }
 
   public static class SideBySide extends PatchLink {
-    public SideBySide(final String text, final Patch.Key patchKey,
-        final int patchIndex, PatchSetDetail patchSetDetail,
+    public SideBySide(String text, PatchSet.Id base, Patch.Key patchKey,
+        int patchIndex, PatchSetDetail patchSetDetail,
         PatchTable parentPatchTable) {
-      super(text, patchKey, patchIndex, Dispatcher.toPatchSideBySide(patchKey),
+      super(text, base, patchKey, patchIndex,
+          Dispatcher.toPatchSideBySide(base, patchKey),
           patchSetDetail, parentPatchTable, null);
     }
   }
 
   public static class Unified extends PatchLink {
-    public Unified(final String text, final Patch.Key patchKey,
-        final int patchIndex, PatchSetDetail patchSetDetail,
+    public Unified(String text, PatchSet.Id base, final Patch.Key patchKey,
+        int patchIndex, PatchSetDetail patchSetDetail,
         PatchTable parentPatchTable) {
-      super(text, patchKey, patchIndex, Dispatcher.toPatchUnified(patchKey),
+      super(text, base, patchKey, patchIndex,
+          Dispatcher.toPatchUnified(base, patchKey),
           patchSetDetail, parentPatchTable, null);
     }
   }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectLink.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectLink.java
index b2c4c3e..05def9c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectLink.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectLink.java
@@ -17,9 +17,9 @@
 import com.google.gerrit.client.Gerrit;
 import com.google.gerrit.client.changes.QueryScreen;
 import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Change.Status;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Change.Status;
 
 /** Link to the open changes of a project. */
 public class ProjectLink extends InlineHyperlink {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java
index 49fe165..be82eff 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectNameSuggestOracle.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.client.RpcStatus;
 import com.google.gerrit.client.rpc.GerritCallback;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.user.client.ui.SuggestOracle;
 import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
index 96089b9..b768643 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectsTable.java
@@ -15,8 +15,7 @@
 package com.google.gerrit.client.ui;
 
 import com.google.gerrit.client.Gerrit;
-import com.google.gerrit.client.ui.NavigationTable;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwt.event.dom.client.KeyCodes;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ReviewerSuggestOracle.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ReviewerSuggestOracle.java
index 75a3b83..747ef40 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ReviewerSuggestOracle.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ReviewerSuggestOracle.java
@@ -20,7 +20,7 @@
 import com.google.gerrit.client.rpc.GerritCallback;
 import com.google.gerrit.common.data.AccountInfo;
 import com.google.gerrit.common.data.ReviewerInfo;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gwt.user.client.ui.SuggestOracle;
 import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
 
@@ -30,13 +30,13 @@
 /** Suggestion Oracle for reviewers. */
 public class ReviewerSuggestOracle extends HighlightSuggestOracle {
 
-  private Project.NameKey project;
+  private Change.Id changeId;
 
   @Override
   protected void onRequestSuggestions(final Request req, final Callback callback) {
     RpcStatus.hide(new Runnable() {
       public void run() {
-        SuggestUtil.SVC.suggestReviewer(project, req.getQuery(),
+        SuggestUtil.SVC.suggestChangeReviewer(changeId, req.getQuery(),
             req.getLimit(), new GerritCallback<List<ReviewerInfo>>() {
               public void onSuccess(final List<ReviewerInfo> result) {
                 final List<ReviewerSuggestion> r =
@@ -52,8 +52,8 @@
     });
   }
 
-  public void setProject(final Project.NameKey project) {
-    this.project = project;
+  public void setChange(Change.Id changeId) {
+    this.changeId = changeId;
   }
 
   private static class ReviewerSuggestion implements SuggestOracle.Suggestion {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.java
similarity index 86%
rename from gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.java
rename to gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.java
index 8b13392..ebbb049 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.java
@@ -16,7 +16,10 @@
 
 import com.google.gwt.i18n.client.Constants;
 
-public interface ProjectConstants extends Constants {
+public interface UIConstants extends Constants {
+  String commentedActionButtonSend();
+  String commentedActionButtonCancel();
+
   String projectName();
   String projectDescription();
   String projectListOpen();
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.properties
similarity index 69%
rename from gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.properties
rename to gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.properties
index 15de117..aa00cee 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/ProjectConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/UIConstants.properties
@@ -1,3 +1,6 @@
+commentedActionButtonSend = Submit
+commentedActionButtonCancel = Cancel
+
 projectName = Project Name
 projectDescription = Project Description
 projectListOpen = Select project
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java
index ebed764..98f13ef 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/Util.java
@@ -17,5 +17,5 @@
 import com.google.gwt.core.client.GWT;
 
 public class Util {
-  public static final ProjectConstants C = GWT.create(ProjectConstants.class);
+  public static final UIConstants C = GWT.create(UIConstants.class);
 }
diff --git a/gerrit-httpd/pom.xml b/gerrit-httpd/pom.xml
index 6c2190d..a6374da 100644
--- a/gerrit-httpd/pom.xml
+++ b/gerrit-httpd/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-httpd</artifactId>
@@ -55,11 +55,6 @@
     </dependency>
 
     <dependency>
-      <groupId>com.google.gwt</groupId>
-      <artifactId>gwt-servlet</artifactId>
-    </dependency>
-
-    <dependency>
       <groupId>eu.medsea.mimeutil</groupId>
       <artifactId>mime-util</artifactId>
     </dependency>
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/AdvertisedObjectsCacheKey.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/AdvertisedObjectsCacheKey.java
index 95a4f14..d594d77 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/AdvertisedObjectsCacheKey.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/AdvertisedObjectsCacheKey.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.httpd;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Project;
 
 class AdvertisedObjectsCacheKey {
   private final Account.Id account;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
index 270b476..fb30a4d 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CacheBasedWebSession.java
@@ -19,8 +19,8 @@
 
 import com.google.gerrit.httpd.WebSessionManager.Key;
 import com.google.gerrit.httpd.WebSessionManager.Val;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.CurrentUser;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ChangeQueryServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ChangeQueryServlet.java
index 468c6d8..9c4c598 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ChangeQueryServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ChangeQueryServlet.java
@@ -69,6 +69,7 @@
         return;
     }
 
+    p.setIncludeComments(get(req, "comments", false));
     p.setIncludeCurrentPatchSet(get(req, "current-patch-set", false));
     p.setIncludePatchSets(get(req, "patch-sets", false));
     p.setIncludeApprovals(get(req, "all-approvals", false));
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java
index b7709be..407784e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/DirectChangeByCommit.java
@@ -3,7 +3,7 @@
 package com.google.gerrit.httpd;
 
 import com.google.gerrit.common.PageLinks;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
@@ -11,7 +11,7 @@
 import com.google.gerrit.server.query.change.ChangeDataSource;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
 import com.google.gerrit.server.query.change.ChangeQueryRewriter;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
index 469af22..1953480 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.common.data.ApprovalTypes;
 import com.google.gerrit.common.data.GerritConfig;
-import com.google.gerrit.common.data.GitwebLink;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.common.data.GitwebConfig;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.AnonymousCowardName;
@@ -127,7 +127,7 @@
     config.setEditableAccountFields(fields);
 
     if (gitWebConfig.getUrl() != null) {
-      config.setGitwebLink(new GitwebLink(gitWebConfig.getUrl(), gitWebConfig
+      config.setGitwebLink(new GitwebConfig(gitWebConfig.getUrl(), gitWebConfig
           .getGitWebType()));
     }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
index 145891f..c36df04a 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitOverHttpServlet.java
@@ -15,13 +15,14 @@
 package com.google.gerrit.httpd;
 
 import com.google.gerrit.common.data.Capable;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.git.AsyncReceiveCommits;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ReceiveCommits;
 import com.google.gerrit.server.git.TagCache;
@@ -215,7 +216,7 @@
       }
 
       if (!pc.allRefsAreVisible()) {
-        up.setRefFilter(new VisibleRefFilter(tagCache, repo, pc, db.get(), true));
+        up.setAdvertiseRefsHook(new VisibleRefFilter(tagCache, repo, pc, db.get(), true));
       }
 
       next.doFilter(request, response);
@@ -231,11 +232,12 @@
   }
 
   static class ReceiveFactory implements ReceivePackFactory<HttpServletRequest> {
-    private final ReceiveCommits.Factory factory;
+    private final AsyncReceiveCommits.Factory factory;
     private final Provider<WebSession> session;
 
     @Inject
-    ReceiveFactory(ReceiveCommits.Factory factory, Provider<WebSession> session) {
+    ReceiveFactory(AsyncReceiveCommits.Factory factory,
+        Provider<WebSession> session) {
       this.factory = factory;
       this.session = session;
     }
@@ -251,7 +253,7 @@
       }
 
       final IdentifiedUser user = (IdentifiedUser) pc.getCurrentUser();
-      final ReceiveCommits rc = factory.create(pc, db);
+      final ReceiveCommits rc = factory.create(pc, db).getReceiveCommits();
       rc.getReceivePack().setRefLogIdent(user.newRefLogIdent());
       req.setAttribute(ATT_RC, rc);
       session.get().setAccessPath(AccessPath.GIT);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java
index 9f437bf..7de4bc3 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GitWebConfig.java
@@ -54,6 +54,7 @@
     type.setBranch(cfg.getString("gitweb", null, "branch"));
     type.setProject(cfg.getString("gitweb", null, "project"));
     type.setRevision(cfg.getString("gitweb", null, "revision"));
+    type.setFileHistory(cfg.getString("gitweb", null, "filehistory"));
     String pathSeparator = cfg.getString("gitweb", null, "pathSeparator");
     if (pathSeparator != null) {
       if (pathSeparator.length() == 1) {
@@ -77,6 +78,9 @@
     } else if (type.getRevision() == null) {
       log.warn("No Pattern specified for gitweb.revision, disabling.");
       type = null;
+    } else if (type.getFileHistory() == null) {
+      log.warn("No Pattern specified for gitweb.filehistory, disabling.");
+      type = null;
     }
 
     if ((cfgUrl != null && cfgUrl.isEmpty())
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpIdentifiedUserProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpIdentifiedUserProvider.java
index ba2d135..6c420a5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpIdentifiedUserProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpIdentifiedUserProvider.java
@@ -22,16 +22,16 @@
 import com.google.inject.ProvisionException;
 
 class HttpIdentifiedUserProvider implements Provider<IdentifiedUser> {
-  private final WebSession session;
+  private final Provider<CurrentUser> currUserProvider;
 
   @Inject
-  HttpIdentifiedUserProvider(WebSession session) {
-    this.session = session;
+  HttpIdentifiedUserProvider(Provider<CurrentUser> currUserProvider) {
+    this.currUserProvider = currUserProvider;
   }
 
   @Override
   public IdentifiedUser get() {
-    CurrentUser user = session.getCurrentUser();
+    CurrentUser user = currUserProvider.get();
     if (user instanceof IdentifiedUser) {
       return (IdentifiedUser) user;
     }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpLogoutServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpLogoutServlet.java
index 7b2c3f0..13a6f43 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpLogoutServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpLogoutServlet.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.httpd;
 
+import com.google.common.base.Strings;
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.CanonicalWebUrl;
@@ -53,7 +54,17 @@
     if (logoutUrl != null) {
       rsp.sendRedirect(logoutUrl);
     } else {
-      rsp.sendRedirect(urlProvider.get());
+      String url = urlProvider.get();
+      if (Strings.isNullOrEmpty(url)) {
+        url = req.getContextPath();
+      }
+      if (Strings.isNullOrEmpty(url)) {
+        url = "/";
+      }
+      if (!url.endsWith("/")) {
+        url += "/";
+      }
+      rsp.sendRedirect(url);
     }
   }
 }
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 1964c29..f90c20d 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
@@ -23,8 +23,8 @@
 import com.google.gerrit.httpd.raw.SshInfoServlet;
 import com.google.gerrit.httpd.raw.StaticServlet;
 import com.google.gerrit.httpd.raw.ToolServlet;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gwtexpui.server.CacheControlFilter;
 import com.google.inject.Key;
 import com.google.inject.Provider;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
index eb71733..8ee2c41 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java
@@ -36,6 +36,8 @@
 import com.google.gerrit.server.config.GerritRequestModule;
 import com.google.gerrit.server.contact.ContactStore;
 import com.google.gerrit.server.contact.ContactStoreProvider;
+import com.google.gerrit.server.util.GuiceRequestScopePropagator;
+import com.google.gerrit.server.util.RequestScopePropagator;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
@@ -76,6 +78,7 @@
         filter("/*").through(RequestCleanupFilter.class);
       }
     });
+    bind(RequestScopePropagator.class).to(GuiceRequestScopePropagator.class);
 
     if (wantSSL) {
       install(new RequireSslFilter.Module());
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java
index 869b8e7..2925896 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSession.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.httpd;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.AuthResult;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java
index 186d5da..55d0ca5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebSessionManager.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.httpd;
 
+import static com.google.gerrit.httpd.CacheBasedWebSession.MAX_AGE_MINUTES;
 import static com.google.gerrit.server.ioutil.BasicSerialization.readFixInt64;
 import static com.google.gerrit.server.ioutil.BasicSerialization.readString;
 import static com.google.gerrit.server.ioutil.BasicSerialization.readVarInt32;
@@ -21,13 +22,12 @@
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeFixInt64;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
-import static com.google.gerrit.httpd.CacheBasedWebSession.MAX_AGE_MINUTES;
 import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.MINUTES;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index d80cbaf..4710c39 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -14,22 +14,21 @@
 
 package com.google.gerrit.httpd.auth.become;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_USERNAME;
 
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.httpd.WebSession;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -44,7 +43,6 @@
 import java.util.List;
 import java.util.UUID;
 
-import javax.annotation.Nullable;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -58,17 +56,14 @@
 
   private final SchemaFactory<ReviewDb> schema;
   private final Provider<WebSession> webSession;
-  private final Provider<String> urlProvider;
   private final AccountManager accountManager;
 
   @Inject
   BecomeAnyAccountLoginServlet(final Provider<WebSession> ws,
       final SchemaFactory<ReviewDb> sf,
-      final @CanonicalWebUrl @Nullable Provider<String> up,
       final AccountManager am, final ServletContext servletContext) {
     webSession = ws;
     schema = sf;
-    urlProvider = up;
     accountManager = am;
   }
 
@@ -120,7 +115,7 @@
     if (res != null) {
       webSession.get().login(res, false);
       final StringBuilder rdr = new StringBuilder();
-      rdr.append(urlProvider.get());
+      rdr.append(req.getContextPath());
       if (IS_DEV && req.getParameter("gwt.codesvr") != null) {
         if (rdr.indexOf("?") < 0) {
           rdr.append("?");
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
index 1afd72d..eb8a76b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.httpd.WebSession;
 import com.google.gerrit.httpd.raw.HostPageServlet;
-import com.google.gwt.user.server.rpc.RPCServletUtils;
+import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/UserPassAuthServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/UserPassAuthServiceImpl.java
index a77dfc9..9d14872 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/UserPassAuthServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/UserPassAuthServiceImpl.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.common.auth.userpass.LoginResult;
 import com.google.gerrit.common.auth.userpass.UserPassAuthService;
 import com.google.gerrit.httpd.WebSession;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.account.AccountUserNameException;
@@ -25,7 +25,7 @@
 import com.google.gerrit.server.account.AuthResult;
 import com.google.gerrit.server.auth.AuthenticationUnavailableException;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java
index a4df147..e397961 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.httpd.GitWebConfig;
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gwt.user.server.rpc.RPCServletUtils;
+import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
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 a72fd08..fb04226 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
@@ -32,7 +32,7 @@
 import com.google.gerrit.common.data.GerritConfig;
 import com.google.gerrit.httpd.GitWebConfig;
 import com.google.gerrit.launcher.GerritLauncher;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.SitePaths;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java
index b4c3519..adf4ad5 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java
@@ -14,16 +14,16 @@
 
 package com.google.gerrit.httpd.raw;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.FileTypeRegistry;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
index f105df0..6a43d95 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/HostPageServlet.java
@@ -22,7 +22,7 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gwt.user.server.rpc.RPCServletUtils;
+import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.gwtexpui.linker.server.Permutation;
 import com.google.gwtexpui.linker.server.PermutationSelector;
 import com.google.gwtjsonrpc.server.JsonServlet;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
index 5a72230..d387f6e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/LegacyGerritServlet.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.httpd.raw;
 
 import com.google.gerrit.httpd.HtmlDomUtil;
-import com.google.gwt.user.server.rpc.RPCServletUtils;
+import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java
index c33a2aa..988dadb 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/StaticServlet.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.httpd.raw;
 
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gwt.user.server.rpc.RPCServletUtils;
+import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ToolServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ToolServlet.java
index 4a688aa..810cc2a 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ToolServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/ToolServlet.java
@@ -25,7 +25,7 @@
 import com.google.gerrit.common.Version;
 import com.google.gerrit.server.tools.ToolsCatalog;
 import com.google.gerrit.server.tools.ToolsCatalog.Entry;
-import com.google.gwt.user.server.rpc.RPCServletUtils;
+import com.google.gwtjsonrpc.server.RPCServletUtils;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java
index ed21b39..26db6f9 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/BaseServiceImplementation.java
@@ -18,14 +18,14 @@
 import com.google.gerrit.common.errors.InvalidQueryException;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.NoSuchProjectException;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 /** Support for services which require a {@link ReviewDb} instance. */
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/ChangeListServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/ChangeListServiceImpl.java
index 777d63e..9a101d3 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/ChangeListServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/ChangeListServiceImpl.java
@@ -22,13 +22,14 @@
 import com.google.gerrit.common.data.ToggleStarRequest;
 import com.google.gerrit.common.errors.InvalidQueryException;
 import com.google.gerrit.common.errors.NoSuchEntityException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeAccess;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.StarredChange;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.StarredChange;
+import com.google.gerrit.reviewdb.server.ChangeAccess;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.account.AccountControl;
 import com.google.gerrit.server.account.AccountInfoCacheFactory;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
@@ -38,11 +39,11 @@
 import com.google.gerrit.server.query.change.ChangeDataSource;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
 import com.google.gerrit.server.query.change.ChangeQueryRewriter;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.impl.ListResultSet;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.ListResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -253,6 +254,15 @@
           Collections.sort(d.getClosed(), SORT_KEY_COMP);
         }
 
+        // User dashboards are visible to other users, if the current user
+        // can see any of the changes in the dashboard.
+        if (!target.equals(me)
+            && d.getByOwner().isEmpty()
+            && d.getClosed().isEmpty()
+            && d.getForReview().isEmpty()) {
+          throw new Failure(new NoSuchEntityException());
+        }
+
         d.setAccounts(ac.create());
         return d;
       }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java
index 8f7754a..3513f89 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServlet.java
@@ -18,10 +18,10 @@
 import com.google.gerrit.common.errors.NotSignedInException;
 import com.google.gerrit.httpd.WebSession;
 import com.google.gson.GsonBuilder;
-import com.google.gwtjsonrpc.client.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
 import com.google.gwtjsonrpc.server.ActiveCall;
 import com.google.gwtjsonrpc.server.JsonServlet;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServletProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServletProvider.java
index 823ee7a..9361130 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServletProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/GerritJsonServletProvider.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.httpd.rpc;
 
-import com.google.gwtjsonrpc.client.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/Handler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/Handler.java
index 29aaf2c..911d1cc 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/Handler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/Handler.java
@@ -19,9 +19,9 @@
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.NoSuchRefException;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
 
 import java.util.concurrent.Callable;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/RpcServletModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/RpcServletModule.java
index 29abee6..876fee3 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/RpcServletModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/RpcServletModule.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.httpd.rpc;
 
-import com.google.gwtjsonrpc.client.RemoteJsonService;
+import com.google.gwtjsonrpc.common.RemoteJsonService;
 import com.google.inject.Key;
 import com.google.inject.Scopes;
 import com.google.inject.internal.UniqueAnnotations;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
index bf77c6a..f3e8e65e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestServiceImpl.java
@@ -19,25 +19,30 @@
 import com.google.gerrit.common.data.ReviewerInfo;
 import com.google.gerrit.common.data.SuggestService;
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountControl;
+import com.google.gerrit.server.account.AccountVisibility;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.account.GroupControl;
 import com.google.gerrit.server.account.GroupMembers;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.patch.AddReviewer;
+import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -45,7 +50,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -55,17 +59,18 @@
     SuggestService {
   private static final String MAX_SUFFIX = "\u9fa5";
 
+  private final Provider<ReviewDb> reviewDbProvider;
   private final ProjectControl.Factory projectControlFactory;
   private final ProjectCache projectCache;
   private final AccountCache accountCache;
   private final GroupControl.Factory groupControlFactory;
   private final GroupMembers.Factory groupMembersFactory;
-  private final IdentifiedUser.GenericFactory userFactory;
-  private final Provider<CurrentUser> currentUser;
-  private final SuggestAccountsEnum suggestAccounts;
+  private final IdentifiedUser.GenericFactory identifiedUserFactory;
+  private final AccountControl.Factory accountControlFactory;
+  private final ChangeControl.Factory changeControlFactory;
   private final Config cfg;
   private final GroupCache groupCache;
-
+  private final boolean suggestAccounts;
 
   @Inject
   SuggestServiceImpl(final Provider<ReviewDb> schema,
@@ -73,21 +78,37 @@
       final ProjectCache projectCache, final AccountCache accountCache,
       final GroupControl.Factory groupControlFactory,
       final GroupMembers.Factory groupMembersFactory,
-      final IdentifiedUser.GenericFactory userFactory,
       final Provider<CurrentUser> currentUser,
+      final IdentifiedUser.GenericFactory identifiedUserFactory,
+      final AccountControl.Factory accountControlFactory,
+      final ChangeControl.Factory changeControlFactory,
       @GerritServerConfig final Config cfg, final GroupCache groupCache) {
     super(schema, currentUser);
+    this.reviewDbProvider = schema;
     this.projectControlFactory = projectControlFactory;
     this.projectCache = projectCache;
     this.accountCache = accountCache;
     this.groupControlFactory = groupControlFactory;
     this.groupMembersFactory = groupMembersFactory;
-    this.userFactory = userFactory;
-    this.currentUser = currentUser;
-    this.suggestAccounts =
-        cfg.getEnum("suggest", null, "accounts", SuggestAccountsEnum.ALL);
+    this.identifiedUserFactory = identifiedUserFactory;
+    this.accountControlFactory = accountControlFactory;
+    this.changeControlFactory = changeControlFactory;
     this.cfg = cfg;
     this.groupCache = groupCache;
+
+    if ("OFF".equals(cfg.getString("suggest", null, "accounts"))) {
+      this.suggestAccounts = false;
+    } else {
+      boolean suggestAccounts;
+      try {
+        AccountVisibility av =
+            cfg.getEnum("suggest", null, "accounts", AccountVisibility.ALL);
+        suggestAccounts = (av != AccountVisibility.NONE);
+      } catch (IllegalArgumentException err) {
+        suggestAccounts = cfg.getBoolean("suggest", null, "accounts", true);
+      }
+      this.suggestAccounts = suggestAccounts;
+    }
   }
 
   public void suggestProjectNameKey(final String query, final int limit,
@@ -112,19 +133,29 @@
     callback.onSuccess(r);
   }
 
+  private interface VisibilityControl {
+    boolean isVisible(Account account) throws OrmException;
+  }
+
   public void suggestAccount(final String query, final Boolean active,
       final int limit, final AsyncCallback<List<AccountInfo>> callback) {
     run(callback, new Action<List<AccountInfo>>() {
       public List<AccountInfo> run(final ReviewDb db) throws OrmException {
-        return suggestAccount(db, query, active, limit);
+        return suggestAccount(db, query, active, limit, new VisibilityControl() {
+          @Override
+          public boolean isVisible(Account account) throws OrmException {
+            return accountControlFactory.get().canSee(account);
+          }
+        });
       }
     });
   }
 
   private List<AccountInfo> suggestAccount(final ReviewDb db,
-      final String query, final Boolean active, final int limit)
+      final String query, final Boolean active, final int limit,
+      VisibilityControl visibilityControl)
       throws OrmException {
-    if (suggestAccounts == SuggestAccountsEnum.OFF) {
+    if (!suggestAccounts) {
       return Collections.<AccountInfo> emptyList();
     }
 
@@ -136,12 +167,12 @@
     final LinkedHashMap<Account.Id, AccountInfo> r =
         new LinkedHashMap<Account.Id, AccountInfo>();
     for (final Account p : db.accounts().suggestByFullName(a, b, n)) {
-      addSuggestion(r, p, new AccountInfo(p), active);
+      addSuggestion(r, p, new AccountInfo(p), active, visibilityControl);
     }
     if (r.size() < n) {
       for (final Account p : db.accounts().suggestByPreferredEmail(a, b,
           n - r.size())) {
-        addSuggestion(r, p, new AccountInfo(p), active);
+        addSuggestion(r, p, new AccountInfo(p), active, visibilityControl);
       }
     }
     if (r.size() < n) {
@@ -151,7 +182,7 @@
           final Account p = accountCache.get(e.getAccountId()).getAccount();
           final AccountInfo info = new AccountInfo(p);
           info.setPreferredEmail(e.getEmailAddress());
-          addSuggestion(r, p, info, active);
+          addSuggestion(r, p, info, active, visibilityControl);
         }
       }
     }
@@ -159,57 +190,19 @@
   }
 
   private void addSuggestion(Map<Account.Id, AccountInfo> map, Account account,
-      AccountInfo info, Boolean active) {
+      AccountInfo info, Boolean active, VisibilityControl visibilityControl)
+      throws OrmException {
     if (map.containsKey(account.getId())) {
       return;
     }
     if (active != null && active != account.isActive()) {
       return;
     }
-    switch (suggestAccounts) {
-      case ALL:
-        map.put(account.getId(), info);
-        break;
-      case SAME_GROUP: {
-        Set<AccountGroup.UUID> usersGroups = groupsOf(account);
-        usersGroups.remove(AccountGroup.ANONYMOUS_USERS);
-        usersGroups.remove(AccountGroup.REGISTERED_USERS);
-        for (AccountGroup.UUID myGroup : currentUser.get().getEffectiveGroups()) {
-          if (usersGroups.contains(myGroup)) {
-            map.put(account.getId(), info);
-            break;
-          }
-        }
-        break;
-      }
-      case VISIBLE_GROUP: {
-        Set<AccountGroup.UUID> usersGroups = groupsOf(account);
-        usersGroups.remove(AccountGroup.ANONYMOUS_USERS);
-        usersGroups.remove(AccountGroup.REGISTERED_USERS);
-        for (AccountGroup.UUID usersGroup : usersGroups) {
-          try {
-            if (groupControlFactory.controlFor(usersGroup).isVisible()) {
-              map.put(account.getId(), info);
-              break;
-            }
-          } catch (NoSuchGroupException e) {
-            continue;
-          }
-        }
-        break;
-      }
-      case OFF:
-        break;
-      default:
-        throw new IllegalStateException("Bad SuggestAccounts " + suggestAccounts);
+    if (visibilityControl.isVisible(account)) {
+      map.put(account.getId(), info);
     }
   }
 
-  private Set<AccountGroup.UUID> groupsOf(Account account) {
-    IdentifiedUser user = userFactory.create(account.getId());
-    return new HashSet<AccountGroup.UUID>(user.getEffectiveGroups());
-  }
-
   public void suggestAccountGroup(final String query, final int limit,
       final AsyncCallback<List<GroupReference>> callback) {
     run(callback, new Action<List<GroupReference>>() {
@@ -242,13 +235,35 @@
   }
 
   @Override
-  public void suggestReviewer(final Project.NameKey project,
+  public void suggestReviewer(Project.NameKey project, String query, int limit,
+      AsyncCallback<List<ReviewerInfo>> callback) {
+    // The RPC is deprecated, but return an empty list for RPC API compatibility.
+    callback.onSuccess(Collections.<ReviewerInfo>emptyList());
+  }
+
+  @Override
+  public void suggestChangeReviewer(final Change.Id change,
       final String query, final int limit,
       final AsyncCallback<List<ReviewerInfo>> callback) {
     run(callback, new Action<List<ReviewerInfo>>() {
       public List<ReviewerInfo> run(final ReviewDb db) throws OrmException {
+        final ChangeControl changeControl;
+        try {
+          changeControl = changeControlFactory.controlFor(change);
+        } catch (NoSuchChangeException e) {
+          return Collections.emptyList();
+        }
+        VisibilityControl visibilityControl = new VisibilityControl() {
+          @Override
+          public boolean isVisible(Account account) throws OrmException {
+            IdentifiedUser who =
+                identifiedUserFactory.create(reviewDbProvider, account.getId());
+            return changeControl.forUser(who).isVisible(reviewDbProvider.get());
+          }
+        };
+
         final List<AccountInfo> suggestedAccounts =
-            suggestAccount(db, query, Boolean.TRUE, limit);
+            suggestAccount(db, query, Boolean.TRUE, limit, visibilityControl);
         final List<ReviewerInfo> reviewer =
             new ArrayList<ReviewerInfo>(suggestedAccounts.size());
         for (final AccountInfo a : suggestedAccounts) {
@@ -257,7 +272,7 @@
         final List<GroupReference> suggestedAccountGroups =
             suggestAccountGroup(db, query, limit);
         for (final GroupReference g : suggestedAccountGroups) {
-          if (suggestGroupAsReviewer(project, g)) {
+          if (suggestGroupAsReviewer(changeControl.getProject().getNameKey(), g)) {
             reviewer.add(new ReviewerInfo(g));
           }
         }
@@ -300,4 +315,4 @@
 
     return true;
   }
-}
\ No newline at end of file
+}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java
index 393c44b..9de7d88 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SystemInfoServiceImpl.java
@@ -17,13 +17,13 @@
 import com.google.gerrit.common.data.GerritConfig;
 import com.google.gerrit.common.data.SshHostKey;
 import com.google.gerrit.common.data.SystemInfoService;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ssh.SshInfo;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java
index be28840..aa94759f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountSecurityImpl.java
@@ -24,14 +24,14 @@
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountAgreement;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountSshKey;
-import com.google.gerrit.reviewdb.AuthType;
-import com.google.gerrit.reviewdb.ContactInformation;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountAgreement;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
+import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gerrit.reviewdb.client.ContactInformation;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountByEmailCache;
@@ -49,9 +49,9 @@
 import com.google.gerrit.server.mail.EmailTokenVerifier;
 import com.google.gerrit.server.mail.RegisterNewEmailSender;
 import com.google.gerrit.server.ssh.SshKeyCache;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
index 3951554..2fe3124 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AccountServiceImpl.java
@@ -20,22 +20,22 @@
 import com.google.gerrit.common.errors.InvalidQueryException;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmDuplicateKeyException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
index 4f62330..39712e4 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/AgreementInfoFactory.java
@@ -16,11 +16,11 @@
 
 import com.google.gerrit.common.data.AgreementInfo;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.AccountAgreement;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupAgreement;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountAgreement;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupAgreement;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.inject.Inject;
@@ -59,7 +59,7 @@
 
     final List<AccountGroupAgreement> groupAccepted =
         new ArrayList<AccountGroupAgreement>();
-    for (final AccountGroup.UUID groupUUID : user.getEffectiveGroups()) {
+    for (final AccountGroup.UUID groupUUID : user.getEffectiveGroups().getKnownGroups()) {
       AccountGroup group = groupCache.get(groupUUID);
       if (group == null) {
         continue;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/CreateGroup.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/CreateGroup.java
index 6639ac5..ebebd04 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/CreateGroup.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/CreateGroup.java
@@ -17,11 +17,11 @@
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.PermissionDeniedException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.PerformCreateGroup;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java
index 4edd571..12bc761 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/DeleteExternalIds.java
@@ -15,12 +15,12 @@
 package com.google.gerrit.httpd.rpc.account;
 
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountByEmailCache;
 import com.google.gerrit.server.account.AccountCache;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/ExternalIdDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/ExternalIdDetailFactory.java
index de0dec9..d876f2e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/ExternalIdDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/ExternalIdDetailFactory.java
@@ -14,15 +14,15 @@
 
 package com.google.gerrit.httpd.rpc.account;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_USERNAME;
 
 import com.google.gerrit.httpd.WebSession;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import java.util.Collections;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
index 448baf9..e90c2bf 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupAdminServiceImpl.java
@@ -24,13 +24,13 @@
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.AccountGroupIncludeAudit;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.AccountGroupMemberAudit;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountResolver;
@@ -38,9 +38,9 @@
 import com.google.gerrit.server.account.GroupControl;
 import com.google.gerrit.server.account.GroupIncludeCache;
 import com.google.gerrit.server.account.Realm;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -131,7 +131,6 @@
         final AccountGroup group = db.accountGroups().get(groupId);
         assertAmGroupOwner(db, group);
         group.setVisibleToAll(groupOptions.isVisibleToAll());
-        group.setEmailOnlyAuthors(groupOptions.isEmailOnlyAuthors());
         db.accountGroups().update(Collections.singleton(group));
         groupCache.evict(group);
         return VoidResult.INSTANCE;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupDetailHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupDetailHandler.java
index 513c90f..ce74218 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupDetailHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/GroupDetailHandler.java
@@ -17,9 +17,9 @@
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.GroupDetailFactory;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java
index d0557ae..fd274fd 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/MyGroupsFactory.java
@@ -19,7 +19,7 @@
 import com.google.gerrit.httpd.rpc.Handler;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.VisibleGroups;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import java.util.List;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
index 2d7770e..09dc582 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
@@ -18,9 +18,9 @@
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.PerformRenameGroup;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/AbandonChangeHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/AbandonChangeHandler.java
index c8bb0f7..3aecb0c 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/AbandonChangeHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/AbandonChangeHandler.java
@@ -18,13 +18,13 @@
 import com.google.gerrit.common.data.ReviewResult;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.server.changedetail.AbandonChange;
 import com.google.gerrit.server.mail.EmailException;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
index d226fd0..47a9395 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java
@@ -22,17 +22,16 @@
 import com.google.gerrit.common.data.SubmitRecord;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetAncestor;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+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.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.ChangeUtil;
-import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountInfoCacheFactory;
 import com.google.gerrit.server.config.GerritServerConfig;
@@ -42,8 +41,8 @@
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.workflow.CategoryFunction;
 import com.google.gerrit.server.workflow.FunctionState;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -130,6 +129,8 @@
 
     detail.setCanRevert(change.getStatus() == Change.Status.MERGED && control.canAddPatchSet());
 
+    detail.setCanRebase(detail.getChange().getStatus().isOpen() && control.canRebase());
+
     detail.setCanEdit(control.getRefControl().canWrite());
 
     if (detail.getChange().getStatus().isOpen()) {
@@ -161,7 +162,6 @@
   private void loadPatchSets() throws OrmException {
     ResultSet<PatchSet> source = db.patchSets().byChange(changeId);
     List<PatchSet> patches = new ArrayList<PatchSet>();
-    CurrentUser user = control.getCurrentUser();
     for (PatchSet ps : source) {
       if (control.isPatchVisible(ps, db)) {
         patches.add(ps);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
index fa0579e..8090451 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailServiceImpl.java
@@ -19,10 +19,10 @@
 import com.google.gerrit.common.data.IncludedInDetail;
 import com.google.gerrit.common.data.PatchSetDetail;
 import com.google.gerrit.common.data.PatchSetPublishDetail;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.inject.Inject;
 
 class ChangeDetailServiceImpl implements ChangeDetailService {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeManageServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeManageServiceImpl.java
index f055498..f99921b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeManageServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeManageServiceImpl.java
@@ -16,14 +16,15 @@
 
 import com.google.gerrit.common.data.ChangeDetail;
 import com.google.gerrit.common.data.ChangeManageService;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
 import com.google.inject.Inject;
 
 class ChangeManageServiceImpl implements ChangeManageService {
   private final SubmitAction.Factory submitAction;
   private final AbandonChangeHandler.Factory abandonChangeHandlerFactory;
+  private final RebaseChange.Factory rebaseChangeFactory;
   private final RestoreChangeHandler.Factory restoreChangeHandlerFactory;
   private final RevertChange.Factory revertChangeFactory;
   private final PublishAction.Factory publishAction;
@@ -32,12 +33,14 @@
   @Inject
   ChangeManageServiceImpl(final SubmitAction.Factory patchSetAction,
       final AbandonChangeHandler.Factory abandonChangeHandlerFactory,
+      final RebaseChange.Factory rebaseChangeFactory,
       final RestoreChangeHandler.Factory restoreChangeHandlerFactory,
       final RevertChange.Factory revertChangeFactory,
       final PublishAction.Factory publishAction,
       final DeleteDraftChange.Factory deleteDraftChangeFactory) {
     this.submitAction = patchSetAction;
     this.abandonChangeHandlerFactory = abandonChangeHandlerFactory;
+    this.rebaseChangeFactory = rebaseChangeFactory;
     this.restoreChangeHandlerFactory = restoreChangeHandlerFactory;
     this.revertChangeFactory = revertChangeFactory;
     this.publishAction = publishAction;
@@ -54,6 +57,11 @@
     abandonChangeHandlerFactory.create(patchSetId, message).to(callback);
   }
 
+  public void rebaseChange(final PatchSet.Id patchSetId,
+      final AsyncCallback<ChangeDetail> callback) {
+    rebaseChangeFactory.create(patchSetId).to(callback);
+  }
+
   public void revertChange(final PatchSet.Id patchSetId, final String message,
       final AsyncCallback<ChangeDetail> callback) {
     revertChangeFactory.create(patchSetId, message).to(callback);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeModule.java
index 4224293..b672a439 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeModule.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeModule.java
@@ -31,6 +31,7 @@
         factory(AbandonChangeHandler.Factory.class);
         factory(RestoreChangeHandler.Factory.class);
         factory(RevertChange.Factory.class);
+        factory(RebaseChange.Factory.class);
         factory(ChangeDetailFactory.Factory.class);
         factory(IncludedInDetailFactory.Factory.class);
         factory(PatchSetDetailFactory.Factory.class);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/DeleteDraftChange.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/DeleteDraftChange.java
index ab809ce..66c11c0 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/DeleteDraftChange.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/DeleteDraftChange.java
@@ -15,16 +15,16 @@
 package com.google.gerrit.httpd.rpc.changedetail;
 
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ReplicationQueue;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/IncludedInDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/IncludedInDetailFactory.java
index 398ca7e..c07ee51 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/IncludedInDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/IncludedInDetailFactory.java
@@ -17,13 +17,13 @@
 import com.google.gerrit.common.data.IncludedInDetail;
 import com.google.gerrit.common.errors.InvalidRevisionException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
index 9ef715f..de3ff2f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetDetailFactory.java
@@ -17,15 +17,15 @@
 import com.google.gerrit.common.data.PatchSetDetail;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
-import com.google.gerrit.reviewdb.AccountPatchReview;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountPatchReview;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.patch.PatchList;
@@ -35,7 +35,7 @@
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
index 32a58d0..638bfe3 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PatchSetPublishDetailFactory.java
@@ -20,19 +20,19 @@
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.SubmitRecord;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountInfoCacheFactory;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PublishAction.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PublishAction.java
index f6241fa..4ea279f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PublishAction.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/PublishAction.java
@@ -18,11 +18,11 @@
 import com.google.gerrit.common.data.ReviewResult;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.server.changedetail.PublishDraft;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RebaseChange.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RebaseChange.java
new file mode 100644
index 0000000..3c29074
--- /dev/null
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RebaseChange.java
@@ -0,0 +1,110 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.httpd.rpc.changedetail;
+
+import com.google.gerrit.common.ChangeHookRunner;
+import com.google.gerrit.common.data.ApprovalTypes;
+import com.google.gerrit.common.data.ChangeDetail;
+import com.google.gerrit.common.errors.NoSuchEntityException;
+import com.google.gerrit.httpd.rpc.Handler;
+import com.google.gerrit.reviewdb.client.PatchSet;
+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.git.GitRepositoryManager;
+import com.google.gerrit.server.git.ReplicationQueue;
+import com.google.gerrit.server.mail.EmailException;
+import com.google.gerrit.server.mail.RebasedPatchSetSender;
+import com.google.gerrit.server.patch.PatchSetInfoFactory;
+import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
+import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.InvalidChangeOperationException;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.PersonIdent;
+
+import java.io.IOException;
+
+class RebaseChange extends Handler<ChangeDetail> {
+  interface Factory {
+    RebaseChange create(PatchSet.Id patchSetId);
+  }
+
+  private final ChangeControl.Factory changeControlFactory;
+  private final ReviewDb db;
+  private final IdentifiedUser currentUser;
+  private final RebasedPatchSetSender.Factory rebasedPatchSetSenderFactory;
+
+  private final ChangeDetailFactory.Factory changeDetailFactory;
+  private final ReplicationQueue replication;
+
+  private final PatchSet.Id patchSetId;
+
+  private final ChangeHookRunner hooks;
+
+  private final GitRepositoryManager gitManager;
+  private final PatchSetInfoFactory patchSetInfoFactory;
+
+  private final PersonIdent myIdent;
+
+  private final ApprovalTypes approvalTypes;
+
+  @Inject
+  RebaseChange(final ChangeControl.Factory changeControlFactory,
+      final ReviewDb db, final IdentifiedUser currentUser,
+      final RebasedPatchSetSender.Factory rebasedPatchSetSenderFactory,
+      final ChangeDetailFactory.Factory changeDetailFactory,
+      @Assisted final PatchSet.Id patchSetId, final ChangeHookRunner hooks,
+      final GitRepositoryManager gitManager,
+      final PatchSetInfoFactory patchSetInfoFactory,
+      final ReplicationQueue replication,
+      @GerritPersonIdent final PersonIdent myIdent,
+      final ApprovalTypes approvalTypes) {
+    this.changeControlFactory = changeControlFactory;
+    this.db = db;
+    this.currentUser = currentUser;
+    this.rebasedPatchSetSenderFactory = rebasedPatchSetSenderFactory;
+    this.changeDetailFactory = changeDetailFactory;
+
+    this.patchSetId = patchSetId;
+    this.hooks = hooks;
+    this.gitManager = gitManager;
+
+    this.patchSetInfoFactory = patchSetInfoFactory;
+    this.replication = replication;
+    this.myIdent = myIdent;
+
+    this.approvalTypes = approvalTypes;
+  }
+
+  @Override
+  public ChangeDetail call() throws NoSuchChangeException, OrmException,
+      EmailException, NoSuchEntityException, PatchSetInfoNotAvailableException,
+      MissingObjectException, IncorrectObjectTypeException, IOException,
+      InvalidChangeOperationException {
+
+    ChangeUtil.rebaseChange(patchSetId, currentUser, db,
+        rebasedPatchSetSenderFactory, hooks, gitManager, patchSetInfoFactory,
+        replication, myIdent, changeControlFactory, approvalTypes);
+
+    return changeDetailFactory.create(patchSetId.getParentKey()).call();
+  }
+}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RestoreChangeHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RestoreChangeHandler.java
index 667861a..f018750 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RestoreChangeHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RestoreChangeHandler.java
@@ -18,13 +18,13 @@
 import com.google.gerrit.common.data.ReviewResult;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.server.changedetail.RestoreChange;
 import com.google.gerrit.server.mail.EmailException;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RevertChange.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RevertChange.java
index da74941..9fb9ae1 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RevertChange.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/RevertChange.java
@@ -18,9 +18,9 @@
 import com.google.gerrit.common.data.ChangeDetail;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+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;
@@ -32,7 +32,7 @@
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/SubmitAction.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/SubmitAction.java
index 38574bc..80100ad 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/SubmitAction.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/SubmitAction.java
@@ -18,12 +18,12 @@
 import com.google.gerrit.common.data.ReviewResult;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.server.changedetail.Submit;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/AddReviewerHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/AddReviewerHandler.java
index 953657b..60d6e60 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/AddReviewerHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/AddReviewerHandler.java
@@ -17,7 +17,7 @@
 import com.google.gerrit.common.data.ReviewerResult;
 import com.google.gerrit.httpd.rpc.Handler;
 import com.google.gerrit.httpd.rpc.changedetail.ChangeDetailFactory;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.patch.AddReviewer;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
index 50d6cea..e90467e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchDetailServiceImpl.java
@@ -14,45 +14,41 @@
 
 package com.google.gerrit.httpd.rpc.patch;
 
-import com.google.gerrit.common.data.ChangeDetail;
-import com.google.gerrit.common.data.ReviewerResult;
-import com.google.gerrit.common.data.ReviewResult;
 import com.google.gerrit.common.data.ApprovalSummary;
 import com.google.gerrit.common.data.ApprovalSummarySet;
 import com.google.gerrit.common.data.ApprovalTypes;
+import com.google.gerrit.common.data.ChangeDetail;
 import com.google.gerrit.common.data.PatchDetailService;
 import com.google.gerrit.common.data.PatchScript;
+import com.google.gerrit.common.data.ReviewResult;
+import com.google.gerrit.common.data.ReviewerResult;
 import com.google.gerrit.common.errors.NoSuchEntityException;
 import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
 import com.google.gerrit.httpd.rpc.Handler;
 import com.google.gerrit.httpd.rpc.changedetail.ChangeDetailFactory;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountPatchReview;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.Patch.Key;
-import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountPatchReview;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Patch.Key;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.AccountInfoCacheFactory;
 import com.google.gerrit.server.changedetail.DeleteDraftPatchSet;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.ReplicationQueue;
-import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
 import com.google.gerrit.server.patch.PublishComments;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.workflow.FunctionState;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -75,9 +71,6 @@
   private final PublishComments.Factory publishCommentsFactory;
   private final PatchScriptFactory.Factory patchScriptFactoryFactory;
   private final SaveDraft.Factory saveDraftFactory;
-  private final PatchSetInfoFactory patchSetInfoFactory;
-  private final GitRepositoryManager gitManager;
-  private final ReplicationQueue replication;
   private final ChangeDetailFactory.Factory changeDetailFactory;
 
   @Inject
@@ -93,9 +86,6 @@
       final PatchScriptFactory.Factory patchScriptFactoryFactory,
       final PublishComments.Factory publishCommentsFactory,
       final SaveDraft.Factory saveDraftFactory,
-      final PatchSetInfoFactory patchSetInfoFactory,
-      final GitRepositoryManager gitManager,
-      final ReplicationQueue replication,
       final ChangeDetailFactory.Factory changeDetailFactory) {
     super(schema, currentUser);
     this.approvalTypes = approvalTypes;
@@ -109,9 +99,6 @@
     this.patchScriptFactoryFactory = patchScriptFactoryFactory;
     this.publishCommentsFactory = publishCommentsFactory;
     this.saveDraftFactory = saveDraftFactory;
-    this.patchSetInfoFactory = patchSetInfoFactory;
-    this.gitManager = gitManager;
-    this.replication = replication;
     this.changeDetailFactory = changeDetailFactory;
   }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
index 302135e..ad7746f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
@@ -19,12 +19,12 @@
 import com.google.gerrit.common.data.PatchScript.DisplayMethod;
 import com.google.gerrit.prettify.common.EditList;
 import com.google.gerrit.prettify.common.SparseFileContent;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.server.FileTypeRegistry;
 import com.google.gerrit.server.patch.IntraLineDiff;
 import com.google.gerrit.server.patch.IntraLineDiffKey;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java
index 5a60623..d61e6e7 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptFactory.java
@@ -17,27 +17,28 @@
 import com.google.gerrit.common.data.CommentDetail;
 import com.google.gerrit.common.data.PatchScript;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
-import com.google.gerrit.reviewdb.Patch.ChangeType;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.client.Patch.ChangeType;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountInfoCacheFactory;
 import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.LargeObjectException;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.patch.PatchListEntry;
 import com.google.gerrit.server.patch.PatchListKey;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
@@ -120,7 +121,8 @@
   }
 
   @Override
-  public PatchScript call() throws OrmException, NoSuchChangeException {
+  public PatchScript call() throws OrmException, NoSuchChangeException,
+      LargeObjectException {
     validatePatchSetId(psa);
     validatePatchSetId(psb);
 
@@ -156,6 +158,8 @@
       } catch (IOException e) {
         log.error("File content unavailable", e);
         throw new NoSuchChangeException(changeId, e);
+      } catch (org.eclipse.jgit.errors.LargeObjectException err) {
+        throw new LargeObjectException("File content is too large", err);
       }
     } finally {
       git.close();
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/RemoveReviewerHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/RemoveReviewerHandler.java
index 8849e8e..2b31c1c 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/RemoveReviewerHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/RemoveReviewerHandler.java
@@ -17,8 +17,8 @@
 import com.google.gerrit.common.data.ReviewerResult;
 import com.google.gerrit.httpd.rpc.Handler;
 import com.google.gerrit.httpd.rpc.changedetail.ChangeDetailFactory;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.patch.RemoveReviewer;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java
index 0f14635..06c21df 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/SaveDraft.java
@@ -15,17 +15,17 @@
 package com.google.gerrit.httpd.rpc.patch;
 
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java
index db03f16..44c3141 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/AddBranch.java
@@ -19,8 +19,8 @@
 import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.common.errors.InvalidRevisionException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ReplicationQueue;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
index 18d037f..777329b 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectAccess.java
@@ -22,8 +22,8 @@
 import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
@@ -31,14 +31,13 @@
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.RefControl;
-import com.google.gwtorm.client.OrmConcurrencyException;
+import com.google.gwtorm.server.OrmConcurrencyException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Repository;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -117,28 +116,12 @@
           }
           replace(config, toDelete, section);
 
-        } else if (AccessSection.isAccessSection(name)) {
+        } else if (AccessSection.isValid(name)) {
           if (!projectControl.controlForRef(name).isOwner()) {
             continue;
           }
 
-          if (name.startsWith(AccessSection.REGEX_PREFIX)) {
-            if (!Repository.isValidRefName(RefControl.shortestExample(name))) {
-              throw new InvalidNameException();
-            }
-
-          } else if (name.equals(AccessSection.ALL)) {
-            // This is a special case we have to allow, it fails below.
-
-          } else if (name.endsWith("/*")) {
-            String prefix = name.substring(0, name.length() - 2);
-            if (!Repository.isValidRefName(prefix)) {
-              throw new InvalidNameException();
-            }
-
-          } else if (!Repository.isValidRefName(name)) {
-            throw new InvalidNameException();
-          }
+          RefControl.validateRefPattern(name);
 
           replace(config, toDelete, section);
         }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java
index 7d1ad51..bd6e460 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ChangeProjectSettings.java
@@ -16,15 +16,15 @@
 
 import com.google.gerrit.common.data.ProjectDetail;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.PerRequestProjectControlCache;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwtorm.client.OrmConcurrencyException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmConcurrencyException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/CreateProjectHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/CreateProjectHandler.java
index 8360615..039a301 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/CreateProjectHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/CreateProjectHandler.java
@@ -16,13 +16,13 @@
 
 import com.google.gerrit.common.errors.ProjectCreationFailedException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.SubmitType;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.SubmitType;
 import com.google.gerrit.server.project.CreateProject;
 import com.google.gerrit.server.project.CreateProjectArgs;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gwtjsonrpc.common.VoidResult;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java
index 0f19bbc..073e2d7 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/DeleteBranches.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ReplicationQueue;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ListBranches.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ListBranches.java
index 7be0f66..68fde45 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ListBranches.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ListBranches.java
@@ -16,9 +16,9 @@
 
 import com.google.gerrit.common.data.ListBranchesResult;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.RevId;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
index d2a2900..7ac4ec3 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAccessFactory.java
@@ -18,10 +18,11 @@
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
 import com.google.gerrit.common.data.ProjectAccess;
+import com.google.gerrit.common.data.RefConfigSection;
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.account.GroupControl;
 import com.google.gerrit.server.config.AllProjectsName;
@@ -122,7 +123,7 @@
           ownerOf.add(name);
         }
 
-      } else if (AccessSection.isAccessSection(name)) {
+      } else if (RefConfigSection.isValid(name)) {
         RefControl rc = pc.controlForRef(name);
         if (rc.isOwner()) {
           local.add(section);
@@ -184,17 +185,12 @@
       detail.setRevision(config.getRevision().name());
     }
 
+    detail.setInheritsFrom(config.getProject().getParent(allProjectsName));
+
     if (projectName.equals(allProjectsName)) {
       if (pc.isOwner()) {
         ownerOf.add(AccessSection.GLOBAL_CAPABILITIES);
       }
-      detail.setInheritsFrom(null);
-
-    } else if (config.getProject().getParent() != null) {
-      detail.setInheritsFrom(config.getProject().getParent());
-
-    } else {
-      detail.setInheritsFrom(allProjectsName);
     }
 
     detail.setLocal(local);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
index bf7eeae..a6bb74f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectAdminServiceImpl.java
@@ -20,10 +20,10 @@
 import com.google.gerrit.common.data.ProjectAdminService;
 import com.google.gerrit.common.data.ProjectDetail;
 import com.google.gerrit.common.data.ProjectList;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwtjsonrpc.client.VoidResult;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gwtjsonrpc.common.AsyncCallback;
+import com.google.gwtjsonrpc.common.VoidResult;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.lib.ObjectId;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectDetailFactory.java
index 05f66e9..d782da4 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectDetailFactory.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/ProjectDetailFactory.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.common.data.ProjectDetail;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/SuggestParentCandidatesHandler.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/SuggestParentCandidatesHandler.java
index a6442e3..ba0e4cd 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/SuggestParentCandidatesHandler.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/SuggestParentCandidatesHandler.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.httpd.rpc.project;
 
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.project.SuggestParentCandidates;
 import com.google.inject.Inject;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjectDetails.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjectDetails.java
index 9899147..e12cfb1 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjectDetails.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjectDetails.java
@@ -17,7 +17,7 @@
 
 import com.google.gerrit.common.data.ProjectDetail;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Inject;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjects.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjects.java
index 8d4596f..ba65617 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjects.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/project/VisibleProjects.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.common.data.ProjectList;
 import com.google.gerrit.httpd.rpc.Handler;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectCache;
diff --git a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/rpc/project/ListBranchesTest.java b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/rpc/project/ListBranchesTest.java
index 51fcf2e..5cfde6a 100644
--- a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/rpc/project/ListBranchesTest.java
+++ b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/rpc/project/ListBranchesTest.java
@@ -31,8 +31,8 @@
 import static org.junit.Assert.fail;
 
 import com.google.gerrit.common.data.ListBranchesResult;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
diff --git a/gerrit-launcher/pom.xml b/gerrit-launcher/pom.xml
index 5707a22..7d07652 100644
--- a/gerrit-launcher/pom.xml
+++ b/gerrit-launcher/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-launcher</artifactId>
diff --git a/gerrit-main/pom.xml b/gerrit-main/pom.xml
index 96f1886..9d8320c 100644
--- a/gerrit-main/pom.xml
+++ b/gerrit-main/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-main</artifactId>
diff --git a/gerrit-openid/pom.xml b/gerrit-openid/pom.xml
index 74328cc..ed2625e 100644
--- a/gerrit-openid/pom.xml
+++ b/gerrit-openid/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-openid</artifactId>
@@ -50,11 +50,6 @@
     </dependency>
 
     <dependency>
-      <groupId>com.google.gwt</groupId>
-      <artifactId>gwt-servlet</artifactId>
-    </dependency>
-
-    <dependency>
       <groupId>org.openid4java</groupId>
       <artifactId>openid4java-consumer</artifactId>
       <type>pom</type>
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
index 02ef765..0593bce 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
@@ -21,7 +21,7 @@
 import com.google.gerrit.common.auth.openid.OpenIdService;
 import com.google.gerrit.common.auth.openid.OpenIdUrls;
 import com.google.gerrit.httpd.WebSession;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.UrlEncoded;
 import com.google.gerrit.server.account.AccountException;
@@ -30,7 +30,7 @@
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwtjsonrpc.common.AsyncCallback;
 import com.google.gwtorm.client.KeyUtil;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
diff --git a/gerrit-patch-commonsnet/pom.xml b/gerrit-patch-commonsnet/pom.xml
index f267920..75ee12e 100644
--- a/gerrit-patch-commonsnet/pom.xml
+++ b/gerrit-patch-commonsnet/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-patch-commonsnet</artifactId>
diff --git a/gerrit-patch-jgit/pom.xml b/gerrit-patch-jgit/pom.xml
index 4c2aa0b..f8190f5 100644
--- a/gerrit-patch-jgit/pom.xml
+++ b/gerrit-patch-jgit/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-patch-jgit</artifactId>
diff --git a/gerrit-pgm/pom.xml b/gerrit-pgm/pom.xml
index e816797..1463d15 100644
--- a/gerrit-pgm/pom.xml
+++ b/gerrit-pgm/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-pgm</artifactId>
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index 7382096..25b7699 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -25,6 +25,7 @@
 import com.google.gerrit.httpd.WebSshGlueModule;
 import com.google.gerrit.httpd.auth.openid.OpenIdModule;
 import com.google.gerrit.lifecycle.LifecycleManager;
+import com.google.gerrit.pgm.http.jetty.GetUserFilter;
 import com.google.gerrit.pgm.http.jetty.JettyEnv;
 import com.google.gerrit.pgm.http.jetty.JettyModule;
 import com.google.gerrit.pgm.http.jetty.ProjectQoSFilter;
@@ -32,7 +33,7 @@
 import com.google.gerrit.pgm.util.LogFileCompressor;
 import com.google.gerrit.pgm.util.RuntimeShutdown;
 import com.google.gerrit.pgm.util.SiteProgram;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.AuthConfigModule;
 import com.google.gerrit.server.config.CanonicalWebUrlModule;
@@ -41,6 +42,7 @@
 import com.google.gerrit.server.config.MasterNodeStartup;
 import com.google.gerrit.server.contact.HttpContactStoreConnection;
 import com.google.gerrit.server.git.PushReplication;
+import com.google.gerrit.server.git.ReceiveCommitsExecutorModule;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
 import com.google.gerrit.server.mail.SmtpEmailSender;
@@ -200,6 +202,7 @@
     modules.add(new LogFileCompressor.Module());
     modules.add(new WorkQueue.Module());
     modules.add(new ChangeHookRunner.Module());
+    modules.add(new ReceiveCommitsExecutorModule());
     modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
     modules.add(new EhcachePoolImpl.Module());
     modules.add(new SmtpEmailSender.Module());
@@ -274,6 +277,7 @@
     if (authConfig.getAuthType() == AuthType.OPENID) {
       modules.add(new OpenIdModule());
     }
+    modules.add(sysInjector.getInstance(GetUserFilter.Module.class));
 
     return sysInjector.createChildInjector(modules);
   }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java
index 7842b6c..5f0bc80 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ExportReviewNotes.java
@@ -21,10 +21,10 @@
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.pgm.util.SiteProgram;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountCacheImpl;
 import com.google.gerrit.server.account.GroupCacheImpl;
 import com.google.gerrit.server.cache.CachePool;
@@ -37,8 +37,8 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.LocalDiskRepositoryManager;
 import com.google.gerrit.server.schema.SchemaVersionCheck;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
@@ -97,7 +97,6 @@
             Scopes.SINGLETON);
         bind(String.class).annotatedWith(CanonicalWebUrl.class)
             .toProvider(CanonicalWebUrlProvider.class).in(Scopes.SINGLETON);
-        bind(CachePool.class);
 
         install(AccountCacheImpl.module());
         install(GroupCacheImpl.module());
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
index 68ac33d..f06946f 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
@@ -28,18 +28,18 @@
 import com.google.gerrit.pgm.util.ErrorLogFile;
 import com.google.gerrit.pgm.util.IoUtil;
 import com.google.gerrit.pgm.util.SiteProgram;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.SitePath;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.schema.SchemaUpdater;
 import com.google.gerrit.server.schema.UpdateUI;
 import com.google.gerrit.server.util.HostPlatform;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
-import com.google.gwtorm.client.StatementExecutor;
 import com.google.gwtorm.jdbc.JdbcExecutor;
 import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.gwtorm.server.StatementExecutor;
 import com.google.inject.AbstractModule;
 import com.google.inject.CreationException;
 import com.google.inject.Guice;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
index 082279c..323d7f28 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
@@ -18,11 +18,11 @@
 
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.pgm.util.SiteProgram;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.schema.SchemaVersionCheck;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ProtoGen.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ProtoGen.java
index bc7b254..17b7017 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ProtoGen.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ProtoGen.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.pgm;
 
 import com.google.gerrit.pgm.util.AbstractProgram;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gwtorm.schema.java.JavaSchemaModel;
 
 import org.eclipse.jgit.storage.file.LockFile;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
index 19b1ab9..451ed30 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Rulec.java
@@ -18,7 +18,7 @@
 
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.pgm.util.SiteProgram;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.rules.PrologCompiler;
 import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.git.GitRepositoryManager;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java
index 8bf5f98..c09329a 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/ScanTrackingIds.java
@@ -18,16 +18,16 @@
 
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.pgm.util.SiteProgram;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.config.TrackingFooters;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.schema.SchemaVersionCheck;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/GetUserFilter.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/GetUserFilter.java
new file mode 100644
index 0000000..f54b3c5
--- /dev/null
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/GetUserFilter.java
@@ -0,0 +1,86 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.pgm.http.jetty;
+
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.servlet.ServletModule;
+
+import org.eclipse.jgit.lib.Config;
+
+import java.io.IOException;
+import java.net.URI;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * Stores as a request attribute, so the {@link HttpLog} can include the the
+ * user for the request outside of the request scope.
+ */
+@Singleton
+public class GetUserFilter implements Filter {
+
+  static final String REQ_ATTR_KEY = CurrentUser.class.toString();
+
+  public static class Module extends ServletModule {
+
+    private boolean loggingEnabled;
+
+    @Inject
+    Module(@GerritServerConfig final Config cfg) {
+      URI[] urls = JettyServer.listenURLs(cfg);
+      boolean reverseProxy = JettyServer.isReverseProxied(urls);
+      this.loggingEnabled = cfg.getBoolean("httpd", "requestlog", !reverseProxy);
+    }
+
+    @Override
+    protected void configureServlets() {
+      if (loggingEnabled) {
+        filter("/*").through(GetUserFilter.class);
+      }
+    }
+  }
+
+  private final Provider<CurrentUser> userProvider;
+
+  @Inject
+  GetUserFilter(final Provider<CurrentUser> userProvider) {
+    this.userProvider = userProvider;
+  }
+
+  @Override
+  public void doFilter(
+      ServletRequest req, ServletResponse resp, FilterChain chain)
+      throws IOException, ServletException {
+    req.setAttribute(REQ_ATTR_KEY, userProvider.get());
+    chain.doFilter(req, resp);
+  }
+
+  @Override
+  public void destroy() {
+  }
+
+  @Override
+  public void init(FilterConfig arg0) {
+  }
+}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HttpLog.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
index a4e13d3..6f439d2 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/HttpLog.java
@@ -17,8 +17,6 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.inject.Provider;
-import com.google.inject.servlet.GuiceHelper;
 
 import org.apache.log4j.Appender;
 import org.apache.log4j.AsyncAppender;
@@ -32,6 +30,7 @@
 import org.eclipse.jetty.server.RequestLog;
 import org.eclipse.jetty.server.Response;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jgit.lib.Config;
 
 import java.io.File;
 import java.io.IOException;
@@ -55,11 +54,8 @@
   private static final String P_USER_AGENT = "User-Agent";
 
   private final AsyncAppender async;
-  private final Provider<CurrentUser> userProvider;
 
-  HttpLog(final SitePaths site, final Provider<CurrentUser> userProvider) {
-    this.userProvider = userProvider;
-
+  HttpLog(final SitePaths site, final Config config) {
     final DailyRollingFileAppender dst = new DailyRollingFileAppender();
     dst.setName(LOG_NAME);
     dst.setLayout(new MyLayout());
@@ -74,7 +70,7 @@
 
     async = new AsyncAppender();
     async.setBlocking(true);
-    async.setBufferSize(64);
+    async.setBufferSize(config.getInt("core", "asyncLoggingBufferSize", 64));
     async.setLocationInfo(false);
     async.addAppender(dst);
     async.activateOptions();
@@ -91,18 +87,14 @@
 
   @Override
   public void log(final Request req, final Response rsp) {
-    GuiceHelper.runInContext(req, rsp, new Runnable() {
-      @Override
-      public void run() {
-        doLog(req, rsp);
-      }
-    });
+    CurrentUser user = (CurrentUser) req.getAttribute(GetUserFilter.REQ_ATTR_KEY);
+    doLog(req, rsp, user);
   }
 
-  private void doLog(Request req, Response rsp) {
+  private void doLog(Request req, Response rsp, CurrentUser user) {
     final LoggingEvent event = new LoggingEvent( //
         Logger.class.getName(), // fqnOfCategoryClass
-        null, // logger (optional)
+        log, // logger
         System.currentTimeMillis(), // when
         Level.INFO, // level
         "", // message text
@@ -119,7 +111,6 @@
       uri = uri + "?" + qs;
     }
 
-    CurrentUser user = userProvider.get();
     if (user instanceof IdentifiedUser) {
       IdentifiedUser who = (IdentifiedUser) user;
       if (who.getUserName() != null && !who.getUserName().isEmpty()) {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
index a309e4e..0a0a3cc 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
@@ -19,17 +19,14 @@
 
 import com.google.gerrit.launcher.GerritLauncher;
 import com.google.gerrit.lifecycle.LifecycleListener;
-import com.google.gerrit.reviewdb.AuthType;
-import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
-import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.google.inject.servlet.GuiceFilter;
-import com.google.inject.servlet.GuiceHelper;
 import com.google.inject.servlet.GuiceServletContextListener;
 
 import org.eclipse.jetty.io.EndPoint;
@@ -68,10 +65,6 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 @Singleton
 public class JettyServer {
   static class Lifecycle implements LifecycleListener {
@@ -112,7 +105,7 @@
 
   @Inject
   JettyServer(@GerritServerConfig final Config cfg, final SitePaths site,
-      final JettyEnv env, final Provider<CurrentUser> userProvider)
+      final JettyEnv env)
       throws MalformedURLException, IOException {
     this.site = site;
 
@@ -122,24 +115,8 @@
 
     Handler app = makeContext(env, cfg);
     if (cfg.getBoolean("httpd", "requestlog", !reverseProxy)) {
-      RequestLogHandler handler = new RequestLogHandler() {
-        @Override
-        public void handle(String target, Request baseRequest,
-            final HttpServletRequest req, final HttpServletResponse rsp)
-            throws IOException, ServletException {
-          // Force the user to construct, so it's available to our HttpLog
-          // later on when the request gets logged out to the access file.
-          //
-          GuiceHelper.runInContext(req, rsp, new Runnable() {
-            @Override
-            public void run() {
-              userProvider.get();
-            }
-          });
-          super.handle(target, baseRequest, req, rsp);
-        }
-      };
-      handler.setRequestLog(new HttpLog(site, userProvider));
+      RequestLogHandler handler = new RequestLogHandler();
+      handler.setRequestLog(new HttpLog(site, cfg));
       handler.setHandler(app);
       app = handler;
     }
@@ -164,7 +141,7 @@
     final int acceptors = cfg.getInt("httpd", "acceptorThreads", 2);
     final AuthType authType = ConfigUtil.getEnum(cfg, "auth", null, "type", AuthType.OPENID);
 
-    reverseProxy = true;
+    reverseProxy = isReverseProxied(listenUrls);
     final Connector[] connectors = new Connector[listenUrls.length];
     for (int idx = 0; idx < listenUrls.length; idx++) {
       final URI u = listenUrls[idx];
@@ -179,7 +156,6 @@
       }
 
       if ("http".equals(u.getScheme())) {
-        reverseProxy = false;
         defaultPort = 80;
         c = new SelectChannelConnector();
       } else if ("https".equals(u.getScheme())) {
@@ -198,7 +174,6 @@
           ssl.setNeedClientAuth(true);
         }
 
-        reverseProxy = false;
         defaultPort = 443;
         c = ssl;
 
@@ -256,7 +231,16 @@
     return connectors;
   }
 
-  private URI[] listenURLs(final Config cfg) {
+  static boolean isReverseProxied(final URI[] listenUrls) {
+    for (URI u : listenUrls) {
+      if ("http".equals(u.getScheme()) || "https".equals(u.getScheme())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  static URI[] listenURLs(final Config cfg) {
     String[] urls = cfg.getStringList("httpd", null, "listenurl");
     if (urls.length == 0) {
       urls = new String[] {"http://*:8080/"};
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java
index a4007d5..f809c73 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitAuth.java
@@ -17,7 +17,7 @@
 import static com.google.gerrit.pgm.init.InitUtil.dnOf;
 
 import com.google.gerrit.pgm.util.ConsoleUI;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gwtjsonrpc.server.SignedToken;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java
index 8b4803f..98d2e47 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitHttpd.java
@@ -21,7 +21,7 @@
 import static com.google.gerrit.pgm.init.InitUtil.toURI;
 
 import com.google.gerrit.pgm.util.ConsoleUI;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gwtjsonrpc.server.SignedToken;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java
index 7a3556e..c5732e9 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitSendEmail.java
@@ -28,12 +28,14 @@
 class InitSendEmail implements InitStep {
   private final ConsoleUI ui;
   private final Section sendemail;
+  private final SitePaths site;
 
   @Inject
   InitSendEmail(final ConsoleUI ui, final SitePaths site,
       final Section.Factory sections) {
     this.ui = ui;
     this.sendemail = sections.get("sendemail");
+    this.site = site;
   }
 
   public void run() {
@@ -49,7 +51,9 @@
             true);
 
     String username = null;
-    if ((enc != null && enc != Encryption.NONE) || !isLocal(hostname)) {
+    if (site.gerrit_config.exists()) {
+      username = sendemail.get("smtpUser");
+    } else if ((enc != null && enc != Encryption.NONE) || !isLocal(hostname)) {
       username = username();
     }
     sendemail.string("SMTP username", "smtpUser", username);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/AbstractProgram.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/AbstractProgram.java
index ecd0a16..833b4d8 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/AbstractProgram.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/AbstractProgram.java
@@ -34,9 +34,6 @@
   @Option(name = "--show-stack-trace", usage = "display stack trace on failure")
   protected boolean showStackTrace;
 
-  @Option(name = "--help", usage = "display this help text", aliases = {"-h"})
-  private boolean help;
-
   private String getName() {
     String n = getClass().getName();
     int dot = n.lastIndexOf('.');
@@ -52,21 +49,15 @@
     try {
       clp.parseArgument(argv);
     } catch (CmdLineException err) {
-      if (!help) {
+      if (!clp.wasHelpRequestedByOption()) {
         System.err.println("fatal: " + err.getMessage());
         return 1;
       }
     }
 
-    if (help) {
-      final StringWriter msg = new StringWriter();
-      msg.write(getName());
-      clp.printSingleLineUsage(msg, null);
-      msg.write('\n');
-
-      msg.write('\n');
-      clp.printUsage(msg, null);
-      msg.write('\n');
+    if (clp.wasHelpRequestedByOption()) {
+      StringWriter msg = new StringWriter();
+      clp.printDetailedUsage(getName(), msg);
       System.err.println(msg.toString());
       return 1;
     }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
index 7bc6c0a..4893579 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -24,7 +24,7 @@
 import com.google.gerrit.server.schema.DataSourceProvider;
 import com.google.gerrit.server.schema.DatabaseModule;
 import com.google.gerrit.server.schema.SchemaModule;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.AbstractModule;
 import com.google.inject.CreationException;
 import com.google.inject.Guice;
diff --git a/gerrit-pgm/src/main/java/com/google/inject/servlet/GuiceHelper.java b/gerrit-pgm/src/main/java/com/google/inject/servlet/GuiceHelper.java
deleted file mode 100644
index 5b6cc09..0000000
--- a/gerrit-pgm/src/main/java/com/google/inject/servlet/GuiceHelper.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (C) 2010 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.inject.servlet;
-
-import com.google.inject.servlet.GuiceFilter.Context;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public class GuiceHelper {
-  public static void runInContext(HttpServletRequest req,
-      HttpServletResponse rsp, Runnable thunk) {
-    Context previous = GuiceFilter.localContext.get();
-    try {
-      GuiceFilter.localContext.set(new Context(req, rsp));
-      thunk.run();
-    } finally {
-      GuiceFilter.localContext.set(previous);
-    }
-  }
-
-  private GuiceHelper() {
-  }
-}
diff --git a/gerrit-prettify/pom.xml b/gerrit-prettify/pom.xml
index 4f05573..f5bd3d6 100644
--- a/gerrit-prettify/pom.xml
+++ b/gerrit-prettify/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-prettify</artifactId>
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java
index 5d1592d..c9a9ab8 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.prettify.common;
 
-import com.google.gerrit.reviewdb.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
 import com.google.gwtexpui.safehtml.client.SafeHtml;
 import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
 
diff --git a/gerrit-reviewdb/pom.xml b/gerrit-reviewdb/pom.xml
index 5e8a37c..24d6a1b 100644
--- a/gerrit-reviewdb/pom.xml
+++ b/gerrit-reviewdb/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-reviewdb</artifactId>
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/ReviewDB.gwt.xml b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDB.gwt.xml
similarity index 95%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/ReviewDB.gwt.xml
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDB.gwt.xml
index c5f8912..4402826 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/ReviewDB.gwt.xml
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDB.gwt.xml
@@ -15,5 +15,4 @@
 -->
 <module>
   <inherits name='com.google.gwtorm.GWTORM'/>
-  <source path='reviewdb' />
 </module>
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AbstractAgreement.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AbstractAgreement.java
similarity index 96%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AbstractAgreement.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AbstractAgreement.java
index 987fc4b..0ed7410 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AbstractAgreement.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AbstractAgreement.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import java.sql.Timestamp;
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Account.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Account.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
index be2cb20..b23aa86 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Account.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
@@ -146,7 +146,8 @@
   /**
    * Create a new account.
    *
-   * @param newId unique id, see {@link ReviewDb#nextAccountId()}.
+   * @param newId unique id, see
+   *        {@link com.google.gerrit.reviewdb.server.ReviewDb#nextAccountId()}.
    */
   public Account(final Account.Id newId) {
     accountId = newId;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreement.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountAgreement.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreement.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountAgreement.java
index 57b9340..baa9b5c 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreement.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountAgreement.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountDiffPreference.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
similarity index 94%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountDiffPreference.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
index c362f26..3b04725 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountDiffPreference.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountDiffPreference.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 
@@ -65,6 +65,7 @@
     p.setIntralineDifference(true);
     p.setShowTabs(true);
     p.setContext(DEFAULT_CONTEXT);
+    p.setManualReview(false);
     return p;
   }
 
@@ -108,6 +109,9 @@
   @Column(id = 13)
   protected boolean retainHeader;
 
+  @Column(id = 14)
+  protected boolean manualReview;
+
   protected AccountDiffPreference() {
   }
 
@@ -129,6 +133,7 @@
     this.expandAllComments = p.expandAllComments;
     this.context = p.context;
     this.retainHeader = p.retainHeader;
+    this.manualReview = p.manualReview;
   }
 
   public Account.Id getAccountId() {
@@ -233,4 +238,12 @@
   public void setRetainHeader(boolean retain) {
     retainHeader = retain;
   }
+
+  public boolean isManualReview() {
+    return manualReview;
+  }
+
+  public void setManualReview(boolean manual) {
+    manualReview = manual;
+  }
 }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountExternalId.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountExternalId.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountExternalId.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountExternalId.java
index 853ebd5..0705284 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountExternalId.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountExternalId.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGeneralPreferences.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGeneralPreferences.java
similarity index 99%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGeneralPreferences.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGeneralPreferences.java
index ebaf0c8..b9ff4fb 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGeneralPreferences.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGeneralPreferences.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroup.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroup.java
similarity index 94%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroup.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroup.java
index 5d8a4b9..8e2541a 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroup.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroup.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
@@ -216,11 +216,6 @@
   @Column(id = 7)
   protected boolean visibleToAll;
 
-  /** Comment and action email notifications by users in this group are only
-   *  sent to change authors. */
-  @Column(id = 8)
-  protected boolean emailOnlyAuthors;
-
   /** Globally unique identifier name for this group. */
   @Column(id = 9)
   protected UUID groupUUID;
@@ -294,14 +289,6 @@
     return visibleToAll;
   }
 
-  public boolean isEmailOnlyAuthors() {
-    return emailOnlyAuthors;
-  }
-
-  public void setEmailOnlyAuthors(boolean emailOnlyAuthors) {
-    this.emailOnlyAuthors = emailOnlyAuthors;
-  }
-
   public AccountGroup.UUID getGroupUUID() {
     return groupUUID;
   }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreement.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupAgreement.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreement.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupAgreement.java
index fd5d58b..c712b3d 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreement.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupAgreement.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupInclude.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupInclude.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupInclude.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupInclude.java
index 86b0966..4b58689 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupInclude.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupInclude.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAudit.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupIncludeAudit.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAudit.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupIncludeAudit.java
index 326dfd3..275c3c3 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAudit.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupIncludeAudit.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMember.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupMember.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMember.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupMember.java
index 1ca9123..4869cf8 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMember.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupMember.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAudit.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupMemberAudit.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAudit.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupMemberAudit.java
index 7547efb..8ba8912 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAudit.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupMemberAudit.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupName.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupName.java
similarity index 96%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupName.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupName.java
index 3b31dc6..701f2c3 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupName.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountGroupName.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountPatchReview.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountPatchReview.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountPatchReview.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountPatchReview.java
index 4d16bb6..a1c3c3c 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountPatchReview.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountPatchReview.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountProjectWatch.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountProjectWatch.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountProjectWatch.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountProjectWatch.java
index 6c62e12..93e6fb3 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountProjectWatch.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountProjectWatch.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountSshKey.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountSshKey.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountSshKey.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountSshKey.java
index 7a79980..8c4ac82 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountSshKey.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AccountSshKey.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategory.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ApprovalCategory.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategory.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ApprovalCategory.java
index d7e5024..bb25265 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategory.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ApprovalCategory.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.Key;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryValue.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ApprovalCategoryValue.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryValue.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ApprovalCategoryValue.java
index 84f0a17..b7761c5 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryValue.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ApprovalCategoryValue.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.ShortKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AuthType.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AuthType.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
index 843f41b..962426b 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AuthType.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/AuthType.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 public enum AuthType {
   /** Login relies upon the OpenID standard: {@link "http://openid.net/"} */
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Branch.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Branch.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Branch.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Branch.java
index 27716a8..e1a15e5 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Branch.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Branch.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Change.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Change.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
index fc544fa..61e6a97 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Change.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Change.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
@@ -182,16 +182,16 @@
   /** Minimum database status constant for an open change. */
   private static final char MIN_OPEN = 'a';
   /** Database constant for {@link Status#NEW}. */
-  protected static final char STATUS_NEW = 'n';
+  public static final char STATUS_NEW = 'n';
   /** Database constant for {@link Status#SUBMITTED}. */
-  protected static final char STATUS_SUBMITTED = 's';
+  public static final char STATUS_SUBMITTED = 's';
   /** Database constant for {@link Status#DRAFT}. */
-  protected static final char STATUS_DRAFT = 'd';
+  public static final char STATUS_DRAFT = 'd';
   /** Maximum database status constant for an open change. */
   private static final char MAX_OPEN = 'z';
 
   /** Database constant for {@link Status#MERGED}. */
-  protected static final char STATUS_MERGED = 'M';
+  public static final char STATUS_MERGED = 'M';
 
   /**
    * Current state within the basic workflow of the change.
@@ -432,6 +432,10 @@
     lastUpdatedOn = new Timestamp(System.currentTimeMillis());
   }
 
+  public int getNumberOfPatchSets() {
+    return nbrPatchSets;
+  }
+
   public String getSortKey() {
     return sortKey;
   }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeMessage.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ChangeMessage.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeMessage.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ChangeMessage.java
index d8f1dd4..e05f5e7 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeMessage.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ChangeMessage.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CodedEnum.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CodedEnum.java
similarity index 94%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CodedEnum.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CodedEnum.java
index 5900292..11e7efa 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CodedEnum.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CodedEnum.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 /** Extension of Enum which provides distinct character code values. */
 public interface CodedEnum {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContactInformation.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ContactInformation.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContactInformation.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ContactInformation.java
index d28467c..195387c 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContactInformation.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ContactInformation.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContributorAgreement.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ContributorAgreement.java
similarity index 95%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContributorAgreement.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ContributorAgreement.java
index 9e285b8..12e7459 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContributorAgreement.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/ContributorAgreement.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
@@ -80,7 +80,8 @@
   /**
    * Create a new agreement.
    *
-   * @param newId unique id, see {@link ReviewDb#nextAccountId()}.
+   * @param newId unique id, see
+   *        {@link com.google.gerrit.reviewdb.server.ReviewDb#nextAccountId()}.
    * @param name a short title/name for the agreement.
    */
   public ContributorAgreement(final ContributorAgreement.Id newId,
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CurrentSchemaVersion.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CurrentSchemaVersion.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CurrentSchemaVersion.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CurrentSchemaVersion.java
index 8878225..183bb1e 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CurrentSchemaVersion.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/CurrentSchemaVersion.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Patch.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
similarity index 99%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Patch.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
index 0153755..0d0ea88 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Patch.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Patch.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchLineComment.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
similarity index 96%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchLineComment.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
index 0828c95..c8a970d 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchLineComment.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchLineComment.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
@@ -55,8 +55,8 @@
     }
   }
 
-  protected static final char STATUS_DRAFT = 'd';
-  protected static final char STATUS_PUBLISHED = 'P';
+  public static final char STATUS_DRAFT = 'd';
+  public static final char STATUS_PUBLISHED = 'P';
 
   public static enum Status {
     DRAFT(STATUS_DRAFT),
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSet.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSet.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSet.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSet.java
index 1e7643f..83ce828 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSet.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSet.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAncestor.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetAncestor.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAncestor.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetAncestor.java
index 8310e4d..8412788 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAncestor.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetAncestor.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.IntKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetApproval.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetApproval.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetApproval.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetApproval.java
index a3698f4..04b2b6f 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetApproval.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetApproval.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetInfo.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetInfo.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetInfo.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetInfo.java
index f96a5b3..1a00fae 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetInfo.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/PatchSetInfo.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import java.util.List;
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
similarity index 83%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
index 33c6d31..a2fc46f 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/Project.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Project.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
@@ -184,10 +184,36 @@
     state = update.state;
   }
 
+  /**
+   * Returns the name key of the parent project.
+   *
+   * @return name key of the parent project, <code>null</code> if this project
+   *         is the wild project, <code>null</code> or the name key of the wild
+   *         project if this project is a direct child of the wild project
+   */
   public Project.NameKey getParent() {
     return parent;
   }
 
+  /**
+   * Returns the name key of the parent project.
+   *
+   * @param allProjectsName name key of the wild project
+   * @return name key of the parent project, <code>null</code> if this project
+   *         is the wild project
+   */
+  public Project.NameKey getParent(final Project.NameKey allProjectsName) {
+    if (parent != null) {
+      return parent;
+    }
+
+    if (name.equals(allProjectsName)) {
+      return null;
+    }
+
+    return allProjectsName;
+  }
+
   public String getParentName() {
     return parent != null ? parent.get() : null;
   }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/RevId.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RevId.java
similarity index 96%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/RevId.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RevId.java
index 7077312..d90a81c 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/RevId.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/RevId.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/StarredChange.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/StarredChange.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/StarredChange.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/StarredChange.java
index 426bd11..d427b09 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/StarredChange.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/StarredChange.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SubmoduleSubscription.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/SubmoduleSubscription.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SubmoduleSubscription.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/SubmoduleSubscription.java
index 026348a..32a9131 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SubmoduleSubscription.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/SubmoduleSubscription.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SystemConfig.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/SystemConfig.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SystemConfig.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/SystemConfig.java
index e366a47..0f8d005 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SystemConfig.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/SystemConfig.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.StringKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/TrackingId.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/TrackingId.java
similarity index 98%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/TrackingId.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/TrackingId.java
index 1548807..e73dd73 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/TrackingId.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/TrackingId.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import com.google.gwtorm.client.Column;
 import com.google.gwtorm.client.CompoundKey;
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/UserIdentity.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/UserIdentity.java
similarity index 97%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/UserIdentity.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/UserIdentity.java
index 6eabbda..c7b4cfe 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/UserIdentity.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/UserIdentity.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.client;
 
 import java.sql.Timestamp;
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountAccess.java
similarity index 82%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountAccess.java
index d7a784a..2b23b7a 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountAccess.java
@@ -12,13 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 /** Access interface for {@link Account}. */
 public interface AccountAccess extends Access<Account, Account.Id> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreementAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountAgreementAccess.java
similarity index 66%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreementAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountAgreementAccess.java
index f65af5e..86ea372 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountAgreementAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountAgreementAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountAgreement;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gerrit.reviewdb.client.AccountAgreement.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountAgreementAccess extends
     Access<AccountAgreement, AccountAgreement.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountDiffPreferenceAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountDiffPreferenceAccess.java
similarity index 70%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountDiffPreferenceAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountDiffPreferenceAccess.java
index d1d134b..8574758 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountDiffPreferenceAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountDiffPreferenceAccess.java
@@ -12,11 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
 
 public interface AccountDiffPreferenceAccess extends Access<AccountDiffPreference, Account.Id> {
 
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountExternalIdAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountExternalIdAccess.java
similarity index 77%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountExternalIdAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountExternalIdAccess.java
index 4c78139..b263552 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountExternalIdAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountExternalIdAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gerrit.reviewdb.client.AccountExternalId.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountExternalIdAccess extends
     Access<AccountExternalId, AccountExternalId.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupAccess.java
similarity index 77%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupAccess.java
index 7eb7ed2..9e88244 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupAccess.java
@@ -12,13 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountGroupAccess extends
     Access<AccountGroup, AccountGroup.Id> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreementAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupAgreementAccess.java
similarity index 66%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreementAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupAgreementAccess.java
index d4a1fcd..ecab70d 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupAgreementAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupAgreementAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupAgreement;
+import com.google.gerrit.reviewdb.client.AccountGroup.Id;
+import com.google.gerrit.reviewdb.client.AccountGroupAgreement.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountGroupAgreementAccess extends
     Access<AccountGroupAgreement, AccountGroupAgreement.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupIncludeAccess.java
similarity index 68%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupIncludeAccess.java
index 4881635..c8c7b40 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupIncludeAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroup.Id;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountGroupIncludeAccess extends
     Access<AccountGroupInclude, AccountGroupInclude.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAuditAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupIncludeAuditAccess.java
similarity index 67%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAuditAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupIncludeAuditAccess.java
index 55b50e8..3cf24f3 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupIncludeAuditAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupIncludeAuditAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit;
+import com.google.gerrit.reviewdb.client.AccountGroup.Id;
+import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountGroupIncludeAuditAccess extends
     Access<AccountGroupIncludeAudit, AccountGroupIncludeAudit.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupMemberAccess.java
similarity index 65%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupMemberAccess.java
index 48a20e3..53ecaae 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupMemberAccess.java
@@ -12,13 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroup.Id;
+import com.google.gerrit.reviewdb.client.AccountGroupMember.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountGroupMemberAccess extends
     Access<AccountGroupMember, AccountGroupMember.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAuditAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupMemberAuditAccess.java
similarity index 65%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAuditAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupMemberAuditAccess.java
index b112059..f26996d 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupMemberAuditAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupMemberAuditAccess.java
@@ -12,13 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.client.AccountGroup.Id;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountGroupMemberAuditAccess extends
     Access<AccountGroupMemberAudit, AccountGroupMemberAudit.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupNameAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupNameAccess.java
similarity index 71%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupNameAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupNameAccess.java
index 12db5ce..d0bc419 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountGroupNameAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountGroupNameAccess.java
@@ -12,13 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.client.AccountGroup.NameKey;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 
 public interface AccountGroupNameAccess extends
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountPatchReviewAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountPatchReviewAccess.java
similarity index 67%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountPatchReviewAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountPatchReviewAccess.java
index e1fa4d4..ef8133b 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountPatchReviewAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountPatchReviewAccess.java
@@ -12,13 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountPatchReview;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gerrit.reviewdb.client.AccountPatchReview.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountPatchReviewAccess
     extends Access<AccountPatchReview, AccountPatchReview.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountProjectWatchAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountProjectWatchAccess.java
similarity index 64%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountProjectWatchAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountProjectWatchAccess.java
index 254aac9..046d5a5 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountProjectWatchAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountProjectWatchAccess.java
@@ -12,13 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch.Key;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountProjectWatchAccess extends
     Access<AccountProjectWatch, AccountProjectWatch.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountSshKeyAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountSshKeyAccess.java
similarity index 68%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountSshKeyAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountSshKeyAccess.java
index 5c511b1..d756a44 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/AccountSshKeyAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/AccountSshKeyAccess.java
@@ -12,13 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface AccountSshKeyAccess extends
     Access<AccountSshKey, AccountSshKey.Id> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ApprovalCategoryAccess.java
similarity index 70%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ApprovalCategoryAccess.java
index d3601f2..31e6c62 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ApprovalCategoryAccess.java
@@ -12,13 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategory.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface ApprovalCategoryAccess extends
     Access<ApprovalCategory, ApprovalCategory.Id> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryValueAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ApprovalCategoryValueAccess.java
similarity index 69%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryValueAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ApprovalCategoryValueAccess.java
index e86d652..acdda5e8 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ApprovalCategoryValueAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ApprovalCategoryValueAccess.java
@@ -12,13 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.ApprovalCategory.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface ApprovalCategoryValueAccess extends
     Access<ApprovalCategoryValue, ApprovalCategoryValue.Id> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeAccess.java
similarity index 78%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeAccess.java
index 9c4605e..4660291 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeAccess.java
@@ -12,13 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Change.Id;
+import com.google.gerrit.reviewdb.client.Change.Key;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface ChangeAccess extends Access<Change, Change.Id> {
   @PrimaryKey("changeId")
@@ -94,6 +101,16 @@
   ResultSet<Change> allClosedNext(char status, String sortKey, int limit)
       throws OrmException;
 
+  @Query("WHERE open = false AND status = ? AND dest = ? AND sortKey > ?"
+      + " ORDER BY sortKey LIMIT ?")
+  ResultSet<Change> byBranchClosedPrev(char status, Branch.NameKey p,
+      String sortKey, int limit) throws OrmException;
+
+  @Query("WHERE open = false AND status = ? AND dest = ? AND sortKey < ?"
+      + " ORDER BY sortKey DESC LIMIT ?")
+  ResultSet<Change> byBranchClosedNext(char status, Branch.NameKey p,
+      String sortKey, int limit) throws OrmException;
+
   @Query
   ResultSet<Change> all() throws OrmException;
 }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeMessageAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeMessageAccess.java
similarity index 67%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeMessageAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeMessageAccess.java
index 725c49f..6db2675 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ChangeMessageAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ChangeMessageAccess.java
@@ -12,13 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Change.Id;
+import com.google.gerrit.reviewdb.client.ChangeMessage.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface ChangeMessageAccess extends
     Access<ChangeMessage, ChangeMessage.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContributorAgreementAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ContributorAgreementAccess.java
similarity index 72%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContributorAgreementAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ContributorAgreementAccess.java
index ae7b41d..3c7f47a 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ContributorAgreementAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ContributorAgreementAccess.java
@@ -12,13 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.ContributorAgreement.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 /** Access interface for {@link ContributorAgreement}. */
 public interface ContributorAgreementAccess extends
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchLineCommentAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchLineCommentAccess.java
similarity index 80%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchLineCommentAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchLineCommentAccess.java
index 29588e1..3be8563 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchLineCommentAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchLineCommentAccess.java
@@ -12,13 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Change.Id;
+import com.google.gerrit.reviewdb.client.PatchLineComment.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface PatchLineCommentAccess extends
     Access<PatchLineComment, PatchLineComment.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetAccess.java
similarity index 71%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetAccess.java
index c9d4b4f..c04fa06 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.client.Change.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface PatchSetAccess extends Access<PatchSet, PatchSet.Id> {
   @PrimaryKey("id")
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAncestorAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetAncestorAccess.java
similarity index 71%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAncestorAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetAncestorAccess.java
index 838af5d..e163bc4 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetAncestorAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetAncestorAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetAncestor;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.client.PatchSetAncestor.Id;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface PatchSetAncestorAccess extends
     Access<PatchSetAncestor, PatchSetAncestor.Id> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetApprovalAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetApprovalAccess.java
similarity index 74%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetApprovalAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetApprovalAccess.java
index 417d264..b30c5bfa 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/PatchSetApprovalAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/PatchSetApprovalAccess.java
@@ -12,13 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+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.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Change.Id;
+import com.google.gerrit.reviewdb.client.PatchSetApproval.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface PatchSetApprovalAccess extends
     Access<PatchSetApproval, PatchSetApproval.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDb.java
similarity index 88%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDb.java
index cd4414e..616a656 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/ReviewDb.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/ReviewDb.java
@@ -12,12 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.Relation;
-import com.google.gwtorm.client.Schema;
-import com.google.gwtorm.client.Sequence;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.Relation;
+import com.google.gwtorm.server.Schema;
+import com.google.gwtorm.server.Sequence;
 
 /**
  * The review service database schema.
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SchemaVersionAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SchemaVersionAccess.java
similarity index 74%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SchemaVersionAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SchemaVersionAccess.java
index eec1643..07f255c 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SchemaVersionAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SchemaVersionAccess.java
@@ -12,11 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
 
 /** Access interface for {@link CurrentSchemaVersion}. */
 public interface SchemaVersionAccess extends
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/StarredChangeAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/StarredChangeAccess.java
similarity index 65%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/StarredChangeAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/StarredChangeAccess.java
index 9e31dbf..88e703a 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/StarredChangeAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/StarredChangeAccess.java
@@ -12,13 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.StarredChange;
+import com.google.gerrit.reviewdb.client.Change.Id;
+import com.google.gerrit.reviewdb.client.StarredChange.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface StarredChangeAccess extends
     Access<StarredChange, StarredChange.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SubmoduleSubscriptionAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SubmoduleSubscriptionAccess.java
similarity index 69%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SubmoduleSubscriptionAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SubmoduleSubscriptionAccess.java
index 909bd57..e1aa907 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SubmoduleSubscriptionAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SubmoduleSubscriptionAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
+import com.google.gerrit.reviewdb.client.Branch.NameKey;
+import com.google.gerrit.reviewdb.client.SubmoduleSubscription.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface SubmoduleSubscriptionAccess extends
     Access<SubmoduleSubscription, SubmoduleSubscription.Key> {
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SystemConfigAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SystemConfigAccess.java
similarity index 71%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SystemConfigAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SystemConfigAccess.java
index dfca1ca..3bb07cb 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/SystemConfigAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/SystemConfigAccess.java
@@ -12,13 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.client.SystemConfig.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 /** Access interface for {@link SystemConfig}. */
 public interface SystemConfigAccess extends
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/TrackingIdAccess.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/TrackingIdAccess.java
similarity index 68%
rename from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/TrackingIdAccess.java
rename to gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/TrackingIdAccess.java
index ad851a4..51babb3 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/TrackingIdAccess.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/server/TrackingIdAccess.java
@@ -12,13 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.reviewdb.server;
 
-import com.google.gwtorm.client.Access;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.PrimaryKey;
-import com.google.gwtorm.client.Query;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.TrackingId;
+import com.google.gerrit.reviewdb.client.Change.Id;
+import com.google.gerrit.reviewdb.client.TrackingId.Key;
+import com.google.gwtorm.server.Access;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.PrimaryKey;
+import com.google.gwtorm.server.Query;
+import com.google.gwtorm.server.ResultSet;
 
 public interface TrackingIdAccess extends Access<TrackingId, TrackingId.Key> {
   @PrimaryKey("key")
diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_generic.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql
similarity index 96%
rename from gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_generic.sql
rename to gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql
index 83f7d15..5d0e15c 100644
--- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_generic.sql
+++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_generic.sql
@@ -109,6 +109,10 @@
 CREATE INDEX changes_allClosed
 ON changes (open, status, sort_key);
 
+--    covers:             byBranchClosedPrev, byBranchClosedNext
+CREATE INDEX changes_byBranchClosed
+ON changes (status, dest_project_name, dest_branch_name, sort_key);
+
 CREATE INDEX changes_key
 ON changes (change_key);
 
diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_postgres.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql
similarity index 97%
rename from gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_postgres.sql
rename to gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql
index 3afa7ef..97ad126 100644
--- a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/index_postgres.sql
+++ b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/index_postgres.sql
@@ -187,6 +187,11 @@
 CREATE INDEX changes_byProject
 ON changes (dest_project_name);
 
+--    covers:             byBranchClosedPrev, byBranchClosedNext
+CREATE INDEX changes_byBranchClosed
+ON changes (status, dest_project_name, dest_branch_name, sort_key)
+WHERE open = 'N';
+
 CREATE INDEX changes_key
 ON changes (change_key);
 
diff --git a/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/mysql_nextval.sql b/gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/mysql_nextval.sql
similarity index 100%
rename from gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/mysql_nextval.sql
rename to gerrit-reviewdb/src/main/resources/com/google/gerrit/reviewdb/server/mysql_nextval.sql
diff --git a/gerrit-server/pom.xml b/gerrit-server/pom.xml
index 20a7286..58e43cf 100644
--- a/gerrit-server/pom.xml
+++ b/gerrit-server/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-server</artifactId>
@@ -90,17 +90,17 @@
     </dependency>
 
     <dependency>
-      <groupId>com.google.code.guice</groupId>
+      <groupId>com.google.inject</groupId>
       <artifactId>guice</artifactId>
     </dependency>
 
     <dependency>
-      <groupId>com.google.code.guice</groupId>
+      <groupId>com.google.inject.extensions</groupId>
       <artifactId>guice-servlet</artifactId>
     </dependency>
 
     <dependency>
-      <groupId>com.google.code.guice</groupId>
+      <groupId>com.google.inject.extensions</groupId>
       <artifactId>guice-assistedinject</artifactId>
     </dependency>
 
@@ -123,6 +123,12 @@
 
     <dependency>
       <groupId>com.google.gerrit</groupId>
+      <artifactId>gerrit-util-cli</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.google.gerrit</groupId>
       <artifactId>gerrit-util-ssl</artifactId>
       <version>${project.version}</version>
     </dependency>
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
index 6ecf19b..31837b0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHookRunner.java
@@ -16,15 +16,15 @@
 
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
@@ -45,7 +45,7 @@
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.ProjectState;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -242,7 +242,7 @@
         addArg(args, "--commit", event.patchSet.revision);
         addArg(args, "--patchset", event.patchSet.number);
 
-        runHook(openRepository(change), patchsetCreatedHook, args);
+        runHook(change.getProject(), patchsetCreatedHook, args);
     }
 
     public void doCommentAddedHook(final Change change, final Account account,
@@ -277,7 +277,7 @@
             addArg(args, "--" + approval.getKey().get(), Short.toString(approval.getValue().get()));
         }
 
-        runHook(openRepository(change), commentAddedHook, args);
+        runHook(change.getProject(), commentAddedHook, args);
     }
 
     public void doChangeMergedHook(final Change change, final Account account,
@@ -297,7 +297,7 @@
         addArg(args, "--submitter", getDisplayName(account));
         addArg(args, "--commit", event.patchSet.revision);
 
-        runHook(openRepository(change), changeMergedHook, args);
+        runHook(change.getProject(), changeMergedHook, args);
     }
 
     public void doChangeAbandonedHook(final Change change, final Account account,
@@ -317,7 +317,7 @@
         addArg(args, "--abandoner", getDisplayName(account));
         addArg(args, "--reason", reason == null ? "" : reason);
 
-        runHook(openRepository(change), changeAbandonedHook, args);
+        runHook(change.getProject(), changeAbandonedHook, args);
     }
 
     public void doChangeRestoreHook(final Change change, final Account account,
@@ -337,7 +337,7 @@
         addArg(args, "--restorer", getDisplayName(account));
         addArg(args, "--reason", reason == null ? "" : reason);
 
-        runHook(openRepository(change), changeRestoredHook, args);
+        runHook(change.getProject(), changeRestoredHook, args);
     }
 
     public void doRefUpdatedHook(final Branch.NameKey refName, final RefUpdate refUpdate, final Account account) {
@@ -362,7 +362,7 @@
         addArg(args, "--submitter", getDisplayName(account));
       }
 
-      runHook(openRepository(refName.getParentKey()), refUpdatedHook, args);
+      runHook(refName.getParentKey(), refUpdatedHook, args);
     }
 
     public void doClaSignupHook(Account account, ContributorAgreement cla) {
@@ -448,18 +448,14 @@
   /**
    * Run a hook.
    *
-   * @param repo repository to run the hook for.
+   * @param project used to open repository to run the hook for.
    * @param hook the hook to execute.
    * @param args Arguments to use to run the hook.
    */
-  private synchronized void runHook(Repository repo, File hook,
+  private synchronized void runHook(Project.NameKey project, File hook,
       List<String> args) {
-    if (repo != null) {
-      if (hook.exists()) {
-        hookQueue.execute(new HookTask(repo, hook, args));
-      } else {
-        repo.close();
-      }
+    if (project != null && hook.exists()) {
+      hookQueue.execute(new HookTask(project, hook, args));
     }
   }
 
@@ -470,18 +466,19 @@
   }
 
   private final class HookTask implements Runnable {
-    private final Repository repo;
+    private final Project.NameKey project;
     private final File hook;
     private final List<String> args;
 
-    private HookTask(Repository repo, File hook, List<String> args) {
-      this.repo = repo;
+    private HookTask(Project.NameKey project, File hook, List<String> args) {
+      this.project = project;
       this.hook = hook;
       this.args = args;
     }
 
     @Override
     public void run() {
+      Repository repo = null;
       try {
         final List<String> argv = new ArrayList<String>(1 + args.size());
         argv.add(hook.getAbsolutePath());
@@ -489,6 +486,11 @@
 
         final ProcessBuilder pb = new ProcessBuilder(argv);
         pb.redirectErrorStream(true);
+
+        if (project != null) {
+          repo = openRepository(project);
+        }
+
         if (repo != null) {
           pb.directory(repo.getDirectory());
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
index 3447c1f..c424a26 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/ChangeHooks.java
@@ -14,16 +14,16 @@
 
 package com.google.gerrit.common;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.RefUpdate;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
index 7f61f62..5544216 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/common/DisabledChangeHooks.java
@@ -14,14 +14,14 @@
 
 package com.google.gerrit.common;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.Branch.NameKey;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Branch.NameKey;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 
 import org.eclipse.jgit.lib.ObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java b/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
index 8d9633f..fd72e0c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/RulesCache.java
@@ -16,7 +16,7 @@
 
 import static com.googlecode.prolog_cafe.lang.PrologMachineCopy.save;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.git.GitRepositoryManager;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
index de85742..8ab9471 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/rules/StoredValues.java
@@ -16,12 +16,12 @@
 
 import static com.google.gerrit.rules.StoredValue.create;
 
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListCache;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
index c1263ef..5d36b33 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/AnonymousUser.java
@@ -14,10 +14,12 @@
 
 package com.google.gerrit.server;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.ListGroupMembership;
 import com.google.inject.Inject;
 
 import java.util.Collection;
@@ -32,8 +34,8 @@
   }
 
   @Override
-  public Set<AccountGroup.UUID> getEffectiveGroups() {
-    return Collections.singleton(AccountGroup.ANONYMOUS_USERS);
+  public GroupMembership getEffectiveGroups() {
+    return new ListGroupMembership(Collections.singleton(AccountGroup.ANONYMOUS_USERS));
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
index 6997d47..3417111 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ApprovalsUtil.java
@@ -14,11 +14,17 @@
 
 package com.google.gerrit.server;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.common.data.ApprovalType;
+import com.google.gerrit.common.data.ApprovalTypes;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
 
+import java.io.IOException;
+import java.util.Collections;
 import java.util.List;
 
 public class ApprovalsUtil {
@@ -33,4 +39,36 @@
     }
     db.patchSetApprovals().update(approvals);
   }
+
+  /**
+   * Moves the PatchSetApprovals to the last PatchSet on the change while
+   * keeping the vetos.
+   *
+   * @param db The review database
+   * @param change Change to update
+   * @param approvalTypes The approval types
+   * @throws OrmException
+   * @throws IOException
+   */
+  public static void copyVetosToLatestPatchSet(final ReviewDb db, Change change,
+      ApprovalTypes approvalTypes) throws OrmException, IOException {
+    PatchSet.Id source;
+    if (change.getNumberOfPatchSets() > 1) {
+      source = new PatchSet.Id(change.getId(), change.getNumberOfPatchSets() - 1);
+    } else {
+      throw new IOException("Previous patch set could not be found");
+    }
+
+    PatchSet.Id dest = change.currPatchSetId();
+    for (PatchSetApproval a : db.patchSetApprovals().byPatchSet(source)) {
+      // ApprovalCategory.SUBMIT is still in db but not relevant in git-store
+      if (!ApprovalCategory.SUBMIT.equals(a.getCategoryId())) {
+        final ApprovalType type = approvalTypes.byId(a.getCategoryId());
+        if (type.getCategory().isCopyMinScore() && type.isMaxNegative(a)) {
+          db.patchSetApprovals().insert(
+              Collections.singleton(new PatchSetApproval(dest, a)));
+        }
+      }
+    }
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
index 55de507..9dc572d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
@@ -14,29 +14,38 @@
 
 package com.google.gerrit.server;
 
+import com.google.gerrit.common.ChangeHookRunner;
 import com.google.gerrit.common.ChangeHooks;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.TrackingId;
+import com.google.gerrit.common.data.ApprovalTypes;
+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.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetAncestor;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.client.TrackingId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.TrackingFooter;
 import com.google.gerrit.server.config.TrackingFooters;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeOp;
 import com.google.gerrit.server.git.ReplicationQueue;
 import com.google.gerrit.server.mail.EmailException;
+import com.google.gerrit.server.mail.RebasedPatchSetSender;
+import com.google.gerrit.server.mail.ReplacePatchSetSender;
 import com.google.gerrit.server.mail.ReplyToChangeSender;
 import com.google.gerrit.server.mail.RevertedSender;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
+import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtorm.client.OrmConcurrencyException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.AtomicUpdate;
+import com.google.gwtorm.server.OrmConcurrencyException;
+import com.google.gwtorm.server.OrmException;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -45,9 +54,11 @@
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.RefUpdate.Result;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.MergeStrategy;
+import org.eclipse.jgit.merge.ThreeWayMerger;
 import org.eclipse.jgit.revwalk.FooterLine;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -55,6 +66,8 @@
 import org.eclipse.jgit.util.NB;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -161,6 +174,252 @@
     opFactory.create(change.getDest()).verifyMergeability(change);
   }
 
+  public static void insertAncestors(ReviewDb db, PatchSet.Id id, RevCommit src)
+      throws OrmException {
+    final int cnt = src.getParentCount();
+    List<PatchSetAncestor> toInsert = new ArrayList<PatchSetAncestor>(cnt);
+    for (int p = 0; p < cnt; p++) {
+      PatchSetAncestor a =
+          new PatchSetAncestor(new PatchSetAncestor.Id(id, p + 1));
+      a.setAncestorRevision(new RevId(src.getParent(p).getId().getName()));
+      toInsert.add(a);
+    }
+    db.patchSetAncestors().insert(toInsert);
+  }
+
+  /**
+   * Rebases a commit
+   *
+   * @param git Repository to find commits in
+   * @param original The commit to rebase
+   * @param base Base to rebase against
+   * @return CommitBuilder the newly rebased commit
+   * @throws IOException Merged failed
+   */
+  public static CommitBuilder rebaseCommit(Repository git, RevCommit original,
+      RevCommit base, PersonIdent committerIdent) throws IOException {
+
+    if (original.getParentCount() == 0) {
+      throw new IOException(
+          "Commits with no parents cannot be rebased (is this the initial commit?).");
+    }
+
+    if (original.getParentCount() > 1) {
+      throw new IOException(
+          "Patch sets with multiple parents cannot be rebased (merge commits)."
+              + " Parents: " + Arrays.toString(original.getParents()));
+    }
+
+    final RevCommit parentCommit = original.getParent(0);
+
+    if (base.equals(parentCommit)) {
+      throw new IOException("Change is already up to date.");
+    }
+
+    final ThreeWayMerger merger = MergeStrategy.RESOLVE.newMerger(git, true);
+    merger.setBase(parentCommit);
+    merger.merge(original, base);
+
+    if (merger.getResultTreeId() == null) {
+      throw new IOException(
+          "The rebase failed since conflicts occured during the merge.");
+    }
+
+    final CommitBuilder rebasedCommitBuilder = new CommitBuilder();
+
+    rebasedCommitBuilder.setTreeId(merger.getResultTreeId());
+    rebasedCommitBuilder.setParentId(base);
+    rebasedCommitBuilder.setAuthor(original.getAuthorIdent());
+    rebasedCommitBuilder.setMessage(original.getFullMessage());
+    rebasedCommitBuilder.setCommitter(committerIdent);
+
+    return rebasedCommitBuilder;
+  }
+
+  public static void rebaseChange(final PatchSet.Id patchSetId,
+      final IdentifiedUser user, final ReviewDb db,
+      RebasedPatchSetSender.Factory rebasedPatchSetSenderFactory,
+      final ChangeHookRunner hooks, GitRepositoryManager gitManager,
+      final PatchSetInfoFactory patchSetInfoFactory,
+      final ReplicationQueue replication, PersonIdent myIdent,
+      final ChangeControl.Factory changeControlFactory,
+      final ApprovalTypes approvalTypes) throws NoSuchChangeException,
+      EmailException, OrmException, MissingObjectException,
+      IncorrectObjectTypeException, IOException,
+      PatchSetInfoNotAvailableException, InvalidChangeOperationException {
+
+    final Change.Id changeId = patchSetId.getParentKey();
+    final ChangeControl changeControl =
+        changeControlFactory.validateFor(changeId);
+
+    if (!changeControl.canRebase()) {
+      throw new InvalidChangeOperationException(
+          "Cannot rebase: New patch sets are not allowed to be added to change: "
+              + changeId.toString());
+    }
+
+    Change change = changeControl.getChange();
+    final Repository git = gitManager.openRepository(change.getProject());
+    try {
+      final RevWalk revWalk = new RevWalk(git);
+      try {
+        final PatchSet originalPatchSet = db.patchSets().get(patchSetId);
+        RevCommit branchTipCommit = null;
+
+        List<PatchSetAncestor> patchSetAncestors =
+            db.patchSetAncestors().ancestorsOf(patchSetId).toList();
+        if (patchSetAncestors.size() > 1) {
+          throw new IOException(
+              "The patch set you are trying to rebase is dependent on several other patch sets: "
+                  + patchSetAncestors.toString());
+        }
+        if (patchSetAncestors.size() == 1) {
+          List<PatchSet> depPatchSetList = db.patchSets()
+                  .byRevision(patchSetAncestors.get(0).getAncestorRevision())
+                  .toList();
+          if (!depPatchSetList.isEmpty()) {
+            PatchSet depPatchSet = depPatchSetList.get(0);
+
+            Change.Id depChangeId = depPatchSet.getId().getParentKey();
+            Change depChange = db.changes().get(depChangeId);
+
+            if (depChange.getStatus() == Status.ABANDONED) {
+              throw new IOException("Cannot rebase against an abandoned change: "
+                  + depChange.getKey().toString());
+            }
+            if (depChange.getStatus().isOpen()) {
+              PatchSet latestDepPatchSet =
+                  db.patchSets().get(depChange.currentPatchSetId());
+              if (!depPatchSet.getId().equals(depChange.currentPatchSetId())) {
+                branchTipCommit =
+                    revWalk.parseCommit(ObjectId
+                        .fromString(latestDepPatchSet.getRevision().get()));
+              } else {
+                throw new IOException(
+                    "Change is already based on the latest patch set of the dependent change.");
+              }
+            }
+          }
+        }
+
+        if (branchTipCommit == null) {
+          // We are dependent on a merged PatchSet or have no PatchSet
+          // dependencies at all.
+          Ref destRef = git.getRef(change.getDest().get());
+          if (destRef == null) {
+            throw new IOException(
+                "The destination branch does not exist: "
+                    + change.getDest().get());
+          }
+          branchTipCommit = revWalk.parseCommit(destRef.getObjectId());
+        }
+
+        final RevCommit originalCommit =
+            revWalk.parseCommit(ObjectId.fromString(originalPatchSet
+                .getRevision().get()));
+
+        CommitBuilder rebasedCommitBuilder =
+            rebaseCommit(git, originalCommit, branchTipCommit, myIdent);
+
+        final ObjectInserter oi = git.newObjectInserter();
+        final ObjectId rebasedCommitId;
+        try {
+          rebasedCommitId = oi.insert(rebasedCommitBuilder);
+          oi.flush();
+        } finally {
+          oi.release();
+        }
+
+        Change updatedChange =
+            db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() {
+              @Override
+              public Change update(Change change) {
+                if (change.getStatus().isOpen()) {
+                  change.nextPatchSetId();
+                  return change;
+                } else {
+                  return null;
+                }
+              }
+            });
+
+        if (updatedChange == null) {
+          throw new InvalidChangeOperationException("Change is closed: "
+              + change.toString());
+        } else {
+          change = updatedChange;
+        }
+
+        final PatchSet rebasedPatchSet = new PatchSet(change.currPatchSetId());
+        rebasedPatchSet.setCreatedOn(change.getCreatedOn());
+        rebasedPatchSet.setUploader(user.getAccountId());
+        rebasedPatchSet.setRevision(new RevId(rebasedCommitId.getName()));
+
+        insertAncestors(db, rebasedPatchSet.getId(),
+            revWalk.parseCommit(rebasedCommitId));
+
+        db.patchSets().insert(Collections.singleton(rebasedPatchSet));
+        final PatchSetInfo info =
+            patchSetInfoFactory.get(db, rebasedPatchSet.getId());
+
+        change =
+            db.changes().atomicUpdate(change.getId(),
+                new AtomicUpdate<Change>() {
+                  @Override
+                  public Change update(Change change) {
+                    change.setCurrentPatchSet(info);
+                    ChangeUtil.updated(change);
+                    return change;
+                  }
+                });
+
+        final RefUpdate ru = git.updateRef(rebasedPatchSet.getRefName());
+        ru.setNewObjectId(rebasedCommitId);
+        ru.disableRefLog();
+        if (ru.update(revWalk) != RefUpdate.Result.NEW) {
+          throw new IOException("Failed to create ref "
+              + rebasedPatchSet.getRefName() + " in " + git.getDirectory()
+              + ": " + ru.getResult());
+        }
+
+        replication.scheduleUpdate(change.getProject(), ru.getName());
+
+        ApprovalsUtil.copyVetosToLatestPatchSet(db, change, approvalTypes);
+
+        final ChangeMessage cmsg =
+            new ChangeMessage(new ChangeMessage.Key(changeId,
+                ChangeUtil.messageUUID(db)), user.getAccountId(), patchSetId);
+        cmsg.setMessage("Patch Set " + patchSetId.get() + ": Rebased");
+        db.changeMessages().insert(Collections.singleton(cmsg));
+
+        final Set<Account.Id> oldReviewers = new HashSet<Account.Id>();
+        final Set<Account.Id> oldCC = new HashSet<Account.Id>();
+
+        for (PatchSetApproval a : db.patchSetApprovals().byChange(change.getId())) {
+          if (a.getValue() != 0) {
+            oldReviewers.add(a.getAccountId());
+          } else {
+            oldCC.add(a.getAccountId());
+          }
+        }
+
+        final ReplacePatchSetSender cm =
+            rebasedPatchSetSenderFactory.create(change);
+        cm.setFrom(user.getAccountId());
+        cm.setPatchSet(rebasedPatchSet);
+        cm.addReviewers(oldReviewers);
+        cm.addExtraCC(oldCC);
+        cm.send();
+
+        hooks.doPatchsetCreatedHook(change, rebasedPatchSet, db);
+      } finally {
+        revWalk.release();
+      }
+    } finally {
+      git.close();
+    }
+  }
+
   public static Change.Id revert(final PatchSet.Id patchSetId,
       final IdentifiedUser user, final String message, final ReviewDb db,
       final RevertedSender.Factory revertedSenderFactory,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
index b9404b0..f057c3a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/CurrentUser.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.account.GroupMembership;
 import com.google.inject.servlet.RequestScoped;
 
 import java.util.Collection;
@@ -60,7 +60,7 @@
    *
    * @return active groups for this user.
    */
-  public abstract Set<AccountGroup.UUID> getEffectiveGroups();
+  public abstract GroupMembership getEffectiveGroups();
 
   /** Set of changes starred by this user. */
   public abstract Set<Change.Id> getStarredChanges();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
index 6828e18..6e519c4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/IdentifiedUser.java
@@ -14,22 +14,23 @@
 
 package com.google.gerrit.server;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountDiffPreference;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.StarredChange;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.StarredChange;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.account.CapabilityControl;
-import com.google.gerrit.server.account.GroupIncludeCache;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.MaterializedGroupMembership;
 import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.OutOfScopeException;
 import com.google.inject.Provider;
@@ -51,10 +52,8 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Queue;
 import java.util.Set;
 import java.util.TimeZone;
 
@@ -71,7 +70,7 @@
     private final Provider<String> canonicalUrl;
     private final Realm realm;
     private final AccountCache accountCache;
-    private final GroupIncludeCache groupIncludeCache;
+    private final MaterializedGroupMembership.Factory groupMembershipFactory;
 
     @Inject
     GenericFactory(
@@ -80,14 +79,14 @@
         final @AnonymousCowardName String anonymousCowardName,
         final @CanonicalWebUrl Provider<String> canonicalUrl,
         final Realm realm, final AccountCache accountCache,
-        final GroupIncludeCache groupIncludeCache) {
+        final MaterializedGroupMembership.Factory groupMembershipFactory) {
       this.capabilityControlFactory = capabilityControlFactory;
       this.authConfig = authConfig;
       this.anonymousCowardName = anonymousCowardName;
       this.canonicalUrl = canonicalUrl;
       this.realm = realm;
       this.accountCache = accountCache;
-      this.groupIncludeCache = groupIncludeCache;
+      this.groupMembershipFactory = groupMembershipFactory;
     }
 
     public IdentifiedUser create(final Account.Id id) {
@@ -97,14 +96,14 @@
     public IdentifiedUser create(Provider<ReviewDb> db, Account.Id id) {
       return new IdentifiedUser(capabilityControlFactory, AccessPath.UNKNOWN,
           authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
-          groupIncludeCache, null, db, id);
+          groupMembershipFactory, null, db, id);
     }
 
     public IdentifiedUser create(AccessPath accessPath,
         Provider<SocketAddress> remotePeerProvider, Account.Id id) {
       return new IdentifiedUser(capabilityControlFactory, accessPath,
           authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
-          groupIncludeCache, remotePeerProvider, null, id);
+          groupMembershipFactory, remotePeerProvider, null, id);
     }
   }
 
@@ -122,7 +121,7 @@
     private final Provider<String> canonicalUrl;
     private final Realm realm;
     private final AccountCache accountCache;
-    private final GroupIncludeCache groupIncludeCache;
+    private final MaterializedGroupMembership.Factory groupMembershipFactory;
 
     private final Provider<SocketAddress> remotePeerProvider;
     private final Provider<ReviewDb> dbProvider;
@@ -134,7 +133,7 @@
         final @AnonymousCowardName String anonymousCowardName,
         final @CanonicalWebUrl Provider<String> canonicalUrl,
         final Realm realm, final AccountCache accountCache,
-        final GroupIncludeCache groupIncludeCache,
+        final MaterializedGroupMembership.Factory groupMembershipFactory,
 
         final @RemotePeer Provider<SocketAddress> remotePeerProvider,
         final Provider<ReviewDb> dbProvider) {
@@ -144,7 +143,7 @@
       this.canonicalUrl = canonicalUrl;
       this.realm = realm;
       this.accountCache = accountCache;
-      this.groupIncludeCache = groupIncludeCache;
+      this.groupMembershipFactory = groupMembershipFactory;
 
       this.remotePeerProvider = remotePeerProvider;
       this.dbProvider = dbProvider;
@@ -154,7 +153,7 @@
         final Account.Id id) {
       return new IdentifiedUser(capabilityControlFactory, accessPath,
           authConfig, anonymousCowardName, canonicalUrl, realm, accountCache,
-          groupIncludeCache, remotePeerProvider, dbProvider, id);
+          groupMembershipFactory, remotePeerProvider, dbProvider, id);
     }
   }
 
@@ -186,7 +185,7 @@
   private final Provider<String> canonicalUrl;
   private final Realm realm;
   private final AccountCache accountCache;
-  private final GroupIncludeCache groupIncludeCache;
+  private final MaterializedGroupMembership.Factory groupMembershipFactory;
   private final AuthConfig authConfig;
   private final String anonymousCowardName;
 
@@ -200,7 +199,7 @@
 
   private AccountState state;
   private Set<String> emailAddresses;
-  private Set<AccountGroup.UUID> effectiveGroups;
+  private GroupMembership effectiveGroups;
   private Set<Change.Id> starredChanges;
   private Collection<AccountProjectWatch> notificationFilters;
 
@@ -211,14 +210,14 @@
       final String anonymousCowardName,
       final Provider<String> canonicalUrl,
       final Realm realm, final AccountCache accountCache,
-      final GroupIncludeCache groupIncludeCache,
+      final MaterializedGroupMembership.Factory groupMembershipFactory,
       @Nullable final Provider<SocketAddress> remotePeerProvider,
       @Nullable final Provider<ReviewDb> dbProvider, final Account.Id id) {
     super(capabilityControlFactory, accessPath);
     this.canonicalUrl = canonicalUrl;
     this.realm = realm;
     this.accountCache = accountCache;
-    this.groupIncludeCache = groupIncludeCache;
+    this.groupMembershipFactory = groupMembershipFactory;
     this.authConfig = authConfig;
     this.anonymousCowardName = anonymousCowardName;
     this.remotePeerProvider = remotePeerProvider;
@@ -270,39 +269,18 @@
   }
 
   @Override
-  public Set<AccountGroup.UUID> getEffectiveGroups() {
+  public GroupMembership getEffectiveGroups() {
     if (effectiveGroups == null) {
-      Set<AccountGroup.UUID> seedGroups;
-
       if (authConfig.isIdentityTrustable(state().getExternalIds())) {
-        seedGroups = realm.groups(state());
+        effectiveGroups = realm.groups(state());
       } else {
-        seedGroups = registeredGroups;
+        effectiveGroups = groupMembershipFactory.create(registeredGroups);
       }
-
-      effectiveGroups = getIncludedGroups(seedGroups);
     }
 
     return effectiveGroups;
   }
 
-  private Set<AccountGroup.UUID> getIncludedGroups(Set<AccountGroup.UUID> seedGroups) {
-    Set<AccountGroup.UUID> includes = new HashSet<AccountGroup.UUID> (seedGroups);
-    Queue<AccountGroup.UUID> groupQueue = new LinkedList<AccountGroup.UUID> (seedGroups);
-
-    while (groupQueue.size() > 0) {
-      AccountGroup.UUID id = groupQueue.remove();
-
-      for (final AccountGroup.UUID groupId : groupIncludeCache.getByInclude(id)) {
-        if (includes.add(groupId)) {
-          groupQueue.add(groupId);
-        }
-      }
-    }
-
-    return Collections.unmodifiableSet(includes);
-  }
-
   @Override
   public Set<Change.Id> getStarredChanges() {
     if (starredChanges == null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
index a58f7b0..352f540 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PeerDaemonUser.java
@@ -14,10 +14,11 @@
 
 package com.google.gerrit.server;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.account.GroupMembership;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -45,8 +46,8 @@
   }
 
   @Override
-  public Set<AccountGroup.UUID> getEffectiveGroups() {
-    return Collections.emptySet();
+  public GroupMembership getEffectiveGroups() {
+    return GroupMembership.EMPTY;
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java
index ae7f5ac..fc6ac9c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ReplicationUser.java
@@ -14,51 +14,39 @@
 
 package com.google.gerrit.server;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.ListGroupMembership;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Set;
 
 public class ReplicationUser extends CurrentUser {
   /** Magic set of groups enabling read of any project and reference. */
-  public static final Set<AccountGroup.UUID> EVERYTHING_VISIBLE =
-      Collections.unmodifiableSet(new HashSet<AccountGroup.UUID>(0));
+  public static final GroupMembership EVERYTHING_VISIBLE =
+      new ListGroupMembership(Collections.<AccountGroup.UUID>emptySet());
 
   public interface Factory {
-    ReplicationUser create(@Assisted Set<AccountGroup.UUID> authGroups);
+    ReplicationUser create(@Assisted GroupMembership authGroups);
   }
 
-  private final Set<AccountGroup.UUID> effectiveGroups;
+  private final GroupMembership effectiveGroups;
 
   @Inject
   protected ReplicationUser(CapabilityControl.Factory capabilityControlFactory,
-      @Assisted Set<AccountGroup.UUID> authGroups) {
+      @Assisted GroupMembership authGroups) {
     super(capabilityControlFactory, AccessPath.REPLICATION);
-
-    if (authGroups == EVERYTHING_VISIBLE) {
-      effectiveGroups = EVERYTHING_VISIBLE;
-
-    } else if (authGroups.isEmpty()) {
-      effectiveGroups = Collections.emptySet();
-
-    } else {
-      effectiveGroups = copy(authGroups);
-    }
-  }
-
-  private static Set<AccountGroup.UUID> copy(Set<AccountGroup.UUID> groups) {
-    return Collections.unmodifiableSet(new HashSet<AccountGroup.UUID>(groups));
+    effectiveGroups = authGroups;
   }
 
   @Override
-  public Set<AccountGroup.UUID> getEffectiveGroups() {
+  public GroupMembership getEffectiveGroups() {
     return effectiveGroups;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCache.java
index 1eb1a4f..406ab52 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 import java.util.Set;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java
index 64046fa..72fb2e8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountByEmailCacheImpl.java
@@ -14,13 +14,13 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java
index 1b3626b..056babd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 /** Caches important (but small) account state to avoid database hits. */
 public interface AccountCache {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
index aea13c7..819ec31 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -14,16 +14,16 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountControl.java
new file mode 100644
index 0000000..b297ed8
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountControl.java
@@ -0,0 +1,121 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import java.util.Set;
+
+/** Access control management for one account's access to other accounts. */
+public class AccountControl {
+  public static class Factory {
+    private final GroupControl.Factory groupControlFactory;
+    private final Provider<CurrentUser> user;
+    private final IdentifiedUser.GenericFactory userFactory;
+    private final AccountVisibility accountVisibility;
+
+    @Inject
+    Factory(final GroupControl.Factory groupControlFactory,
+        final Provider<CurrentUser> user,
+        final IdentifiedUser.GenericFactory userFactory,
+        final AccountVisibility accountVisibility) {
+      this.groupControlFactory = groupControlFactory;
+      this.user = user;
+      this.userFactory = userFactory;
+      this.accountVisibility = accountVisibility;
+    }
+
+    public AccountControl get() {
+      return new AccountControl(groupControlFactory, user.get(), userFactory,
+          accountVisibility);
+    }
+  }
+
+  private final GroupControl.Factory groupControlFactory;
+  private final CurrentUser currentUser;
+  private final IdentifiedUser.GenericFactory userFactory;
+  private final AccountVisibility accountVisibility;
+
+  AccountControl(final GroupControl.Factory groupControlFactory,
+        final CurrentUser currentUser,
+        final IdentifiedUser.GenericFactory userFactory,
+        final AccountVisibility accountVisibility) {
+    this.groupControlFactory = groupControlFactory;
+    this.currentUser = currentUser;
+    this.userFactory = userFactory;
+    this.accountVisibility = accountVisibility;
+  }
+
+  /**
+   * Returns true if the otherUser is allowed to see the current user, based
+   * on the account visibility policy. Depending on the group membership
+   * realms supported, this may not be able to determine SAME_GROUP or
+   * VISIBLE_GROUP correctly (defaulting to not being visible). This is because
+   * {@link GroupMembership#getKnownGroups()} may only return a subset of the
+   * effective groups.
+   */
+  public boolean canSee(final Account otherUser) {
+    // Special case: I can always see myself.
+    if (currentUser instanceof IdentifiedUser
+        && ((IdentifiedUser) currentUser).getAccountId()
+            .equals(otherUser.getId())) {
+      return true;
+    }
+
+    switch (accountVisibility) {
+      case ALL:
+        return true;
+      case SAME_GROUP: {
+        Set<AccountGroup.UUID> usersGroups = groupsOf(otherUser);
+        usersGroups.remove(AccountGroup.ANONYMOUS_USERS);
+        usersGroups.remove(AccountGroup.REGISTERED_USERS);
+        if (currentUser.getEffectiveGroups().containsAnyOf(usersGroups)) {
+          return true;
+        }
+        break;
+      }
+      case VISIBLE_GROUP: {
+        Set<AccountGroup.UUID> usersGroups = groupsOf(otherUser);
+        usersGroups.remove(AccountGroup.ANONYMOUS_USERS);
+        usersGroups.remove(AccountGroup.REGISTERED_USERS);
+        for (AccountGroup.UUID usersGroup : usersGroups) {
+          try {
+            if (groupControlFactory.controlFor(usersGroup).isVisible()) {
+              return true;
+            }
+          } catch (NoSuchGroupException e) {
+            continue;
+          }
+        }
+        break;
+      }
+      case NONE:
+        break;
+      default:
+        throw new IllegalStateException("Bad AccountVisibility " + accountVisibility);
+    }
+    return false;
+  }
+
+  private Set<AccountGroup.UUID> groupsOf(Account account) {
+    return userFactory.create(account.getId()).getEffectiveGroups().getKnownGroups();
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java
index bb6e278..e3cf023 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountInfoCacheFactory.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.common.data.AccountInfo;
 import com.google.gerrit.common.data.AccountInfoCache;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.inject.Inject;
 
 import java.util.ArrayList;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
index 3f4d0d1..6c216a8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountManager.java
@@ -20,17 +20,17 @@
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.errors.InvalidUserNameException;
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.AccountGroupMemberAudit;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
index 3dce94e..3a2ac56 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
index 1b036d8..488370e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.account;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_USERNAME;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 import java.util.Collection;
 import java.util.HashSet;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibility.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibility.java
new file mode 100644
index 0000000..7452da3
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibility.java
@@ -0,0 +1,33 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+/** Visibility level of other accounts to a given user. */
+public enum AccountVisibility {
+  /** All accounts are visible to all users. */
+  ALL,
+
+  /** Accounts sharing a group with the given user. */
+  SAME_GROUP,
+
+  /** Accounts in a group that is visible to the given user. */
+  VISIBLE_GROUP,
+
+  /**
+   * Other accounts are not visible to the given user unless they are explicitly
+   * collaborating on a change.
+   */
+  NONE;
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibilityProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibilityProvider.java
new file mode 100644
index 0000000..d7f7a19
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountVisibilityProvider.java
@@ -0,0 +1,59 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.lib.Config;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AccountVisibilityProvider implements Provider<AccountVisibility> {
+  private static final Logger log =
+      LoggerFactory.getLogger(AccountVisibilityProvider.class);
+
+  private final AccountVisibility accountVisibility;
+
+  @Inject
+  AccountVisibilityProvider(@GerritServerConfig Config cfg) {
+    AccountVisibility av;
+    if (cfg.getString("accounts", null, "visibility") != null) {
+      av = cfg.getEnum("accounts", null, "visibility", AccountVisibility.ALL);
+    } else if (cfg.getString("suggest", null, "accounts") != null) {
+      try {
+        av = cfg.getEnum("suggest", null, "accounts", AccountVisibility.ALL);
+        log.warn(String.format(
+            "Using legacy value %s for suggest.accounts;"
+            + " use accounts.visibility=%s instead",
+            av, av));
+      } catch (IllegalArgumentException err) {
+        // If suggest.accounts is a valid boolean, it's a new-style config, and
+        // we should use the default here. Invalid values are caught in
+        // SuggestServiceImpl so we don't worry about them here.
+        av = AccountVisibility.ALL;
+      }
+    } else {
+      av = AccountVisibility.ALL;
+    }
+    accountVisibility = av;
+  }
+
+  @Override
+  public AccountVisibility get() {
+    return accountVisibility;
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthRequest.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthRequest.java
index 034b176..35ab3af 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthRequest.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthRequest.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.account;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_GERRIT;
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_MAILTO;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_MAILTO;
 
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 
 /**
  * Information for {@link AccountManager#authenticate(AuthRequest)}.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthResult.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthResult.java
index df65796..b94e41a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthResult.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AuthResult.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
 
 /** Result from {@link AccountManager#authenticate(AuthRequest)}. */
 public class AuthResult {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java
index 3d03ed8..796b44e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityCollection.java
@@ -20,7 +20,7 @@
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -34,6 +34,7 @@
   private final Map<String, List<PermissionRule>> permissions;
 
   public final List<PermissionRule> administrateServer;
+  public final List<PermissionRule> emailReviewers;
   public final List<PermissionRule> priority;
   public final List<PermissionRule> queryLimit;
 
@@ -46,14 +47,17 @@
         new HashMap<String, List<PermissionRule>>();
     for (Permission permission : section.getPermissions()) {
       for (PermissionRule rule : permission.getRules()) {
-        if (rule.getAction() != PermissionRule.Action.DENY) {
-          List<PermissionRule> r = tmp.get(permission.getName());
-          if (r == null) {
-            r = new ArrayList<PermissionRule>(2);
-            tmp.put(permission.getName(), r);
-          }
-          r.add(rule);
+        if (!permission.getName().equals(GlobalCapability.EMAIL_REVIEWERS)
+            && rule.getAction() == PermissionRule.Action.DENY) {
+          continue;
         }
+
+        List<PermissionRule> r = tmp.get(permission.getName());
+        if (r == null) {
+          r = new ArrayList<PermissionRule>(2);
+          tmp.put(permission.getName(), r);
+        }
+        r.add(rule);
       }
     }
     configureDefaults(tmp, section);
@@ -72,6 +76,7 @@
     permissions = Collections.unmodifiableMap(res);
 
     administrateServer = getPermission(GlobalCapability.ADMINISTRATE_SERVER);
+    emailReviewers = getPermission(GlobalCapability.EMAIL_REVIEWERS);
     priority = getPermission(GlobalCapability.PRIORITY);
     queryLimit = getPermission(GlobalCapability.QUERY_LIMIT);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
index 57d01fe..eb42921 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/CapabilityControl.java
@@ -14,11 +14,16 @@
 
 package com.google.gerrit.server.account;
 
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.common.data.PermissionRule.Action;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.PeerDaemonUser;
 import com.google.gerrit.server.git.QueueProvider;
@@ -31,7 +36,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /** Access control management for server-wide capabilities. */
 public class CapabilityControl {
@@ -44,6 +48,7 @@
   private final Map<String, List<PermissionRule>> effective;
 
   private Boolean canAdministrateServer;
+  private Boolean canEmailReviewers;
 
   @Inject
   CapabilityControl(ProjectCache projectCache, @Assisted CurrentUser currentUser) {
@@ -61,7 +66,7 @@
   public boolean canAdministrateServer() {
     if (canAdministrateServer == null) {
       canAdministrateServer = user instanceof PeerDaemonUser
-          || matchAny(capabilities.administrateServer);
+          || matchAny(capabilities.administrateServer, ALLOWED_RULE);
     }
     return canAdministrateServer;
   }
@@ -84,6 +89,17 @@
       || canAdministrateServer();
   }
 
+  /** @return true if the user can email reviewers. */
+  public boolean canEmailReviewers() {
+    if (canEmailReviewers == null) {
+      canEmailReviewers =
+          matchAny(capabilities.emailReviewers, ALLOWED_RULE)
+          || !matchAny(capabilities.emailReviewers, Predicates.not(ALLOWED_RULE));
+
+    }
+    return canEmailReviewers;
+  }
+
   /** @return true if the user can kill any running task. */
   public boolean canKillTask() {
     return canPerform(GlobalCapability.KILL_TASK)
@@ -129,7 +145,7 @@
     // the 'CI Servers' actually use the BATCH queue while everyone else gets
     // to use the INTERACTIVE queue without additional grants.
     //
-    Set<AccountGroup.UUID> groups = user.getEffectiveGroups();
+    GroupMembership groups = user.getEffectiveGroups();
     boolean batch = false;
     for (PermissionRule r : capabilities.priority) {
       if (match(groups, r)) {
@@ -198,7 +214,7 @@
       return rules;
     }
 
-    Set<AccountGroup.UUID> groups = user.getEffectiveGroups();
+    GroupMembership groups = user.getEffectiveGroups();
     if (rules.size() == 1) {
       if (!match(groups, rules.get(0))) {
         rules = Collections.emptyList();
@@ -221,17 +237,26 @@
     return mine;
   }
 
-  private boolean matchAny(List<PermissionRule> rules) {
-    Set<AccountGroup.UUID> groups = user.getEffectiveGroups();
-    for (PermissionRule rule : rules) {
-      if (match(groups, rule)) {
-        return true;
-      }
+  private static final Predicate<PermissionRule> ALLOWED_RULE = new Predicate<PermissionRule>() {
+    @Override
+    public boolean apply(PermissionRule rule) {
+      return rule.getAction() == Action.ALLOW;
     }
-    return false;
+  };
+
+  private boolean matchAny(Iterable<PermissionRule> rules, Predicate<PermissionRule> predicate) {
+    Iterable<AccountGroup.UUID> ids = Iterables.transform(
+        Iterables.filter(rules, predicate),
+        new Function<PermissionRule, AccountGroup.UUID>() {
+          @Override
+          public AccountGroup.UUID apply(PermissionRule rule) {
+            return rule.getGroup().getUUID();
+          }
+        });
+    return user.getEffectiveGroups().containsAnyOf(ids);
   }
 
-  private static boolean match(Set<AccountGroup.UUID> groups,
+  private static boolean match(GroupMembership groups,
       PermissionRule rule) {
     return groups.contains(rule.getGroup().getUUID());
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java
index e875a19..d6f45f5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/ChangeUserName.java
@@ -14,18 +14,18 @@
 
 package com.google.gerrit.server.account;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_USERNAME;
 
 import com.google.gerrit.common.errors.InvalidUserNameException;
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.ssh.SshKeyCache;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmDuplicateKeyException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/ClearPassword.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/ClearPassword.java
index 1fc87fe..255c248 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/ClearPassword.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/ClearPassword.java
@@ -15,10 +15,10 @@
 package com.google.gerrit.server.account;
 
 import com.google.gerrit.common.errors.NoSuchEntityException;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
index c03aee9..56a95ba 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/DefaultRealm.java
@@ -14,23 +14,27 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.inject.Inject;
 
 import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 
 public class DefaultRealm implements Realm {
   private final EmailExpander emailExpander;
   private final AccountByEmailCache byEmail;
+  private final MaterializedGroupMembership.Factory groupMembershipFactory;
 
   @Inject
   DefaultRealm(final EmailExpander emailExpander,
-      final AccountByEmailCache byEmail) {
+      final AccountByEmailCache byEmail,
+      final MaterializedGroupMembership.Factory groupMembershipFactory) {
     this.emailExpander = emailExpander;
     this.byEmail = byEmail;
+    this.groupMembershipFactory = groupMembershipFactory;
   }
 
   @Override
@@ -57,8 +61,8 @@
   }
 
   @Override
-  public Set<AccountGroup.UUID> groups(final AccountState who) {
-    return who.getInternalGroups();
+  public GroupMembership groups(final AccountState who) {
+    return groupMembershipFactory.create(who.getInternalGroups());
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GeneratePassword.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GeneratePassword.java
index 1b30503..bbab126 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GeneratePassword.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GeneratePassword.java
@@ -15,10 +15,10 @@
 package com.google.gerrit.server.account;
 
 import com.google.gerrit.common.errors.NoSuchEntityException;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java
index 788e08e..b092ac4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 import java.util.Collection;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
index 0e11d6b..d29a5e5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupCacheImpl.java
@@ -14,13 +14,13 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupComparator.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupComparator.java
index 9348a0c..13800b5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupComparator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupComparator.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 import java.util.Comparator;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupControl.java
index d26a37f..f7451a8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupControl.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.account;
 
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java
index d4c85760..7f88134 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupDetailFactory.java
@@ -16,12 +16,12 @@
 
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java
index e5f73a3..432a8b8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 import java.util.Collection;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
index 830d01c..791d0f5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
@@ -14,13 +14,13 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupInfoCacheFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupInfoCacheFactory.java
index a3e592f..19d953d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupInfoCacheFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupInfoCacheFactory.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.common.data.GroupInfo;
 import com.google.gerrit.common.data.GroupInfoCache;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.inject.Inject;
 
 import java.util.ArrayList;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java
index bf5329a..84282b5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembers.java
@@ -16,15 +16,15 @@
 
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
new file mode 100644
index 0000000..9bb571e
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+import com.google.gerrit.reviewdb.client.AccountGroup;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Implementations of GroupMembership provide methods to test
+ * the presence of a user in a particular group.
+ */
+public interface GroupMembership {
+
+  public static final GroupMembership EMPTY =
+      new ListGroupMembership(Collections.<AccountGroup.UUID>emptySet());
+
+  /**
+   * Returns {@code true} when the user this object was created for is a member
+   * of the specified group.
+   */
+  boolean contains(AccountGroup.UUID groupId);
+
+  /**
+   * Returns {@code true} when the user this object was created for is a member
+   * of any of the specified group.
+   */
+  boolean containsAnyOf(Iterable<AccountGroup.UUID> groupIds);
+
+  /**
+   * Returns the set of groups that can be determined by the implementation.
+   * This may not return all groups the {@link #contains(AccountGroup.UUID)}
+   * would return {@code true} for, but will at least contain all top level
+   * groups. This restriction stems from the API of some group systems, which
+   * make it expensive to enumate the members of a group.
+   */
+  Set<AccountGroup.UUID> getKnownGroups();
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupUUID.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupUUID.java
index 9eec1df..b871c68 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupUUID.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupUUID.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
new file mode 100644
index 0000000..237d381
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
@@ -0,0 +1,52 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+
+import java.util.Set;
+
+/**
+ * GroupMembership over an explicit list.
+ */
+public class ListGroupMembership implements GroupMembership {
+
+  private final Set<AccountGroup.UUID> groups;
+
+  public ListGroupMembership(Iterable<AccountGroup.UUID> groupIds) {
+    this.groups = ImmutableSet.copyOf(groupIds);
+  }
+
+  @Override
+  public boolean contains(AccountGroup.UUID groupId) {
+    return groups.contains(groupId);
+  }
+
+  @Override
+  public boolean containsAnyOf(Iterable<AccountGroup.UUID> groupIds) {
+    for (AccountGroup.UUID groupId : groupIds) {
+      if (contains(groupId)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Set<AccountGroup.UUID> getKnownGroups() {
+    return ImmutableSet.copyOf(groups);
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/MaterializedGroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/MaterializedGroupMembership.java
new file mode 100644
index 0000000..81ff656
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/MaterializedGroupMembership.java
@@ -0,0 +1,93 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.account;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import java.util.Collections;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * Creates a GroupMembership object from materialized collection of groups.
+ */
+public class MaterializedGroupMembership implements GroupMembership {
+  public interface Factory {
+    MaterializedGroupMembership create(Iterable<AccountGroup.UUID> groupIds);
+  }
+
+  private final GroupIncludeCache groupIncludeCache;
+  private final Set<AccountGroup.UUID> includes;
+  private final Queue<AccountGroup.UUID> groupQueue;
+
+  @Inject
+  MaterializedGroupMembership(
+      GroupIncludeCache groupIncludeCache,
+      @Assisted Iterable<AccountGroup.UUID> seedGroups) {
+    this.groupIncludeCache = groupIncludeCache;
+    this.includes = Sets.newHashSet(seedGroups);
+    this.groupQueue = Lists.newLinkedList(seedGroups);
+  }
+
+  @Override
+  public boolean contains(AccountGroup.UUID id) {
+    if (id == null) {
+      return false;
+    }
+    if (includes.contains(id)) {
+      return true;
+    }
+    return findIncludedGroup(Collections.singleton(id));
+  }
+
+  @Override
+  public boolean containsAnyOf(Iterable<AccountGroup.UUID> ids) {
+    Set<AccountGroup.UUID> query = Sets.newHashSet();
+    for (AccountGroup.UUID groupId : ids) {
+      if (includes.contains(groupId)) {
+        return true;
+      }
+      query.add(groupId);
+    }
+
+    return findIncludedGroup(query);
+  }
+
+  private boolean findIncludedGroup(Set<AccountGroup.UUID> query) {
+    boolean found = false;
+    while (!found && !groupQueue.isEmpty()) {
+      AccountGroup.UUID id = groupQueue.remove();
+
+      for (final AccountGroup.UUID groupId : groupIncludeCache.getByInclude(id)) {
+        if (includes.add(groupId)) {
+          groupQueue.add(groupId);
+          found |= query.contains(groupId);
+        }
+      }
+    }
+
+    return found;
+  }
+
+  @Override
+  public Set<AccountGroup.UUID> getKnownGroups() {
+    findIncludedGroup(Collections.<AccountGroup.UUID>emptySet()); // find all
+    return Sets.newHashSet(includes);
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
index 0b3555c..5f94df2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformCreateGroup.java
@@ -16,18 +16,18 @@
 
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.PermissionDeniedException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupInclude;
-import com.google.gerrit.reviewdb.AccountGroupIncludeAudit;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.AccountGroupMemberAudit;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupInclude;
+import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gwtorm.client.OrmDuplicateKeyException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.lib.PersonIdent;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
index a57b708..6db232a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
@@ -17,13 +17,13 @@
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.RenameGroupOp;
-import com.google.gwtorm.client.OrmDuplicateKeyException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
index 58527ac..fc7c0be 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/Realm.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.account;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 
 import java.util.Set;
 
@@ -31,7 +31,7 @@
 
   public void onCreateAccount(AuthRequest who, Account account);
 
-  public Set<AccountGroup.UUID> groups(AccountState who);
+  public GroupMembership groups(AccountState who);
 
   /**
    * Locate an account whose local username is the given account name.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/VisibleGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/VisibleGroups.java
index 44d360e..3112ed4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/VisibleGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/VisibleGroups.java
@@ -18,10 +18,10 @@
 import com.google.gerrit.common.data.GroupList;
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -87,11 +87,18 @@
     return createGroupList(filterGroups(groups));
   }
 
+  /**
+   * Returns visible list of known groups for the user. Depending on the group
+   * membership realms supported, this may only return a subset of the effective
+   * groups.
+   * @See GroupMembership#getKnownGroups()
+   */
   public GroupList get(final IdentifiedUser user) throws OrmException,
       NoSuchGroupException {
     if (identifiedUser.get().getAccountId().equals(user.getAccountId())
         || identifiedUser.get().getCapabilities().canAdministrateServer()) {
-      final Set<AccountGroup.UUID> effective = user.getEffectiveGroups();
+      final Set<AccountGroup.UUID> effective =
+          user.getEffectiveGroups().getKnownGroups();
       final Set<AccountGroup> groups =
           new TreeSet<AccountGroup>(new GroupComparator());
       for (final AccountGroup.UUID groupId : effective) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
index 4dd4742..e81bfc2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/Helper.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.server.auth.ldap;
 
 import com.google.gerrit.common.data.ParameterizedString;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.config.ConfigUtil;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java
index d41fe82..6eb2f54 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapModule.java
@@ -16,8 +16,8 @@
 
 import static java.util.concurrent.TimeUnit.HOURS;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
index 5b19f81..e085d1e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/auth/ldap/LdapRealm.java
@@ -14,18 +14,21 @@
 
 package com.google.gerrit.server.auth.ldap;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_GERRIT;
 
+import com.google.common.collect.Iterables;
 import com.google.gerrit.common.data.ParameterizedString;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AuthType;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AuthType;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.account.EmailExpander;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.MaterializedGroupMembership;
 import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.auth.AuthenticationUnavailableException;
 import com.google.gerrit.server.auth.ldap.Helper.LdapSchema;
@@ -34,8 +37,8 @@
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.google.inject.name.Named;
@@ -72,6 +75,7 @@
   private final Config config;
 
   private final Cache<String, Set<AccountGroup.UUID>> membershipCache;
+  private final MaterializedGroupMembership.Factory groupMembershipFactory;
 
   @Inject
   LdapRealm(
@@ -80,13 +84,15 @@
       final EmailExpander emailExpander,
       @Named(LdapModule.GROUP_CACHE) final Cache<String, Set<AccountGroup.UUID>> membershipCache,
       @Named(LdapModule.USERNAME_CACHE) final Cache<String, Account.Id> usernameCache,
-      @GerritServerConfig final Config config) {
+      @GerritServerConfig final Config config,
+      final MaterializedGroupMembership.Factory groupMembershipFactory) {
     this.helper = helper;
     this.authConfig = authConfig;
     this.emailExpander = emailExpander;
     this.usernameCache = usernameCache;
     this.membershipCache = membershipCache;
     this.config = config;
+    this.groupMembershipFactory = groupMembershipFactory;
 
     this.readOnlyAccountFields = new HashSet<Account.FieldName>();
 
@@ -254,14 +260,12 @@
   }
 
   @Override
-  public Set<AccountGroup.UUID> groups(final AccountState who) {
-    final HashSet<AccountGroup.UUID> r = new HashSet<AccountGroup.UUID>();
-    r.addAll(membershipCache.get(findId(who.getExternalIds())));
-    r.addAll(who.getInternalGroups());
-    return r;
+  public GroupMembership groups(final AccountState who) {
+    return groupMembershipFactory.create(Iterables.concat(
+        membershipCache.get(findId(who.getExternalIds())),
+        who.getInternalGroups()));
   }
 
-
   private static String findId(final Collection<AccountExternalId> ids) {
     for (final AccountExternalId i : ids) {
       if (i.isScheme(AccountExternalId.SCHEME_GERRIT)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/AbandonChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/AbandonChange.java
index cc111e6..1fac8c5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/AbandonChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/AbandonChange.java
@@ -17,19 +17,19 @@
 
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.common.data.ReviewResult;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.mail.AbandonedSender;
 import com.google.gerrit.server.mail.EmailException;
+import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtorm.client.AtomicUpdate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.AtomicUpdate;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/DeleteDraftPatchSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/DeleteDraftPatchSet.java
index 761b765..268e118 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/DeleteDraftPatchSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/DeleteDraftPatchSet.java
@@ -16,17 +16,17 @@
 package com.google.gerrit.server.changedetail;
 
 import com.google.gerrit.common.data.ReviewResult;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ReplicationQueue;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
-import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/PublishDraft.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/PublishDraft.java
index c24c73c..028feac 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/PublishDraft.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/PublishDraft.java
@@ -16,14 +16,14 @@
 package com.google.gerrit.server.changedetail;
 
 import com.google.gerrit.common.data.ReviewResult;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
-import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtorm.client.AtomicUpdate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gwtorm.server.AtomicUpdate;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java
index 5df973b..7232755 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RestoreChange.java
@@ -17,19 +17,19 @@
 
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.common.data.ReviewResult;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.mail.RestoredSender;
 import com.google.gerrit.server.mail.EmailException;
+import com.google.gerrit.server.mail.RestoredSender;
+import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtorm.client.AtomicUpdate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.AtomicUpdate;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java
index 813b92a..abd3582 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java
@@ -14,30 +14,30 @@
 
 package com.google.gerrit.server.changedetail;
 
-import static com.google.gerrit.reviewdb.ApprovalCategory.SUBMIT;
+import static com.google.gerrit.reviewdb.client.ApprovalCategory.SUBMIT;
 
 import com.google.gerrit.common.data.ReviewResult;
 import com.google.gerrit.common.data.SubmitRecord;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.MergeOp;
 import com.google.gerrit.server.git.MergeQueue;
+import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtorm.client.AtomicUpdate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.AtomicUpdate;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
-import java.util.concurrent.Callable;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Callable;
 
 public class Submit implements Callable<ReviewResult> {
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AllProjectsName.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AllProjectsName.java
index bb5d9d9..198d5c5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AllProjectsName.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AllProjectsName.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.config;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 /** Special name of the project that all projects derive from. */
 @SuppressWarnings("serial")
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ApprovalTypesProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ApprovalTypesProvider.java
index 0afaa05..ed9416d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ApprovalTypesProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ApprovalTypesProvider.java
@@ -16,11 +16,11 @@
 
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
index fc189dd..a0f0d36 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfig.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.config;
 
 import com.google.gerrit.common.auth.openid.OpenIdProviderPattern;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gwtjsonrpc.server.SignedToken;
 import com.google.gwtjsonrpc.server.XsrfException;
 import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java
index 1c70c78..8d66d33 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.server.config;
 
-import static com.google.inject.Scopes.SINGLETON;
-
 import com.google.inject.AbstractModule;
 import com.google.inject.Provider;
 
@@ -31,7 +29,6 @@
     // running in an HTTP environment.
     //
     final Class<? extends Provider<String>> provider = provider();
-    bind(provider).in(SINGLETON);
     bind(String.class).annotatedWith(CanonicalWebUrl.class)
         .toProvider(provider);
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
index 3c102ba..e76249a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java
@@ -16,11 +16,15 @@
 
 import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.OrmRuntimeException;
+import com.google.gwtorm.server.SchemaFactory;
 
 import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
@@ -28,7 +32,9 @@
 import java.lang.reflect.InvocationTargetException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -317,25 +323,41 @@
     try {
       final ReviewDb db = dbfactory.open();
       try {
-        for (String name : groupNames) {
-          AccountGroupName group =
-              db.accountGroupNames().get(new AccountGroup.NameKey(name));
-          if (group == null) {
-            log.warn(MessageFormat.format(groupNotFoundWarning, name));
+        List<AccountGroupName> groups = db.accountGroupNames().get(
+            Iterables.transform(Arrays.asList(groupNames),
+                new Function<String, AccountGroup.NameKey>() {
+                  @Override
+                  public AccountGroup.NameKey apply(String name) {
+                    return new AccountGroup.NameKey(name);
+                  }
+            })).toList();
+
+        Iterator<AccountGroup> ags = db.accountGroups().get(
+            Iterables.transform(Iterables.filter(groups, Predicates.notNull()),
+                new Function<AccountGroupName, AccountGroup.Id>() {
+                  @Override
+                  public AccountGroup.Id apply(AccountGroupName group) {
+                    return group.getId();
+                  }
+            })).iterator();
+
+        for (int i = 0; i < groupNames.length; i++) {
+          if (groups.get(i) == null) {
+            log.warn(MessageFormat.format(groupNotFoundWarning, groupNames[i]));
             continue;
           }
-
-          AccountGroup ag = db.accountGroups().get(group.getId());
+          AccountGroup ag = ags.next();
           if (ag == null) {
-            log.warn(MessageFormat.format(groupNotFoundWarning, name));
-            continue;
+            log.warn(MessageFormat.format(groupNotFoundWarning, groupNames[i]));
+          } else {
+            result.add(ag.getGroupUUID());
           }
-
-          result.add(ag.getGroupUUID());
         }
       } finally {
         db.close();
       }
+    } catch (OrmRuntimeException e) {
+      log.error("Database error, cannot load groups", e);
     } catch (OrmException e) {
       log.error("Database error, cannot load groups", e);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadSchemeConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadSchemeConfig.java
index 6f67032..ecfe4f5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadSchemeConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/DownloadSchemeConfig.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.config;
 
-import com.google.gerrit.reviewdb.SystemConfig;
-import com.google.gerrit.reviewdb.AccountGeneralPreferences.DownloadScheme;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.client.AccountGeneralPreferences.DownloadScheme;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/FactoryModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/FactoryModule.java
index 331f471..a0cf2ab 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/FactoryModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/FactoryModule.java
@@ -15,11 +15,7 @@
 package com.google.gerrit.server.config;
 
 import com.google.inject.AbstractModule;
-import com.google.inject.Key;
-import com.google.inject.assistedinject.FactoryProvider;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
 
 public abstract class FactoryModule extends AbstractModule {
   /**
@@ -42,63 +38,9 @@
    * Just pass {@code Foo.Factory.class} to this method. The factory will be
    * generated to return its one return type as declared in the creation method.
    *
-   * @param <F>
    * @param factory interface which specifies the bean factory method.
    */
-  protected <F> void factory(final Class<F> factory) {
-    factory(Key.get(factory), factory);
-  }
-
-  /**
-   * Register an assisted injection factory.
-   * <p>
-   * This function provides an automatic way to define a factory that creates a
-   * concrete type through assited injection. For example to configure the
-   * following assisted injection case:
-   *
-   * <pre>
-   * public class Foo {
-   *   public interface Factory {
-   *     Foo create(int a);
-   *   }
-   *   &#064;Inject
-   *   Foo(Logger log, @Assisted int a) {...}
-   * }
-   * </pre>
-   *
-   * Just pass {@code Foo.Factory.class} to this method. The factory will be
-   * generated to return its one return type as declared in the creation method.
-   *
-   * @param <F>
-   * @param key key to bind with in Guice bindings.
-   * @param factory interface which specifies the bean factory method.
-   */
-  protected <F> void factory(final Key<F> key, final Class<F> factory) {
-    final Method[] methods = factory.getDeclaredMethods();
-    switch (methods.length) {
-      case 1: {
-        final Class<?> result = methods[0].getReturnType();
-        if (isAbstract(result)) {
-          addError("Factory " + factory.getName() + " returns abstract result.");
-        } else {
-          bind(key).toProvider(FactoryProvider.newFactory(factory, result));
-        }
-        break;
-      }
-
-      case 0:
-        addError("Factory " + factory.getName() + " has no create method.");
-        break;
-
-      default:
-        addError("Factory " + factory.getName()
-            + " has more than one create method.");
-        break;
-    }
-  }
-
-  private static boolean isAbstract(final Class<?> result) {
-    return result.isInterface()
-        || (result.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
+  protected void factory(final Class<?> factory) {
+    install(new FactoryModuleBuilder().build(factory));
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 171d719..99dd54a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -17,7 +17,7 @@
 import static com.google.inject.Scopes.SINGLETON;
 
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.rules.PrologModule;
 import com.google.gerrit.rules.RulesCache;
 import com.google.gerrit.server.FileTypeRegistry;
@@ -27,12 +27,15 @@
 import com.google.gerrit.server.account.AccountByEmailCacheImpl;
 import com.google.gerrit.server.account.AccountCacheImpl;
 import com.google.gerrit.server.account.AccountInfoCacheFactory;
+import com.google.gerrit.server.account.AccountVisibility;
+import com.google.gerrit.server.account.AccountVisibilityProvider;
 import com.google.gerrit.server.account.CapabilityControl;
 import com.google.gerrit.server.account.DefaultRealm;
 import com.google.gerrit.server.account.EmailExpander;
 import com.google.gerrit.server.account.GroupCacheImpl;
 import com.google.gerrit.server.account.GroupIncludeCacheImpl;
 import com.google.gerrit.server.account.GroupInfoCacheFactory;
+import com.google.gerrit.server.account.MaterializedGroupMembership;
 import com.google.gerrit.server.account.Realm;
 import com.google.gerrit.server.auth.ldap.LdapModule;
 import com.google.gerrit.server.events.EventFactory;
@@ -54,6 +57,7 @@
 import com.google.gerrit.server.project.PermissionCollection;
 import com.google.gerrit.server.project.ProjectCacheImpl;
 import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.ProjectNode;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.project.SectionSortCache;
 import com.google.gerrit.server.tools.ToolsCatalog;
@@ -115,8 +119,13 @@
     factory(AccountInfoCacheFactory.Factory.class);
     factory(CapabilityControl.Factory.class);
     factory(GroupInfoCacheFactory.Factory.class);
+    factory(ProjectNode.Factory.class);
     factory(ProjectState.Factory.class);
+    factory(MaterializedGroupMembership.Factory.class);
     bind(PermissionCollection.Factory.class);
+    bind(AccountVisibility.class)
+        .toProvider(AccountVisibilityProvider.class)
+        .in(SINGLETON);
 
     bind(FileTypeRegistry.class).to(MimeUtilFileTypeRegistry.class);
     bind(ToolsCatalog.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
index 54445c5..71bcc6c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
@@ -16,10 +16,11 @@
 
 import static com.google.inject.Scopes.SINGLETON;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.RequestCleanup;
+import com.google.gerrit.server.account.AccountControl;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.GroupControl;
 import com.google.gerrit.server.account.GroupDetailFactory;
@@ -32,10 +33,10 @@
 import com.google.gerrit.server.changedetail.PublishDraft;
 import com.google.gerrit.server.changedetail.RestoreChange;
 import com.google.gerrit.server.changedetail.Submit;
+import com.google.gerrit.server.git.AsyncReceiveCommits;
 import com.google.gerrit.server.git.CreateCodeReviewNotes;
 import com.google.gerrit.server.git.MergeOp;
 import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ReceiveCommits;
 import com.google.gerrit.server.git.SubmoduleOp;
 import com.google.gerrit.server.mail.AbandonedSender;
 import com.google.gerrit.server.mail.AddReviewerSender;
@@ -43,6 +44,7 @@
 import com.google.gerrit.server.mail.CreateChangeSender;
 import com.google.gerrit.server.mail.MergeFailSender;
 import com.google.gerrit.server.mail.MergedSender;
+import com.google.gerrit.server.mail.RebasedPatchSetSender;
 import com.google.gerrit.server.mail.ReplacePatchSetSender;
 import com.google.gerrit.server.mail.RestoredSender;
 import com.google.gerrit.server.mail.RevertedSender;
@@ -51,6 +53,7 @@
 import com.google.gerrit.server.patch.RemoveReviewer;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.CreateProject;
+import com.google.gerrit.server.project.ListProjects;
 import com.google.gerrit.server.project.PerRequestProjectControlCache;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.SuggestParentCandidates;
@@ -69,18 +72,20 @@
     bind(MetaDataUpdate.User.class).in(RequestScoped.class);
     bind(AccountResolver.class);
     bind(ChangeQueryRewriter.class);
+    bind(ListProjects.class);
 
     bind(AnonymousUser.class).in(RequestScoped.class);
     bind(PerRequestProjectControlCache.class).in(RequestScoped.class);
     bind(ChangeControl.Factory.class).in(SINGLETON);
     bind(GroupControl.Factory.class).in(SINGLETON);
     bind(ProjectControl.Factory.class).in(SINGLETON);
+    bind(AccountControl.Factory.class).in(SINGLETON);
 
     factory(ChangeQueryBuilder.Factory.class);
-    factory(ReceiveCommits.Factory.class);
     factory(SubmoduleOp.Factory.class);
     factory(MergeOp.Factory.class);
     factory(CreateCodeReviewNotes.Factory.class);
+    install(new AsyncReceiveCommits.Module());
 
     // Not really per-request, but dammit, I don't know where else to
     // easily park this stuff.
@@ -93,6 +98,7 @@
     factory(PublishComments.Factory.class);
     factory(PublishDraft.Factory.class);
     factory(ReplacePatchSetSender.Factory.class);
+    factory(RebasedPatchSetSender.Factory.class);
     factory(AbandonedSender.Factory.class);
     factory(RemoveReviewer.Factory.class);
     factory(RestoreChange.Factory.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
index 1c13b9e..9992f18 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitReceivePackGroupsProvider.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.config;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.lib.Config;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
index 65e6900..76d8844 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitUploadPackGroupsProvider.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.config;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.lib.Config;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
index 6ff977f..15711af 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GroupSetProvider.java
@@ -17,9 +17,9 @@
 import static com.google.gerrit.server.config.ConfigUtil.groupsFor;
 import static java.util.Collections.unmodifiableSet;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroups.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroups.java
index 4ce1258..876c51f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroups.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroups.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.config;
 
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 import com.google.inject.BindingAnnotation;
 
 import java.lang.annotation.Retention;
 
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
 /**
  * Marker on a {@code Set&lt;AccountGroup.Id>} for the configured groups which
  * should become owners of a created project.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
index 05ea11d..b279086 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ProjectOwnerGroupsProvider.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.config;
 
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.lib.Config;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/RequestScopedReviewDbProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/RequestScopedReviewDbProvider.java
index 9c3da74..4518a2e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/RequestScopedReviewDbProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/RequestScopedReviewDbProvider.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.config;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.RequestCleanup;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java
index 06ef0dc..c10c0eb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/TrackingFootersProvider.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.config;
 
-import com.google.gerrit.reviewdb.TrackingId;
+import com.google.gerrit.reviewdb.client.TrackingId;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStore.java
index 84c7c75..0ab21f9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStore.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.contact;
 
 import com.google.gerrit.common.errors.ContactInformationStoreException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ContactInformation;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ContactInformation;
 
 public interface ContactStore {
   boolean isEnabled();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java
index 73dd46e..d5cd11a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.contact;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
index d391694..bc88cd2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
@@ -15,13 +15,13 @@
 package com.google.gerrit.server.contact;
 
 import com.google.gerrit.common.errors.ContactInformationStoreException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.ContactInformation;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.ContactInformation;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.UrlEncoded;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.ProvisionException;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/HttpContactStoreConnection.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/HttpContactStoreConnection.java
index 781f401..e210865 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/HttpContactStoreConnection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/HttpContactStoreConnection.java
@@ -2,15 +2,11 @@
 
 package com.google.gerrit.server.contact;
 
-import static com.google.inject.Scopes.SINGLETON;
-
-import com.google.gerrit.server.contact.ContactStoreConnection;
-import com.google.gerrit.server.contact.HttpContactStoreConnection;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.assistedinject.Assisted;
-import com.google.inject.assistedinject.FactoryProvider;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
 
 import org.eclipse.jgit.util.IO;
 
@@ -27,11 +23,9 @@
     return new AbstractModule() {
       @Override
       protected void configure() {
-        bind(ContactStoreConnection.Factory.class)
-            .toProvider(FactoryProvider.newFactory(
-                ContactStoreConnection.Factory.class,
-                HttpContactStoreConnection.class))
-            .in(SINGLETON);
+        install(new FactoryModuleBuilder()
+            .implement(ContactStoreConnection.class, HttpContactStoreConnection.class)
+            .build(ContactStoreConnection.Factory.class));
       }
     };
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/NoContactStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/NoContactStore.java
index e219186..a625c0c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/NoContactStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/NoContactStore.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.contact;
 
 import com.google.gerrit.common.errors.ContactInformationStoreException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ContactInformation;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ContactInformation;
 
 class NoContactStore implements ContactStore {
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeAttribute.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeAttribute.java
index 9050641..9810f59 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeAttribute.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/ChangeAttribute.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.events;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 
 import java.util.List;
 
@@ -39,4 +39,7 @@
     public List<TrackingIdAttribute> trackingIds;
     public PatchSetAttribute currentPatchSet;
     public List<PatchSetAttribute> patchSets;
+
+    public List<DependencyAttribute> dependsOn;
+    public List<DependencyAttribute> neededBy;
 }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CodedEnum.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/DependencyAttribute.java
similarity index 67%
copy from gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CodedEnum.java
copy to gerrit-server/src/main/java/com/google/gerrit/server/events/DependencyAttribute.java
index 5900292..47fbdac 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/CodedEnum.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/DependencyAttribute.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 The Android Open Source Project
+// Copyright (C) 2012 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,9 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.reviewdb;
+package com.google.gerrit.server.events;
 
-/** Extension of Enum which provides distinct character code values. */
-public interface CodedEnum {
-  char getCode();
+public class DependencyAttribute {
+  public String id;
+  public String number;
+  public String revision;
+  public String ref;
+  public Boolean isCurrentPatchSet;
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
index cf035c8..4d34b71 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
@@ -16,19 +16,24 @@
 
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.TrackingId;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetAncestor;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.client.TrackingId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.patch.PatchListEntry;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -47,16 +52,18 @@
   private final Provider<String> urlProvider;
   private final ApprovalTypes approvalTypes;
   private final PatchListCache patchListCache;
+  private final SchemaFactory<ReviewDb> schema;
 
   @Inject
   EventFactory(AccountCache accountCache,
       @CanonicalWebUrl @Nullable Provider<String> urlProvider,
       ApprovalTypes approvalTypes,
-      PatchListCache patchListCache) {
+      PatchListCache patchListCache, SchemaFactory<ReviewDb> schema) {
     this.accountCache = accountCache;
     this.urlProvider = urlProvider;
     this.approvalTypes = approvalTypes;
     this.patchListCache = patchListCache;
+    this.schema = schema;
   }
 
   /**
@@ -110,6 +117,61 @@
     a.status = change.getStatus();
   }
 
+  public void addDependencies(ChangeAttribute ca, Change change) {
+    ca.dependsOn = new ArrayList<DependencyAttribute>();
+    ca.neededBy = new ArrayList<DependencyAttribute>();
+    try {
+      final ReviewDb db = schema.open();
+      try {
+        final PatchSet.Id psId = change.currentPatchSetId();
+        for (PatchSetAncestor a : db.patchSetAncestors().ancestorsOf(psId)) {
+          for (PatchSet p :
+              db.patchSets().byRevision(a.getAncestorRevision())) {
+            Change c = db.changes().get(p.getId().getParentKey());
+            ca.dependsOn.add(newDependsOn(c, p));
+          }
+        }
+
+        final RevId revId = db.patchSets().get(psId).getRevision();
+        for (PatchSetAncestor a : db.patchSetAncestors().descendantsOf(revId)) {
+          final PatchSet p = db.patchSets().get(a.getPatchSet());
+          final Change c = db.changes().get(p.getId().getParentKey());
+          ca.neededBy.add(newNeededBy(c, p));
+        }
+      } finally {
+        db.close();
+      }
+    } catch (OrmException e) {
+      // Squash DB exceptions and leave dependency lists partially filled.
+    }
+    // Remove empty lists so a confusing label won't be displayed in the output.
+    if (ca.dependsOn.isEmpty()) {
+      ca.dependsOn = null;
+    }
+    if (ca.neededBy.isEmpty()) {
+      ca.neededBy = null;
+    }
+  }
+
+  private DependencyAttribute newDependsOn(Change c, PatchSet ps) {
+    DependencyAttribute d = newDependencyAttribute(c, ps);
+    d.isCurrentPatchSet = c.currPatchSetId().equals(ps.getId());
+    return d;
+  }
+
+  private DependencyAttribute newNeededBy(Change c, PatchSet ps) {
+    return newDependencyAttribute(c, ps);
+  }
+
+  private DependencyAttribute newDependencyAttribute(Change c, PatchSet ps) {
+    DependencyAttribute d = new DependencyAttribute();
+    d.number = c.getId().toString();
+    d.id = c.getKey().toString();
+    d.revision = ps.getRevision().get();
+    d.ref = ps.getRefName();
+    return d;
+  }
+
   public void addTrackingIds(ChangeAttribute a, Collection<TrackingId> ids) {
     if (!ids.isEmpty()) {
       a.trackingIds = new ArrayList<TrackingIdAttribute>(ids.size());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/PatchAttribute.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/PatchAttribute.java
index 2b08fa7..3802fdd 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/PatchAttribute.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/PatchAttribute.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.events;
 
-import com.google.gerrit.reviewdb.Patch.ChangeType;
+import com.google.gerrit.reviewdb.client.Patch.ChangeType;
 
 public class PatchAttribute {
     public String file;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/AsyncReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/AsyncReceiveCommits.java
new file mode 100644
index 0000000..c8d741b
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/AsyncReceiveCommits.java
@@ -0,0 +1,184 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.config.ConfigUtil;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.WorkQueue.Executor;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.util.RequestScopePropagator;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+import com.google.inject.Inject;
+
+import com.google.inject.name.Named;
+import com.google.inject.PrivateModule;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.PreReceiveHook;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.transport.ReceiveCommand.Result;
+import org.eclipse.jgit.transport.ReceivePack;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/** Hook that delegates to {@link ReceiveCommits} in a worker thread. */
+public class AsyncReceiveCommits implements PreReceiveHook {
+  private static final Logger log =
+      LoggerFactory.getLogger(AsyncReceiveCommits.class);
+
+  private static final String TIMEOUT_NAME = "ReceiveCommitsOverallTimeout";
+
+  public interface Factory {
+    AsyncReceiveCommits create(ProjectControl projectControl,
+        Repository repository);
+  }
+
+  public static class Module extends PrivateModule {
+    @Override
+    public void configure() {
+      install(new FactoryModuleBuilder()
+          .build(AsyncReceiveCommits.Factory.class));
+      expose(AsyncReceiveCommits.Factory.class);
+      // Don't expose the binding for ReceiveCommits.Factory. All callers should
+      // be using AsyncReceiveCommits.Factory instead.
+      install(new FactoryModuleBuilder()
+          .build(ReceiveCommits.Factory.class));
+    }
+
+    @Provides
+    @Singleton
+    @Named(TIMEOUT_NAME)
+    long getTimeoutMillis(@GerritServerConfig final Config cfg) {
+      return ConfigUtil.getTimeUnit(
+          cfg, "receive", null, "timeout",
+          TimeUnit.MINUTES.toMillis(2),
+          TimeUnit.MILLISECONDS);
+    }
+  }
+
+  private class Worker implements ProjectRunnable {
+    private final Collection<ReceiveCommand> commands;
+
+    private Worker(final Collection<ReceiveCommand> commands) {
+      this.commands = commands;
+    }
+
+    @Override
+    public void run() {
+      rc.processCommands(commands, progress);
+    }
+
+    @Override
+    public Project.NameKey getProjectNameKey() {
+      return rc.getProject().getNameKey();
+    }
+
+    @Override
+    public String getRemoteName() {
+      return null;
+    }
+
+    @Override
+    public boolean hasCustomizedPrint() {
+      return true;
+    }
+
+    @Override
+    public String toString() {
+      return "receive-commits";
+    }
+  }
+
+  private class MessageSenderOutputStream extends OutputStream {
+    @Override
+    public void write(int b) {
+      rc.getMessageSender().sendBytes(new byte[]{(byte)b});
+    }
+
+    @Override
+    public void write(byte[] what, int off, int len) {
+      rc.getMessageSender().sendBytes(what, off, len);
+    }
+
+    @Override
+    public void write(byte[] what) {
+      rc.getMessageSender().sendBytes(what);
+    }
+
+    @Override
+    public void flush() {
+      rc.getMessageSender().flush();
+    }
+  }
+
+  private final ReceiveCommits rc;
+  private final Executor executor;
+  private final RequestScopePropagator scopePropagator;
+  private final MultiProgressMonitor progress;
+  private final long timeoutMillis;
+
+  @Inject
+  AsyncReceiveCommits(final ReceiveCommits.Factory factory,
+      @ReceiveCommitsExecutor final Executor executor,
+      final RequestScopePropagator scopePropagator,
+      @Named(TIMEOUT_NAME) final long timeoutMillis,
+      @Assisted final ProjectControl projectControl,
+      @Assisted final Repository repo) {
+    this.executor = executor;
+    this.scopePropagator = scopePropagator;
+    rc = factory.create(projectControl, repo);
+    rc.getReceivePack().setPreReceiveHook(this);
+
+    progress = new MultiProgressMonitor(
+        new MessageSenderOutputStream(), "Processing changes");
+    this.timeoutMillis = timeoutMillis;
+  }
+
+  @Override
+  public void onPreReceive(final ReceivePack rp,
+      final Collection<ReceiveCommand> commands) {
+    try {
+      progress.waitFor(
+          executor.submit(scopePropagator.wrap(new Worker(commands))),
+          timeoutMillis, TimeUnit.MILLISECONDS);
+    } catch (ExecutionException e) {
+      log.warn("Error in ReceiveCommits", e);
+      rc.addError("internal error while processing changes");
+      // ReceiveCommits has tried its best to catch errors, so anything at this
+      // point is very bad.
+      for (final ReceiveCommand c : commands) {
+        if (c.getResult() == Result.NOT_ATTEMPTED) {
+          c.setResult(Result.REJECTED_OTHER_REASON, "internal error");
+        }
+      }
+    } finally {
+      rc.sendMessages();
+    }
+  }
+
+  public ReceiveCommits getReceiveCommits() {
+    return rc;
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java
index 0bcd37b..86e0740 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ChangeMergeQueue.java
@@ -17,13 +17,14 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.RemotePeer;
 import com.google.gerrit.server.config.GerritRequestModule;
 import com.google.gerrit.server.ssh.SshInfo;
+import com.google.gerrit.server.util.RequestScopePropagator;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
@@ -65,6 +66,8 @@
       @Override
       protected void configure() {
         bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST);
+        bind(RequestScopePropagator.class)
+            .to(PerThreadRequestScope.Propagator.class);
         install(new GerritRequestModule());
 
         bind(CurrentUser.class).to(IdentifiedUser.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/CodeReviewCommit.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/CodeReviewCommit.java
index 863c0bd..86d79e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/CodeReviewCommit.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/CodeReviewCommit.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
 
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java
index 129dfa9..6fea8f1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/CreateCodeReviewNotes.java
@@ -18,16 +18,16 @@
 
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
index cce318a..a2b0495 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/GitRepositoryManager.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
@@ -70,11 +70,12 @@
    * @param name the repository name, relative to the base directory.
    * @return the cached Repository instance. Caller must call {@code close()}
    *         when done to decrement the resource handle.
-   * @throws RepositoryNotFoundException the name does not denote an existing
-   *         repository, or the name cannot be read as a repository.
+   * @throws RepositoryCaseMismatchException the name collides with an existing
+   *         repository name, but only in case of a character within the name.
+   * @throws RepositoryNotFoundException the name is invalid.
    */
   public abstract Repository createRepository(Project.NameKey name)
-      throws RepositoryNotFoundException;
+      throws RepositoryCaseMismatchException, RepositoryNotFoundException;
 
   /** @return set of all known projects, sorted by natural NameKey order. */
   public abstract SortedSet<Project.NameKey> list();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LargeObjectException.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LargeObjectException.java
new file mode 100644
index 0000000..d08b8768
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LargeObjectException.java
@@ -0,0 +1,33 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+/**
+ * Wrapper for {@link org.eclipse.jgit.errors.LargeObjectException}. Since
+ * org.eclipse.jgit.errors.LargeObjectException is a {@link RuntimeException}
+ * the GerritJsonServlet would treat it as internal failure and as result the
+ * web ui would just show 'Internal Server Error'. Wrapping
+ * org.eclipse.jgit.errors.LargeObjectException into a normal {@link Exception}
+ * allows to display a proper error message.
+ */
+public class LargeObjectException extends Exception {
+
+  private static final long serialVersionUID = 1L;
+
+  public LargeObjectException(final String message,
+      final org.eclipse.jgit.errors.LargeObjectException cause) {
+    super(message, cause);
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index be444f8..9fa45e1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.lifecycle.LifecycleListener;
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.AbstractModule;
@@ -46,6 +46,8 @@
 import java.util.Collections;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 /** Manages Git repositories stored on the local filesystem. */
 @Singleton
@@ -91,6 +93,8 @@
   }
 
   private final File basePath;
+  private final Lock namesUpdateLock;
+  private volatile SortedSet<Project.NameKey> names;
 
   @Inject
   LocalDiskRepositoryManager(final SitePaths site,
@@ -99,6 +103,8 @@
     if (basePath == null) {
       throw new IllegalStateException("gerrit.basePath must be configured");
     }
+    namesUpdateLock = new ReentrantLock(true /* fair */);
+    names = list();
   }
 
   /** @return base directory under which all projects are stored. */
@@ -115,13 +121,10 @@
     if (isUnreasonableName(name)) {
       throw new RepositoryNotFoundException("Invalid name: " + name);
     }
-
-    final FileKey loc = FileKey.lenient(gitDirOf(name), FS.DETECTED);
-
-    if (!getProjectName(loc.getFile()).equals(name)) {
+    if (!names.contains(name)) {
       throw new RepositoryNotFoundException(gitDirOf(name));
     }
-
+    final FileKey loc = FileKey.lenient(gitDirOf(name), FS.DETECTED);
     try {
       return RepositoryCache.open(loc);
     } catch (IOException e1) {
@@ -133,7 +136,7 @@
   }
 
   public Repository createRepository(final Project.NameKey name)
-      throws RepositoryNotFoundException {
+      throws RepositoryNotFoundException, RepositoryCaseMismatchException {
     if (isUnreasonableName(name)) {
       throw new RepositoryNotFoundException("Invalid name: " + name);
     }
@@ -145,10 +148,8 @@
       //
       loc = FileKey.exact(dir, FS.DETECTED);
 
-      final Project.NameKey nameOfExistingProject =
-          getProjectName(loc.getFile());
-      if (!nameOfExistingProject.equals(name)) {
-        throw new RepositoryCaseMismatchException(name, nameOfExistingProject);
+      if (!names.contains(name)) {
+        throw new RepositoryCaseMismatchException(name);
       }
     } else {
       // It doesn't exist under any of the standard permutations
@@ -170,6 +171,8 @@
         null, ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
       config.save();
 
+      onCreateProject(name);
+
       return db;
     } catch (IOException e1) {
       final RepositoryNotFoundException e2;
@@ -179,6 +182,17 @@
     }
   }
 
+  private void onCreateProject(final Project.NameKey newProjectName) {
+    namesUpdateLock.lock();
+    try {
+      SortedSet<Project.NameKey> n = new TreeSet<Project.NameKey>(names);
+      n.add(newProjectName);
+      names = Collections.unmodifiableSortedSet(n);
+    } finally {
+      namesUpdateLock.unlock();
+    }
+  }
+
   public String getProjectDescription(final Project.NameKey name)
       throws RepositoryNotFoundException, IOException {
     final Repository e = openRepository(name);
@@ -268,9 +282,18 @@
 
   @Override
   public SortedSet<Project.NameKey> list() {
-    SortedSet<Project.NameKey> names = new TreeSet<Project.NameKey>();
-    scanProjects(basePath, "", names);
-    return Collections.unmodifiableSortedSet(names);
+    // The results of this method are cached by ProjectCacheImpl. Control only
+    // enters here if the cache was flushed by the administrator to force
+    // scanning the filesystem. Don't rely on the cached names collection.
+    namesUpdateLock.lock();
+    try {
+      SortedSet<Project.NameKey> n = new TreeSet<Project.NameKey>();
+      scanProjects(basePath, "", n);
+      names = Collections.unmodifiableSortedSet(n);
+      return n;
+    } finally {
+      namesUpdateLock.unlock();
+    }
   }
 
   private void scanProjects(final File dir, final String prefix,
@@ -312,16 +335,4 @@
 
     return new Project.NameKey(projectName);
   }
-
-  private Project.NameKey getProjectName(final File gitDir) {
-    String relativeGitPath =
-        getBasePath().toURI().relativize(gitDir.toURI()).getPath();
-    if (!relativeGitPath.endsWith("/")) {
-      relativeGitPath = relativeGitPath + "/";
-    }
-    final String prefix =
-        relativeGitPath.substring(0, relativeGitPath.length() - 1
-            - gitDir.getName().length());
-    return getProjectName(prefix, gitDir.getName());
-  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index c0f5f182..4773680 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -21,23 +21,22 @@
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
 import com.google.gerrit.common.data.Capable;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetAncestor;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+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.PatchSetApproval;
+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.account.AccountCache;
 import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gerrit.server.mail.EmailException;
 import com.google.gerrit.server.mail.MergeFailSender;
 import com.google.gerrit.server.mail.MergedSender;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
@@ -46,12 +45,13 @@
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.util.RequestScopePropagator;
 import com.google.gerrit.server.workflow.CategoryFunction;
 import com.google.gerrit.server.workflow.FunctionState;
-import com.google.gwtorm.client.AtomicUpdate;
-import com.google.gwtorm.client.OrmConcurrencyException;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.AtomicUpdate;
+import com.google.gwtorm.server.OrmConcurrencyException;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
@@ -150,8 +150,8 @@
   private final List<CodeReviewCommit> toMerge;
   private List<Change> submitted;
   private final Map<Change.Id, CodeReviewCommit> commits;
-  private ReviewDb schema;
-  private Repository db;
+  private ReviewDb db;
+  private Repository repo;
   private RevWalk rw;
   private RevFlag CAN_MERGE;
   private CodeReviewCommit branchTip;
@@ -164,6 +164,8 @@
   private final TagCache tagCache;
   private final CreateCodeReviewNotes.Factory codeReviewNotesFactory;
   private final SubmoduleOp.Factory subOpFactory;
+  private final WorkQueue workQueue;
+  private final RequestScopePropagator requestScopePropagator;
 
   @Inject
   MergeOp(final GitRepositoryManager grm, final SchemaFactory<ReviewDb> sf,
@@ -178,7 +180,9 @@
       final MergeQueue mergeQueue, @Assisted final Branch.NameKey branch,
       final ChangeHooks hooks, final AccountCache accountCache,
       final TagCache tagCache, final CreateCodeReviewNotes.Factory crnf,
-      final SubmoduleOp.Factory subOpFactory) {
+      final SubmoduleOp.Factory subOpFactory,
+      final WorkQueue workQueue,
+      final RequestScopePropagator requestScopePropagator) {
     repoManager = grm;
     schemaFactory = sf;
     functionState = fs;
@@ -197,7 +201,8 @@
     this.tagCache = tagCache;
     codeReviewNotesFactory = crnf;
     this.subOpFactory = subOpFactory;
-
+    this.workQueue = workQueue;
+    this.requestScopePropagator = requestScopePropagator;
     this.myIdent = myIdent;
     destBranch = branch;
     toMerge = new ArrayList<CodeReviewCommit>();
@@ -208,7 +213,7 @@
     try {
       setDestProject();
       openRepository();
-      final Ref destBranchRef = db.getRef(destBranch.get());
+      final Ref destBranchRef = repo.getRef(destBranch.get());
       submitted = new ArrayList<Change>();
       submitted.add(change);
 
@@ -230,7 +235,7 @@
           change.setLastSha1MergeTested(new RevId(""));
         }
         change.setMergeable(isMergeable(change));
-        schema.changes().update(Collections.singleton(change));
+        db.changes().update(Collections.singleton(change));
       }
     } catch (MergeException e) {
       log.error("Test merge attempt for change: " + change.getId()
@@ -242,10 +247,10 @@
       log.error("Test merge attempt for change: " + change.getId()
           + " failed", e);
     } finally {
-      if (schema != null) {
-        schema.close();
+      if (db != null) {
+        db.close();
       }
-      schema = null;
+      db = null;
     }
   }
 
@@ -258,8 +263,8 @@
   }
 
   private void openSchema() throws OrmException {
-    if (schema == null) {
-      schema = schemaFactory.open();
+    if (db == null) {
+      db = schemaFactory.open();
     }
   }
 
@@ -268,7 +273,7 @@
     try {
       openSchema();
       openRepository();
-      submitted = schema.changes().submitted(destBranch).toList();
+      submitted = db.changes().submitted(destBranch).toList();
       preMerge();
       updateBranch();
       updateChangeStatus();
@@ -279,11 +284,11 @@
       if (rw != null) {
         rw.release();
       }
-      if (db != null) {
-        db.close();
+      if (repo != null) {
+        repo.close();
       }
-      schema.close();
-      schema = null;
+      db.close();
+      db = null;
     }
   }
 
@@ -310,13 +315,13 @@
   private void openRepository() throws MergeException {
     final Project.NameKey name = destBranch.getParentKey();
     try {
-      db = repoManager.openRepository(name);
+      repo = repoManager.openRepository(name);
     } catch (RepositoryNotFoundException notGit) {
       final String m = "Repository \"" + name.get() + "\" unknown.";
       throw new MergeException(m, notGit);
     }
 
-    rw = new RevWalk(db) {
+    rw = new RevWalk(repo) {
       @Override
       protected RevCommit createCommit(final AnyObjectId id) {
         return new CodeReviewCommit(id);
@@ -331,7 +336,7 @@
     alreadyAccepted = new HashSet<RevCommit>();
 
     try {
-      branchUpdate = db.updateRef(destBranch.get());
+      branchUpdate = repo.updateRef(destBranch.get());
       if (branchUpdate.getOldObjectId() != null) {
         branchTip =
             (CodeReviewCommit) rw.parseCommit(branchUpdate.getOldObjectId());
@@ -340,7 +345,7 @@
         branchTip = null;
       }
 
-      for (final Ref r : db.getAllRefs().values()) {
+      for (final Ref r : repo.getAllRefs().values()) {
         if (r.getName().startsWith(Constants.R_HEADS)
             || r.getName().startsWith(Constants.R_TAGS)) {
           try {
@@ -357,7 +362,7 @@
 
   private void validateChangeList() throws MergeException {
     final Set<ObjectId> tips = new HashSet<ObjectId>();
-    for (final Ref r : db.getAllRefs().values()) {
+    for (final Ref r : repo.getAllRefs().values()) {
       tips.add(r.getObjectId());
     }
 
@@ -372,7 +377,7 @@
 
       final PatchSet ps;
       try {
-        ps = schema.patchSets().get(chg.currentPatchSetId());
+        ps = db.patchSets().get(chg.currentPatchSetId());
       } catch (OrmException e) {
         throw new MergeException("Cannot query the database", e);
       }
@@ -501,11 +506,11 @@
       // Settings for this project allow us to try and
       // automatically resolve conflicts within files if needed.
       // Use ResolveMerge and instruct to operate in core.
-      m = MergeStrategy.RESOLVE.newMerger(db, true);
+      m = MergeStrategy.RESOLVE.newMerger(repo, true);
     } else {
       // No auto conflict resolving allowed. If any of the
       // affected files was modified, merge will fail.
-      m = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+      m = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(repo);
     }
 
     try {
@@ -603,7 +608,7 @@
       final List<CodeReviewCommit> codeReviewCommits) {
     PatchSetApproval submitter = null;
     for (final CodeReviewCommit c : codeReviewCommits) {
-      PatchSetApproval s = getSubmitter(c.patchsetId);
+      PatchSetApproval s = getSubmitter(db, c.patchsetId);
       if (submitter == null
           || (s != null && s.getGranted().compareTo(submitter.getGranted()) > 0)) {
         submitter = s;
@@ -663,7 +668,7 @@
         if (c.patchsetId != null) {
           c.statusCode = CommitMergeStatus.CLEAN_MERGE;
           if (branchUpdate.getRefLogIdent() == null) {
-            setRefLogIdent(getSubmitter(c.patchsetId));
+            setRefLogIdent(getSubmitter(db, c.patchsetId));
           }
         }
       }
@@ -688,11 +693,11 @@
         // Settings for this project allow us to try and
         // automatically resolve conflicts within files if needed.
         // Use ResolveMerge and instruct to operate in core.
-        m = MergeStrategy.RESOLVE.newMerger(db, true);
+        m = MergeStrategy.RESOLVE.newMerger(repo, true);
       } else {
         // No auto conflict resolving allowed. If any of the
         // affected files was modified, merge will fail.
-        m = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+        m = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(repo);
       }
 
       try {
@@ -807,7 +812,7 @@
     List<PatchSetApproval> approvalList = null;
     try {
       approvalList =
-          schema.patchSetApprovals().byPatchSet(n.patchsetId).toList();
+          db.patchSetApprovals().byPatchSet(n.patchsetId).toList();
       Collections.sort(approvalList, new Comparator<PatchSetApproval>() {
         public int compare(final PatchSetApproval a, final PatchSetApproval b) {
           return a.getGranted().compareTo(b.getGranted());
@@ -893,7 +898,7 @@
     final CodeReviewCommit newCommit = (CodeReviewCommit) rw.parseCommit(id);
 
     n.change =
-        schema.changes().atomicUpdate(n.change.getId(),
+        db.changes().atomicUpdate(n.change.getId(),
             new AtomicUpdate<Change>() {
               @Override
               public Change update(Change change) {
@@ -907,10 +912,10 @@
     ps.setUploader(submitAudit.getAccountId());
     ps.setRevision(new RevId(id.getName()));
     insertAncestors(ps.getId(), newCommit);
-    schema.patchSets().insert(Collections.singleton(ps));
+    db.patchSets().insert(Collections.singleton(ps));
 
     n.change =
-        schema.changes().atomicUpdate(n.change.getId(),
+        db.changes().atomicUpdate(n.change.getId(),
             new AtomicUpdate<Change>() {
               @Override
               public Change update(Change change) {
@@ -922,7 +927,7 @@
 
     if (approvalList != null) {
       for (PatchSetApproval a : approvalList) {
-        schema.patchSetApprovals().insert(
+        db.patchSetApprovals().insert(
             Collections.singleton(new PatchSetApproval(ps.getId(), a)));
       }
     }
@@ -945,7 +950,7 @@
       a.setAncestorRevision(new RevId(src.getParent(p).getId().name()));
       toInsert.add(a);
     }
-    schema.patchSetAncestors().insert(toInsert);
+    db.patchSetAncestors().insert(toInsert);
   }
 
   private ObjectId commit(final Merger m, final CommitBuilder mergeCommit)
@@ -992,7 +997,7 @@
       if (GitRepositoryManager.REF_CONFIG.equals(branchUpdate.getName())) {
         try {
           ProjectConfig cfg = new ProjectConfig(destProject.getNameKey());
-          cfg.load(db, mergeTip);
+          cfg.load(repo, mergeTip);
         } catch (Exception e) {
           throw new MergeException("Submit would store invalid"
               + " project configuration " + mergeTip.name() + " for "
@@ -1025,7 +1030,7 @@
                 .getName());
 
             Account account = null;
-            final PatchSetApproval submitter = getSubmitter(mergeTip.patchsetId);
+            final PatchSetApproval submitter = getSubmitter(db, mergeTip.patchsetId);
             if (submitter != null) {
               account = accountCache.get(submitter.getAccountId()).getAccount();
             }
@@ -1041,7 +1046,7 @@
     }
   }
 
-  private boolean isMergeable(Change c) throws OrmException {
+  private boolean isMergeable(Change c) {
     final CodeReviewCommit commit = commits.get(c.getId());
     final CommitMergeStatus s = commit != null ? commit.statusCode : null;
     boolean isMergeable = false;
@@ -1055,7 +1060,7 @@
     return isMergeable;
   }
 
-  private void updateChangeStatus() throws MergeException {
+  private void updateChangeStatus() {
     List<CodeReviewCommit> merged = new ArrayList<CodeReviewCommit>();
 
     for (final Change c : submitted) {
@@ -1111,7 +1116,7 @@
     }
 
     CreateCodeReviewNotes codeReviewNotes =
-        codeReviewNotesFactory.create(schema, db);
+        codeReviewNotesFactory.create(db, repo);
     try {
       codeReviewNotes.create(merged, computeAuthor(merged));
     } catch (CodeReviewNoteCreationException e) {
@@ -1121,10 +1126,10 @@
         GitRepositoryManager.REFS_NOTES_REVIEW);
   }
 
-  private void updateSubscriptions() throws MergeException {
+  private void updateSubscriptions() {
     if (mergeTip != null && (branchTip == null || branchTip != mergeTip)) {
       SubmoduleOp subOp =
-          subOpFactory.create(destBranch, mergeTip, rw, db, destProject,
+          subOpFactory.create(destBranch, mergeTip, rw, repo, destProject,
               submitted, commits);
       try {
         subOp.update();
@@ -1236,11 +1241,11 @@
     if (commit.patchsetId == null) {
       try {
         List<PatchSet> matches =
-            schema.patchSets().byRevision(new RevId(commit.name())).toList();
+            db.patchSets().byRevision(new RevId(commit.name())).toList();
         if (matches.size() == 1) {
           final PatchSet ps = matches.get(0);
           commit.patchsetId = ps.getId();
-          commit.change = schema.changes().get(ps.getId().getParentKey());
+          commit.change = db.changes().get(ps.getId().getParentKey());
         }
       } catch (OrmException e) {
       }
@@ -1250,7 +1255,7 @@
   private boolean isAlreadySent(final Change c, final String prefix) {
     try {
       final List<ChangeMessage> msgList =
-          schema.changeMessages().byChange(c.getId()).toList();
+          db.changeMessages().byChange(c.getId()).toList();
       if (msgList.size() > 0) {
         final ChangeMessage last = msgList.get(msgList.size() - 1);
         if (last.getAuthor() == null && last.getMessage().startsWith(prefix)) {
@@ -1274,7 +1279,7 @@
   private ChangeMessage message(final Change c, final String body) {
     final String uuid;
     try {
-      uuid = ChangeUtil.messageUUID(schema);
+      uuid = ChangeUtil.messageUUID(db);
     } catch (OrmException e) {
       return null;
     }
@@ -1285,14 +1290,15 @@
     return m;
   }
 
-  private PatchSetApproval getSubmitter(PatchSet.Id c) {
+  private static PatchSetApproval getSubmitter(ReviewDb reviewDb,
+      PatchSet.Id c) {
     if (c == null) {
       return null;
     }
     PatchSetApproval submitter = null;
     try {
       final List<PatchSetApproval> approvals =
-          schema.patchSetApprovals().byPatchSet(c).toList();
+          reviewDb.patchSetApprovals().byPatchSet(c).toList();
       for (PatchSetApproval a : approvals) {
         if (a.getValue() > 0
             && ApprovalCategory.SUBMIT.equals(a.getCategoryId())) {
@@ -1307,7 +1313,7 @@
     return submitter;
   }
 
-  private void setMerged(Change c, ChangeMessage msg) {
+  private void setMerged(final Change c, final ChangeMessage msg) {
     final Change.Id changeId = c.getId();
     // We must pull the patchset out of commits, because the patchset ID is
     // modified when using the cherry-pick merge strategy.
@@ -1315,7 +1321,7 @@
     final PatchSet.Id merged = commit.change.currentPatchSetId();
 
     try {
-      schema.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() {
+      db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() {
         @Override
         public Change update(Change c) {
           c.setStatus(Change.Status.MERGED);
@@ -1328,7 +1334,7 @@
             // Go back to the patch set that was actually merged.
             //
             try {
-              c.setCurrentPatchSet(patchSetInfoFactory.get(schema, merged));
+              c.setCurrentPatchSet(patchSetInfoFactory.get(db, merged));
             } catch (PatchSetInfoNotAvailableException e1) {
               log.error("Cannot read merged patch set " + merged, e1);
             }
@@ -1352,7 +1358,7 @@
     try {
       c.setStatus(Change.Status.MERGED);
       final List<PatchSetApproval> approvals =
-          schema.patchSetApprovals().byChange(changeId).toList();
+          db.patchSetApprovals().byChange(changeId).toList();
       final FunctionState fs = functionState.create(
           changeControlFactory.controlFor(
               c,
@@ -1372,7 +1378,7 @@
         }
         a.cache(c);
       }
-      schema.patchSetApprovals().update(approvals);
+      db.patchSetApprovals().update(approvals);
     } catch (NoSuchChangeException err) {
       log.warn("Cannot normalize approvals for change " + changeId, err);
     } catch (OrmException err) {
@@ -1384,29 +1390,53 @@
         msg.setAuthor(submitter.getAccountId());
       }
       try {
-        schema.changeMessages().insert(Collections.singleton(msg));
+        db.changeMessages().insert(Collections.singleton(msg));
       } catch (OrmException err) {
         log.warn("Cannot store message on change", err);
       }
     }
 
-    try {
-      final MergedSender cm = mergedSenderFactory.create(c);
-      if (submitter != null) {
-        cm.setFrom(submitter.getAccountId());
+    final PatchSetApproval from = submitter;
+    workQueue.getDefaultQueue()
+        .submit(requestScopePropagator.wrap(new Runnable() {
+      @Override
+      public void run() {
+        PatchSet patchSet;
+        try {
+          ReviewDb reviewDb = schemaFactory.open();
+          try {
+            patchSet = reviewDb.patchSets().get(c.currentPatchSetId());
+          } finally {
+            reviewDb.close();
+          }
+        } catch (Exception e) {
+          log.error("Cannot send email for submitted patch set " + c.getId(), e);
+          return;
+        }
+
+        try {
+          final MergedSender cm = mergedSenderFactory.create(c);
+          if (from != null) {
+            cm.setFrom(from.getAccountId());
+          }
+          cm.setPatchSet(patchSet);
+          cm.send();
+        } catch (Exception e) {
+          log.error("Cannot send email for submitted patch set " + c.getId(), e);
+        }
       }
-      cm.setPatchSet(schema.patchSets().get(c.currentPatchSetId()));
-      cm.send();
-    } catch (OrmException e) {
-      log.error("Cannot send email for submitted patch set " + c.getId(), e);
-    } catch (EmailException e) {
-      log.error("Cannot send email for submitted patch set " + c.getId(), e);
-    }
+
+      @Override
+      public String toString() {
+        return "send-email merged";
+      }
+    }));
+
 
     try {
       hooks.doChangeMergedHook(c, //
           accountCache.get(submitter.getAccountId()).getAccount(), //
-          schema.patchSets().get(c.currentPatchSetId()), schema);
+          db.patchSets().get(c.currentPatchSetId()), db);
     } catch (OrmException ex) {
       log.error("Cannot run hook for submitted patch set " + c.getId(), ex);
     }
@@ -1416,16 +1446,17 @@
     sendMergeFail(c, msg, true);
   }
 
-  private void sendMergeFail(Change c, ChangeMessage msg, final boolean makeNew) {
+  private void sendMergeFail(final Change c, final ChangeMessage msg,
+      final boolean makeNew) {
     try {
-      schema.changeMessages().insert(Collections.singleton(msg));
+      db.changeMessages().insert(Collections.singleton(msg));
     } catch (OrmException err) {
       log.warn("Cannot record merge failure message", err);
     }
 
     if (makeNew) {
       try {
-        schema.changes().atomicUpdate(c.getId(), new AtomicUpdate<Change>() {
+        db.changes().atomicUpdate(c.getId(), new AtomicUpdate<Change>() {
           @Override
           public Change update(Change c) {
             if (c.getStatus().isOpen()) {
@@ -1441,25 +1472,48 @@
       }
     } else {
       try {
-        ChangeUtil.touch(c, schema);
+        ChangeUtil.touch(c, db);
       } catch (OrmException err) {
         log.warn("Cannot update change timestamp", err);
       }
     }
 
-    try {
-      final MergeFailSender cm = mergeFailSenderFactory.create(c);
-      final PatchSetApproval submitter = getSubmitter(c.currentPatchSetId());
-      if (submitter != null) {
-        cm.setFrom(submitter.getAccountId());
+    workQueue.getDefaultQueue()
+        .submit(requestScopePropagator.wrap(new Runnable() {
+      @Override
+      public void run() {
+        PatchSet patchSet;
+        PatchSetApproval submitter;
+        try {
+          ReviewDb reviewDb = schemaFactory.open();
+          try {
+            patchSet = reviewDb.patchSets().get(c.currentPatchSetId());
+            submitter = getSubmitter(reviewDb, c.currentPatchSetId());
+          } finally {
+            reviewDb.close();
+          }
+        } catch (Exception e) {
+          log.error("Cannot send email notifications about merge failure", e);
+          return;
+        }
+
+        try {
+          final MergeFailSender cm = mergeFailSenderFactory.create(c);
+          if (submitter != null) {
+            cm.setFrom(submitter.getAccountId());
+          }
+          cm.setPatchSet(patchSet);
+          cm.setChangeMessage(msg);
+          cm.send();
+        } catch (Exception e) {
+          log.error("Cannot send email notifications about merge failure", e);
+        }
       }
-      cm.setPatchSet(schema.patchSets().get(c.currentPatchSetId()));
-      cm.setChangeMessage(msg);
-      cm.send();
-    } catch (OrmException e) {
-      log.error("Cannot send email notifications about merge failure", e);
-    } catch (EmailException e) {
-      log.error("Cannot send email notifications about merge failure", e);
-    }
+
+      @Override
+      public String toString() {
+        return "send-email merge-failed";
+      }
+    }));
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeQueue.java
index 39017eb..1071768 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeQueue.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Branch;
+import com.google.gerrit.reviewdb.client.Branch;
 
 import java.util.concurrent.TimeUnit;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
index 568c8cf9..fbe9d16 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MetaDataUpdate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiProgressMonitor.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiProgressMonitor.java
new file mode 100644
index 0000000..dbb849c
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MultiProgressMonitor.java
@@ -0,0 +1,325 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import org.eclipse.jgit.lib.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.List;
+
+/**
+ * Progress reporting interface that multiplexes multiple sub-tasks.
+ * <p>
+ * Output is of the format:
+ * <pre>
+ *   Task: subA: 1, subB: 75% (3/4) (-)\r
+ *   Task: subA: 2, subB: 75% (3/4), subC: 1 (\)\r
+ *   Task: subA: 2, subB: 100% (4/4), subC: 1 (|)\r
+ *   Task: subA: 4, subB: 100% (4/4), subC: 4, done    \n
+ * </pre>
+ * <p>
+ * Callers should try to keep task and sub-task descriptions short, since the
+ * output should fit on one terminal line. (Note that git clients do not accept
+ * terminal control characters, so true multi-line progress messages would be
+ * impossible.)
+ */
+public class MultiProgressMonitor {
+  private static final Logger log =
+      LoggerFactory.getLogger(MultiProgressMonitor.class);
+
+  /** Constant indicating the total work units cannot be predicted. */
+  public static final int UNKNOWN = 0;
+
+  private static final char[] SPINNER_STATES = new char[]{'-', '\\', '|', '/'};
+  private static final char NO_SPINNER = ' ';
+
+  /** Handle for a sub-task. */
+  public class Task {
+    private final String name;
+    private final int total;
+    private volatile int count;
+    private int lastPercent;
+
+    Task(final String subTaskName, final int totalWork) {
+      this.name = subTaskName;
+      this.total = totalWork;
+    }
+
+    /**
+     * Indicate that work has been completed on this sub-task.
+     * <p>
+     * Must be called from the worker thread.
+     *
+     * @param completed number of work units completed.
+     */
+    public void update(final int completed) {
+      count += completed;
+      if (total != UNKNOWN) {
+        int percent = count * 100 / total;
+        if (percent > lastPercent) {
+          lastPercent = percent;
+          wakeUp();
+        }
+      }
+    }
+
+    /**
+     * Indicate that this sub-task is finished.
+     * <p>
+     * Must be called from the worker thread.
+     */
+    public void end() {
+      if (total == UNKNOWN && count > 0) {
+        wakeUp();
+      }
+    }
+  }
+
+  private final OutputStream out;
+  private final String taskName;
+  private final List<Task> tasks = new CopyOnWriteArrayList<Task>();
+  private int spinnerIndex;
+  private char spinnerState = NO_SPINNER;
+  private boolean done;
+  private boolean write = true;
+
+  private final long maxIntervalNanos;
+
+  /**
+   * Create a new progress monitor for multiple sub-tasks.
+   *
+   * @param out stream for writing progress messages.
+   * @param taskName name of the overall task.
+   */
+  public MultiProgressMonitor(final OutputStream out, final String taskName) {
+    this(out, taskName, 500, TimeUnit.MILLISECONDS);
+  }
+
+  /**
+   * Create a new progress monitor for multiple sub-tasks.
+   *
+   * @param out stream for writing progress messages.
+   * @param taskName name of the overall task.
+   * @param maxIntervalTime maximum interval between progress messages.
+   * @param maxIntervalUnit time unit for progress interval.
+   */
+  public MultiProgressMonitor(final OutputStream out, final String taskName,
+      long maxIntervalTime, TimeUnit maxIntervalUnit) {
+    this.out = out;
+    this.taskName = taskName;
+    maxIntervalNanos = NANOSECONDS.convert(maxIntervalTime, maxIntervalUnit);
+  }
+
+  /**
+   * Wait for a task managed by a {@link Future}, with no timeout.
+   *
+   * @see #waitFor(Future, long, TimeUnit)
+   */
+  public void waitFor(final Future<?> workerFuture) throws ExecutionException {
+    waitFor(workerFuture, 0, null);
+  }
+
+  /**
+   * Wait for a task managed by a {@link Future}.
+   * <p>
+   * Must be called from the main thread, <em>not</em> the worker thread. Once
+   * the worker thread calls {@link #end()}, the future has an additional
+   * <code>maxInterval</code> to finish before it is forcefully cancelled and
+   * {@link ExecutionException} is thrown.
+   *
+   * @param workerFuture a future that returns when the worker thread is
+   *     finished.
+   * @param timeoutTime overall timeout for the task; the future is forcefully
+   *     cancelled if the task exceeds the timeout. Non-positive values indicate
+   *     no timeout.
+   * @param timeoutUnit unit for overall task timeout.
+   * @throws ExecutionException if this thread or the worker thread was
+   *     interrupted, the worker was cancelled, or the worker timed out.
+   */
+  public void waitFor(final Future<?> workerFuture, final long timeoutTime,
+      final TimeUnit timeoutUnit) throws ExecutionException {
+    long overallStart = System.nanoTime();
+    long deadline;
+    if (timeoutTime > 0) {
+      deadline = overallStart + NANOSECONDS.convert(timeoutTime, timeoutUnit);
+    } else {
+      deadline = 0;
+    }
+
+    synchronized (this) {
+      long left = maxIntervalNanos;
+      while (!done) {
+        long start = System.nanoTime();
+        try {
+          NANOSECONDS.timedWait(this, left);
+        } catch (InterruptedException e) {
+          throw new ExecutionException(e);
+        }
+
+        // Send an update on every wakeup (manual or spurious), but only move
+        // the spinner every maxInterval.
+        long now = System.nanoTime();
+
+        if (deadline > 0 && now > deadline) {
+          log.warn(String.format(
+              "MultiProgressMonitor worker killed after %sms",
+              TimeUnit.MILLISECONDS.convert(now - overallStart, NANOSECONDS)));
+          workerFuture.cancel(true);
+          break;
+        }
+
+        left -= now - start;
+        if (left <= 0) {
+          moveSpinner();
+          left = maxIntervalNanos;
+        }
+        sendUpdate();
+        if (!done && workerFuture.isDone()) {
+          // The worker may not have called end() explicitly, which is likely a
+          // programming error.
+          log.warn("MultiProgressMonitor worker did not call end()"
+              + " before returning");
+          end();
+        }
+      }
+      sendDone();
+    }
+
+    // The loop exits as soon as the worker calls end(), but we give it another
+    // maxInterval to finish up and return.
+    try {
+      workerFuture.get(maxIntervalNanos, NANOSECONDS);
+    } catch (InterruptedException e) {
+      throw new ExecutionException(e);
+    } catch (CancellationException e) {
+      throw new ExecutionException(e);
+    } catch (TimeoutException e) {
+      workerFuture.cancel(true);
+      throw new ExecutionException(e);
+    }
+  }
+
+  private synchronized void wakeUp() {
+    notifyAll();
+  }
+
+  /**
+   * Begin a sub-task.
+   *
+   * @param subTask sub-task name.
+   * @param subTaskWork total work units in sub-task, or {@link #UNKNOWN}.
+   * @return sub-task handle.
+   */
+  public Task beginSubTask(final String subTask, final int subTaskWork) {
+    Task task = new Task(subTask, subTaskWork);
+    tasks.add(task);
+    return task;
+  }
+
+  /**
+   * End the overall task.
+   * <p>
+   * Must be called from the worker thread.
+   */
+  public synchronized void end() {
+    done = true;
+    wakeUp();
+  }
+
+  private void sendDone() {
+    spinnerState = NO_SPINNER;
+    StringBuilder s = format();
+    boolean any = false;
+    for (Task t : tasks) {
+      if (t.count != 0) {
+        any = true;
+        break;
+      }
+    }
+    if (any) {
+      s.append(",");
+    }
+    s.append(" done    \n");
+    send(s);
+  }
+
+  private void moveSpinner() {
+    spinnerIndex = (spinnerIndex + 1) % SPINNER_STATES.length;
+    spinnerState = SPINNER_STATES[spinnerIndex];
+  }
+
+  private void sendUpdate() {
+    send(format());
+  }
+
+  private StringBuilder format() {
+    StringBuilder s = new StringBuilder().append("\r").append(taskName)
+        .append(':');
+
+    if (!tasks.isEmpty()) {
+      boolean first = true;
+      for (Task t : tasks) {
+        int count = t.count;
+        if (count == 0) {
+          continue;
+        }
+
+        if (!first) {
+          s.append(',');
+        } else {
+          first = false;
+        }
+
+        s.append(' ').append(t.name).append(": ");
+        if (t.total == UNKNOWN) {
+          s.append(count);
+        } else {
+          s.append(String.format("%d%% (%d/%d)",
+              count * 100 / t.total,
+              count, t.total));
+        }
+      }
+    }
+
+    if (spinnerState != NO_SPINNER) {
+      // Don't output a spinner until the alarm fires for the first time.
+      s.append(" (").append(spinnerState).append(')');
+    }
+    return s;
+  }
+
+  private void send(StringBuilder s) {
+    if (write) {
+      try {
+        out.write(Constants.encode(s.toString()));
+        out.flush();
+      } catch (IOException e) {
+        write = false;
+      }
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java
index ceb70d2..c5ee262 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/NoReplication.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 /** A disabled {@link ReplicationQueue}. */
 public final class NoReplication implements ReplicationQueue {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java
index 592f44f..057e80d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PerThreadRequestScope.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.git;
 
 import com.google.gerrit.server.RequestCleanup;
+import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator;
 import com.google.inject.Key;
 import com.google.inject.OutOfScopeException;
 import com.google.inject.Provider;
@@ -24,10 +25,23 @@
 import java.util.Map;
 
 class PerThreadRequestScope {
+  static class Propagator
+      extends ThreadLocalRequestScopePropagator<PerThreadRequestScope> {
+    Propagator() {
+      super(REQUEST, current);
+    }
+
+    @Override
+    protected PerThreadRequestScope continuingContext(
+        PerThreadRequestScope ctx) {
+      return new PerThreadRequestScope();
+    }
+  }
+
   private static final ThreadLocal<PerThreadRequestScope> current =
       new ThreadLocal<PerThreadRequestScope>();
 
-  private static PerThreadRequestScope getContext() {
+  private static PerThreadRequestScope requireContext() {
     final PerThreadRequestScope ctx = current.get();
     if (ctx == null) {
       throw new OutOfScopeException("Not in command/request");
@@ -45,7 +59,7 @@
     public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
       return new Provider<T>() {
         public T get() {
-          return getContext().get(key, creator);
+          return requireContext().get(key, creator);
         }
 
         @Override
@@ -82,4 +96,4 @@
     }
     return t;
   }
-}
\ No newline at end of file
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
index 7131012..d15095b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectConfig.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.server.git;
 
-import static com.google.gerrit.common.data.AccessSection.isAccessSection;
 import static com.google.gerrit.common.data.Permission.isPermission;
 
 import com.google.gerrit.common.data.AccessSection;
@@ -22,11 +21,12 @@
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.State;
-import com.google.gerrit.reviewdb.Project.SubmitType;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.State;
+import com.google.gerrit.reviewdb.client.Project.SubmitType;
 import com.google.gerrit.server.account.GroupCache;
+import com.google.gerrit.common.data.RefConfigSection;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.CommitBuilder;
@@ -225,7 +225,7 @@
 
     accessSections = new HashMap<String, AccessSection>();
     for (String refName : rc.getSubsections(ACCESS)) {
-      if (isAccessSection(refName)) {
+      if (RefConfigSection.isValid(refName)) {
         AccessSection as = getAccessSection(refName, true);
 
         for (String varName : rc.getStringList(ACCESS, refName, KEY_GROUP_PERMISSIONS)) {
@@ -421,7 +421,7 @@
     }
 
     for (String name : rc.getSubsections(ACCESS)) {
-      if (isAccessSection(name) && !accessSections.containsKey(name)) {
+      if (RefConfigSection.isValid(name) && !accessSections.containsKey(name)) {
         rc.unsetSection(ACCESS, name);
       }
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectRunnable.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectRunnable.java
index a94ba39..32f157d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectRunnable.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ProjectRunnable.java
@@ -13,7 +13,7 @@
 // limitations under the License.
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 /** Used to retrieve the project name from an operation **/
 public interface ProjectRunnable extends Runnable {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java
index b5f991c..845d037 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushAllProjectsOp.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java
index 5279ae4..0868749 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushOp.java
@@ -14,13 +14,13 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.NameKey;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -343,10 +343,6 @@
 
       if (config.isMirror()) {
         for (final Ref ref : remote.values()) {
-          if (noPerms && GitRepositoryManager.REF_CONFIG.equals(ref.getName())) {
-            continue;
-          }
-
           if (!Constants.HEAD.equals(ref.getName())) {
             final RefSpec spec = matchDst(ref.getName());
             if (spec != null && !local.containsKey(spec.getSource())) {
@@ -360,16 +356,13 @@
 
     } else {
       for (final String src : delta) {
-        if (noPerms && GitRepositoryManager.REF_CONFIG.equals(src)) {
-          continue;
-        }
-
         final RefSpec spec = matchSrc(src);
         if (spec != null) {
           // If the ref still exists locally, send it, otherwise delete it.
           //
           Ref srcRef = local.get(src);
-          if (srcRef != null) {
+          if (srcRef != null &&
+              !(noPerms && GitRepositoryManager.REF_CONFIG.equals(src))) {
             send(cmds, spec, srcRef);
           } else if (config.isMirror()) {
             delete(cmds, spec);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
index 154c609..5cf5f7a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
@@ -14,22 +14,23 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.ReplicationUser;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.ListGroupMembership;
 import com.google.gerrit.server.config.ConfigUtil;
+import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.PerRequestProjectControlCache;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Singleton;
-import com.google.inject.assistedinject.FactoryProvider;
 import com.google.inject.servlet.RequestScoped;
 
 import com.jcraft.jsch.Session;
@@ -66,7 +67,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /** Manages automatic replication to remote repositories. */
@@ -353,7 +353,7 @@
       }
 
       @Override
-      public synchronized void write(final int b) throws IOException {
+      public synchronized void write(final int b) {
         if (b == '\r') {
           return;
         }
@@ -404,10 +404,10 @@
 
       String[] authGroupNames =
           cfg.getStringList("remote", rc.getName(), "authGroup");
-      final Set<AccountGroup.UUID> authGroups;
+      final GroupMembership authGroups;
       if (authGroupNames.length > 0) {
-        authGroups = ConfigUtil.groupsFor(db, authGroupNames, //
-            log, "Group \"{0}\" not in database, removing from authGroup");
+        authGroups = new ListGroupMembership(ConfigUtil.groupsFor(db, authGroupNames, //
+            log, "Group \"{0}\" not in database, removing from authGroup"));
       } else {
         authGroups = ReplicationUser.EVERYTHING_VISIBLE;
       }
@@ -430,14 +430,12 @@
             }
           }).getInstance(ProjectControl.Factory.class);
 
-      opFactory = injector.createChildInjector(new AbstractModule() {
+      opFactory = injector.createChildInjector(new FactoryModule() {
         @Override
         protected void configure() {
-          bind(PushReplication.ReplicationConfig.class).toInstance(
-              ReplicationConfig.this);
+          bind(PushReplication.ReplicationConfig.class).toInstance(ReplicationConfig.this);
           bind(RemoteConfig.class).toInstance(remote);
-          bind(PushOp.Factory.class).toProvider(
-              FactoryProvider.newFactory(PushOp.Factory.class, PushOp.class));
+          factory(PushOp.Factory.class);
         }
       }).getInstance(PushOp.Factory.class);
     }
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 8450dc5..37fbdb2 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
@@ -14,6 +14,13 @@
 
 package com.google.gerrit.server.git;
 
+import static com.google.gerrit.server.git.MultiProgressMonitor.UNKNOWN;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_MISSING_OBJECT;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD;
+import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
+
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.data.ApprovalType;
@@ -21,18 +28,18 @@
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.common.data.PermissionRule;
 import com.google.gerrit.common.errors.NoSuchAccountException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetAncestor;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+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.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+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.ApprovalsUtil;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.GerritPersonIdent;
@@ -40,8 +47,8 @@
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.TrackingFooters;
+import com.google.gerrit.server.git.MultiProgressMonitor.Task;
 import com.google.gerrit.server.mail.CreateChangeSender;
-import com.google.gerrit.server.mail.EmailException;
 import com.google.gerrit.server.mail.MergedSender;
 import com.google.gerrit.server.mail.ReplacePatchSetSender;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
@@ -51,8 +58,9 @@
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.project.RefControl;
 import com.google.gerrit.server.util.MagicBranch;
-import com.google.gwtorm.client.AtomicUpdate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.server.util.RequestScopePropagator;
+import com.google.gwtorm.server.AtomicUpdate;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -74,10 +82,9 @@
 import org.eclipse.jgit.revwalk.RevSort;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
-import org.eclipse.jgit.transport.PostReceiveHook;
-import org.eclipse.jgit.transport.PreReceiveHook;
+import org.eclipse.jgit.transport.AdvertiseRefsHook;
+import org.eclipse.jgit.transport.AdvertiseRefsHookChain;
 import org.eclipse.jgit.transport.ReceiveCommand;
-import org.eclipse.jgit.transport.ReceiveCommand.Result;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -98,7 +105,7 @@
 import javax.annotation.Nullable;
 
 /** Receives change upload using the Git receive-pack protocol. */
-public class ReceiveCommits implements PreReceiveHook, PostReceiveHook {
+public class ReceiveCommits {
   private static final Logger log =
       LoggerFactory.getLogger(ReceiveCommits.class);
 
@@ -109,10 +116,63 @@
   private static final FooterKey TESTED_BY = new FooterKey("Tested-by");
   private static final FooterKey CHANGE_ID = new FooterKey("Change-Id");
 
-  public interface Factory {
+  interface Factory {
     ReceiveCommits create(ProjectControl projectControl, Repository repository);
   }
 
+  public interface MessageSender {
+    void sendMessage(String what);
+    void sendError(String what);
+    void sendBytes(byte[] what);
+    void sendBytes(byte[] what, int off, int len);
+    void flush();
+  }
+
+  private class ReceivePackMessageSender implements MessageSender {
+    @Override
+    public void sendMessage(String what) {
+      rp.sendMessage(what);
+    }
+
+    @Override
+    public void sendError(String what) {
+      rp.sendError(what);
+    }
+
+    @Override
+    public void sendBytes(byte[] what) {
+      sendBytes(what, 0, what.length);
+    }
+
+    @Override
+    public void sendBytes(byte[] what, int off, int len) {
+      try {
+        rp.getMessageOutputStream().write(what, off, len);
+      } catch (IOException e) {
+        // Ignore write failures (matching JGit behavior).
+      }
+    }
+
+    @Override
+    public void flush() {
+      try {
+        rp.getMessageOutputStream().flush();
+      } catch (IOException e) {
+        // Ignore write failures (matching JGit behavior).
+      }
+    }
+  }
+
+  private static class Message {
+    private final String message;
+    private final boolean isError;
+
+    private Message(final String message, final boolean isError) {
+      this.message = message;
+      this.isError = isError;
+    }
+  }
+
   private final Set<Account.Id> reviewerId = new HashSet<Account.Id>();
   private final Set<Account.Id> ccId = new HashSet<Account.Id>();
 
@@ -132,13 +192,14 @@
   private final PersonIdent gerritIdent;
   private final TrackingFooters trackingFooters;
   private final TagCache tagCache;
+  private final WorkQueue workQueue;
+  private final RequestScopePropagator requestScopePropagator;
 
   private final ProjectControl projectControl;
   private final Project project;
   private final Repository repo;
   private final ReceivePack rp;
   private final NoteMap rejectCommits;
-
   private ReceiveCommand newChange;
   private Branch.NameKey destBranch;
   private RefControl destBranchCtl;
@@ -156,6 +217,13 @@
 
   private final SubmoduleOp.Factory subOpFactory;
 
+  private final List<Message> messages = new ArrayList<Message>();
+  private Task newProgress;
+  private Task replaceProgress;
+  private Task closeProgress;
+  private Task commandProgress;
+  private MessageSender messageSender;
+
   @Inject
   ReceiveCommits(final ReviewDb db, final ApprovalTypes approvalTypes,
       final AccountResolver accountResolver,
@@ -171,6 +239,8 @@
       @CanonicalWebUrl @Nullable final String canonicalWebUrl,
       @GerritPersonIdent final PersonIdent gerritIdent,
       final TrackingFooters trackingFooters,
+      final WorkQueue workQueue,
+      final RequestScopePropagator requestScopePropagator,
 
       @Assisted final ProjectControl projectControl,
       @Assisted final Repository repo,
@@ -191,6 +261,8 @@
     this.gerritIdent = gerritIdent;
     this.trackingFooters = trackingFooters;
     this.tagCache = tagCache;
+    this.workQueue = workQueue;
+    this.requestScopePropagator = requestScopePropagator;
 
     this.projectControl = projectControl;
     this.project = projectControl.getProject();
@@ -200,6 +272,8 @@
 
     this.subOpFactory = subOpFactory;
 
+    this.messageSender = new ReceivePackMessageSender();
+
     rp.setAllowCreates(true);
     rp.setAllowDeletes(true);
     rp.setAllowNonFastForwards(true);
@@ -207,12 +281,12 @@
 
     if (!projectControl.allRefsAreVisible()) {
       rp.setCheckReferencedObjectsAreReachable(true);
-      rp.setRefFilter(new VisibleRefFilter(tagCache, repo, projectControl, db, false));
+      rp.setAdvertiseRefsHook(new VisibleRefFilter(tagCache, repo, projectControl, db, false));
     }
-    rp.setRefFilter(new ReceiveCommitsRefFilter(rp.getRefFilter()));
-
-    rp.setPreReceiveHook(this);
-    rp.setPostReceiveHook(this);
+    List<AdvertiseRefsHook> advHooks = new ArrayList<AdvertiseRefsHook>(2);
+    advHooks.add(rp.getAdvertiseRefsHook());
+    advHooks.add(new ReceiveCommitsAdvertiseRefsHook());
+    rp.setAdvertiseRefsHook(AdvertiseRefsHookChain.newChain(advHooks));
   }
 
   /** Add reviewers for new (or updated) changes. */
@@ -225,6 +299,22 @@
     ccId.addAll(who);
   }
 
+  /** Set a message sender for this operation. */
+  public void setMessageSender(final MessageSender ms) {
+    messageSender = ms != null ? ms : new ReceivePackMessageSender();
+  }
+
+  MessageSender getMessageSender() {
+    if (messageSender == null) {
+      setMessageSender(null);
+    }
+    return messageSender;
+  }
+
+  Project getProject() {
+    return project;
+  }
+
   /** @return the ReceivePack instance to speak the native Git protocol. */
   public ReceivePack getReceivePack() {
     return rp;
@@ -314,22 +404,42 @@
     return MagicBranch.checkMagicBranchRefs(repo, project);
   }
 
-  @Override
-  public void onPreReceive(final ReceivePack arg0,
-      final Collection<ReceiveCommand> commands) {
-    parseCommands(commands);
-    if (newChange != null
-        && newChange.getResult() == ReceiveCommand.Result.NOT_ATTEMPTED) {
-      createNewChanges();
-    }
-    doReplaces();
+  private void addMessage(String message) {
+    messages.add(new Message(message, false));
   }
 
-  @Override
-  public void onPostReceive(final ReceivePack arg0,
-      final Collection<ReceiveCommand> commands) {
+  void addError(String error) {
+    messages.add(new Message(error, true));
+  }
+
+  void sendMessages() {
+    for (Message m : messages) {
+      if (m.isError) {
+        messageSender.sendError(m.message);
+      } else {
+        messageSender.sendMessage(m.message);
+      }
+    }
+  }
+
+  void processCommands(final Collection<ReceiveCommand> commands,
+      final MultiProgressMonitor progress) {
+    newProgress = progress.beginSubTask("new", UNKNOWN);
+    replaceProgress = progress.beginSubTask("updated", UNKNOWN);
+    closeProgress = progress.beginSubTask("closed", UNKNOWN);
+    commandProgress = progress.beginSubTask("refs", UNKNOWN);
+
+    parseCommands(commands);
+    if (newChange != null && newChange.getResult() == NOT_ATTEMPTED) {
+      createNewChanges();
+    }
+    newProgress.end();
+
+    doReplaces();
+    replaceProgress.end();
+
     for (final ReceiveCommand c : commands) {
-      if (c.getResult() == Result.OK) {
+      if (c.getResult() == OK) {
         switch (c.getType()) {
           case CREATE:
             if (isHead(c)) {
@@ -368,23 +478,27 @@
           replication.scheduleUpdate(project.getNameKey(), c.getRefName());
           Branch.NameKey destBranch = new Branch.NameKey(project.getNameKey(), c.getRefName());
           hooks.doRefUpdatedHook(destBranch, c.getOldId(), c.getNewId(), currentUser.getAccount());
+          commandProgress.update(1);
         }
       }
     }
+    closeProgress.end();
+    commandProgress.end();
+    progress.end();
 
     if (!allNewChanges.isEmpty() && canonicalWebUrl != null) {
       final String url = canonicalWebUrl;
-      rp.sendMessage("");
-      rp.sendMessage("New Changes:");
+      addMessage("");
+      addMessage("New Changes:");
       for (final Change c : allNewChanges) {
         if (c.getStatus() == Change.Status.DRAFT) {
-          rp.sendMessage("  " + url + c.getChangeId() + " [DRAFT]");
+          addMessage("  " + url + c.getChangeId() + " [DRAFT]");
         }
         else {
-          rp.sendMessage("  " + url + c.getChangeId());
+          addMessage("  " + url + c.getChangeId());
         }
       }
-      rp.sendMessage("");
+      addMessage("");
     }
   }
 
@@ -400,7 +514,7 @@
 
   private void parseCommands(final Collection<ReceiveCommand> commands) {
     for (final ReceiveCommand cmd : commands) {
-      if (cmd.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED) {
+      if (cmd.getResult() != NOT_ATTEMPTED) {
         // Already rejected by the core receive process.
         //
         continue;
@@ -448,7 +562,7 @@
           continue;
       }
 
-      if (cmd.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED){
+      if (cmd.getResult() != NOT_ATTEMPTED) {
         continue;
       }
 
@@ -466,9 +580,9 @@
               ProjectConfig cfg = new ProjectConfig(project.getNameKey());
               cfg.load(repo, cmd.getNewId());
               if (!cfg.getValidationErrors().isEmpty()) {
-                rp.sendError("Invalid project configuration:");
+                addError("Invalid project configuration:");
                 for (ValidationError err : cfg.getValidationErrors()) {
-                  rp.sendError("  " + err.getMessage());
+                  addError("  " + err.getMessage());
                 }
                 reject(cmd, "invalid project configuration");
                 log.error("User " + currentUser.getUserName()
@@ -514,8 +628,9 @@
     RefControl ctl = projectControl.controlForRef(cmd.getRefName());
     if (ctl.canCreate(rp.getRevWalk(), obj)) {
       validateNewCommits(ctl, cmd);
-
-      // Let the core receive process handle it
+      if (cmd.getResult() == NOT_ATTEMPTED) {
+        cmd.execute(rp);
+      }
     } else {
       reject(cmd, "can not create new references");
     }
@@ -529,7 +644,9 @@
       }
 
       validateNewCommits(ctl, cmd);
-      // Let the core receive process handle it
+      if (cmd.getResult() == NOT_ATTEMPTED) {
+        cmd.execute(rp);
+      }
     } else {
       reject(cmd, "can not update the reference as a fast forward");
     }
@@ -557,7 +674,9 @@
   private void parseDelete(final ReceiveCommand cmd) {
     RefControl ctl = projectControl.controlForRef(cmd.getRefName());
     if (ctl.canDelete()) {
-      // Let the core receive process handle it
+      if (cmd.getResult() == NOT_ATTEMPTED) {
+        cmd.execute(rp);
+      }
     } else {
       reject(cmd, "can not delete references");
     }
@@ -579,15 +698,17 @@
     RefControl ctl = projectControl.controlForRef(cmd.getRefName());
     if (newObject != null) {
       validateNewCommits(ctl, cmd);
-      if (cmd.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED) {
+      if (cmd.getResult() != NOT_ATTEMPTED) {
         return;
       }
     }
 
     if (ctl.canForceUpdate()) {
-      // Let the core receive process handle it
+      if (cmd.getResult() == NOT_ATTEMPTED) {
+        cmd.execute(rp);
+      }
     } else {
-      cmd.setResult(ReceiveCommand.Result.REJECTED_NONFASTFORWARD, " need '"
+      cmd.setResult(REJECTED_NONFASTFORWARD, " need '"
           + PermissionRule.FORCE_PUSH + "' privilege.");
     }
   }
@@ -693,7 +814,7 @@
         walk.setRevFilter(oldRevFilter);
       }
     } catch (IOException e) {
-      newChange.setResult(Result.REJECTED_MISSING_OBJECT);
+      newChange.setResult(REJECTED_MISSING_OBJECT);
       log.error("Invalid pack upload; one or more objects weren't sent", e);
       return;
     }
@@ -868,7 +989,7 @@
       // Should never happen, the core receive process would have
       // identified the missing object earlier before we got control.
       //
-      newChange.setResult(Result.REJECTED_MISSING_OBJECT);
+      newChange.setResult(REJECTED_MISSING_OBJECT);
       log.error("Invalid pack upload; one or more objects weren't sent", e);
       return;
     } catch (OrmException e) {
@@ -894,8 +1015,9 @@
         reject(newChange, "database error");
         return;
       }
+      newProgress.update(1);
     }
-    newChange.setResult(ReceiveCommand.Result.OK);
+    newChange.setResult(OK);
   }
 
   private static boolean isValidChangeId(String idStr) {
@@ -998,17 +1120,28 @@
 
     allNewChanges.add(change);
 
-    try {
-      final CreateChangeSender cm;
-      cm = createChangeSenderFactory.create(change);
-      cm.setFrom(me);
-      cm.setPatchSet(ps, info);
-      cm.addReviewers(reviewers);
-      cm.addExtraCC(cc);
-      cm.send();
-    } catch (EmailException e) {
-      log.error("Cannot send email for new change " + change.getId(), e);
-    }
+    workQueue.getDefaultQueue()
+        .submit(requestScopePropagator.wrap(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          final CreateChangeSender cm;
+          cm = createChangeSenderFactory.create(change);
+          cm.setFrom(me);
+          cm.setPatchSet(ps, info);
+          cm.addReviewers(reviewers);
+          cm.addExtraCC(cc);
+          cm.send();
+        } catch (Exception e) {
+          log.error("Cannot send email for new change " + change.getId(), e);
+        }
+      }
+
+      @Override
+      public String toString() {
+        return "send-email newchange";
+      }
+    }));
 
     hooks.doPatchsetCreatedHook(change, ps, db);
   }
@@ -1023,7 +1156,8 @@
   private void doReplaces() {
     for (final ReplaceRequest request : replaceByChange.values()) {
       try {
-        doReplace(request);
+        doReplace(request, false);
+        replaceProgress.update(1);
       } catch (IOException err) {
         log.error("Error computing replacement patch for change "
             + request.ontoChange + ", commit " + request.newCommit.name(), err);
@@ -1033,7 +1167,7 @@
             + request.ontoChange + ", commit " + request.newCommit.name(), err);
         reject(request.cmd, "database error");
       }
-      if (request.cmd.getResult() == ReceiveCommand.Result.NOT_ATTEMPTED) {
+      if (request.cmd.getResult() == NOT_ATTEMPTED) {
         log.error("Replacement patch for change " + request.ontoChange
             + ", commit " + request.newCommit.name() + " wasn't attempted."
             + "  This is a bug in the receive process implementation.");
@@ -1042,7 +1176,7 @@
     }
   }
 
-  private PatchSet.Id doReplace(final ReplaceRequest request)
+  private PatchSet.Id doReplace(final ReplaceRequest request, boolean ignoreNoChanges)
       throws IOException, OrmException {
     final RevCommit c = request.newCommit;
     rp.getRevWalk().parseBody(c);
@@ -1138,7 +1272,7 @@
           final boolean parentsEq = parentsEqual(c, prior);
           final boolean authorEq = authorEqual(c, prior);
 
-          if (messageEq && parentsEq && authorEq) {
+          if (messageEq && parentsEq && authorEq && !ignoreNoChanges) {
             reject(request.cmd, "no changes made");
             return null;
           } else {
@@ -1157,7 +1291,7 @@
             if (!parentsEq) {
               msg.append(", was rebased");
             }
-            rp.sendMessage(msg.toString());
+            addMessage(msg.toString());
           }
         }
       } catch (IOException e) {
@@ -1332,22 +1466,33 @@
     }
     replication.scheduleUpdate(project.getNameKey(), ru.getName());
     hooks.doPatchsetCreatedHook(result.change, ps, db);
-    request.cmd.setResult(ReceiveCommand.Result.OK);
+    request.cmd.setResult(OK);
 
-    try {
-      final ReplacePatchSetSender cm;
-      cm = replacePatchSetFactory.create(result.change);
-      cm.setFrom(me);
-      cm.setPatchSet(ps, result.info);
-      cm.setChangeMessage(result.msg);
-      cm.addReviewers(reviewers);
-      cm.addExtraCC(cc);
-      cm.addReviewers(oldReviewers);
-      cm.addExtraCC(oldCC);
-      cm.send();
-    } catch (EmailException e) {
-      log.error("Cannot send email for new patch set " + ps.getId(), e);
-    }
+    workQueue.getDefaultQueue()
+        .submit(requestScopePropagator.wrap(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          final ReplacePatchSetSender cm;
+          cm = replacePatchSetFactory.create(result.change);
+          cm.setFrom(me);
+          cm.setPatchSet(ps, result.info);
+          cm.setChangeMessage(result.msg);
+          cm.addReviewers(reviewers);
+          cm.addExtraCC(cc);
+          cm.addReviewers(oldReviewers);
+          cm.addExtraCC(oldCC);
+          cm.send();
+        } catch (Exception e) {
+          log.error("Cannot send email for new patch set " + ps.getId(), e);
+        }
+      }
+
+      @Override
+      public String toString() {
+        return "send-email newpatchset";
+      }
+    }));
 
     sendMergedEmail(result);
     return result != null ? result.info.getKey() : null;
@@ -1477,7 +1622,7 @@
         }
       }
     } catch (IOException err) {
-      cmd.setResult(Result.REJECTED_MISSING_OBJECT);
+      cmd.setResult(REJECTED_MISSING_OBJECT);
       log.error("Invalid pack upload; one or more objects weren't sent", err);
     }
   }
@@ -1562,7 +1707,7 @@
         if (project.isRequireChangeID()) {
           String errMsg = "missing Change-Id in commit message";
           reject(cmd, errMsg);
-          rp.sendMessage(getFixedCommitMsgWithChangeId(errMsg, c));
+          addMessage(getFixedCommitMsgWithChangeId(errMsg, c));
           return false;
         }
       } else if (idList.size() > 1) {
@@ -1574,7 +1719,7 @@
           final String errMsg =
               "missing or invalid Change-Id line format in commit message";
           reject(cmd, errMsg);
-          rp.sendMessage(getFixedCommitMsgWithChangeId(errMsg, c));
+          addMessage(getFixedCommitMsgWithChangeId(errMsg, c));
           return false;
         }
       }
@@ -1592,9 +1737,9 @@
         ProjectConfig cfg = new ProjectConfig(project.getNameKey());
         cfg.load(repo, cmd.getNewId());
         if (!cfg.getValidationErrors().isEmpty()) {
-          rp.sendError("Invalid project configuration:");
+          addError("Invalid project configuration:");
           for (ValidationError err : cfg.getValidationErrors()) {
-            rp.sendError("  " + err.getMessage());
+            addError("  " + err.getMessage());
           }
           reject(cmd, "invalid project configuration");
           log.error("User " + currentUser.getUserName()
@@ -1673,7 +1818,7 @@
       sb.append("ERROR:  " + canonicalWebUrl + "#" + PageLinks.SETTINGS_CONTACT + "\n");
     }
     sb.append("\n");
-    getReceivePack().sendMessage(sb.toString());
+    addMessage(sb.toString());
   }
 
   private void warnMalformedMessage(RevCommit c) {
@@ -1685,7 +1830,7 @@
       } catch (IOException err) {
         id = c.abbreviate(6);
       }
-      rp.sendMessage("(W) " + id.name() //
+      addMessage("(W) " + id.name() //
           + ": commit subject >65 characters; use shorter first paragraph");
     }
 
@@ -1706,7 +1851,7 @@
       } catch (IOException err) {
         id = c.abbreviate(6);
       }
-      rp.sendMessage("(W) " + id.name() //
+      addMessage("(W) " + id.name() //
           + ": commit message lines >70 characters; manually wrap lines");
     }
   }
@@ -1730,7 +1875,7 @@
         if (ref != null) {
           rw.parseBody(c);
           closeChange(cmd, PatchSet.Id.fromRef(ref.getName()), c);
-          continue;
+          closeProgress.update(1);
         }
 
         rw.parseBody(c);
@@ -1744,9 +1889,10 @@
       }
 
       for (final ReplaceRequest req : toClose) {
-        final PatchSet.Id psi = doReplace(req);
+        final PatchSet.Id psi = doReplace(req, true);
         if (psi != null) {
           closeChange(req.cmd, psi, req.newCommit);
+          closeProgress.update(1);
         }
       }
 
@@ -1867,15 +2013,26 @@
 
   private void sendMergedEmail(final ReplaceResult result) {
     if (result != null && result.mergedIntoRef != null) {
-      try {
-        final MergedSender cm = mergedSenderFactory.create(result.change);
-        cm.setFrom(currentUser.getAccountId());
-        cm.setPatchSet(result.patchSet, result.info);
-        cm.send();
-      } catch (EmailException e) {
-        final PatchSet.Id psi = result.patchSet.getId();
-        log.error("Cannot send email for submitted patch set " + psi, e);
-      }
+      workQueue.getDefaultQueue()
+          .submit(requestScopePropagator.wrap(new Runnable() {
+        @Override
+        public void run() {
+          try {
+            final MergedSender cm = mergedSenderFactory.create(result.change);
+            cm.setFrom(currentUser.getAccountId());
+            cm.setPatchSet(result.patchSet, result.info);
+            cm.send();
+          } catch (Exception e) {
+            final PatchSet.Id psi = result.patchSet.getId();
+            log.error("Cannot send email for submitted patch set " + psi, e);
+          }
+        }
+
+        @Override
+        public String toString() {
+          return "send-email merged";
+        }
+      }));
 
       try {
         hooks.doChangeMergedHook(result.change, currentUser.getAccount(),
@@ -1904,12 +2061,13 @@
     return new RevId(src.getId().name());
   }
 
-  private static void reject(final ReceiveCommand cmd) {
+  private void reject(final ReceiveCommand cmd) {
     reject(cmd, "prohibited by Gerrit");
   }
 
-  private static void reject(final ReceiveCommand cmd, final String why) {
-    cmd.setResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, why);
+  private void reject(final ReceiveCommand cmd, final String why) {
+    cmd.setResult(REJECTED_OTHER_REASON, why);
+    commandProgress.update(1);
   }
 
   private static boolean isHead(final Ref ref) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
new file mode 100644
index 0000000..e87fe2b
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsAdvertiseRefsHook.java
@@ -0,0 +1,47 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.transport.AdvertiseRefsHook;
+import org.eclipse.jgit.transport.ReceivePack;
+import org.eclipse.jgit.transport.UploadPack;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** Exposes only the non refs/changes/ reference names. */
+public class ReceiveCommitsAdvertiseRefsHook implements AdvertiseRefsHook {
+  @Override
+  public void advertiseRefs(UploadPack us) {
+    throw new UnsupportedOperationException(
+        "ReceiveCommitsAdvertiseRefsHook cannot be used for UploadPack");
+  }
+
+  @Override
+  public void advertiseRefs(ReceivePack rp) {
+    Map<String, Ref> oldRefs = rp.getAdvertisedRefs();
+    if (oldRefs == null) {
+      oldRefs = rp.getRepository().getAllRefs();
+    }
+    HashMap<String, Ref> r = new HashMap<String, Ref>();
+    for (Map.Entry<String, Ref> e : oldRefs.entrySet()) {
+      if (!e.getKey().startsWith("refs/changes/")) {
+        r.put(e.getKey(), e.getValue());
+      }
+    }
+    rp.setAdvertisedRefs(r, rp.getAdvertisedObjects());
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutor.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutor.java
new file mode 100644
index 0000000..2049cea
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutor.java
@@ -0,0 +1,30 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.BindingAnnotation;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Marker on the global {@link WorkQueue.Executor} used by
+ * {@link ReceiveCommits}.
+ */
+@Retention(RUNTIME)
+@BindingAnnotation
+public @interface ReceiveCommitsExecutor {
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
new file mode 100644
index 0000000..063db2d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsExecutorModule.java
@@ -0,0 +1,41 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.git;
+
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.git.WorkQueue.Executor;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+
+import org.eclipse.jgit.lib.Config;
+
+/** Module providing the {@link ReceiveCommitsExecutor}. */
+public class ReceiveCommitsExecutorModule extends AbstractModule {
+  @Override
+  protected void configure() {
+  }
+
+  @Provides
+  @Singleton
+  @ReceiveCommitsExecutor
+  public Executor getReceiveCommitsExecutor(@GerritServerConfig Config config,
+      WorkQueue queues) {
+    int poolSize = config.getInt("receive", null, "threadPoolSize",
+        Runtime.getRuntime().availableProcessors());
+    return queues.createQueue(poolSize, "ReceiveCommits");
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsRefFilter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsRefFilter.java
deleted file mode 100644
index 730305c..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReceiveCommitsRefFilter.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2010 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.git;
-
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.transport.RefFilter;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/** Exposes only the non refs/changes/ reference names. */
-class ReceiveCommitsRefFilter implements RefFilter {
-  private final RefFilter base;
-
-  public ReceiveCommitsRefFilter(RefFilter base) {
-    this.base = base != null ? base : RefFilter.DEFAULT;
-  }
-
-  @Override
-  public Map<String, Ref> filter(Map<String, Ref> refs) {
-    HashMap<String, Ref> r = new HashMap<String, Ref>();
-    for (Map.Entry<String, Ref> e : refs.entrySet()) {
-      if (!e.getKey().startsWith("refs/changes/")) {
-        r.put(e.getKey(), e.getValue());
-      }
-    }
-    return base.filter(r);
-  }
-}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java
index 356981d..bcc2107 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReloadSubmitQueueOp.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 
 import org.slf4j.Logger;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java
index cedcb0b..f5e8fa8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/RenameGroupOp.java
@@ -15,9 +15,9 @@
 package com.google.gerrit.server.git;
 
 import com.google.gerrit.common.data.GroupReference;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.NameKey;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplicationQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplicationQueue.java
index d1c518d..f7bb9f8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplicationQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReplicationQueue.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 /** Manages replication to other nodes. */
 public interface ReplicationQueue {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java
index 3c8a1a5..64ba6e8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.NameKey;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
 
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 
@@ -31,21 +31,11 @@
 
   private static final long serialVersionUID = 1L;
 
-  private final NameKey nameOfExistingProject;
-
   /**
    * @param projectName name of the project that cannot be created
-   * @param nameOfExistingProject name of the project that already exists and
-   *        occupies the name for the git repository in the file system
    */
-  public RepositoryCaseMismatchException(final Project.NameKey projectName,
-      final Project.NameKey nameOfExistingProject) {
-    super("Name occupied in other case: " + projectName.get() + "; project "
-        + nameOfExistingProject.get() + " exists");
-    this.nameOfExistingProject = nameOfExistingProject;
-  }
-
-  public NameKey getNameOfExistingProject() {
-    return nameOfExistingProject;
+  public RepositoryCaseMismatchException(final Project.NameKey projectName) {
+    super("Name occupied in other case. Project " + projectName.get()
+        + " cannot be created.");
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReviewNoteHeaderFormatter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReviewNoteHeaderFormatter.java
index 39ae9b3..7b669b2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/ReviewNoteHeaderFormatter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/ReviewNoteHeaderFormatter.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
index a7a43b1..706ba7d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/SubmoduleOp.java
@@ -14,16 +14,16 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SubmoduleSubscription;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.util.SubmoduleSectionParser;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
@@ -31,8 +31,8 @@
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheEditor;
-import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
+import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagCache.java
index 053fda8..ac4882f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java
index cfa5420..8830580 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java
@@ -17,8 +17,8 @@
 import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
 
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.lib.AnyObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSetHolder.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSetHolder.java
index c6667c5..91c8a5c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSetHolder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSetHolder.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
index 655daa3..c34cc54 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VersionedMetaData.java
@@ -17,9 +17,9 @@
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheEditor;
-import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath;
 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
+import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
index feadaf1..fc47f10 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/VisibleRefFilter.java
@@ -14,17 +14,18 @@
 
 package com.google.gerrit.server.git;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.RefFilter;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.AbstractAdvertiseRefsHook;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,7 +37,7 @@
 import java.util.Map;
 import java.util.Set;
 
-public class VisibleRefFilter implements RefFilter {
+public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
   private static final Logger log =
       LoggerFactory.getLogger(VisibleRefFilter.class);
 
@@ -58,11 +59,6 @@
     this.showChanges = showChanges;
   }
 
-  @Override
-  public Map<String, Ref> filter(Map<String, Ref> refs) {
-    return filter(refs, false);
-  }
-
   public Map<String, Ref> filter(Map<String, Ref> refs, boolean filterTagsSeperately) {
     final Set<Change.Id> visibleChanges = visibleChanges();
     final Map<String, Ref> result = new HashMap<String, Ref>();
@@ -108,6 +104,16 @@
     return result;
   }
 
+  @Override
+  protected Map<String, Ref> getAdvertisedRefs(
+      Repository repository, RevWalk revWalk) {
+    return filter(repository.getAllRefs());
+  }
+
+  private Map<String, Ref> filter(Map<String, Ref> refs) {
+    return filter(refs, false);
+  }
+
   private Set<Change.Id> visibleChanges() {
     if (!showChanges) {
       return Collections.emptySet();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
index 87e6880..987ab7c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/WorkQueue.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.lifecycle.LifecycleListener;
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.reviewdb.Project.NameKey;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
 import com.google.gerrit.server.util.IdGenerator;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ioutil/BasicSerialization.java b/gerrit-server/src/main/java/com/google/gerrit/server/ioutil/BasicSerialization.java
index 2971906..4210363 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ioutil/BasicSerialization.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ioutil/BasicSerialization.java
@@ -29,7 +29,7 @@
 
 package com.google.gerrit.server.ioutil;
 
-import com.google.gerrit.reviewdb.CodedEnum;
+import com.google.gerrit.reviewdb.client.CodedEnum;
 
 import org.eclipse.jgit.util.IO;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
index ac62bd0..7fabcfe1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AbandonedSender.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
index 02f8fb7..f7ace27 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/AddReviewerSender.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.ssh.SshInfo;
 import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
index 822bd51..ff0bb578 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ChangeEmail.java
@@ -14,17 +14,17 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.StarredChange;
-import com.google.gerrit.reviewdb.AccountProjectWatch.NotifyType;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.StarredChange;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListEntry;
@@ -34,7 +34,7 @@
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
@@ -70,14 +70,7 @@
 
     /** Is the from user in an email squelching group? */
     final IdentifiedUser user =  args.identifiedUserFactory.create(id);
-    final Set<AccountGroup.UUID> gids = user.getEffectiveGroups();
-    for (final AccountGroup.UUID gid : gids) {
-      AccountGroup group = args.groupCache.get(gid);
-      if (group != null && group.isEmailOnlyAuthors()) {
-        emailOnlyAuthors = true;
-        break;
-      }
-    }
+    emailOnlyAuthors = !user.getCapabilities().canEmailReviewers();
   }
 
   public void setPatchSet(final PatchSet ps) {
@@ -296,7 +289,7 @@
       //
       for (StarredChange w : args.db.get().starredChanges().byChange(
           change.getId())) {
-        add(RecipientType.BCC, w.getAccountId());
+        super.add(RecipientType.BCC, w.getAccountId());
       }
     } catch (OrmException err) {
       // Just don't BCC everyone. Better to send a partial message to those
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
index e887221..f054ee8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CommentSender.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.patch.PatchFile;
 import com.google.gerrit.server.patch.PatchList;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
index dabb6f3..c6f716d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/CreateChangeSender.java
@@ -14,16 +14,16 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.AccountProjectWatch.NotifyType;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.ssh.SshInfo;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailArguments.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailArguments.java
index 15f6846..68f78d0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailArguments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailArguments.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.IdentifiedUser.GenericFactory;
 import com.google.gerrit.server.account.AccountCache;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
index 16f9062..ce8c8f9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailHeader.java
@@ -19,8 +19,8 @@
 import java.io.Writer;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
index 374ae34..4307854 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
@@ -1,8 +1,20 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AuthRequest;
 
 /** Verifies the token sent by {@link RegisterNewEmailSender}. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGenerator.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGenerator.java
index aa948f1..dec3d2c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGenerator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGenerator.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 
 /** Constructs an address to send email from. */
 public interface FromAddressGenerator {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java
index 0abf96f..bb50374 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/FromAddressGeneratorProvider.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.server.mail;
 
 import com.google.gerrit.common.data.ParameterizedString;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.config.AnonymousCowardName;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
index f11b7c4..b695fb4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergeFailSender.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
index 54efb02..3590b8a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/MergedSender.java
@@ -16,15 +16,15 @@
 
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.AccountProjectWatch.NotifyType;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
 import com.google.gerrit.server.config.AnonymousCowardName;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
index fb9ba60..2e459d4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/NewChangeSender.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.ssh.SshInfo;
 
 import com.jcraft.jsch.HostKey;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
index d208c84..de8628f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/OutgoingEmail.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.UserIdentity;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.UserIdentity;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.mail.EmailHeader.AddressList;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.velocity.Template;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RebasedPatchSetSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RebasedPatchSetSender.java
new file mode 100644
index 0000000..8fc8238
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RebasedPatchSetSender.java
@@ -0,0 +1,40 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.mail;
+
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.config.AnonymousCowardName;
+import com.google.gerrit.server.ssh.SshInfo;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+/** Send notice to reviewers that a change has been rebased. */
+public class RebasedPatchSetSender extends ReplacePatchSetSender {
+  public static interface Factory {
+    RebasedPatchSetSender create(Change change);
+  }
+
+  @Inject
+  public RebasedPatchSetSender(EmailArguments ea,
+      @AnonymousCowardName String anonymousCowardName, SshInfo si,
+      @Assisted Change c) {
+    super(ea, anonymousCowardName, si, c);
+  }
+
+  @Override
+  protected void formatChange() throws EmailException {
+    appendText(velocifyFile("RebasedPatchSet.vm"));
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
index b09cb27..9705b8a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplacePatchSetSender.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.ssh.SshInfo;
 import com.google.inject.Inject;
@@ -67,6 +67,7 @@
     add(RecipientType.TO, reviewers);
     add(RecipientType.CC, extraCC);
     rcptToAuthors(RecipientType.CC);
+    bccStarredBy();
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
index 6b0ed4d..2a77d39 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/ReplyToChangeSender.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 
 /** Alert a user to a reply to a change, usually commentary made during review. */
 public abstract class ReplyToChangeSender extends ChangeEmail {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
index b9df397..c9afdde 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RestoredSender.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
index e6f88ea..964bfed 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RevertedSender.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
index aad2f76..4d6eb8e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
@@ -1,8 +1,20 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 package com.google.gerrit.server.mail;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gwtjsonrpc.server.SignedToken;
 import com.google.gwtjsonrpc.server.ValidToken;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/AddReviewer.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/AddReviewer.java
index 9fdc899..df93852 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/AddReviewer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/AddReviewer.java
@@ -18,13 +18,13 @@
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
 import com.google.gerrit.common.data.ReviewerResult;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.GroupCache;
@@ -32,7 +32,7 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.mail.AddReviewerSender;
 import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java
index 3805f8f..46def59 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiff.java
@@ -19,7 +19,7 @@
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeEnum;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
 
-import com.google.gerrit.reviewdb.CodedEnum;
+import com.google.gerrit.reviewdb.client.CodedEnum;
 
 import org.eclipse.jgit.diff.Edit;
 import org.eclipse.jgit.diff.ReplaceEdit;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiffKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiffKey.java
index a8d62fc..c5c5925 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiffKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/IntraLineDiffKey.java
@@ -17,7 +17,7 @@
 import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 import org.eclipse.jgit.diff.Edit;
 import org.eclipse.jgit.lib.ObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
index 4feccd0..f120ebf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
@@ -16,7 +16,7 @@
 
 import com.google.gerrit.common.errors.CorruptEntityException;
 import com.google.gerrit.common.errors.NoSuchEntityException;
-import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.client.Patch;
 
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
index 7194a22..93d7bf7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchList.java
@@ -24,8 +24,8 @@
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeCanBeNull;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
 
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
 
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
@@ -142,8 +142,12 @@
   }
 
   private int search(final String fileName) {
+    if (Patch.COMMIT_MSG.equals(fileName)) {
+      return 0;
+    }
+
     int high = patches.length;
-    int low = 0;
+    int low = 1;
     while (low < high) {
       final int mid = (low + high) >>> 1;
       final int cmp = patches[mid].getNewName().compareTo(fileName);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCache.java
index a7cf10a..8a61d30 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCache.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.patch;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
 
 /** Provides a cached list of {@link PatchListEntry}. */
 public interface PatchListCache {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
index e1a0a40..26dbe2d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
@@ -16,10 +16,10 @@
 package com.google.gerrit.server.patch;
 
 
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
+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.AccountDiffPreference.Whitespace;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EvictionPolicy;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
index 837ec9c..33ed54e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
@@ -23,10 +23,10 @@
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeString;
 import static com.google.gerrit.server.ioutil.BasicSerialization.writeVarInt32;
 
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Patch.ChangeType;
-import com.google.gerrit.reviewdb.Patch.PatchType;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.Patch.ChangeType;
+import com.google.gerrit.reviewdb.client.Patch.PatchType;
 
 import org.eclipse.jgit.diff.Edit;
 import org.eclipse.jgit.lib.Constants;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
index 18fa5b0..de12cc6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListKey.java
@@ -21,8 +21,8 @@
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeCanBeNull;
 import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull;
 
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
index 0bb4bcc..5bba42b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListLoader.java
@@ -15,8 +15,8 @@
 
 package com.google.gerrit.server.patch;
 
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.AccountDiffPreference.Whitespace;
 import com.google.gerrit.server.cache.EntryCreator;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
index 0c70eac..f59dcc3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchSetInfoFactory.java
@@ -14,17 +14,17 @@
 
 package com.google.gerrit.server.patch;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.UserIdentity;
+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.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.client.UserIdentity;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountByEmailCache;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java
index 039e0f6..fdabcaa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java
@@ -17,24 +17,27 @@
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.mail.CommentSender;
-import com.google.gerrit.server.mail.EmailException;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gerrit.server.util.RequestScopePropagator;
 import com.google.gerrit.server.workflow.FunctionState;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -60,6 +63,7 @@
         Set<ApprovalCategoryValue.Id> approvals, boolean forceMessage);
   }
 
+  private final SchemaFactory<ReviewDb> schemaFactory;
   private final ReviewDb db;
   private final IdentifiedUser user;
   private final ApprovalTypes types;
@@ -68,6 +72,8 @@
   private final ChangeControl.Factory changeControlFactory;
   private final FunctionState.Factory functionStateFactory;
   private final ChangeHooks hooks;
+  private final WorkQueue workQueue;
+  private final RequestScopePropagator requestScopePropagator;
 
   private final PatchSet.Id patchSetId;
   private final String messageText;
@@ -80,18 +86,22 @@
   private List<PatchLineComment> drafts;
 
   @Inject
-  PublishComments(final ReviewDb db, final IdentifiedUser user,
+  PublishComments(final SchemaFactory<ReviewDb> sf, final ReviewDb db,
+      final IdentifiedUser user,
       final ApprovalTypes approvalTypes,
       final CommentSender.Factory commentSenderFactory,
       final PatchSetInfoFactory patchSetInfoFactory,
       final ChangeControl.Factory changeControlFactory,
       final FunctionState.Factory functionStateFactory,
       final ChangeHooks hooks,
+      final WorkQueue workQueue,
+      final RequestScopePropagator requestScopePropagator,
 
       @Assisted final PatchSet.Id patchSetId,
       @Assisted final String messageText,
       @Assisted final Set<ApprovalCategoryValue.Id> approvals,
       @Assisted final boolean forceMessage) {
+    this.schemaFactory = sf;
     this.db = db;
     this.user = user;
     this.types = approvalTypes;
@@ -100,6 +110,8 @@
     this.changeControlFactory = changeControlFactory;
     this.functionStateFactory = functionStateFactory;
     this.hooks = hooks;
+    this.workQueue = workQueue;
+    this.requestScopePropagator = requestScopePropagator;
 
     this.patchSetId = patchSetId;
     this.messageText = messageText;
@@ -151,7 +163,8 @@
     db.patchComments().update(drafts);
   }
 
-  private void publishApprovals(ChangeControl ctl) throws OrmException {
+  private void publishApprovals(ChangeControl ctl)
+      throws InvalidChangeOperationException, OrmException {
     ChangeUtil.updated(change);
 
     final Set<ApprovalCategory.Id> dirty = new HashSet<ApprovalCategory.Id>();
@@ -188,6 +201,11 @@
       if (!ApprovalCategory.SUBMIT.equals(a.getCategoryId())) {
         functionState.normalize(types.byId(a.getCategoryId()), a);
       }
+      if (want.get() != a.getValue()) {
+        throw new InvalidChangeOperationException(
+            types.byId(a.getCategoryId()).getCategory().getLabelName()
+            + "=" + want.get() + " not permitted");
+      }
       if (o != a.getValue()) {
         // Value changed, ensure we update the database.
         //
@@ -294,20 +312,47 @@
   }
 
   private void email() {
-    try {
-      if (message != null) {
-        final CommentSender cm = commentSenderFactory.create(change);
-        cm.setFrom(user.getAccountId());
-        cm.setPatchSet(patchSet, patchSetInfoFactory.get(db, patchSetId));
-        cm.setChangeMessage(message);
-        cm.setPatchLineComments(drafts);
-        cm.send();
-      }
-    } catch (EmailException e) {
-      log.error("Cannot send comments by email for patch set " + patchSetId, e);
-    } catch (PatchSetInfoNotAvailableException e) {
-      log.error("Failed to obtain PatchSetInfo for patch set " + patchSetId, e);
+    if (message == null) {
+      return;
     }
+
+    workQueue.getDefaultQueue()
+        .submit(requestScopePropagator.wrap(new Runnable() {
+      @Override
+      public void run() {
+        PatchSetInfo patchSetInfo;
+        try {
+          ReviewDb reviewDb = schemaFactory.open();
+          try {
+            patchSetInfo = patchSetInfoFactory.get(reviewDb, patchSetId);
+          } finally {
+            reviewDb.close();
+          }
+        } catch (PatchSetInfoNotAvailableException e) {
+          log.error("Cannot read PatchSetInfo of " + patchSetId, e);
+          return;
+        } catch (Exception e) {
+          log.error("Cannot email comments for " + patchSetId, e);
+          return;
+        }
+
+        try {
+          final CommentSender cm = commentSenderFactory.create(change);
+          cm.setFrom(user.getAccountId());
+          cm.setPatchSet(patchSet, patchSetInfo);
+          cm.setChangeMessage(message);
+          cm.setPatchLineComments(drafts);
+          cm.send();
+        } catch (Exception e) {
+          log.error("Cannot email comments for " + patchSetId, e);
+        }
+      }
+
+      @Override
+      public String toString() {
+        return "send-email comments";
+      }
+    }));
   }
 
   private void fireHook() throws OrmException {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/RemoveReviewer.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/RemoveReviewer.java
index 884cb54..af9bb8c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/RemoveReviewer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/RemoveReviewer.java
@@ -16,14 +16,14 @@
 package com.google.gerrit.server.patch;
 
 import com.google.gerrit.common.data.ReviewerResult;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.project.ChangeControl;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java
index 09a2a91..3b1191c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/AccessControlModule.java
@@ -16,7 +16,7 @@
 
 import static com.google.inject.Scopes.SINGLETON;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.GitReceivePackGroups;
 import com.google.gerrit.server.config.GitReceivePackGroupsProvider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
index 073372c..d17762e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
@@ -16,18 +16,18 @@
 
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.SubmitRecord;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+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.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.rules.PrologEnvironment;
 import com.google.gerrit.rules.StoredValues;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -199,6 +199,12 @@
     return isOwner() && isVisible(db);
   }
 
+  /** Can this user rebase this change? */
+  public boolean canRebase() {
+    return isOwner() || getRefControl().canSubmit()
+        || getRefControl().canRebase();
+  }
+
   /** Can this user restore this change? */
   public boolean canRestore() {
     return canAbandon(); // Anyone who can abandon the change can restore it back
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
index 474c5c4..65bdc1e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProject.java
@@ -19,9 +19,9 @@
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
 import com.google.gerrit.common.errors.ProjectCreationFailedException;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.GroupCache;
@@ -30,6 +30,7 @@
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
 import com.google.gerrit.server.git.ReplicationQueue;
+import com.google.gerrit.server.git.RepositoryCaseMismatchException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -41,8 +42,8 @@
 import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.lib.Repository;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,9 +51,6 @@
 import java.util.ArrayList;
 import java.util.Set;
 
-import com.google.gerrit.server.git.RepositoryCaseMismatchException;
-import com.google.gerrit.server.project.ProjectCache;
-
 
 /** Common class that holds the code to create projects */
 public class CreateProject {
@@ -93,8 +91,8 @@
 
   public void createProject() throws ProjectCreationFailedException {
     validateParameters();
+    final Project.NameKey nameKey = createProjectArgs.getProject();
     try {
-      final Project.NameKey nameKey = createProjectArgs.getProject();
       final String head =
           createProjectArgs.permissionsOnly ? GitRepositoryManager.REF_CONFIG
               : createProjectArgs.branch;
@@ -115,12 +113,30 @@
       } finally {
         repo.close();
       }
-    } catch (IllegalStateException e) {
-      handleRepositoryExistsException(createProjectArgs.getProject(), e);
-    } catch (RepositoryCaseMismatchException ee) {
-      handleRepositoryExistsException(ee.getNameOfExistingProject(), ee);
+    } catch (RepositoryCaseMismatchException e) {
+      throw new ProjectCreationFailedException("Cannot create " + nameKey.get()
+          + " because the name is already occupied by another project."
+          + " The other project has the same name, only spelled in a"
+          + " different case.", e);
+    } catch (RepositoryNotFoundException badName) {
+      throw new ProjectCreationFailedException("Cannot create " + nameKey, badName);
+    } catch (IllegalStateException err) {
+      try {
+        final Repository repo = repoManager.openRepository(nameKey);
+        try {
+          if (repo.getObjectDatabase().exists()) {
+            throw new ProjectCreationFailedException("project \"" + nameKey + "\" exists");
+          }
+        } finally {
+          repo.close();
+        }
+      } catch (RepositoryNotFoundException doesNotExist) {
+        final String msg = "Cannot create " + nameKey;
+        log.error(msg, err);
+        throw new ProjectCreationFailedException(msg, err);
+      }
     } catch (Exception e) {
-      final String msg = "Cannot create " + createProjectArgs.getProject();
+      final String msg = "Cannot create " + nameKey;
       log.error(msg, e);
       throw new ProjectCreationFailedException(msg, e);
     }
@@ -245,22 +261,4 @@
       oi.release();
     }
   }
-
-  private void handleRepositoryExistsException(final Project.NameKey nameKey,
-      Exception e) throws ProjectCreationFailedException {
-    try {
-      Repository repo = repoManager.openRepository(nameKey);
-      try {
-        if (repo.getObjectDatabase().exists()) {
-          throw new ProjectCreationFailedException("Project \"" + nameKey
-              + "\" exists", e);
-        }
-      } finally {
-        repo.close();
-      }
-    } catch (RepositoryNotFoundException er) {
-      throw new ProjectCreationFailedException("Cannot create \"" + nameKey
-          + "\"", er);
-    }
-  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProjectArgs.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProjectArgs.java
index 63e358f..98adf85 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProjectArgs.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/CreateProjectArgs.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.SubmitType;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.SubmitType;
 
 import java.util.List;
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
similarity index 79%
rename from gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
index 9aafc0e..95a8b77 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjects.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java
@@ -12,18 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.sshd.commands;
+package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectControl;
-import com.google.gerrit.server.project.ProjectState;
-import com.google.gerrit.sshd.BaseCommand;
+import com.google.gerrit.server.util.TreeFormatter;
 import com.google.inject.Inject;
 
-import org.apache.sshd.server.Environment;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
@@ -32,18 +28,23 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.BufferedWriter;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeMap;
 import java.util.TreeSet;
 
-final class ListProjects extends BaseCommand {
+/** List projects visible to the calling user. */
+public class ListProjects {
   private static final Logger log = LoggerFactory.getLogger(ListProjects.class);
 
-  static enum FilterType {
+  public static enum FilterType {
     CODE {
       @Override
       boolean matches(Repository git) throws IOException {
@@ -69,24 +70,18 @@
     abstract boolean matches(Repository git) throws IOException;
   }
 
-  @Inject
-  private IdentifiedUser currentUser;
-
-  @Inject
-  private ProjectCache projectCache;
-
-  @Inject
-  private GitRepositoryManager repoManager;
-
-  @Inject
-  private ProjectNode.Factory projectNodeFactory;
+  private final CurrentUser currentUser;
+  private final ProjectCache projectCache;
+  private final GitRepositoryManager repoManager;
+  private final ProjectNode.Factory projectNodeFactory;
 
   @Option(name = "--show-branch", aliases = {"-b"}, multiValued = true,
       usage = "displays the sha of each project in the specified branch")
   private List<String> showBranch;
 
-  @Option(name = "--tree", aliases = {"-t"}, usage = "displays project inheritance in a tree-like format\n" +
-      "this option does not work together with the show-branch option")
+  @Option(name = "--tree", aliases = {"-t"}, usage =
+      "displays project inheritance in a tree-like format\n"
+      + "this option does not work together with the show-branch option")
   private boolean showTree;
 
   @Option(name = "--type", usage = "type of project")
@@ -98,27 +93,37 @@
   @Option(name = "--all", usage = "display all projects that are accessible by the calling user")
   private boolean all;
 
-  @Override
-  public void start(final Environment env) {
-    startThread(new CommandRunnable() {
-      @Override
-      public void run() throws Exception {
-        parseCommandLine();
-        ListProjects.this.display();
-      }
-    });
+  @Inject
+  protected ListProjects(CurrentUser currentUser, ProjectCache projectCache,
+      GitRepositoryManager repoManager,
+      ProjectNode.Factory projectNodeFactory) {
+    this.currentUser = currentUser;
+    this.projectCache = projectCache;
+    this.repoManager = repoManager;
+    this.projectNodeFactory = projectNodeFactory;
   }
 
-  private void display() throws Failure {
-    if (showTree && (showBranch != null)) {
-      throw new UnloggedFailure(1, "fatal: --tree and --show-branch options are not compatible.");
+  public List<String> getShowBranch() {
+    return showBranch;
+  }
+
+  public boolean isShowTree() {
+    return showTree;
+  }
+
+  public boolean isShowDescription() {
+    return showDescription;
+  }
+
+  public void display(OutputStream out) {
+    final PrintWriter stdout;
+    try {
+      stdout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, "UTF-8")));
+    } catch (UnsupportedEncodingException e) {
+      // Our encoding is required by the specifications for the runtime.
+      throw new RuntimeException("JVM lacks UTF-8 encoding", e);
     }
 
-    if (showTree && showDescription) {
-      throw new UnloggedFailure(1, "fatal: --tree and --description options are not compatible.");
-    }
-
-    final PrintWriter stdout = toPrintWriter(out);
     final TreeMap<Project.NameKey, ProjectNode> treeMap =
         new TreeMap<Project.NameKey, ProjectNode>();
     try {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchChangeException.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchChangeException.java
index d5a22fd..f766c7f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchChangeException.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchChangeException.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 
 /** Indicates the change does not exist. */
 public class NoSuchChangeException extends Exception {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchProjectException.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchProjectException.java
index a1448d5..2ac494d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchProjectException.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/NoSuchProjectException.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 /** Indicates the project does not exist. */
 public class NoSuchProjectException extends Exception {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java
index 1a96381..19a42ae 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PerRequestProjectControlCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.inject.Inject;
 import com.google.inject.servlet.RequestScoped;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
index 02f56c5..e416ed7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/PermissionCollection.java
@@ -19,7 +19,7 @@
 import com.google.gerrit.common.data.AccessSection;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCache.java
index cff554c..70f4013 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCache.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 /** Cache of project information, including access rights. */
 public interface ProjectCache {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index 7a7f56e..51d8fb2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
index d08f8e3..29a6432 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
@@ -20,15 +20,15 @@
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AbstractAgreement;
-import com.google.gerrit.reviewdb.AccountAgreement;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupAgreement;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ContributorAgreement;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AbstractAgreement;
+import com.google.gerrit.reviewdb.client.AccountAgreement;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupAgreement;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ContributorAgreement;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.ReplicationUser;
@@ -36,8 +36,8 @@
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.GitReceivePackGroups;
 import com.google.gerrit.server.config.GitUploadPackGroups;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
@@ -281,7 +281,7 @@
     ContributorAgreement bestCla = null;
     try {
 
-      OUTER: for (AccountGroup.UUID groupUUID : iUser.getEffectiveGroups()) {
+      OUTER: for (AccountGroup.UUID groupUUID : iUser.getEffectiveGroups().getKnownGroups()) {
         AccountGroup group = groupCache.get(groupUUID);
         if (group == null) {
           continue;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ProjectNode.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectNode.java
similarity index 83%
rename from gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ProjectNode.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectNode.java
index 8e12571..1c4d7c4 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ProjectNode.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectNode.java
@@ -12,32 +12,31 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.sshd.commands;
+package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.sshd.commands.TreeFormatter.TreeNode;
+import com.google.gerrit.server.util.TreeFormatter.TreeNode;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
 import java.util.SortedSet;
 import java.util.TreeSet;
 
+/** Node of a Project in a tree formatted by {@link ListProjects}. */
 public class ProjectNode implements TreeNode, Comparable<ProjectNode> {
-
   public interface Factory {
     ProjectNode create(final Project project, final boolean isVisible);
   }
 
   private final AllProjectsName allProjectsName;
-
   private final Project project;
   private final boolean isVisible;
 
   private final SortedSet<ProjectNode> children = new TreeSet<ProjectNode>();
 
   @Inject
-  public ProjectNode(final AllProjectsName allProjectsName,
+  protected ProjectNode(final AllProjectsName allProjectsName,
       @Assisted final Project project, @Assisted final boolean isVisible) {
     this.allProjectsName = allProjectsName;
     this.project = project;
@@ -51,15 +50,7 @@
    *         project
    */
   public Project.NameKey getParentName() {
-    if (project.getParent() != null) {
-      return project.getParent();
-    }
-
-    if (project.getNameKey().equals(allProjectsName)) {
-      return null;
-    }
-
-    return allProjectsName;
+    return project.getParent(allProjectsName);
   }
 
   public boolean isAllProjects() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index a72fc16..6eac998 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -19,12 +19,13 @@
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.rules.PrologEnvironment;
 import com.google.gerrit.rules.RulesCache;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityCollection;
+import com.google.gerrit.server.account.GroupMembership;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectConfig;
@@ -240,13 +241,13 @@
    * @return true if any of the groups listed in {@code groups} was declared to
    *         be an owner of this project, or one of its parent projects..
    */
-  boolean isOwner(Set<AccountGroup.UUID> groups) {
+  boolean isOwner(GroupMembership groups) {
     Set<Project.NameKey> seen = new HashSet<Project.NameKey>();
     seen.add(getProject().getNameKey());
 
     ProjectState s = this;
     do {
-      if (CollectionsUtil.isAnyIncludedIn(s.localOwners, groups)) {
+      if (groups.containsAnyOf(s.localOwners)) {
         return true;
       }
 
@@ -272,10 +273,6 @@
     if (isAllProjects) {
       return null;
     }
-    Project.NameKey parentName = getProject().getParent();
-    if (parentName == null) {
-      parentName = allProjectsName;
-    }
-    return projectCache.get(parentName);
+    return projectCache.get(getProject().getParent(allProjectsName));
   }
 }
\ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
index e1341da..db370e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java
@@ -18,7 +18,9 @@
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.common.data.RefConfigSection;
+import com.google.gerrit.common.errors.InvalidNameException;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -26,6 +28,7 @@
 import dk.brics.automaton.RegExp;
 
 import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevTag;
@@ -122,6 +125,12 @@
         && canWrite();
   }
 
+  /** @return true if this user can rebase changes on this ref */
+  public boolean canRebase() {
+    return canPerform(Permission.REBASE)
+        && canWrite();
+  }
+
   /** @return true if this user can submit patch sets to this ref */
   public boolean canSubmit() {
     if (GitRepositoryManager.REF_CONFIG.equals(refName)) {
@@ -400,7 +409,7 @@
     return mine;
   }
 
-  static boolean isRE(String refPattern) {
+  public static boolean isRE(String refPattern) {
     return refPattern.startsWith(AccessSection.REGEX_PREFIX);
   }
 
@@ -414,10 +423,28 @@
     }
   }
 
-  static RegExp toRegExp(String refPattern) {
+  public static RegExp toRegExp(String refPattern) {
     if (isRE(refPattern)) {
       refPattern = refPattern.substring(1);
     }
     return new RegExp(refPattern, RegExp.NONE);
   }
+
+  public static void validateRefPattern(String refPattern)
+      throws InvalidNameException {
+    if (refPattern.startsWith(RefConfigSection.REGEX_PREFIX)) {
+      if (!Repository.isValidRefName(RefControl.shortestExample(refPattern))) {
+        throw new InvalidNameException(refPattern);
+      }
+    } else if (refPattern.equals(RefConfigSection.ALL)) {
+      // This is a special case we have to allow, it fails below.
+    } else if (refPattern.endsWith("/*")) {
+      String prefix = refPattern.substring(0, refPattern.length() - 2);
+      if (!Repository.isValidRefName(prefix)) {
+        throw new InvalidNameException(refPattern);
+      }
+    } else if (!Repository.isValidRefName(refPattern)) {
+      throw new InvalidNameException(refPattern);
+    }
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java
index ce7530e..1c70b04 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionMatcher.java
@@ -33,7 +33,7 @@
 abstract class SectionMatcher {
   static SectionMatcher wrap(AccessSection section) {
     String ref = section.getName();
-    if (AccessSection.isAccessSection(ref)) {
+    if (AccessSection.isValid(ref)) {
       return wrap(ref, section);
     } else {
       return null;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
index 2bc957e..047997e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SectionSortCache.java
@@ -14,26 +14,21 @@
 
 package com.google.gerrit.server.project;
 
-import static com.google.gerrit.server.project.RefControl.isRE;
-import static com.google.gerrit.server.project.RefControl.shortestExample;
-import static com.google.gerrit.server.project.RefControl.toRegExp;
-
 import com.google.gerrit.common.data.AccessSection;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.util.MostSpecificComparator;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
 import com.google.inject.TypeLiteral;
 import com.google.inject.name.Named;
 
-import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.IdentityHashMap;
 import java.util.List;
 
@@ -171,103 +166,5 @@
     }
   }
 
-  /**
-   * Order the Ref Pattern by the most specific. This sort is done by:
-   * <ul>
-   * <li>1 - The minor value of Levenshtein string distance between the branch
-   * name and the regex string shortest example. A shorter distance is a more
-   * specific match.
-   * <li>2 - Finites first, infinities after.
-   * <li>3 - Number of transitions.
-   * <li>4 - Length of the expression text.
-   * </ul>
-   *
-   * Levenshtein distance is a measure of the similarity between two strings.
-   * The distance is the number of deletions, insertions, or substitutions
-   * required to transform one string into another.
-   *
-   * For example, if given refs/heads/m* and refs/heads/*, the distances are 5
-   * and 6. It means that refs/heads/m* is more specific because it's closer to
-   * refs/heads/master than refs/heads/*.
-   *
-   * Another example could be refs/heads/* and refs/heads/[a-zA-Z]*, the
-   * distances are both 6. Both are infinite, but refs/heads/[a-zA-Z]* has more
-   * transitions, which after all turns it more specific.
-   */
-  private static final class MostSpecificComparator implements
-      Comparator<AccessSection> {
-    private final String refName;
 
-    MostSpecificComparator(String refName) {
-      this.refName = refName;
-    }
-
-    public int compare(AccessSection a, AccessSection b) {
-      return compare(a.getName(), b.getName());
-    }
-
-    private int compare(final String pattern1, final String pattern2) {
-      int cmp = distance(pattern1) - distance(pattern2);
-      if (cmp == 0) {
-        boolean p1_finite = finite(pattern1);
-        boolean p2_finite = finite(pattern2);
-
-        if (p1_finite && !p2_finite) {
-          cmp = -1;
-        } else if (!p1_finite && p2_finite) {
-          cmp = 1;
-        } else /* if (f1 == f2) */{
-          cmp = 0;
-        }
-      }
-      if (cmp == 0) {
-        cmp = transitions(pattern1) - transitions(pattern2);
-      }
-      if (cmp == 0) {
-        cmp = pattern2.length() - pattern1.length();
-      }
-      return cmp;
-    }
-
-    private int distance(String pattern) {
-      String example;
-      if (isRE(pattern)) {
-        example = shortestExample(pattern);
-
-      } else if (pattern.endsWith("/*")) {
-        example = pattern.substring(0, pattern.length() - 1) + '1';
-
-      } else if (pattern.equals(refName)) {
-        return 0;
-
-      } else {
-        return Math.max(pattern.length(), refName.length());
-      }
-      return StringUtils.getLevenshteinDistance(example, refName);
-    }
-
-    private boolean finite(String pattern) {
-      if (isRE(pattern)) {
-        return toRegExp(pattern).toAutomaton().isFinite();
-
-      } else if (pattern.endsWith("/*")) {
-        return false;
-
-      } else {
-        return true;
-      }
-    }
-
-    private int transitions(String pattern) {
-      if (isRE(pattern)) {
-        return toRegExp(pattern).toAutomaton().getNumberOfTransitions();
-
-      } else if (pattern.endsWith("/*")) {
-        return pattern.length();
-
-      } else {
-        return pattern.length();
-      }
-    }
-  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java
index 9585e1e..c73de60 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SuggestParentCandidates.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.project;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import java.util.ArrayList;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
index f79fbac..096e12e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/AndPredicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query;
 
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
index f039e19..f94e1f6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/NotPredicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query;
 
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/ObjectIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/ObjectIdPredicate.java
index 0d68fea..bea4da12 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/ObjectIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/ObjectIdPredicate.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.server.query;
 
-import com.google.gerrit.server.query.OperatorPredicate;
-
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
index a198745..57d21b1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/OrPredicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query;
 
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
index 485087f..ce47d2d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/Predicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query;
 
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
index 5de116f..45b27e5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/VariablePredicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query;
 
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java
index 2b8d37d..e072760 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AbstractResultSet.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.ResultSet;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
index 18a0c82..d0c9e4c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
@@ -17,11 +17,11 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class AgePredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java
index e74b390..3a0bfa3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AndSource.java
@@ -16,9 +16,9 @@
 
 import com.google.gerrit.server.query.AndPredicate;
 import com.google.gerrit.server.query.Predicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.impl.ListResultSet;
+import com.google.gwtorm.server.ListResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 
 import java.util.ArrayList;
 import java.util.Collection;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BranchPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BranchPredicate.java
index 1083d6a..e5b4143 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BranchPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BranchPredicate.java
@@ -14,21 +14,20 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class BranchPredicate extends OperatorPredicate<ChangeData> {
   private final Provider<ReviewDb> dbProvider;
-  private final String shortName;
 
   BranchPredicate(Provider<ReviewDb> dbProvider, String branch) {
-    super(ChangeQueryBuilder.FIELD_BRANCH, branch);
+    super(ChangeQueryBuilder.FIELD_BRANCH, branch.startsWith(Branch.R_HEADS)
+        ? branch : Branch.R_HEADS + branch);
     this.dbProvider = dbProvider;
-    this.shortName = branch;
   }
 
   @Override
@@ -38,7 +37,7 @@
       return false;
     }
     return change.getDest().get().startsWith(Branch.R_HEADS)
-        && shortName.equals(change.getDest().getShortName());
+        && getValue().equals(change.getDest().get());
   }
 
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index 2f648a9..7a85b6f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -14,21 +14,21 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.Patch;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.TrackingId;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.Patch;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.TrackingId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.patch.PatchListEntry;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import org.eclipse.jgit.lib.ObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java
index fc7ba59..c2eb9b9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataResultSet.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gwtorm.server.ResultSet;
 
 import java.util.HashSet;
 import java.util.Iterator;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataSource.java
index a770b54..ecfd48c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataSource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeDataSource.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 
 public interface ChangeDataSource {
   /** @return an estimate of the number of results from {@link #read()}. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
index 83107bb..7116aa9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Provider;
 
 class ChangeIdPredicate extends OperatorPredicate<ChangeData> implements
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 64a5d07..4d8e806 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -15,12 +15,12 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Change;
+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.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountResolver;
@@ -35,7 +35,7 @@
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryBuilder;
 import com.google.gerrit.server.query.QueryParseException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.assistedinject.Assisted;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryRewriter.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryRewriter.java
index b31bf65..34ec2f4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryRewriter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryRewriter.java
@@ -14,16 +14,17 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeAccess;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ChangeAccess;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeUtil;
 import com.google.gerrit.server.query.IntPredicate;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryRewriter;
 import com.google.gerrit.server.query.RewritePredicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.OutOfScopeException;
 import com.google.inject.Provider;
@@ -118,6 +119,75 @@
     return a.getValue().compareTo(b.getValue()) >= 0 ? a : b;
   }
 
+  @Rewrite("status:open P=(project:*) B=(branch:*)")
+  public Predicate<ChangeData> r05_byBranchOpen(
+      @Named("P") final ProjectPredicate p,
+      @Named("B") final BranchPredicate b) {
+    return new ChangeSource(500) {
+      @Override
+      ResultSet<Change> scan(ChangeAccess a)
+          throws OrmException {
+        return a.byBranchOpenAll(
+            new Branch.NameKey(p.getValueKey(), b.getValue()));
+      }
+
+      @Override
+      public boolean match(ChangeData cd) throws OrmException {
+        return cd.change(dbProvider).getStatus().isOpen()
+            && p.match(cd)
+            && b.match(cd);
+      }
+    };
+  }
+
+  @Rewrite("status:merged P=(project:*) B=(branch:*) S=(sortkey_after:*) L=(limit:*)")
+  public Predicate<ChangeData> r05_byBranchMergedPrev(
+      @Named("P") final ProjectPredicate p,
+      @Named("B") final BranchPredicate b,
+      @Named("S") final SortKeyPredicate.After s,
+      @Named("L") final IntPredicate<ChangeData> l) {
+    return new PaginatedSource(40000, s.getValue(), l.intValue()) {
+      @Override
+      ResultSet<Change> scan(ChangeAccess a, String key, int limit)
+          throws OrmException {
+        return a.byBranchClosedPrev(Change.Status.MERGED.getCode(), //
+            new Branch.NameKey(p.getValueKey(), b.getValue()), key, limit);
+      }
+
+      @Override
+      public boolean match(ChangeData cd) throws OrmException {
+        return cd.change(dbProvider).getStatus() == Change.Status.MERGED
+            && p.match(cd) //
+            && b.match(cd) //
+            && s.match(cd);
+      }
+    };
+  }
+
+  @Rewrite("status:merged P=(project:*) B=(branch:*) S=(sortkey_before:*) L=(limit:*)")
+  public Predicate<ChangeData> r05_byBranchMergedNext(
+      @Named("P") final ProjectPredicate p,
+      @Named("B") final BranchPredicate b,
+      @Named("S") final SortKeyPredicate.Before s,
+      @Named("L") final IntPredicate<ChangeData> l) {
+    return new PaginatedSource(40000, s.getValue(), l.intValue()) {
+      @Override
+      ResultSet<Change> scan(ChangeAccess a, String key, int limit)
+          throws OrmException {
+        return a.byBranchClosedNext(Change.Status.MERGED.getCode(), //
+            new Branch.NameKey(p.getValueKey(), b.getValue()), key, limit);
+      }
+
+      @Override
+      public boolean match(ChangeData cd) throws OrmException {
+        return cd.change(dbProvider).getStatus() == Change.Status.MERGED
+            && p.match(cd) //
+            && b.match(cd) //
+            && s.match(cd);
+      }
+    };
+  }
+
   @Rewrite("status:open P=(project:*) S=(sortkey_after:*) L=(limit:*)")
   public Predicate<ChangeData> r10_byProjectOpenPrev(
       @Named("P") final ProjectPredicate p,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
index 4ae2278..6e9e79c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
 import com.google.gerrit.server.query.Predicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import java.util.ArrayList;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
index c03cddc..274b40c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.ObjectIdPredicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Provider;
 
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
index 07d4dd2..1d9a9a4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
@@ -14,14 +14,14 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.impl.ListResultSet;
+import com.google.gwtorm.server.ListResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Provider;
 
 import java.util.ArrayList;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
index 46c7741..639be517c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class IsReviewedPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
index aaf8478..3fd9feb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsStarredByPredicate.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Provider;
 
 class IsStarredByPredicate extends OperatorPredicate<ChangeData> implements
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
index 739d9bc..413e6c4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsVisibleToPredicate.java
@@ -14,14 +14,14 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class IsVisibleToPredicate extends OperatorPredicate<ChangeData> {
@@ -30,7 +30,7 @@
       return ((IdentifiedUser) user).getAccountId().toString();
     }
     if (user instanceof SingleGroupUser) {
-      return "group:" + ((SingleGroupUser) user).getEffectiveGroups() //
+      return "group:" + ((SingleGroupUser) user).getEffectiveGroups().getKnownGroups() //
           .iterator().next().toString();
     }
     return user.toString();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
index 69d379cf..25cfae7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
@@ -14,15 +14,15 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.query.OperatorPredicate;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LabelPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LabelPredicate.java
index 7342c4f..bf21261 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LabelPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LabelPredicate.java
@@ -17,14 +17,14 @@
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
 import com.google.gerrit.common.data.Permission;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import java.util.regex.Matcher;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
index ac544a3..4c47e73 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.impl.ListResultSet;
+import com.google.gwtorm.server.ListResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Provider;
 
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
index 20b777d..f016c37 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
@@ -14,14 +14,14 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
+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.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java
index 617a14a..ec5195b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OrSource.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.query.OrPredicate;
 import com.google.gerrit.server.query.Predicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.impl.ListResultSet;
+import com.google.gwtorm.server.ListResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 
 import java.util.ArrayList;
 import java.util.Collection;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
index 224dce9..7a85ef6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class OwnerPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java
index 92890b7..05c4cbf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerinPredicate.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class OwnerinPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java
index b046db6..2b3edf7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 
 interface Paginated {
   int limit();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
index 91203d6..cce2f2a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class ProjectPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
index 030e83f..a2fa7fe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
@@ -15,9 +15,9 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.common.data.GlobalCapability;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.events.ChangeAttribute;
 import com.google.gerrit.server.events.EventFactory;
@@ -27,7 +27,7 @@
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gson.Gson;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -77,6 +77,7 @@
   private boolean includeComments;
   private boolean includeFiles;
   private boolean includeCommitMessage;
+  private boolean includeDependencies;
 
   private OutputStream outputStream = DisabledOutputStream.INSTANCE;
   private PrintWriter out;
@@ -128,6 +129,14 @@
     return includeFiles;
   }
 
+  public void setIncludeDependencies(boolean on) {
+    includeDependencies = on;
+  }
+
+  public boolean getIncludeDependencies() {
+    return includeDependencies;
+  }
+
   public void setIncludeCommitMessage(boolean on) {
     includeCommitMessage = on;
   }
@@ -137,6 +146,51 @@
     this.outputFormat = fmt;
   }
 
+  public List<ChangeData> queryChanges(final String queryString)
+      throws OrmException, QueryParseException {
+    final Predicate<ChangeData> visibleToMe = queryBuilder.is_visible();
+    Predicate<ChangeData> s = compileQuery(queryString, visibleToMe);
+    List<ChangeData> results = new ArrayList<ChangeData>();
+    HashSet<Change.Id> want = new HashSet<Change.Id>();
+    for (ChangeData d : ((ChangeDataSource) s).read()) {
+      if (d.hasChange()) {
+        // Checking visibleToMe here should be unnecessary, the
+        // query should have already performed it. But we don't
+        // want to trust the query rewriter that much yet.
+        //
+        if (visibleToMe.match(d)) {
+          results.add(d);
+        }
+      } else {
+        want.add(d.getId());
+      }
+    }
+
+    if (!want.isEmpty()) {
+      for (Change c : db.get().changes().get(want)) {
+        ChangeData d = new ChangeData(c);
+        if (visibleToMe.match(d)) {
+          results.add(d);
+        }
+      }
+    }
+
+    Collections.sort(results, new Comparator<ChangeData>() {
+      @Override
+      public int compare(ChangeData a, ChangeData b) {
+        return b.getChange().getSortKey().compareTo(
+            a.getChange().getSortKey());
+      }
+    });
+
+    int limit = limit(s);
+    if (limit < results.size()) {
+      results = results.subList(0, limit);
+    }
+
+    return results;
+  }
+
   public void query(String queryString) throws IOException {
     out = new PrintWriter( //
         new BufferedWriter( //
@@ -153,46 +207,7 @@
         final QueryStats stats = new QueryStats();
         stats.runTimeMilliseconds = System.currentTimeMillis();
 
-        final Predicate<ChangeData> visibleToMe = queryBuilder.is_visible();
-        Predicate<ChangeData> s = compileQuery(queryString, visibleToMe);
-        List<ChangeData> results = new ArrayList<ChangeData>();
-        HashSet<Change.Id> want = new HashSet<Change.Id>();
-        for (ChangeData d : ((ChangeDataSource) s).read()) {
-          if (d.hasChange()) {
-            // Checking visibleToMe here should be unnecessary, the
-            // query should have already performed it. But we don't
-            // want to trust the query rewriter that much yet.
-            //
-            if (visibleToMe.match(d)) {
-              results.add(d);
-            }
-          } else {
-            want.add(d.getId());
-          }
-        }
-
-        if (!want.isEmpty()) {
-          for (Change c : db.get().changes().get(want)) {
-            ChangeData d = new ChangeData(c);
-            if (visibleToMe.match(d)) {
-              results.add(d);
-            }
-          }
-        }
-
-        Collections.sort(results, new Comparator<ChangeData>() {
-          @Override
-          public int compare(ChangeData a, ChangeData b) {
-            return b.getChange().getSortKey().compareTo(
-                a.getChange().getSortKey());
-          }
-        });
-
-        int limit = limit(s);
-        if (limit < results.size()) {
-          results = results.subList(0, limit);
-        }
-
+        List<ChangeData> results = queryChanges(queryString);
         for (ChangeData d : results) {
           ChangeAttribute c = eventFactory.asChangeAttribute(d.getChange());
           eventFactory.extend(c, d.getChange());
@@ -236,6 +251,10 @@
             }
           }
 
+          if (includeDependencies) {
+            eventFactory.addDependencies(c, d.getChange());
+          }
+
           show(c);
         }
 
@@ -361,7 +380,20 @@
       out.print('\n');
     } else if (value instanceof Collection) {
       out.print('\n');
+      boolean firstElement = true;
       for (Object thing : ((Collection<?>) value)) {
+        // The name of the collection was initially printed at the beginning
+        // of this routine.  Beginning at the second sub-element, reprint
+        // the collection name so humans can separate individual elements
+        // with less strain and error.
+        //
+        if (firstElement) {
+          firstElement = false;
+        } else {
+          out.print(indent);
+          out.print(field);
+          out.print(":\n");
+        }
         if (isPrimitive(thing)) {
           out.print(' ');
           out.print(value);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
index f5f83e2..4811f9a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class RefPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexBranchPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexBranchPredicate.java
index a18d43a..6704a10 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexBranchPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexBranchPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import dk.brics.automaton.RegExp;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexFilePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexFilePredicate.java
index 6bccec1..11856e4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexFilePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexFilePredicate.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import dk.brics.automaton.Automaton;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
index c35b66e..b8911a4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import dk.brics.automaton.RegExp;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
index e9e9958..1480de6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import dk.brics.automaton.RegExp;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
index e16088c..03814f8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 import dk.brics.automaton.RegExp;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
index bcece94..8e910df 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class ReviewerPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java
index ea4d7b6..421c6c6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerinPredicate.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class ReviewerinPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
index ad28b41..cdce217 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SingleGroupUser.java
@@ -14,19 +14,21 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityControl;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.ListGroupMembership;
 
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 
 final class SingleGroupUser extends CurrentUser {
-  private final Set<AccountGroup.UUID> groups;
+  private final GroupMembership groups;
 
   SingleGroupUser(CapabilityControl.Factory capabilityControlFactory,
       AccountGroup.UUID groupId) {
@@ -36,11 +38,11 @@
   SingleGroupUser(CapabilityControl.Factory capabilityControlFactory,
       Set<AccountGroup.UUID> groups) {
     super(capabilityControlFactory, AccessPath.UNKNOWN);
-    this.groups = groups;
+    this.groups = new ListGroupMembership(groups);
   }
 
   @Override
-  public Set<AccountGroup.UUID> getEffectiveGroups() {
+  public GroupMembership getEffectiveGroups() {
     return groups;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SortKeyPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SortKeyPredicate.java
index f67bee1..e7668c6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SortKeyPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SortKeyPredicate.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 abstract class SortKeyPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java
index 7bc972d..8d58376 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TopicPredicate.java
@@ -14,10 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Provider;
 
 class TopicPredicate extends OperatorPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
index eef568d..e022f86 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
@@ -14,13 +14,13 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.TrackingId;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.TrackingId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.query.OperatorPredicate;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.impl.ListResultSet;
+import com.google.gwtorm.server.ListResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Provider;
 
 import java.util.ArrayList;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
index 65f5820..2a98e96 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
@@ -15,7 +15,8 @@
 package com.google.gerrit.server.schema;
 
 import static com.google.gerrit.server.config.ConfigUtil.getEnum;
-import static java.util.concurrent.TimeUnit.*;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
 
 import com.google.gerrit.lifecycle.LifecycleListener;
 import com.google.gerrit.server.config.ConfigUtil;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java
index 6b66e33..c7832d4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DatabaseModule.java
@@ -16,10 +16,10 @@
 
 import static com.google.inject.Scopes.SINGLETON;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.FactoryModule;
-import com.google.gwtorm.client.SchemaFactory;
 import com.google.gwtorm.jdbc.Database;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.TypeLiteral;
 
 /** Loads the database with standard dependencies. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java
index 56b0379..ed77fff 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ReviewDbDatabaseProvider.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gwtorm.jdbc.Database;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java
index b8164b4..d8809da 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaCreator.java
@@ -19,14 +19,14 @@
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.CurrentSchemaVersion;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.account.GroupUUID;
 import com.google.gerrit.server.config.AllProjectsName;
@@ -36,13 +36,13 @@
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.NoReplication;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gwtorm.client.OrmException;
 import com.google.gwtorm.jdbc.JdbcExecutor;
 import com.google.gwtorm.jdbc.JdbcSchema;
 import com.google.gwtorm.schema.sql.DialectH2;
 import com.google.gwtorm.schema.sql.DialectMySQL;
 import com.google.gwtorm.schema.sql.DialectPostgreSQL;
 import com.google.gwtorm.schema.sql.SqlDialect;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
index 3937aaa..305fb84 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaUpdater.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.CurrentSchemaVersion;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
index abdc0ee..f789300 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersion.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.CurrentSchemaVersion;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.StatementExecutor;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gwtorm.jdbc.JdbcExecutor;
 import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.StatementExecutor;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provider;
 
@@ -32,7 +32,7 @@
 /** A version of the database schema. */
 public abstract class SchemaVersion {
   /** The current schema version. */
-  public static final Class<Schema_61> C = Schema_61.class;
+  public static final Class<Schema_64> C = Schema_64.class;
 
   public static class Module extends AbstractModule {
     @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java
index 9a59567..75d8a39 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/SchemaVersionCheck.java
@@ -16,10 +16,10 @@
 
 import com.google.gerrit.lifecycle.LifecycleListener;
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.reviewdb.CurrentSchemaVersion;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Provider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_52.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_52.java
index e16b95c..12a22f9 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_52.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_52.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.CurrentSchemaVersion;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
index 89ee5cf..d49b34e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_53.java
@@ -30,19 +30,19 @@
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.account.GroupUUID;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.NoReplication;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gwtorm.client.OrmException;
 import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java
index 8d00b73..9032bb0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.LocalDiskRepositoryManager;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
index bbb7109..2409b12e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.LocalDiskRepositoryManager;
 import com.google.inject.Inject;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
index 2ae1b7a..2247fdb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
@@ -18,11 +18,11 @@
 import com.google.gerrit.common.data.GlobalCapability;
 import com.google.gerrit.common.data.PermissionRule;
 import com.google.gerrit.common.data.PermissionRule.Action;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupName;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.config.SitePaths;
@@ -30,7 +30,7 @@
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.NoReplication;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_59.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_59.java
index 0b722bc..d90ecc1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_59.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_59.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java
index eec7256..3f49b0c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_60.java
@@ -14,13 +14,12 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.Change;
-
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestAccountsEnum.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_62.java
similarity index 72%
rename from gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestAccountsEnum.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_62.java
index 2ef2d44..4de8e55 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/SuggestAccountsEnum.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_62.java
@@ -12,11 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.httpd.rpc;
+package com.google.gerrit.server.schema;
 
-public enum SuggestAccountsEnum {
-  ALL,
-  SAME_GROUP,
-  VISIBLE_GROUP,
-  OFF;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class Schema_62 extends SchemaVersion {
+  @Inject
+  Schema_62(Provider<Schema_61> prior) {
+    super(prior);
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_63.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_63.java
new file mode 100644
index 0000000..761c36a
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_63.java
@@ -0,0 +1,48 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.schema;
+
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.schema.sql.DialectPostgreSQL;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class Schema_63 extends SchemaVersion {
+  @Inject
+  Schema_63(Provider<Schema_62> prior) {
+    super(prior);
+  }
+
+  @Override
+  protected void migrateData(ReviewDb db, UpdateUI ui) throws SQLException {
+    Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
+    try {
+      if (((JdbcSchema) db).getDialect() instanceof DialectPostgreSQL) {
+        stmt.execute("CREATE INDEX changes_byBranchClosed"
+            + " ON changes (status, dest_project_name, dest_branch_name, sort_key)"
+            + " WHERE open = 'N'");
+      } else {
+        stmt.execute("CREATE INDEX changes_byBranchClosed"
+            + " ON changes (status, dest_project_name, dest_branch_name, sort_key)");
+      }
+    } finally {
+      stmt.close();
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_64.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_64.java
new file mode 100644
index 0000000..26890a3
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_64.java
@@ -0,0 +1,121 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.schema;
+
+import com.google.common.collect.Lists;
+import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.common.data.Permission;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.NoReplication;
+import com.google.gerrit.server.git.ProjectConfig;
+import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+
+import java.io.IOException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+public class Schema_64 extends SchemaVersion {
+  private final AllProjectsName allProjects;
+  private final GitRepositoryManager mgr;
+  private final PersonIdent serverUser;
+
+  @Inject
+  Schema_64(Provider<Schema_63> prior,
+      AllProjectsName allProjects,
+      GitRepositoryManager mgr,
+      @GerritPersonIdent PersonIdent serverUser) {
+    super(prior);
+    this.allProjects = allProjects;
+    this.mgr = mgr;
+    this.serverUser = serverUser;
+  }
+
+  @Override
+  protected void migrateData(ReviewDb db, UpdateUI ui)
+      throws OrmException, SQLException {
+    List<GroupReference> groups = Lists.newArrayList();
+    Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
+    try {
+      ResultSet rs = stmt.executeQuery(
+          "SELECT group_uuid, name FROM account_groups WHERE email_only_authors = 'Y'");
+      try {
+        while (rs.next()) {
+          AccountGroup.UUID uuid = new AccountGroup.UUID(rs.getString(1));
+          GroupReference group = new GroupReference(uuid, rs.getString(2));
+          groups.add(group);
+        }
+      } finally {
+        rs.close();
+      }
+    } finally {
+      stmt.close();
+    }
+
+    if (groups.isEmpty()) {
+      return;
+    }
+    ui.message("Moved account_groups.email_only_authors to 'Email Reviewers' capability");
+
+    Repository git;
+    try {
+      git = mgr.openRepository(allProjects);
+    } catch (RepositoryNotFoundException e) {
+      throw new OrmException(e);
+    }
+    try {
+      MetaDataUpdate md =
+          new MetaDataUpdate(new NoReplication(), allProjects, git);
+      md.getCommitBuilder().setAuthor(serverUser);
+      md.getCommitBuilder().setCommitter(serverUser);
+
+      ProjectConfig config = ProjectConfig.read(md);
+      AccessSection section =
+          config.getAccessSection(AccessSection.GLOBAL_CAPABILITIES, true);
+      Permission capability =
+          section.getPermission(GlobalCapability.EMAIL_REVIEWERS, true);
+      for (GroupReference group : groups) {
+        capability.getRule(config.resolve(group), true).setDeny();
+      }
+
+      md.setMessage("Upgrade to Gerrit Code Review schema 64\n");
+      if (!config.commit(md)) {
+        throw new OrmException("Cannot update " + allProjects);
+      }
+    } catch (IOException e) {
+      throw new OrmException(e);
+    } catch (ConfigInvalidException e) {
+      throw new OrmException(e);
+    } finally {
+      git.close();
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java
index 34c47a8..8cf2f26 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/ScriptRunner.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
 
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java
index ac07efd..64b3afa 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/UpdateUI.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.StatementExecutor;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.StatementExecutor;
 
 import java.util.List;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshInfo.java b/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshInfo.java
index 882181d..519b922 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshInfo.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshInfo.java
@@ -14,8 +14,6 @@
 
 package com.google.gerrit.server.ssh;
 
-import com.google.gerrit.server.ssh.SshInfo;
-
 import com.jcraft.jsch.HostKey;
 
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshKeyCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshKeyCache.java
index ad18b3f..6a07ca7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshKeyCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ssh/NoSshKeyCache.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.server.ssh;
 
 import com.google.gerrit.common.errors.InvalidSshKeyException;
-import com.google.gerrit.reviewdb.AccountSshKey;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
 
 class NoSshKeyCache implements SshKeyCache {
   @Override
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ssh/SshKeyCache.java b/gerrit-server/src/main/java/com/google/gerrit/server/ssh/SshKeyCache.java
index b56405a..13c5703 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ssh/SshKeyCache.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ssh/SshKeyCache.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.server.ssh;
 
 import com.google.gerrit.common.errors.InvalidSshKeyException;
-import com.google.gerrit.reviewdb.AccountSshKey;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
 
 /** Permits controlling the contents of the SSH key cache area. */
 public interface SshKeyCache {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/GuiceRequestScopePropagator.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/GuiceRequestScopePropagator.java
new file mode 100644
index 0000000..9befc7d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/GuiceRequestScopePropagator.java
@@ -0,0 +1,81 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.util;
+
+import com.google.common.collect.Maps;
+import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.RemotePeer;
+import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.inject.Inject;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.servlet.ServletScopes;
+import com.google.inject.util.Providers;
+import com.google.inject.util.Types;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.SocketAddress;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import javax.annotation.Nullable;
+
+/** Propagator for Guice's built-in servlet scope. */
+public class GuiceRequestScopePropagator extends RequestScopePropagator {
+
+  private final String url;
+  private final SocketAddress peer;
+  private final CurrentUser user;
+
+  @Inject
+  GuiceRequestScopePropagator(
+      @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+      @RemotePeer Provider<SocketAddress> remotePeerProvider,
+      Provider<CurrentUser> currentUserProvider) {
+    super(ServletScopes.REQUEST);
+    this.url = urlProvider != null ? urlProvider.get() : null;
+    this.peer = remotePeerProvider.get();
+    this.user = currentUserProvider.get();
+  }
+
+  /**
+   * @see RequestScopePropagator#wrap(Callable)
+   */
+  @Override
+  protected <T> Callable<T> wrapImpl(Callable<T> callable) {
+    Map<Key<?>, Object> seedMap = Maps.newHashMap();
+
+    // Request scopes appear to use specific keys in their map, instead of only
+    // providers. Add bindings for both the key to the instance directly and the
+    // provider to the instance to be safe.
+    seedMap.put(Key.get(typeOfProvider(String.class), CanonicalWebUrl.class),
+        Providers.of(url));
+    seedMap.put(Key.get(String.class, CanonicalWebUrl.class), url);
+
+    seedMap.put(Key.get(typeOfProvider(SocketAddress.class), RemotePeer.class),
+        Providers.of(peer));
+    seedMap.put(Key.get(SocketAddress.class, RemotePeer.class), peer);
+
+    seedMap.put(Key.get(typeOfProvider(CurrentUser.class)), Providers.of(user));
+    seedMap.put(Key.get(CurrentUser.class), user);
+
+    return ServletScopes.continueRequest(callable, seedMap);
+  }
+
+  private ParameterizedType typeOfProvider(Type type) {
+    return Types.newParameterizedType(Provider.class, type);
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/MagicBranch.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/MagicBranch.java
index ef08d78..510deaa02 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/MagicBranch.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/MagicBranch.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.server.util;
 
 import com.google.gerrit.common.data.Capable;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.Repository;
@@ -108,4 +108,4 @@
 
   private MagicBranch() {
   }
-}
\ No newline at end of file
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/MostSpecificComparator.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/MostSpecificComparator.java
new file mode 100644
index 0000000..804a7ec
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/MostSpecificComparator.java
@@ -0,0 +1,124 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.util;
+
+import com.google.gerrit.common.data.RefConfigSection;
+import com.google.gerrit.server.project.RefControl;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Comparator;
+
+/**
+ * Order the Ref Pattern by the most specific. This sort is done by:
+ * <ul>
+ * <li>1 - The minor value of Levenshtein string distance between the branch
+ * name and the regex string shortest example. A shorter distance is a more
+ * specific match.
+ * <li>2 - Finites first, infinities after.
+ * <li>3 - Number of transitions.
+ * <li>4 - Length of the expression text.
+ * </ul>
+ *
+ * Levenshtein distance is a measure of the similarity between two strings.
+ * The distance is the number of deletions, insertions, or substitutions
+ * required to transform one string into another.
+ *
+ * For example, if given refs/heads/m* and refs/heads/*, the distances are 5
+ * and 6. It means that refs/heads/m* is more specific because it's closer to
+ * refs/heads/master than refs/heads/*.
+ *
+ * Another example could be refs/heads/* and refs/heads/[a-zA-Z]*, the
+ * distances are both 6. Both are infinite, but refs/heads/[a-zA-Z]* has more
+ * transitions, which after all turns it more specific.
+ */
+public final class MostSpecificComparator implements
+    Comparator<RefConfigSection> {
+  private final String refName;
+
+  public MostSpecificComparator(String refName) {
+    this.refName = refName;
+  }
+
+  @Override
+  public int compare(RefConfigSection a, RefConfigSection b) {
+    return compare(a.getName(), b.getName());
+  }
+
+  public int compare(final String pattern1, final String pattern2) {
+    int cmp = distance(pattern1) - distance(pattern2);
+    if (cmp == 0) {
+      boolean p1_finite = finite(pattern1);
+      boolean p2_finite = finite(pattern2);
+
+      if (p1_finite && !p2_finite) {
+        cmp = -1;
+      } else if (!p1_finite && p2_finite) {
+        cmp = 1;
+      } else /* if (f1 == f2) */{
+        cmp = 0;
+      }
+    }
+    if (cmp == 0) {
+      cmp = transitions(pattern1) - transitions(pattern2);
+    }
+    if (cmp == 0) {
+      cmp = pattern2.length() - pattern1.length();
+    }
+    return cmp;
+  }
+
+  private int distance(String pattern) {
+    String example;
+    if (RefControl.isRE(pattern)) {
+      example = RefControl.shortestExample(pattern);
+
+    } else if (pattern.endsWith("/*")) {
+      example = pattern.substring(0, pattern.length() - 1) + '1';
+
+    } else if (pattern.equals(refName)) {
+      return 0;
+
+    } else {
+      return Math.max(pattern.length(), refName.length());
+    }
+    return StringUtils.getLevenshteinDistance(example, refName);
+  }
+
+  private boolean finite(String pattern) {
+    if (RefControl.isRE(pattern)) {
+      return RefControl.toRegExp(pattern).toAutomaton().isFinite();
+
+    } else if (pattern.endsWith("/*")) {
+      return false;
+
+    } else {
+      return true;
+    }
+  }
+
+  private int transitions(String pattern) {
+    if (RefControl.isRE(pattern)) {
+      return RefControl.toRegExp(pattern).toAutomaton()
+          .getNumberOfTransitions();
+
+    } else if (pattern.endsWith("/*")) {
+      return pattern.length();
+
+    } else {
+      return pattern.length();
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/RequestScopePropagator.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/RequestScopePropagator.java
new file mode 100644
index 0000000..3661aa2
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/RequestScopePropagator.java
@@ -0,0 +1,181 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.util;
+
+import com.google.gerrit.reviewdb.client.Project.NameKey;
+import com.google.gerrit.server.RequestCleanup;
+import com.google.gerrit.server.git.ProjectRunnable;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.Scope;
+import com.google.inject.servlet.ServletScopes;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+
+/**
+ * Base class for propagating request-scoped data between threads.
+ * <p>
+ * Request scopes are typically linked to a {@link ThreadLocal}, which is only
+ * available to the current thread.  In order to allow background work involving
+ * RequestScoped data, the ThreadLocal data must be copied from the request thread to
+ * the new background thread.
+ * <p>
+ * Every type of RequestScope must provide an implementation of
+ * RequestScopePropagator. See {@link #wrap(Callable)} for details on the
+ * implementation, usage, and restrictions.
+ *
+ * @see ThreadLocalRequestScopePropagator
+ */
+public abstract class RequestScopePropagator {
+
+  private final Scope scope;
+
+  protected RequestScopePropagator(Scope scope) {
+    this.scope = scope;
+  }
+
+  /**
+   * Wraps callable in a new {@link Callable} that propagates the current
+   * request state when the callable is invoked. The method must be called in a
+   * request scope and the returned Callable may only be invoked in a thread
+   * that is not already in a request scope. The returned Callable will inherit
+   * toString() from the passed in Callable. A
+   * {@link com.google.gerrit.server.git.WorkQueue.Executor} does not accept a
+   * Callable, so there is no ProjectCallable implementation. Implementations of
+   * this method must be consistent with Guice's
+   * {@link ServletScopes#continueRequest(Callable, java.util.Map)}.
+   * <p>
+   * There are some limitations:
+   * <ul>
+   * <li>Derived objects (i.e. anything marked created in a request scope) will
+   * not be transported.</li>
+   * <li>State changes to the request scoped context after this method is called
+   * will not be seen in the continued thread.</li>
+   * </ul>
+   *
+   * @param callable the Callable to wrap.
+   * @return a new Callable which will execute in the current request scope.
+   */
+  public final <T> Callable<T> wrap(final Callable<T> callable) {
+    final Callable<T> wrapped = wrapImpl(new Callable<T>() {
+      @Override
+      public T call() throws Exception {
+        RequestCleanup cleanup = scope.scope(
+            Key.get(RequestCleanup.class),
+            new Provider<RequestCleanup>() {
+              @Override
+              public RequestCleanup get() {
+                return new RequestCleanup();
+              }
+            }).get();
+
+        try {
+          return callable.call();
+        } finally {
+          cleanup.run();
+        }
+      }
+    });
+
+    return new Callable<T>() {
+      @Override
+      public T call() throws Exception {
+        return wrapped.call();
+      }
+
+      @Override
+      public String toString() {
+        return callable.toString();
+      }
+    };
+  }
+
+  /**
+   * Wraps runnable in a new {@link Runnable} that propagates the current
+   * request state when the runnable is invoked. The method must be called in a
+   * request scope and the returned Runnable may only be invoked in a thread
+   * that is not already in a request scope. The returned Runnable will inherit
+   * toString() from the passed in Runnable. Furthermore, if the passed runnable
+   * is of type {@link ProjectRunnable}, the returned runnable will be of the
+   * same type with the methods delegated.
+   *
+   * See {@link #wrap(Callable)} for details on implementation and usage.
+   *
+   * @param runnable the Runnable to wrap.
+   * @return a new Runnable which will execute in the current request scope.
+   */
+  public final Runnable wrap(final Runnable runnable) {
+    final Callable<Object> wrapped = wrap(Executors.callable(runnable));
+
+    if (runnable instanceof ProjectRunnable) {
+      return new ProjectRunnable() {
+        @Override
+        public void run() {
+          try {
+            wrapped.call();
+          } catch (RuntimeException e) {
+            throw e;
+          } catch (Exception e) {
+            throw new RuntimeException(e); // Not possible.
+          }
+        }
+
+        @Override
+        public NameKey getProjectNameKey() {
+          return ((ProjectRunnable) runnable).getProjectNameKey();
+        }
+
+        @Override
+        public String getRemoteName() {
+          return ((ProjectRunnable) runnable).getRemoteName();
+        }
+
+        @Override
+        public boolean hasCustomizedPrint() {
+          return ((ProjectRunnable) runnable).hasCustomizedPrint();
+        }
+
+        @Override
+        public String toString() {
+          return runnable.toString();
+        }
+      };
+    } else {
+      return new Runnable() {
+        @Override
+        public void run() {
+          try {
+            wrapped.call();
+          } catch (RuntimeException e) {
+            throw e;
+          } catch (Exception e) {
+            throw new RuntimeException(e); // Not possible.
+          }
+        }
+
+        @Override
+        public String toString() {
+          return runnable.toString();
+        }
+      };
+    }
+  }
+
+  /**
+   * @see #wrap(Callable)
+   */
+  protected abstract <T> Callable<T> wrapImpl(final Callable<T> callable);
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
index 3148aaa..7310703 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.util;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.SubmoduleSubscription;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
 import com.google.gerrit.server.git.GitRepositoryManager;
 
 import org.eclipse.jgit.lib.BlobBasedConfig;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestScopePropagator.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestScopePropagator.java
new file mode 100644
index 0000000..581ccc1
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/ThreadLocalRequestScopePropagator.java
@@ -0,0 +1,89 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.util;
+
+import com.google.inject.OutOfScopeException;
+import com.google.inject.Scope;
+
+import java.util.concurrent.Callable;
+
+/**
+ * {@link RequestScopePropagator} implementation for request scopes based on
+ * a {@link ThreadLocal} context.
+ *
+ * @param <C> "context" type stored in the {@link ThreadLocal}.
+ */
+public abstract class ThreadLocalRequestScopePropagator<C>
+    extends RequestScopePropagator {
+
+  private final ThreadLocal<C> threadLocal;
+
+  protected ThreadLocalRequestScopePropagator(Scope scope,
+      ThreadLocal<C> threadLocal) {
+    super(scope);
+    this.threadLocal = threadLocal;
+  }
+
+  /**
+   * @see RequestScopePropagator#wrap(Callable)
+   */
+  @Override
+  protected final <T> Callable<T> wrapImpl(final Callable<T> callable) {
+    final C ctx = continuingContext(requireContext());
+    return new Callable<T>() {
+      @Override
+      public T call() throws Exception {
+        if (threadLocal.get() != null) {
+          // This is consistent with the Guice ServletScopes.continueRequest()
+          // behavior.
+          throw new IllegalStateException("Cannot continue request, "
+              + "thread already has request in progress. A new thread must "
+              + "be used to propagate the request scope context.");
+        }
+
+        threadLocal.set(ctx);
+        try {
+          return callable.call();
+        } finally {
+          threadLocal.remove();
+        }
+      }
+    };
+  }
+
+  private C requireContext() {
+    C context = threadLocal.get();
+    if (context == null) {
+      throw new OutOfScopeException("Cannot access scoped object");
+    }
+    return context;
+  }
+
+  /**
+   * Returns a new context object based on the passed in context that has no
+   * request scoped objects initialized.
+   * <p>
+   * Note that some code paths expect request-scoped objects like
+   * {@code CurrentUser} to be constructible starting from just the context
+   * object returned by this method. For example, in the SSH scope, the context
+   * includes the {@code SshSession}, which is used by
+   * {@code SshCurrentUserProvider} to construct a new {@code CurrentUser} in
+   * the new thread.
+   *
+   * @param ctx the context to continue.
+   * @return a new context.
+   */
+  protected abstract C continuingContext(C ctx);
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TreeFormatter.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/TreeFormatter.java
similarity index 98%
rename from gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TreeFormatter.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/util/TreeFormatter.java
index 3aa83c3..1c68a75 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/TreeFormatter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/TreeFormatter.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.sshd.commands;
+package com.google.gerrit.server.util;
 
 import java.io.PrintWriter;
 import java.util.SortedSet;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java
index e475b13..f6f1bfb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/CategoryFunction.java
@@ -15,8 +15,9 @@
 package com.google.gerrit.server.workflow;
 
 import com.google.gerrit.common.data.ApprovalType;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+
 import java.util.HashMap;
 import java.util.Map;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java
index 2a871f7..d08bd1f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/FunctionState.java
@@ -18,12 +18,12 @@
 import com.google.gerrit.common.data.ApprovalTypes;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRange;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ApprovalCategory.Id;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.ApprovalCategory.Id;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.GroupCache;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxNoBlock.java b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxNoBlock.java
index 5f10c28..3272f8a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxNoBlock.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxNoBlock.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.workflow;
 
 import com.google.gerrit.common.data.ApprovalType;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 
 /**
  * Computes an {@link ApprovalCategory} by looking at maximum values.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxWithBlock.java b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxWithBlock.java
index 7bf7e9b..ce84499 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxWithBlock.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/workflow/MaxWithBlock.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.workflow;
 
 import com.google.gerrit.common.data.ApprovalType;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
 
 /**
  * Computes an {@link ApprovalCategory} by looking at maximum values.
diff --git a/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java b/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java
index 27bc286..ac74147 100644
--- a/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java
+++ b/gerrit-server/src/main/java/gerrit/AbstractCommitUserIdentityPredicate.java
@@ -14,8 +14,8 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.UserIdentity;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.UserIdentity;
 
 import com.googlecode.prolog_cafe.lang.IntegerTerm;
 import com.googlecode.prolog_cafe.lang.Operation;
diff --git a/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java b/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
index 8b35e12..c760426 100644
--- a/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED__load_commit_labels_1.java
@@ -4,12 +4,12 @@
 
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.rules.PrologEnvironment;
 import com.google.gerrit.rules.StoredValues;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 
 import com.googlecode.prolog_cafe.lang.IntegerTerm;
 import com.googlecode.prolog_cafe.lang.JavaException;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java
index 59ec28b..7cc9f35 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_branch_1.java
@@ -14,8 +14,8 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.rules.StoredValues;
 
 import com.googlecode.prolog_cafe.lang.Operation;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java
index 0be151a..09be902 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_owner_1.java
@@ -14,8 +14,8 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.rules.StoredValues;
 
 import com.googlecode.prolog_cafe.lang.IntegerTerm;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java
index 19f3e61..d1cd20d 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_project_1.java
@@ -14,8 +14,8 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.rules.StoredValues;
 
 import com.googlecode.prolog_cafe.lang.Operation;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java b/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java
index a7694c1..d200f7e 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_change_topic_1.java
@@ -14,7 +14,7 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.Change;
+import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.rules.StoredValues;
 
 import com.googlecode.prolog_cafe.lang.Operation;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java b/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java
index 142e51b..a0817a1 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_author_3.java
@@ -14,8 +14,8 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.UserIdentity;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.UserIdentity;
 import com.google.gerrit.rules.StoredValues;
 
 import com.googlecode.prolog_cafe.lang.Operation;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java b/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java
index c0f9ec3..78e6cf7 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_committer_3.java
@@ -14,8 +14,8 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.PatchSetInfo;
-import com.google.gerrit.reviewdb.UserIdentity;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.UserIdentity;
 import com.google.gerrit.rules.StoredValues;
 
 import com.googlecode.prolog_cafe.lang.Operation;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java b/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java
index 77bd81e..c2c2d1c 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java
@@ -14,7 +14,7 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.client.Patch;
 import com.google.gerrit.rules.StoredValues;
 import com.google.gerrit.server.patch.PatchList;
 import com.google.gerrit.server.patch.PatchListEntry;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java b/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java
index 8c94b34..0ed7443 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_commit_message_1.java
@@ -14,7 +14,7 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
 import com.google.gerrit.rules.StoredValues;
 
 import com.googlecode.prolog_cafe.lang.Operation;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java b/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java
index 516e873..23cedce 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_current_user_1.java
@@ -14,7 +14,7 @@
 
 package gerrit;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.rules.StoredValues;
 import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.CurrentUser;
diff --git a/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java b/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
index fe74f5d..0a15608 100644
--- a/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
+++ b/gerrit-server/src/main/java/gerrit/PRED_current_user_2.java
@@ -16,8 +16,8 @@
 
 import static com.googlecode.prolog_cafe.lang.SymbolTerm.intern;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.rules.PrologEnvironment;
 import com.google.gerrit.rules.StoredValues;
 import com.google.gerrit.server.AnonymousUser;
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/RebasedPatchSet.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/RebasedPatchSet.vm
new file mode 100644
index 0000000..e761627
--- /dev/null
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/RebasedPatchSet.vm
@@ -0,0 +1,54 @@
+## Copyright (C) 2012 The Android Open Source Project
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+##
+##
+## Template Type:
+## -------------
+## This is a velocity mail template, see: http://velocity.apache.org and the
+## gerrit-docs:config-mail.txt for more info on modifying gerrit mail templates.
+##
+## Template File Names and extensions:
+## ----------------------------------
+## Gerrit will use templates ending in ".vm" but will ignore templates ending
+## in ".vm.example".  If a .vm template does not exist, the default internal
+## gerrit template which is the same as the .vm.example will be used.  If you
+## want to override the default template, copy the .vm.example file to a .vm
+## file and edit it appropriately.
+##
+## This Template:
+## --------------
+## The RebasedPatchSet.vm template will determine the contents of the email
+## related to a user rebasing a patchset for a change through the Gerrit UI.
+## It is a ChangeEmail: see ChangeSubject.vm and ChangeFooter.vm.
+##
+#if($email.reviewerNames)
+Hello $email.joinStrings($email.reviewerNames, ', '),
+
+I'd like you to reexamine a rebased change.#if($email.changeUrl)  Please visit
+
+    $email.changeUrl
+
+to look at the new rebased patch set (#$patchSet.patchSetId).
+#end
+#else
+$fromName has created a new patch set by issuing a rebase in Gerrit (#$patchSet.patchSetId).
+#end
+
+Change subject: $change.subject
+......................................................................
+
+$email.changeDetail
+#if($email.sshHost)
+  git pull ssh://$email.sshHost/$projectName $patchSet.refName
+#end
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
index a0e3554..212ffb1 100644
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
+++ b/gerrit-server/src/main/resources/com/google/gerrit/server/tools/root/hooks/commit-msg
@@ -36,56 +36,126 @@
 		return
 	fi
 
+	# Does Change-Id: already exist? if so, exit (no change).
 	if grep -i '^Change-Id:' "$MSG" >/dev/null
 	then
 		return
 	fi
 
 	id=`_gen_ChangeId`
-	perl -e '
-		$MSG = shift;
-		$id = shift;
-		$CHANGE_ID_AFTER = shift;
+	T="$MSG.tmp.$$"
+	AWK=awk
+	if [ -x /usr/xpg4/bin/awk ]; then
+		# Solaris AWK is just too broken
+		AWK=/usr/xpg4/bin/awk
+	fi
 
-		undef $/;
-		open(I, $MSG); $_ = <I>; close I;
-		s|^diff --git a/.*||ms;
-		s|^#.*$||mg;
-		exit unless $_;
+	# How this works:
+	# - parse the commit message as (textLine+ blankLine*)*
+	# - assume textLine+ to be a footer until proven otherwise
+	# - exception: the first block is not footer (as it is the title)
+	# - read textLine+ into a variable
+	# - then count blankLines
+	# - once the next textLine appears, print textLine+ blankLine* as these
+	#   aren't footer
+	# - in END, the last textLine+ block is available for footer parsing
+	$AWK '
+	BEGIN {
+		# while we start with the assumption that textLine+
+		# is a footer, the first block is not.
+		isFooter = 0
+		footerComment = 0
+		blankLines = 0
+	}
 
-		@message = split /\n/;
-		$haveFooter = 0;
-		$startFooter = @message;
-		for($line = @message - 1; $line >= 0; $line--) {
-			$_ = $message[$line];
+	# Skip lines starting with "#" without any spaces before it.
+	/^#/ { next }
 
-			if (/^[a-zA-Z0-9-]+:/ && !m,^[a-z0-9-]+://,) {
-				$haveFooter++;
-				next;
+	# Skip the line starting with the diff command and everything after it,
+	# up to the end of the file, assuming it is only patch data.
+	# If more than one line before the diff was empty, strip all but one.
+	/^diff --git a/ {
+		blankLines = 0
+		while (getline) { }
+		next
+	}
+
+	# Count blank lines outside footer comments
+	/^$/ && (footerComment == 0) {
+		blankLines++
+		next
+	}
+
+	# Catch footer comment
+	/^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) {
+		footerComment = 1
+	}
+
+	/]$/ && (footerComment == 1) {
+		footerComment = 2
+	}
+
+	# We have a non-blank line after blank lines. Handle this.
+	(blankLines > 0) {
+		print lines
+		for (i = 0; i < blankLines; i++) {
+			print ""
+		}
+
+		lines = ""
+		blankLines = 0
+		isFooter = 1
+		footerComment = 0
+	}
+
+	# Detect that the current block is not the footer
+	(footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) {
+		isFooter = 0
+	}
+
+	{
+		# We need this information about the current last comment line
+		if (footerComment == 2) {
+			footerComment = 0
+		}
+		if (lines != "") {
+			lines = lines "\n";
+		}
+		lines = lines $0
+	}
+
+	# Footer handling:
+	# If the last block is considered a footer, splice in the Change-Id at the
+	# right place.
+	# Look for the right place to inject Change-Id by considering
+	# CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first,
+	# then Change-Id, then everything else (eg. Signed-off-by:).
+	#
+	# Otherwise just print the last block, a new line and the Change-Id as a
+	# block of its own.
+	END {
+		unprinted = 1
+		if (isFooter == 0) {
+			print lines "\n"
+			lines = ""
+		}
+		changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):"
+		numlines = split(lines, footer, "\n")
+		for (line = 1; line <= numlines; line++) {
+			if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) {
+				unprinted = 0
+				print "Change-Id: I'"$id"'"
 			}
-			next if /^[ []/;
-			$startFooter = $line if ($haveFooter && /^\r?$/);
-			last;
+			print footer[line]
 		}
-
-		@footer = @message[$startFooter+1..@message];
-		@message = @message[0..$startFooter];
-		push(@footer, "") unless @footer;
-
-		for ($line = 0; $line < @footer; $line++) {
-			$_ = $footer[$line];
-			next if /^($CHANGE_ID_AFTER):/i;
-			last;
+		if (unprinted) {
+			print "Change-Id: I'"$id"'"
 		}
-		splice(@footer, $line, 0, "Change-Id: I$id");
-
-		$_ = join("\n", @message, @footer);
-		open(O, ">$MSG"); print O; close O;
-	' "$MSG" "$id" "$CHANGE_ID_AFTER"
+	}' "$MSG" > $T && mv $T "$MSG" || rm -f $T
 }
 _gen_ChangeIdInput() {
 	echo "tree `git write-tree`"
-	if parent=`git rev-parse HEAD^0 2>/dev/null`
+	if parent=`git rev-parse "HEAD^0" 2>/dev/null`
 	then
 		echo "parent $parent"
 	fi
diff --git a/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java b/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
index 2b8dad5..9f2ccbf 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/rules/GerritCommonTest.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
 import com.google.inject.AbstractModule;
 
 import java.util.ArrayList;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
index 386a6d1..37197ec 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/config/ConfigUtilTest.java
@@ -15,7 +15,10 @@
 package com.google.gerrit.server.config;
 
 import static java.util.concurrent.TimeUnit.DAYS;
-import static java.util.concurrent.TimeUnit.*;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static java.util.concurrent.TimeUnit.SECONDS;
 
 import junit.framework.TestCase;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
index c5b5164..ca2b03a 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/ProjectConfigTest.java
@@ -25,8 +25,8 @@
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.data.Permission;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/PushReplicationTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/PushReplicationTest.java
index b95c7da..7ae705f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/PushReplicationTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/PushReplicationTest.java
@@ -14,7 +14,9 @@
 
 package com.google.gerrit.server.git;
 
-import static com.google.gerrit.server.git.PushReplication.ReplicationConfig.*;
+import static com.google.gerrit.server.git.PushReplication.ReplicationConfig.encode;
+import static com.google.gerrit.server.git.PushReplication.ReplicationConfig.needsUrlEncoding;
+
 import junit.framework.TestCase;
 
 import org.eclipse.jgit.transport.URIish;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
index e086070..b32d54c 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/git/SubmoduleOpTest.java
@@ -19,17 +19,17 @@
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SubmoduleSubscription;
-import com.google.gerrit.reviewdb.SubmoduleSubscriptionAccess;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.reviewdb.server.SubmoduleSubscriptionAccess;
 import com.google.gwtorm.client.KeyUtil;
-import com.google.gwtorm.client.ResultSet;
-import com.google.gwtorm.client.SchemaFactory;
-import com.google.gwtorm.client.impl.ListResultSet;
+import com.google.gwtorm.server.ListResultSet;
+import com.google.gwtorm.server.ResultSet;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.gwtorm.server.StandardKeyEncoder;
 import com.google.inject.Provider;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
index 2332eb6..29e3df0 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/mail/FromAddressGeneratorProviderTest.java
@@ -20,9 +20,9 @@
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
index 24f6f63..7df0696 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/patch/PatchListEntryTest.java
@@ -15,7 +15,7 @@
 
 package com.google.gerrit.server.patch;
 
-import com.google.gerrit.reviewdb.Patch;
+import com.google.gerrit.reviewdb.client.Patch;
 
 import junit.framework.TestCase;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
index 77775d8..cd6fa69 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/project/RefControlTest.java
@@ -20,36 +20,41 @@
 import static com.google.gerrit.common.data.Permission.READ;
 import static com.google.gerrit.common.data.Permission.SUBMIT;
 
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.PermissionRule;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountProjectWatch;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountProjectWatch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.rules.PrologEnvironment;
 import com.google.gerrit.rules.RulesCache;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.CapabilityControl;
 import com.google.gerrit.server.account.GroupCache;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.account.ListGroupMembership;
 import com.google.gerrit.server.cache.ConcurrentHashMapCache;
 import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gwtorm.client.SchemaFactory;
-import com.google.inject.AbstractModule;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
-import com.google.inject.assistedinject.FactoryProvider;
 
 import junit.framework.TestCase;
 
 import org.eclipse.jgit.lib.Config;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -306,18 +311,14 @@
       }
     };
 
-    Injector injector = Guice.createInjector(new AbstractModule() {
+    Injector injector = Guice.createInjector(new FactoryModule() {
       @Override
       protected void configure() {
-        bind(Config.class) //
-            .annotatedWith(GerritServerConfig.class) //
+        bind(Config.class)
+            .annotatedWith(GerritServerConfig.class)
             .toInstance(new Config());
 
-        bind(CapabilityControl.Factory.class)
-            .toProvider(FactoryProvider.newFactory(
-              CapabilityControl.Factory.class,
-              CapabilityControl.class));
-
+        factory(CapabilityControl.Factory.class);
         bind(ProjectCache.class).toInstance(projectCache);
       }
     });
@@ -416,18 +417,19 @@
 
   private class MockUser extends CurrentUser {
     private final String username;
-    private final Set<AccountGroup.UUID> groups;
+    private final GroupMembership groups;
 
     MockUser(String name, AccountGroup.UUID[] groupId) {
       super(RefControlTest.this.capabilityControlFactory, AccessPath.UNKNOWN);
       username = name;
-      groups = new HashSet<AccountGroup.UUID>(Arrays.asList(groupId));
-      groups.add(registered);
-      groups.add(anonymous);
+      ArrayList<AccountGroup.UUID> groupIds = Lists.newArrayList(groupId);
+      groupIds.add(registered);
+      groupIds.add(anonymous);
+      groups = new ListGroupMembership(groupIds);
     }
 
     @Override
-    public Set<AccountGroup.UUID> getEffectiveGroups() {
+    public GroupMembership getEffectiveGroups() {
       return groups;
     }
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java
index 3a390b5..ce7b25c 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/RegexFilePredicateTest.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.reviewdb.Change;
-import com.google.gwtorm.client.OrmException;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gwtorm.server.OrmException;
 
 import junit.framework.TestCase;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
index d31bd3c..8750ee4 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaCreatorTest.java
@@ -14,12 +14,12 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.testutil.InMemoryDatabase;
-import com.google.gwtorm.client.OrmException;
 import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
 
 import junit.framework.TestCase;
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
index 7d69672..39cbfe4 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.schema;
 
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.GerritPersonIdentProvider;
 import com.google.gerrit.server.config.AllProjectsName;
@@ -24,9 +24,9 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.LocalDiskRepositoryManager;
 import com.google.gerrit.testutil.InMemoryDatabase;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
-import com.google.gwtorm.client.StatementExecutor;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.gwtorm.server.StatementExecutor;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.TypeLiteral;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
index 0d84a93..17fe068 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
@@ -388,6 +388,25 @@
             "git://example.com/ fixes this\n"));
   }
 
+  @Test
+  public void testWithFalseTags() throws Exception {
+    assertEquals("foo\n" + //
+	"\n" + //
+	"FakeLine:\n" + //
+	"  foo\n" + //
+	"  bar\n" + //
+	"\n" + //
+	"Change-Id: I67632a37fd2e08a35f766f52fc9a47f4ea868c55\n" + //
+	"RealTag: abc\n", //
+	call("foo\n" + //
+	    "\n" + //
+	    "FakeLine:\n" + //
+	    "  foo\n" + //
+	    "  bar\n" + //
+	    "\n" + //
+	    "RealTag: abc\n"));
+  }
+
   private void hookDoesNotModify(final String in) throws Exception {
     assertEquals(in, call(in));
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
index b2c2fc9..c8e684f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/util/SubmoduleSectionParserTest.java
@@ -20,9 +20,9 @@
 import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.assertEquals;
 
-import com.google.gerrit.reviewdb.Branch;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.SubmoduleSubscription;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
 import com.google.gerrit.server.git.GitRepositoryManager;
 
 import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
index 82dcbea..a44f84f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryDatabase.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.testutil;
 
-import com.google.gerrit.reviewdb.CurrentSchemaVersion;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.GerritPersonIdentProvider;
 import com.google.gerrit.server.config.AllProjectsName;
@@ -27,10 +27,10 @@
 import com.google.gerrit.server.schema.Current;
 import com.google.gerrit.server.schema.SchemaCreator;
 import com.google.gerrit.server.schema.SchemaVersion;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
 import com.google.gwtorm.jdbc.Database;
 import com.google.gwtorm.jdbc.SimpleDataSource;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Key;
@@ -117,6 +117,9 @@
                   .annotatedWith(GerritPersonIdent.class) //
                   .toProvider(GerritPersonIdentProvider.class);
 
+              bind(AllProjectsName.class)
+                  .toInstance(new AllProjectsName("All-Projects"));
+
               bind(GitRepositoryManager.class) //
                   .to(LocalDiskRepositoryManager.class);
             }
diff --git a/gerrit-sshd/pom.xml b/gerrit-sshd/pom.xml
index c02e108..55e8725 100644
--- a/gerrit-sshd/pom.xml
+++ b/gerrit-sshd/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-sshd</artifactId>
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
index a72b50e..eb8a5c2 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
index 52a0277..a926e77 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.sshd;
 
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.NameKey;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.RequestCleanup;
@@ -60,9 +60,6 @@
   static final int STATUS_NOT_FOUND = PRIVATE_STATUS | 2;
   public static final int STATUS_NOT_ADMIN = PRIVATE_STATUS | 3;
 
-  @Option(name = "--help", usage = "display this help text", aliases = {"-h"})
-  private boolean help;
-
   @SuppressWarnings("unused")
   @Option(name = "--", usage = "end of options", handler = EndOfOptionsHandler.class)
   private boolean endOfOptions;
@@ -155,28 +152,37 @@
    * @see Argument
    */
   protected void parseCommandLine() throws UnloggedFailure {
-    final CmdLineParser clp = newCmdLineParser();
+    parseCommandLine(this);
+  }
+
+  /**
+   * Parses the command line argument, injecting parsed values into fields.
+   * <p>
+   * This method must be explicitly invoked to cause a parse.
+   *
+   * @param options object whose fields declare Option and Argument annotations
+   *        to describe the parameters of the command. Usually {@code this}.
+   * @throws UnloggedFailure if the command line arguments were invalid.
+   * @see Option
+   * @see Argument
+   */
+  protected void parseCommandLine(Object options) throws UnloggedFailure {
+    final CmdLineParser clp = newCmdLineParser(options);
     try {
       clp.parseArgument(argv);
     } catch (IllegalArgumentException err) {
-      if (!help) {
+      if (!clp.wasHelpRequestedByOption()) {
         throw new UnloggedFailure(1, "fatal: " + err.getMessage());
       }
     } catch (CmdLineException err) {
-      if (!help) {
+      if (!clp.wasHelpRequestedByOption()) {
         throw new UnloggedFailure(1, "fatal: " + err.getMessage());
       }
     }
 
-    if (help) {
-      final StringWriter msg = new StringWriter();
-      msg.write(commandName);
-      clp.printSingleLineUsage(msg, null);
-      msg.write('\n');
-
-      msg.write('\n');
-      clp.printUsage(msg, null);
-      msg.write('\n');
+    if (clp.wasHelpRequestedByOption()) {
+      StringWriter msg = new StringWriter();
+      clp.printDetailedUsage(commandName, msg);
       msg.write(usage());
       throw new UnloggedFailure(1, msg.toString());
     }
@@ -187,8 +193,8 @@
   }
 
   /** Construct a new parser for this command's received command line. */
-  protected CmdLineParser newCmdLineParser() {
-    return cmdLineParserFactory.create(this);
+  protected CmdLineParser newCmdLineParser(Object options) {
+    return cmdLineParserFactory.create(options);
   }
 
   /**
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
index fb17169..66e6add 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/CommandFactoryProvider.java
@@ -14,6 +14,8 @@
 
 package com.google.gerrit.sshd;
 
+import com.google.common.util.concurrent.Atomics;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.sshd.SshScope.Context;
@@ -36,6 +38,11 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Creates a CommandFactory using commands registered by {@link CommandModule}.
@@ -46,7 +53,8 @@
 
   private final DispatchCommandProvider dispatcher;
   private final SshLog log;
-  private final Executor startExecutor;
+  private final ScheduledExecutorService startExecutor;
+  private final Executor destroyExecutor;
 
   @Inject
   CommandFactoryProvider(
@@ -58,6 +66,11 @@
 
     int threads = cfg.getInt("sshd","commandStartThreads", 2);
     startExecutor = workQueue.createQueue(threads, "SshCommandStart");
+    destroyExecutor = Executors.newSingleThreadExecutor(
+        new ThreadFactoryBuilder()
+          .setNameFormat("SshCommandDestroy-%s")
+          .setDaemon(true)
+          .build());
   }
 
   @Override
@@ -79,11 +92,14 @@
     private Environment env;
     private Context ctx;
     private DispatchCommand cmd;
-    private boolean logged;
+    private final AtomicBoolean logged;
+    private final AtomicReference<Future<?>> task;
 
     Trampoline(final String cmdLine) {
       commandLine = cmdLine;
       argv = split(cmdLine);
+      logged = new AtomicBoolean();
+      task = Atomics.newReference();
     }
 
     public void setInputStream(final InputStream in) {
@@ -110,7 +126,7 @@
     public void start(final Environment env) throws IOException {
       this.env = env;
       final Context ctx = this.ctx;
-      startExecutor.execute(new Runnable() {
+      task.set(startExecutor.submit(new Runnable() {
         public void run() {
           try {
             onStart();
@@ -124,7 +140,7 @@
         public String toString() {
           return "start (user " + ctx.getSession().getUsername() + ")";
         }
-      });
+      }));
     }
 
     private void onStart() throws IOException {
@@ -173,16 +189,26 @@
     }
 
     private void log(final int rc) {
-      synchronized (this) {
-        if (!logged) {
-          log.onExecute(rc);
-          logged = true;
-        }
+      if (logged.compareAndSet(false, true)) {
+        log.onExecute(rc);
       }
     }
 
     @Override
     public void destroy() {
+      Future<?> future = task.getAndSet(null);
+      if (future != null) {
+        future.cancel(true);
+        destroyExecutor.execute(new Runnable() {
+          @Override
+          public void run() {
+            onDestroy();
+          }
+        });
+      }
+    }
+
+    private void onDestroy() {
       synchronized (this) {
         if (cmd != null) {
           final Context old = SshScope.set(ctx);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
index 805549e..a96a661 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd;
 
-import com.google.gerrit.reviewdb.AccountSshKey;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
index cc9d6ab..be513b3 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.ssh.SshInfo;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheEntry.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheEntry.java
index 81e019e..0d2f1fc 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheEntry.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheEntry.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.sshd;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountSshKey;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
 
 import java.security.PublicKey;
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
index c5f64f7..1f5ac28 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
@@ -14,18 +14,18 @@
 
 package com.google.gerrit.sshd;
 
-import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_USERNAME;
 
 import com.google.gerrit.common.errors.InvalidSshKeyException;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountSshKey;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.cache.Cache;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.cache.EntryCreator;
 import com.google.gerrit.server.ssh.SshKeyCache;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Singleton;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
index 32d5a07..923ac98 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
@@ -18,6 +18,7 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PeerDaemonUser;
+import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.util.IdGenerator;
 import com.google.gerrit.sshd.SshScope.Context;
@@ -33,6 +34,7 @@
 import org.apache.log4j.Logger;
 import org.apache.log4j.spi.ErrorHandler;
 import org.apache.log4j.spi.LoggingEvent;
+import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.util.QuotedString;
 
 import java.io.File;
@@ -59,7 +61,7 @@
 
   @Inject
   SshLog(final Provider<SshSession> session, final Provider<Context> context,
-      final SitePaths site) {
+      final SitePaths site, @GerritServerConfig Config config) {
     this.session = session;
     this.context = context;
 
@@ -77,7 +79,7 @@
 
     async = new AsyncAppender();
     async.setBlocking(true);
-    async.setBufferSize(64);
+    async.setBufferSize(config.getInt("core", "asyncLoggingBufferSize", 64));
     async.setLocationInfo(false);
     async.addAppender(dst);
     async.activateOptions();
@@ -99,7 +101,7 @@
   void onAuthFail(final SshSession sd) {
     final LoggingEvent event = new LoggingEvent( //
         Logger.class.getName(), // fqnOfCategoryClass
-        null, // logger (optional)
+        log, // logger
         System.currentTimeMillis(), // when
         Level.INFO, // level
         "AUTH FAILURE FROM " + sd.getRemoteAddressAsString(), // message text
@@ -168,7 +170,7 @@
 
     final LoggingEvent event = new LoggingEvent( //
         Logger.class.getName(), // fqnOfCategoryClass
-        null, // logger (optional)
+        log, // logger
         System.currentTimeMillis(), // when
         Level.INFO, // level
         msg, // message text
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 816955d..54b0bb5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -17,9 +17,9 @@
 import static com.google.inject.Scopes.SINGLETON;
 
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PeerDaemonUser;
@@ -32,6 +32,7 @@
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.ssh.SshInfo;
+import com.google.gerrit.server.util.RequestScopePropagator;
 import com.google.gerrit.sshd.args4j.AccountGroupIdHandler;
 import com.google.gerrit.sshd.args4j.AccountGroupUUIDHandler;
 import com.google.gerrit.sshd.args4j.AccountIdHandler;
@@ -39,14 +40,9 @@
 import com.google.gerrit.sshd.args4j.ProjectControlHandler;
 import com.google.gerrit.sshd.args4j.SocketAddressHandler;
 import com.google.gerrit.sshd.commands.DefaultCommandModule;
-import com.google.gerrit.sshd.commands.ProjectNode;
 import com.google.gerrit.sshd.commands.QueryShell;
 import com.google.gerrit.util.cli.CmdLineParser;
-import com.google.gerrit.util.cli.OptionHandlerFactory;
 import com.google.gerrit.util.cli.OptionHandlerUtil;
-import com.google.inject.Key;
-import com.google.inject.TypeLiteral;
-import com.google.inject.assistedinject.FactoryProvider;
 import com.google.inject.servlet.RequestScoped;
 
 import org.apache.sshd.common.KeyPairProvider;
@@ -61,6 +57,7 @@
   @Override
   protected void configure() {
     bindScope(RequestScoped.class, SshScope.REQUEST);
+    bind(RequestScopePropagator.class).to(SshScope.Propagator.class);
 
     configureRequestScope();
     configureCmdLineParser();
@@ -81,7 +78,6 @@
     bind(QueueProvider.class).to(CommandExecutorQueueProvider.class).in(SINGLETON);
     bind(AccountManager.class);
     factory(ChangeUserName.Factory.class);
-    factory(ProjectNode.Factory.class);
 
     bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class);
     bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);
@@ -129,14 +125,6 @@
 
   private <T> void registerOptionHandler(Class<T> type,
       Class<? extends OptionHandler<T>> impl) {
-    final Key<OptionHandlerFactory<T>> key = OptionHandlerUtil.keyFor(type);
-
-    final TypeLiteral<OptionHandlerFactory<T>> factoryType =
-        new TypeLiteral<OptionHandlerFactory<T>>() {};
-
-    final TypeLiteral<? extends OptionHandler<T>> implType =
-        TypeLiteral.get(impl);
-
-    bind(key).toProvider(FactoryProvider.newFactory(factoryType, implType));
+    install(OptionHandlerUtil.moduleFor(type, impl));
   }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
index d32d429..92609b5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshScope.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.sshd;
 
 import com.google.gerrit.server.RequestCleanup;
+import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator;
 import com.google.inject.Key;
 import com.google.inject.OutOfScopeException;
 import com.google.inject.Provider;
@@ -38,7 +39,7 @@
     volatile long started;
     volatile long finished;
 
-    Context(final SshSession s, final String c) {
+    private Context(final SshSession s, final String c, final long at) {
       cleanup = new RequestCleanup();
       session = s;
       commandLine = c;
@@ -46,25 +47,17 @@
       map = new HashMap<Key<?>, Object>();
       map.put(RC_KEY, cleanup);
 
-      final long now = System.currentTimeMillis();
-      created = now;
-      started = now;
-      finished = now;
+      created = started = finished = at;
     }
 
     private Context(Context p, SshSession s, String c) {
-      cleanup = new RequestCleanup();
-      session = s;
-      commandLine = c;
-
-      map = new HashMap<Key<?>, Object>();
-      map.put(RC_KEY, cleanup);
-
-      created = p.created;
+      this(s, c, p.created);
       started = p.started;
       finished = p.finished;
+    }
 
-      p.cleanup.add(cleanup);
+    Context(final SshSession s, final String c) {
+      this(s, c, System.currentTimeMillis());
     }
 
     String getCommandLine() {
@@ -86,28 +79,43 @@
     }
 
     synchronized Context subContext(SshSession newSession, String newCommandLine) {
-      return new Context(this, newSession, newCommandLine);
+      Context ctx = new Context(this, newSession, newCommandLine);
+      cleanup.add(ctx.cleanup);
+      return ctx;
     }
   }
 
   static class ContextProvider implements Provider<Context> {
     @Override
     public Context get() {
-      return getContext();
+      return requireContext();
     }
   }
 
   static class SshSessionProvider implements Provider<SshSession> {
     @Override
     public SshSession get() {
-      return getContext().getSession();
+      return requireContext().getSession();
+    }
+  }
+
+  static class Propagator extends ThreadLocalRequestScopePropagator<Context> {
+    Propagator() {
+      super(REQUEST, current);
+    }
+
+    @Override
+    protected Context continuingContext(Context ctx) {
+      // The cleanup is not chained, since the RequestScopePropagator executors
+      // the Context's cleanup when finished executing.
+      return new Context(ctx, ctx.getSession(), ctx.getCommandLine());
     }
   }
 
   private static final ThreadLocal<Context> current =
       new ThreadLocal<Context>();
 
-  private static Context getContext() {
+  private static Context requireContext() {
     final Context ctx = current.get();
     if (ctx == null) {
       throw new OutOfScopeException("Not in command/request");
@@ -126,7 +134,7 @@
     public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
       return new Provider<T>() {
         public T get() {
-          return getContext().get(key, creator);
+          return requireContext().get(key, creator);
         }
 
         @Override
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
index 65cfcdb..da245a3 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd;
 
-import com.google.gerrit.reviewdb.AccountSshKey;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.sshd.common.KeyPairProvider;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
index 199d210..492966e 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SuExec.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd;
 
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.AccessPath;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupIdHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupIdHandler.java
index f269541..307a10a 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupIdHandler.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupIdHandler.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.args4j;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
@@ -29,11 +29,10 @@
 public class AccountGroupIdHandler extends OptionHandler<AccountGroup.Id> {
   private final GroupCache groupCache;
 
-  @SuppressWarnings({"unchecked", "rawtypes"})
   @Inject
   public AccountGroupIdHandler(final GroupCache groupCache,
       @Assisted final CmdLineParser parser, @Assisted final OptionDef option,
-      @Assisted final Setter setter) {
+      @Assisted final Setter<AccountGroup.Id> setter) {
     super(parser, option, setter);
     this.groupCache = groupCache;
   }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupUUIDHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupUUIDHandler.java
index 90b4987..49bf695 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupUUIDHandler.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountGroupUUIDHandler.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.args4j;
 
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.GroupCache;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
@@ -29,11 +29,10 @@
 public class AccountGroupUUIDHandler extends OptionHandler<AccountGroup.UUID> {
   private final GroupCache groupCache;
 
-  @SuppressWarnings({"unchecked", "rawtypes"})
   @Inject
   public AccountGroupUUIDHandler(final GroupCache groupCache,
       @Assisted final CmdLineParser parser, @Assisted final OptionDef option,
-      @Assisted final Setter setter) {
+      @Assisted final Setter<AccountGroup.UUID> setter) {
     super(parser, option, setter);
     this.groupCache = groupCache;
   }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountIdHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountIdHandler.java
index 1f6454b..d54ae34 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountIdHandler.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/AccountIdHandler.java
@@ -14,14 +14,14 @@
 
 package com.google.gerrit.sshd.args4j;
 
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -37,13 +37,12 @@
   private final AccountManager accountManager;
   private final AuthType authType;
 
-  @SuppressWarnings({"unchecked", "rawtypes"})
   @Inject
   public AccountIdHandler(final AccountResolver accountResolver,
       final AccountManager accountManager,
       final AuthConfig authConfig,
       @Assisted final CmdLineParser parser, @Assisted final OptionDef option,
-      @Assisted final Setter setter) {
+      @Assisted final Setter<Account.Id> setter) {
     super(parser, option, setter);
     this.accountResolver = accountResolver;
     this.accountManager = accountManager;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/PatchSetIdHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/PatchSetIdHandler.java
index 847184d..2d6a4df 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/PatchSetIdHandler.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/PatchSetIdHandler.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.args4j;
 
-import com.google.gerrit.reviewdb.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
@@ -26,10 +26,10 @@
 import org.kohsuke.args4j.spi.Setter;
 
 public class PatchSetIdHandler extends OptionHandler<PatchSet.Id> {
-  @SuppressWarnings({"unchecked", "rawtypes"})
+
   @Inject
   public PatchSetIdHandler(@Assisted final CmdLineParser parser,
-      @Assisted final OptionDef option, @Assisted final Setter setter) {
+      @Assisted final OptionDef option, @Assisted final Setter<PatchSet.Id> setter) {
     super(parser, option, setter);
   }
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/ProjectControlHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/ProjectControlHandler.java
index 1e0c3a6..e0f7c4c 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/ProjectControlHandler.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/ProjectControlHandler.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.args4j;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.inject.Inject;
@@ -30,12 +30,11 @@
 public class ProjectControlHandler extends OptionHandler<ProjectControl> {
   private final ProjectControl.Factory projectControlFactory;
 
-  @SuppressWarnings({"unchecked", "rawtypes"})
   @Inject
   public ProjectControlHandler(
       final ProjectControl.Factory projectControlFactory,
       @Assisted final CmdLineParser parser, @Assisted final OptionDef option,
-      @Assisted final Setter setter) {
+      @Assisted final Setter<ProjectControl> setter) {
     super(parser, option, setter);
     this.projectControlFactory = projectControlFactory;
   }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SocketAddressHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SocketAddressHandler.java
index 50e41ae..454a084 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SocketAddressHandler.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SocketAddressHandler.java
@@ -28,10 +28,10 @@
 import java.net.SocketAddress;
 
 public class SocketAddressHandler extends OptionHandler<SocketAddress> {
-  @SuppressWarnings({"unchecked", "rawtypes"})
+
   @Inject
   public SocketAddressHandler(@Assisted final CmdLineParser parser,
-      @Assisted final OptionDef option, @Assisted final Setter setter) {
+      @Assisted final OptionDef option, @Assisted final Setter<SocketAddress> setter) {
     super(parser, option, setter);
   }
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SubcommandHandler.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SubcommandHandler.java
index 434230f..3df73a8 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SubcommandHandler.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/args4j/SubcommandHandler.java
@@ -25,10 +25,10 @@
 import org.kohsuke.args4j.spi.Setter;
 
 public class SubcommandHandler extends OptionHandler<String> {
-  @SuppressWarnings({"unchecked", "rawtypes"})
+
   @Inject
   public SubcommandHandler(@Assisted final CmdLineParser parser,
-      @Assisted final OptionDef option, @Assisted final Setter setter) {
+      @Assisted final OptionDef option, @Assisted final Setter<String> setter) {
     super(parser, option, setter);
   }
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
index f3bd051..950bf341 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminSetParent.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.commands;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
@@ -224,7 +224,7 @@
         // If we can't get it from the cache, pretend it's not present.
         break;
       }
-      p = getParentName(e.getProject());
+      p = e.getProject().getParent(allProjectsName);
     }
     return parents;
   }
@@ -238,28 +238,10 @@
         continue;
       }
 
-      if (parentName.equals(getParentName(e.getProject()))) {
+      if (parentName.equals(e.getProject().getParent(projectName))) {
         childProjects.add(e.getProject());
       }
     }
     return childProjects;
   }
-
-  /**
-   * Returns the project parent name.
-   *
-   * @return Project parent name, <code>null</code> for the 'All-Projects' root
-   *         project
-   */
-  private Project.NameKey getParentName(final Project project) {
-    if (project.getParent() != null) {
-      return project.getParent();
-    }
-
-    if (project.getNameKey().equals(allProjectsName)) {
-      return null;
-    }
-
-    return allProjectsName;
-  }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
index cc23d1d..a1b8988 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ApproveOption.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.sshd.commands;
 
 import com.google.gerrit.common.data.ApprovalType;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
 
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
index b46a2f2..38e0bcb 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateAccountCommand.java
@@ -15,20 +15,20 @@
 package com.google.gerrit.sshd.commands;
 
 import com.google.gerrit.common.errors.InvalidSshKeyException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountExternalId;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupMember;
-import com.google.gerrit.reviewdb.AccountGroupMemberAudit;
-import com.google.gerrit.reviewdb.AccountSshKey;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountExternalId;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.AccountGroupMember;
+import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.client.AccountSshKey;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountByEmailCache;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.ssh.SshKeyCache;
 import com.google.gerrit.sshd.BaseCommand;
-import com.google.gwtorm.client.OrmDuplicateKeyException;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import org.apache.sshd.server.Environment;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
index 05e6e59..98202e2 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateGroupCommand.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.common.errors.NameAlreadyUsedException;
 import com.google.gerrit.common.errors.PermissionDeniedException;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.account.PerformCreateGroup;
 import com.google.gerrit.sshd.BaseCommand;
 import com.google.inject.Inject;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
index f0327c5..a93cab1 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateProjectCommand.java
@@ -15,9 +15,9 @@
 package com.google.gerrit.sshd.commands;
 
 import com.google.gerrit.common.errors.ProjectCreationFailedException;
-import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.Project;
-import com.google.gerrit.reviewdb.Project.SubmitType;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.SubmitType;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.project.CreateProject;
 import com.google.gerrit.server.project.CreateProjectArgs;
@@ -32,7 +32,6 @@
 import org.kohsuke.args4j.Option;
 
 import java.io.PrintWriter;
-
 import java.util.List;
 
 /** Create a new project. **/
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
index 5cee06e..16461b6 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
@@ -36,7 +36,7 @@
 
     command(gerrit).toProvider(new DispatchCommandProvider(gerrit));
     command(gerrit, "flush-caches").to(FlushCaches.class);
-    command(gerrit, "ls-projects").to(ListProjects.class);
+    command(gerrit, "ls-projects").to(ListProjectsCommand.class);
     command(gerrit, "ls-groups").to(ListGroupsCommand.class);
     command(gerrit, "query").to(Query.class);
     command(gerrit, "show-caches").to(ShowCaches.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
index fd34ab5..e0b988e 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListGroupsCommand.java
@@ -17,13 +17,13 @@
 import com.google.gerrit.common.data.GroupDetail;
 import com.google.gerrit.common.data.GroupList;
 import com.google.gerrit.common.errors.NoSuchGroupException;
-import com.google.gerrit.server.account.VisibleGroups;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.VisibleGroups;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.sshd.BaseCommand;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import org.apache.sshd.server.Environment;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjectsCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjectsCommand.java
new file mode 100644
index 0000000..d0bbc72
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ListProjectsCommand.java
@@ -0,0 +1,43 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.sshd.commands;
+
+import com.google.gerrit.server.project.ListProjects;
+import com.google.gerrit.sshd.BaseCommand;
+import com.google.inject.Inject;
+
+import org.apache.sshd.server.Environment;
+
+final class ListProjectsCommand extends BaseCommand {
+  @Inject
+  private ListProjects impl;
+
+  @Override
+  public void start(final Environment env) {
+    startThread(new CommandRunnable() {
+      @Override
+      public void run() throws Exception {
+        parseCommandLine(impl);
+        if (impl.isShowTree() && (impl.getShowBranch() != null)) {
+          throw new UnloggedFailure(1, "fatal: --tree and --show-branch options are not compatible.");
+        }
+        if (impl.isShowTree() && impl.isShowDescription()) {
+          throw new UnloggedFailure(1, "fatal: --tree and --description options are not compatible.");
+        }
+        impl.display(out);
+      }
+    });
+  }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
index 9bca0e5..d9a1c3f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
@@ -66,6 +66,11 @@
     processor.setIncludeCommitMessage(on);
   }
 
+  @Option(name = "--dependencies", usage = "Include depends-on and needed-by information")
+  void setDependencies(boolean on) {
+    processor.setIncludeDependencies(on);
+  }
+
   @Argument(index = 0, required = true, multiValued = true, metaVar = "QUERY", usage = "Query to execute")
   private List<String> query;
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
index e68c747..18ce77f 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/QueryShell.java
@@ -15,11 +15,11 @@
 package com.google.gerrit.sshd.commands;
 
 import com.google.gerrit.common.Version;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gson.JsonObject;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
 import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
index c2b5e9c..85f53bf 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
@@ -15,21 +15,24 @@
 package com.google.gerrit.sshd.commands;
 
 import com.google.gerrit.common.data.Capable;
-import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.git.AsyncReceiveCommits;
 import com.google.gerrit.server.git.ReceiveCommits;
 import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.server.git.VisibleRefFilter;
 import com.google.gerrit.sshd.AbstractGitCommand;
 import com.google.inject.Inject;
 
+import org.eclipse.jgit.errors.TooLargeObjectInPackException;
 import org.eclipse.jgit.errors.UnpackException;
 import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.transport.AdvertiseRefsHook;
 import org.eclipse.jgit.transport.ReceivePack;
-import org.eclipse.jgit.transport.RefFilter;
 import org.kohsuke.args4j.Option;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -39,7 +42,7 @@
 /** Receives change upload over SSH using the Git receive-pack protocol. */
 final class Receive extends AbstractGitCommand {
   @Inject
-  private ReceiveCommits.Factory factory;
+  private AsyncReceiveCommits.Factory factory;
 
   @Inject
   private IdentifiedUser currentUser;
@@ -69,7 +72,8 @@
       throw new Failure(1, "fatal: receive-pack not permitted on this server");
     }
 
-    final ReceiveCommits receive = factory.create(projectControl, repo);
+    final ReceiveCommits receive = factory.create(projectControl, repo)
+        .getReceiveCommits();
 
     Capable r = receive.canUpload();
     if (r != Capable.OK) {
@@ -90,6 +94,15 @@
       receive.advertiseHistory();
       rp.receive(in, out, err);
     } catch (UnpackException badStream) {
+      // In case this was caused by the user pushing an object whose size
+      // is larger than the receive.maxObjectSizeLimit gerrit.config parameter
+      // we want to present this error to the user
+      if (badStream.getCause() instanceof TooLargeObjectInPackException) {
+        PrintWriter p = toPrintWriter(err);
+        p.print("error: " + badStream.getCause().getMessage() + "\n");
+        p.flush();
+      }
+
       // This may have been triggered by branch level access controls.
       // Log what the heck is going on, as detailed as we can.
       //
@@ -97,17 +110,17 @@
       msg.append("Unpack error on project \""
           + projectControl.getProject().getName() + "\":\n");
 
-      msg.append("  RefFilter: " + rp.getRefFilter());
-      if (rp.getRefFilter() == RefFilter.DEFAULT) {
+      msg.append("  AdvertiseRefsHook: " + rp.getAdvertiseRefsHook());
+      if (rp.getAdvertiseRefsHook() == AdvertiseRefsHook.DEFAULT) {
         msg.append("DEFAULT");
-      } else if (rp.getRefFilter() instanceof VisibleRefFilter) {
+      } else if (rp.getAdvertiseRefsHook() instanceof VisibleRefFilter) {
         msg.append("VisibleRefFilter");
       } else {
-        msg.append(rp.getRefFilter().getClass());
+        msg.append(rp.getAdvertiseRefsHook().getClass());
       }
       msg.append("\n");
 
-      if (rp.getRefFilter() instanceof VisibleRefFilter) {
+      if (rp.getAdvertiseRefsHook() instanceof VisibleRefFilter) {
         Map<String, Ref> adv = rp.getAdvertisedRefs();
         msg.append("  Visible references (" + adv.size() + "):\n");
         for (Ref ref : adv.values()) {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
index b6d5bf5..5b6cf39 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
@@ -18,7 +18,7 @@
 import com.google.gerrit.common.errors.NoSuchGroupException;
 import com.google.gerrit.server.account.PerformRenameGroup;
 import com.google.gerrit.sshd.BaseCommand;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 
 import org.apache.sshd.server.Environment;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java
index 9dc8671..bc4e0bb 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Replicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.commands;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.PushAllProjectsOp;
 import com.google.gerrit.server.git.ReplicationQueue;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
index 8eb6058..640adbf 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java
@@ -17,14 +17,12 @@
 import com.google.gerrit.common.data.ApprovalType;
 import com.google.gerrit.common.data.ApprovalTypes;
 import com.google.gerrit.common.data.ReviewResult;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.changedetail.AbandonChange;
 import com.google.gerrit.server.changedetail.DeleteDraftPatchSet;
 import com.google.gerrit.server.changedetail.PublishDraft;
@@ -32,15 +30,13 @@
 import com.google.gerrit.server.changedetail.Submit;
 import com.google.gerrit.server.mail.EmailException;
 import com.google.gerrit.server.patch.PublishComments;
-import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectControl;
-import com.google.gerrit.server.workflow.FunctionState;
 import com.google.gerrit.sshd.BaseCommand;
 import com.google.gerrit.util.cli.CmdLineParser;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 
 import org.apache.sshd.server.Environment;
@@ -61,8 +57,8 @@
       LoggerFactory.getLogger(ReviewCommand.class);
 
   @Override
-  protected final CmdLineParser newCmdLineParser() {
-    final CmdLineParser parser = super.newCmdLineParser();
+  protected final CmdLineParser newCmdLineParser(Object options) {
+    final CmdLineParser parser = super.newCmdLineParser(options);
     for (ApproveOption c : optionList) {
       parser.addOption(c, c);
     }
@@ -111,24 +107,15 @@
   private ReviewDb db;
 
   @Inject
-  private IdentifiedUser currentUser;
-
-  @Inject
   private ApprovalTypes approvalTypes;
 
   @Inject
-  private ChangeControl.Factory changeControlFactory;
-
-  @Inject
   private DeleteDraftPatchSet.Factory deleteDraftPatchSetFactory;
 
   @Inject
   private AbandonChange.Factory abandonChangeFactory;
 
   @Inject
-  private FunctionState.Factory functionStateFactory;
-
-  @Inject
   private PublishComments.Factory publishCommentsFactory;
 
   @Inject
@@ -205,10 +192,6 @@
   private void approveOne(final PatchSet.Id patchSetId) throws
       NoSuchChangeException, OrmException, EmailException, Failure {
 
-    final Change.Id changeId = patchSetId.getParentKey();
-
-    ChangeControl changeControl = changeControlFactory.validateFor(changeId);
-
     if (changeComment == null) {
       changeComment = "";
     }
@@ -217,7 +200,6 @@
     for (ApproveOption ao : optionList) {
       Short v = ao.value();
       if (v != null) {
-        assertScoreIsAllowed(patchSetId, changeControl, ao, v);
         aps.add(new ApprovalCategoryValue.Id(ao.getCategoryId(), v));
       }
     }
@@ -362,22 +344,6 @@
     return projectControl.getProject().getNameKey().equals(change.getProject());
   }
 
-  private void assertScoreIsAllowed(final PatchSet.Id patchSetId,
-      final ChangeControl changeControl, ApproveOption ao, Short v)
-      throws UnloggedFailure {
-    final PatchSetApproval psa =
-        new PatchSetApproval(new PatchSetApproval.Key(patchSetId, currentUser
-            .getAccountId(), ao.getCategoryId()), v);
-    final FunctionState fs =
-        functionStateFactory.create(changeControl, patchSetId,
-            Collections.<PatchSetApproval> emptyList());
-    psa.setValue(v);
-    fs.normalize(approvalTypes.byId(psa.getCategoryId()), psa);
-    if (v != psa.getValue()) {
-      throw error(ao.name() + "=" + ao.value() + " not permitted");
-    }
-  }
-
   private void initOptionList() {
     optionList = new ArrayList<ApproveOption>();
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
index 985c2d5..6e1a32b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetReviewersCommand.java
@@ -15,19 +15,19 @@
 package com.google.gerrit.sshd.commands;
 
 import com.google.gerrit.common.data.ReviewerResult;
-import com.google.gerrit.reviewdb.Account;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.RevId;
-import com.google.gerrit.reviewdb.ReviewDb;
+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.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.patch.AddReviewer;
 import com.google.gerrit.server.patch.RemoveReviewer;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.sshd.BaseCommand;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.ResultSet;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 
 import org.apache.sshd.server.Environment;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java
index 80a6c11..e835ffe 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowQueue.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.commands;
 
-import com.google.gerrit.reviewdb.Project;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.git.WorkQueue.ProjectTask;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
index b072abf..46eb788 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.sshd.commands;
 
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.TagCache;
 import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.server.git.VisibleRefFilter;
@@ -45,8 +45,8 @@
 
     final UploadPack up = new UploadPack(repo);
     if (!projectControl.allRefsAreVisible()) {
-      up.setRefFilter(new VisibleRefFilter(tagCache, repo, projectControl,
-          db.get(), true));
+      up.setAdvertiseRefsHook(new VisibleRefFilter(tagCache, repo,
+          projectControl, db.get(), true));
     }
     up.setPackConfig(config.getPackConfig());
     up.setTimeout(config.getTimeout());
diff --git a/gerrit-util-cli/pom.xml b/gerrit-util-cli/pom.xml
index 401a2ba..4ecbda4 100644
--- a/gerrit-util-cli/pom.xml
+++ b/gerrit-util-cli/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-util-cli</artifactId>
@@ -39,12 +39,12 @@
     </dependency>
 
     <dependency>
-      <groupId>com.google.code.guice</groupId>
+      <groupId>com.google.inject</groupId>
       <artifactId>guice</artifactId>
     </dependency>
 
     <dependency>
-      <groupId>com.google.code.guice</groupId>
+      <groupId>com.google.inject.extensions</groupId>
       <artifactId>guice-assistedinject</artifactId>
     </dependency>
   </dependencies>
diff --git a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
index d5a2a98..de2f7e9 100644
--- a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
+++ b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/CmdLineParser.java
@@ -42,13 +42,19 @@
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.IllegalAnnotationError;
+import org.kohsuke.args4j.NamedOptionDef;
 import org.kohsuke.args4j.Option;
 import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.spi.BooleanOptionHandler;
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Setter;
 
+import java.io.StringWriter;
 import java.io.Writer;
+import java.lang.annotation.Annotation;
 import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 import java.util.ResourceBundle;
 
 /**
@@ -60,6 +66,7 @@
  * args4j style format prior to invoking args4j for parsing.
  */
 public class CmdLineParser {
+
   public interface Factory {
     CmdLineParser create(Object bean);
   }
@@ -102,6 +109,19 @@
     parser.printUsage(out, rb);
   }
 
+  public void printDetailedUsage(String name, StringWriter out) {
+    out.write(name);
+    printSingleLineUsage(out, null);
+    out.write('\n');
+    out.write('\n');
+    printUsage(out, null);
+    out.write('\n');
+  }
+
+  public boolean wasHelpRequestedByOption() {
+    return parser.help.value;
+  }
+
   public void parseArgument(final String... args) throws CmdLineException {
     final ArrayList<String> tmp = new ArrayList<String>(args.length);
     for (int argi = 0; argi < args.length; argi++) {
@@ -123,13 +143,86 @@
 
       tmp.add(str);
     }
-
     parser.parseArgument(tmp.toArray(new String[tmp.size()]));
   }
 
+  public void parseOptionMap(Map<String, String[]> parameters)
+      throws CmdLineException {
+    ArrayList<String> tmp = new ArrayList<String>();
+    for (Map.Entry<String, String[]> ent : parameters.entrySet()) {
+      String name = ent.getKey();
+      if (!name.startsWith("-")) {
+        if (name.length() == 1) {
+          name = "-" + name;
+        } else {
+          name = "--" + name;
+        }
+      }
+
+      if (findHandler(name) instanceof BooleanOptionHandler) {
+        boolean on = false;
+        for (String value : ent.getValue()) {
+          on = toBoolean(ent.getKey(), value);
+        }
+        if (on) {
+          tmp.add(name);
+        }
+      } else {
+        for (String value : ent.getValue()) {
+          tmp.add(name);
+          tmp.add(value);
+        }
+      }
+    }
+    parser.parseArgument(tmp.toArray(new String[tmp.size()]));
+  }
+
+  @SuppressWarnings("rawtypes")
+  private OptionHandler findHandler(String name) {
+    for (OptionHandler handler : parser.options) {
+      if (handler.option instanceof NamedOptionDef) {
+        NamedOptionDef def = (NamedOptionDef) handler.option;
+        if (name.equals(def.name())) {
+          return handler;
+        }
+        for (String alias : def.aliases()) {
+          if (name.equals(alias)) {
+            return handler;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  private boolean toBoolean(String name, String value) throws CmdLineException {
+    if ("true".equals(value) || "t".equals(value)
+        || "yes".equals(value) || "y".equals(value)
+        || "on".equals(value)
+        || "1".equals(value)
+        || value == null || "".equals(value)) {
+      return true;
+    }
+
+    if ("false".equals(value) || "f".equals(value)
+        || "no".equals(value) || "n".equals(value)
+        || "off".equals(value)
+        || "0".equals(value)) {
+      return false;
+    }
+
+    throw new CmdLineException(parser, String.format(
+        "invalid boolean \"%s=%s\"", name, value));
+  }
+
   private class MyParser extends org.kohsuke.args4j.CmdLineParser {
+    @SuppressWarnings("rawtypes")
+    private List<OptionHandler> options;
+    private HelpOption help;
+
     MyParser(final Object bean) {
       super(bean);
+      ensureOptionsInitialized();
     }
 
     @SuppressWarnings({"unchecked", "rawtypes"})
@@ -137,7 +230,7 @@
     protected OptionHandler createOptionHandler(final OptionDef option,
         final Setter setter) {
       if (isHandlerSpecified(option) || isEnum(setter) || isPrimitive(setter)) {
-        return super.createOptionHandler(option, setter);
+        return add(super.createOptionHandler(option, setter));
       }
 
       final Key<OptionHandlerFactory<?>> key =
@@ -145,12 +238,28 @@
       Injector i = injector;
       while (i != null) {
         if (i.getBindings().containsKey(key)) {
-          return i.getInstance(key).create(this, option, setter);
+          return add(i.getInstance(key).create(this, option, setter));
         }
         i = i.getParent();
       }
 
-      return super.createOptionHandler(option, setter);
+      return add(super.createOptionHandler(option, setter));
+    }
+
+    @SuppressWarnings("rawtypes")
+    private OptionHandler add(OptionHandler handler) {
+      ensureOptionsInitialized();
+      options.add(handler);
+      return handler;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private void ensureOptionsInitialized() {
+      if (options == null) {
+        help = new HelpOption();
+        options = new ArrayList<OptionHandler>();
+        addOption(help, help);
+      }
     }
 
     private boolean isHandlerSpecified(final OptionDef option) {
@@ -165,4 +274,63 @@
       return setter.getType().isPrimitive();
     }
   }
+
+  private static class HelpOption implements Option, Setter<Boolean> {
+    private boolean value;
+
+    @Override
+    public String name() {
+      return "--help";
+    }
+
+    @Override
+    public String[] aliases() {
+      return new String[] {"-h"};
+    }
+
+    @Override
+    public String usage() {
+      return "display this help text";
+    }
+
+    @Override
+    public void addValue(Boolean val) {
+      value = val;
+    }
+
+    @Override
+    public Class<? extends OptionHandler<Boolean>> handler() {
+      return BooleanOptionHandler.class;
+    }
+
+    @Override
+    public String metaVar() {
+      return "";
+    }
+
+    @Override
+    public boolean multiValued() {
+      return false;
+    }
+
+    @Override
+    public boolean required() {
+      return false;
+    }
+
+    @Override
+    public Class<? extends Annotation> annotationType() {
+      return Option.class;
+    }
+
+    @Override
+    public Class<Boolean> getType() {
+      return Boolean.class;
+    }
+
+    @Override
+    public boolean isMultiValued() {
+      return multiValued();
+    }
+  }
 }
diff --git a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerFactory.java b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerFactory.java
index 0009d05..8e99778 100644
--- a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerFactory.java
+++ b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerFactory.java
@@ -20,7 +20,6 @@
 
 /** Creates an args4j OptionHandler through a Guice Injector. */
 public interface OptionHandlerFactory<T> {
-  @SuppressWarnings("rawtypes")
-  OptionHandler create(org.kohsuke.args4j.CmdLineParser cmdLineParser,
-      OptionDef optionDef, Setter setter);
+  OptionHandler<T> create(org.kohsuke.args4j.CmdLineParser cmdLineParser,
+      OptionDef optionDef, Setter<T> setter);
 }
diff --git a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerUtil.java b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerUtil.java
index ab67397..7af544c 100644
--- a/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerUtil.java
+++ b/gerrit-util-cli/src/main/java/com/google/gerrit/util/cli/OptionHandlerUtil.java
@@ -15,8 +15,11 @@
 package com.google.gerrit.util.cli;
 
 import com.google.inject.Key;
-import com.google.inject.TypeLiteral;
-import com.google.inject.internal.MoreTypes.ParameterizedTypeImpl;
+import com.google.inject.Module;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+import com.google.inject.util.Types;
+
+import org.kohsuke.args4j.spi.OptionHandler;
 
 import java.lang.reflect.Type;
 
@@ -25,10 +28,21 @@
   /** Generate a key for an {@link OptionHandlerFactory} in Guice. */
   @SuppressWarnings("unchecked")
   public static <T> Key<OptionHandlerFactory<T>> keyFor(final Class<T> valueType) {
-    final Type factoryType =
-        new ParameterizedTypeImpl(null, OptionHandlerFactory.class, valueType);
+    final Type factoryType = Types.newParameterizedType(OptionHandlerFactory.class, valueType);
+    return (Key<OptionHandlerFactory<T>>) Key.get(factoryType);
+  }
 
-    return (Key<OptionHandlerFactory<T>>) Key.get(TypeLiteral.get(factoryType));
+  @SuppressWarnings("unchecked")
+  private static <T> Key<OptionHandler<T>> handlerOf(Class<T> type) {
+    final Type handlerType = Types.newParameterizedTypeWithOwner(null, OptionHandler.class, type);
+    return (Key<OptionHandler<T>>) Key.get(handlerType);
+  }
+
+  @SuppressWarnings("unchecked")
+  public static <T> Module moduleFor(final Class<T> type, Class<? extends OptionHandler<T>> impl) {
+    return new FactoryModuleBuilder()
+        .implement(handlerOf(type), impl)
+        .build(keyFor(type));
   }
 
   private OptionHandlerUtil() {
diff --git a/gerrit-util-ssl/pom.xml b/gerrit-util-ssl/pom.xml
index eefca62..2e49d47 100644
--- a/gerrit-util-ssl/pom.xml
+++ b/gerrit-util-ssl/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-util-ssl</artifactId>
diff --git a/gerrit-war/pom.xml b/gerrit-war/pom.xml
index ad58440..733d976a 100644
--- a/gerrit-war/pom.xml
+++ b/gerrit-war/pom.xml
@@ -22,7 +22,7 @@
   <parent>
     <groupId>com.google.gerrit</groupId>
     <artifactId>gerrit-parent</artifactId>
-    <version>2.3-SNAPSHOT</version>
+    <version>2.4-SNAPSHOT</version>
   </parent>
 
   <artifactId>gerrit-war</artifactId>
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
index 3bbcc98..b97df3f 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/SitePathFromSystemConfigProvider.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.httpd;
 
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.reviewdb.SystemConfig;
+import com.google.gerrit.reviewdb.client.SystemConfig;
+import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.SitePath;
-import com.google.gwtorm.client.OrmException;
-import com.google.gwtorm.client.SchemaFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index ecb0977..01b4a44 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -22,7 +22,7 @@
 import com.google.gerrit.httpd.auth.openid.OpenIdModule;
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.gerrit.reviewdb.AuthType;
+import com.google.gerrit.reviewdb.client.AuthType;
 import com.google.gerrit.server.config.AuthConfig;
 import com.google.gerrit.server.config.AuthConfigModule;
 import com.google.gerrit.server.config.CanonicalWebUrlModule;
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.contact.HttpContactStoreConnection;
 import com.google.gerrit.server.git.LocalDiskRepositoryManager;
 import com.google.gerrit.server.git.PushReplication;
+import com.google.gerrit.server.git.ReceiveCommitsExecutorModule;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
 import com.google.gerrit.server.mail.SmtpEmailSender;
@@ -190,6 +191,7 @@
     final List<Module> modules = new ArrayList<Module>();
     modules.add(new WorkQueue.Module());
     modules.add(new ChangeHookRunner.Module());
+    modules.add(new ReceiveCommitsExecutorModule());
     modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
     modules.add(new EhcachePoolImpl.Module());
     modules.add(new SmtpEmailSender.Module());
diff --git a/pom.xml b/pom.xml
index f3f7c64..1933329 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
   <groupId>com.google.gerrit</groupId>
   <artifactId>gerrit-parent</artifactId>
   <packaging>pom</packaging>
-  <version>2.3-SNAPSHOT</version>
+  <version>2.4-SNAPSHOT</version>
 
   <name>Gerrit Code Review - Parent</name>
   <url>http://code.google.com/p/gerrit/</url>
@@ -46,13 +46,13 @@
   </issueManagement>
 
   <properties>
-    <jgitVersion>1.1.0.201109151100-r.141-gcd958ba</jgitVersion>
-    <gwtormVersion>1.2</gwtormVersion>
-    <gwtjsonrpcVersion>1.2.5</gwtjsonrpcVersion>
+    <jgitVersion>1.3.0.201202151440-r.75-gff13648</jgitVersion>
+    <gwtormVersion>1.4</gwtormVersion>
+    <gwtjsonrpcVersion>1.3</gwtjsonrpcVersion>
     <gwtexpuiVersion>1.2.5</gwtexpuiVersion>
     <gwtVersion>2.3.0</gwtVersion>
     <slf4jVersion>1.6.1</slf4jVersion>
-    <guiceVersion>2.0</guiceVersion>
+    <guiceVersion>3.0</guiceVersion>
     <jettyVersion>7.2.1.v20101111</jettyVersion>
 
     <gwt.compileReport>false</gwt.compileReport>
@@ -486,6 +486,11 @@
         <type>pom</type>
         <exclusions>
           <exclusion>
+            <!-- conflicts with our use of guice 3.0 -->
+            <groupId>com.google.code.guice</groupId>
+            <artifactId>guice</artifactId>
+          </exclusion>
+          <exclusion>
             <!-- jug-1.1 is LGPL, and the source has been lost -->
             <groupId>jug</groupId>
             <artifactId>jug</artifactId>
@@ -557,19 +562,19 @@
       </dependency>
 
       <dependency>
-        <groupId>com.google.code.guice</groupId>
+        <groupId>com.google.inject</groupId>
         <artifactId>guice</artifactId>
         <version>${guiceVersion}</version>
       </dependency>
 
       <dependency>
-        <groupId>com.google.code.guice</groupId>
+        <groupId>com.google.inject.extensions</groupId>
         <artifactId>guice-servlet</artifactId>
         <version>${guiceVersion}</version>
       </dependency>
 
       <dependency>
-        <groupId>com.google.code.guice</groupId>
+        <groupId>com.google.inject.extensions</groupId>
         <artifactId>guice-assistedinject</artifactId>
         <version>${guiceVersion}</version>
       </dependency>
diff --git a/tools/gitlog2asciidoc.py b/tools/gitlog2asciidoc.py
new file mode 100755
index 0000000..dfbad82
--- /dev/null
+++ b/tools/gitlog2asciidoc.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python
+from optparse import OptionParser
+import re
+import subprocess
+import sys
+
+"""
+This script generates a release note from the output of git log
+between the specified tags.
+
+Options:
+--issues          Show output the commits with issues associated with them.
+--issue-numbers   Show outputs issue numbers of the commits with issues
+                  associated with them
+
+Arguments:
+since -- tag name
+until -- tag name
+
+Example Input:
+
+   * <commit subject>
+   +
+   <commit message>
+
+   Bug: issue 123
+   Change-Id: <change id>
+   Signed-off-by: <name>
+
+Expected Output:
+
+   * issue 123 <commit subject>
+   +
+   <commit message>
+"""
+
+parser = OptionParser(usage='usage: %prog [options] <since> <until>')
+
+parser.add_option('-i', '--issues', action='store_true',
+                  dest='issues_only', default=False,
+                  help='only output the commits with issues association')
+
+parser.add_option('-n', '--issue-numbers', action='store_true',
+                  dest='issue_numbers_only', default=False,
+                  help='only outputs issue numbers of the commits with \
+                        issues association')
+
+(options, args) = parser.parse_args()
+
+if len(args) != 2:
+    parser.error("wrong number of arguments")
+
+issues_only = options.issues_only
+issue_numbers_only = options.issue_numbers_only
+
+since_until = args[0] + '..' + args[1]
+proc = subprocess.Popen(['git', 'log', '--reverse', '--no-merges',
+                         since_until, "--format=* %s%n+%n%b"],
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.STDOUT,)
+
+stdout_value = proc.communicate()[0]
+
+subject = ""
+message = []
+is_issue = False
+
+# regex pattern to match following cases such as Bug: 123, Issue Bug: 123,
+# Bug: GERRIT-123, Bug: issue 123, Bug issue: 123, issue: 123, issue: bug 123
+p = re.compile('bug: GERRIT-|bug(:? issue)?:? |issue(:? bug)?:? ',
+               re.IGNORECASE)
+
+if issue_numbers_only:
+    for line in stdout_value.splitlines(True):
+        if p.match(line):
+            sys.stdout.write(p.sub('', line))
+else:
+    for line in stdout_value.splitlines(True):
+        # Move issue number to subject line
+        if p.match(line):
+            line = p.sub('issue ', line).replace('\n',' ')
+            subject = subject[:2] + line + subject[2:]
+            is_issue = True
+        elif line.startswith('* '):
+            # Write change log for a commit
+            if subject != "":
+                if (not issues_only or is_issue):
+                    # Write subject
+                    sys.stdout.write(subject)
+                    # Write message lines
+                    if message != []:
+                        # Clear + from last line in commit message
+                        message[-1] = '\n'
+                    for m in message:
+                        sys.stdout.write(m)
+            # Start new commit block
+            message = []
+            subject = line
+            is_issue = False
+        # Remove commit footers
+        elif re.match(r'((\w+-)+\w+:)', line):
+            continue
+        # Don't add extra blank line if last one is already blank
+        elif line == '\n' and message and message[-1] != '+\n':
+                message.append('+\n')
+        elif line != '\n':
+            message.append(line)