Skip to content

Running a command for each repo in the workspace

tsrc comes with a foreach command that allows you to run the same command for each repo in the workspace.

This can be used for several things. For instance, if you are building an artifact from a group of repositories, you may want to put a tag on each repo that was used to produce it:

$ tsrc foreach git tag v1.2
:: Using workspace in /path/to/work
:: Running `git tag v1.1` on 2 repos
/path/to/work/foo $ git tag v1.2
/path/to/work/bar $ git tag v1.2
/path/to/work/baz $ git tag v1.2
OK ✓

Caveats

  • If the command you want to run contains arguments starting with -: you need to call foreach like this:
$ tsrc foreach -- some-command --with-option
  • By default, the command is passed "as is", without starting a shell. If you want to use a shell, use the -c option:
$ tsrc foreach -c  'echo $PWD'

Note that we need single quotes here to prevent the shell from expanding the PWD environment variable when tsrc is run.

Using repo and manifest data

The current tsrc implementation may not contain all the features your organization needs.

The good news is that you can extend tsrc's feature set by using tsrc foreach.

Let's take an example, where you have a manifest containing foo and bar and both repos are configured to use a master branch.

Here's what happens if you run tsrc sync with bar on the correct branch (master), and foo on an incorrect branch (devel):

$ tsrc sync
:: Using workspace in /path/to/work
=> Updating manifest
...
=> Cloning missing repos
=> Configuring remotes
=> Synchronizing repos
* (1/2) Synchronizing foo
* Fetching origin
* Updating branch: devel
Updating 702f428..2e4fb45
Fast-forward
...
* (2/2) Synchronizing bar
* Fetching origin
* Updating branch: master
Already up to date.
Error: Failed to synchronize the following repos:
* foo : Current branch: 'devel' does not match expected branch: 'master'

If this happens with multiple repos, you may want a command to checkout the correct branch automatically.

Here's one way to do it:

$ tsrc foreach -c 'git checkout $TSRC_PROJECT_MANIFEST_BRANCH'

Here we take advantage of the fact that tsrc sets the TSRC_PROJECT_MANIFEST_BRANCH environment variable correctly for each repository before running the command.

Here's the whole list:

Variable Description
TSRC_WORKSPACE_PATH Full path of the workspace root
TSRC_MANIFEST_BRANCH Branch of the manifest
TSRC_MANIFEST_URL URL of the manifest
TSRC_PROJECT_CLONE_URL URL used to clone the repo
TSRC_PROJECT_DEST Relative path of the repo in the workspace
TSRC_PROJECT_MANIFEST_BRANCH Branch configured in the manifest for this repo
TSRC_PROJECT_REMOTE_<NAME> URL of the remote named 'NAME'
TSRC_PROJECT_STATUS_DIRTY Set to true if the project is dirty, otherwise unset
TSRC_PROJECT_STATUS_AHEAD Number of commits ahead of the remote ref
TSRC_PROJECT_STATUS_BEHIND Number of commits behind the remote ref
TSRC_PROJECT_STATUS_BRANCH Current branch of the repo
TSRC_PROJECT_STATUS_SHA1 SHA1 of the current branch
TSRC_PROJECT_STATUS_STAGED Number of files that are staged but not committed
TSRC_PROJECT_STATUS_NOT_STAGED Number of files that are changed but not staged
TSRC_PROJECT_STATUS_UNTRACKED Number of files that are untracked

You can implement more complex behavior using the environment variables above, for instance:

#!/bin/bash
# in switch-and-pull
if [[ "${TSRC_PROJECT_STATUS_DIRTY}" = "true" ]]; then
  echo Error: project is dirty
  exit 1
fi

git switch $TSRC_PROJECT_MANIFEST_BRANCH
git pull
$ tsrc foreach switch-and-pull
:: Running `switch-and-pull` on 2 repos
* (1/2) foo
/path/to/foo $ switch-and-pull
Switched to branch 'master'
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)
Updating 9e7a8e4..5f9bbd4
Fast-forward
* (2/2) bar
/path/to/bar $ switch-and-pull
Error: project is dirty
Error: Command failed for 1 repo(s)
* bar

Of course, feel free to use your favorite programming language here :)