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:

  1. origin, which refers to the forked repository. You will use this remote on a day-to-day basis.

  2. 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. The set-url command above will ensure that you cannot accidentally push to upstream.

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 master branch for use by the upstream project only. In this case, all merges can be --ff-only fast-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 a git-subtree workflow 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:

  1. A branch named master that is only for releases. Every merge into master represents a release.

  2. A branch named develop for integrating changes for the next release.

  3. 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:

  1. All commits in upstream/master end up in your project.
  2. 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.