Skip to content

GitLab Integration

Copybara supports GitLab repositories for reading and writing code, including Merge Request workflows.

Read from a GitLab repository:

origin = git.gitlab_origin(
url = "https://gitlab.com/org/project",
ref = "main",
)
ParameterTypeDefaultDescription
urlstringrequiredGitLab repository URL
refstringNoneDefault branch/tag to read from
submodulesstring"NO"Submodule handling: NO, YES, RECURSIVE
excluded_submoduleslist[]Submodule names to exclude
first_parentboolTrueOnly follow first parent in merge commits
partial_fetchboolFalseOnly fetch files matching origin_files glob
describe_versionboolNoneRun git describe on revisions
version_selectorVersionSelectorNoneCustom version/tag selection
patchtransformationNonePatch to apply on checkout
origin = git.gitlab_origin(
url = "https://gitlab.com/org/project",
ref = "main",
submodules = "RECURSIVE",
excluded_submodules = ["large-assets"],
first_parent = True,
)

Read from GitLab Merge Requests:

origin = git.gitlab_mr_origin(
url = "https://gitlab.com/org/project",
credentials = credentials.username_password(
credentials.static_value("username"),
credentials.static_secret("gitlab_token", "GITLAB_TOKEN"),
),
)
ParameterTypeDefaultDescription
urlstringrequiredGitLab repository URL
credentialsUsernamePasswordIssuerNoneAuthentication credentials
use_merge_commitboolFalseUse GitLab’s merge commit instead of MR head
partial_fetchboolFalseOnly fetch files matching origin_files glob
describe_versionboolTrueRun git describe on revisions
first_parentboolTrueOnly follow first parent in merge commits
submodulesstring"NO"Submodule handling: NO, YES, RECURSIVE
excluded_submoduleslist[]Submodule names to exclude
patchtransformationNonePatch to apply on checkout

Pass the Merge Request number as the source reference:

Terminal window
copybara migrate copy.bara.sky import_mr 123

Where 123 is the MR number (IID) in GitLab.

When using git.gitlab_mr_origin, the following labels are available for use in transformations:

LabelDescription
GITLAB_MR_TITLETitle of the Merge Request
GITLAB_MR_URLWeb URL of the Merge Request
GITLAB_MR_DESCRIPTIONDescription/body of the Merge Request
GITLAB_BASE_BRANCH_REFReference to the base branch
core.workflow(
name = "import_mr",
origin = git.gitlab_mr_origin(
url = "https://gitlab.com/org/project",
credentials = credentials.username_password(
credentials.static_value("oauth2"),
credentials.static_secret("gitlab_token", "GITLAB_TOKEN"),
),
use_merge_commit = False,
),
destination = git.destination(
url = "https://internal.example.com/repo",
push = "imported-mrs",
),
authoring = authoring.pass_thru("Bot <bot@example.com>"),
transformations = [
# Use MR metadata in commit message
metadata.replace_message(
"Import MR: ${GITLAB_MR_TITLE}\n\n" +
"Source: ${GITLAB_MR_URL}\n\n" +
"${GITLAB_MR_DESCRIPTION}"
),
],
mode = "CHANGE_REQUEST",
)

GitLab generates a merge commit for each MR showing the result of merging the MR into the target branch:

  • use_merge_commit = False (default): Use the MR head commit (the actual changes)
  • use_merge_commit = True: Use GitLab’s generated merge commit (includes target branch state)
# Use the actual MR changes
origin = git.gitlab_mr_origin(
url = "https://gitlab.com/org/project",
credentials = my_credentials,
use_merge_commit = False, # Default
)
# Use GitLab's merge result (includes target branch)
origin = git.gitlab_mr_origin(
url = "https://gitlab.com/org/project",
credentials = my_credentials,
use_merge_commit = True,
)

Create or update GitLab Merge Requests:

