|author||Nathan Mulcahey <firstname.lastname@example.org>||Sun Aug 29 21:38:37 2021 +0000|
|committer||CQ Bot <email@example.com>||Sun Aug 29 21:38:37 2021 +0000|
[ops] Modify jiri project move behavior Previously, `jiri` would attempt to move a directory atomically with os.Rename(), falling back to exec'ing `mv` directly if the move crossed a mount point. This behavior does not handle a move of a directory to a child of itself, in either the primary or fallback path. Instead we opt to route all moves of directories thru a temporary swap directory in `.jiri_root` to ensure we do not fall into any child path pitfalls and to avoid the mount point complexities if we were to swap thru tmp. Bug: b/195346750 Change-Id: Id99e3127c942f08e4da93d6a5ecf21189b3c8de5 Reviewed-on: https://fuchsia-review.googlesource.com/c/jiri/+/574151 Reviewed-by: Petr Hosek <firstname.lastname@example.org> Commit-Queue: Nathan Mulcahey <email@example.com>
“Jiri integrates repositories intelligently”
Jiri is a tool for multi-repo development. It supports:
Jiri has an extensible plugin model, making it easy to create new sub-commands.
Jiri is open-source.
We have prebuilts for linux and darwin
x86_64 systems. In order to fetch latest jiri source code and build jiri manually, latest version of Go should be installed. After installing Go, you can fetch the latest jiri source code by using the command:
git clone https://fuchsia.googlesource.com/jiri
To build (or rebuild) jiri, simply type the following commands:
cd jiri go install ./cmd/jiri
The binary will be installed to
$GOPATH/bin/jiri, if you set
GOPATH) and can be copied to any directory in your PATH, as long as it is writable (to support jiri bootstrapping and self-updates).
Jiri organizes a set of GIT repositories on your local filesystem according to a manifest. These repositories are referred to as “projects”, and are all contained within a single directory called the “jiri root”.
Jiri also supports CIPD “packages”, to download potentially large read-only files, like toolchain binaries or test data, into the jiri root.
The manifest file specifies the relative location of each project or package within the jiri root, and also includes other metadata, such as its remote url, the remote branch or revision it should track, and more.
jiri update command syncs the master branch of all local projects to the revision and remote branch specified in the manifest for each project. Jiri will create the project locally if it does not exist, and if run with the
-gc flag, jiri will “garbage collect” any projects that are not listed in the manifest by deleting them locally.
The command will also download, update or remove CIPD packages according to manifest changes, if necessary.
.jiri_manifest file in the jiri root describes which project jiri should sync. Typically the
.jiri_manifest file will import other manifests, but it can also contain a list of projects.
For example, here is a simple
.jiri_manifest with just two projects, “foo” and “bar”, which are hosted on github and bitbucket respectively.
<?xml version="1.0" encoding="UTF-8"?> <manifest> <projects> <project name="foo-project" remote="https://github.com/my-org/foo" path="foo"/> <project name="bar" remote="https://bitbucket.com/other-org/bar" path="bar"/> </projects> </manifest>
When you run
jiri update for the first time, the “foo” and “bar” repos will be cloned into
bar respectively and repos would be put on DETACHED HEAD. Running
jiri update again will update all the remote refs and rebase your current branch to its upstream branch.
Note that the project paths do not need to be immediate children of the jiri root. We could have decided to set the
path attribute for the “bar” project to “third_party/bar”, or even nest “bar” inside the “foo” project by setting the
path to “foo/bar” (assuming no files in the foo repo conflict with bar).
Because manifest files also need to be kept in sync between various team members, it often makes sense to keep your team's manifests in a version controlled repository.
Jiri makes it easy to “import” a remote manifest from your local
.jiri_manifest file with the
jiri import command. For example, running the following command will create a
.jiri_manifest file (or append to an existing one) with an
import tag that imports the jiri manifest from the
jiri import -name jiri manifest https://fuchsia.googlesource.com/jiri
The next time you run
jiri update, jiri will sync all projects listed in the jiri manifest.
This section explains how to get started with jiri.
First we “bootstrap” jiri so that it can sync and build itself.
Then we create and import a new manifest, which specifies how jiri should manage your projects.
You can get jiri up-and-running in no time with the help of the bootstrap script.
First, pick a jiri root directory. All projects will be synced to subdirectories of the root.
jiri_bootstrap script, which will fetch and build the jiri tool, and initialize the root directory.
curl -s https://fuchsia.googlesource.com/jiri/+/master/scripts/bootstrap_jiri?format=TEXT | base64 --decode | bash -s "$MY_ROOT"
jiri command line tool will be installed in
$MY_ROOT/.jiri_root/bin/jiri, so add that to your
Next, use the
jiri import command to import the “jiri” manifest from the Jiri repo. This manifest includes Jiri's repository.
cd "$MY_ROOT" jiri import -name jiri manifest https://fuchsia.googlesource.com/jiri
You should now have a file in the root directory called
.jiri_manifest, which will contain a single import.
jiri update, which will sync all local projects to the revisions listed in the manifest (which in this case will be
You should now see the imported project in
jiri update again will sync the local repos to the remotes, and update the jiri tool.
Now that jiri is able to sync and build itself, we must tell it how to manage your projects.
In order for jiri to manage a set of projects, those projects must be listed in a manifest, and that manifest must be hosted in a git repo.
If you already have a manifest hosted in a git repo, you can import that manifest the same way we imported the “jiri” manifest.
For example, if your manifest is called “my_manifest” and is in a repo hosted at “https://github.com/my_org/manifests”, then you can import that manifest as follows.
jiri import my_manifest https://github.com/my_org/manifests
The rest of this section walks through how to create a manifest from scratch, host it from a local git repo, and get jiri to manage it.
Suppose that the project you want jiri to manage is the “Hello-World” repo located at https://github.com/Test-Octowin/Hello-World.
First we‘ll create a new git repo to host the manifest we’ll be writing.
mkdir -p /tmp/my_manifest_repo cd /tmp/my_manifest_repo git init
Next we'll create a manifest and commit it to the manifest repo.
The manifest file will include the Hello-World repo as well as the manifest repo itself.
cat <<EOF > my_manifest <?xml version="1.0" encoding="UTF-8"?> <manifest> <projects> <project name="Hello-World" remote="https://github.com/Test-Octowin/Hello-World" path="helloworld"/> <project name="my_manifest_repo" remote="/tmp/my_manifest_repo" path="my_manifest_repo"/> </projects> </manifest> EOF git add my_manifest git commit -m "Add my_manifest."
This manifest contains a single project with the name “Hello-World” and the remote of the repo. The
path attribute tells jiri to sync this repo inside the
Normally we would want to push this repo to some remote to make it accessible to other users who want to sync the same projects. For now, however, we'll just refer to the repo by its path in the local filesystem.
Now we just need to import that new manifest and
cd "$MY_ROOT" jiri import -name=my_manifest_repo my_manifest /tmp/my_manifest_repo jiri update
You should now see the Hello-World repo in
$MY_ROOT/helloworld, and your manifest repo in
jiri help command will print help documentation about the
jiri tool and its subcommands.
For general documentation, including a list of subcommands, run
jiri help. To find documentation about a specific topic or subcommand, run
jiri help <command>.
branch Show or delete branches diff Prints diff between two snapshots grep Search across projects. import Adds imports to .jiri_manifest file init Create a new jiri root patch Patch in the existing change project Manage the jiri projects project-config Prints/sets project's local config run-hooks Run hooks using local manifest runp Run a command in parallel across jiri projects selfupdate Update jiri tool snapshot Create a new project snapshot source-manifest Create a new source-manifest from current checkout status Prints status of all the projects update Update all jiri projects upload Upload a changelist for review version Print the jiri version help Display help for commands or topics
jiri help [command] for command usage.
See the jiri filesystem docs.
See the jiri manifest docs.
TODO(anmittal): Write me.
Gerrit is a collaborative code-review tool used by many open source projects.
One of the peculiarities of Gerrit is that it expects a changelist to be represented by a single commit. This constrains the way developers may use git to work on their changes. In particular, they must use the --amend flag with all but the first git commit operation and they need to use git rebase to sync their pending code change with the remote master. See Android‘s repo command reference or Go’s contributing instructions for examples of how intricate the workflow for resolving conflicts between the pending code change and the remote master is.
The rest of this section describes common development operations using
All development should take place on a non-master “feature” branch. Once the code is reviewed and approved, it is merged into the remote master via the Gerrit code review system. The change can then be merged into the local branches with
jiri update -rebase-all.
git checkout -b <branch-name> --track origin/master
git add <file1> <file2> ... <fileN>
git checkout <branch-name>
git rebase origin/master
git add <file1> <file2> ... <fileN>
git commit --amend
git checkout <branch-name>
If the CL upload is successful, this will print the URL of the CL hosted on Gerrit. You can add reviewers and comments through the Gerrit web UI at that URL.
Note that there are many useful flags for
jiri upload. You can learn about them by running
jiri help upload.
git checkout <branch-name>
git add -u
git commit --amend
git checkout JIRI_HEAD && git branch -d <branch-name>
If you have changes A and B, and B depends on A, you can still submit distinct CLs for A and B that can be reviewed and submitted independently (although A must be submitted before B).
First, create your feature branch for A, make your change, and upload the CL for review according to the instructions above.
Then, while still on the feature branch for A, create your feature branch for B.
git checkout -b feature-B --track origin/master
Then make your change and upload the CL for review according to the instructions above.
You can respond to review comments by submitting new patch sets as normal.
After the CL for A has been submitted, make sure to clean up A's feature branch and upload a new patch set for feature B.
jiri update # fetch update that includes feature A git checkout feature-B git rebase -i origin/master # if u see commit from A, delete it and then rebase properly jiri upload # send new patch set for feature B
The CL for feature B can now be submitted.
This process can be extended for more than 2 CLs. You must keep two things in mind:
The tool was conceived by engineers working on the Vanadium project to facilitate the multi-repository management needs of the project. At the time, it was called “v23”. It was renamed to “jiri” shortly after its creator (named Jiří) left the project and Google.
Jiří is a very popular boys name in the Czech Republic.
We pronounce “jiri” like “yiree”.
The actual Czech name Jiří is pronounced something like “yirzhee”.