1# GitHub Workflow for Open Source Projects
2
3(c) 2017 Stefan Hundhammer
4
5License: GNU Free Documentation License
6
7
8This is the workflow used for Open Source projects like QDirStat and YaST.
9
10Some of this is mandated by the tools used (git, GitHub), some of it is just
11best practices.
12
13
14## Overview
15
16Even though GitHub hosts the original source code repositories for those
17projects, you don't work directly in them. Rather, you create your own forked
18repository (your _fork_), work in that one, and when you finished something you
19want to contribute to the original repository (called _upstream_), you create a
20pull request.
21
22That pull request is reviewed by the owner of the original project or by or
23senior team members. They might ask you for changes if anything in your pull
24request does not meet the project's quality criteria or violates the coding
25style. In that case, you add more commits to the pull request, and it is
26reviewed again etc. until everybody is satisfied and it is either merged (which
27is the normal case) or it is finally rejected (which is a very rare thing).
28
29When your changes are merged, you pull or rebase your fork against _upstream_
30again so it is up to date, and then you can freely work on new things.
31
32One holy rule is that **upstream master always has to work**, even between
33official releases. This is much easier to achieve when everybody works in their
34own fork, preferably in their own branch of their own fork.
35
36
37## Initial Setup
38
39- If you don't have one yet, create a user account at
40  [GitHub](https://www.github.com).
41
42- Make sure to upload your ssh key to your GitHub account.
43  [More info...](https://help.github.com/articles/connecting-to-github-with-ssh/)
44
45- Log in at GitHub.
46
47- Fork the original (upstream) repository to your GitHub account.
48  You now have your own repo with that name.
49
50  **But it does not automatically sync itself with the upstream repo** as
51  others commit changes there after you forked; you have to do that manually
52  (see below).
53
54- In a shell on your working machine (preferably Linux), clone your forked repo
55  to that machine:
56
57      cd ~/src
58      git clone -o mine git@github.com:kilroy/qdirstat.git
59
60  Where _kilroy_ is your GitHub user name which is part of the URL of that
61  fork. **Make sure to use the "git@github" URL**, not the "https://" URL: The
62  https URL is only useful for pulling (i.e. for read-only access), not for
63  pushing (i.e. for read-write access). Since you also want to commit changes
64  to that repo, you need read-write access.
65
66  _mine_ is the name of that _remote_. The default would be _origin_, but that
67  might lead to confusion because we'll add _upstream_ in a moment, so there
68  will be two remotes. If you have the same distinct name for all your forks,
69  your life will be considerably easier. You might also call it the same as
70  your user name (_kilroy_) here. Just make sure you use the same one for all
71  your repos.
72
73  You now have an entry like this in your `.git/config` file in that newly
74  cloned repo:
75
76      [remote "mine"]
77              url = git@github.com:kilroy/qdirstat.git
78              fetch = +refs/heads/*:refs/remotes/kilroy/*
79
80- Add the original repo (_upstream_) as another _remote_ so you can pull /
81  fetch from there to keep your fork up to date:
82
83      git remote add upstream git@github.com:shundhammer/qdirstat.git
84
85  You now have two _remote_ entries in your `.git/config`:
86
87      [remote "mine"]
88              url = git@github.com:kilroy/qdirstat.git
89              fetch = +refs/heads/*:refs/remotes/kilroy/*
90
91      [remote "upstream"]
92              url = git@github.com:shundhammer/qdirstat.git
93              fetch = +refs/heads/*:refs/remotes/huha/*
94
95  You can also check this with this command:
96
97      git remote -v
98
99      mine      git@github.com:kilroy/qdirstat.git (fetch)
100      mine      git@github.com:kilroy/qdirstat.git (push)
101      upstream  git@github.com:shundhammer/qdirstat.git (fetch)
102      upstream  git@github.com:shundhammer/qdirstat.git (push)
103
104  Notice there is no _origin_ as would be the default if we hadn't used
105  `-o mine` during `git clone`. If you forgot that, you can always rename a
106  remote later (this affects only your working copy, not the repo on the GitHub
107  server):
108
109      git remote rename origin mine
110
111- Make sure your user name and e-mail address are up to date and valid in your
112  `$HOME/.gitconfig`:
113
114      [user]
115          name = Kilroy Taylor
116          email = kilroy@mydomain.com
117
118  You can also use separate user names and e-mail addresses for different
119  projects; simply edit .git/config in that project and add a `[user]` section
120  there.
121
122  That name and that e-mail address will be recorded for each commit you make,
123  so this is where your karma points go and how you will be known to the
124  community. So choose that name wisely. Real names are preferred, albeit not
125  enforced.
126
127
128
129## Common Tasks
130
131### Working in Your Fork
132
133Your fork is yours. You can do there whatever you like. But if you want to
134contribute to the upstream project, you should follow some simple rules:
135
136- Keep your fork in sync with upstream as good as possible (see next section
137  about rebasing).
138
139- Work in a feature branch for everything you do. This makes your life much
140  easier when a pull request takes some time to get accepted: You can quickly
141  switch between the pull request and add some more changes there to satisfy
142  the reviewers and the next feature you might already be working on.
143
144- Prefix your branches with your user name so you can easily tell them apart
145  form any upstream branches.
146
147Example:
148
149You plan to work on a _transmogrify_ feature. So you start from _master_,
150create a branch for that and check it out:
151
152    git checkout master
153    git branch kilroy-transmogrify
154    git checkout kilroy-transmogrify
155
156Now work in that branch and commit your changes there. Don't forget to push it
157to your GitHub fork every once in a while:
158
159    git push mine kilroy-transmogrify
160
161At some point, prepare a pull request to get your changes upstream. But before
162you do that, you should rebase your branch so it is in sync with upstream
163(except for your changes, of course).
164
165
166### Rebasing (Updating Your Fork)
167
168As mentioned before, when you fork a repo at GitHub, this will not
169automatically update itself. As new commits are added to the upstream repo,
170your fork will increasingly get out of date, so you have to update it on a
171regular basis.
172
173There are two methods: `pull` and `fetch` / `rebase`. As long as you don't do
174any changes in your fork, there is no noticable difference; but when you work
175in your fork, i.e. when you commit changes there, `fetch` / `rebase` is highly
176recommended to keep the "railway yard" of parallel branches with merge and fork
177points in the `gitk` display to a minimum.
178
179First, get the data from the remote server (GitHub):
180
181    git fetch --all
182
183**Make sure to use `--all`, not `-a`** which is something different (yes, this
184is a common, stupid, unnecessary pitfall of that git command).
185
186If that command remains silent, there was no change, so everything was still up
187to date. If it reports something like
188
189    remote: Counting objects: 21, done.
190    remote: Compressing objects: 100% (21/21), done.
191    ...
192
193it did fetch some changes. Notice that the changes are only in the `.git/`
194subdirectory so far; they are not applied to your source tree yet.
195
196Now **make sure you don't have any pending changes** anymore. Check with
197
198    git status
199
200If it reports any pending changes, you can choose to commit them or to _stash_
201them, i.e. put them into temporary storage:
202
203    git stash
204
205you can later retrieve them with
206
207    git stash pop
208
209Now rebase. Typically, you want to do that based on the _master_ branch of
210_upstream_:
211
212    git rebase upstream/master
213
214This basically checks where you branched off your working copy, then
215temporarily takes away your commits from that point on, then applies the
216commits from upstream that have accumulated in the meantime. As a last step, it
217tries to apply your commits on top of all that.
218
219Since git commits are basically little more than patches (diffs) on top of
220patches, this may or may not work flawlessly. If you are lucky, your commits
221still apply cleanly, and you are set: You successfully rebased your repo.
222
223If any of your commits does not apply cleanly, you will have to resolve merge
224conflicts and afterwards call
225
226    git rebase --continue
227
228to get to the next commit.
229
230When all is done, you can push the result to your fork. Since the rebase caused
231the parent SHAs of your commits to change, you will need to force-push; this is
232normal and expected.
233
234    git push -f mine master
235
236or
237
238    git push -f mine branch-name
239
240if you were working in a branch.
241
242
243### Preparing a Pull Request for Upstream
244
245When you have some changes you would like to get upstream (to contribute to the
246upstream project), you create a _Pull Request_.
247
248To do that, make sure those changes are in a separate branch. If you worked on
249a separate feature branch like recommended earlier in this document, you can
250simply use that one as the branch for the pull request.
251
252But remember to stop working on new features in that branch. As soon as you use
253a branch for a pull request, you only commit changes there that were requested
254by the reviewers.
255
256Before creating a pull request, rebase your branch against upstream/master once
257more and make sure to push your changes (even the latest ones) to your fork:
258
259    git fetch --all
260    git rebase upstream/master
261    git push mine kilroy-transmogrify
262
263After that, go to your fork in the GitHub web UI, select your branch and click
264"New Pull Request". Fill the form with a meaningful description of your changes
265and send it off. Now you will have to wait for feedback from the upstream
266project owner.
267
268In the meantime, you will probably want to continue working on more
269things. Remember to leave the pull request branch alone during that time;
270create a new one for your next changes. It is perfectly okay to base that new
271branch on the last one that has now become a pull request:
272
273    git branch kilroy-hyperforble
274    git checkout kilroy-hyperforble
275    ...(work in that branch...)
276
277When you get feedback about your pull request from your reviewers, you might
278have to add some more changes to the pull request branch. So switch to that
279branch (stash or commit any pending changes to your new working branch during
280that time):
281
282    git checkout kilroy-transmogrify
283    ...(add requested fixes)...
284    git commit -am "Added code review changes"
285    git push mine kilroy-transmogrify
286
287Remember that despite the fact that your branch has become a pull request, it
288is still hosted in your fork (_mine_) rather than upstream, so you still have
289to push to your fork, not to upstream (which you probably can't anyway because
290of insufficient permissions).
291
292After that, switch back to your working branch and continue working there:
293
294    git checkout kilroy-hyperforble
295    git stash pop      # if you stashed any changes
296
297
298### Updating Your Fork After Your PR is Merged
299
300Remember that after your pull request has been merged, _upstream/master_ has
301changed, so make sure to fetch and rebase:
302
303    git fetch --all
304    git checkout master
305    git rebase upstream/master
306
307There should be no conflicts (provided you are only working in branches - which
308you should).
309
310Don't forget to push the new master to your fork, too:
311
312    git push mine master
313
314No `-f` or `--force` needed here either if you only work in branches.
315
316
317## Further Reading
318
319https://guides.github.com/activities/contributing-to-open-source/
320
321https://guides.github.com/
322
323https://www.atlassian.com/git/tutorials/merging-vs-rebasing
324
325https://www.udacity.com/course/how-to-use-git-and-github--ud775
326
327