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