Skip to content

Hello World

Welcome to your first Copybara tutorial! By the end of this guide, you’ll understand how Copybara works by syncing files between two local folders.

No GitHub account or remote servers needed - everything runs on your computer.

You’ll create a workflow that:

  1. Reads files from a “source” folder
  2. Replaces placeholder text (like MYCOMPANYAcme Corp)
  3. Writes the transformed files to a “destination” folder

This is the same pattern used for real-world tasks like publishing internal code to GitHub.

Make sure you have:

  • Java 11 or newer - Check with java -version
  • Git - Check with git --version
  • Copybara JAR file - See Installation

We’ll create this folder structure:

  • Directorycopybara-tutorial/
    • Directorysource/ The folder we’ll read from (origin)
      • README.md
      • Directorysrc/
        • app.py
    • Directorydestination/ The folder we’ll write to (empty for now)
    • copy.bara.sky Your Copybara configuration

Open your terminal and run:

Terminal window
mkdir -p ~/copybara-tutorial/source/src
mkdir -p ~/copybara-tutorial/destination
cd ~/copybara-tutorial

Create source/README.md with this content:

source/README.md
# Welcome to MYPROJECT
This project is built by MYCOMPANY.
For help, contact support@internal.mycompany.com

Create source/src/app.py with this content:

source/src/app.py
# MYPROJECT - Main Application
# Copyright MYCOMPANY
def main():
print("Hello from MYPROJECT!")
if __name__ == "__main__":
main()

Copybara works with Git repositories, so we need to initialize both folders:

Terminal window
# Initialize the source repository
cd ~/copybara-tutorial/source
git init
git add .
git commit -m "Initial commit"
Terminal window
# Initialize the destination repository
cd ~/copybara-tutorial/destination
git init
git commit --allow-empty -m "Initial commit"

Now for the main part - the Copybara configuration file.

Create copy.bara.sky in the copybara-tutorial folder:

copy.bara.sky
sourceUrl = "file://" + "/Users/YOURNAME/copybara-tutorial/source"
destinationUrl = "file://" + "/Users/YOURNAME/copybara-tutorial/destination"
core.workflow(
name = "default",
origin = git.origin(
url = sourceUrl,
ref = "main",
),
destination = git.destination(
url = destinationUrl,
fetch = "main",
push = "main",
),
authoring = authoring.overwrite("Tutorial <tutorial@example.com>"),
transformations = [
core.replace(
before = "MYCOMPANY",
after = "Acme Corp",
),
core.replace(
before = "MYPROJECT",
after = "My Awesome App",
),
core.replace(
before = "internal.mycompany.com",
after = "example.com",
),
],
)

Let’s break down what each part does:

PartWhat it does
originWhere to read files from (our source folder)
destinationWhere to write files to (our destination folder)
ref = "main"Which Git branch to use
authoringWho to credit as the commit author
transformationsChanges to make to the files

The core.replace() transformation finds text and replaces it - like find-and-replace in a text editor, but for your entire project.

Now let’s run it! From the copybara-tutorial folder:

Terminal window
cd ~/copybara-tutorial
java -jar copybara.jar migrate copy.bara.sky default --force

Don’t have copybara.jar in this folder? Use the full path:

Terminal window
java -jar ~/Downloads/copybara_deploy.jar migrate copy.bara.sky default --force

You should see output ending with:

Migration finished successfully.

Let’s see what Copybara created:

Terminal window
cd ~/copybara-tutorial/destination
ls -la

You should see README.md and src/app.py.

Now check the content:

Terminal window
cat README.md

Output:

# Welcome to My Awesome App
This project is built by Acme Corp.
For help, contact support@example.com

The placeholders were replaced:

BeforeAfter
MYPROJECTMy Awesome App
MYCOMPANYAcme Corp
internal.mycompany.comexample.com

Check the Python file too:

Terminal window
cat src/app.py
# My Awesome App - Main Application
# Copyright Acme Corp
def main():
print("Hello from My Awesome App!")
if __name__ == "__main__":
main()
Diagram

Copybara:

  1. Read all committed files from the source Git repository
  2. Applied transformations - replaced the placeholder text
  3. Wrote the transformed files to the destination
  4. Committed the changes in the destination repository

Let’s see incremental sync in action. Edit the source file:

Terminal window
cd ~/copybara-tutorial/source

Add a new file source/src/utils.py:

source/src/utils.py
# MYPROJECT utilities
# Author: MYCOMPANY Team
def helper():
return "I help MYPROJECT run smoothly!"

Commit the change:

Terminal window
git add src/utils.py
git commit -m "Add utilities"

Run Copybara again (no --force needed now):

Terminal window
cd ~/copybara-tutorial
java -jar copybara.jar migrate copy.bara.sky default

Check the destination:

Terminal window
cat ~/copybara-tutorial/destination/src/utils.py

The new file appears with all replacements applied - only the new changes were synced.

Your Git might use master as the default branch. Either:

Option A: Change the config to use master:

ref = "master",
fetch = "master",
push = "master",

Option B: Rename your branch to main:

Terminal window
cd ~/copybara-tutorial/source
git branch -m master main
cd ~/copybara-tutorial/destination
git branch -m master main

This means source and destination are already in sync. Make a change in the source, commit it, then run Copybara again.

Make sure your workflow in copy.bara.sky has name = "default", or use the name you chose:

Terminal window
java -jar copybara.jar migrate copy.bara.sky YOUR_WORKFLOW_NAME --force

Double-check that:

  1. The paths in your config use file:// prefix
  2. The paths are absolute (start with /)
  3. You replaced YOURNAME with your actual username
  4. Both Git repos have at least one commit

Now that you understand the basics: