Lockfile Workflow for Team Reproducibility
Source:vignettes/lockfile-workflow.Rmd
lockfile-workflow.RmdThe Problem
When multiple team members install PIP packages from GitHub branches, they may get different code if new commits are pushed between installations. This leads to inconsistent results and hard-to-debug differences.
The Solution: PIP_LOCK.csv
metapip solves this with a lockfile
(PIP_LOCK.csv) that records the exact commit SHA for every
core package. When team members install from the lock, they all get
identical code.
The Lockfile Format
PIP_LOCK.csv is a simple CSV with three columns:
package,branch,sha
pipapi,DEV,94365f9a1ce45ad0d562e73f0612a0cef49727d9
pipload,PROD,ff9a81e386a09fb2531c154f63fd2b91521313c6
wbpip,DEV,fd2c687ed527ebe33d0a7addf9859f72f71ff39f
...
Team Workflow
Step 1: Create the lock (project lead)
Decide which versions of each package your team should use, then snapshot:
library(metapip)
# Verify packages are at the desired versions
get_current_branches()
core_metadata()
# Write the lock
pip_snapshot()The lock is written to
system.file("PIP_LOCK.csv", package = "metapip").
Step 2: Commit the lock
The lockfile should be committed to the metapip repository (or your project repo) so it’s version-controlled:
Step 3: Team members install from the lock
Each team member runs:
init_metapip() reads the lock and installs every package
at its recorded SHA. This is deterministic: the same lock always
produces the same installation.
For Developers: Bypass the Lock
During development, you may need the absolute latest code from a branch, bypassing the lock:
install_branch("pipfun", "ongoing", force = TRUE)Or install the live HEAD of the most recently updated branch for all packages:
Both functions warn that they bypass the team lockfile.
Custom Lock Paths
By default, the lock lives in the metapip inst/
directory. To use a project-specific lock:
# Set a custom lock path
options(metapip.lock_path = "path/to/my/project/PIP_LOCK.csv")
# Now pip_snapshot() and init_metapip() use this path
pip_snapshot()
init_metapip()Non-Interactive Usage
For CI/CD pipelines or scripts, suppress interactive prompts:
init_metapip(ask = FALSE)
update_pip_packages(ask = FALSE)In non-interactive sessions (e.g., Rscript), these
functions automatically install without prompting.
Combining with renv
metapip manages PIP packages from GitHub. For non-PIP
CRAN dependencies, consider using renv as a
companion:
renv::init()
renv::snapshot()The combination of PIP_LOCK.csv (for PIP packages) and
renv.lock (for CRAN packages) gives full
reproducibility.
Summary
| Action | Function |
|---|---|
| Create/update lock | pip_snapshot() |
| Install from lock | init_metapip() |
| Refresh lock + install | update_pip_packages() |
| Developer: bypass lock | install_branch(force = TRUE) |
| Custom lock location | options(metapip.lock_path = …) |