Merge changes from topics 'tags-ui', 'projects-ui-refactoring'

* changes:
  Add new screen to list tags of a project
  Projects UI: Factor common code out to PaginatedProjectScreen
  Projects UI: Move common parts out of BranchInfo into RefInfo
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index dbfdf4c..68976e7 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -107,6 +107,7 @@
 org.eclipse.jdt.core.compiler.source=1.7
 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
@@ -117,15 +118,18 @@
 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=16
 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16
 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
 org.eclipse.jdt.core.formatter.blank_lines_after_package=1
 org.eclipse.jdt.core.formatter.blank_lines_before_field=0
@@ -145,6 +149,7 @@
 org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
 org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
 org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
 org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
 org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
 org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
@@ -161,10 +166,16 @@
 org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
 org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
 org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
 org.eclipse.jdt.core.formatter.compact_else_if=true
 org.eclipse.jdt.core.formatter.continuation_indentation=2
 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
 org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
 org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
@@ -176,10 +187,16 @@
 org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
 org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
 org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
 org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
 org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
 org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
 org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
@@ -227,6 +244,7 @@
 org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
 org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
 org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
@@ -245,12 +263,14 @@
 org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
 org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
 org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
 org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
 org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
@@ -274,6 +294,7 @@
 org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
 org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
@@ -301,6 +322,7 @@
 org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
@@ -329,6 +351,7 @@
 org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
 org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
 org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
 org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
@@ -338,6 +361,7 @@
 org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
 org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
 org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
 org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
@@ -361,5 +385,9 @@
 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
 org.eclipse.jdt.core.formatter.tabulation.char=space
 org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
 org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
 org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
index 7397758..d990610 100644
--- a/.settings/org.eclipse.jdt.ui.prefs
+++ b/.settings/org.eclipse.jdt.ui.prefs
@@ -1,7 +1,7 @@
 eclipse.preferences.version=1
 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
 formatter_profile=_Google Format
-formatter_settings_version=11
+formatter_settings_version=12
 org.eclipse.jdt.ui.ignorelowercasenames=true
 org.eclipse.jdt.ui.importorder=\#;com.google;com;dk;eu;junit;net;org;java;javax;
 org.eclipse.jdt.ui.ondemandthreshold=99
