Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I setup a staging repository in git?

Tags:

git

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

  • How do I set this up?
  • How do I push and pull from B into and from A?
  • Does this setup make sense?

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.

like image 259
Mark Fisher Avatar asked Oct 20 '11 19:10

Mark Fisher


2 Answers

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

Note 1

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

Note 2

To prevent pushes to master of repo_B, you can use a server-side hook like pre-receive or update.

like image 92
vhallac Avatar answered Oct 30 '22 21:10

vhallac


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
like image 38
Brent Bradburn Avatar answered Oct 30 '22 20:10

Brent Bradburn