| # Workflow tips and questions |
| |
| ## Workflow tips |
| |
| This is a list of tips that should help you be more productive when working |
| on Fuchsia. |
| |
| ### Install Gerrit Monitor |
| |
| Install the [Gerrit Monitor](https://chrome.google.com/webstore/detail/gerrit-monitor/leakcdjcdifiihdgalplgkghidmfafoh) |
| Chrome extension to include the list of Gerrit changes that require |
| your attention in your Chrome toolbar. |
| |
| ### Optimize your Gerrit settings |
| |
| Review [Gerrit settings](https://fuchsia-review.googlesource.com/settings/) |
| and tweak them to your liking. |
| For instance you may want to enable "Publish comments on push", which will |
| automatically send draft comments when a new patch set is published, rather than |
| you having to do this manually from the web UI. |
| |
| ### Enable three-way diffs in Git |
| |
| By default Git uses two-way diffs when presenting conflicts. It does not |
| display what the original text was before the conflict, which makes it [hard to |
| solve some conflicts](https://stackoverflow.com/questions/4129049/why-is-a-3-way-merge-advantageous-over-a-2-way-merge). |
| |
| You can configure Git to show the original text by enabling three-way diffs: |
| |
| ```git config --global merge.conflictstyle diff3``` |
| |
| ### Enable fuchsia-specific git commands |
| |
| Add `$FUCHSIA_DIR/scripts/git` to your PATH to be able to use fuchsia-specific git |
| commands such as `git fuchsia-review [<commit ref>]`, which opens the current |
| or given commit in gerrit. |
| |
| ## Questions and answers |
| |
| You are encouraged to add your own questions (and answers) here! |
| |
| ### Q: Is there a standard Git workflow for Fuchsia? |
| |
| There are a wide variety of workflows used by the Fuchsia team. A daily |
| workflow to get you started is as follows: |
| |
| ```shell |
| $ jiri update -gc |
| # Start a new feature on a `myfeature` branch from the current stable commit |
| $ git checkout -b myfeature JIRI_HEAD |
| # Do work, making changes, etc. |
| $ git commit |
| # Upload your work to Gerrit for review |
| $ jiri upload |
| # OR |
| $ git push origin HEAD:refs/for/main |
| ``` |
| |
| Congratulations, you made your first Gerrit change! |
| |
| Suppose you want to start new work on an `otherfeature` branch |
| while you wait for review of the work located |
| on your `myfeature` branch: |
| |
| ```shell |
| # Start a new independent line of work on the `otherfeature` branch |
| # while waiting for review of `myfeature`: |
| $ git checkout -b otherfeature JIRI_HEAD |
| # OR |
| # Start a derivative line of work while waiting for review: |
| $ git checkout -b otherfeature |
| ``` |
| |
| When you want to update your `myfeature` branch but you've been working on an |
| "independent" line of work on the `otherfeature` branch: |
| |
| ```shell |
| # Commit any present dirty work, then, switch to "myfeature": |
| $ git checkout myfeature |
| # Make any relevant edits to the code, then: |
| $ git commit --amend |
| # Now upload the new patchset to Gerrit: |
| $ jiri upload |
| # OR |
| $ git push origin HEAD:refs/for/main |
| ``` |
| |
| When you want to update your `myfeature` branch because you got some review |
| comments, and you are using a "derivative" line of work: |
| |
| ```shell |
| # Now you get a review comment that needs a change in "myfeature" |
| # Commit your present work, if you aren't finished, maybe use a work-in-progress change: |
| $ git commit -a -m "work in progress" |
| # Start a rebase operation, so you can edit your first change: |
| $ git rebase -i JIRI_HEAD |
| # Replace "pick" with "edit" on the change you need to update and save and close the file |
| # Make the relevant code changes, then: |
| $ git add . && git rebase --continue |
| # You may need to make additional "rebase" steps if your edits need integration |
| # with later commits For each case, look at "git status" to see what files are |
| # in conflict, and make the relevant adjustments. The rebase is complete when |
| # git reports "Successfully rebased and updated ...." If you made a "work in |
| # progress" change and want to unwind that commit: |
| $ git reset HEAD |
| # Now you can upload your modified changes to Gerrit: |
| $ jiri upload |
| # OR |
| $ git push origin HEAD:refs/for/main |
| ``` |
| |
| When you see "merge conflict" in Gerrit because your change can't cleanly be |
| integrated with the `main` branch: |
| |
| ```shell |
| # Checkout the branch for the change you need to update (e.g. "myfeature"): |
| $ git checkout myfeature |
| # Update your git repository: |
| $ git fetch |
| # Update your branch: |
| $ git rebase origin/main |
| # Fixup and continue the rebase as necessary, until you see "Successfully rebased ..." |
| # Then upload your newly updated code: |
| $ jiri upload |
| # OR |
| $ git push origin HEAD:refs/for/main |
| ``` |
| |
| When you've been working for more than a day, and you need to "sync your |
| code" with upstream (you generally want to do this at least once per day): |
| |
| ``` |
| # Commit any in-progress work, then |
| # Checkout the stable upstream you last sync'd |
| $ git checkout JIRI_HEAD |
| # Update your local repository (this will include updates for prebuilts, third |
| # party repositories, and so on): |
| $ jiri update -gc |
| # Now to switch back to, and update your working branch (e.g. "myfeature"): |
| $ git checkout myfeature |
| # Updating "myfeature" with the latest stable code: |
| $ git rebase JIRI_HEAD |
| # Perform fixups and "git rebase --continue" until you get to "Successfully rebased ..." |
| ``` |
| |
| You can find more information on parts of workflows below. |
| You can find more information on general git workflows in [gitworkflows(7)](https://github.com/git/git/blob/HEAD/Documentation/gitworkflows.txt). |
| You can find more information on git in general at [git-scm.com/doc](https://git-scm.com/doc). |
| |
| #### Rebasing |
| |
| Update all projects simultaneously, and rebase your work branch on `JIRI_HEAD`: |
| |
| ```shell |
| $ jiri update -gc -rebase-untracked |
| $ git checkout <my_branch> |
| $ git rebase JIRI_HEAD |
| ``` |
| |
| The `git rebase` to `JIRI_HEAD` should be done in *each* repo where you have |
| ongoing work. It's not needed for repos you haven't touched. |
| |
| #### Uploading a new patch set (snapshot) of a change |
| |
| You'll need to *upload* a patch set to |
| [Gerrit](https://fuchsia-review.googlesource.com/) to have it reviewed by |
| others. We do this with `jiri upload`. |
| |
| Gerrit uses an auto-generated metadata marker in the change's description |
| to figure out which Gerrit review thread to upload a patch to, such |
| as: `Change-Id: I681125d950205fa7654e4a8ac0b3fee7985f5a4f` |
| |
| This is different from a git commit's SHA hash, and can be considered stable |
| during review, as you make edits to your changes and commits. Use the same |
| Change-Id for a given review (in case you are |
| [squashing](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) multiple |
| commits). |
| |
| If you've made changes and want to upload a new patch set, then (assuming that |
| this is the latest change in your branch; use `git log` to find out) you can do |
| something like: |
| |
| ```shell |
| $ git commit -a --amend |
| # -a for all uncommitted files, --amend to amend latest commit |
| $ jiri upload |
| ``` |
| |
| #### Resolving merge conflicts |
| |
| Attempt a rebase: |
| |
| ```shell |
| $ git fetch origin && git rebase origin/main |
| # Resolve conflicts as needed... |
| $ jiri upload |
| ``` |
| |
| But read below about how a `git rebase` can negatively interact with `jiri |
| update`. |
| |
| #### Stashing |
| |
| You can save all uncommitted changes aside, and re-apply them at a later time. |
| This is often useful when you're starting out with Git. |
| |
| ```shell |
| $ git stash # uncommitted changes will go away |
| # do stuff |
| $ git stash pop # uncommitted changes will come back |
| ``` |
| |
| ### Q: I use **fx** and **jiri** a lot. How are they related? |
| |
| A: They are not related. |
| [`jiri`](https://fuchsia.googlesource.com/jiri/+/HEAD/) is a wrapper around |
| git that provides support for managing more than one git repository in sync |
| (the Fuchsia code base is composed of many git repositories), as well as |
| synchronizing a set of prebuilt artifacts, such as those found in |
| `//prebuilt`. |
| [`fx`](/scripts/fx) is a |
| convenience wrapper around many tools built in the Fuchsia tree, and helps |
| with many daily workflow tasks, such as building, running tests, consuming |
| logs, connecting to shells on devices, and many other operations. |
| |
| ### Q: Will a git rebase to origin/main mess up my jiri-updated (i.e. synchronized) view of the repository? |
| |
| A: Yes, unless jiri is configured to sync the rebased repository/petal to HEAD |
| instead of the globally integrated version. This is not the case if you use the |
| current/new default bootstrap setup, which tracks global integration for all |
| repos, but may be the case if you set up your checkout in the past or used `fx |
| set-petal X`. |
| |
| When working at petal X (accomplished with `fx set-petal X`), `jiri update` will |
| rebase the local branches in repo X onto HEAD of origin/main. But other |
| petals' repos will be synced to specific revisions that may be behind HEAD of |
| their origin/main. |
| |
| Fuchsia's continuous integration system (specifically rollers) makes a new revision |
| of a petal available to other petals only after testing that the new revision |
| doesn't break other petals. `jiri update` will always leave other petals synced |
| to these successfully-tested revisions. But a git rebase to origin/main for a |
| petal may advance that repo beyond the tested revision, which has the potential |
| to introduce breaking changes. The result may be that you can build for a |
| certain petal, but not for other petals (e.g., correctly build garnet, but not |
| be able to build topaz). |
| |
| If you have a particular commit that you want jiri to honor, download its |
| `jiri.update` file and feed it to `jiri update`. |
| |
| ### Q: What if I need an atomic commit across git repositories? |
| |
| A: Can't, sorry. Try to arrange your changes so that they don't break each |
| petal during a transition (i.e., do a [soft |
| transition](working_across_petals.md#soft-transitions-preferred)). But sometimes |
| you will necessarily break things; aim to minimize the duration of breakage |
| (i.e., a [hard transition](working_across_petals.md#hard-transitions)). |
| |
| Example scenario: I have an interface defined in stem, and it is implemented in |
| another petal. If I change the interface, am I doomed to break other petals? |
| |
| Yes. But you can "babysit" the rollers so that the breakage range is minimized. |
| The caveat with babysitting is that others may *also* be babysitting a breakage, |
| and you may end up babysitting for longer than you had intended. |
| |
| Alternatively, you *could* do something as follows: |
| |
| 1. Introduce a new interface in `lower` that is a copy of the original |
| interface. |
| 1. Wait for `lower-roller` to roll into `upper`, or roll yourself by updating |
| the file `upper/manifest`. |
| 1. Change `upper` to use the new clone interface that maintains the old |
| contract. |
| 1. Change `lower` such that the original interface’s contract is modified to |
| the new, desired form. |
| 1. Wait for `lower-roller`, or roll yourself. |
| 1. Change `upper` to use the original interface name, now with its new |
| contract. Make any changes required. |
| 1. Delete the clone interface in `lower`. |
| |
| ### Q: How do I do parallel builds from a single set of sources? |
| |
| Note: this answer is subject to change/breakage shortly after authorship. |
| |
| Let's assume you want to produce four builds: |
| |
| * a "bringup" product for x64 |
| * a "workstation" product for x64 |
| * a "core" product for vim2 |
| * a "workstation" product for vim2 |
| |
| First, one must build Zircon, as the Zircon build directory is shared across |
| Fuchsia build targets. It doesn't matter at this stage which product/board |
| combination you pick, we just need to start building Zircon. |
| |
| ```shell |
| # We start with bringup, because it's small, but it doesn't matter which you start with: |
| $ fx --dir out.bringup.x64 set bringup.x64 |
| $ fx --dir out/bringup.x64 build |
| ``` |
| |
| Now you have Zircon built, you can start building several other builds concurrently: |
| |
| ```shell |
| $ fx --dir out/workstation.x64 set workstation.x64 |
| $ fx --dir out/workstation.x64 build > workstation.x64.build.log & |
| |
| $ fx --dir out/core.vim2 set core.arm64 |
| $ fx --dir out/core.vim2 build > core.vim2.build.log & |
| |
| $ fx --dir out/workstation.vim2 set workstation.arm64 |
| $ fx --dir out/workstation.vim2 build > workstation.vim2.build.log & |
| ``` |
| |
| You can reference each of these builds while running `fx` tools by passing |
| `--dir` to your fx command, e.g. to run `fx serve` using the vim2 workstation |
| product, you would use: |
| |
| ```shell |
| $ fx --dir out/workstation.vim2 serve |
| ``` |
| |
| You can also change which build directory is your current default by using `fx use`: |
| |
| ```shell |
| $ fx use out/core.vim2 |
| ``` |
| |
| ### Q: What if I want to build at a previous snapshot across the repos? |
| |
| A: You'll need to `jiri update` against a *jiri snapshot file*, an XML file that |
| captures the state of each repo tracked by jiri. |
| |
| ### Q: How can I get a build that works for a particular fuchsia.git commit? |
| |
| A: `fx sync-from-stem` will do this. It uses `jiri` under the hood. However, |
| instead of syncing fuchsia.git and dependencies to match the current integration |
| repo, it instead finds the integration commit that matches *currently checked |
| out* fuchsia.git, and syncs integration and dependencies to match that |
| fuchsia.git commit. |
| |
| Put another way, fuchsia.git will be untouched, and everything else is synced to |
| match. This can be useful to bisect within fuchsia.git. |
| |
| ### Q: I'm building on Mac, how to do I stop getting spammed with 'incoming network connection' notifications? |
| |
| A: You'll want to run `fx setup-macos`, which registers all the relevant Fuchsia |
| tools with the MacOS Application Firewall. |
| |
| ### Q: When/how do I make a soft vs hard transition when changing APIs? |
| |
| See [this section](working_across_petals.md#hard-and-soft-transitions) about hard |
| and soft transitions. |
| |
| ### Q: How do I update a FIDL protocol? |
| |
| A: The preferred method for updating a FIDL protocol is to use a *soft |
| transition*. In order for a soft transition to work, you need to create an |
| intermediate state that supports both the old and new versions of the protocol. |
| |
| Use the following steps to execute a soft transition: |
| |
| 1. Modify the FIDL definition in the Stem repository to support both the old |
| and new protocol elements. Before landing the change, trigger the *global |
| integration* tryjobs to validate that step 2 will succeed. |
| |
| 1. Publish the Stem repository, either by waiting for the daily automatic |
| publication or by manually publishing the repository. |
| |
| 1. Update all the clients to use the new protocol elements. |
| |
| 1. Publish all the clients. |
| |
| 1. Remove the old protocol elements from the FIDL definition in the Stem |
| repository. |
| |
| 1. Publish the Stem repository, typically by waiting for the daily automatic |
| publication. |
| |
| ### Q: How do I coordinate changes across multiple Petals? |
| |
| A: Coordinating an atomic change across multiple Petals (or between the Stem |
| repository and one or more Petals) requires performing a *hard transition*. |
| |
| Use the following steps to execute a hard transition: |
| |
| 1. Prepare changes to all affected repositories. If all of these repositories |
| are part of the Platform Source Tree: |
| |
| 1. Upload the relevant changes to fuchsia-review.googlesource.com. |
| 1. Upload another change that modifies the *global integration* |
| repository to reference the git revisions from your changes. Perform |
| a "dry run" of the commit queue for this Gerrit change. |
| |
| 1. Notify the team stating your intention to execute a hard transition. |
| |
| 1. Land all the changes in the affected repositories. This step will break |
| local integration in these repositories but will not break global |
| integration because the changes have not been published yet. |
| |
| 1. Land a change in the *global integration* repository that references the new |
| versions of the affected repositories. This change will publish the new |
| version of all the affected repositories and should not break global |
| integration. This change should unbreak local integration in the affected |
| repositories. |
| |
| ### Q: How do I bisect history to track down when something changed? |
| |
| A: To bisect history, perform the following steps: |
| |
| 1. Bisect the history in the configuration repository, which contains the |
| revision history of global integration, before and after the observable |
| change. The result of this bisect will be a single change to configuration |
| repository, presumably that includes the publication of one or more |
| repositories or prebuilt packages. |
| |
| 1. If the change to the configuration repository is a publication of a single |
| repository, bisect the history of that repository before and after the |
| publication of global integration. The result of this bisect should be the |
| revision at which the behavior changed. |
| |
| 1. If the change to the configuration repository is a publication of prebuilt |
| packages, switch to the source tree from which the prebuilt packages were |
| created. Consult the documentation for that repository regarding how to |
| bisect changes in that repository. |
| |
| 1. If the change to the configuration repository is a publication of multiple |
| repositories, bisecting history becomes complicated because the two |
| repositories have likely been changed in concert and you will need to |
| traverse their history in concert. Consider studying the history of the |
| repositories to understand why they were published together. |
| |
| ### Q: Can I search the Fuchsia source code without cloning the repo? |
| |
| A: Sure! The [base repository](https://fuchsia.googlesource.com/fuchsia) |
| provides a [Gitiles](https://gerrit.googlesource.com/gitiles/) UI for |
| navigation. You may also use the Google |
| [Open Source Code Search](https://cs.opensource.google/fuchsia/fuchsia) tool |
| to browse and search the Fuchsia codebase online. |