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