Synchronizing Bitbucket Repositories to GitHub Using a Jenkins Pipeline
This guide explains how to periodically synchronize Bitbucket master branches to GitHub repositories using a Jenkins pipeline, detailing branch policies, a simplified workflow for feature and bugfix branches, and a reusable Jenkinsfile that leverages parameterized builds to control repository syncing.
Our team needs to keep selected examples from an internal Bitbucket server synchronized to GitHub while preserving the existing workflow and only sharing content intended for customers.
The branch strategy enforces that the master branch can only be modified via Pull Request, with at least one reviewer approving before merge. For product and support staff a simplified flow is used: create a feature or bugfix branch from master , commit changes there, then open a Pull Request back to master and merge after reviewer approval.
To avoid adding a Jenkinsfile or webhooks to every repository, a single Jenkins job with a shared Jenkinsfile is created. This reduces redundant Jenkinsfile code, simplifies maintenance, and presents a clean example for non‑IT users.
The approach has drawbacks: it cannot trigger builds directly via SCM webhooks (adding webhooks may require special permissions) and it may be difficult to distinguish which repository sent a request, limiting fine‑grained control.
If synchronization is not frequent, a manual or scheduled job is sufficient.
Jenkins Pipeline
The following Jenkinsfile synchronizes the master branch of selected Bitbucket repositories to the corresponding GitHub repositories. It uses boolean parameters to decide which repositories to process.
// 这个 Jenkinsfile 是用来将 Bitbucket 仓库的 master 分支同步到 GitHub 仓库的 master 分支
@Library('jenkins-shared-library@develop') _
def email = new org.cicd.email()
pipeline {
agent {
label "main-slave"
}
parameters {
booleanParam(defaultValue: false, name: 'git-repo-win', description: 'Sync internal git-repo-win master branch with external git-repo-win on GitHub')
booleanParam(defaultValue: true, name: 'git-repo-lin', description: 'Sync internal git-repo-lin master branch with external git-repo-lin on GitHub')
booleanParam(defaultValue: false, name: 'git-repo-aix', description: 'Sync internal git-repo-aix master branch with external git-repo-aix on GitHub')
booleanParam(defaultValue: false, name: 'git-repo-sol', description: 'Sync internal git-repo-sol master branch with external git-repo-sol on GitHub')
}
options {
timestamps()
buildDiscarder(logRotator(numToKeepStr:'50'))
}
stages {
stage("Synchronous master branch"){
steps{
script {
try {
params.each { key, value ->
def repoName = "${key}"
if ( value == true) {
echo "Start synchronizing ${key} Bitbucket repository."
sh ""
rm -rf ${repoName}
return_status=0
git clone -b master ssh://[email protected]:7999/~xshen/${repoName}.git
cd ${repoName}
git config user.name "Sync Bot"
git config user.email "[email protected]"
git remote add github [email protected]:shenxianpeng/${repoName}.git
git push -u github master
return_status="$?"
if [ $return_status -eq 0 ] ; then
echo "Synchronize ${repoName} from Bitbucket to GitHub success."
cd ..
rm -rf ${repoName}
exit 0
else
echo "Synchronize ${repoName} from Bitbucket to GitHub failed."
exit 1
fi ""
} else {
echo "${repoName} parameter value is $value, skip it."
}
}
cleanWs()
}
catch (error) {
echo "Some error occurs during synchronizing $key process."
} finally {
email.Send(currentBuild.currentResult, env.CHANGE_AUTHOR_EMAIL)
}
}
}
}
}
}The key part of the Jenkinsfile is the params.each { key, value -> } loop, which checks each boolean parameter at build time; if the parameter is selected, the corresponding repository is synchronized, otherwise it is skipped.
In short, this solution provides a lightweight, maintainable way to keep selected Bitbucket repositories in sync with GitHub without altering the existing Bitbucket workflow.
DevOps Engineer
DevOps engineer, Pythonista and FOSS contributor. Created cpp-linter, commit-check, etc.; contributed to PyPA.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.