31

One of the side-effects of using an external Subversion repository was getting automatic offsite backups on every commit.

I'd like to achieve the same using Git.

i.e. every commit to my local repository automatically commits to an external one so the two repositories are always in sync.

I imagine that a post-commit hook would be the way to go. Does anyone have any specific examples of this?

Andy Baker
  • 21,158
  • 12
  • 58
  • 71

3 Answers3

28

I wrote a post-commit hook for just this purpose. The hook itself is simple; just add a file named post-commit to your .git/hooks/ directory with the following contents:

git push my_remote

The post-commit file should be executable. Also make sure that you add a suitable remote repository with the name my_remote for this this hook to work.

I also made a symlink named post-merge that points to post-commit. This is optional. If you do this you'll auto-sync after merges as well.

UPDATE: If you want to ensure that your server, and your mirror do not get out of sync, and ensure that all branches are also backed up, your post-commit hook can use:

git push my_remote -f --mirror
Jay
  • 19,649
  • 38
  • 121
  • 184
Manoj Govindan
  • 72,339
  • 21
  • 134
  • 141
  • 2
    Are there any remaining scenarios where the repo could become out of sync? How would I check (and re-sync). Can people commit to the external repo? – Andy Baker Aug 27 '10 at 11:06
  • `Can people commit to the external repo?`: this would depend on how the external repo is configured. If you want a read only mirror then you can prevent others from committing. `How would I check (and re-sync)` if no one else is committing to the repo then I don't see too many ways of how the repos could be out of sync. If they do then there is always merge. – Manoj Govindan Aug 27 '10 at 11:19
  • Sorry. My additional question was badly worded. – Andy Baker Aug 27 '10 at 11:28
  • 8
    You might want to use `push -f --mirror` so that it will always succeed (even if there are non-fastforward changes) and so it will be a full mirror with *all* refs. (Otherwise, if you add a new branch, it won't get pushed, since it doesn't exist in the mirror, and the default is to push matching branches.) – Cascabel Aug 27 '10 at 13:05
  • Anyone has use this approach in a many user scenario? Rebases, merges and other stuff that could make it more complicated. – Oximer Sep 26 '17 at 01:58
  • Is there a way to set this up as a pre or post-commit hook without having the hook trigger itself? – ConorSheehan1 Feb 12 '19 at 15:26
  • if the push location needs auth, maybe store the password in GitHub secret? – Luk Aron Feb 24 '21 at 01:05
1

I just wanted to add that I had a similar issue, but in my case I needed every push to a remote repository to automatically mirror to another remote as a backup. My local machine also couldn't directly connect to the mirrored repo, so it had to be pushed from the server-side.

For that, I had to create a post-receive hook on the remote repo (under the hooks/ directory). And then, as Manoj's answer suggested, I simply added the following command to the post-receive file:

git push --mirror my_remote

Hopefully that will help others who, like me, stumbled upon this question from Google.

AdHorger
  • 470
  • 6
  • 13
  • How to do this hook for private repository? – WeiHua Liu Jul 14 '22 at 11:12
  • @WeiHuaLiu I'm not sure exactly what you mean by a private repository, but I assume you mean a private *GitHub* repository. For that you would need to make sure that the server with the `post-receive` hook has an SSH key configured for GitHub, then specify the SSH URL of the private repository in the `push` command. For more info, [this link](https://docs.github.com/en/authentication/connecting-to-github-with-ssh) might be helpful. – AdHorger Jul 14 '22 at 15:56
  • Sorry for the bad question. I only know that a ".git/hook" directory is in a local repository. Where is the ".git/hook" directory on a remote server? In my case, I want to make a GitHub private repository automatically mirror to an azure private repository or vice-versa. – WeiHua Liu Aug 01 '22 at 07:57
  • I can't answer much about Azure or GitHub's implementation, since the remote server I used is managed by my team. But I believe you can simply create the `post-receive` hook on your local repository, and when you push your changes to the remote repository the hook will start triggering. However, you might need to check the Azure/GitHub documentation if that doesn't work. – AdHorger Aug 02 '22 at 19:32
1

GitBitLabHub allows you automatically mirror repositories between Bitbucket / Gitlab / Github using simple webhooks. Under the hood it does the following:

git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch --prune
git remote set-head origin -d
git branch -a || 'true'
git push --prune dest +refs/remotes/origin/*:refs/heads/* +refs/tags/*:refs/tags/*

All you need is to set up deploy keys and webhooks:

  1. Generate an ssh key for source and destination repositories:
ssh-keygen -t rsa -f ~/.ssh/project_id_rsa
  • It will generate 2 keys, the PRIVATE key to ~/.ssh/project_id_rsa and the PUBLIC key to ~/.ssh/project_id_rsa.pub.
  • The PUBLIC key is used as Deploy Key while the PRIVATE key should be used in SRC_DEPLOY_KEY and DEST_DEPLOY_KEY env variables.
  1. Add this PUBLIC key as a Deploy Key for the source and destination repositories. Depending on the platform it's called Deploy Key or Access key. See how to add Deploy/Access Key to bitbucket, bitbucket access keys, gitlab, github.
  • Add the PUBLIC key to the source repo with read-only access.
  • Add the PUBLIC key to the destination repo with write access.
  1. Create the webhook in the source repository. Using default settings should be enough. See how to create a webhook in bitbucket, gitlab, github.
karser
  • 1,625
  • 2
  • 20
  • 24