:linkattrs:
= Gerrit Code Review - Submitting Changes Across Repositories by using Topics

== Goal

This document describes how to propose and submit code changes across multiple
Git repositories together in Gerrit.

== When to Use

Oftentimes, especially for larger code bases, code is split across multiple
repositories. The Android operating system’s code base, for example, consists of
https://android.googlesource.com/[hundreds] of separate repositories. When
making a change, you might make code changes that span multiple repositories.
For example, one repository could define an API which is used in another
repository. Submitting these changes across these repositories separately could
cause the build to break for other developers.

Gerrit provides a mechanism called link:intro-user.html#topics[Topics] to submit
changes together to prevent this problem.

|===
|NOTE: Usage of topics to submit multiple changes together requires your
Gerrit host having
link:config-gerrit.html#change.submitWholeTopic[config.submitWholeTopic] set to
true. Ask your Gerrit administrator if you're not sure if this is enabled for
your Gerrit instance.
|===

== What is a Topic?

* A topic is a string that can be associated with a change.
* Multiple changes can use that topic to be submitted at the same time (assuming
  approvals, etc.).
* Submitting a change with a topic causes all of the changes in the topic *to be
  submitted together*
  ** Topics that span only a single repository are guaranteed to be submitted
  together
  ** Topics that span multiple repositories simply triggers submission of all
  changes. No other guarantees are given. Submission of all changes could
  fail, so you could get a partial topic submission. This is very rare but
  can happen in some of the following situations:
  *** Storage layer failures. This is unlikely in single-master installation and
  more likely with multi-master setups.
  *** Race conditions. Concurrent submits to the same repository or concurrent
  updates of the pending changes.

Here are a few intricacies you should be aware of:

1. Topics can only be used for changes within a single Gerrit instance. There is
no builtin support for synchronizing with other Gerrit or Git hosting sites.

