Article Collection
This article is part of the following series:1. Git
Table of Contents
Introduction
Code hosting platforms have become a standard today. If you have a software project and want to share it with the world, there is a good chance you will be hosting it on GitHub, GitLab, Codeberg, or a similar platform. (We cover a total of 9 platforms in this article.)
The convenience as well as project promotion and collaboration opportunities available there usually leave little incentive for users to organize project code hosting themselves.
The Problem
But some of the code hosting platforms are proprietary, and their popularity is an example of trading people’s data for short-term convenience.
Proprietary code hosting platforms collect, process, and use data and metadata extracted from code, projects, authors, contributors, and end users.
And software authors who have given up their own privacy and data also force the same to happen to users who visit their project repositories.
The Solution
The practice of misusing user data is not going to stop. Lacking choice or care, developers and users have accepted that companies process and exploit their data and metadata, and have proven time and time again that convenient solutions will proliferate, regardless of negative consequences.
But software authors can immediately improve the situation by uploading their projects to multiple platforms.
Users are then able to share their data and metadata with the platform of their choosing. Also, it gives platforms an equal opportunity to protect or abuse user data, rather than reserving the privilege for one dominant platform, further reinforcing its position.
And, setting up project redundancy at multiple platforms up-front, when there is no immediate need to migrate or copy, will make the whole process much easier in the future. Eventual migrations from one primary platform to another will become transparent.
This article explains how to set up Git code repositories on multiple code hosting platforms with minimal impact on the standard, single-platform workflow.
Registration
User Account
All code hosting platforms have a web-based account registration procedure. The procedure has to be done once per platform, to create the user account.
It is probably most convenient to pick a single, unique username and register it on all platforms. That will ensure the username is uniformly registered across multiple platforms for brand recognition.
Users and Organizations
However, there is an important consideration to have in mind when choosing usernames.
Most platforms support registering users as well as organizations. Once users are registered, they can create one or more “organizations”. Organizations are something like group, project, or company names.
User and organization names often cannot have the same name because they exist in the same namespace, for example “https://github.com/USER_OR_ORG_NAME/".
Therefore, if you want the same username visible in URLs across different platforms, you need to look at platform specifics (documented below) to check whether organizations are supported and/or required. If they are, then you will want to name your user account slightly differently, not to occupy the name the organization will have.
Project
After creating users and/or organizations, you will also create project repositories at each platform.
Most platforms support importing existing repositories. You can import, but there is no major difference compared to creating empty repositories – with the recipe shared below, as soon as you run git push
for the first time, all repositories will be updated to the same contents, regardless of whether they were a couple commits behind or completely empty in the beginning.
All platforms except GNU Savannah have simple requirements – you can create project repositories immediately, without any particular restrictions.
GNU Savannah, which is maintained by the Free Software Foundation (FSF), has a more rigorous checklist for projects. You need to ensure that the following holds true for your project before admins will approve it:
-
Project software runs primarily on a completely free OS
-
Project license is compatible with GNU General Public License (GPL) v3 and later or GNU Free Documentation License (FDL) v1.3 and later
-
Project dependencies are compatible with project package license
-
All project files include valid copyright notices
-
All project files include a license notice
-
Origin and license of media files is specified
-
Project tar file includes a copy of the license
Making projects compatible with this checklist is a good idea even if you will host them on other platforms.
Code Hosting Platforms
It seems that the most popular code hosting platforms today, listed in alphabetical order, are:
- Bitbucket
- Codeberg
- Gitea
- GitHub
- GitLab
- NotABug
- Savannah
- SourceForge
- SourceHut
-
Your own, local Git server
Platform Characteristics
This section documents characteristics of creating user accounts on the mentioned platforms. Use it to decide will platforms you will use for your projects.
**Summary of required fields and specifics at different code hosting platforms as of Oct 2023:
Platform | Email Required? | Account Verification & Method | Username Required? | Organization Name Required? | Password Supported? | Full / Real Name Required? | OpenID Connect Federation | Public URL | Notes |
---|---|---|---|---|---|---|---|---|---|
Bitbucket | Y | Y (email 6-digit PIN code) | Y | Y (called “Workspace Name”) | Y | Y | Apple, Google, Microsoft, Slack | https://bitbucket.org/ORG_NAME | / |
Codeberg | Y | Y (email link + password) | Y | Optional | Y | N | GitHub, GitLab | https://codeberg.org/USER_OR_ORG_NAME | / |
Gitea | Y | Y (email link + password) | Y | Optional | Y | N | GitHub, GitLab, Google | https://gitea.com/USER_OR_ORG_NAME | / |
GitHub | Y | Y (email 8-digit PIN code) | Y | Optional | Y | N | (Passkey) | https://github.com/USER_OR_ORG_NAME | Optional personalization form |
GitLab | Y | Y (SMS 7-digit PIN code or credit card, and email 6-digit code) | Y | Y (called “Group”) | Y | N | Bitbucket, GitHub, Google, Salesforce | https://gitlab.com/ORG_NAME | Required personalization form, must immediately create or import project |
NotABug | Y | N | Y | Optional | Y | N | N/A | https://notabug.org/USER_OR_ORG_NAME | / |
Savannah | Y | Y (email link, username, and password) | Y | ? | Y | Optional | N/A | https://savannah.nongnu.org/u/USER_NAME | Required GNU GPL-compatible project license; stricter project requirements; manual project approval |
SourceForge | Y | Y (email link, username, and password) | Y | N/A | Y | Y | N/A | https://sf.net/u/USER_NAME | / |
SourceHut | Y | Y (email link) | Y | N/A | Y | N | N/A | https://sr.ht/~USER_NAME | Expected credit card and $2/month or more; provides sr.ht platform code as open source |
Account and Project Registration Links
Once you have chosen the platforms to create your account on, you can use the links below to access the account and project creation pages:
Bitbucket
-
Create an account at https://bitbucket.org/account/signup
-
Log in at https://id.atlassian.com/login
-
Set up an SSH key for access at https://bitbucket.org/account/settings/ssh-keys/
There is a concept of “projects” and “repositories”. Each repository must belong to a project. Project and repository name can be identical, but project names have a length limit.
- Create a new repository by going to https://bitbucket.org/ and clicking “Repositories” or “Create -> Repository” in the menu at the top
Codeberg
-
Create an account by going to https://codeberg.org/ and clicking “Register” on the top-right
-
Log in at https://codeberg.org/user/login
-
Set up an SSH key for access at https://codeberg.org/user/settings/keys
-
Create a new repository at https://codeberg.org/repo/create
Gitea
-
Create an account at https://gitea.com/user/sign_up
-
Log in at https://gitea.com/user/login
-
Set up an SSH key for access at https://gitea.com/user/settings/keys
-
Create a new repository at https://gitea.com/repo/create
GitHub
-
Create an account at https://github.com/signup
-
Log in at https://github.com/login
-
Set up an SSH key for access at https://github.com/settings/keys
-
Create a new repository at https://github.com/new
GitLab
-
Create an account at https://gitlab.com/users/sign_up
-
Log in at https://gitlab.com/users/sign_in
-
Set up an SSH key for access at https://gitlab.com/-/profile/keys
-
Create a new repository at https://gitlab.com/projects/new
NotABug
-
Create an account at https://notabug.org/user/sign_up
-
Log in at https://notabug.org/user/login
-
Set up an SSH key for access at https://notabug.org/user/settings/ssh
-
Create a new repository at https://notabug.org/repo/create
Savannah
-
Create an account at https://savannah.nongnu.org/account/register.php
-
Set up an SSH key for access at https://savannah.nongnu.org/my/admin/editsshkeys.php
-
Create a new repository at https://savannah.nongnu.org/register/
SourceForge
-
Create an account at https://sourceforge.net/user/registration
-
Log in at https://sourceforge.net/auth/
-
Set up an SSH key for access at https://sourceforge.net/auth/shell_services
-
Create a new repository at https://sourceforge.net/p/add_project
SourceHut
-
Create an account at https://meta.sr.ht/register
-
Log in at https://meta.sr.ht/login
-
Set up an SSH key for access at https://meta.sr.ht/keys
-
Create a new repository at https://sr.ht/projects/create
Git Setup
At this stage we expect you have chosen your code hosting platforms and have created your user, optional organization, and project at each one.
Also, you should have a list of the resulting project URLs at different platforms. Then you can proceed with this chapter.
Introduction
In Git, remote repositories are called “remotes”. Each remote has a name, a URL, and a read-write flag.
By default, the default upstream remote is called an “origin”. That is the place from which you have cloned the repository. We will consider that one to be the primary origin.
You can list all remotes on a project by running git remote -v
. For example:
git clone git@github.com:crystallabs/hugo-template-minima-crystallabs blog
cd blog
git remote -v
origin git@github.com:crystallabs/hugo-template-minima-crystallabs (fetch) # Read
origin git@github.com:crystallabs/hugo-template-minima-crystallabs (push) # Write
git remote get-url origin
git@github.com:crystallabs/hugo-template-minima-crystallabs
Note that all Git-related settings are stored in the file .git/config
in the project’s root directory. The settings can be changed by running various git
commands or by just directly modifying the file.
Adding Multiple Origins
Multiple origins can be configured in two basic ways:
-
Multiple URLs can be added under the existing
origin
entry -
Separate
origin
entries can be created, each with a different name and URL
Our procedure for adding multiple origins will be the second one – adding separate, provider-specific origins to the project configuration.
The primary origin will thus appear in the list twice – the first time because it was cloned from and is already configured as origin
, and the second time because it will be added as origin-PROVIDER
.
That’s done simply for consistency and does not affect behavior.
For a project that was cloned from GitHub and is about to be configured for multiple providers, the procedure might look like this:
USER_OR_ORG=crystallabs
REPOSITORY=hugo-template-minima-crystallabs
# Add origins
git remote add origin-bitbucket git@bitbucket.org:$USER_OR_ORG/$REPOSITORY.git
git remote add origin-codeberg git@codeberg.org:$USER_OR_ORG/$REPOSITORY.git
git remote add origin-gitea git@gitea.com:$USER_OR_ORG/$REPOSITORY.git
git remote add origin-github git@github.com:$USER_OR_ORG/$REPOSITORY.git
git remote add origin-gitlab git@gitlab.com:$USER_OR_ORG/$REPOSITORY.git
# NaB, Savannah, SF
git remote add origin-sourcehut git@git.sr.ht:~$USER_OR_ORG/$REPOSITORY.git
# Check origins
git remote -v
origin git@github.com:crystallabs/hugo-template-minima-crystallabs (fetch)
origin git@github.com:crystallabs/hugo-template-minima-crystallabs (push)
origin-bitbucket git@bitbucket.org:crystallabs/hugo-template-minima-crystallabs.git (fetch)
origin-bitbucket git@bitbucket.org:crystallabs/hugo-template-minima-crystallabs.git (push)
origin-codeberg git@codeberg.org:crystallabs/hugo-template-minima-crystallabs.git (fetch)
origin-codeberg git@codeberg.org:crystallabs/hugo-template-minima-crystallabs.git (push)
origin-gitea git@gitea.com:crystallabs/hugo-template-minima-crystallabs.git (fetch)
origin-gitea git@gitea.com:crystallabs/hugo-template-minima-crystallabs.git (push)
origin-github git@github.com:crystallabs/hugo-template-minima-crystallabs (fetch)
origin-github git@github.com:crystallabs/hugo-template-minima-crystallabs (push)
origin-gitlab git@gitlab.com:crystallabs/hugo-template-minima-crystallabs.git (fetch)
origin-gitlab git@gitlab.com:crystallabs/hugo-template-minima-crystallabs.git (push)
origin-sourcehut git@git.sr.ht:~crystallabs/hugo-template-minima-crystallabs (fetch)
origin-sourcehut git@git.sr.ht:~crystallabs/hugo-template-minima-crystallabs (push)
When we take a look at what was configured in .git/config
, we see:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = git@github.com:crystallabs/hugo-template-minima-crystallabs
fetch = +refs/heads/*:refs/remotes/origin-github/*
[branch "master"]
remote = origin-github
merge = refs/heads/master
[remote "origin-github"]
url = git@github.com:crystallabs/hugo-template-minima-crystallabs
fetch = +refs/heads/*:refs/remotes/origin-github/*
[remote "origin-bitbucket"]
url = git@bitbucket.org:crystallabs/hugo-template-minima-crystallabs.git
fetch = +refs/heads/*:refs/remotes/origin-bitbucket/*
[remote "origin-codeberg"]
url = git@codeberg.org:crystallabs/hugo-template-minima-crystallabs.git
fetch = +refs/heads/*:refs/remotes/origin-codeberg/*
[remote "origin-sourcehut"]
url = git@git.sr.ht:~crystallabs/hugo-template-minima-crystallabs
fetch = +refs/heads/*:refs/remotes/origin-sourcehut/*
Working with Multiple Origins
Many commands default to origin
being the default value. As long as you do not specify anything manually, origin
will be used. That is the standard workflow, unaffected by our addition of origins.
Git Push
Command git push
does not support an option like --all-remotes
to push to all remotes at once. That even makes sense because not all remotes configured on a project are its origins.
You can push to specific origins with e.g.:
git push origin-codeberg
But our naming was purposely origin-*
so that origins could be easily recognized among the remotes, and that pushing to multiple origins could be scripted.
for p in `git remote | grep origin`; do echo -n "$p "; git push $p; done
origin Everything up-to-date
origin-github Everything up-to-date
origin-bitbucket Everything up-to-date
origin-codeberg Everything up-to-date
origin-sourcehut Everything up-to-date
The workflow assumes that a successful push will always be done to all origins. That is recommended and what users generally expect, although it is not critical because nothing bad will happen if some origins are temporarily behind.
Git Pull, Git Fetch
Internally, git pull
does a git fetch
and then updates the current tree.
Git does not support pulling from multiple origins, but that is expected. If your repositories at different providers are all in sync, it does not matter which one you pull from – you can just pull from the default origin
:
git pull
But what if you or other team members have pushed changes to an incomplete list of remote origins, or to just the default origin
?
What you can do in that case is fetch
updates from all origins, and then pull from the specific, newest one:
git fetch --all
Fetching origin
Fetching origin-github
Fetching origin-bitbucket
Fetching origin-codeberg
Fetching origin-sourcehut
git pull # Pulls from default origin
git pull origin-codeberg master # Pulls the master branch from `origin-codeberg`
There’s no need to worry about remote origins and versions they contain – as long as the code did not diverge, a git push
to all origins will bring them to the same state.
Branches
Each branch can track a single remote branch. This is visible in .git/config
under a particular branch, e.g.:
[branch "master"]
remote = origin-github
merge = refs/heads/master
Branch in the example is called master
. Sometimes copy-paste instructions create a branch called main
instead; adjust as necessary in your specific case.
The remote used by a branch can be tuned either in the file, or with git checkout BRANCH; git branch -u REMOTE/BRANCH
. For example:
git checkout master
git branch -u origin-codeberg/master
cat .git/config | grep -A3 master
[branch "master"]
remote = origin-codeberg
merge = refs/heads/master
Article Collection
This article is part of the following series:1. Git
Automatic Links
The following links appear in the article:
1. https://bitbucket.org/
2. https://bitbucket.org/account/settings/ssh-keys/
3. https://bitbucket.org/account/signup
4. https://codeberg.org/
5. https://codeberg.org/repo/create
6. https://codeberg.org/user/login
7. https://codeberg.org/user/settings/keys
8. Free Software Foundation (FSF) - https://en.wikipedia.org/wiki/Free_Software_Foundation
9. GNU Savannah - https://en.wikipedia.org/wiki/GNU_Savannah
10. Gitea - https://gitea.com/
11. https://gitea.com/repo/create
12. https://gitea.com/user/login
13. https://gitea.com/user/settings/keys
14. https://gitea.com/user/sign_up
15. GitHub - https://github.com/
16. https://github.com/login
17. https://github.com/new
18. https://github.com/settings/keys
19. https://github.com/signup
20. GitLab - https://gitlab.com/
21. https://gitlab.com/-/profile/keys
22. https://gitlab.com/projects/new
23. https://gitlab.com/users/sign_in
24. https://gitlab.com/users/sign_up
25. https://id.atlassian.com/login
26. https://meta.sr.ht/keys
27. https://meta.sr.ht/login
28. https://meta.sr.ht/register
29. NotABug - https://notabug.org/
30. https://notabug.org/repo/create
31. https://notabug.org/user/login
32. https://notabug.org/user/settings/ssh
33. https://notabug.org/user/sign_up
34. Savannah - https://savannah.nongnu.org/
35. https://savannah.nongnu.org/account/login.php
36. https://savannah.nongnu.org/account/register.php
37. https://savannah.nongnu.org/my/admin/editsshkeys.php
38. https://savannah.nongnu.org/register/
39. SourceForge - https://sf.net/
40. https://sourceforge.net/auth/
41. https://sourceforge.net/auth/shell_services
42. https://sourceforge.net/p/add_project
43. https://sourceforge.net/user/registration
44. SourceHut - https://sr.ht/
45. https://sr.ht/projects/create
46. GNU Free Documentation License (FDL) V1.3 - https://www.gnu.org/licenses/fdl-1.3.html
47. GNU General Public License (GPL) V3 - https://www.gnu.org/licenses/gpl-3.0.en.html