Forking a Receive Mirror
git-teleport Receive Mirrors are READ-ONLY. You MUST NOT make any commits to git-teleport mirrors. Instead, they must be treated like external repositories for which you lack write permission.
If you want to make changes to a mirrored project, you need to fork it. "Forking" a repository creates a new one with the same commits as the upstream project. This process is identical to that used by Github et. al.: A copy of the original repository is made. This copy, called the "fork," is a place where you can make your changes. Forks are kept up-to-date by manually merging in changes from the original repository, which is called the "upstream."
Create the Fork
git-teleport does not create or manage forks. If you want a fork, you must create one "by hand."
On a filesystem
Make a new server-style repository for your forked changes. It will start empty. For a mythical Receive Mirror stored at
/net/git/mirrors/intranet/ProjectAlpha.git
you can create the mirror as follows
cd /net/git
# you should probably ensure the fork is group read/write
umask 002
# create a new bare repo and mirror
git init ProjectAlpha.git --shared --bare
cd ProjectAlpha.git
git fetch \
file:///net/git/mirrors/intranet/ProjectAlpha.git \
'+refs/*:refs/*'
# --shared ensures your repository is always group read-write,
# but it also disables force-push by default. You probably
# want to do this:
git config --local receive.denyNonFastForwards false
On a smart host
If you use smart repository hosting software, it likely has a "fork" option. You can use this option to duplicate a Receive Mirror into another repository. If your Receive Mirror is named
mirrors/intranet/ProjectAlpha.git
then your fork should probably be named
ProjectAlpha.git
On some hosting software, like Gitlab, using the "fork" button will make merge requests target the Receive Mirror (mirrors/intranet/ProjectAlpha.git) by default. This is not what you want! You can't merge anything into the Receive Mirror because it's read-only. Adjust your options to ensure that all merge requests target the fork itself.
Merges Happen in a Working Copy
Your fork will probably diverge from its parent project. To keep your fork up-to-date, you need to merge changes from the outside world into your fork.
Git merges require a working copy, so let's make one of those.
cd "$SOMEWORKDIR"
git clone file:///net/git/ProjectAlpha.git
cd ProjectAlpha
git remote add upstream file:///net/git/mirrors/intranet/ProjectAlpha.git
git remote set-url --push upstream /dev/null
The working copy now has two remotes:
-
origin, which refers to the forked repository. You will use this remote on a day-to-day basis. -
upstream, which points to the git-teleport mirror from the remote system. This is a read-only mirror. Like a Github project which belongs to someone else, you can't change it. Theset-urlcommand above will ensure that you cannot accidentally push toupstream.
Whenever you receive git-teleport updates, you should merge them into your fork. To merge their master branch into your master branch, you can run something like:
git fetch --all
git checkout master
git rebase # origin/master
git merge --no-ff upstream/master
# … resolve conflicts if necessary …
git push --follow-tags origin master
The above merging workflow is only one possible flow. Here are a few more:
-
Fast-forward only: You can reserve the
masterbranch for use by the upstream project only. In this case, all merges can be--ff-onlyfast-forward merges. Use a different branch for your site's local changes. -
Subtree merges: If the upstream project is a small piece of your project—i.e., a dependency—you can keep it in a subdirectory of your repository like
project_alpha/. In this case, you may not want a fork at all. Consider if agit-subtreeworkflow is the right approach. -
Independent projects: In some cases, you might want to make permanent changes to the project which are never going to be ported upstream. These might include CI/CD jobs, build-system tweaks, or even code changes. You might also want to make your own tagged releases. This workflow is discussed in the next section.
Regardless of the workflow you choose, you should be sure to document which branches get merged, and when.
Independent Projects
If you are making a long-lived fork, chances are you will want to make your own releases. This section assumes that you will have:
-
A branch named
masterthat is only for releases. Every merge intomasterrepresents a release. -
A branch named
developfor integrating changes for the next release. -
Other branches for features and bugfixes.
This is the git-flow workflow used by git-teleport and many other projects. You can use a simpler, single-branch workflow without a develop branch if that is more to your liking.
To begin, don't make a fork. Instead, create a new empty server repository (like file:///net/git/ProjectAlpha.git) and working copy.
cd "$SOMEWORKDIR"
git init ProjectAlpha
cd ProjectAlpha
# you can also use `git flow init -d` if installed
git commit --allow-empty -m 'Initial commit'
git checkout -b develop
# populate the server-side repository, wherever you put it
git remote add origin file:///net/git/ProjectAlpha.git
git push --set-upstream origin master develop
# add the upstream project mirrored by git-teleport
git remote add upstream file:///net/git/mirrors/intranet/ProjectAlpha.git
git remote set-url --push upstream /dev/null
If you are using a git-flow workflow, you probably want to periodically merge one of the upstream project's version tags, or their master branch, into your develop branch.
git fetch --all
git checkout develop
git rebase
git merge --no-ff v1.0.4 # or upstream/master
This merge workflow ensures that:
- All commits in
upstream/masterend up in your project. - Upstream updates are easy to identify in your history.
If your project will make its own tagged releases, make sure to pick a different tag prefix than the upstream project.
Be sure to document your chosen approach.
Submit Your Changes Upstream
Over time, a long-running fork can diverge from its parent project. This will invariably lead to merge conflicts and other maintenance issues—all of which may require substantial effort to fix.
One of the most helpful and productive things a software engineer can do is to find problems and fix them. An even more productive thing to do is to fix them upstream. By submitting your changes back to the original maintainer, you can reduce your maintenance burden and also improve the software for everyone.
Changes may be submitted to an upstream repository via a patch workflow.