diff --git a/BUCK b/BUCK
index 4dd69c3..82f1d72 100644
--- a/BUCK
+++ b/BUCK
@@ -9,6 +9,9 @@
 gerrit_war(name = 'release',  ui = 'ui_optdbg_r', docs = True, context = ['//plugins:core'],  visibility = ['//tools/maven:'])
 
 API_DEPS = [
+  '//gerrit-acceptance-framework:acceptance-framework',
+  '//gerrit-acceptance-framework:acceptance-framework-src',
+  '//gerrit-acceptance-framework:acceptance-framework-javadoc',
   '//gerrit-extension-api:extension-api',
   '//gerrit-extension-api:extension-api-src',
   '//gerrit-extension-api:extension-api-javadoc',
@@ -22,11 +25,9 @@
 
 genrule(
   name = 'api',
-  cmd = ';'.join(
-    ['cd $TMP'] +
-    ['ln -s $(location %s) .' % n for n in API_DEPS] +
-    ['zip -q0 $OUT *']),
-  out = 'api.zip',
+  cmd = 'echo done >$OUT',
+  deps = API_DEPS,
+  out = '__fake.api__',
 )
 
 genrule(
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 1b497a9..42549c8 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -237,6 +237,13 @@
 +
 Default is -1, permitting infinite time between authentications.
 
+[[auth.registerEmailPrivateKey]]auth.registerEmailPrivateKey::
++
+Private key to use when generating an email verification token.
++
+If not set, a random key is generated when running the
+link:pgm-init.html[site initialization].
+
 [[auth.maxRegisterEmailTokenAge]]auth.maxRegisterEmailTokenAge::
 +
 Time in seconds before an email verification token sent to a user in
@@ -3888,7 +3895,6 @@
 ----
 [auth]
   registerEmailPrivateKey = 2zHNrXE2bsoylzUqDxZp0H1cqUmjgWb6
-  restTokenPrivateKey = 7e40PzCjlUKOnXATvcBNXH6oyiu+r0dFk2c=
 
 [database]
   username = webuser
diff --git a/Documentation/install-quick.txt b/Documentation/install-quick.txt
index 4a64892..ffd68e7 100644
--- a/Documentation/install-quick.txt
+++ b/Documentation/install-quick.txt
@@ -163,7 +163,7 @@
 Download a local clone of the repository and move into it
 
 ----
-  user@host:~$ git clone ssh://user@host:29418/demo-project
+  user@host:~$ git clone ssh://user@localhost:29418/demo-project
   Cloning into demo-project...
   remote: Counting objects: 2, done
   remote: Finding sources: 100% (2/2)
diff --git a/Documentation/pgm-reindex.txt b/Documentation/pgm-reindex.txt
index b1116d3..e1d8e8b 100644
--- a/Documentation/pgm-reindex.txt
+++ b/Documentation/pgm-reindex.txt
@@ -15,15 +15,6 @@
 --threads::
 	Number of threads to use for indexing.
 
---recheck-mergeable::
-	Recheck the mergeable flag on all open changes. For each open change,
-	look up for which commit the mergeability check was last done and if
-	this commit is different from the HEAD commit of the change's destination
-	branch, recompute the mergeability flag of the change by checking if the
-	commit of the current patch set can be merged into the destination branch.
-	Because this operation is computationally expensive, it is not enabled
-	by default.
-
 --schema-version::
 	Schema version to reindex; default is most recent version.
 
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 4b57827..cbd748c 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -3347,10 +3347,13 @@
 The HTTP resource Content-Type is dependent on the file type: the
 applicable type for safe files, or "application/zip" for unsafe files.
 
-The `suffix` parameter can be specified to decorate the names of the files.
-The suffix is inserted between the base filename and the random component or
-extension, or appended to the filename if neither such component is present.
-Only the lowercase Roman letters a-z are permitted; other characters are ignored.
+The optional, integer-valued `parent` parameter can be specified to request
+the named file from a parent commit of the specified revision. The value is
+the 1-based index of the parent's position in the commit object. If the
+parameter is omitted or the value non-positive, the patch set is referenced.
+
+Filenames are decorated with a suffix of `_new` for the current patch,
+`_old` for the only parent, or `_oldN` for the Nth parent of many.
 
 .Request
 ----
diff --git a/bucklets/gerrit_plugin.bucklet b/bucklets/gerrit_plugin.bucklet
index ae7e1a2..cd2edae 100644
--- a/bucklets/gerrit_plugin.bucklet
+++ b/bucklets/gerrit_plugin.bucklet
@@ -14,7 +14,8 @@
 # When compiling from standalone cookbook-plugin, bucklets directory points
 # to cloned bucklets library that includes real gerrit_plugin.bucklet code.
 
-GERRIT_PLUGIN_API = ['//gerrit-plugin-api:lib']
 GERRIT_GWT_API = ['//gerrit-plugin-gwtui/gerrit:gwtui-api']
+GERRIT_PLUGIN_API = ['//gerrit-plugin-api:lib']
+GERRIT_TESTS = ['//gerrit-acceptance-framework:lib']
 
 STANDALONE_MODE = False
diff --git a/gerrit-acceptance-framework/BUCK b/gerrit-acceptance-framework/BUCK
new file mode 100644
index 0000000..d8f0276
--- /dev/null
+++ b/gerrit-acceptance-framework/BUCK
@@ -0,0 +1,87 @@
+SRCS = glob(['src/test/java/com/google/gerrit/acceptance/*.java'])
+
+DEPS = [
+  '//gerrit-gpg:gpg',
+  '//gerrit-pgm:daemon',
+  '//gerrit-pgm:util-nodep',
+  '//gerrit-server:testutil',
+  '//lib/auto:auto-value',
+  '//lib/httpcomponents:fluent-hc',
+  '//lib/httpcomponents:httpclient',
+  '//lib/httpcomponents:httpcore',
+  '//lib/jgit:junit',
+  '//lib/log:impl_log4j',
+  '//lib/log:log4j',
+]
+
+PROVIDED = [
+  '//gerrit-common:annotations',
+  '//gerrit-common:server',
+  '//gerrit-extension-api:api',
+  '//gerrit-httpd:httpd',
+  '//gerrit-lucene:lucene',
+  '//gerrit-pgm:init',
+  '//gerrit-reviewdb:server',
+  '//gerrit-server:server',
+  '//lib:gson',
+  '//lib/jgit:jgit',
+  '//lib:jsch',
+  '//lib/mina:sshd',
+  '//lib:servlet-api-3_1',
+]
+
+java_binary(
+  name = 'acceptance-framework',
+  deps = [':lib'],
+  visibility = ['PUBLIC'],
+)
+
+java_library(
+  name = 'lib',
+  srcs = SRCS,
+  exported_deps = DEPS + [
+    '//lib:truth',
+  ],
+  provided_deps = PROVIDED + [
+    '//lib:gwtorm',
+    '//lib/guice:guice',
+    '//lib/guice:guice-assistedinject',
+    '//lib/guice:guice-servlet',
+  ],
+  visibility = ['PUBLIC'],
+)
+
+java_sources(
+  name = 'src',
+  srcs = SRCS,
+  visibility = ['PUBLIC'],
+)
+
+# The above java_sources produces a .jar somewhere in the depths of
+# buck-out, but it does not bring it to
+# buck-out/gen/gerrit-acceptance-framework/gerrit-acceptance-framework-src.jar.
+# We fix that by the following java_binary.
+java_binary(
+  name = 'acceptance-framework-src',
+  deps = [ ':src' ],
+  visibility = ['PUBLIC'],
+)
+
+java_doc(
+  name = 'acceptance-framework-javadoc',
+  title = 'Gerrit Acceptance Test Framework Documentation',
+  pkgs = [' com.google.gerrit.acceptance'],
+  paths = ['src/test/java'],
+  srcs = SRCS,
+  deps = DEPS + PROVIDED + [
+    '//lib:guava',
+    '//lib/guice:guice-assistedinject',
+    '//lib/guice:guice_library',
+    '//lib/guice:guice-servlet',
+    '//lib/guice:javax-inject',
+    '//lib:gwtorm_client',
+    '//lib:junit__jar',
+    '//lib:truth__jar',
+  ],
+  visibility = ['PUBLIC'],
+)
diff --git a/gerrit-acceptance-framework/pom.xml b/gerrit-acceptance-framework/pom.xml
new file mode 100644
index 0000000..ca1ecd9
--- /dev/null
+++ b/gerrit-acceptance-framework/pom.xml
@@ -0,0 +1,59 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.google.gerrit</groupId>
+  <artifactId>gerrit-acceptance-framework</artifactId>
+  <version>2.12-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <name>Gerrit Code Review - Acceptance Test Framework</name>
+  <description>API for Gerrit Plugins</description>
+  <url>https://www.gerritcodereview.com/</url>
+
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+
+  <scm>
+    <url>https://gerrit.googlesource.com/gerrit</url>
+    <connection>https://gerrit.googlesource.com/gerrit</connection>
+  </scm>
+
+  <developers>
+    <developer>
+      <name>Dave Borowitz</name>
+    </developer>
+    <developer>
+      <name>David Pursehouse</name>
+    </developer>
+    <developer>
+      <name>Edwin Kempin</name>
+    </developer>
+    <developer>
+      <name>Martin Fick</name>
+    </developer>
+    <developer>
+      <name>Saša Živkov</name>
+    </developer>
+    <developer>
+      <name>Shawn Pearce</name>
+    </developer>
+  </developers>
+
+  <mailingLists>
+    <mailingList>
+      <name>Repo and Gerrit Discussion</name>
+      <post>repo-discuss@googlegroups.com</post>
+      <subscribe>https://groups.google.com/forum/#!forum/repo-discuss</subscribe>
+      <unsubscribe>https://groups.google.com/forum/#!forum/repo-discuss</unsubscribe>
+      <archive>https://groups.google.com/forum/#!forum/repo-discuss</archive>
+    </mailingList>
+  </mailingLists>
+
+  <issueManagement>
+    <url>http://code.google.com/p/gerrit/issues/list</url>
+    <system>Google Code Issue Tracker</system>
+  </issueManagement>
+</project>
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AcceptanceTestRequestScope.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AccountCreator.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/ConfigAnnotationParser.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GcAssert.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GcAssert.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GcAssert.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GcAssert.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfig.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritConfig.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfig.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritConfig.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfigs.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritConfigs.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritConfigs.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritConfigs.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GitUtil.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GitUtil.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpResponse.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/HttpResponse.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpResponse.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/HttpResponse.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpSession.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/HttpSession.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/HttpSession.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/HttpSession.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InProcessProtocol.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/InProcessProtocol.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InProcessProtocol.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/InProcessProtocol.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/MergeableFileBasedConfig.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/NoHttpd.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/NoHttpd.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/NoHttpd.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/NoHttpd.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PluginDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PluginDaemonTest.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PluginDaemonTest.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PluginDaemonTest.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/PushOneCommit.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestResponse.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestResponse.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestResponse.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestResponse.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestSession.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/RestSession.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/SshSession.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/SshSession.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/SshSession.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/SshSession.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestAccount.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestProjectInput.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestProjectInput.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/TestProjectInput.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestProjectInput.java
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseLocalDisk.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/UseLocalDisk.java
similarity index 100%
rename from gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseLocalDisk.java
rename to gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/UseLocalDisk.java
diff --git a/gerrit-acceptance-tests/BUCK b/gerrit-acceptance-tests/BUCK
index 3adab73..0a39ea7 100644
--- a/gerrit-acceptance-tests/BUCK
+++ b/gerrit-acceptance-tests/BUCK
@@ -2,10 +2,10 @@
   name = 'lib',
   srcs = glob(['src/test/java/com/google/gerrit/acceptance/*.java']),
   exported_deps = [
+    '//gerrit-acceptance-framework:lib',
     '//gerrit-common:annotations',
     '//gerrit-common:server',
     '//gerrit-extension-api:api',
-    '//gerrit-gpg:gpg',
     '//gerrit-gpg:testutil',
     '//gerrit-launcher:launcher',
     '//gerrit-lucene:lucene',
@@ -15,8 +15,8 @@
     '//gerrit-pgm:util',
     '//gerrit-reviewdb:server',
     '//gerrit-server:server',
-    '//gerrit-server/src/main/prolog:common',
     '//gerrit-server:testutil',
+    '//gerrit-server/src/main/prolog:common',
     '//gerrit-sshd:sshd',
 
     '//lib:args4j',
@@ -26,21 +26,13 @@
     '//lib:h2',
     '//lib:jsch',
     '//lib:servlet-api-3_1',
-    '//lib:truth',
 
-    '//lib/auto:auto-value',
     '//lib/bouncycastle:bcpg',
     '//lib/bouncycastle:bcprov',
     '//lib/guice:guice',
     '//lib/guice:guice-assistedinject',
     '//lib/guice:guice-servlet',
-    '//lib/httpcomponents:fluent-hc',
-    '//lib/httpcomponents:httpclient',
-    '//lib/httpcomponents:httpcore',
     '//lib/jgit:jgit',
-    '//lib/jgit:junit',
-    '//lib/log:impl_log4j',
-    '//lib/log:log4j',
     '//lib/mina:sshd',
   ],
   visibility = [
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
index 9a8bb51..78ffa20 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
@@ -80,8 +80,6 @@
   @Test
   public void submitOnPushWithAnnotatedTag() throws Exception {
     grant(Permission.SUBMIT, project, "refs/for/refs/heads/master");
-    grant(Permission.CREATE, project, "refs/tags/*");
-    grant(Permission.PUSH, project, "refs/tags/*");
     PushOneCommit.AnnotatedTag tag =
         new PushOneCommit.AnnotatedTag("v1.0", "annotation", admin.getIdent());
     PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
diff --git a/gerrit-antlr/BUCK b/gerrit-antlr/BUCK
index 03c3c1e..e858a72 100644
--- a/gerrit-antlr/BUCK
+++ b/gerrit-antlr/BUCK
@@ -25,7 +25,6 @@
 genrule(
   name = 'query_link',
   cmd = 'ln -s $(location :lib) $OUT',
-  deps = [':lib'],
   out = 'query_parser.jar',
 )
 
diff --git a/gerrit-gpg/BUCK b/gerrit-gpg/BUCK
index 592a5190..0b78e9a 100644
--- a/gerrit-gpg/BUCK
+++ b/gerrit-gpg/BUCK
@@ -1,22 +1,23 @@
+DEPS = [
+  '//gerrit-common:server',
+  '//gerrit-extension-api:api',
+  '//gerrit-reviewdb:server',
+  '//gerrit-server:server',
+  '//lib:guava',
+  '//lib:gwtorm',
+  '//lib/guice:guice',
+  '//lib/guice:guice-assistedinject',
+  '//lib/guice:guice-servlet',
+  '//lib/jgit:jgit',
+  '//lib/log:api',
+]
+
 java_library(
   name = 'gpg',
   srcs = glob(['src/main/java/**/*.java']),
-  deps = [
-    '//gerrit-common:server',
-    '//gerrit-extension-api:api',
-    '//gerrit-reviewdb:server',
-    '//gerrit-server:server',
-    '//lib:guava',
-    '//lib:gwtorm',
-    '//lib/guice:guice',
-    '//lib/guice:guice-assistedinject',
-    '//lib/guice:guice-servlet',
-    '//lib/jgit:jgit',
-    '//lib/log:api',
-  ],
-  provided_deps = [
-    '//lib/bouncycastle:bcprov',
+  provided_deps = DEPS + [
     '//lib/bouncycastle:bcpg',
+    '//lib/bouncycastle:bcprov',
   ],
   visibility = ['PUBLIC'],
 )
@@ -28,12 +29,10 @@
 java_library(
   name = 'testutil',
   srcs = TESTUTIL_SRCS,
-  deps = [
+  deps = DEPS + [
     ':gpg',
-    '//lib:guava',
     '//lib/bouncycastle:bcpg',
     '//lib/bouncycastle:bcprov',
-    '//lib/jgit:jgit',
   ],
   visibility = ['PUBLIC'],
 )
@@ -44,20 +43,15 @@
     ['src/test/java/**/*.java'],
     excludes = TESTUTIL_SRCS,
   ),
-  deps = [
+  deps = DEPS + [
     ':gpg',
     ':testutil',
-    '//gerrit-extension-api:api',
-    '//gerrit-reviewdb:server',
-    '//gerrit-server:server',
+    '//gerrit-cache-h2:cache-h2',
+    '//gerrit-lucene:lucene',  
     '//gerrit-server:testutil',
-    '//lib:guava',
-    '//lib:gwtorm',
     '//lib:truth',
     '//lib/bouncycastle:bcpg',
     '//lib/bouncycastle:bcprov',
-    '//lib/guice:guice',
-    '//lib/jgit:jgit',
     '//lib/jgit:junit',
   ],
   source_under_test = [':gpg'],
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java
index 5044c62..c0498c7 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/PushCertificateChecker.java
@@ -17,6 +17,8 @@
 import static com.google.gerrit.gpg.PublicKeyStore.keyIdToString;
 import static com.google.gerrit.gpg.PublicKeyStore.keyToString;
 
+import com.google.common.base.Joiner;
+
 import org.bouncycastle.bcpg.ArmoredInputStream;
 import org.bouncycastle.openpgp.PGPException;
 import org.bouncycastle.openpgp.PGPObjectFactory;
@@ -145,13 +147,10 @@
     }
     CheckResult result = publicKeyChecker.check(signer, store);
     if (!result.isOk()) {
-      StringBuilder err = new StringBuilder("Invalid public key ")
-          .append(keyToString(signer))
-          .append(":");
-      for (String problem : result.getProblems()) {
-        err.append("\n  ").append(problem);
-      }
-      problems.add(err.toString());
+      problems.add("Invalid public key "
+          + keyToString(signer)
+          + ":\n  "
+          + Joiner.on("\n  ").join(result.getProblems()));
     }
   }
 }
diff --git a/gerrit-gwtdebug/BUCK b/gerrit-gwtdebug/BUCK
index bf05af0..3670916 100644
--- a/gerrit-gwtdebug/BUCK
+++ b/gerrit-gwtdebug/BUCK
@@ -2,6 +2,7 @@
   name = 'gwtdebug',
   srcs = glob(['src/main/java/**/*.java']),
   deps = [
+    '//gerrit-pgm:daemon',
     '//gerrit-pgm:pgm',
     '//gerrit-pgm:util',
     '//gerrit-util-cli:cli',
diff --git a/gerrit-gwtui-common/BUCK b/gerrit-gwtui-common/BUCK
index 2a79db4..ef4de82 100644
--- a/gerrit-gwtui-common/BUCK
+++ b/gerrit-gwtui-common/BUCK
@@ -64,6 +64,7 @@
   deps = [
     ':client',
     '//lib:junit',
+    '//lib/gwt:user',
     '//lib/jgit:jgit',
   ],
   source_under_test = [':client'],
diff --git a/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/ui/HighlightSuggestion.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/ui/HighlightSuggestion.java
new file mode 100644
index 0000000..10e20bf
--- /dev/null
+++ b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/ui/HighlightSuggestion.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.ui;
+
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
+
+/** A {@code Suggestion} with highlights. */
+public class HighlightSuggestion implements Suggestion {
+
+  private final String keyword;
+  private final String value;
+
+  public HighlightSuggestion(String keyword, String value) {
+    this.keyword = keyword;
+    this.value = value;
+  }
+
+  @Override
+  public String getDisplayString() {
+    int start = 0;
+    int keyLen = keyword.length();
+    SafeHtmlBuilder builder = new SafeHtmlBuilder();
+    for (;;) {
+      int index = value.indexOf(keyword, start);
+      if (index == -1) {
+        builder.appendEscaped(value.substring(start));
+        break;
+      }
+      builder.appendEscaped(value.substring(start, index));
+      builder.appendHtmlConstant("<strong>");
+      start = index + keyLen;
+      builder.appendEscaped(value.substring(index, start));
+      builder.appendHtmlConstant("</strong>");
+    }
+    return builder.toSafeHtml().asString();
+  }
+
+  @Override
+  public String getReplacementString() {
+    return value;
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestOracle.java b/gerrit-gwtui-common/src/main/java/com/google/gerrit/client/ui/RemoteSuggestOracle.java
similarity index 100%
rename from gerrit-gwtui/src/main/java/com/google/gerrit/client/ui/RemoteSuggestOracle.java
rename to gerrit-gwtui-common/src/main/java/com/google/gerrit/client/ui/RemoteSuggestOracle.java
diff --git a/gerrit-gwtui-common/src/test/java/com/google/gerrit/client/ui/HighlightSuggestionTest.java b/gerrit-gwtui-common/src/test/java/com/google/gerrit/client/ui/HighlightSuggestionTest.java
new file mode 100644
index 0000000..44ed50b
--- /dev/null
+++ b/gerrit-gwtui-common/src/test/java/com/google/gerrit/client/ui/HighlightSuggestionTest.java
@@ -0,0 +1,53 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.client.ui;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class HighlightSuggestionTest {
+
+  @Test
+  public void singleHighlight() throws Exception {
+    String keyword = "key";
+    String value = "somethingkeysomething";
+    HighlightSuggestion suggestion = new HighlightSuggestion(keyword, value);
+    assertEquals(
+        "something<strong>key</strong>something",
+        suggestion.getDisplayString());
+    assertEquals(value, suggestion.getReplacementString());
+  }
+
+  @Test
+  public void noHighlight() throws Exception {
+    String keyword = "key";
+    String value = "something";
+    HighlightSuggestion suggestion = new HighlightSuggestion(keyword, value);
+    assertEquals(value, suggestion.getDisplayString());
+    assertEquals(value, suggestion.getReplacementString());
+  }
+
+  @Test
+  public void doubleHighlight() throws Exception {
+    String keyword = "key";
+    String value = "somethingkeysomethingkeysomething";
+    HighlightSuggestion suggestion = new HighlightSuggestion(keyword, value);
+    assertEquals(
+        "something<strong>key</strong>something<strong>key</strong>something",
+        suggestion.getDisplayString());
+    assertEquals(value, suggestion.getReplacementString());
+  }
+}
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
index 8ee573e..6e4b1c7 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/EditPreferences.java
@@ -85,9 +85,18 @@
   }
   private final native String keyMapTypeRaw() /*-{ return this.key_map_type }-*/;
 
-  public final int tabSize() {return get("tab_size", 8); }
-  public final int lineLength() {return get("line_length", 100); }
-  public final int cursorBlinkRate() {return get("cursor_blink_rate", 0); }
+  public final int tabSize() {
+    return get("tab_size", 8);
+  }
+
+  public final int lineLength() {
+    return get("line_length", 100);
+  }
+
+  public final int cursorBlinkRate() {
+    return get("cursor_blink_rate", 0);
+  }
+
   public final native boolean hideTopMenu() /*-{ return this.hide_top_menu || false }-*/;
   public final native boolean showTabs() /*-{ return this.show_tabs || false }-*/;
   public final native boolean showWhitespaceErrors() /*-{ return this.show_whitespace_errors || false }-*/;
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 3cbb68b..ce696a1 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
@@ -15,48 +15,23 @@
 package com.google.gerrit.httpd.raw;
 
 import com.google.common.base.Optional;
-import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.Url;
 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.CurrentUser;
 import com.google.gerrit.server.edit.ChangeEdit;
 import com.google.gerrit.server.edit.ChangeEditUtil;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.mime.FileTypeRegistry;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
-import com.google.gwtexpui.server.CacheHeaders;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
-import eu.medsea.mimeutil.MimeType;
-
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectLoader;
-import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.treewalk.TreeWalk;
-import org.eclipse.jgit.util.NB;
-
-import java.io.FilterOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
-import java.security.SecureRandom;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
 
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -74,26 +49,17 @@
 @SuppressWarnings("serial")
 @Singleton
 public class CatServlet extends HttpServlet {
-  private static final MimeType ZIP = new MimeType("application/zip");
   private final Provider<ReviewDb> requestDb;
-  private final GitRepositoryManager repoManager;
-  private final SecureRandom rng;
-  private final FileTypeRegistry registry;
   private final Provider<CurrentUser> userProvider;
   private final ChangeControl.GenericFactory changeControl;
   private final ChangeEditUtil changeEditUtil;
 
   @Inject
-  CatServlet(GitRepositoryManager grm,
-      Provider<ReviewDb> sf,
-      FileTypeRegistry ftr,
+  CatServlet(Provider<ReviewDb> sf,
       ChangeControl.GenericFactory ccf,
       Provider<CurrentUser> usrprv,
       ChangeEditUtil ceu) {
     requestDb = sf;
-    repoManager = grm;
-    rng = new SecureRandom();
-    registry = ftr;
     changeControl = ccf;
     userProvider = usrprv;
     changeEditUtil = ceu;
@@ -130,7 +96,6 @@
 
       if (c < 0) {
         side = 0;
-
       } else {
         try {
           side = Integer.parseInt(keyStr.substring(c + 1));
@@ -150,15 +115,11 @@
     }
 
     final Change.Id changeId = patchKey.getParentKey().getParentKey();
-    final Project project;
-    final String revision;
+    String revision;
     try {
       final ReviewDb db = requestDb.get();
       final ChangeControl control = changeControl.validateFor(changeId,
           userProvider.get());
-
-      project = control.getProject();
-
       if (patchKey.getParentKey().get() == 0) {
         // change edit
         try {
@@ -190,184 +151,9 @@
       return;
     }
 
-    ObjectLoader blobLoader;
-    RevCommit fromCommit;
-    String suffix;
     String path = patchKey.getFileName();
-    try (Repository repo = repoManager.openRepository(project.getNameKey())) {
-      try (ObjectReader reader = repo.newObjectReader();
-          RevWalk rw = new RevWalk(reader)) {
-        RevCommit c;
-
-        c = rw.parseCommit(ObjectId.fromString(revision));
-        if (side == 0) {
-          fromCommit = c;
-          suffix = "new";
-
-        } else if (1 <= side && side - 1 < c.getParentCount()) {
-          fromCommit = rw.parseCommit(c.getParent(side - 1));
-          if (c.getParentCount() == 1) {
-            suffix = "old";
-          } else {
-            suffix = "old" + side;
-          }
-
-        } else {
-          rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
-          return;
-        }
-
-        try (TreeWalk tw = TreeWalk.forPath(reader, path, fromCommit.getTree())) {
-          if (tw == null) {
-            rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
-            return;
-          }
-
-          if (tw.getFileMode(0).getObjectType() == Constants.OBJ_BLOB) {
-            blobLoader = reader.open(tw.getObjectId(0), Constants.OBJ_BLOB);
-
-          } else {
-            rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            return;
-          }
-        }
-      }
-    } catch (RepositoryNotFoundException e) {
-      getServletContext().log("Cannot open repository", e);
-      rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-      return;
-    } catch (IOException | RuntimeException e) {
-      getServletContext().log("Cannot read repository", e);
-      rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-      return;
-    }
-
-    final byte[] raw =
-        blobLoader.isLarge() ? null : blobLoader.getCachedBytes();
-    final long when = fromCommit.getCommitTime() * 1000L;
-
-    rsp.setDateHeader("Last-Modified", when);
-    CacheHeaders.setNotCacheable(rsp);
-
-    try (OutputStream out = openOutputStream(
-        req, rsp, blobLoader, fromCommit, when, path, suffix, raw)) {
-      if (raw != null) {
-        out.write(raw);
-      } else {
-        blobLoader.copyTo(out);
-      }
-    }
+    String restUrl = String.format("%s/changes/%d/revisions/%s/files/%s/download?parent=%d",
+        req.getContextPath(), changeId.get(), revision, Url.encode(path), side);
+    rsp.sendRedirect(restUrl);
   }
-
-  private OutputStream openOutputStream(HttpServletRequest req,
-      HttpServletResponse rsp, ObjectLoader blobLoader,
-      RevCommit fromCommit, long when, String path, String suffix, byte[] raw)
-      throws IOException {
-    MimeType contentType = registry.getMimeType(path, raw);
-    if (!registry.isSafeInline(contentType)) {
-      // The content may not be safe to transmit inline, as a browser might
-      // interpret it as HTML or JavaScript hosted by this site. Such code
-      // might then run in the site's security domain, and may be able to use
-      // the user's cookies to perform unauthorized actions.
-      //
-      // Usually, wrapping the content into a ZIP file forces the browser to
-      // save the content to the local system instead.
-      //
-
-      rsp.setContentType(ZIP.toString());
-      rsp.setHeader("Content-Disposition", "attachment; filename=\""
-          + safeFileName(path, suffix) + ".zip" + "\"");
-
-      final ZipOutputStream zo = new ZipOutputStream(rsp.getOutputStream());
-
-      ZipEntry e = new ZipEntry(safeFileName(path, rand(req, suffix)));
-      e.setComment(fromCommit.name() + ":" + path);
-      e.setSize(blobLoader.getSize());
-      e.setTime(when);
-      zo.putNextEntry(e);
-      return new FilterOutputStream(zo) {
-        @Override
-        public void close() throws IOException {
-          try {
-            zo.closeEntry();
-          } finally {
-            super.close();
-          }
-        }
-      };
-
-    } else {
-      rsp.setContentType(contentType.toString());
-      rsp.setHeader("Content-Length", "" + blobLoader.getSize());
-
-      return rsp.getOutputStream();
-    }
-  }
-
-  private static String safeFileName(String fileName, final String suffix) {
-    // Convert a file path (e.g. "src/Init.c") to a safe file name with
-    // no meta-characters that might be unsafe on any given platform.
-    //
-    final int slash = fileName.lastIndexOf('/');
-    if (slash >= 0) {
-      fileName = fileName.substring(slash + 1);
-    }
-
-    final StringBuilder r = new StringBuilder(fileName.length());
-    for (int i = 0; i < fileName.length(); i++) {
-      final char c = fileName.charAt(i);
-      if (c == '_' || c == '-' || c == '.' || c == '@') {
-        r.append(c);
-
-      } else if ('0' <= c && c <= '9') {
-        r.append(c);
-
-      } else if ('A' <= c && c <= 'Z') {
-        r.append(c);
-
-      } else if ('a' <= c && c <= 'z') {
-        r.append(c);
-
-      } else if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
-        r.append('-');
-
-      } else {
-        r.append('_');
-      }
-    }
-    fileName = r.toString();
-
-    final int ext = fileName.lastIndexOf('.');
-    if (ext <= 0) {
-      return fileName + "_" + suffix;
-
-    } else {
-      return fileName.substring(0, ext) + "_" + suffix
-          + fileName.substring(ext);
-    }
-  }
-
-  private String rand(final HttpServletRequest req, final String suffix)
-      throws UnsupportedEncodingException {
-    // Produce a random suffix that is difficult (or nearly impossible)
-    // for an attacker to guess in advance. This reduces the risk that
-    // an attacker could upload a *.class file and have us send a ZIP
-    // that can be invoked through an applet tag in the victim's browser.
-    //
-    final MessageDigest md = Constants.newMessageDigest();
-    final byte[] buf = new byte[8];
-
-    NB.encodeInt32(buf, 0, req.getRemotePort());
-    md.update(req.getRemoteAddr().getBytes("UTF-8"));
-    md.update(buf, 0, 4);
-
-    NB.encodeInt64(buf, 0, TimeUtil.nowMs());
-    md.update(buf, 0, 8);
-
-    rng.nextBytes(buf);
-    md.update(buf, 0, 8);
-
-    return suffix + "-" + ObjectId.fromRaw(md.digest()).name();
-  }
-
 }
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java
index 27ded17..4e47bca 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/AutoCommitWriter.java
@@ -25,13 +25,28 @@
 import java.io.IOException;
 
 /** Writer that optionally flushes/commits after every write. */
-class AutoCommitWriter extends IndexWriter {
+public class AutoCommitWriter extends IndexWriter {
   private boolean autoCommit;
 
+  AutoCommitWriter(Directory dir, IndexWriterConfig config)
+      throws IOException {
+    this(dir, config, false);
+  }
+
   AutoCommitWriter(Directory dir, IndexWriterConfig config, boolean autoCommit)
       throws IOException {
     super(dir, config);
-    this.autoCommit = autoCommit;
+    setAutoCommit(autoCommit);
+  }
+
+  /**
+   * This method will override Gerrit configuration index.name.commitWithin
+   * until next Gerrit restart (or reconfiguration through this method).
+   *
+   * @param enable auto commit
+   */
+  public void setAutoCommit(boolean enable) {
+    this.autoCommit = enable;
   }
 
   @Override
@@ -99,7 +114,7 @@
     }
   }
 
-  private void autoFlush() throws IOException {
+  public void autoFlush() throws IOException {
     if (autoCommit) {
       manualFlush();
     }
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index 55ed22d..99003ee 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -386,6 +386,14 @@
     }
   }
 
+  public SubIndex getOpenChangesIndex() {
+    return openIndex;
+  }
+
+  public SubIndex getClosedChangesIndex() {
+    return closedIndex;
+  }
+
   private class QuerySource implements ChangeDataSource {
     private final List<SubIndex> indexes;
     private final Query query;
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
index 5778008..bb69533bf 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/SubIndex.java
@@ -47,7 +47,7 @@
 import java.util.concurrent.TimeoutException;
 
 /** Piece of the change index that is implemented as a separate Lucene index. */
-class SubIndex {
+public class SubIndex {
   private static final Logger log = LoggerFactory.getLogger(SubIndex.class);
 
   private final Directory dir;
@@ -70,13 +70,13 @@
     long commitPeriod = writerConfig.getCommitWithinMs();
 
     if (commitPeriod < 0) {
-      delegateWriter = new IndexWriter(dir, writerConfig.getLuceneConfig());
+      delegateWriter = new AutoCommitWriter(dir, writerConfig.getLuceneConfig());
     } else if (commitPeriod == 0) {
       delegateWriter =
           new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), true);
     } else {
       final AutoCommitWriter autoCommitWriter =
-          new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), false);
+          new AutoCommitWriter(dir, writerConfig.getLuceneConfig());
       delegateWriter = autoCommitWriter;
 
       new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder()
@@ -191,6 +191,10 @@
     writer.deleteAll();
   }
 
+  public TrackingIndexWriter getWriter() {
+    return writer;
+  }
+
   IndexSearcher acquire() throws IOException {
     return searcherManager.acquire();
   }
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
index bd7558b..b73c94d 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
@@ -164,11 +164,14 @@
       mode = SignInMode.SIGN_IN;
     }
 
+    log.debug("mode \"{}\"", mode);
     OAuthServiceProvider oauthProvider = lookupOAuthServiceProvider(id);
 
     if (oauthProvider == null) {
+      log.debug("OpenId provider \"{}\"", id);
       discover(req, res, link, id, remember, token, mode);
     } else {
+      log.debug("OAuth provider \"{}\"", id);
       OAuthSessionOverOpenID oauthSession = oauthSessionProvider.get();
       if (!currentUserProvider.get().isIdentifiedUser()
           && oauthSession.isLoggedIn()) {
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
index 6d129bf..8d5d4b9 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
@@ -127,10 +127,12 @@
       Account.Id actualId = accountManager.lookup(user.getExternalId());
       // Use case 1: claimed identity was provided during handshake phase
       if (!Strings.isNullOrEmpty(claimedIdentifier)) {
+        log.debug("Claimed identity is set");
         Account.Id claimedId = accountManager.lookup(claimedIdentifier);
         if (claimedId != null && actualId != null) {
           if (claimedId.equals(actualId)) {
             // Both link to the same account, that's what we expected.
+            log.debug("Both link to the same account. All is fine.");
           } else {
             // This is (for now) a fatal error. There are two records
             // for what might be the same user.
@@ -144,7 +146,7 @@
           }
         } else if (claimedId != null && actualId == null) {
           // Claimed account already exists: link to it.
-          //
+          log.debug("Claimed account already exists: link to it.");
           try {
             accountManager.link(claimedId, areq);
           } catch (OrmException e) {
@@ -157,11 +159,14 @@
         }
       } else if (linkMode) {
         // Use case 2: link mode activated from the UI
+        Account.Id accountId = identifiedUser.get().getAccountId();
         try {
-          accountManager.link(identifiedUser.get().getAccountId(), areq);
+          log.debug("Linking \"{}\" to \"{}\"", user.getExternalId(),
+              accountId);
+          accountManager.link(accountId, areq);
         } catch (OrmException e) {
           log.error("Cannot link: " + user.getExternalId()
-              + " to user identity: " + identifiedUser.get().getAccountId());
+              + " to user identity: " + accountId);
           rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
           return;
         } finally {
diff --git a/gerrit-pgm/BUCK b/gerrit-pgm/BUCK
index 80c37f7..e06e900 100644
--- a/gerrit-pgm/BUCK
+++ b/gerrit-pgm/BUCK
@@ -53,21 +53,24 @@
   ],
   provided_deps = ['//gerrit-launcher:launcher'],
   visibility = [
+    '//gerrit-acceptance-framework/...',
     '//gerrit-acceptance-tests/...',
     '//gerrit-war:',
   ],
 )
 
+REST_UTIL_DEPS = [
+  '//gerrit-cache-h2:cache-h2',
+  '//gerrit-util-cli:cli',
+  '//lib:args4j',
+  '//lib:gwtorm',
+  '//lib/commons:dbcp',
+]
+
 java_library(
   name = 'util',
-  srcs = glob([SRCS + 'util/*.java']),
-  deps = DEPS + [
-    '//gerrit-cache-h2:cache-h2',
-    '//gerrit-util-cli:cli',
-    '//lib:args4j',
-    '//lib:gwtorm',
-    '//lib/commons:dbcp',
-  ],
+  deps = DEPS + REST_UTIL_DEPS,
+  exported_deps = [':util-nodep'],
   visibility = [
     '//gerrit-acceptance-tests/...',
     '//gerrit-gwtdebug:gwtdebug',
@@ -76,6 +79,15 @@
 )
 
 java_library(
+  name = 'util-nodep',
+  srcs = glob([SRCS + 'util/*.java']),
+  provided_deps = DEPS + REST_UTIL_DEPS,
+  visibility = [
+    '//gerrit-acceptance-framework/...',
+  ],
+)
+
+java_library(
   name = 'http',
   srcs = glob([SRCS + 'http/**/*.java']),
   deps = DEPS + [
@@ -90,30 +102,32 @@
   visibility = ['//gerrit-war:'],
 )
 
+REST_PGM_DEPS = [
+  ':http',
+  ':init',
+  ':init-api',
+  ':util',
+  '//gerrit-cache-h2:cache-h2',
+  '//gerrit-gpg:gpg',
+  '//gerrit-lucene:lucene',
+  '//gerrit-oauth:oauth',
+  '//gerrit-openid:openid',
+  '//lib:args4j',
+  '//lib:gwtorm',
+  '//lib:protobuf',
+  '//lib:servlet-api-3_1',
+  '//lib/auto:auto-value',
+  '//lib/prolog:cafeteria',
+  '//lib/prolog:compiler',
+  '//lib/prolog:runtime',
+]
+
 java_library(
   name = 'pgm',
-  srcs = glob([SRCS + '*.java', SRCS + 'rules/*.java']),
   resources = glob([RSRCS + '*']),
-  deps = DEPS + [
-    ':http',
-    ':init',
-    ':init-api',
-    ':util',
-    '//gerrit-cache-h2:cache-h2',
-    '//gerrit-gpg:gpg',
-    '//gerrit-lucene:lucene',
-    '//gerrit-oauth:oauth',
-    '//gerrit-openid:openid',
-    '//lib:args4j',
-    '//lib:gwtorm',
-    '//lib:protobuf',
-    '//lib:servlet-api-3_1',
-    '//lib/auto:auto-value',
-    '//lib/prolog:cafeteria',
-    '//lib/prolog:compiler',
-    '//lib/prolog:runtime',
+  deps = DEPS + REST_PGM_DEPS + [
+    ':daemon',
   ],
-  provided_deps = ['//gerrit-launcher:launcher'],
   visibility = [
     '//:',
     '//gerrit-acceptance-tests/...',
@@ -123,6 +137,21 @@
   ],
 )
 
+# no transitive deps, used for gerrit-acceptance-framework
+java_library(
+  name = 'daemon',
+  srcs = glob([SRCS + '*.java', SRCS + 'rules/*.java']),
+  resources = glob([RSRCS + '*']),
+  deps = ['//lib/auto:auto-value'],
+  provided_deps = DEPS + REST_PGM_DEPS + [
+    '//gerrit-launcher:launcher',
+  ],
+  visibility = [
+    '//gerrit-acceptance-framework/...',
+    '//gerrit-gwtdebug:gwtdebug',
+  ],
+)
+
 java_test(
   name = 'pgm_tests',
   srcs = glob(['src/test/java/**/*.java']),
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 da87a20..39a5cbd 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
@@ -80,6 +80,7 @@
 import com.google.gerrit.sshd.SshKeyCacheImpl;
 import com.google.gerrit.sshd.SshModule;
 import com.google.gerrit.sshd.commands.DefaultCommandModule;
+import com.google.gerrit.sshd.commands.IndexCommandsModule;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -155,6 +156,7 @@
   private Module emailModule;
 
   private Runnable serverStarted;
+  private IndexType indexType;
 
   public Daemon() {
   }
@@ -276,6 +278,7 @@
     cfgInjector = createCfgInjector();
     config = cfgInjector.getInstance(
         Key.get(Config.class, GerritServerConfig.class));
+    initIndexType();
     sysInjector = createSysInjector();
     sysInjector.getInstance(PluginGuiceEnvironment.class)
       .setDbCfgInjector(dbInjector, cfgInjector);
@@ -379,7 +382,6 @@
     if (slave) {
       return new DummyIndexModule();
     }
-    IndexType indexType = IndexModule.getIndexType(cfgInjector);
     switch (indexType) {
       case LUCENE:
         return luceneModule != null ? luceneModule : new LuceneIndexModule();
@@ -388,6 +390,16 @@
     }
   }
 
+  private void initIndexType() {
+    indexType = IndexModule.getIndexType(cfgInjector);
+    switch (indexType) {
+      case LUCENE:
+        break;
+      default:
+        throw new IllegalStateException("unsupported index.type = " + indexType);
+    }
+  }
+
   private void initSshd() {
     sshInjector = createSshInjector();
     sysInjector.getInstance(PluginGuiceEnvironment.class)
@@ -403,6 +415,9 @@
     }
     modules.add(new DefaultCommandModule(slave,
         sysInjector.getInstance(DownloadConfig.class)));
+    if (indexType == IndexType.LUCENE) {
+      modules.add(new IndexCommandsModule());
+    }
     return sysInjector.createChildInjector(modules);
   }
 
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 a3a3f27..69f2c15 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
@@ -61,9 +61,6 @@
     if (auth.getSecure("registerEmailPrivateKey") == null) {
       auth.setSecure("registerEmailPrivateKey", SignedToken.generateRandomKey());
     }
-    if (auth.getSecure("restTokenPrivateKey") == null) {
-      auth.setSecure("restTokenPrivateKey", SignedToken.generateRandomKey());
-    }
 
     initSignedPush();
   }
diff --git a/gerrit-plugin-api/BUCK b/gerrit-plugin-api/BUCK
index ed11e0f..abcacf9 100644
--- a/gerrit-plugin-api/BUCK
+++ b/gerrit-plugin-api/BUCK
@@ -20,7 +20,6 @@
 java_library(
   name = 'lib',
   exported_deps = PLUGIN_API + [
-    '//gerrit-acceptance-tests:lib',
     '//gerrit-antlr:query_exception',
     '//gerrit-antlr:query_parser',
     '//gerrit-common:annotations',
@@ -34,11 +33,13 @@
     '//lib:jsch',
     '//lib:mime-util',
     '//lib:servlet-api-3_1',
+    '//lib:velocity',
     '//lib/commons:lang',
     '//lib/guice:guice',
     '//lib/guice:guice-assistedinject',
     '//lib/guice:guice-servlet',
     '//lib/jgit:jgit',
+    '//lib/joda:joda-time',
     '//lib/log:api',
     '//lib/mina:sshd',
   ],
diff --git a/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/ui/GroupSuggestOracle.java b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/ui/GroupSuggestOracle.java
new file mode 100644
index 0000000..528b07a
--- /dev/null
+++ b/gerrit-plugin-gwtui/src/main/java/com/google/gerrit/plugin/client/ui/GroupSuggestOracle.java
@@ -0,0 +1,77 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.plugin.client.ui;
+
+import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.client.ui.HighlightSuggestion;
+import com.google.gerrit.plugin.client.rpc.RestApi;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.SuggestOracle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** A {@code SuggestOracle} for groups. */
+public class GroupSuggestOracle extends SuggestOracle {
+
+  private final int chars;
+
+  /**
+   * @param chars minimum chars to start suggesting.
+   */
+  public GroupSuggestOracle(int chars) {
+    this.chars = chars;
+  }
+
+  @Override
+  public boolean isDisplayStringHTML() {
+    return true;
+  }
+
+  @Override
+  public void requestSuggestions(final Request req, final Callback done) {
+    if (req.getQuery().length() < chars) {
+      responseEmptySuggestion(req, done);
+      return;
+    }
+    RestApi rest = new RestApi("/groups/").addParameter("suggest", req.getQuery());
+    if (req.getLimit() > 0) {
+      rest.addParameter("n", req.getLimit());
+    }
+    rest.get(new AsyncCallback<NativeMap<JavaScriptObject>>() {
+      @Override
+      public void onSuccess(NativeMap<JavaScriptObject> result) {
+        List<String> keys = result.sortedKeys();
+        List<Suggestion> suggestions = new ArrayList<>(keys.size());
+        for (String g : keys) {
+          suggestions.add(new HighlightSuggestion(req.getQuery(), g));
+        }
+        done.onSuggestionsReady(req, new Response(suggestions));
+      }
+
+      @Override
+      public void onFailure(Throwable caught) {
+        responseEmptySuggestion(req, done);
+      }
+    });
+  }
+
+  private static void responseEmptySuggestion(Request req, Callback done) {
+    List<Suggestion> empty = Collections.emptyList();
+    done.onSuggestionsReady(req, new Response(empty));
+  }
+}
diff --git a/gerrit-server/BUCK b/gerrit-server/BUCK
index 31a9b49..c264779 100644
--- a/gerrit-server/BUCK
+++ b/gerrit-server/BUCK
@@ -82,6 +82,26 @@
   visibility = ['PUBLIC'],
 )
 
+TESTUTIL_DEPS = [
+  ':server',
+  '//gerrit-common:server',
+  '//gerrit-cache-h2:cache-h2',
+  '//gerrit-extension-api:api',
+  '//gerrit-gpg:gpg',
+  '//gerrit-lucene:lucene',
+  '//gerrit-reviewdb:server',
+  '//lib:gwtorm',
+  '//lib:h2',
+  '//lib:truth',
+  '//lib/guice:guice',
+  '//lib/guice:guice-servlet',
+  '//lib/jgit:jgit',
+  '//lib/jgit:junit',
+  '//lib/log:api',
+  '//lib/log:impl_log4j',
+  '//lib/log:log4j',
+]
+
 TESTUTIL = glob([
   'src/test/java/com/google/gerrit/testutil/**/*.java',
   'src/test/java/com/google/gerrit/server/project/Util.java',
@@ -90,25 +110,9 @@
   name = 'testutil',
   srcs = TESTUTIL,
   deps = [
-    ':server',
-    '//gerrit-common:server',
-    '//gerrit-cache-h2:cache-h2',
-    '//gerrit-extension-api:api',
-    '//gerrit-gpg:gpg',
-    '//gerrit-lucene:lucene',
-    '//gerrit-reviewdb:server',
-    '//lib:gwtorm',
-    '//lib:h2',
-    '//lib:truth',
     '//lib/auto:auto-value',
-    '//lib/guice:guice',
-    '//lib/guice:guice-servlet',
-    '//lib/jgit:jgit',
-    '//lib/jgit:junit',
-    '//lib/log:api',
-    '//lib/log:impl_log4j',
-    '//lib/log:log4j',
   ],
+  provided_deps = TESTUTIL_DEPS,
   exported_deps = [
     '//lib/easymock:easymock',
     '//lib/powermock:powermock-api-easymock',
@@ -147,19 +151,10 @@
   name = 'prolog_tests',
   srcs = PROLOG_TESTS,
   resources = glob(['src/test/resources/com/google/gerrit/rules/**/*']),
-  deps = [
+  deps = TESTUTIL_DEPS + [
     ':prolog_test_case',
-    ':server',
     ':testutil',
-    '//gerrit-common:server',
-    '//gerrit-reviewdb:server',
     '//gerrit-server/src/main/prolog:common',
-    '//lib:guava',
-    '//lib:gwtorm',
-    '//lib:junit',
-    '//lib:truth',
-    '//lib/jgit:jgit',
-    '//lib/guice:guice',
     '//lib/prolog:runtime',
   ],
 )
@@ -171,22 +166,13 @@
 java_test(
   name = 'query_tests',
   srcs = QUERY_TESTS,
-  deps = [
-    ':server',
+  deps = TESTUTIL_DEPS + [
     ':testutil',
     '//gerrit-antlr:query_exception',
     '//gerrit-antlr:query_parser',
     '//gerrit-common:annotations',
-    '//gerrit-common:server',
-    '//gerrit-extension-api:api',
-    '//gerrit-reviewdb:server',
     '//gerrit-server/src/main/prolog:common',
-    '//lib:gwtorm',
-    '//lib:truth',
     '//lib/antlr:java_runtime',
-    '//lib/guice:guice',
-    '//lib/jgit:jgit',
-    '//lib/jgit:junit',
     '//lib/joda:joda-time',
   ],
   source_under_test = [':server'],
@@ -199,25 +185,15 @@
     ['src/test/java/**/*.java'],
     excludes = TESTUTIL + PROLOG_TESTS + PROLOG_TEST_CASE + QUERY_TESTS
   ),
-  deps = [
-    ':server',
+  deps = TESTUTIL_DEPS + [
     ':testutil',
     '//gerrit-antlr:query_exception',
     '//gerrit-common:annotations',
-    '//gerrit-common:server',
-    '//gerrit-extension-api:api',
-    '//gerrit-gpg:gpg',
-    '//gerrit-reviewdb:server',
     '//gerrit-server/src/main/prolog:common',
     '//lib:args4j',
     '//lib:grappa',
     '//lib:guava',
-    '//lib:gwtorm',
-    '//lib:truth',
-    '//lib/guice:guice',
     '//lib/guice:guice-assistedinject',
-    '//lib/jgit:jgit',
-    '//lib/jgit:junit',
     '//lib/joda:joda-time',
     '//lib/prolog:runtime',
   ],
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 baba4bb..885a97f 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
@@ -39,7 +39,6 @@
 import com.google.gerrit.server.config.DisableReverseDnsLookup;
 import com.google.gerrit.server.group.SystemGroupBackend;
 import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.OrmRuntimeException;
 import com.google.gwtorm.server.ResultSet;
 import com.google.inject.Inject;
 import com.google.inject.OutOfScopeException;
@@ -334,8 +333,11 @@
       try {
         starredChanges = starredChangeIds(
             starredQuery != null ? starredQuery : starredQuery());
-      } catch (OrmException | OrmRuntimeException e) {
+      } catch (OrmException | RuntimeException e) {
         log.warn("Cannot query starred changes", e);
+        starredChanges = Collections.emptySet();
+      } finally {
+        starredQuery = null;
       }
     }
     return starredChanges;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
index 15519cc..7b182b1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/PatchLineCommentsUtil.java
@@ -68,7 +68,7 @@
  */
 @Singleton
 public class PatchLineCommentsUtil {
-  public static Ordering<PatchLineComment> PLC_ORDER =
+  public static final Ordering<PatchLineComment> PLC_ORDER =
       new Ordering<PatchLineComment>() {
     @Override
     public int compare(PatchLineComment c1, PatchLineComment c2) {
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 7940219..7de3d64 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
@@ -106,7 +106,7 @@
     try {
       try (ReviewDb db = schema.open()) {
         AccountExternalId.Key key = id(who);
-        AccountExternalId id = db.accountExternalIds().get(key);
+        AccountExternalId id = getAccountExternalId(db, key);
         if (id == null) {
           // New account, automatically create and return.
           //
@@ -130,6 +130,29 @@
     }
   }
 
+  private AccountExternalId getAccountExternalId(ReviewDb db,
+      AccountExternalId.Key key) throws OrmException {
+    String keyValue = key.get();
+    String keyScheme = keyValue.substring(0, keyValue.indexOf(':') + 1);
+
+    // We don't have at the moment an account_by_external_id cache
+    // but by using the accounts cache we get the list of external_ids
+    // without having to query the DB every time
+    if (keyScheme.equals(AccountExternalId.SCHEME_GERRIT)
+        || keyScheme.equals(AccountExternalId.SCHEME_USERNAME)) {
+      AccountState state = byIdCache.getByUsername(
+          keyValue.substring(keyScheme.length()));
+      if (state != null) {
+        for (AccountExternalId accountExternalId : state.getExternalIds()) {
+          if (accountExternalId.getKey().equals(key)) {
+            return accountExternalId;
+          }
+        }
+      }
+    }
+    return db.accountExternalIds().get(key);
+  }
+
   private void update(ReviewDb db, AuthRequest who, AccountExternalId extId)
       throws OrmException, NameAlreadyUsedException, InvalidUserNameException {
     IdentifiedUser user = userFactory.create(extId.getAccountId());
@@ -324,7 +347,7 @@
       who = realm.link(db, to, who);
 
       AccountExternalId.Key key = id(who);
-      AccountExternalId extId = db.accountExternalIds().get(key);
+      AccountExternalId extId = getAccountExternalId(db, key);
       if (extId != null) {
         if (!extId.getAccountId().equals(to)) {
           throw new AccountException("Identity in use by another account");
@@ -415,7 +438,7 @@
       who = realm.unlink(db, from, who);
 
       AccountExternalId.Key key = id(who);
-      AccountExternalId extId = db.accountExternalIds().get(key);
+      AccountExternalId extId = getAccountExternalId(db, key);
       if (extId != null) {
         if (!extId.getAccountId().equals(from)) {
           throw new AccountException("Identity in use by another account");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
index acdf004..1c19bf5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ChangeJson.java
@@ -294,7 +294,7 @@
     Map<Change.Id, ChangeInfo> out = Maps.newHashMap();
     for (QueryResult r : in) {
       List<ChangeInfo> infos = toChangeInfo(out, r.changes());
-      if (r.moreChanges()) {
+      if (!infos.isEmpty() && r.moreChanges()) {
         infos.get(infos.size() - 1)._moreChanges = true;
       }
       res.add(infos);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DownloadContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DownloadContent.java
index 733ff0b..24c2f0e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/DownloadContent.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DownloadContent.java
@@ -30,8 +30,8 @@
 public class DownloadContent implements RestReadView<FileResource> {
   private final FileContentUtil fileContentUtil;
 
-  @Option(name = "--suffix")
-  private String suffix;
+  @Option(name = "--parent")
+  private Integer parent;
 
   @Inject
   DownloadContent(FileContentUtil fileContentUtil) {
@@ -47,6 +47,6 @@
         rsrc.getRevision().getControl().getProjectControl().getProjectState();
     ObjectId revstr = ObjectId.fromString(
         rsrc.getRevision().getPatchSet().getRevision().get());
-    return fileContentUtil.downloadContent(projectState, revstr, path, suffix);
+    return fileContentUtil.downloadContent(projectState, revstr, path, parent);
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
index fef09a2..d145ddf 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/FileContentUtil.java
@@ -16,7 +16,6 @@
 
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 
-import com.google.common.base.CharMatcher;
 import com.google.common.base.Strings;
 import com.google.common.hash.Hasher;
 import com.google.common.hash.Hashing;
@@ -60,8 +59,6 @@
   private static final int MAX_SIZE = 5 << 20;
   private static final String ZIP_TYPE = "application/zip";
   private static final Random rng = new Random();
-  private static final CharMatcher LOWERCASE_OR_DIGITS =
-      CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('0', '9'));
 
   private final GitRepositoryManager repoManager;
   private final FileTypeRegistry registry;
@@ -128,14 +125,20 @@
   }
 
   public BinaryResult downloadContent(ProjectState project, ObjectId revstr,
-      String path, @Nullable String suffix)
+      String path, @Nullable Integer parent)
           throws ResourceNotFoundException, IOException {
-    suffix = Strings.emptyToNull(
-        LOWERCASE_OR_DIGITS.retainFrom(Strings.nullToEmpty(suffix)));
-
     try (Repository repo = openRepository(project);
         RevWalk rw = new RevWalk(repo)) {
+      String suffix = "new";
       RevCommit commit = rw.parseCommit(revstr);
+      if (parent != null && parent > 0) {
+        if (commit.getParentCount() == 1) {
+          suffix = "old";
+        } else {
+          suffix = "old" + parent;
+        }
+        commit = rw.parseCommit(commit.getParent(parent - 1));
+      }
       ObjectReader reader = rw.getObjectReader();
       TreeWalk tw = TreeWalk.forPath(reader, path, commit.getTree());
       if (tw == null) {
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 163fb10..6e6ed97 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
@@ -60,7 +60,6 @@
   private final String cookiePath;
   private final boolean cookieSecure;
   private final SignedToken emailReg;
-  private final SignedToken restToken;
 
   @Inject
   AuthConfig(@GerritServerConfig final Config cfg)
@@ -103,15 +102,6 @@
     } else {
       emailReg = null;
     }
-
-    key = cfg.getString("auth", null, "restTokenPrivateKey");
-    if (key != null && !key.isEmpty()) {
-      int age = (int) ConfigUtil.getTimeUnit(cfg,
-          "auth", null, "maxRestTokenAge", 60, TimeUnit.SECONDS);
-      restToken = new SignedToken(age, key);
-    } else {
-      restToken = null;
-    }
   }
 
   private static List<OpenIdProviderPattern> toPatterns(Config cfg, String name) {
@@ -196,10 +186,6 @@
     return emailReg;
   }
 
-  public SignedToken getRestToken() {
-    return restToken;
-  }
-
   /** OpenID identities which the server permits for authentication. */
   public List<OpenIdProviderPattern> getAllowedOpenIDs() {
     return allowedOpenIDs;
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 cb99688..d12d30a 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
@@ -547,7 +547,7 @@
       Config rc, Map<String, GroupReference> groupsByName) {
     accessSections = new HashMap<>();
     for (String refName : rc.getSubsections(ACCESS)) {
-      if (RefConfigSection.isValid(refName)) {
+      if (RefConfigSection.isValid(refName) & isValidRegex(refName)) {
         AccessSection as = getAccessSection(refName, true);
 
         for (String varName : rc.getStringList(ACCESS, refName, KEY_GROUP_PERMISSIONS)) {
@@ -580,6 +580,17 @@
     }
   }
 
+  private boolean isValidRegex(String refPattern) {
+    try {
+      Pattern.compile(refPattern.replace("${username}/", ""));
+    } catch (PatternSyntaxException e) {
+      error(new ValidationError(PROJECT_CONFIG, "Invalid ref name: "
+          + e.getMessage()));
+      return false;
+    }
+    return true;
+  }
+
   private void loadBranchOrderSection(Config rc) {
     if (rc.getSections().contains(BRANCH_ORDER)) {
       branchOrderSection = new BranchOrderSection(
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 cfabf13..741efb4 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
@@ -50,6 +50,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
 
 
 /** Manages access control for Git references (aka branches, tags). */
@@ -683,5 +685,10 @@
     } else if (!Repository.isValidRefName(refPattern)) {
       throw new InvalidNameException(refPattern);
     }
+    try {
+      Pattern.compile(refPattern.replace("${username}/", ""));
+    } catch (PatternSyntaxException e) {
+      throw new InvalidNameException(refPattern + " " + e.getMessage());
+    }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_108.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_108.java
index 8cbf119..cfafb37 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_108.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_108.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Multimap;
 import com.google.common.collect.SetMultimap;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
@@ -143,9 +144,15 @@
     SetMultimap<Project.NameKey, Change.Id> openByProject =
         HashMultimap.create();
     for (Change c : db.changes().all()) {
-      if (c.getStatus().isOpen()) {
-        openByProject.put(c.getProject(), c.getId());
+      Status status = c.getStatus();
+      if (status != null && status.isClosed()) {
+        continue;
       }
+
+      // The old "submitted" state is not supported anymore
+      // (thus status is null) but it was an opened state and needs
+      // to be migrated as such
+      openByProject.put(c.getProject(), c.getId());
     }
     return openByProject;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java
index 7665c64..a2693e0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/securestore/DefaultSecureStore.java
@@ -26,7 +26,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -36,8 +35,7 @@
 
   @Inject
   DefaultSecureStore(SitePaths site) {
-    Path secureConfig = site.etc_dir.resolve("secure.config");
-    sec = new FileBasedConfig(secureConfig.toFile(), FS.DETECTED);
+    sec = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED);
     try {
       sec.load();
     } catch (Exception e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/PluginLogFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/PluginLogFile.java
new file mode 100644
index 0000000..17f6535
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/PluginLogFile.java
@@ -0,0 +1,65 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.util;
+
+import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.systemstatus.ServerInformation;
+import com.google.inject.Inject;
+
+import org.apache.log4j.AsyncAppender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+public abstract class PluginLogFile implements LifecycleListener {
+
+  private final SystemLog systemLog;
+  private final ServerInformation serverInfo;
+  private final String logName;
+  private final Layout layout;
+
+  @Inject
+  public PluginLogFile(SystemLog systemLog,
+      ServerInformation serverInfo,
+      String logName,
+      Layout layout) {
+    this.systemLog = systemLog;
+    this.serverInfo = serverInfo;
+    this.logName = logName;
+    this.layout = layout;
+  }
+
+  @Override
+  public void start() {
+    AsyncAppender asyncAppender =
+        systemLog.createAsyncAppender(logName, layout);
+    Logger logger = LogManager.getLogger(logName);
+    logger.removeAppender(logName);
+    logger.addAppender(asyncAppender);
+    logger.setAdditivity(false);
+  }
+
+  @Override
+  public void stop() {
+    // stop is called when plugin is unloaded or when the server shutdown.
+    // Only clean up when the server is shutting down to prevent issue when a
+    // plugin is reloaded. The issue is that gerrit load the new plugin and then
+    // unload the old one so because loggers are static, the unload of the old
+    // plugin would remove the appenders just created by the new plugin.
+    if (serverInfo.getState() == ServerInformation.State.SHUTDOWN) {
+      LogManager.getLogger(logName).removeAllAppenders();
+    }
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java b/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java
index 32cdca5..c2d01ca 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/util/SystemLog.java
@@ -72,6 +72,7 @@
 
   public AsyncAppender createAsyncAppender(String name, Layout layout) {
     AsyncAppender async = new AsyncAppender();
+    async.setName(name);
     async.setBlocking(true);
     async.setBufferSize(config.getInt("core", "asyncLoggingBufferSize", 64));
     async.setLocationInfo(false);
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 85272d0..9706feb 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
@@ -35,6 +35,7 @@
 import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.common.data.PermissionRange;
 import com.google.gerrit.common.data.PermissionRule;
+import com.google.gerrit.common.errors.InvalidNameException;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.git.ProjectConfig;
@@ -670,4 +671,29 @@
     assertCannotVote(-2, range);
     assertCannotVote(2, range);
   }
+
+  @Test
+  public void testValidateRefPatternsOK() throws Exception {
+    RefControl.validateRefPattern("refs/*");
+    RefControl.validateRefPattern("^refs/heads/*");
+    RefControl.validateRefPattern("^refs/tags/[0-9a-zA-Z-_.]+");
+    RefControl.validateRefPattern("refs/heads/review/${username}/*");
+  }
+
+  @Test(expected = InvalidNameException.class)
+  public void testValidateBadRefPatternDoubleCaret() throws Exception {
+    RefControl.validateRefPattern("^^refs/*");
+  }
+
+  @Test(expected = InvalidNameException.class)
+  public void testValidateBadRefPatternDanglingCharacter() throws Exception {
+    RefControl
+        .validateRefPattern("^refs/heads/tmp/sdk/[0-9]{3,3}_R[1-9][A-Z][0-9]{3,3}*");
+  }
+
+  @Test
+  public void testValidateRefPatternNoDanglingCharacter() throws Exception {
+    RefControl
+        .validateRefPattern("^refs/heads/tmp/sdk/[0-9]{3,3}_R[1-9][A-Z][0-9]{3,3}");
+  }
 }
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 05c1bfc..c6eaebb 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
@@ -34,12 +34,11 @@
 
   @Override
   protected void configure() {
-    final CommandName git = Commands.named("git");
-    final CommandName gerrit = Commands.named("gerrit");
-    CommandName index = Commands.named(gerrit, "index");
-    final CommandName logging = Commands.named(gerrit, "logging");
-    final CommandName plugin = Commands.named(gerrit, "plugin");
-    final CommandName testSubmit = Commands.named(gerrit, "test-submit");
+    CommandName git = Commands.named("git");
+    CommandName gerrit = Commands.named("gerrit");
+    CommandName logging = Commands.named(gerrit, "logging");
+    CommandName plugin = Commands.named(gerrit, "plugin");
+    CommandName testSubmit = Commands.named(gerrit, "test-submit");
 
     command(gerrit).toProvider(new DispatchCommandProvider(gerrit));
     command(gerrit, AproposCommand.class);
@@ -58,10 +57,6 @@
     command(gerrit, VersionCommand.class);
     command(gerrit, GarbageCollectionCommand.class);
 
-    command(index).toProvider(new DispatchCommandProvider(index));
-    command(index, IndexActivateCommand.class);
-    command(index, IndexStartCommand.class);
-
     command(gerrit, "plugin").toProvider(new DispatchCommandProvider(plugin));
     command(plugin, PluginLsCommand.class);
     command(plugin, PluginEnableCommand.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexCommandsModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexCommandsModule.java
new file mode 100644
index 0000000..3e7b293
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/IndexCommandsModule.java
@@ -0,0 +1,32 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.sshd.commands;
+
+import com.google.gerrit.sshd.CommandModule;
+import com.google.gerrit.sshd.CommandName;
+import com.google.gerrit.sshd.Commands;
+import com.google.gerrit.sshd.DispatchCommandProvider;
+
+public class IndexCommandsModule extends CommandModule {
+
+  @Override
+  protected void configure() {
+    CommandName gerrit = Commands.named("gerrit");
+    CommandName index = Commands.named(gerrit, "index");
+    command(index).toProvider(new DispatchCommandProvider(index));
+    command(index, IndexActivateCommand.class);
+    command(index, IndexStartCommand.class);
+  }
+}
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 905d776..5e36318 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
@@ -45,6 +45,7 @@
 import com.google.gerrit.server.git.ReceiveCommitsExecutorModule;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.index.IndexModule;
+import com.google.gerrit.server.index.IndexModule.IndexType;
 import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
 import com.google.gerrit.server.mail.SmtpEmailSender;
 import com.google.gerrit.server.mime.MimeUtil2Module;
@@ -64,6 +65,7 @@
 import com.google.gerrit.sshd.SshKeyCacheImpl;
 import com.google.gerrit.sshd.SshModule;
 import com.google.gerrit.sshd.commands.DefaultCommandModule;
+import com.google.gerrit.sshd.commands.IndexCommandsModule;
 import com.google.inject.AbstractModule;
 import com.google.inject.CreationException;
 import com.google.inject.Guice;
@@ -116,6 +118,7 @@
   private GuiceFilter filter;
 
   private ServletContext servletContext;
+  private IndexType indexType;
 
   @Override
   public void doFilter(ServletRequest req, ServletResponse res,
@@ -165,6 +168,7 @@
       }
 
       cfgInjector = createCfgInjector();
+      initIndexType();
       config = cfgInjector.getInstance(
           Key.get(Config.class, GerritServerConfig.class));
       sysInjector = createSysInjector();
@@ -298,15 +302,13 @@
     modules.add(new PluginRestApiModule());
     modules.add(new RestCacheAdminModule());
     modules.add(new GpgModule(config));
-    AbstractModule changeIndexModule;
-    switch (IndexModule.getIndexType(cfgInjector)) {
+    switch (indexType) {
       case LUCENE:
-        changeIndexModule = new LuceneIndexModule();
+        modules.add(new LuceneIndexModule());
         break;
       default:
-        throw new IllegalStateException("unsupported index.type");
+        throw new IllegalStateException("unsupported index.type = " + indexType);
     }
-    modules.add(changeIndexModule);
     modules.add(new CanonicalWebUrlModule() {
       @Override
       protected Class<? extends Provider<String>> provider() {
@@ -325,12 +327,19 @@
     return cfgInjector.createChildInjector(modules);
   }
 
+  private void initIndexType() {
+    indexType = IndexModule.getIndexType(cfgInjector);
+  }
+
   private Injector createSshInjector() {
     final List<Module> modules = new ArrayList<>();
     modules.add(sysInjector.getInstance(SshModule.class));
     modules.add(new SshHostKeyModule());
     modules.add(new DefaultCommandModule(false,
         sysInjector.getInstance(DownloadConfig.class)));
+    if (indexType == IndexType.LUCENE) {
+      modules.add(new IndexCommandsModule());
+    }
     return sysInjector.createChildInjector(modules);
   }
 
diff --git a/lib/BUCK b/lib/BUCK
index 1dbac0a..16b962e 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -58,8 +58,8 @@
 
 maven_jar(
   name = 'guava',
-  id = 'com.google.guava:guava:19.0-rc1',
-  sha1 = '0364538ac107b8943a1f4d68ac50f1b0421bb983',
+  id = 'com.google.guava:guava:19.0-rc2',
+  sha1 = '93e17f60bc524c2610b41c494bb829c11ca89436',
   license = 'Apache2.0',
 )
 
@@ -153,8 +153,8 @@
 
 maven_jar(
   name = 'h2',
-  id = 'com.h2database:h2:1.3.174',
-  sha1 = '2fb55391f525bc3ef9f320a379d19350af96a554',
+  id = 'com.h2database:h2:1.3.176',
+  sha1 = 'fd369423346b2f1525c413e33f8cf95b09c92cbd',
   license = 'h2',
 )
 
diff --git a/lib/prolog/prolog.defs b/lib/prolog/prolog.defs
index 677a9e2..e74c21d 100644
--- a/lib/prolog/prolog.defs
+++ b/lib/prolog/prolog.defs
@@ -33,7 +33,6 @@
   genrule(
     name = name + '__ln',
     cmd = 'ln -s $(location :%s__lib) $OUT' % name,
-    deps = [':%s__lib' % name],
     out = name + '.jar',
   )
   prebuilt_jar(
diff --git a/plugins/cookbook-plugin b/plugins/cookbook-plugin
index ec6ed89..2d25ede 160000
--- a/plugins/cookbook-plugin
+++ b/plugins/cookbook-plugin
@@ -1 +1 @@
-Subproject commit ec6ed89c47ba7223f82d9cb512926a6c5081343e
+Subproject commit 2d25edee3f9ae354d875c2591bdd44bd937125fe
diff --git a/plugins/replication b/plugins/replication
index cc91e0c..e9fd843 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit cc91e0c2987a4606e19b10e320b14f6a0c911c06
+Subproject commit e9fd84329b77544cd6d61bc833f0000c54110299
diff --git a/tools/maven/BUCK b/tools/maven/BUCK
index fdc01a8..98a7ade 100644
--- a/tools/maven/BUCK
+++ b/tools/maven/BUCK
@@ -10,16 +10,19 @@
   url = URL,
   version = GERRIT_VERSION,
   jar = {
+    'gerrit-acceptance-framework': '//gerrit-acceptance-framework:acceptance-framework',
     'gerrit-extension-api': '//gerrit-extension-api:extension-api',
     'gerrit-plugin-api': '//gerrit-plugin-api:plugin-api',
     'gerrit-plugin-gwtui': '//gerrit-plugin-gwtui:gwtui-api',
   },
   src = {
+    'gerrit-acceptance-framework': '//gerrit-acceptance-framework:acceptance-framework-src',
     'gerrit-extension-api': '//gerrit-extension-api:extension-api-src',
     'gerrit-plugin-api': '//gerrit-plugin-api:plugin-api-src',
     'gerrit-plugin-gwtui': '//gerrit-plugin-gwtui:gwtui-api-src',
   },
   doc = {
+    'gerrit-acceptance-framework': '//gerrit-acceptance-framework:acceptance-framework-javadoc',
     'gerrit-extension-api': '//gerrit-extension-api:extension-api-javadoc',
     'gerrit-plugin-api': '//gerrit-plugin-api:plugin-api-javadoc',
     'gerrit-plugin-gwtui': '//gerrit-plugin-gwtui:gwtui-api-javadoc',
diff --git a/tools/version.py b/tools/version.py
index e2d9ead..9f03a59 100755
--- a/tools/version.py
+++ b/tools/version.py
@@ -45,10 +45,10 @@
 
 src_pattern = re.compile(r'^(\s*<version>)([-.\w]+)(</version>\s*)$',
                          re.MULTILINE)
-for project in ['gerrit-extension-api', 'gerrit-plugin-api',
-                'gerrit-plugin-archetype', 'gerrit-plugin-gwt-archetype',
-                'gerrit-plugin-gwtui', 'gerrit-plugin-js-archetype',
-                'gerrit-war']:
+for project in ['gerrit-acceptance-framework', 'gerrit-extension-api',
+                'gerrit-plugin-api', 'gerrit-plugin-archetype',
+                'gerrit-plugin-gwt-archetype', 'gerrit-plugin-gwtui',
+                'gerrit-plugin-js-archetype', 'gerrit-war']:
   pom = os.path.join(project, 'pom.xml')
   replace_in_file(pom, src_pattern)