简体   繁体   中英

How to push git snapshots from a private git repository to public git repository?

I have two git repos:

  1. A private one for the developers and their daily commits
  2. And a public one for public releases.

Whenever I want to release code I want to push a snapshot of the developer repo to the public repo. Since the developer repo might contain some commit messages which are not suitable for public, I want to push to the public repo with a new commit message.

My I idea was (assuming I'm in the master branch of the dev repo):

// create remote 
git remote add p_repo git://some_repo
// create orphaned branch to get rid of commit history
git checkout --orphan pub_sync
// commit 
git commit -m "release info"
// push local master to remote master
git push p_repo pub_sync:master

This works for the very first time when the public repo is empty. But for the second public push I get an fast-forward error. There was no other commit to the public repo in the mean time!

I assume the problem is, that git doesn't know that the orphaned branch is related to the public master.

But how can I solve this?

TL;DR

Use git merge --squash --no-commit

Details

For the first commit, your procedure sounds find.

For subsequent commits, I would use

git merge --squash --no-commit

For this to work, you need a sandbox with both your dev repo and your public repo, as you did, though I expect it would be easiest if the sandbox was a clone of the public repo.

Here's a procedure that should work:

git clone public_repo
cd public_repo
git remote add dev dev_repo_url
git fetch dev
git merge --squash --no-commit dev/master
git commit -m'updated to version X'
git push

The results you get from git merge --squash --no-commit will have no connections to your dev repo, it only gets the state of the files into your sandbox, which you can then commit as a subsequent step.

You might need to add a -Xtheirs if the merge results in conflicts, since I'm assuming you want exactly the state of dev/master , not some merge of the public and dev branches.

Why

The point of this approach is that the new commit has the previous public version as its parent, which is what you want in your public repo. The error you got was due to the new version not being a child of the previous one, but a fresh root, which is not generally recommended.

The problem is that you're trying to push a new commit to the remote master, from which the commit currently at the remote master isn't reachable. The first time you did it, presumably the remote had no commits. So you started with

O -- x ... x -- A <--(master)

in your local repo. You create the orphan branch and push, so now you have

O -- x ... x -- A <--(master)

R1 <--(pub_sync)(p-repo/master)

Now you didn't say explicitly how you did this the 2nd time, but it sounds like you either deleted the local pub_sync branch, or did something equivalent. (Because otherwise, following exactly the same steps as above, the branch creation would fail.) So after you did some development and another new checkout --orphan you would have

O -- x ... x -- A -- x .. x -- B <--(master)

R1 <--(p-repo/master)

R2 <--(pub_sync)

Perhaps that's what you meant about git "not knowing" that the new orphan branch is related to the remote master , in which case you're right. Now you could force-push pub_sync , but I don't recommend it for two reasons: First, force pushing shouldn't be a routine part of your workflow. Second, since you're keeping the releases in a repo, I assume you want to preserve the release history there.

What you really need is to create R2 as a child of R1 .

In another answer, someone suggests squash merging; the problem with that is, you would have to manually track a merge base. There's a pattern you could follow where you first do true merges to an intermediate branch, and then reapply just that one patch to the final release branch; but it's probably overkill for your use case. Alternately you could create a ref to represent the merge base, and remember to move it after each squash merge. Also, contrary to the instructions from the other answer, if you don't want to risk accidentally exposing the dev commits in the prod repo, you'd need to do the squash merges on the dev side and push only the result.

Or, you could use commit-tree ; that's a bit of a hassle, too, but perhaps could be scripted or aliased. You would not delete / re-orphan the sync branch; so starting from

O -- x ... x -- A -- x .. x -- B <--(master)

R1 <--(pub_sync)(p-repo/master)

you would

git checkout pub_sync
git merge $(git commit-tree -p HEAD -m "commit message" master)
git push p-repo pub_sync:master

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