1.. _development-workflow: 2 3#################### 4Development workflow 5#################### 6 7You already have your own forked copy of the dipy_ repository, by 8following :ref:`forking`. You have :ref:`set-up-fork`. You have configured 9git by following :ref:`configure-git`. Now you are ready for some real work. 10 11Workflow summary 12================ 13 14In what follows we'll refer to the upstream dipy ``master`` branch, as 15"trunk". 16 17* Don't use your ``master`` branch for anything. Consider deleting it. 18* When you are starting a new set of changes, fetch any changes from trunk, 19 and start a new *feature branch* from that. 20* Make a new branch for each separable set of changes |emdash| "one task, one 21 branch" (`ipython git workflow`_). 22* Name your branch for the purpose of the changes - e.g. 23 ``bugfix-for-issue-14`` or ``refactor-database-code``. 24* If you can possibly avoid it, avoid merging trunk or any other branches into 25 your feature branch while you are working. 26* If you do find yourself merging from trunk, consider :ref:`rebase-on-trunk` 27* Ask on the `DIPY mailing list`_ if you get stuck. 28* Ask for code review! 29 30This way of working helps to keep work well organized, with readable history. 31This in turn makes it easier for project maintainers (that might be you) to see 32what you've done, and why you did it. 33 34See `linux git workflow`_ and `ipython git workflow`_ for some explanation. 35 36Consider deleting your master branch 37==================================== 38 39It may sound strange, but deleting your own ``master`` branch can help reduce 40confusion about which branch you are on. See `deleting master on github`_ for 41details. 42 43.. _update-mirror-trunk: 44 45Update the mirror of trunk 46========================== 47 48First make sure you have done :ref:`linking-to-upstream`. 49 50From time to time you should fetch the upstream (trunk) changes from github:: 51 52 git fetch upstream 53 54This will pull down any commits you don't have, and set the remote branches to 55point to the right commit. For example, 'trunk' is the branch referred to by 56(remote/branchname) ``upstream/master`` - and if there have been commits since 57you last checked, ``upstream/master`` will change after you do the fetch. 58 59.. _make-feature-branch: 60 61Make a new feature branch 62========================= 63 64When you are ready to make some changes to the code, you should start a new 65branch. Branches that are for a collection of related edits are often called 66'feature branches'. 67 68Making an new branch for each set of related changes will make it easier for 69someone reviewing your branch to see what you are doing. 70 71Choose an informative name for the branch to remind yourself and the rest of us 72what the changes in the branch are for. For example ``add-ability-to-fly``, or 73``bugfix-for-issue-42``. 74 75:: 76 77 # Update the mirror of trunk 78 git fetch upstream 79 # Make new feature branch starting at current trunk 80 git branch my-new-feature upstream/master 81 git checkout my-new-feature 82 83Generally, you will want to keep your feature branches on your public github_ 84fork of dipy_. To do this, you `git push`_ this new branch up to your 85github repo. Generally (if you followed the instructions in these pages, and by 86default), git will have a link to your github repo, called ``origin``. You push 87up to your own repo on github with:: 88 89 git push origin my-new-feature 90 91In git >= 1.7 you can ensure that the link is correctly set by using the 92``--set-upstream`` option:: 93 94 git push --set-upstream origin my-new-feature 95 96From now on git will know that ``my-new-feature`` is related to the 97``my-new-feature`` branch in the github repo. 98 99.. _edit-flow: 100 101The editing workflow 102==================== 103 104Overview 105-------- 106 107:: 108 109 # hack hack 110 git add my_new_file 111 git commit -am 'NF - some message' 112 git push 113 114In more detail 115-------------- 116 117#. Make some changes 118#. See which files have changed with ``git status`` (see `git status`_). 119 You'll see a listing like this one:: 120 121 # On branch ny-new-feature 122 # Changed but not updated: 123 # (use "git add <file>..." to update what will be committed) 124 # (use "git checkout -- <file>..." to discard changes in working directory) 125 # 126 # modified: README 127 # 128 # Untracked files: 129 # (use "git add <file>..." to include in what will be committed) 130 # 131 # INSTALL 132 no changes added to commit (use "git add" and/or "git commit -a") 133 134#. Check what the actual changes are with ``git diff`` (`git diff`_). 135#. Add any new files to version control ``git add new_file_name`` (see 136 `git add`_). 137#. To commit all modified files into the local copy of your repo,, do 138 ``git commit -am 'A commit message'``. Note the ``-am`` options to 139 ``commit``. The ``m`` flag just signals that you're going to type a 140 message on the command line. The ``a`` flag |emdash| you can just take on 141 faith |emdash| or see `why the -a flag?`_ |emdash| and the helpful use-case 142 description in the `tangled working copy problem`_. The `git commit`_ manual 143 page might also be useful. 144#. To push the changes up to your forked repo on github, do a ``git 145 push`` (see `git push`_). 146 147Ask for your changes to be reviewed or merged 148============================================= 149 150When you are ready to ask for someone to review your code and consider a merge: 151 152#. Go to the URL of your forked repo, say 153 ``http://github.com/your-user-name/dipy``. 154#. Use the 'Branch' dropdown menu near the top left of the page to 155 select the branch with your changes: 156 157 .. image:: branch_dropdown.png 158 159#. Click on the 'New pull request' button near the 'Branch' dropdown. 160 161 Enter a title for the set of changes, and some explanation of what you've 162 done. Say if there is anything you'd like particular attention for - like a 163 complicated change or some code you are not happy with. 164 165 If you don't think your request is ready to be merged, just say so in your 166 pull request message. This is still a good way of getting some preliminary 167 code review. 168 169Some other things you might want to do 170====================================== 171 172Delete a branch on github 173------------------------- 174 175:: 176 177 git checkout master 178 # delete branch locally 179 git branch -D my-unwanted-branch 180 # delete branch on github 181 git push origin :my-unwanted-branch 182 183(Note the colon ``:`` before ``test-branch``. See also: `remove remote branch`_. 184 185Several people sharing a single repository 186------------------------------------------ 187 188If you want to work on some stuff with other people, where you are all 189committing into the same repository, or even the same branch, then just 190share it via github. 191 192First fork dipy into your account, as from :ref:`forking`. 193 194Then, go to your forked repository github page, say 195``http://github.com/your-user-name/dipy`` 196 197Click on the 'Settings' on the right, then 'Collaborators' on the left, and add anyone else to the repo as a 198collaborator: 199 200 .. image:: collaborators.png 201 202Now all those people can do:: 203 204 git clone git@githhub.com:your-user-name/dipy.git 205 206Remember that links starting with ``git@`` use the ssh protocol and are 207read-write; links starting with ``git://`` are read-only. 208 209Your collaborators can then commit directly into that repo with the 210usual:: 211 212 git commit -am 'ENH - much better code' 213 git push origin master # pushes directly into your repo 214 215Explore your repository 216----------------------- 217 218To see a graphical representation of the repository branches and 219commits:: 220 221 gitk --all 222 223To see a linear list of commits for this branch:: 224 225 git log 226 227You can also look at the `network graph visualizer`_ for your github 228repo. 229 230Finally the :ref:`fancy-log` ``lg`` alias will give you a reasonable text-based 231graph of the repository. 232 233.. _rebase-on-trunk: 234 235Rebasing on trunk 236----------------- 237 238Let's say you thought of some work you'd like to do. You 239:ref:`update-mirror-trunk` and :ref:`make-feature-branch` called 240``cool-feature``. At this stage trunk is at some commit, let's call it E. Now 241you make some new commits on your ``cool-feature`` branch, let's call them A, B, 242C. Maybe your changes take a while, or you come back to them after a while. In 243the meantime, trunk has progressed from commit E to commit (say) G:: 244 245 A---B---C cool-feature 246 / 247 D---E---F---G trunk 248 249At this stage you consider merging trunk into your feature branch, and you 250remember that this here page sternly advises you not to do that, because the 251history will get messy. Most of the time you can just ask for a review, and not 252worry that trunk has got a little ahead. But sometimes, the changes in trunk 253might affect your changes, and you need to harmonize them. In this situation 254you may prefer to do a rebase. 255 256rebase takes your changes (A, B, C) and replays them as if they had been made to 257the current state of ``trunk``. In other words, in this case, it takes the 258changes represented by A, B, C and replays them on top of G. After the rebase, 259your history will look like this:: 260 261 A'--B'--C' cool-feature 262 / 263 D---E---F---G trunk 264 265See `rebase without tears`_ for more detail. 266 267To do a rebase on trunk:: 268 269 # Update the mirror of trunk 270 git fetch upstream 271 # go to the feature branch 272 git checkout cool-feature 273 # make a backup in case you mess up 274 git branch tmp cool-feature 275 # rebase cool-feature onto trunk 276 git rebase --onto upstream/master upstream/master cool-feature 277 278In this situation, where you are already on branch ``cool-feature``, the last 279command can be written more succinctly as:: 280 281 git rebase upstream/master 282 283When all looks good you can delete your backup branch:: 284 285 git branch -D tmp 286 287If it doesn't look good you may need to have a look at 288:ref:`recovering-from-mess-up`. 289 290If you have made changes to files that have also changed in trunk, this may 291generate merge conflicts that you need to resolve - see the `git rebase`_ man 292page for some instructions at the end of the "Description" section. There is 293some related help on merging in the git user manual - see `resolving a merge`_. 294 295.. _recovering-from-mess-up: 296 297Recovering from mess-ups 298------------------------ 299 300Sometimes, you mess up merges or rebases. Luckily, in git it is 301relatively straightforward to recover from such mistakes. 302 303If you mess up during a rebase:: 304 305 git rebase --abort 306 307If you notice you messed up after the rebase:: 308 309 # reset branch back to the saved point 310 git reset --hard tmp 311 312If you forgot to make a backup branch:: 313 314 # look at the reflog of the branch 315 git reflog show cool-feature 316 317 8630830 cool-feature@{0}: commit: BUG: io: close file handles immediately 318 278dd2a cool-feature@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d 319 26aa21a cool-feature@{2}: commit: BUG: lib: make seek_gzip_factory not leak gzip obj 320 ... 321 322 # reset the branch to where it was before the botched rebase 323 git reset --hard cool-feature@{2} 324 325.. _rewriting-commit-history: 326 327Rewriting commit history 328------------------------ 329 330.. note:: 331 332 Do this only for your own feature branches. 333 334There's an embarassing typo in a commit you made? Or perhaps the you 335made several false starts you would like the posterity not to see. 336 337This can be done via *interactive rebasing*. 338 339Suppose that the commit history looks like this:: 340 341 git log --oneline 342 eadc391 Fix some remaining bugs 343 a815645 Modify it so that it works 344 2dec1ac Fix a few bugs + disable 345 13d7934 First implementation 346 6ad92e5 * masked is now an instance of a new object, MaskedConstant 347 29001ed Add pre-nep for a copule of structured_array_extensions. 348 ... 349 350and ``6ad92e5`` is the last commit in the ``cool-feature`` branch. Suppose we 351want to make the following changes: 352 353* Rewrite the commit message for ``13d7934`` to something more sensible. 354* Combine the commits ``2dec1ac``, ``a815645``, ``eadc391`` into a single one. 355 356We do as follows:: 357 358 # make a backup of the current state 359 git branch tmp HEAD 360 # interactive rebase 361 git rebase -i 6ad92e5 362 363This will open an editor with the following text in it:: 364 365 pick 13d7934 First implementation 366 pick 2dec1ac Fix a few bugs + disable 367 pick a815645 Modify it so that it works 368 pick eadc391 Fix some remaining bugs 369 370 # Rebase 6ad92e5..eadc391 onto 6ad92e5 371 # 372 # Commands: 373 # p, pick = use commit 374 # r, reword = use commit, but edit the commit message 375 # e, edit = use commit, but stop for amending 376 # s, squash = use commit, but meld into previous commit 377 # f, fixup = like "squash", but discard this commit's log message 378 # 379 # If you remove a line here THAT COMMIT WILL BE LOST. 380 # However, if you remove everything, the rebase will be aborted. 381 # 382 383To achieve what we want, we will make the following changes to it:: 384 385 r 13d7934 First implementation 386 pick 2dec1ac Fix a few bugs + disable 387 f a815645 Modify it so that it works 388 f eadc391 Fix some remaining bugs 389 390This means that (i) we want to edit the commit message for 391``13d7934``, and (ii) collapse the last three commits into one. Now we 392save and quit the editor. 393 394Git will then immediately bring up an editor for editing the commit 395message. After revising it, we get the output:: 396 397 [detached HEAD 721fc64] FOO: First implementation 398 2 files changed, 199 insertions(+), 66 deletions(-) 399 [detached HEAD 0f22701] Fix a few bugs + disable 400 1 files changed, 79 insertions(+), 61 deletions(-) 401 Successfully rebased and updated refs/heads/my-feature-branch. 402 403and the history looks now like this:: 404 405 0f22701 Fix a few bugs + disable 406 721fc64 ENH: Sophisticated feature 407 6ad92e5 * masked is now an instance of a new object, MaskedConstant 408 409If it went wrong, recovery is again possible as explained :ref:`above 410<recovering-from-mess-up>`. 411 412.. include:: links.inc 413