简体   繁体   中英

How do I setup a staging repository in 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.

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 repository 1 :

$ git fetch upstream +master:refs/heads/x_master

This will overwrite 2 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 .

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

The best way would be to have one responsible developer (call him dev0) who will do the stuff. He has to have read and write access to A. He can set A as a remote in his local repo and maintains B/x_master by pulling commits from A/master to his local x_master and pushing it to B. As you mentioned, that should be easy and always fast-forward. (So it may be scripted)

As B/x_master is also visible to all of the developers anybody can merge (and see/fix conflicts) x_master to master when they feel the need to integrate it to development.

When development is done, dev0 will merge master to x_master. This needs the supervision of a human anyhow, because of possible conflicts. He has also the chance to cancel the merge at this point and do additional commits to reflect the conflict resolving in your development branch. So you can also discuss them in group. When that is done, dev0 can again try to merge master to x_master. Afterwards x_master is pushed to A/master.

I assume both A and B are bare repositories used only for pushing and pulling with, right?

I'd argue the simplest way would be to simply have an intermediate repository between A and B. That is, a non-bare one, with a working tree. That way, you can pull and merge from any of the branches in A and B in complete peace and isolation from everyone else, fine-tune the merges until you are entirely happy with them, and then push them to either one of A and B.

Of course, if you already have a working copy, you could simply use that one as that intermediate repository. There's no particular need to create an explicit one; just do all your intermediate work in temporary branches.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM