How can I move a Git repository with all branches from Bitbucket to GitHub?
Asked Answered
G

12

368

What is the best way to move a Git repository with all branches and full history from Bitbucket to GitHub?

Is there a script or a list of commands I have to use?

Gregarine answered 7/4, 2014 at 8:12 Comment(2)
Github provide tools and documentation for that: help.github.com/articles/… help.github.com/articles/…Nevernever
Little late to the party but here is a script for migration: gist.github.com/chinmaya-n/cff02f1277c811deab2e550f2aad9967Radiative
B
427

You can refer to the GitHub page "Duplicating a repository"

It uses:

That would give:

git clone --mirror https://bitbucket.org/exampleuser/repository-to-mirror.git
# Make a bare mirrored clone of the repository

cd repository-to-mirror.git
git remote set-url --push origin https://github.com/exampleuser/mirrored
# Set the push location to your mirror

git push --mirror

As Noted in the comments by L S:

Beloved answered 7/4, 2014 at 8:25 Comment(11)
This method created a problem for me (not sure if it is problem). When I mirrored the repo from bitbucket to github then for 5 branches it is shown as "Compare and Pull Request" in github. It is not shown as branches in github. What can I do about it?Vidda
And then what about issues and wikis?Certainly
@FractalizeR wiki is just another repo, that you can replicate as well (github.com/blog/699-making-github-more-open-git-backed-wikis). There is no easy way to replicate issues though. You need to use the Api (various GitHub repo backup programs do just that: addyosmani.com/blog/backing-up-a-github-account)Beloved
@Vidda I think you are looking for this answer: #13322016 I was also initially wondering about the same problem.Infeudation
This worked great for me. I moved a repository from bitbucket to github.Gibber
This works if you want to move a repository from Github to Bitbucket as well.Archduchy
I think the problem is that this does not work for enterprise accounts.Condenser
I needed to use the this method to copy a repo because it contained a large file (>100MB). GH wouldn't allow large files in their repos. I removed the large file before pushing the repo to GH. However, barring other problems, using GH's "Import repository" feature is the right choice 95% of the time, as described in another answer. However, if it fails, it doesn't give helpful error messages and you must contact GH support. It was GH support that informed me of the file size restriction.Flori
@LS Thank you. I have included your comment in the answer for more visibility.Beloved
How can we update / git pull from Bitbucket to GitHubConsolata
@transformer Yes, pull from one remote, push to the other.Beloved
B
442

It's very simple.

  1. Create a new empty repository in GitHub (without a README or license, you can add them later) and the following screen will show.

  2. In the import code option, paste your Bitbucket repository's URL and voilà!!

Click Import code

Basaltware answered 2/11, 2014 at 18:9 Comment(8)
You're really answering the question here, as the accepted answer shows only a generic Git related method. Your answer is way simpler!Kloman
This answer is good as long as you are the one creating the repository and it is bare. If someone else has created the repository for you (like the admin incharge of branch creation) then this doesn't work. Accepted answer is the way to go in such a case.Giroux
Heads up for anyone else thinking about using this method, remove your two-factor authentication on your previous repository host before you use this service, otherwise you'll be stuck in an endless loop of trying to remove the newly created repository in GitHub, and the only way to get out of that is to replace the /import on the end of the URL with /settings to access the settings and remove it.Covey
Small caveat- if you run into an issue you won't get a descriptive error message.Blastema
Using GH's "Import repository" feature is the right choice 95% of the time. However, if it fails, it doesn't give helpful error messages and you must contact GH support. I couldn't use it for one repo because it contained a large file (>100MB). I needed to use the accepted CLI method, removing the large file just before pushing the repo to GH.Flori
Give the bitbucket private repo url, submit the login details of bitbucket and you are done.Respectful
doesn't fracking work anymore with the new bitbucket authentificationNiggerhead
Can someone tell me, please, what exactly do I need to use for 'Private Access Token' to clone it correctly? I have already tried to use generated 'Personal Access Token' and 'Repository access token' and I still get login page without any importing. The second answer with git clone --mirror is working fine for me, but this one - not, for some reason.Iguanodon
B
427

