Skip to content

Metadata Transformations

Metadata transformations modify commit messages, author information, and other Git metadata.

Customize the commit message when squashing:

metadata.squash_notes(
prefix = "Sync from internal:\n\n",
show_author = True,
show_description = True,
)
ParameterDescription
prefixText before the notes
show_authorInclude original authors
show_descriptionInclude original commit messages
oldest_firstOrder by oldest first (default: newest)
maxMaximum number of notes to include
compactUse compact format
# Full details
metadata.squash_notes(
prefix = "Changes imported from internal:\n\n",
show_author = True,
show_description = True,
oldest_first = True,
)
# Compact format
metadata.squash_notes(
compact = True,
max = 10,
)
Changes imported from internal:
- Alice <alice@example.com>: Fix validation bug
- Bob <bob@example.com>: Add user authentication
- Alice <alice@example.com>: Update tests
GitOrigin-RevId: abc123def456

Add text to commit messages:

metadata.add_header("Synced-From: internal-repo")
ParameterDescription
textText to add
new_lineAdd newline before header (default: True)
ignore_label_not_foundDon’t fail if label missing
# Simple header
metadata.add_header("Synced-From: internal")
# With label reference
metadata.add_header(
text = "Reviewed-By: ${REVIEWED_BY}",
ignore_label_not_found = True,
)
# Multiple headers
transformations = [
metadata.add_header("Synced-From: internal"),
metadata.add_header("Sync-Bot: copybara"),
]

Make commit message labels available for use:

metadata.expose_label("Bug")
metadata.expose_label("Reviewed-by")
transformations = [
# Standard Git trailers
metadata.expose_label("Co-authored-by"),
metadata.expose_label("Signed-off-by"),
metadata.expose_label("Reviewed-by"),
# GitHub keywords
metadata.expose_label("Closes"),
metadata.expose_label("Fixes"),
metadata.expose_label("Resolves"),
]

Remap author email addresses:

metadata.map_author({
"internal@corp.com": "external@example.com",
"alice.internal@corp.com": "alice@example.com",
})
# Map multiple authors
metadata.map_author({
"alice@internal.corp": "alice@public.example.com",
"bob@internal.corp": "bob@public.example.com",
"service@internal.corp": "bot@public.example.com",
})

Replace the entire commit message:

metadata.replace_message("Automated sync from internal repository")
metadata.replace_message("""\
Sync: ${COPYBARA_CONTEXT_REFERENCE}
This commit was automatically synced from the internal repository.
Original commit: ${COPYBARA_CONTEXT_REFERENCE}
""")

Remove a label from commit messages:

metadata.remove_label("Internal-Bug")

Restore original author from a label:

metadata.restore_author(
label = "ORIGINAL_AUTHOR",
search_all_changes = True,
)
transformations = [
# Preserve standard trailers
metadata.expose_label("Co-authored-by"),
metadata.expose_label("Signed-off-by"),
# Map internal emails
metadata.map_author({
"internal@corp.com": "external@example.com",
}),
# Add sync metadata
metadata.add_header("Synced-From: internal"),
metadata.add_header("Sync-Time: ${COPYBARA_CURRENT_TIME}"),
# Squash with notes
metadata.squash_notes(
prefix = "Imported changes:\n\n",
show_author = True,
show_description = True,
),
]

In ITERATIVE mode, each commit retains its individual message:

# Only add header, don't squash
transformations = [
metadata.add_header("GitOrigin-RevId: ${COPYBARA_CONTEXT_REFERENCE}"),
]

Copybara adds state tracking to commit messages:

Original commit message here.
GitOrigin-RevId: abc123def456789

This allows Copybara to track what’s been synced.