2. A topic can be any string, and they are not namespaced in a Gerrit instance;
there is a chance for collisions and inadvertently grouping changes together
that weren’t meant to be grouped. This could even happen with changes you can’t
see, leading to more confusion e.g. (change not submittable, but you can't see
why it's not submittable.). We suggest prefixing topic strings with the author’s
username e.g. “username-” to help avoid this.

You can view the assigned topic from the change screen in Gerrit:

image::images/cross-repository-changes-topic.png[width=600]

=== Topic submission behavior
* Submitting a topic will submit any dependent changes as well. For example,
  an unsubmitted parent change will also be submitted, even if it isn’t in the
  original topic.
* A change with a topic is submittable when *all changes* in the topic are
  submittable and *all of the changes’ dependent changes* (and their topics!)
  are also submittable.
* Gerrit calls the totality of these changes "Submitted Together", and they can
be found with the
  link:rest-api-changes.html#submitted-together[Submitted Together endpoint] or
  on the change screen.

image::images/cross-repository-changes-submitted-together.png[width=600]

* A submission creates a unique submission ID
    (link:rest-api-changes.html#change-info[`submission_id`]), which can be
    used in Gerrit's search bar to find all the submitted changes for the
    submission. This ID is relevant when <<reverting,reverting a submission>>.

To better underestand this behavior, consider this following example.

[[example_submission]]
=== Example Submission

image::images/cross-repository-changes-example.png[width=600]

* Two repositories: A and B
* Two changes in A: A1 and A2, where A2 is the child change.
* Two changes in B: B1 and B2, where B2 is the child change.
* Topic X contains change A1 and B1
* Topic Y contains change A2 and B2

Submission of A2 will submit all four of these changes because submission of A2
submits all of topic Y as well as all dependent changes and their topics i.e. A1
and topic X.

Because of this, any submission is blocked until all four of these changes are
submittable.

|===
| Important point: B1 can unexpectedly block the submission of A2!
This kind of situation is hard to immediately grok: B1 isn't in the topic you're
trying to submit, and it isn't a depnedent change of A2. If your topic isn’t
submittable and you can’t figure out why, this might be a reason.
|===

== Submitting Changes Using Topics

=== 1. *Associate the changes to a topic*

The first step is to associate all the changes you want to be submitted together
with the same topic. There are multiple ways to associate changes with a topic.

==== From the command line
You can set the topic name when uploading to Gerrit

----
$ git push origin HEAD:refs/heads/master -o topic=[YOUR_TOPIC_NAME]
----

*OR*

----
$ git push origin HEAD:refs/for/master%topic=[YOUR_TOPIC_NAME]
----

If you’re using https://source.android.com/setup/develop[repo] to upload a
change to Android Gerrit, you can associate a topic via:

----
$ repo upload -o topic=[YOUR_TOPIC_NAME]
----

If you’re using
https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools.html[depot_tools]
to upload a change to Chromium Gerrit, you can associate a topic via:

----
$ git cl upload --topic=[YOUR_TOPIC_NAME]
----

==== From the UI

If the change has already been created, you can add a topic from the change page
by clicking ADD TOPIC, found on the left side of the top of the Change screen.

image::images/cross-repository-changes-add-topic.png[width=600]

=== 2. *Go through the normal code review process*

Each change still goes through the normal code review process where reviewers
vote on each change individually. The changes won’t be able to be submitted
until *all* changes in the topic are submittable.

The requirements for submittability vary based on rules set by your repository
administrators; often this includes being approved by all requisite parties,
passing presubmit testing, and being able to merge cleanly (without conflicts)
into the target branch.

=== 3. *Submit the change*

When all changes in the topic are submittable, you’ll see *SUBMIT WHOLE TOPIC*
at the top of the _Change screen_. Clicking it will submit all the changes in
"Submitted Together."

image::images/cross-repository-changes-submit-topic.png[width=600]

[[reverting]]
== Reverting a Submission

After a topic is submitted, you can revert all or one of the changes by clicking
the *REVERT* button on any change.

image::images/cross-repository-changes-revert-topic.png[width=600]

This will give you the option to either revert just the change in question or
the entire topic:

image::images/cross-repository-changes-revert-topic-options.png[width=600]

Reverting the entire submission creates revert commits for each change and
automatically associates them together under the same topic. To submit
these changes, go through the normal review process.

When submitting a topic, dependent changes and their topics are submitted as
well. The RevertSubmission creates reverts for all the changes that were
submitted at that time. When reverting the submission described in
<<example_submission,Example Submission>>, all 4 of those changes will get
reverted.

|===
| NOTE: We say “reverting a submission” instead of “reverting a submitted
  topic” because submissions are defined by submission id, not by the topic
  string. So even though topics names could be reused, this doesn't effect
  reverting. For example:

  1. Submission #1 uses topic A

  2. Later, Submission #2 uses topic A again

  Reverting submission #2 only reverts the changes in that submission, not all
  changes included in topic A.
|===

== Cherry-Picking a Topic

You may want to cherry-pick the changes (i.e. copy the changes) of a topic to
another branch, perhaps because you have multiple branches that all need to be
updated with the same change (e.g. you're porting a security fix across
branches). Gerrit provides a mechanism to create these changes.

From the overflow menu (3 dot icon) in the top right of the Change Screen,
select “Cherry pick.” In the screenshot below, we’re showing this on a
submitted change, but this option is available if the change is pending as
well.

image::images/cross-repository-changes-cp-menu.png[width=600]

Afterwards, you’ll be presented with a modal where you can “Cherry Pick entire
topic.”

image::images/cross-repository-changes-cp-modal.png[width=600]

Enter the branch name that you want to target for these repositories. The
branch must already exist on all of the repositories. After clicking
“CHERRY PICK,” Gerrit will create new changes all targeting the entered
branch in their respective repositories, and these new changes will all be
associated with a new, uniquely-generated topic name.

To submit the cherry-picked changes, go through the normal submission
process.

|===
| NOTE: You cannot cherry pick two or more changes that all target the same
 repository from the Gerrit UI at this time; you’ll get an error message saying
 “changes cannot be of the same repository.” To accomplish this, you’d
 need to do the cherry-pick locally.
|===

== Searching for Topics

In the Gerrit search bar, you can search for changes attached to a specific
topic using the `topic` operator e.g. `topic:MY_TOPIC_NAME`. The `intopic`
operator works similary but supports free-text and regular expression search.

You can also search for a submission using the `submissionid` operator. Topic
submission IDs are "<id>-<topic>" where id is the change number of the change
that triggered the submission (though this could change in the future). As a
full example, if the topic name is my-topic and change 12345 was the one that
triggered submission, you could find it with `submissionid:12345-my-topic`.

