{"id":3431,"date":"2022-11-28T10:40:57","date_gmt":"2022-11-28T10:40:57","guid":{"rendered":"https:\/\/gitprotect.io\/blog\/?p=3431"},"modified":"2025-06-13T09:10:30","modified_gmt":"2025-06-13T09:10:30","slug":"bitbucket-to-gitlab-migration-in-a-few-simple-steps","status":"publish","type":"post","link":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/","title":{"rendered":"Bitbucket to GitLab Migration in a Few Simple Steps"},"content":{"rendered":"\n<p><strong>Moving data from Bitbucket to GitLab is usually dictated by the need to streamline the company\u2019s development processes. It also involves the desire to unify the toolset and the benefits of using GitLab&#8217;s versatile DevOps features.<\/strong><\/p>\n\n\n\n<!--more-->\n\n\n\n<p>A foundation of a smooth transition lies in a detailed roadmap for developers and admins. It includes all technical measures necessary to minimize disruptions and mitigate unwanted challenges. As always, the whole process begins with preparations.<\/p>\n\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Key preparations for the migration process<\/strong><\/h2>\n\n\n\n<p>The first step is to assess your current environment in Bitbucket. This will allow you to determine the scope of your dataset and maintain continuity during the migration. It can also serve as a form of audit before making a business change.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Current environment assessment<\/strong><\/h3>\n\n\n\n<p>To properly assess your Bitbucket platform for migration purposes, you need to pay attention to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>repository inventory<\/li>\n\n\n\n<li>repos size and complexity<\/li>\n\n\n\n<li>active users and permissions<\/li>\n\n\n\n<li>CI\/CD pipelines.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Repository inventory<\/strong><\/h4>\n\n\n\n<p>You can approach this step programmatically by utilizing Bitbucket REST API to obtain the list of your repos. You won\u2019t overlook any directory, even in large workspaces.<\/p>\n\n\n\n<p>An example API call may look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl -u<\/strong> &lt;username&gt;:&lt;app_password&gt; \\ \nhttps:&#47;&#47;api.bitbucket.org\/2.0\/repositories\/&lt;workspace&gt;<\/code><\/pre>\n\n\n\n<p>Next, to extract repository names, types (private, public, fork), and links, you should parse the JSON response. If you plan to use a Python snippet (an example):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>import<\/strong> requests\n\nrepos_url = \"https:\/\/api.bitbucket.org\/2.0\/repositories\/&lt;workspace&gt;\"\nresponse = requests.get(repos_url, auth=('&lt;username&gt;', '&lt;app_password&gt;'))\nrepos = response.json()\nfor repo in repos&#091;'values']:\n&nbsp;&nbsp;&nbsp;&nbsp;print(f\"Repo Name: {repo&#091;'name']}, Type: {repo&#091;'is_private'] and 'Private'\n&nbsp;&nbsp;&nbsp;&nbsp;or 'Public'}\")<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Repository size and complexity<\/strong><\/h4>\n\n\n\n<p>To assess repository size and branching structure, you can utilize the git clone &#8211;mirror command or Bitbucket\u2019s API. Migrating big repos, all the more so with long commit histories, may require, e.g., pruning unused branches or history compression.<\/p>\n\n\n\n<p>For instance, fetching repo size:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>git clone --mirror<\/strong> https:\/\/&lt;username&gt;@bitbucket.org\/&lt;workspace&gt;\/&lt;repo&gt;.git\n<strong>du<\/strong> -sh &lt;repo&gt;.git<\/code><\/pre>\n\n\n\n<p>Further, use the git branch and git log to analyze branching complexity. To identify unused tags or orphaned branches you can also utilize custom scripts.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Active users and permissions<\/strong><\/h4>\n\n\n\n<p>Dealing with users, you\u2019ll export the entire list of collaborators, including their roles. To retrieve permissions, you can use an API from Bitbucket.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl -u<\/strong> &lt;username&gt;:&lt;app_password&gt; \\\nhttps:&#47;&#47;api.bitbucket.org\/2.0\/repositories\/&lt;workspace&gt;\/&lt;repo&gt;\/permissions\/users<\/code><\/pre>\n\n\n\n<p>Next, it\u2019s time for role mapping. For that, documenting all roles (admin, write, or read access) for all repositories is a necessity. You must determine how such details will map to GitLab\u2019s permission model.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>CI\/CD pipelines<\/strong><\/h4>\n\n\n\n<p>For CI\/CD pipelines, you\u2019ll need to export current CI\/CD configurations from Bitbucket Pipelines \u2013 for each repo. For this purpose, use the bitbucket-pipeline.yml file to evaluate workflows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>build stages<\/li>\n\n\n\n<li>deployment scripts<\/li>\n\n\n\n<li>environment variables.<\/li>\n<\/ul>\n\n\n\n<p>The Bitbucket pipeline YAML snippet can be formatted like this (an example):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>pipelines<\/strong>:\n&nbsp;&nbsp;default:\n&nbsp;&nbsp;&nbsp;&nbsp;- step:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name: Build\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;script:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- npm install\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- npm run build<\/code><\/pre>\n\n\n\n<p>It\u2019s crucial to compare the extended pipeline structure with the syntax of the .gitlab-ci.yml file to spot potential gaps or areas for optimization.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/gitprotect.io\/git-backup-guide.html?utm_source=blog&amp;utm_medium=blog\" target=\"_blank\" rel=\"noreferrer noopener\"><img decoding=\"async\" width=\"512\" height=\"512\" src=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/07\/Ebook-Git-backup-guide.png\" alt=\"Git Backup Guide\" class=\"wp-image-5473\" style=\"width:500px;height:auto\" srcset=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/07\/Ebook-Git-backup-guide.png 512w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/07\/Ebook-Git-backup-guide-300x300.png 300w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/07\/Ebook-Git-backup-guide-150x150.png 150w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/07\/Ebook-Git-backup-guide-180x180.png 180w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/07\/Ebook-Git-backup-guide-400x400.png 400w\" sizes=\"(max-width: 512px) 100vw, 512px\" \/><\/a><\/figure><\/div>\n\n\n<p>&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Defining the target state<\/strong><\/h3>\n\n\n\n<p>At this stage, you dive a bit deeper into your GitLab repos elements \u2013 planning group and project structures, CI\/CD pipeline identification, and setting a timeline with milestones.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Plan GitLab group and project structure<\/strong><\/h4>\n\n\n\n<p>One of the things that differentiates GitLab from Bitbucket is the organization of repos into groups and subgroups. You can plan your structure based on your organization\u2019s needs, including:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Top-level groups: <\/strong>These represent business units or departments.<\/li>\n\n\n\n<li><strong>Subgroups: <\/strong>They relate to projects, teams, or products.<\/li>\n\n\n\n<li><strong>Projects: <\/strong>The last group contains repositories.<\/li>\n<\/ul>\n\n\n\n<p>In practice, the structure described above may look like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" width=\"496\" height=\"436\" src=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration.png\" alt=\"organization structure\" class=\"wp-image-6348\" style=\"width:500px;height:auto\" srcset=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration.png 496w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-300x264.png 300w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-400x352.png 400w\" sizes=\"(max-width: 496px) 100vw, 496px\" \/><\/figure><\/div>\n\n\n<p>When creating a structure, planning namespace mappings is necessary to make sure repos align logically. You can use the GitLab API to automate the process.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl<\/strong> --header \"PRIVATE-TOKEN: &lt;your_access_token&gt;\" \\\n&nbsp;     --data \"name=Backend&amp;path=backend&amp;namespace_id=&lt;group_id&gt;\" \\\n&nbsp;     \"https:\/\/&lt;gitlab_instance&gt;\/api\/v4\/projects\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Identifying CI\/CD pipeline features<\/strong><\/h4>\n\n\n\n<p>For this purpose, it\u2019s recommended to (a necessity) compare Bitbucket Pipelines with GitLab\u2019s CI\/CD features, considering:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Bitbucket features<br><\/strong>&#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211;<br><br>&#8211; sequential steps<br>&#8211; parallel builds<br>&#8211; deployment environments<\/td><td><strong>GitLab features<\/strong><br>&#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211; &#8211;<strong> <br><br><\/strong>&#8211; stages<br>&#8211; jobs<br>&#8211; dependencies<br>&#8211; built-in runners<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Such a pipeline conversion may be realized utilizing the YAML structure.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Bitbucket YAML<\/strong><\/td><td><strong>GitLab YAML<\/strong><\/td><\/tr><tr><td>&nbsp; pipelines:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8211; step:<br>  &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; name: Build<br>  &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; script:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; mvn clean install<\/td><td> stages:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8211; build<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;build-job:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stage: build<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;script:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8211; mvn clean install<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Setting a timeline with milestones<\/strong><\/h4>\n\n\n\n<p>You can divide this particular step into 5 phases. Their number, given time, and scope of activities depend strictly on your needs and the mitigation volume.<\/p>\n\n\n\n<p><strong>Phase 1. Repository preparation<\/strong>&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Inventory all repos and CI\/CD pipelines.<\/li>\n\n\n\n<li>Clean up unused branches, tags, and obsolete pipelines.<\/li>\n<\/ul>\n\n\n\n<p><strong>Phase 2. Initial migration<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Migrate smaller repositories to test GitLab configurations.<\/li>\n\n\n\n<li>Validate repository structures, permissions, and access levels.<\/li>\n<\/ul>\n\n\n\n<p><strong>Phase 3. CI\/CD migration and testing<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Migrate and test CI\/CD workflows in GitLab.<\/li>\n\n\n\n<li>Use GitLab\u2019s pipeline lint to validate .gitlab-ci.yml.<\/li>\n<\/ul>\n\n\n\n<p><strong>Phase 4. Full migration and final testing<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Complete repository migration.<\/li>\n\n\n\n<li>Conduct final validations to guarantee data integrity and access control.<\/li>\n<\/ul>\n\n\n\n<p><strong>Phase 5. Decommission Bitbucket<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mark Bitbucket repositories as read-only. Archive or delete after approval.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Bitbucket to GitLab migration steps<\/strong><\/h2>\n\n\n\n<p>All pre-migration preparations described so far should allow you to initiate the migration process confidently. Especially if your team took care of every detail. The migration process starts with setting up GitLab.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Set up GitLab<\/strong><\/h3>\n\n\n\n<p>Given your business and chosen IT stack, you can install GitLab on-premises or sign up for GitLab online (SaaS).<\/p>\n\n\n\n<p>For an <strong>on-premise installation<\/strong>, download and install the GitLab package from GitLab\u2019s repository. Installation options include Docker, Kubernetes, and Linux package managers like apt or yum.<\/p>\n\n\n\n<p>In the Ubuntu distro, the installation approach looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl<\/strong> -s https:\/\/packages.gitlab.com\/install\/repositories\/gitlab\/gitlab-ee\/script.deb.sh | \n<strong>sudo bash<\/strong>\n<strong>sudo apt-get install<\/strong> gitlab-ee\n<strong>sudo gitlab-ctl<\/strong> reconfigure<\/code><\/pre>\n\n\n\n<p>Sign up at GitLab.com and create a new group or project for SaaS.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Configure project namespaces and groups<\/strong><\/h4>\n\n\n\n<p>Having the platform working, define <strong>top-level groups <\/strong>to represent organizational units (departments, teams, or clients). Use <strong>subgroups<\/strong> to align with product lines or projects.<\/p>\n\n\n\n<p>Next, automate group creation with GitLab\u2019s API:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl --header<\/strong> \"PRIVATE-TOKEN: &lt;your_access_token&gt;\" \\\n&nbsp; --data \"name=&lt;group_name&gt;&amp;path=&lt;group_path&gt;\" \\\n&nbsp; \"https:\/\/&lt;gitlab_instance&gt;\/api\/v4\/groups\"<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Set up user accounts and permissions<\/strong><\/h4>\n\n\n\n<p>Now, import users from Bitbucket using the GitLab API. Assign roles based on Bitbucket permissions.&nbsp;<\/p>\n\n\n\n<p>To automate user assignment, use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl --header<\/strong> \"PRIVATE-TOKEN: &lt;your_access_token&gt;\" \\\n&nbsp; --data \"user_id=&lt;user_id&gt;&amp;access_level=&lt;access_level&gt;\" \\\n  \"https:\/\/&lt;gitlab_instance&gt;\/api\/v4\/projects\/&lt;project_id&gt;\/members\"<\/code><\/pre>\n\n\n\n<p>If you use GitLab SaaS, integrate with SSO providers or LDAP for seamless user management.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/gitprotect.io\/devops-backup-academy.html\" target=\"_blank\" rel=\" noreferrer noopener\"><img decoding=\"async\" width=\"1024\" height=\"346\" src=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/banner_orange-1024x346.png\" alt=\"DevOps Backup Academy\" class=\"wp-image-6787\" style=\"width:500px;height:auto\" srcset=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/banner_orange-1024x346.png 1024w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/banner_orange-300x102.png 300w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/banner_orange-768x260.png 768w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/banner_orange-400x135.png 400w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/banner_orange.png 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\"><strong>Export repositories from Bitbucket<\/strong><\/h3>\n\n\n\n<p>When the above elements are set, it\u2019s time to prepare Bitbucket repos to export.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Clone repositories<\/strong><\/h4>\n\n\n\n<p>You should start by cloning repos using the\u2014-mirror flag. This will preserve all branches, tags, and references, which is crucial for an accurate migration.<\/p>\n\n\n\n<p>Execute the git clone &#8211;mirror command for each repository.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>git clone<\/strong> --mirror https:\/\/&lt;username&gt;@bitbucket.org\/&lt;workspace&gt;\/&lt;repo&gt;.git<\/code><\/pre>\n\n\n\n<p>You can also automate cloning for multiple repositories using a script, for example (Bash):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Define workspace and credentials\nWORKSPACE=\"&lt;workspace&gt;\"\nUSERNAME=\"&lt;username&gt;\"\nAPP_PASSWORD=\"&lt;app_password&gt;\"\n\n# List of repositories\nREPOS=(\"repo1\" \"repo2\" \"repo3\")\n\n# Loop through repositories and clone each\nfor REPO in \"${REPOS&#091;@]}\"; do\n      echo \"Cloning $REPO...\"\n      git clone --mirror https:\/\/${USERNAME}:${APP_PASSWORD}@bitbucket.org\/${WORKSPACE}\/${REPO}.git\ndone<\/code><\/pre>\n\n\n\n<p>The script above iterates over a predefined list of repositories and clones each one.<\/p>\n\n\n\n<p>In the next step, verify repository integrity post-clone.<\/p>\n\n\n\n<p>Check the size:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>du<\/strong> -sh &lt;repo&gt;.git<\/code><\/pre>\n\n\n\n<p>Confirm branches and tags:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git show-ref<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Archive metadata<\/strong><\/h4>\n\n\n\n<p><br>Metadata includes pull requests, issues, comments, and other repository-related data. The Bitbucket REST API is necessary to extract such information.<\/p>\n\n\n\n<p><strong>Pull requests<\/strong><\/p>\n\n\n\n<p>Using the API mentioned above, export pull requests:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl -u<\/strong> &lt;username&gt;:&lt;app_password&gt; \\\n \thttps:&#47;&#47;api.bitbucket.org\/2.0\/repositories\/&lt;workspace&gt;\/&lt;repo&gt;\/pullrequests<\/code><\/pre>\n\n\n\n<p>It\u2019s worth noting that you may also need to handle paged results for large databases, as pagination applies.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl -u<\/strong> &lt;username&gt;:&lt;app_password&gt; \\ \"https:\/\/api.bitbucket.org\/2.0\/repositories\/&lt;workspace&gt;\/&lt;repo&gt;\/pullrequests?page=2\"<\/code><\/pre>\n\n\n\n<p>To save the output to a file (e.g., for later use), utilize:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl -u<\/strong> &lt;username&gt;:&lt;app_password&gt; \\\n \thttps:\/\/api.bitbucket.org\/2.0\/repositories\/&lt;workspace&gt;\/&lt;repo&gt;\/pullrequests &gt; pullrequests.json<\/code><\/pre>\n\n\n\n<p>The command retrieves pull requests in JSON format. For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"values\": &#091;\n\t{\n  \t\"id\": 1,\n  \t\"title\": \"Update README\",\n  \t\"state\": \"MERGED\",\n  \t\"author\": {\n    \t\"display_name\": \"John Doe\"\n  \t},\n  \t\"created_on\": \"2023-01-15T12:34:56Z\",\n  \t\"updated_on\": \"2023-01-18T08:45:00Z\"\n\t}\n  ]\n}<\/code><\/pre>\n\n\n\n<p><strong>Issues<\/strong><\/p>\n\n\n\n<p>Fetch issues using a similar API request.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl -u<\/strong> &lt;username&gt;:&lt;app_password&gt; \\\n \thttps:&#47;&#47;api.bitbucket.org\/2.0\/repositories\/&lt;workspace&gt;\/&lt;repo&gt;\/issues<\/code><\/pre>\n\n\n\n<p>In the same way, as in the above pull request case, you can handle pagination and save output in JSON format. However, you can <strong>convert JSON<\/strong> files <strong>to CSV format<\/strong> to make the review more manageable.<\/p>\n\n\n\n<p>A Python script, for example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>import<\/strong> json\n<strong>import<\/strong> csv\n\n# Load JSON data\nwith open('issues.json', 'r') as file:\n\tdata = json.load(file)\n\n# Write to CSV\nwith open('issues.csv', 'w', newline='') as csvfile:\n\tfieldnames = &#091;'id', 'title', 'state', 'created_on,' 'updated_on']\n\twriter = csv.DictWriter(csvfile, fieldnames=fieldnames)\n\n\twriter.writeheader()\n\tfor issue in data&#091;'values']:\n    \twriter.writerow({\n        \t'id': issue&#091;'id'],\n        \t'title': issue&#091;'title'],\n        \t'state': issue&#091;'state'],\n        \t'created_on': issue&#091;'created_on'],\n        \t'updated_on': issue&#091;'updated_on']\n    \t})<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Import repositories to GitLab<\/strong><\/h4>\n\n\n\n<p>Start importing repos to GitLab by <strong>pushing cloned repositories<\/strong> to GitLab using the &#8211;mirror flag.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>git push --mirror<\/strong> https:\/\/&lt;gitlab_instance&gt;\/&lt;group&gt;\/&lt;repo&gt;.git<\/code><\/pre>\n\n\n\n<p>To automate project creation and repository imports, use GitLab\u2019s API. Take a script for bulk import as an example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>for<\/strong> repo in $(cat repos.txt); do\n  curl --header \"PRIVATE-TOKEN: &lt;your_access_token&gt;\" \\\n   \t--data \"name=$(basename $repo)&amp;namespace_id=&lt;group_id&gt;\" \\\n   \t\"https:\/\/&lt;gitlab_instance&gt;\/api\/v4\/projects\"\ndone<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Migrate CI\/CD pipelines<\/strong><\/h3>\n\n\n\n<p>Start the CI\/CD pipeline migration process with their conversion.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Pipeline conversion<\/strong><\/h4>\n\n\n\n<p>Before transforming Bitbucket Pipelines to GitLab CI\/CD,&nbsp; you should analyze the structure and adapt stages, jobs, and steps to GitLab\u2019s syntax.<\/p>\n\n\n\n<p><strong>1. Review the Bitbucket pipeline<\/strong> (bitbucket-pipelines.yml)<\/p>\n\n\n\n<p>For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>pipelines<\/strong>:\n  <strong>default<\/strong>:\n\t- <strong>step<\/strong>:\n    \t<strong>name<\/strong>: Build and Test\n    \t<strong>script<\/strong>:\n      \t- npm install\n      \t- npm run build\n      \t- npm test\n\t- <strong>step<\/strong>:\n    \t<strong>name<\/strong>: Deploy\n    \t<strong>script<\/strong>:\n      \t- npm run deploy\n  <strong>branches<\/strong>:\n\tfeature\/*:\n  \t- <strong>step<\/strong>:\n      \t<strong>name<\/strong>: Feature Branch Build\n      \t<strong>script<\/strong>:\n        \t- npm install\n        \t- npm run build<\/code><\/pre>\n\n\n\n<p><strong>2. Map to GitLab\u2019s syntax<\/strong><\/p>\n\n\n\n<p>GitLab CI\/CD uses (.gitlab-ci.yml) with stages and jobs. You need to convert Bitbucket\u2019s step into GitLab\u2019s job under a specific stage.<\/p>\n\n\n\n<p>The converted GitLab Pipeline may look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>stages<\/strong>:\n  - build\n  - test\n  - deploy\n\n<strong>build-job<\/strong>:\n  <strong>stage<\/strong>: build\n  <strong>script<\/strong>:\n\t- npm install\n\t- npm run build\n\n<strong>test-job<\/strong>:\n  <strong>stage<\/strong>: test\n  <strong>script<\/strong>:\n\t- npm test\n\n<strong>deploy-job<\/strong>:\n  <strong>stage<\/strong>: deploy\n  <strong>script<\/strong>:\n\t- npm run deploy\n\n<strong>feature-branch-build<\/strong>:\n  <strong>stage<\/strong>: build\n  <strong>script<\/strong>:\n\t- npm install\n\t- npm run build\n  <strong>only<\/strong>:\n\t- \/^feature\\\/.*$\/<\/code><\/pre>\n\n\n\n<p>As you can see:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>stages are defined explicitly: <em>build, test, deploy<\/em><\/li>\n\n\n\n<li>each Bitbucket <em>step<\/em> becomes a GitLab <em>job<\/em><\/li>\n\n\n\n<li>to replicate Bitbucket\u2019s branch-specific pipelines only, or excerpts are used in GitLab. For instance, <em>only: &#8211; \/^feature\\\/.*$\/<\/em> guarantees jobs run on feature branches.<\/li>\n<\/ul>\n\n\n\n<p><strong>3. Handle environment variables<\/strong><\/p>\n\n\n\n<p>You need to migrate the environmental variables defined in Bitbucket to GitLab manually. In Bitbucket, they are typically defined in repository settings or bitbucket-pipelines.yml.<\/p>\n\n\n\n<p>As for GitLab, you can add environment variables via the GitLab UI or API:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>navigate to <strong>Settings \u2192 CI\/CD \u2192 Variables<\/strong><\/li>\n\n\n\n<li>define each variable (e.g., API_KEY, NODE_ENV)<\/li>\n<\/ul>\n\n\n\n<p>Use the<strong> GitLab API <\/strong>to set variables:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl --header<\/strong> \"PRIVATE-TOKEN: &lt;your_access_token&gt;\" \\\n \t--data \"key=API_KEY&amp;value=your_api_key&amp;protected=true\" \\\n \t\"https:\/\/&lt;gitlab_instance&gt;\/api\/v4\/projects\/&lt;project_id&gt;\/variables\"<\/code><\/pre>\n\n\n\n<p>As for variable mapping, it looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Bitbucket <\/strong>BITBUCKET_ENV_VAR<br>script:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8211; echo $BITBUCKET_ENV_VAR<\/td><td><strong>GitLab <\/strong>GITLAB_ENV_VAR<br>script:<br>&nbsp;&nbsp;&nbsp;&#8211; echo $GITLAB_ENV_VAR<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><strong>4. Validation process<\/strong><\/p>\n\n\n\n<p>Before moving further, it\u2019s a recommended practice (if not a necessity) to validate pipeline migration.<\/p>\n\n\n\n<p>In the first step, <strong>lint the GitLab CI\/CD pipeline.<\/strong> Validate ..gitlab-ci.yml syntax using (Gitlab\u2019s CI\/CD) lint tool before you push the file.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Go to <strong>CI\/CD \u2192 Pipeline Editor \u2192 Lint<\/strong>.<\/li>\n\n\n\n<li>Paste the .gitlab-ci.yml content and check for errors.<\/li>\n<\/ul>\n\n\n\n<p>The alternative approach involves API:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl<\/strong> --header \"PRIVATE-TOKEN: &lt;your_access_token&gt;\" \\\n \t--header \"Content-Type: application\/json\" \\\n \t--data '{\"content\": \"&lt;your .gitlab-ci.yml content&gt;\"}' \\\n \t\"https:\/\/&lt;gitlab_instance&gt;\/api\/v4\/ci\/lint\"<\/code><\/pre>\n\n\n\n<p>Next, <strong>test pipelines<\/strong>. Commit the .gitlab-ci.yml to the repo and trigger a pipeline run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git add .gitlab-ci.yml\ngit commit -m \"Add GitLab pipeline\"\ngit push<\/code><\/pre>\n\n\n\n<p>Remember to monitor the pipeline execution in <strong>CI\/CD \u2192 Pipelines<\/strong>.<\/p>\n\n\n\n<p>Before completing the whole pipeline migration step, adjust and refine. In other words:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>address any discrepancies between the behavior of the Bitbucket pipeline and the GitLab one<\/li>\n\n\n\n<li>make sure that deployment stages are executed correctly and verify all external integrations (e.g., artifact repos, deployment servers).<\/li>\n<\/ul>\n\n\n\n<p>During the described activities, consider pipeline complexity, like multiple dependencies or conditional stages. In this case, utilize GitLab\u2019s rules and needs features.<\/p>\n\n\n\n<p>An example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>build:\n  stage: build\n  script:\n\t- npm install\n\t- npm run build\n  <strong>rules<\/strong>:\n\t- if: '$CI_COMMIT_BRANCH == \"main\"'<\/code><\/pre>\n\n\n\n<p>In GitLab, you can enable caching for dependencies:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>cache<\/strong>:\n   paths:\n      - node_modules\/<\/code><\/pre>\n\n\n\n<p>Finally, if Bitbucket pipelines use artifacts, map them to GitLab\u2019s&nbsp; artifacts syntax:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>build:\n  stage: build\n  script:\n\t- npm install\n\t- npm run build\n  <strong>artifacts<\/strong>:\n\tpaths:\n  \t- dist\/<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Migrate all needed issues and pull requests<\/strong><\/h3>\n\n\n\n<p>As you probably know, the GitLab platform doesn\u2019t offer any feature that might help you transfer issues of pull requests directly from the Bitbucket. That leaves custom methods to rely on. In turn, you must transfer issue details, comments, and progress status(es) manually \u2013&nbsp; or automatically (with the proper tool).<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Custom scripts for migration<\/strong><\/h4>\n\n\n\n<p>A suitable method to migrate issues from Bitbucket to GitLab &#8211; in addition to a third-party tool &#8211; might be a Python script. It should include enhancements for error handling, pagination, and support for issue comments.<\/p>\n\n\n\n<p>However, if issues in Bitbucket have file attachments, you should download them and re-upload them to GitLab. Migrating comments on each issue requires a separate (additional) API call.<br><br>For example, you can extend the script by adding:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bitbucket_comments_url = f\"{bitbucket_issues_url}\/{issue&#091;'id']}\/comments\"\ncomments = requests.get(bitbucket_comments_url, auth=auth).json()<\/code><\/pre>\n\n\n\n<p>Third-party tools, such as Bitbucket to GitLab migration utilities or Python libraries (e.g., python-gitlab), can be helpful when you plan to automate the process. The best choice among such tools will be GitProtect.io.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Test and validation<\/strong><\/h3>\n\n\n\n<p>In this step, you focus mainly on dry run and testing your migration outcome. It\u2019ll involve a dry run, data validation, pipeline execution, and permission testing at the end.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Dry run<\/strong><\/h4>\n\n\n\n<p>Select test repositories with varied characteristics, e.g., small and large, with CI\/CD pipelines. Perform the migration steps for these repos to evaluate time, complexity, and potential errors.&nbsp;<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Data validation<\/strong><\/h4>\n\n\n\n<p>You can start by validating the commit history for completeness.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git log --oneline<\/code><\/pre>\n\n\n\n<p>Next, compare branch and tag structures between Bitbucket and GitLab.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git <strong>branch<\/strong> -r\ngit <strong>tag<\/strong><\/code><\/pre>\n\n\n\n<p>Confirm that the issue count, description, and labels match. Use GitLab\u2019s issue listing API for validation.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>curl<\/strong> --header \"PRIVATE-TOKEN: &lt;your_access_token&gt;\" \\\n \t\"https:\/\/&lt;gitlab_instance&gt;\/api\/v4\/projects\/&lt;project_id&gt;\/issues\"<\/code><\/pre>\n\n\n\n<p>After it&#8217;s done, you can verify whether the history of pull requests (from Bitbucket) is accurately represented in GitLab merge requests.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Pipeline execution<\/strong><\/h4>\n\n\n\n<p>For proper execution, trigger pipelines in GitLab and validate all stages, jobs, and environment variables in the CI\/CD Pipelines section. Then, check all necessary permissions.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Permission testing<\/strong><\/h4>\n\n\n\n<p>Log in with different user accounts to test all required permissions to confirm role-based access control. Include group and project permissions to verify if they align with expectations (source system).&nbsp;<\/p>\n\n\n\n<p>During the test phase, any findings should be gathered in the document. This is essential. The file should address discrepancies or errors before proceeding with the full-scale migration.&nbsp;&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Complete Bitbucket do GitLab migration in just a few clicks<\/strong><\/h2>\n\n\n\n<p>During our consideration, we mentioned the third-party solution and GitProtect tool. The latter provides a way to perform the described migration much faster, easier, and in a far more predictable and safe manner.<\/p>\n\n\n\n<p>GitProtect.io is an all\u2013scenario\u2013ready DevOps Backup and Disaster Recovery system. It offers one central management console and lets you keep and restore any data you need, including projects, labels, issues, pull requests, pipelines, etc.<\/p>\n\n\n\n<p>By offering cross-restore capabilities, the software gives you the freedom to migrate between vendors easily:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GitHub<\/strong><\/li>\n\n\n\n<li><strong>GitLab<\/strong><\/li>\n\n\n\n<li><strong>Bitbucket<\/strong><\/li>\n\n\n\n<li><strong>Azure DevOps<\/strong><\/li>\n<\/ul>\n\n\n\n<p>The above also relates to various accounts or deployments (C2C, P2C, etc.).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>GitProtect\u2019s cross recovery &#8211; data migration with no headaches<\/strong><\/h3>\n\n\n\n<p>The migration process is swift when both Bitbucket and GitLab accounts are added and authorized in the application.<\/p>\n\n\n\n<p>To perform migration:<\/p>\n\n\n\n<p><strong>1. Choose your Bitbucket backup<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" width=\"468\" height=\"243\" src=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-2.png\" alt=\"Bitbucket to GitLab migration 1\" class=\"wp-image-6349\" style=\"width:500px;height:auto\" srcset=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-2.png 468w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-2-300x156.png 300w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-2-400x208.png 400w\" sizes=\"(max-width: 468px) 100vw, 468px\" \/><\/figure><\/div>\n\n\n<p><strong>2. Click the <em>Restore<\/em> button (right side of the screen).<\/strong><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" width=\"739\" height=\"544\" src=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-3.png\" alt=\"Bitbucket to GitLab migration 2\" class=\"wp-image-6350\" style=\"width:500px;height:auto\" srcset=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-3.png 739w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-3-300x221.png 300w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-3-400x294.png 400w\" sizes=\"(max-width: 739px) 100vw, 739px\" \/><\/figure><\/div>\n\n\n<p><strong>3. Select GitLab destination by clicking on the <\/strong><strong><em>Restore to<\/em><\/strong><strong> button.<\/strong><\/p>\n\n\n\n<p>That\u2019s all you need to do. The migrated project is in your Git hosting service (GitLab) and the GitProtect window.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img decoding=\"async\" width=\"697\" height=\"134\" src=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-4.png\" alt=\"Bitbucket to GitLab migration 3\" class=\"wp-image-6351\" style=\"width:500px;height:auto\" srcset=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-4.png 697w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-4-300x58.png 300w, https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/bitbucket-to-gitlab-migration-4-400x77.png 400w\" sizes=\"(max-width: 697px) 100vw, 697px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Key takeaway<\/strong><\/h2>\n\n\n\n<p>The Bitbucket to GitLab migration process is undoubtedly a strategic move to leverage the latter\u2019s DevOps capabilities. Its success hinges on pre-migration planning. It should include assessing the Bitbucket environment (repos, users, CI\/CD) and defining the target GitLab structure.<\/p>\n\n\n\n<p>Moving repositories from BitBucket to GitLab is not the most complicated IT and business venture. Yet, it still demands focusing on details and testing. That\u2019s because GitLab lacks a mechanism supporting direct data transfer from an Atlassian Git-based solution.<\/p>\n\n\n\n<p>While manual migration can be troublesome, tools like GitProtect.io offer a streamlined, automated, and far more reliable alternative for a smoother transition.<\/p>\n\n\n\n<p class=\"has-background\" style=\"background-color:#f4fafe\"><a href=\"https:\/\/calendly.com\/d\/3s9-n9z-pgc\/gitprotect-live-demo?month=2024-07\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>[FREE TRIAL] Ensure compliant DevOps backup and recovery with a 14-day trial<\/strong><\/a>\ud83d\ude80<br><br><a href=\"https:\/\/calendly.com\/d\/3s9-n9z-pgc\/gitprotect-live-demo?month=2024-07\"><strong>[CUSTOM DEMO] Let\u2019s talk on how backup &amp; DR software for DevOps can make your migration process smooth and secure<\/strong><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Moving data from Bitbucket to GitLab is usually dictated by the need to streamline the company\u2019s development processes. It also involves the desire to unify the toolset and the benefits of using GitLab&#8217;s versatile DevOps features.<\/p>\n","protected":false},"author":16,"featured_media":3434,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,70],"tags":[],"class_list":["post-3431","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bitbucket","category-gitlab","post--single"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Bitbucket to GitLab Migration in a Few Simple Steps - Blog | GitProtect.io<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Bitbucket to GitLab Migration in a Few Simple Steps - Blog | GitProtect.io\" \/>\n<meta property=\"og:description\" content=\"Moving data from Bitbucket to GitLab is usually dictated by the need to streamline the company\u2019s development processes. It also involves the desire to unify the toolset and the benefits of using GitLab&#8217;s versatile DevOps features.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog | GitProtect.io\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/XoperoSoftware\/\" \/>\n<meta property=\"article:published_time\" content=\"2022-11-28T10:40:57+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-13T09:10:30+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"600\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Wojciech Andryszek, Technical Content Writer at GitProtect.io\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GitProtectio\" \/>\n<meta name=\"twitter:site\" content=\"@GitProtectio\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Wojciech Andryszek, Technical Content Writer at GitProtect.io\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/\"},\"author\":{\"name\":\"Wojciech Andryszek, Technical Content Writer at GitProtect.io\",\"@id\":\"https:\/\/gitprotect.io\/blog\/#\/schema\/person\/967901c0176390b9c3fa15c5da47f37b\"},\"headline\":\"Bitbucket to GitLab Migration in a Few Simple Steps\",\"datePublished\":\"2022-11-28T10:40:57+00:00\",\"dateModified\":\"2025-06-13T09:10:30+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/\"},\"wordCount\":2443,\"publisher\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg\",\"articleSection\":[\"Bitbucket\",\"GitLab\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/\",\"url\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/\",\"name\":\"Bitbucket to GitLab Migration in a Few Simple Steps - Blog | GitProtect.io\",\"isPartOf\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg\",\"datePublished\":\"2022-11-28T10:40:57+00:00\",\"dateModified\":\"2025-06-13T09:10:30+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage\",\"url\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg\",\"contentUrl\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg\",\"width\":1200,\"height\":600},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Strona g\u0142\u00f3wna\",\"item\":\"https:\/\/gitprotect.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Bitbucket to GitLab Migration in a Few Simple Steps\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/gitprotect.io\/blog\/#website\",\"url\":\"https:\/\/gitprotect.io\/blog\/\",\"name\":\"GitProtect.io Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/gitprotect.io\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/gitprotect.io\/blog\/#organization\",\"name\":\"GitProtect.io\",\"url\":\"https:\/\/gitprotect.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/gitprotect.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2023\/05\/favicon-528x528-1.png\",\"contentUrl\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2023\/05\/favicon-528x528-1.png\",\"width\":528,\"height\":528,\"caption\":\"GitProtect.io\"},\"image\":{\"@id\":\"https:\/\/gitprotect.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/XoperoSoftware\/\",\"https:\/\/x.com\/GitProtectio\",\"https:\/\/www.linkedin.com\/company\/xopero-software\/\",\"https:\/\/www.youtube.com\/channel\/UCiEnl6n0mIO6w7twccz-l2w\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/gitprotect.io\/blog\/#\/schema\/person\/967901c0176390b9c3fa15c5da47f37b\",\"name\":\"Wojciech Andryszek, Technical Content Writer at GitProtect.io\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/gitprotect.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/10\/wojciech-andryszek-technical-content-writer-at-gitprotect.io_avatar-96x96.jpg\",\"contentUrl\":\"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/10\/wojciech-andryszek-technical-content-writer-at-gitprotect.io_avatar-96x96.jpg\",\"caption\":\"Wojciech Andryszek, Technical Content Writer at GitProtect.io\"},\"description\":\"Wojtek is a Technical Content Writer at GitProtect. As a science journalist under his belt, he enjoys all kinds of knowledge. When writing about tech, Wojtek plays the role of an IT professional as well as his opposite - like Dr. Jekyll and Mr. Hyde. ;)\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/wojciech-andryszek\/\"],\"url\":\"https:\/\/gitprotect.io\/blog\/author\/wojciech-andryszek\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Bitbucket to GitLab Migration in a Few Simple Steps - Blog | GitProtect.io","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/","og_locale":"en_US","og_type":"article","og_title":"Bitbucket to GitLab Migration in a Few Simple Steps - Blog | GitProtect.io","og_description":"Moving data from Bitbucket to GitLab is usually dictated by the need to streamline the company\u2019s development processes. It also involves the desire to unify the toolset and the benefits of using GitLab&#8217;s versatile DevOps features.","og_url":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/","og_site_name":"Blog | GitProtect.io","article_publisher":"https:\/\/www.facebook.com\/XoperoSoftware\/","article_published_time":"2022-11-28T10:40:57+00:00","article_modified_time":"2025-06-13T09:10:30+00:00","og_image":[{"width":1200,"height":600,"url":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg","type":"image\/jpeg"}],"author":"Wojciech Andryszek, Technical Content Writer at GitProtect.io","twitter_card":"summary_large_image","twitter_creator":"@GitProtectio","twitter_site":"@GitProtectio","twitter_misc":{"Written by":"Wojciech Andryszek, Technical Content Writer at GitProtect.io","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#article","isPartOf":{"@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/"},"author":{"name":"Wojciech Andryszek, Technical Content Writer at GitProtect.io","@id":"https:\/\/gitprotect.io\/blog\/#\/schema\/person\/967901c0176390b9c3fa15c5da47f37b"},"headline":"Bitbucket to GitLab Migration in a Few Simple Steps","datePublished":"2022-11-28T10:40:57+00:00","dateModified":"2025-06-13T09:10:30+00:00","mainEntityOfPage":{"@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/"},"wordCount":2443,"publisher":{"@id":"https:\/\/gitprotect.io\/blog\/#organization"},"image":{"@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage"},"thumbnailUrl":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg","articleSection":["Bitbucket","GitLab"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/","url":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/","name":"Bitbucket to GitLab Migration in a Few Simple Steps - Blog | GitProtect.io","isPartOf":{"@id":"https:\/\/gitprotect.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage"},"image":{"@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage"},"thumbnailUrl":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg","datePublished":"2022-11-28T10:40:57+00:00","dateModified":"2025-06-13T09:10:30+00:00","breadcrumb":{"@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#primaryimage","url":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg","contentUrl":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2022\/11\/11.22-bitbucket-to-GitLab-migration.jpg","width":1200,"height":600},{"@type":"BreadcrumbList","@id":"https:\/\/gitprotect.io\/blog\/bitbucket-to-gitlab-migration-in-a-few-simple-steps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Strona g\u0142\u00f3wna","item":"https:\/\/gitprotect.io\/blog\/"},{"@type":"ListItem","position":2,"name":"Bitbucket to GitLab Migration in a Few Simple Steps"}]},{"@type":"WebSite","@id":"https:\/\/gitprotect.io\/blog\/#website","url":"https:\/\/gitprotect.io\/blog\/","name":"GitProtect.io Blog","description":"","publisher":{"@id":"https:\/\/gitprotect.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gitprotect.io\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/gitprotect.io\/blog\/#organization","name":"GitProtect.io","url":"https:\/\/gitprotect.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/gitprotect.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2023\/05\/favicon-528x528-1.png","contentUrl":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2023\/05\/favicon-528x528-1.png","width":528,"height":528,"caption":"GitProtect.io"},"image":{"@id":"https:\/\/gitprotect.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/XoperoSoftware\/","https:\/\/x.com\/GitProtectio","https:\/\/www.linkedin.com\/company\/xopero-software\/","https:\/\/www.youtube.com\/channel\/UCiEnl6n0mIO6w7twccz-l2w"]},{"@type":"Person","@id":"https:\/\/gitprotect.io\/blog\/#\/schema\/person\/967901c0176390b9c3fa15c5da47f37b","name":"Wojciech Andryszek, Technical Content Writer at GitProtect.io","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/gitprotect.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/10\/wojciech-andryszek-technical-content-writer-at-gitprotect.io_avatar-96x96.jpg","contentUrl":"https:\/\/gitprotect.io\/blog\/wp-content\/uploads\/2024\/10\/wojciech-andryszek-technical-content-writer-at-gitprotect.io_avatar-96x96.jpg","caption":"Wojciech Andryszek, Technical Content Writer at GitProtect.io"},"description":"Wojtek is a Technical Content Writer at GitProtect. As a science journalist under his belt, he enjoys all kinds of knowledge. When writing about tech, Wojtek plays the role of an IT professional as well as his opposite - like Dr. Jekyll and Mr. Hyde. ;)","sameAs":["https:\/\/www.linkedin.com\/in\/wojciech-andryszek\/"],"url":"https:\/\/gitprotect.io\/blog\/author\/wojciech-andryszek\/"}]}},"_links":{"self":[{"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/posts\/3431","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/comments?post=3431"}],"version-history":[{"count":13,"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/posts\/3431\/revisions"}],"predecessor-version":[{"id":6791,"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/posts\/3431\/revisions\/6791"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/media\/3434"}],"wp:attachment":[{"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/media?parent=3431"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/categories?post=3431"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gitprotect.io\/blog\/wp-json\/wp\/v2\/tags?post=3431"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}