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