You can refer to the GitHub page "Duplicating a repository"

It uses:

That would give:

git clone --mirror https://bitbucket.org/exampleuser/repository-to-mirror.git
# Make a bare mirrored clone of the repository

cd repository-to-mirror.git
git remote set-url --push origin https://github.com/exampleuser/mirrored
# Set the push location to your mirror

git push --mirror

As Noted in the comments by L S:

Beloved answered 7/4, 2014 at 8:25 Comment(11)
This method created a problem for me (not sure if it is problem). When I mirrored the repo from bitbucket to github then for 5 branches it is shown as "Compare and Pull Request" in github. It is not shown as branches in github. What can I do about it?Vidda
And then what about issues and wikis?Certainly
@FractalizeR wiki is just another repo, that you can replicate as well (github.com/blog/699-making-github-more-open-git-backed-wikis). There is no easy way to replicate issues though. You need to use the Api (various GitHub repo backup programs do just that: addyosmani.com/blog/backing-up-a-github-account)Beloved
@Vidda I think you are looking for this answer: #13322016 I was also initially wondering about the same problem.Infeudation
This worked great for me. I moved a repository from bitbucket to github.Gibber
This works if you want to move a repository from Github to Bitbucket as well.Archduchy
I think the problem is that this does not work for enterprise accounts.Condenser
I needed to use the this method to copy a repo because it contained a large file (>100MB). GH wouldn't allow large files in their repos. I removed the large file before pushing the repo to GH. However, barring other problems, using GH's "Import repository" feature is the right choice 95% of the time, as described in another answer. However, if it fails, it doesn't give helpful error messages and you must contact GH support. It was GH support that informed me of the file size restriction.Flori
@LS Thank you. I have included your comment in the answer for more visibility.Beloved
How can we update / git pull from Bitbucket to GitHubConsolata
@transformer Yes, pull from one remote, push to the other.Beloved
L
128

In case you couldn't find the "Import code" button on GitHub, you can:

  1. Directly open GitHub Importer and enter the URL. It will look like:

    Screenshot of GitHub importer

  2. Give it a name (or it will import the name automatically)

  3. Select Public or Private repository

  4. Click Begin Import

In May 2016, GitHub announced the ability to "Import repositories with large files".

Lanchow answered 24/11, 2014 at 5:9 Comment(8)
Unfortunately this didn't work for my attempt at moving from codebasehq to git-hub, gave an "This URL is not supported". :(Chishima
@Chishima Sorry it didn't but I believe it should have worked since the codebasehq URL points to a git repository.Lanchow
URL no longer exists.Condenser
@CodedContainer I just checked and it works. I even updated the screen shot just now.Lanchow
@CodedContainer If you click on 'Github Importer' link on line 1, it will point you to the correct URL: import.github.com/new. You are using an incorrect URLLanchow
The link that you provided redirects to github.com/new/import and is incorrect.Condenser
@CodedContainer You can see youtu.be/aDRGgK4wVA8 video that shows you - when I click on the link it displays the page. May be it could be a problem with your internet or DNS or something ....Lanchow
The url will only return a 404 if you are not logged into GitHub. If you are logged in, the import tool will load.Bohun
L
47

Se Moving Repository from Bitbucket to GitHub.

This helped me move from one Git provider to another. At the end of it, all the commits were in the destination Git repository. Simple and straightforward.

git remote rename origin bitbucket
git remote add origin https://github.com/edwardaux/Pipelines.git
git push origin master

Once I was happy that the push had been successful to GitHub, I could delete the old remote by issuing:

git remote rm bitbucket
Lait answered 18/9, 2014 at 4:15 Comment(3)
Please include the relevant parts of a link in your answer as it should be able to stand on its own.Sarinasarine
I get an error that says "Error: failed to push som refs to 'url.gi' hint: updates were rejected because the remote contains work that you do not have locally. This is usually caused by another repository pushing to the same ref. You may want to first integrate the remote changes (eg pull...) before pushing again. See the note about fast-forwards in git push --help for details.Condenser
So simple! Love it.Gerundive
S
13