destination = git.gitlab_mr_destination(
url = "https://gitlab.com/org/project",
credentials = credentials.username_password(
credentials.static_value("oauth2"),
credentials.static_secret("gitlab_token", "GITLAB_TOKEN"),
),
target_branch = "main",
)
ParameterTypeDefaultDescription
urlstringrequiredGitLab repository URL
credentialsUsernamePasswordIssuerrequiredAuthentication credentials
target_branchstringrequiredTarget branch for the MR
source_branchstringNoneSource branch name (auto-generated if not set)
titlestringNoneMR title template (supports labels)
bodystringNoneMR description template (supports labels)
assigneeslist[]GitLab usernames to assign
allow_empty_diffboolFalseAllow pushing even if no changes
allow_empty_diff_merge_statuseslist[]Merge statuses that allow empty diff
partial_fetchboolFalseUse partial fetch for baseline
destination = git.gitlab_mr_destination(
url = "https://gitlab.com/org/project",
credentials = credentials.username_password(
credentials.static_value("oauth2"),
credentials.static_secret("gitlab_token", "GITLAB_TOKEN"),
),
target_branch = "main",
source_branch = "copybara/sync-${CONTEXT_REFERENCE}",
title = "Sync from internal: ${CONTEXT_REFERENCE}",
body = """\
## Automated Sync
This MR was automatically created by Copybara.
### Source Reference
${CONTEXT_REFERENCE}
### Review Checklist
- [ ] Review changes
- [ ] Run CI pipeline
- [ ] Approve and merge
""",
assignees = ["maintainer1", "maintainer2"],
allow_empty_diff = False,
)

Available in title, body, and source_branch templates:

VariableDescription
${CONTEXT_REFERENCE}Source commit reference (short SHA or ref)

GitLab integration requires authentication using a Personal Access Token or Project Access Token.

  1. Go to GitLab → User Settings → Access Tokens
  2. Create a new token with scopes:
    • api - Full API access
    • read_repository - Read repository
    • write_repository - Write repository
  3. Copy the token value

GitLab uses bearer token authentication. Configure credentials using credentials.username_password:

# The username can be anything for token auth (commonly "oauth2" or "gitlab-ci-token")
# The password is your GitLab token
my_credentials = credentials.username_password(
credentials.static_value("oauth2"),
credentials.static_secret("gitlab_token", "GITLAB_TOKEN"),
)
Terminal window
# Set the token in environment
export GITLAB_TOKEN="glpat-xxxxxxxxxxxxxxxxxxxx"
# Run Copybara
copybara migrate copy.bara.sky workflow_name

In GitLab CI:

sync:
script:
- copybara migrate copy.bara.sky export
variables:
GITLAB_TOKEN: $CI_JOB_TOKEN # Or use a project variable

In GitHub Actions (syncing TO GitLab):

- name: Run Copybara
env:
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
run: java -jar copybara.jar migrate copy.bara.sky export

Push changes to a GitLab repository:

core.workflow(
name = "export",
origin = git.origin(
url = "https://internal.example.com/repo",
ref = "main",
),
destination = git.destination(
url = "https://gitlab.com/org/project",
push = "main",
),
authoring = authoring.pass_thru("Bot <bot@example.com>"),
origin_files = glob(["src/**"]),
mode = "SQUASH",
)

Create MRs for review before merging:

core.workflow(
name = "export_mr",
origin = git.origin(
url = "https://internal.example.com/repo",
ref = "main",
),
destination = git.gitlab_mr_destination(
url = "https://gitlab.com/org/project",
credentials = credentials.username_password(
credentials.static_value("oauth2"),
credentials.static_secret("gitlab_token", "GITLAB_TOKEN"),
),
target_branch = "main",
title = "Sync from internal",
),
authoring = authoring.pass_thru("Bot <bot@example.com>"),
origin_files = glob(["src/**"]),
mode = "CHANGE_REQUEST",
)

Import external MRs to internal systems:

core.workflow(
name = "import_mr",
origin = git.gitlab_mr_origin(
url = "https://gitlab.com/org/project",
credentials = credentials.username_password(
credentials.static_value("oauth2"),
credentials.static_secret("gitlab_token", "GITLAB_TOKEN"),
),
),
destination = git.gerrit_destination(
url = "https://gerrit.internal.com/repo",
push_to_refs_for = "main",
),
authoring = authoring.allowed(
default = "External Contributor <external@example.com>",
allowlist = ["*@company.com"],
),
transformations = [
metadata.replace_message(
"Import from GitLab MR\n\n" +
"Original: ${GITLAB_MR_URL}\n" +
"Title: ${GITLAB_MR_TITLE}"
),
],
mode = "CHANGE_REQUEST_FROM_SOT",
)

Current limitations of GitLab integration:

FeatureStatus
Basic Git operationsSupported
Merge Request originExperimental
Merge Request destinationExperimental
Feedback endpointNot yet implemented
MR approval requirementsNot yet supported
MR labels/milestonesNot yet supported

FeatureGitHubGitLab
Origingit.github_origingit.gitlab_origin
PR/MR Origingit.github_pr_origingit.gitlab_mr_origin
PR/MR Destinationgit.github_pr_destinationgit.gitlab_mr_destination
API Endpointgit.github_apiNot available
Event Triggergit.github_triggerNot available
StatusStableExperimental