1:orphan:
2
3.. _additional-git:
4
5Some other things you might want to do
6**************************************
7
8Delete a branch on GitHub
9=========================
10
11`git`_ strongly encourages making a new branch each time you make a change in the
12code. At some point you will need to clean up the branches you no longer need--
13that point is *after* your changes have been accepted if you made a pull request
14for those changes.
15
16There are two places to delete the branch: in your local repo and on GitHub.
17
18You can do these independent of each other.
19
20To delete both your local copy AND the GitHub copy from the command line follow
21these instructions::
22
23   # change to the main branch (if you still have one, otherwise change to
24   # another branch)
25   git checkout main
26
27   # delete branch locally
28   # Note: -d tells git to check whether your branch has been merged somewhere
29   # if it hasn't, and you delete it, it is gone forever.
30   #
31   # Use -D instead to force deletion regardless of merge status
32   git branch -d my-unwanted-branch
33
34   # delete branch on GitHub
35   git push origin :my-unwanted-branch
36
37(Note the colon ``:`` before ``test-branch``.) See `Github's instructions for
38deleting a branch
39<https://help.github.com/en/articles/creating-and-deleting-branches-within-your-repository>`_
40if you want to delete the GitHub copy through GitHub.
41
42Several people sharing a single repository
43==========================================
44
45If you want to work on some stuff with other people, where you are all
46committing into the same repository, or even the same branch, then just
47share it via GitHub.
48
49First fork Astropy into your account, as from :ref:`fork_a_copy`.
50
51Then, go to your forked repository GitHub page, e.g.,
52``https://github.com/your-user-name/astropy``
53
54Click on the 'Admin' button, and add anyone else to the repo as a
55collaborator:
56
57   .. image:: pull_button.png
58
59Now all those people can do::
60
61    git clone --recursive git@githhub.com:your-user-name/astropy.git
62
63Remember that links starting with ``git@`` use the ssh protocol and are
64read-write; links starting with ``git://`` are read-only.
65
66Your collaborators can then commit directly into that repo with the
67usual::
68
69     git commit -am 'ENH - much better code'
70     git push origin main # pushes directly into your repo
71
72Explore your repository
73=======================
74
75To see a graphical representation of the repository branches and
76commits::
77
78   gitk --all
79
80To see a linear list of commits for this branch::
81
82   git log
83
84You can also look at the `network graph visualizer`_ for your GitHub
85repo.
86
87.. _rebase-on-trunk:
88
89Rebasing on trunk
90=================
91
92Let's say you thought of some work you'd like to do. You
93:ref:`fetch-latest` and :ref:`make-feature-branch` called
94``cool-feature``. At this stage trunk is at some commit, let's call it E. Now
95you make some new commits on your ``cool-feature`` branch, let's call them A,
96B, C. Maybe your changes take a while, or you come back to them after a while.
97In the meantime, trunk has progressed from commit E to commit (say) G::
98
99          A---B---C cool-feature
100         /
101    D---E---F---G trunk
102
103At this stage you consider merging trunk into your feature branch, and you
104remember that this here page sternly advises you not to do that, because the
105history will get messy. Most of the time you can just ask for a review, and
106not worry that trunk has got a little ahead. But sometimes, the changes in
107trunk might affect your changes, and you need to harmonize them. In this
108situation you may prefer to do a rebase.
109
110Rebase takes your changes (A, B, C) and replays them as if they had been made
111to the current state of ``trunk``. In other words, in this case, it takes the
112changes represented by A, B, C and replays them on top of G. After the rebase,
113your history will look like this::
114
115                  A'--B'--C' cool-feature
116                 /
117    D---E---F---G trunk
118
119See `rebase without tears`_ for more detail.
120
121To do a rebase on trunk::
122
123    # Update the mirror of trunk
124    git fetch upstream
125
126    # Go to the feature branch
127    git checkout cool-feature
128
129    # Make a backup in case you mess up
130    git branch tmp cool-feature
131
132    # Rebase cool-feature onto trunk
133    git rebase --onto upstream/main upstream/main cool-feature
134
135In this situation, where you are already on branch ``cool-feature``, the last
136command can be written more succinctly as::
137
138    git rebase upstream/main
139
140When all looks good you can delete your backup branch::
141
142   git branch -D tmp
143
144If it doesn't look good you may need to have a look at
145:ref:`recovering-from-mess-up`.
146
147If you have made changes to files that have also changed in trunk, this may
148generate merge conflicts that you need to resolve - see the `git rebase`_ man
149page for some instructions at the end of the "Description" section. There is
150some related help on merging in the git user manual - see `resolving a
151merge`_.
152
153If your feature branch is already on GitHub and you rebase, you will have to
154force push the branch; a normal push would give an error. If the branch you
155rebased is called ``cool-feature`` and your GitHub fork is available as the
156remote called ``origin``, you use this command to force-push::
157
158   git push -f origin cool-feature
159
160Note that this will overwrite the branch on GitHub, i.e. this is one of the few
161ways you can actually lose commits with git. Also note that it is never allowed
162to force push to the main astropy repo (typically called ``upstream``), because
163this would re-write commit history and thus cause problems for all others.
164
165.. _recovering-from-mess-up:
166
167Recovering from mess-ups
168========================
169
170Sometimes, you mess up merges or rebases. Luckily, in git it is relatively
171straightforward to recover from such mistakes.
172
173If you mess up during a rebase::
174
175   git rebase --abort
176
177If you notice you messed up after the rebase::
178
179   # Reset branch back to the saved point
180   git reset --hard tmp
181
182If you forgot to make a backup branch::
183
184   # Look at the reflog of the branch
185   git reflog show cool-feature
186
187   8630830 cool-feature@{0}: commit: BUG: io: close file handles immediately
188   278dd2a cool-feature@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d
189   26aa21a cool-feature@{2}: commit: BUG: lib: make seek_gzip_factory not leak gzip obj
190   ...
191
192   # Reset the branch to where it was before the botched rebase
193   git reset --hard cool-feature@{2}
194
195.. _rewriting-commit-history:
196
197Rewriting commit history
198========================
199
200.. note::
201
202   Do this only for your own feature branches.
203
204There's an embarrassing typo in a commit you made? Or perhaps the you
205made several false starts you would like the posterity not to see.
206
207This can be done via *interactive rebasing*.
208
209Suppose that the commit history looks like this::
210
211    git log --oneline
212    eadc391 Fix some remaining bugs
213    a815645 Modify it so that it works
214    2dec1ac Fix a few bugs + disable
215    13d7934 First implementation
216    6ad92e5 * masked is now an instance of a new object, MaskedConstant
217    29001ed Add pre-nep for a couple of structured_array_extensions.
218    ...
219
220and ``6ad92e5`` is the last commit in the ``cool-feature`` branch. Suppose we
221want to make the following changes:
222
223* Rewrite the commit message for ``13d7934`` to something more sensible.
224* Combine the commits ``2dec1ac``, ``a815645``, ``eadc391`` into a single one.
225
226We do as follows::
227
228    # make a backup of the current state
229    git branch tmp HEAD
230    # interactive rebase
231    git rebase -i 6ad92e5
232
233This will open an editor with the following text in it::
234
235    pick 13d7934 First implementation
236    pick 2dec1ac Fix a few bugs + disable
237    pick a815645 Modify it so that it works
238    pick eadc391 Fix some remaining bugs
239
240    # Rebase 6ad92e5..eadc391 onto 6ad92e5
241    #
242    # Commands:
243    #  p, pick = use commit
244    #  r, reword = use commit, but edit the commit message
245    #  e, edit = use commit, but stop for amending
246    #  s, squash = use commit, but meld into previous commit
247    #  f, fixup = like "squash", but discard this commit's log message
248    #
249    # If you remove a line here THAT COMMIT WILL BE LOST.
250    # However, if you remove everything, the rebase will be aborted.
251    #
252
253To achieve what we want, we will make the following changes to it::
254
255    r 13d7934 First implementation
256    pick 2dec1ac Fix a few bugs + disable
257    f a815645 Modify it so that it works
258    f eadc391 Fix some remaining bugs
259
260This means that (i) we want to edit the commit message for ``13d7934``, and
261(ii) collapse the last three commits into one. Now we save and quit the
262editor.
263
264Git will then immediately bring up an editor for editing the commit message.
265After revising it, we get the output::
266
267    [detached HEAD 721fc64] FOO: First implementation
268     2 files changed, 199 insertions(+), 66 deletions(-)
269    [detached HEAD 0f22701] Fix a few bugs + disable
270     1 files changed, 79 insertions(+), 61 deletions(-)
271    Successfully rebased and updated refs/heads/my-feature-branch.
272
273and the history looks now like this::
274
275     0f22701 Fix a few bugs + disable
276     721fc64 ENH: Sophisticated feature
277     6ad92e5 * masked is now an instance of a new object, MaskedConstant
278
279If it went wrong, recovery is again possible as explained :ref:`above
280<recovering-from-mess-up>`.
281
282.. _merge-commits-and-cherry-picks:
283
284Merge commits and cherry picks
285==============================
286
287Let's say that you have a fork (origin) on GitHub of the main Astropy
288repository (upstream).  Your fork is up to date with upstream's main branch
289and you've made some commits branching off from it on your own branch::
290
291    upstream:
292
293       main
294          |
295    A--B--C
296
297    origin:
298
299     upstream/main
300          |
301    A--B--C
302           \
303            D--E
304               |
305           issue-branch
306
307Then say you make a pull request of issue-branch against Astroy's main, and
308the pull request is accepted and merged.  When GitHub merges the pull request
309it's basically doing the following in the upstream repository::
310
311    $ git checkout main
312    $ git remote add yourfork file:///path/to/your/fork/astropy
313    $ git fetch yourfork
314    $ git merge --no-ff yourfork/issue-branch
315
316
317Because it always uses ``--no-ff`` we always get a merge commit (it is possible
318to manually do a fast-forward merge of a pull request, but we rarely ever do
319that).  Now the main Astropy repository looks like this::
320
321
322    upstream:
323
324              main
325                 |
326    A--B--C------F
327           \    /
328            D--E
329               |
330        yourfork/issue-branch
331
332where "F" is the merge commit GitHub just made in upstream.
333
334When you do cherry-pick of a non-merge commit, say you want to just cherry-pick
335"D" from the branch, what happens is it does a diff of "D" with its parent (in
336this case "C") and applies that diff as a patch to whatever your HEAD is.
337
338The problem with a merge commit, such as "F", is that "F" has two parents: "C"
339and "E".  It doesn't know whether to apply the diff of "F" with "C" or the diff
340of "F" with "E".  Clearly in this case of backporting a pull request to a bug
341fix branch we want to apply everything that changed on main from the merge,
342so we want the diff of "F" with "C".
343
344Since GitHub was on ``main`` when it did ``git merge yourfork/issue-branch``, the
345last commit in ``main`` is the first parent.  Basically whatever HEAD you're on
346when you do the merge is the first parent, and the tip you're merging from is
347the second parent (octopus merge gets more complicated but only a little, and
348that doesn't apply to pull requests).  Since parents are numbered starting from
349"1" then we will always cherry-pick merge commits with ``-m 1`` in this case.
350
351That's not to say that the cherry-pick will always apply cleanly.  Say in
352upstream we also have a backport branch that we want to cherry pick "F" onto::
353
354    upstream:
355
356      backport
357         |
358         G       main
359        /          |
360    A--B----C------F
361             \    /
362              D--E
363
364We would do::
365
366    $ git checkout backport
367    $ git cherry-pick -m 1 F
368
369But this applies the diff of "F" with "C", not of "F" with "G".  So clearly
370there's potential for conflicts and incongruity here.  But this will work like
371any merge that has conflicts--you can resolve any conflicts manually and then
372commit.  As long as the fix being merged is reasonably self-contained this
373usually requires little effort.
374
375.. include:: links.inc
376