I had the reverse use case of importing an existing repository from GitHub to Bitbucket.

Bitbucket offers an Import tool as well. The only necessary step is to add URL to repository.

It looks like:

Screenshot of the Bitbucket import tool

Sarinasarine answered 16/2, 2015 at 11:24 Comment(0)
E
6

There is the Importing a repository with GitHub Importer

If you have a project hosted on another version control system as Mercurial, you can automatically import it to GitHub using the GitHub Importer tool.

  1. In the upper-right corner of any page, click, and then click Import repository.
  2. Under "Your old repository's clone URL", type the URL of the project you want to import.
  3. Choose your user account or an organization to own the repository, then type a name for the repository on GitHub.
  4. Specify whether the new repository should be public or private.
  • Public repositories are visible to any user on GitHub, so you can benefit from GitHub's collaborative community.
  • Public or private repository radio buttonsPrivate repositories are only available to the repository owner, as well as any collaborators you choose to share with.
  1. Review the information you entered, then click Begin import.

You'll receive an email when the repository has been completely imported.

  1. Importing your projects to GitHub
  2. Importing a repository with GitHub Importer
Etka answered 24/11, 2016 at 19:10 Comment(0)
P
5

I found this question several months ago when I was trying to do the same thing, and was underwhelmed by the answers given. They all seemed to deal with importing from Bitbucket to GitHub one repository at a time, either via commands issued à la carte, or via the GitHub importer.

I grabulated the code from a GitHub project called gitter and modified it to suite my needs.

You can fork the gist, or take the code from here:

#!/usr/bin/env ruby
require 'fileutils'

# Originally  -- Dave Deriso        -- [email protected]
# Contributor -- G. Richard Bellamy -- [email protected]
# If you contribute, put your name here!
# To get your team ID:
# 1. Go to your GitHub profile, select 'Personal Access Tokens', and create an Access token
# 2. curl -H "Authorization: token <very-long-access-token>" https://api.github.com/orgs/<org-name>/teams
# 3. Find the team name, and grabulate the Team ID
# 4. PROFIT!

#----------------------------------------------------------------------
#your particulars
@access_token = ''
@team_id = ''
@org = ''


#----------------------------------------------------------------------
#the version of this app
@version = "0.2"

#----------------------------------------------------------------------
#some global parameters
@create = false
@add = false
@migrate = false
@debug = false
@done = false
@error = false

#----------------------------------------------------------------------
#fancy schmancy color scheme

class String; def c(cc); "\e[#{cc}m#{self}\e[0m" end end
#200.to_i.times{ |i| print i.to_s.c(i) + " " }; puts
@sep = "-".c(90)*95
@sep_pref = ".".c(90)*95
@sep_thick = "+".c(90)*95

#----------------------------------------------------------------------
# greetings

def hello
  puts @sep
  puts "BitBucket to GitHub migrator -- v.#{@version}".c(95)
  #puts @sep_thick
end

def goodbye
  puts @sep
  puts "done!".c(95)
  puts @sep
  exit
end

def puts_title(text)
   puts  @sep, "#{text}".c(36), @sep
end

#----------------------------------------------------------------------
# helper methods

