4c0f35815fbc2fe8543006354b6e177a6e5f60a3
[git-mirror.git] / README.md
1 # git-mirror: Sync your git repositories
2
3 ## Introduction
4
5 [git-mirror](https://www.ralfj.de/projects/git-mirror) is a tool to keep 
6 multiple git repositories of the same project in sync. Whenever something is 
7 pushed to any repository, the commits will immediately be forwarded to all the 
8 others. The tool assumes to run on a server hosting one of these repositories - 
9 so there has to be at least one you can control. A typical use-case would be 
10 your own [gitolite](http://gitolite.com/gitolite/index.html) installation, that 
11 you want to keep in sync with [GitHub](https://github.com/).
12
13 ## Setup (gitolite)
14
15 This describes how you set up git-mirror on a server running gitolite. For other 
16 git hosting software, please consult the respective documentation on adding git 
17 hooks. I will assume that gitolite is installed to `/home/git/gitolite`, that 
18 the repositories are sitting in `/home/git/repositories`, and that git-mirror 
19 has been cloned to `/home/git/git-mirror`.
20
21 First of all, you need to create a file called `git-mirror.conf` in the 
22 `git-mirror` directory. For now, it only needs to contain a single line:
23
24     mail-sender = git@example.com
25
26 We will also need to add hooks to the git repositories you want to sync. The 
27 easiest way to manage these hooks is to put them into your `gitolite-admin` 
28 repository, so enable the following line in `/home/git/.gitolite.rc`:
29
30     LOCAL_CODE                =>  "$rc{GL_ADMIN_BASE}/local",
31
32 Make sure you read the [security note](http://gitolite.com/gitolite/non-core.html#pushcode)
33 concerning this configuration.
34
35 Furthermore, uncomment the `repo-specific-hooks` line in the rc file or add it
36 to the `ENABLE` list if it doesn't exist.
37
38 Now add a file called `local/hooks/repo-specific/git-mirror` to your 
39 `gitolite-admin` repository, make it executable, and give it the following
40 content:
41
42     #!/bin/sh
43     exec ~/git-mirror/githook.py
44
45 For every repository you want to be synced, you can enable the hook by adding 
46 the following line to its configuration in `conf/gitolite.conf`:
47
48     option hook.post-receive = git-mirror
49
50 (If you need multiple hooks here, you can separate them by spaces.)
51
52 Finally, you need to tell git-mirror where to sync incoming changes to this 
53 repository to. Add a block like the following to `git-mirror.conf`:
54
55     [repo-name]
56     owner = email@example.com
57     local = /home/git/repositories/repo-name.git
58     deploy-key = ssh-key
59     mirror-a = git@server2.example.com:repo-name.git
60     mirror-b = git@server2.example.org:the-repo.git
61
62 Here, `local` has to be set to the path where the repository is stored 
63 locally. `deploy-key` is the name of the SSH key used for pushing the changes 
64 to other repositories. `owner` is the e-mail-address that errors occurring 
65 during synchronization are sent to. And finally, the URLs to push to are given 
66 by `mirror-<something>`. If these other servers also run gitolite and have a 
67 symmetric setup, then no matter where a change is pushed, git-mirror will 
68 forward it to all the other repositories.
69
70 ## Setup (GitHub)
71
72 If one of the to-be-synced repositories is on GitHub, you can obviously not use 
73 the procedure above to sync changes that are arriving at GitHub, to the other 
74 repositories. Instead, we will use a webhook, such that GitHub tells your server 
75 that a change happened, and then your server can pull the changes to its local 
76 repository and synchronize all the others. This assumes that the server running 
77 the webhook also hosts one of the copies of the git repository.
78
79 First of all, you will have to configure your webserver to run `webhook.py` as 
80 CGI script. Consult the webserver documentation for more details.
81
82 Secondly, `webhook.py` needs to be able to find the main git-mirror scripts, 
83 and it needs to be able to execute them as the `git` user. For the first 
84 point, open `webhook.py` and change `webhook_core` to point to the file 
85 `webhook-core.py` in your git-mirror clone. If your installation matches the 
86 paths I used above, that should already be the case. For the second point, 
87 `webhook.py` is using `sudo` to elevate its privileges. You need to tell 
88 `sudo` that this is all right, by creating a file 
89 `/etc/sudoers.d/git-mirror` with content:
90
91     www-data        ALL=(git) NOPASSWD: /home/git/git-mirror/webhook-core.py
92
93 Now, if you visit `https://example.com/git-mirror/webhook.py` (replace with 
94 your URL), the script should run and tell you `Repository missing or not 
95 found.`.
96
97 The next step is to add this as a webhook to the GitHub repository you want to 
98 sync with, to create a fresh SSH key and configure it as deployment key for the 
99 repository, and to configure git-mirror accordingly. For additional security, 
100 one should also configure a shared HMAC secret, such that the webhook can verify 
101 that the data indeed comes from GitHub.  On the git-mirror side, the HMAC secret
102 is configured with the `hmac-secret` repository option.
103
104 To make your job easier, there is a script `github-add-hooks.py` that can do 
105 all this for you. It assumes that the repository exists on the GitHub side, but 
106 has not yet been configured for git-mirror at all.
107
108 To give the script access to your repositories, you need to create an access 
109 token for it. Go to "Personal Access Tokens" in your GitHub configuration, and 
110 create a new token with the permissions `admin:repo_hook` and `public_repo`. 
111 Add the token and the webhook URL to the top part of `git-mirror.conf` (right 
112 below `mail-sender`):
113
114     github-token = pastethetokenhere
115     webhook-url = https://example.com/git-mirror/webhook.py
116
117 Now you can call the automatic setup script as follows:
118
119     ./github-add-hooks.py -o UserName -e email@example.com \
120       -l ~/repositories/repo-name.git/ -n github-repo-name
121
122 Notice that the username is case-sensitive! This will do all the setup
123 on the GitHub side, and it will add an appropriate configuration block
124 to your local `git-mirror.conf`. You still have to manually add the
125 local git hook to gitolite. Once you are done, any push happening to
126 either gitolite or GitHub will be visible on the other side
127 immediately. This applies even to pull requests that you merge in the
128 GitHub web interface.
129
130 ## Source, License
131
132 You can find the sources in the [git
133 repository](https://git.ralfj.de/git-mirror.git) (also available
134 [on GitHub](https://github.com/RalfJung/git-mirror)).  Guess what, the
135 two are synced with this tool ;-) . They are provided under a
136 [2-clause BSD
137 license](http://opensource.org/licenses/bsd-license.php). See the file
138 `LICENSE-BSD` for more details.
139
140 ## Contact
141
142 If you found a bug, or want to leave a comment, please [send me a
143 mail](mailto:post-AT-ralfj-DOT-de). I'm also happy about pull requests
144 :)