| # Workflow: Tips |
| |
| This is a list of tips that should help you be more productive when working on fuchsia. |
| |
| ## Gerrit Monitor |
| |
| Install the [Gerrit Monitor](https://chrome.google.com/webstore/detail/gerrit-monitor/leakcdjcdifiihdgalplgkghidmfafoh) |
| Chrome extension to have in the Chrome toolbar the list of CLs requiring your |
| attention. |
| |
| ## Enabling 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 |
| solves 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``` |
| |
| ## Enabling fuchsia-specific git commands |
| |
| Add `$FUCHSIA_REPO/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. |
| |
| |
| # Workflow: Questions and Answers |
| |
| You are encouraged to add your own questions (and answers) here! |
| |
| [TOC] |
| |
| ## 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 "myfeature" 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/master |
| ``` |
| |
| Congratulations, you made your first Gerrit change! |
| |
| Suppose you want to start new work while you wait for review of "myfeature": |
| |
| ```shell |
| # Start a new independent line of work while waiting for review: |
| $ 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 "myfeature" and you've been working on an |
| "independent" line of work: |
| |
| ```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/master |
| ``` |
| |
| When you want to update "myfeature" 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/master |
| ``` |
| |
| When you see "merge conflict" in Gerrit because your change can't cleanly be |
| integrated with "master": |
| |
| ```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/master |
| # 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/master |
| ``` |
| |
| 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/master/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 CL 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/master |
| # 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/+/master/) 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` and `//buildtools`. |
| [`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/master mess up my jiri-updated (i.e. synchronized) view of the repository? |
| |
| A: No, if jiri is managing up to the *same petal* as your repository. |
| |
| 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/master. But other |
| petals' repos will be synced to specific revisions that may be behind HEAD of |
| their origin/master. |
| |
| Our 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/master 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 CLs to not break each petal during a |
| transition (i.e., do a [soft |
| transition](multilayer_changes.md#soft-transitions-preferred)). But sometimes |
| you will necessarily break things; aim to minimize the duration of breakage |
| (i.e., a [hard transition](multilayer_changes.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 gotcha 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. |
| |
| Lets 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 set bringup.x64 out/bringup.x64 |
| $ fx --dir=out/bringup.x64 build |
| ``` |
| |
| Now you have Zircon built, you can start building several other builds concurrently: |
| |
| ```shell |
| $ fx set workstation.x64 out/workstation.x64 |
| $ fx --dir out/workstation.x64 build > workstation.x64.build.log & |
| |
| $ fx set core.arm64 out/core.vim2 |
| $ fx --dir out/core.vim2 build > core.vim2.build.log & |
| |
| $ fx set workstation.arm64 out/workstation.vim2 |
| $ 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: 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](multilayer_changes.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 CLs containing the changes to fuchsia-review.googlesource.com. |
| 1. Upload another CL that modifies the *global integration* repository to |
| reference the git revisions from your CLs. Perform a "dry run" of the |
| commit queue for this CL. |
| |
| 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. |