def get_options
  require 'optparse'

  n_options = 0
  show_options = false

  OptionParser.new do |opts|
    opts.banner = @sep +"\nUsage: gitter [options]\n".c(36)
    opts.version = @version
    opts.on('-n', '--name [name]', String, 'Set the name of the new repo') { |value| @repo_name = value; n_options+=1 }
    opts.on('-c', '--create', String, 'Create new repo') { @create = true; n_options+=1 }
    opts.on('-m', '--migrate', String, 'Migrate the repo') { @migrate = true; n_options+=1 }
    opts.on('-a', '--add', String, 'Add repo to team') { @add = true; n_options+=1 }
    opts.on('-l', '--language [language]', String, 'Set language of the new repo') { |value| @language = value.strip.downcase; n_options+=1 }
    opts.on('-d', '--debug', 'Print commands for inspection, doesn\'t actually run them') { @debug = true; n_options+=1 }
    opts.on_tail('-h', '--help', 'Prints this little guide') { show_options = true; n_options+=1 }
    @opts = opts
  end.parse!

  if show_options || n_options == 0
    puts @opts
    puts "\nExamples:".c(36)
    puts 'create new repo: ' + "\t\tgitter -c -l javascript -n node_app".c(93)
    puts 'migrate existing to GitHub: ' + "\tgitter -m -n node_app".c(93)
    puts 'create repo and migrate to it: ' + "\tgitter -c -m -l javascript -n node_app".c(93)
    puts 'create repo, migrate to it, and add it to a team: ' + "\tgitter -c -m -a -l javascript -n node_app".c(93)
    puts "\nNotes:".c(36)
    puts "Access Token for repo is #{@access_token} - change this on line 13"
    puts "Team ID for repo is #{@team_id} - change this on line 14"
    puts "Organization for repo is #{@org} - change this on line 15"
    puts 'The assumption is that the person running the script has SSH access to Bitbucket,'
    puts 'and GitHub, and that if the current directory contains a directory with the same'
    puts 'name as the repo to migrated, it will deleted and recreated, or created if it'
    puts 'doesn\'t exist - the repo to migrate is mirrored locally, and then created on'
    puts 'GitHub and pushed from that local clone.'
    puts 'New repos are private by default'
    puts "Doesn\'t like symbols for language (ex. use \'c\' instead of \'c++\')"
    puts @sep
    exit
  end
end

#----------------------------------------------------------------------
# git helper methods

