I want to create a repository [B] that tracks a remote repository's master [A] in a branch called x_master. Its own master should also be a clone at the initial creation time that others [Devs] can clone and push changes into.
Occasionally, as there are changes in A, I will need to be able to pull them down and merge them into B's x_master (which, if I understand this, should be a fast-forward as they will be the only changes in x_master branch on B), and then be able to merge those changes into B's master, and thus onto anyone cloning B's master when they pull.
What I conceptually want is this:
master x_master
[A] <---------> [B] <-------> [Dev2]
^-------> [Dev1]
master
Eventually I'd need to push changes in B's master up to A's master when all the dev is done, but there will be changes going on in A that need to be merged into B
I've tried all kinds of clone --mirror, branch --track, and just don't seem to get the changes in A and B pushing and pulling correctly.
I am sure there is a shortcut for it, but I tend to just use basic commands. In any case, set up repository for B
:
$ cd repo_B
$ git init --bare
$ git remote add upstream URL_FOR_REPO_A
$ git fetch upstream +master:refs/heads/x_master
$ git branch master x_master
When upstream repository is modified, you need to pull those changes in on the bare repository1:
$ git fetch upstream +master:refs/heads/x_master
This will overwrite2 any possible changes in x_master
, so you'd better leave that branch alone. :)
You will want to merge upstream changes in x_master
into master
when/if A changes. Unfortunately, there may be conflicts at this stage, so it must be done with a clone of our bare repository. Simply clone the B repository (to a local or a remote location), and merge x_master
into master
, resolve the conflicts, and push back.
And the final task is pushing development done in master
to repository A. This can be done in two ways. The first is by directly pushing B's master to repository A. This can be done by running:
$ git push upstream
on repository B. An alternative is a more controlled merge from master
to x_master
using a third repository:
$ git clone URL_FOR_REPO_A
$ cd repoDir
$ git remote add dev URL_FOR_REPO_B
$ git fetch dev
$ git branch --track master_b dev/master
$ git merge master_b
$ <resolve conflicts, if any>
$ git push origin master
For completion, you can configure the remote to only fetch that branch by default:
$ git configure branch.upstream.fetch +master:refs/heads/x_master
And with --add
, you can even add more branches to fetch:
$ git configure --add branch.upstream.fetch +branch_1_0:refs/heads/x_branch_1_0
Now, fetch will work properly without refspecs:
$ git fetch upstream
To prevent pushes to master
of repo_B
, you can use a server-side hook like pre-receive
or update
.
I was inspired, but also somewhat confused by vhallac's answer. I think something simpler may work just as well...
mkdir (name).staging.git ; cd (name).staging.git
git init --bare
git remote add origin (remote-repo)
Periodically (including initially), you will want to fetch changes and update the local branches...
git fetch
for remote in $(git branch -r) ; do git branch --force --no-track $(basename $remote) $remote ; done
Note that it is necessary to update the local branches every time you fetch, otherwise the third-level repo won't see the upstream changes. My example updates all local branches, but you could instead do this manually for only the branches of interest. I suggest creation of an alias "git staging-fetch" that combines these two lines into a single command.
Pushing from the staging repository to the master repository is straightforward as long as there is no merge required (just do a regular push). If the push fails due to conflicts, then you need to fetch the updates through both levels and resolve things in the working repository.
Note: This scheme does not require a branch called "x_master". Git has built-in support for using a local branch to shadow a remote branch. So all "master" branches are just called "master", but when referring to the branch in the immediately upstream repository, you would call it "origin/master" or "staging/master" as the case may be.
branch: origin master staging master working master
============= ============== ==============
origin sees: master
staging sees: origin/master master
working sees: staging/master master
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With