def gitter_create(repo)
  if @language
    %q[curl https://api.github.com/orgs/] + @org + %q[/repos -H "Authorization: token ] + @access_token + %q[" -d '{"name":"] + repo + %q[","private":true,"language":"] + @language + %q["}']
  else
    %q[curl https://api.github.com/orgs/] + @org + %q[/repos -H "Authorization: token ] + @access_token + %q[" -d '{"name":"] + repo + %q[","private":true}']
  end
end

def gitter_add(repo)
  if @language
    %q[curl https://api.github.com/teams/] + @team_id + %q[/repos/] + @org + %q[/] + repo + %q[ -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ] + @access_token + %q[" -d '{"permission":"pull","language":"] + @language + %q["}']
  else
    %q[curl https://api.github.com/teams/] + @team_id + %q[/repos/] + @org + %q[/] + repo + %q[ -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ] + @access_token + %q[" -d '{"permission":"pull"}']
  end
end

def git_clone_mirror(bitbucket_origin, path)
  "git clone --mirror #{bitbucket_origin}"
end

def git_push_mirror(github_origin, path)
  "(cd './#{path}' && git push --mirror #{github_origin} && cd ..)"
end

def show_pwd
  if @debug
    Dir.getwd()
  end
end

def git_list_origin(path)
  "(cd './#{path}' && git config remote.origin.url && cd ..)"
end

# error checks

def has_repo
  File.exist?('.git')
end

def has_repo_or_error(show_error)
  @repo_exists = has_repo
  if !@repo_exists
    puts 'Error: no .git folder in current directory'.c(91) if show_error
    @error = true
  end
  "has repo: #{@repo_exists}"
end

def has_repo_name_or_error(show_error)
  @repo_name_exists = !(defined?(@repo_name)).nil?
  if !@repo_name_exists
    puts 'Error: repo name missing (-n your_name_here)'.c(91) if show_error
    @error = true
  end
end

#----------------------------------------------------------------------
# main methods
def run(commands)
  if @debug
    commands.each { |x| puts(x) }
  else
    commands.each { |x| system(x) }
  end
end

def set_globals

  puts_title 'Parameters'

  @git_bitbucket_origin =   "[email protected]:#{@org}/#{@repo_name}.git"
  @git_github_origin = "[email protected]:#{@org}/#{@repo_name}.git"

  puts 'debug: ' + @debug.to_s.c(93)
  puts 'working in: ' + Dir.pwd.c(93)
  puts 'create: ' + @create.to_s.c(93)
  puts 'migrate: ' + @migrate.to_s.c(93)
  puts 'add: ' + @add.to_s.c(93)
  puts 'language: ' + @language.to_s.c(93)
  puts 'repo name: '+ @repo_name.to_s.c(93)
  puts 'bitbucket: ' + @git_bitbucket_origin.to_s.c(93)
  puts 'github: ' + @git_github_origin.to_s.c(93)
  puts 'team_id: ' + @team_id.to_s.c(93)
  puts 'org: ' + @org.to_s.c(93)
end

def create_repo
  puts_title 'Creating'

  #error checks
  has_repo_name_or_error(true)
  goodbye if @error

  puts @sep

  commands = [
      gitter_create(@repo_name)
  ]

  run commands
end


def add_repo
  puts_title 'Adding repo to team'

  #error checks
  has_repo_name_or_error(true)
  goodbye if @error

  puts @sep

  commands = [
      gitter_add(@repo_name)
  ]

  run commands
end

def migrate_repo

  puts_title "Migrating Repo to #{@repo_provider}"

  #error checks
  has_repo_name_or_error(true)
  goodbye if @error

  if Dir.exists?("#{@repo_name}.git")
    puts "#{@repo_name} already exists... recursively deleting."
    FileUtils.rm_r("#{@repo_name}.git")
  end

  path = "#{@repo_name}.git"
  commands = [
    git_clone_mirror(@git_bitbucket_origin, path),
    git_list_origin(path),
    git_push_mirror(@git_github_origin, path)
  ]

  run commands
end

#----------------------------------------------------------------------
#sequence control
hello
get_options

#do stuff
set_globals
create_repo if @create
migrate_repo if @migrate
add_repo if @add

#peace out
goodbye

Then, to use the script:

# create a list of repos
foo
bar
baz

# execute the script, iterating over your list
while read p; do ./bitbucket-to-github.rb -a -n $p; done<repos

# good enough
Perryperryman answered 7/11, 2015 at 6:4 Comment(0)
F
4

I made the following Bash script in order to clone all of my Bitbucket (user) repositories to GitHub as private repositories.


Requirements:

  • jq (command-line JSON processor) | macOS: brew install jq

Steps:

  1. Go to Personal access tokens and create an access token. We only need the "repo" scope.

  2. Save the move_me.sh script in a working folder and edit the file as needed.

  3. Don't forget to chmod 755

  4. Run! ./move_me.sh

  5. Enjoy the time you have saved.


Notes:

  • It will clone the Bitbucket repositories inside the directory the script resides (your working directory).

  • This script does not delete your Bitbucket repositories.


Need to move to public repositories on GitHub?

Find and change the "private": true to "private": false below.

Moving an organization's repositories?

Check out the developer guide. It's a couple of edits away.


Happy moving.

#!/bin/bash

BB_USERNAME=your_bitbucket_username
BB_PASSWORD=your_bitbucket_password

GH_USERNAME=your_github_username
GH_ACCESS_TOKEN=your_github_access_token

###########################

pagelen=$(curl -s -u $BB_USERNAME:$BB_PASSWORD https://api.bitbucket.org/2.0/repositories/$BB_USERNAME | jq -r '.pagelen')

echo "Total number of pages: $pagelen"

hr () {
  printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
}

i=1

while [ $i -le $pagelen ]
do
  echo
  echo "* Processing Page: $i..."
  hr
  pageval=$(curl -s -u $BB_USERNAME:$BB_PASSWORD https://api.bitbucket.org/2.0/repositories/$BB_USERNAME?page=$i)

  next=$(echo $pageval | jq -r '.next')
  slugs=($(echo $pageval | jq -r '.values[] | .slug'))
  repos=($(echo $pageval | jq -r '.values[] | .links.clone[1].href'))

  j=0
  for repo in ${repos[@]}
  do
    echo "$(($j + 1)) = ${repos[$j]}"
    slug=${slugs[$j]}
  git clone --bare $repo
  cd "$slug.git"
  echo
  echo "* $repo cloned, now creating $slug on GitHub..."
  echo

  read -r -d '' PAYLOAD <<EOP
  {
    "name": "$slug",
    "description": "$slug - moved from Bitbucket",
    "homepage": "https://github.com/$slug",
    "private": true
  }
  EOP

  curl -H "Authorization: token $GH_ACCESS_TOKEN" --data "$PAYLOAD" \
      https://api.github.com/user/repos
  echo
  echo "* mirroring $repo to GitHub..."
  echo
  git push --mirror "[email protected]:$GH_USERNAME/$slug.git"
  j=$(( $j + 1 ))
  hr
  cd ..
  done
  i=$(( $i + 1 ))
done
Frication answered 11/12, 2019 at 21:38 Comment(0)
S
3

In case you want to move your local Git repository to another upstream, you can also do this:

To get the current remote URL:

git remote get-url origin

will show something like: https://bitbucket.com/git/myrepo

To set new remote repository:

git remote set-url origin [email protected]:folder/myrepo.git

now push contents of current (develop) branch:

git push --set-upstream origin develop

You now have a full copy of the branch in the new remote.

Optionally, return to original git-remote for this local folder:

git remote set-url origin https://bitbucket.com/git/myrepo

It gives the benefit you can now get your new Git repository from GitHub in another folder so that you have two local folders both pointing to the different remotes, the previous (Bitbucket) and the new one both available.

Scotia answered 21/12, 2018 at 12:35 Comment(0)
S
2

Here are the steps to move a private Git repository:

Step 1: Create a GitHub repository

First, create a new private repository on GitHub. It’s important to keep the repository empty, e.g., don’t check option Initialize this repository with a README when creating the repository.

Step 2: Move existing content

Next, we need to fill the GitHub repository with the content from our Bitbucket repository:

  1. Check out the existing repository from Bitbucket:

    git clone https://[email protected]/USER/PROJECT.git
    
  2. Add the new GitHub repository as upstream remote of the repository checked out from Bitbucket:

    cd PROJECT
    git remote add upstream https://github.com:USER/PROJECT.git
    
  3. Push all branches (below: just master) and tags to the GitHub repository:

    git push upstream master
    git push --tags upstream
    

Step 3: Clean up the old repository

Finally, we need to ensure that developers don’t get confused by having two repositories for the same project. Here is how to delete the Bitbucket repository:

  1. Double-check that the GitHub repository has all content

  2. Go to the web interface of the old Bitbucket repository

  3. Select menu option SettingDelete repository

  4. Add the URL of the new GitHub repository as the redirect URL

With that, the repository completely settled into its new home at GitHub. Let all the developers know!

Sheryllshetland answered 24/7, 2019 at 6:59 Comment(0)
L
2

Following on from @MarMass' answer, if the GitHub importer is constantly redirecting you to the authentication screen, you'll need to create an App Password in BitBucket in order to import your private repository:

  1. Go to Bitbucket > Personal Settings > App Passwords.
  2. Create an app password with repository read access.
  3. When prompted for your username/password in the GitHub importer, enter your BitBucket username, and the token created above as your password.

After managing to sort out the authentication issue, my imports also errored out with the following message: "There was an error pushing commits to GitHub.".

The issue here, at least for me, was that my GitHub account was set to "Block command line pushes that expose my email", and the repository I was attempting to import from Bitbucket contained commits from my personal email address. After temporarily disabling this setting (GitHub > Settings > Email) I was good to go.

Lagena answered 26/1, 2023 at 19:15 Comment(1)
Thanks for your post. I tried with my email but it didn't work but with the username it worked perfectly. (And the most popular answer didn't work for me because I don't have permissions to access the repo's settings)Wesle
L
-1

The simplest way of doing it:

git remote rename origin repo_bitbucket

git remote add origin https://github.com/abc/repo.git

git push origin master

Once the push to GitHub is successful, delete the old remote by running:

git remote rm repo_bitbucket
Lachance answered 5/9, 2017 at 0:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.