├── .gitignore ├── LICENSE ├── README.md ├── git-intro.ipynb └── images ├── HEAD_testing.png ├── branchcommit.png ├── commit_anatomy.png ├── masterbranch.png ├── mergeaftermath.png ├── mergescenario.png └── threecommits.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | 59 | 60 | # Python 61 | .ipynb_checkpoints -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Jake Vanderplas 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of git-intro nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # git-intro 2 | Git/Github Intro 3 | -------------------------------------------------------------------------------- /git-intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "slideshow": { 7 | "slide_type": "slide" 8 | } 9 | }, 10 | "source": [ 11 | "# Version control for fun and profit:\n", 12 | "\n", 13 | "## Git: the tool you didn't know you needed\n", 14 | "\n", 15 | "#### Sources of this material:\n", 16 | "\n", 17 | "This tutorial is adapted from \n", 18 | "[\"Version Control for Fun and Profit\"](http://nbviewer.ipython.org/urls/github.com/fperez/reprosw/raw/master/Version%2520Control.ipynb) by Fernando Perez\n", 19 | "\n", 20 | "For an excellent list of Git resources for scientists, see [Fernando's Page](http://www.fperez.org/py4science/git.html).\n", 21 | "\n", 22 | "Fernando's original notebook specifically mentions two references he drew from:\n", 23 | "\n", 24 | "- [\"Git for Scientists: A Tutorial\"](http://nyuccl.org/pages/GitTutorial) by John McDonnell \n", 25 | "- Emanuele Olivetti's lecture notes and exercises from the G-Node summer school on [Advanced Scientific Programming in Python](https://python.g-node.org/wiki/schedule).\n", 26 | "\n", 27 | "Via Fernando, some of the images below are copied from the [Pro Git book](http://git-scm.com/book)\n", 28 | "\n", 29 | "Also see [J.R. Johansson](https://github.com/jrjohansson)'s [tutorial on version control](http://nbviewer.ipython.org/urls/raw.github.com/jrjohansson/scientific-python-lectures/master/Lecture-7-Revision-Control-Software.ipynb), part of his excellent series [Lectures on Scientific Computing with Python](https://github.com/jrjohansson/scientific-python-lectures)" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": { 35 | "slideshow": { 36 | "slide_type": "slide" 37 | } 38 | }, 39 | "source": [ 40 | "## What is Version Control?\n", 41 | "\n", 42 | "#### From Wikipedia:\n", 43 | "“Revision control, also known as version control, source control\n", 44 | "or software configuration management (SCM), is the\n", 45 | "**management of changes to documents, programs, and other information stored as computer files.**”\n", 46 | "\n", 47 | "#### Reproducibility?\n", 48 | "\n", 49 | "* Tracking and recreating every step of your work\n", 50 | "* In the software world: it's called *Version Control*!\n", 51 | "\n", 52 | "What do (good) version control tools give you?\n", 53 | "\n", 54 | "* Peace of mind (backups)\n", 55 | "* Freedom (exploratory branching)\n", 56 | "* Collaboration (synchronization)\n" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": { 62 | "slideshow": { 63 | "slide_type": "slide" 64 | } 65 | }, 66 | "source": [ 67 | "## Git is an enabling technology: Use version control for everything\n", 68 | "* Paper writing (never get ``paper_v5_jake_final_oct22_9.tex``\n", 69 | " by email again!)\n", 70 | "* Grant writing\n", 71 | "* Everyday research\n", 72 | "* Teaching (never accept an emailed homework assignment again!)\n", 73 | "* Code management\n", 74 | "* Personal website history tracking" 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": { 80 | "slideshow": { 81 | "slide_type": "slide" 82 | } 83 | }, 84 | "source": [ 85 | "## The plan for this tutorial\n", 86 | "\n", 87 | "- Overview of Git key concepts\n", 88 | "\n", 89 | "- Hands-on work with Git\n", 90 | "\n", 91 | "- 5 \"stages\" of using Git:\n", 92 | " \n", 93 | " 1. Local, single-user, linear workflow\n", 94 | " 2. Single local user, branching\n", 95 | " 3. Using remotes as a single user\n", 96 | " 4. Remotes for collaborating in a small team\n", 97 | " 5. Full-contact github: distributed collaboration with large teams" 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": { 103 | "slideshow": { 104 | "slide_type": "slide" 105 | } 106 | }, 107 | "source": [ 108 | "## High level picture: overview of key concepts\n", 109 | "\n", 110 | "The **commit**: *a snapshot of work at a point in time*\n", 111 | "\n", 112 | "![](files/images/commit_anatomy.png)\n", 113 | "\n", 114 | "Credit: ProGit book, by Scott Chacon, CC License." 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": { 120 | "slideshow": { 121 | "slide_type": "slide" 122 | } 123 | }, 124 | "source": [ 125 | "### Looking at my current directory:" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 1, 131 | "metadata": { 132 | "collapsed": false, 133 | "slideshow": { 134 | "slide_type": "fragment" 135 | } 136 | }, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "00_intro.ipynb myfile.html\r\n", 143 | "01_basic_training.ipynb myfile.py\r\n", 144 | "02_advanced_data_structures.ipynb myfile.pyc\r\n", 145 | "03_IPython_intro.ipynb mymodule.py\r\n", 146 | "04_Functions_and_modules.ipynb mymodule.pyc\r\n", 147 | "05_NumpyIntro.ipynb mymodule2.py\r\n", 148 | "05_Trapezoid_Solution.ipynb mymodule2.pyc\r\n", 149 | "06_Denoise_Solution.ipynb number_game.py\r\n", 150 | "06_MatplotlibIntro.ipynb style.css\r\n", 151 | "07_GitIntro.ipynb test.npy\r\n", 152 | "README.txt test.npz\r\n", 153 | "\u001b[34mimages\u001b[m\u001b[m test.out\r\n", 154 | "modfun.py tmp.py~\r\n" 155 | ] 156 | } 157 | ], 158 | "source": [ 159 | "!ls" 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": { 165 | "slideshow": { 166 | "slide_type": "slide" 167 | } 168 | }, 169 | "source": [ 170 | "A **repository**: a group of *linked* commits\n", 171 | "\n", 172 | "![](files/images/threecommits.png)\n", 173 | "\n", 174 | "Note: these form a Directed Acyclic Graph (DAG), with nodes identified by their *hash*." 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": { 180 | "slideshow": { 181 | "slide_type": "slide" 182 | } 183 | }, 184 | "source": [ 185 | "A **hash**: a fingerprint of the content of each commit *and its parent*" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": 2, 191 | "metadata": { 192 | "collapsed": false, 193 | "slideshow": { 194 | "slide_type": "fragment" 195 | } 196 | }, 197 | "outputs": [ 198 | { 199 | "name": "stdout", 200 | "output_type": "stream", 201 | "text": [ 202 | "Hash: 7bb695b77966e27cfaebfa59e27a0b91f1d33813\n" 203 | ] 204 | } 205 | ], 206 | "source": [ 207 | "import sha\n", 208 | "\n", 209 | "# Our first commit\n", 210 | "data1 = 'This is the start of my paper2.'\n", 211 | "meta1 = 'date: 1/1/12'\n", 212 | "hash1 = sha.sha(data1 + meta1).hexdigest()\n", 213 | "print('Hash:', hash1)" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 3, 219 | "metadata": { 220 | "collapsed": false, 221 | "slideshow": { 222 | "slide_type": "fragment" 223 | } 224 | }, 225 | "outputs": [ 226 | { 227 | "name": "stdout", 228 | "output_type": "stream", 229 | "text": [ 230 | "Hash: 543da8bac9f643ba5611897b192a16dea42d2ab7\n" 231 | ] 232 | } 233 | ], 234 | "source": [ 235 | "# Our second commit, linked to the first\n", 236 | "data2 = 'Some more text in my paper...'\n", 237 | "meta2 = 'date: 1/2/12'\n", 238 | "# Note we add the parent hash here!\n", 239 | "hash2 = sha.sha(data2 + meta2 + hash1).hexdigest()\n", 240 | "print('Hash:', hash2)" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "metadata": { 246 | "slideshow": { 247 | "slide_type": "fragment" 248 | } 249 | }, 250 | "source": [ 251 | "And this is pretty much the essence of Git!" 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "metadata": { 257 | "slideshow": { 258 | "slide_type": "slide" 259 | } 260 | }, 261 | "source": [ 262 | "## First: Configuring Git\n", 263 | "The minimal amount of configuration for git to work without pestering you is to tell it who you are. All the commands here modify the ``.gitconfig`` file in your home\n", 264 | "directory.\n", 265 | "\n", 266 | "Modify these before running them:" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": 2, 272 | "metadata": { 273 | "collapsed": false, 274 | "slideshow": { 275 | "slide_type": "fragment" 276 | } 277 | }, 278 | "outputs": [], 279 | "source": [ 280 | "%%bash\n", 281 | "git config --global user.name \"John Doe\"\n", 282 | "git config --global user.email \"johndoe@uw.edu\"" 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "metadata": { 288 | "slideshow": { 289 | "slide_type": "slide" 290 | } 291 | }, 292 | "source": [ 293 | "### Other settings\n", 294 | "\n", 295 | "Change how you will edit text files (it will often ask you to edit messages and other information, and thus wants to know how you like to edit your files):" 296 | ] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": 3, 301 | "metadata": { 302 | "collapsed": false, 303 | "slideshow": { 304 | "slide_type": "fragment" 305 | } 306 | }, 307 | "outputs": [], 308 | "source": [ 309 | "%%bash\n", 310 | "# Put here your preferred editor. If this is not set, git will honor\n", 311 | "# the $EDITOR environment variable\n", 312 | "git config --global core.editor /usr/bin/nano # my preferred editor\n", 313 | "\n", 314 | "# On Windows Notepad will do in a pinch,\n", 315 | "# I recommend Notepad++ as a free alternative\n", 316 | "# On the mac, you can set nano or emacs as a basic option" 317 | ] 318 | }, 319 | { 320 | "cell_type": "code", 321 | "execution_count": 4, 322 | "metadata": { 323 | "collapsed": false, 324 | "slideshow": { 325 | "slide_type": "fragment" 326 | } 327 | }, 328 | "outputs": [], 329 | "source": [ 330 | "%%bash\n", 331 | "# And while we're at it, we also turn on the use of color, which is very useful\n", 332 | "git config --global color.ui \"auto\"" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": { 338 | "slideshow": { 339 | "slide_type": "slide" 340 | } 341 | }, 342 | "source": [ 343 | "### Password memory\n", 344 | "\n", 345 | "Set git to use the credential memory cache so we don't have to retype passwords too frequently. On Linux, you should run the following (note that this requires git version 1.7.10 or newer):" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": 6, 351 | "metadata": { 352 | "collapsed": false, 353 | "slideshow": { 354 | "slide_type": "fragment" 355 | } 356 | }, 357 | "outputs": [], 358 | "source": [ 359 | "%%bash \n", 360 | "git config --global credential.helper cache\n", 361 | "# Set the cache to timeout after 2 hours (setting is in seconds)\n", 362 | "git config --global credential.helper 'cache --timeout=7200'" 363 | ] 364 | }, 365 | { 366 | "cell_type": "markdown", 367 | "metadata": { 368 | "slideshow": { 369 | "slide_type": "fragment" 370 | } 371 | }, 372 | "source": [ 373 | "Github offers in its help pages instructions on how to configure the credentials helper for [Mac OSX](https://help.github.com/articles/set-up-git#platform-mac) and [Windows](https://help.github.com/articles/set-up-git#platform-windows)." 374 | ] 375 | }, 376 | { 377 | "cell_type": "markdown", 378 | "metadata": { 379 | "slideshow": { 380 | "slide_type": "slide" 381 | } 382 | }, 383 | "source": [ 384 | "## Double-checking the result:" 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "execution_count": 7, 390 | "metadata": { 391 | "collapsed": false, 392 | "slideshow": { 393 | "slide_type": "fragment" 394 | } 395 | }, 396 | "outputs": [ 397 | { 398 | "name": "stdout", 399 | "output_type": "stream", 400 | "text": [ 401 | "[user]\r\n", 402 | "\tname = Jake Vanderplas\r\n", 403 | "\temail = vanderplas@astro.washington.edu\r\n", 404 | "[core]\r\n", 405 | "\teditor = /usr/bin/nano\r\n", 406 | "[color]\r\n", 407 | "\tui = auto\r\n", 408 | "[credential]\r\n", 409 | "\thelper = cache --timeout=7200\r\n" 410 | ] 411 | } 412 | ], 413 | "source": [ 414 | "!cat ~/.gitconfig" 415 | ] 416 | }, 417 | { 418 | "cell_type": "markdown", 419 | "metadata": { 420 | "slideshow": { 421 | "slide_type": "slide" 422 | } 423 | }, 424 | "source": [ 425 | "## Stage 1: Local, single-user, linear workflow\n", 426 | "Simply type `git` to see a full list of all the 'core' commands. We'll now go through most of these via small practical exercises:" 427 | ] 428 | }, 429 | { 430 | "cell_type": "code", 431 | "execution_count": 80, 432 | "metadata": { 433 | "collapsed": false, 434 | "slideshow": { 435 | "slide_type": "fragment" 436 | } 437 | }, 438 | "outputs": [ 439 | { 440 | "name": "stdout", 441 | "output_type": "stream", 442 | "text": [ 443 | "usage: git [--version] [--exec-path[=]] [--html-path] [--man-path] [--info-path]\r\n", 444 | " [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\r\n", 445 | " [--git-dir=] [--work-tree=] [--namespace=]\r\n", 446 | " [-c name=value] [--help]\r\n", 447 | " []\r\n", 448 | "\r\n", 449 | "The most commonly used git commands are:\r\n", 450 | " add Add file contents to the index\r\n", 451 | " bisect Find by binary search the change that introduced a bug\r\n", 452 | " branch List, create, or delete branches\r\n", 453 | " checkout Checkout a branch or paths to the working tree\r\n", 454 | " clone Clone a repository into a new directory\r\n", 455 | " commit Record changes to the repository\r\n", 456 | " diff Show changes between commits, commit and working tree, etc\r\n", 457 | " fetch Download objects and refs from another repository\r\n", 458 | " grep Print lines matching a pattern\r\n", 459 | " init Create an empty git repository or reinitialize an existing one\r\n", 460 | " log Show commit logs\r\n", 461 | " merge Join two or more development histories together\r\n", 462 | " mv Move or rename a file, a directory, or a symlink\r\n", 463 | " pull Fetch from and merge with another repository or a local branch\r\n", 464 | " push Update remote refs along with associated objects\r\n", 465 | " rebase Forward-port local commits to the updated upstream head\r\n", 466 | " reset Reset current HEAD to the specified state\r\n", 467 | " rm Remove files from the working tree and from the index\r\n", 468 | " show Show various types of objects\r\n", 469 | " status Show the working tree status\r\n", 470 | " tag Create, list, delete or verify a tag object signed with GPG\r\n", 471 | "\r\n", 472 | "See 'git help ' for more information on a specific command.\r\n" 473 | ] 474 | } 475 | ], 476 | "source": [ 477 | "!git" 478 | ] 479 | }, 480 | { 481 | "cell_type": "markdown", 482 | "metadata": {}, 483 | "source": [ 484 | "### `git init`: create an empty repository" 485 | ] 486 | }, 487 | { 488 | "cell_type": "code", 489 | "execution_count": 8, 490 | "metadata": { 491 | "collapsed": false, 492 | "slideshow": { 493 | "slide_type": "fragment" 494 | } 495 | }, 496 | "outputs": [ 497 | { 498 | "name": "stdout", 499 | "output_type": "stream", 500 | "text": [ 501 | "Initialized empty Git repository in /Users/jakevdp/Opensource/2013_fall_ASTR599/notebooks/test/.git/\n" 502 | ] 503 | } 504 | ], 505 | "source": [ 506 | "%%bash\n", 507 | "rm -rf test\n", 508 | "git init test" 509 | ] 510 | }, 511 | { 512 | "cell_type": "markdown", 513 | "metadata": { 514 | "slideshow": { 515 | "slide_type": "fragment" 516 | } 517 | }, 518 | "source": [ 519 | "**Note:** all these cells below are meant to be run by you in a terminal where you change *once* to the `test` directory and continue working there.\n", 520 | "\n", 521 | "Since we are putting all of them here in a single notebook for the purposes of the tutorial, they will all be prepended with the first two lines:\n", 522 | "\n", 523 | " %%bash\n", 524 | " cd test\n", 525 | "\n", 526 | "that tell IPython to do that each time. But you should ignore those two lines and type the rest of each cell yourself in your terminal." 527 | ] 528 | }, 529 | { 530 | "cell_type": "markdown", 531 | "metadata": { 532 | "slideshow": { 533 | "slide_type": "slide" 534 | } 535 | }, 536 | "source": [ 537 | "Let's look at what git did:" 538 | ] 539 | }, 540 | { 541 | "cell_type": "code", 542 | "execution_count": 9, 543 | "metadata": { 544 | "collapsed": false, 545 | "slideshow": { 546 | "slide_type": "fragment" 547 | } 548 | }, 549 | "outputs": [], 550 | "source": [ 551 | "%%bash\n", 552 | "cd test\n", 553 | "\n", 554 | "ls" 555 | ] 556 | }, 557 | { 558 | "cell_type": "code", 559 | "execution_count": 40, 560 | "metadata": { 561 | "collapsed": false, 562 | "slideshow": { 563 | "slide_type": "fragment" 564 | } 565 | }, 566 | "outputs": [ 567 | { 568 | "name": "stdout", 569 | "output_type": "stream", 570 | "text": [ 571 | "total 12\n", 572 | "drwxr-xr-x 3 fperez wavelet 4096 Feb 14 00:57 .\n", 573 | "drwxr-xr-x 7 fperez wavelet 4096 Feb 14 00:57 ..\n", 574 | "drwxr-xr-x 7 fperez wavelet 4096 Feb 14 00:57 .git\n" 575 | ] 576 | } 577 | ], 578 | "source": [ 579 | "%%bash\n", 580 | "cd test\n", 581 | "\n", 582 | "ls -la" 583 | ] 584 | }, 585 | { 586 | "cell_type": "code", 587 | "execution_count": 41, 588 | "metadata": { 589 | "collapsed": false, 590 | "slideshow": { 591 | "slide_type": "fragment" 592 | } 593 | }, 594 | "outputs": [ 595 | { 596 | "name": "stdout", 597 | "output_type": "stream", 598 | "text": [ 599 | "total 32\n", 600 | "drwxr-xr-x 2 fperez wavelet 4096 Feb 14 00:57 branches\n", 601 | "-rw-r--r-- 1 fperez wavelet 92 Feb 14 00:57 config\n", 602 | "-rw-r--r-- 1 fperez wavelet 73 Feb 14 00:57 description\n", 603 | "-rw-r--r-- 1 fperez wavelet 23 Feb 14 00:57 HEAD\n", 604 | "drwxr-xr-x 2 fperez wavelet 4096 Feb 14 00:57 hooks\n", 605 | "drwxr-xr-x 2 fperez wavelet 4096 Feb 14 00:57 info\n", 606 | "drwxr-xr-x 4 fperez wavelet 4096 Feb 14 00:57 objects\n", 607 | "drwxr-xr-x 4 fperez wavelet 4096 Feb 14 00:57 refs\n" 608 | ] 609 | } 610 | ], 611 | "source": [ 612 | "%%bash\n", 613 | "cd test\n", 614 | "\n", 615 | "ls -l .git" 616 | ] 617 | }, 618 | { 619 | "cell_type": "markdown", 620 | "metadata": { 621 | "slideshow": { 622 | "slide_type": "slide" 623 | } 624 | }, 625 | "source": [ 626 | "Now let's edit our first file in the test directory with a text editor... I'm doing it programatically here for automation purposes, but you'd normally be editing by hand" 627 | ] 628 | }, 629 | { 630 | "cell_type": "code", 631 | "execution_count": 11, 632 | "metadata": { 633 | "collapsed": false, 634 | "slideshow": { 635 | "slide_type": "fragment" 636 | } 637 | }, 638 | "outputs": [], 639 | "source": [ 640 | "%%bash\n", 641 | "cd test\n", 642 | "\n", 643 | "echo \"My first bit of text\" > file1.txt" 644 | ] 645 | }, 646 | { 647 | "cell_type": "code", 648 | "execution_count": 13, 649 | "metadata": { 650 | "collapsed": false, 651 | "slideshow": { 652 | "slide_type": "fragment" 653 | } 654 | }, 655 | "outputs": [ 656 | { 657 | "name": "stdout", 658 | "output_type": "stream", 659 | "text": [ 660 | "total 8\n", 661 | "drwxrwxrwx 4 jakevdp staff 136 Sep 12 10:05 .\n", 662 | "drwxr-xr-x 30 jakevdp staff 1020 Sep 12 10:03 ..\n", 663 | "drwxrwxrwx 9 jakevdp staff 306 Sep 12 10:03 .git\n", 664 | "-rw-rw-rw- 1 jakevdp staff 21 Sep 12 10:05 file1.txt\n" 665 | ] 666 | } 667 | ], 668 | "source": [ 669 | "%%bash\n", 670 | "cd test\n", 671 | "\n", 672 | "ls -al" 673 | ] 674 | }, 675 | { 676 | "cell_type": "markdown", 677 | "metadata": {}, 678 | "source": [ 679 | "### `git add`: tell git about this new file" 680 | ] 681 | }, 682 | { 683 | "cell_type": "code", 684 | "execution_count": 14, 685 | "metadata": { 686 | "collapsed": false, 687 | "slideshow": { 688 | "slide_type": "fragment" 689 | } 690 | }, 691 | "outputs": [], 692 | "source": [ 693 | "%%bash\n", 694 | "cd test\n", 695 | "\n", 696 | "git add file1.txt" 697 | ] 698 | }, 699 | { 700 | "cell_type": "markdown", 701 | "metadata": { 702 | "slideshow": { 703 | "slide_type": "fragment" 704 | } 705 | }, 706 | "source": [ 707 | "We can now ask git about what happened with `status`:" 708 | ] 709 | }, 710 | { 711 | "cell_type": "code", 712 | "execution_count": 15, 713 | "metadata": { 714 | "collapsed": false, 715 | "slideshow": { 716 | "slide_type": "fragment" 717 | } 718 | }, 719 | "outputs": [ 720 | { 721 | "name": "stdout", 722 | "output_type": "stream", 723 | "text": [ 724 | "# On branch master\n", 725 | "#\n", 726 | "# Initial commit\n", 727 | "#\n", 728 | "# Changes to be committed:\n", 729 | "# (use \"git rm --cached ...\" to unstage)\n", 730 | "#\n", 731 | "#\tnew file: file1.txt\n", 732 | "#\n" 733 | ] 734 | } 735 | ], 736 | "source": [ 737 | "%%bash\n", 738 | "cd test\n", 739 | "\n", 740 | "git status" 741 | ] 742 | }, 743 | { 744 | "cell_type": "markdown", 745 | "metadata": { 746 | "slideshow": { 747 | "slide_type": "slide" 748 | } 749 | }, 750 | "source": [ 751 | "### `git commit`: permanently record our changes in git's database\n", 752 | "For now, we are *always* going to call `git commit` either with the `-a` option *or* with specific filenames (`git commit file1 file2...`).\n", 753 | "\n", 754 | "This delays the discussion of an aspect of git called the *index* (often referred to also as the 'staging area') that we will cover later. Most everyday work in regular scientific practice doesn't require understanding the extra moving parts that the index involves, so on a first round we'll bypass it. Later on we will discuss how to use it to achieve more fine-grained control of what and how git records our actions." 755 | ] 756 | }, 757 | { 758 | "cell_type": "code", 759 | "execution_count": 16, 760 | "metadata": { 761 | "collapsed": false, 762 | "slideshow": { 763 | "slide_type": "fragment" 764 | } 765 | }, 766 | "outputs": [ 767 | { 768 | "name": "stdout", 769 | "output_type": "stream", 770 | "text": [ 771 | "[master (root-commit) 609a459] This is our first commit\n", 772 | " 1 file changed, 1 insertion(+)\n", 773 | " create mode 100644 file1.txt\n" 774 | ] 775 | } 776 | ], 777 | "source": [ 778 | "%%bash\n", 779 | "cd test\n", 780 | "\n", 781 | "git commit -a -m \"This is our first commit\"" 782 | ] 783 | }, 784 | { 785 | "cell_type": "markdown", 786 | "metadata": { 787 | "slideshow": { 788 | "slide_type": "fragment" 789 | } 790 | }, 791 | "source": [ 792 | "In the commit above, we used the `-m` flag to specify a message at the command line.\n", 793 | "\n", 794 | "If we don't do that, git will open the editor we specified in our configuration above and require that we enter a message.\n", 795 | "\n", 796 | "By default, git refuses to record changes that don't have a message to go along with them (though you can obviously 'cheat' by using an empty or meaningless string: git only tries to facilitate best practices, it's not your nanny)." 797 | ] 798 | }, 799 | { 800 | "cell_type": "markdown", 801 | "metadata": { 802 | "slideshow": { 803 | "slide_type": "slide" 804 | } 805 | }, 806 | "source": [ 807 | "### `git log`: what has been committed so far" 808 | ] 809 | }, 810 | { 811 | "cell_type": "code", 812 | "execution_count": 17, 813 | "metadata": { 814 | "collapsed": false, 815 | "slideshow": { 816 | "slide_type": "fragment" 817 | } 818 | }, 819 | "outputs": [ 820 | { 821 | "name": "stdout", 822 | "output_type": "stream", 823 | "text": [ 824 | "commit 609a45916899c56d1e3b8fe021b907f58845e75e\n", 825 | "Author: Jake Vanderplas \n", 826 | "Date: Thu Sep 12 10:06:55 2013 -0700\n", 827 | "\n", 828 | " This is our first commit\n" 829 | ] 830 | } 831 | ], 832 | "source": [ 833 | "%%bash\n", 834 | "cd test\n", 835 | "\n", 836 | "git log" 837 | ] 838 | }, 839 | { 840 | "cell_type": "markdown", 841 | "metadata": { 842 | "slideshow": { 843 | "slide_type": "slide" 844 | } 845 | }, 846 | "source": [ 847 | "### `git diff`: what have I changed?\n", 848 | "Let's do a little bit more work... Again, in practice you'll be editing the files by hand, here we do it via shell commands for the sake of automation (and therefore the reproducibility of this tutorial!)" 849 | ] 850 | }, 851 | { 852 | "cell_type": "code", 853 | "execution_count": 18, 854 | "metadata": { 855 | "collapsed": false, 856 | "slideshow": { 857 | "slide_type": "fragment" 858 | } 859 | }, 860 | "outputs": [], 861 | "source": [ 862 | "%%bash\n", 863 | "cd test\n", 864 | "\n", 865 | "echo \"And now some more text...\" >> file1.txt" 866 | ] 867 | }, 868 | { 869 | "cell_type": "markdown", 870 | "metadata": { 871 | "slideshow": { 872 | "slide_type": "fragment" 873 | } 874 | }, 875 | "source": [ 876 | "And now we can ask git what is different:" 877 | ] 878 | }, 879 | { 880 | "cell_type": "code", 881 | "execution_count": 19, 882 | "metadata": { 883 | "collapsed": false, 884 | "slideshow": { 885 | "slide_type": "fragment" 886 | } 887 | }, 888 | "outputs": [ 889 | { 890 | "name": "stdout", 891 | "output_type": "stream", 892 | "text": [ 893 | "diff --git a/file1.txt b/file1.txt\n", 894 | "index ce645c7..4baa979 100644\n", 895 | "--- a/file1.txt\n", 896 | "+++ b/file1.txt\n", 897 | "@@ -1 +1,2 @@\n", 898 | " My first bit of text\n", 899 | "+And now some more text...\n" 900 | ] 901 | } 902 | ], 903 | "source": [ 904 | "%%bash\n", 905 | "cd test\n", 906 | "\n", 907 | "git diff" 908 | ] 909 | }, 910 | { 911 | "cell_type": "markdown", 912 | "metadata": { 913 | "slideshow": { 914 | "slide_type": "slide" 915 | } 916 | }, 917 | "source": [ 918 | "### The cycle of git virtue: work, commit, work, commit, ..." 919 | ] 920 | }, 921 | { 922 | "cell_type": "code", 923 | "execution_count": 20, 924 | "metadata": { 925 | "collapsed": false, 926 | "slideshow": { 927 | "slide_type": "fragment" 928 | } 929 | }, 930 | "outputs": [ 931 | { 932 | "name": "stdout", 933 | "output_type": "stream", 934 | "text": [ 935 | "[master 43ed8dd] I have made great progress on this critical matter.\n", 936 | " 1 file changed, 1 insertion(+)\n" 937 | ] 938 | } 939 | ], 940 | "source": [ 941 | "%%bash\n", 942 | "cd test\n", 943 | "\n", 944 | "git commit -a -m \"I have made great progress on this critical matter.\"" 945 | ] 946 | }, 947 | { 948 | "cell_type": "markdown", 949 | "metadata": { 950 | "slideshow": { 951 | "slide_type": "slide" 952 | } 953 | }, 954 | "source": [ 955 | "### `git log` revisited\n", 956 | "First, let's see what the log shows us now:" 957 | ] 958 | }, 959 | { 960 | "cell_type": "code", 961 | "execution_count": 21, 962 | "metadata": { 963 | "collapsed": false, 964 | "slideshow": { 965 | "slide_type": "fragment" 966 | } 967 | }, 968 | "outputs": [ 969 | { 970 | "name": "stdout", 971 | "output_type": "stream", 972 | "text": [ 973 | "commit 43ed8dd431bde1d511934526da8414113965178b\n", 974 | "Author: Jake Vanderplas \n", 975 | "Date: Thu Sep 12 10:09:41 2013 -0700\n", 976 | "\n", 977 | " I have made great progress on this critical matter.\n", 978 | "\n", 979 | "commit 609a45916899c56d1e3b8fe021b907f58845e75e\n", 980 | "Author: Jake Vanderplas \n", 981 | "Date: Thu Sep 12 10:06:55 2013 -0700\n", 982 | "\n", 983 | " This is our first commit\n" 984 | ] 985 | } 986 | ], 987 | "source": [ 988 | "%%bash\n", 989 | "cd test\n", 990 | "\n", 991 | "git log" 992 | ] 993 | }, 994 | { 995 | "cell_type": "markdown", 996 | "metadata": { 997 | "slideshow": { 998 | "slide_type": "fragment" 999 | } 1000 | }, 1001 | "source": [ 1002 | "Sometimes it's handy to see a very summarized version of the log:" 1003 | ] 1004 | }, 1005 | { 1006 | "cell_type": "code", 1007 | "execution_count": 51, 1008 | "metadata": { 1009 | "collapsed": false, 1010 | "slideshow": { 1011 | "slide_type": "fragment" 1012 | } 1013 | }, 1014 | "outputs": [ 1015 | { 1016 | "name": "stdout", 1017 | "output_type": "stream", 1018 | "text": [ 1019 | "* 2d29a7b I have made great progress on this critical matter!\n", 1020 | "* 679f246 This is our first commit\n" 1021 | ] 1022 | } 1023 | ], 1024 | "source": [ 1025 | "%%bash\n", 1026 | "cd test\n", 1027 | "\n", 1028 | "git log --oneline --topo-order --graph" 1029 | ] 1030 | }, 1031 | { 1032 | "cell_type": "markdown", 1033 | "metadata": { 1034 | "slideshow": { 1035 | "slide_type": "slide" 1036 | } 1037 | }, 1038 | "source": [ 1039 | "### Defining an alias\n", 1040 | "\n", 1041 | "Git supports *aliases:* new names given to command combinations. Let's make this handy shortlog an alias, so we only have to type `git slog` and see this compact log:" 1042 | ] 1043 | }, 1044 | { 1045 | "cell_type": "code", 1046 | "execution_count": 22, 1047 | "metadata": { 1048 | "collapsed": false, 1049 | "slideshow": { 1050 | "slide_type": "fragment" 1051 | } 1052 | }, 1053 | "outputs": [ 1054 | { 1055 | "name": "stdout", 1056 | "output_type": "stream", 1057 | "text": [ 1058 | "* 43ed8dd I have made great progress on this critical matter.\n", 1059 | "* 609a459 This is our first commit\n" 1060 | ] 1061 | } 1062 | ], 1063 | "source": [ 1064 | "%%bash\n", 1065 | "cd test\n", 1066 | "\n", 1067 | "# We create our alias (this saves it in git's permanent configuration file):\n", 1068 | "git config --global alias.slog \"log --oneline --topo-order --graph\"\n", 1069 | "\n", 1070 | "# And now we can use it\n", 1071 | "git slog" 1072 | ] 1073 | }, 1074 | { 1075 | "cell_type": "markdown", 1076 | "metadata": { 1077 | "slideshow": { 1078 | "slide_type": "slide" 1079 | } 1080 | }, 1081 | "source": [ 1082 | "### `git mv` and `rm`: moving and removing files\n", 1083 | "While `git add` is used to add fils to the list git tracks, we must also tell it if we want their names to change or for it to stop tracking them. In familiar Unix fashion, the `mv` and `rm` git commands do precisely this:" 1084 | ] 1085 | }, 1086 | { 1087 | "cell_type": "code", 1088 | "execution_count": 23, 1089 | "metadata": { 1090 | "collapsed": false, 1091 | "slideshow": { 1092 | "slide_type": "fragment" 1093 | } 1094 | }, 1095 | "outputs": [ 1096 | { 1097 | "name": "stdout", 1098 | "output_type": "stream", 1099 | "text": [ 1100 | "# On branch master\n", 1101 | "# Changes to be committed:\n", 1102 | "# (use \"git reset HEAD ...\" to unstage)\n", 1103 | "#\n", 1104 | "#\trenamed: file1.txt -> file-newname.txt\n", 1105 | "#\n" 1106 | ] 1107 | } 1108 | ], 1109 | "source": [ 1110 | "%%bash\n", 1111 | "cd test\n", 1112 | "\n", 1113 | "git mv file1.txt file-newname.txt\n", 1114 | "git status" 1115 | ] 1116 | }, 1117 | { 1118 | "cell_type": "markdown", 1119 | "metadata": { 1120 | "slideshow": { 1121 | "slide_type": "fragment" 1122 | } 1123 | }, 1124 | "source": [ 1125 | "Note that these changes must be committed too, to become permanent! In git's world, until something hasn't been committed, it isn't permanently recorded anywhere." 1126 | ] 1127 | }, 1128 | { 1129 | "cell_type": "code", 1130 | "execution_count": 24, 1131 | "metadata": { 1132 | "collapsed": false, 1133 | "slideshow": { 1134 | "slide_type": "fragment" 1135 | } 1136 | }, 1137 | "outputs": [ 1138 | { 1139 | "name": "stdout", 1140 | "output_type": "stream", 1141 | "text": [ 1142 | "[master 110c1bb] I like this new name better\n", 1143 | " 1 file changed, 0 insertions(+), 0 deletions(-)\n", 1144 | " rename file1.txt => file-newname.txt (100%)\n", 1145 | "Let's look at the log again:\n", 1146 | "* 110c1bb I like this new name better\n", 1147 | "* 43ed8dd I have made great progress on this critical matter.\n", 1148 | "* 609a459 This is our first commit\n" 1149 | ] 1150 | } 1151 | ], 1152 | "source": [ 1153 | "%%bash\n", 1154 | "cd test\n", 1155 | "\n", 1156 | "git commit -a -m\"I like this new name better\"\n", 1157 | "echo \"Let's look at the log again:\"\n", 1158 | "git slog" 1159 | ] 1160 | }, 1161 | { 1162 | "cell_type": "markdown", 1163 | "metadata": { 1164 | "slideshow": { 1165 | "slide_type": "fragment" 1166 | } 1167 | }, 1168 | "source": [ 1169 | "And `git rm` works in a similar fashion." 1170 | ] 1171 | }, 1172 | { 1173 | "cell_type": "markdown", 1174 | "metadata": { 1175 | "slideshow": { 1176 | "slide_type": "slide" 1177 | } 1178 | }, 1179 | "source": [ 1180 | "### Exercise\n", 1181 | "Add a new file `file2.txt`, commit it, make some changes to it, commit them again, and then remove it (and don't forget to commit this last step!)." 1182 | ] 1183 | }, 1184 | { 1185 | "cell_type": "markdown", 1186 | "metadata": { 1187 | "slideshow": { 1188 | "slide_type": "slide" 1189 | } 1190 | }, 1191 | "source": [ 1192 | "## 2. Single Local user, branching\n", 1193 | "What is a branch? Simply a *label for the 'current' commit in a sequence of ongoing commits*:\n", 1194 | "\n", 1195 | "![](files/images/masterbranch.png)" 1196 | ] 1197 | }, 1198 | { 1199 | "cell_type": "markdown", 1200 | "metadata": { 1201 | "slideshow": { 1202 | "slide_type": "slide" 1203 | } 1204 | }, 1205 | "source": [ 1206 | "### Mulitple Branches\n", 1207 | "There can be multiple branches alive at any point in time; the working directory is the state of a special pointer called HEAD. In this example there are two branches, *master* and *testing*, and *testing* is the currently active branch since it's what HEAD points to:\n", 1208 | "\n", 1209 | "![](files/images/HEAD_testing.png)" 1210 | ] 1211 | }, 1212 | { 1213 | "cell_type": "markdown", 1214 | "metadata": { 1215 | "slideshow": { 1216 | "slide_type": "slide" 1217 | } 1218 | }, 1219 | "source": [ 1220 | "Once new commits are made on a branch, HEAD and the branch label move with the new commits:\n", 1221 | "\n", 1222 | "![](files/images/branchcommit.png)" 1223 | ] 1224 | }, 1225 | { 1226 | "cell_type": "markdown", 1227 | "metadata": { 1228 | "slideshow": { 1229 | "slide_type": "slide" 1230 | } 1231 | }, 1232 | "source": [ 1233 | "This allows the history of both branches to diverge:\n", 1234 | "\n", 1235 | "![](files/images/mergescenario.png)" 1236 | ] 1237 | }, 1238 | { 1239 | "cell_type": "markdown", 1240 | "metadata": { 1241 | "slideshow": { 1242 | "slide_type": "slide" 1243 | } 1244 | }, 1245 | "source": [ 1246 | "But based on this graph structure, git can compute the necessary information to merge the divergent branches back and continue with a unified line of development:\n", 1247 | " \n", 1248 | "![](files/images/mergeaftermath.png)" 1249 | ] 1250 | }, 1251 | { 1252 | "cell_type": "markdown", 1253 | "metadata": { 1254 | "slideshow": { 1255 | "slide_type": "slide" 1256 | } 1257 | }, 1258 | "source": [ 1259 | "### Branching Example\n", 1260 | "\n", 1261 | "Let's now illustrate all of this with a concrete example. Let's get our bearings first:" 1262 | ] 1263 | }, 1264 | { 1265 | "cell_type": "code", 1266 | "execution_count": 25, 1267 | "metadata": { 1268 | "collapsed": false, 1269 | "slideshow": { 1270 | "slide_type": "fragment" 1271 | } 1272 | }, 1273 | "outputs": [ 1274 | { 1275 | "name": "stdout", 1276 | "output_type": "stream", 1277 | "text": [ 1278 | "# On branch master\n", 1279 | "nothing to commit, working directory clean\n", 1280 | "file-newname.txt\n" 1281 | ] 1282 | } 1283 | ], 1284 | "source": [ 1285 | "%%bash\n", 1286 | "cd test\n", 1287 | "\n", 1288 | "git status\n", 1289 | "ls" 1290 | ] 1291 | }, 1292 | { 1293 | "cell_type": "markdown", 1294 | "metadata": { 1295 | "slideshow": { 1296 | "slide_type": "fragment" 1297 | } 1298 | }, 1299 | "source": [ 1300 | "We are now going to try two different routes of development: on the `master` branch we will add one file and on the `experiment` branch, which we will create, we will add a different one. We will then merge the experimental branch into `master`." 1301 | ] 1302 | }, 1303 | { 1304 | "cell_type": "code", 1305 | "execution_count": 26, 1306 | "metadata": { 1307 | "collapsed": false, 1308 | "slideshow": { 1309 | "slide_type": "fragment" 1310 | } 1311 | }, 1312 | "outputs": [ 1313 | { 1314 | "name": "stderr", 1315 | "output_type": "stream", 1316 | "text": [ 1317 | "Switched to branch 'experiment'\n" 1318 | ] 1319 | } 1320 | ], 1321 | "source": [ 1322 | "%%bash\n", 1323 | "cd test\n", 1324 | "\n", 1325 | "git branch experiment\n", 1326 | "git checkout experiment" 1327 | ] 1328 | }, 1329 | { 1330 | "cell_type": "code", 1331 | "execution_count": 27, 1332 | "metadata": { 1333 | "collapsed": false, 1334 | "slideshow": { 1335 | "slide_type": "fragment" 1336 | } 1337 | }, 1338 | "outputs": [ 1339 | { 1340 | "name": "stdout", 1341 | "output_type": "stream", 1342 | "text": [ 1343 | "[experiment 2ac278c] Trying something new\n", 1344 | " 1 file changed, 1 insertion(+)\n", 1345 | " create mode 100644 experiment.txt\n", 1346 | "* 2ac278c Trying something new\n", 1347 | "* 110c1bb I like this new name better\n", 1348 | "* 43ed8dd I have made great progress on this critical matter.\n", 1349 | "* 609a459 This is our first commit\n" 1350 | ] 1351 | } 1352 | ], 1353 | "source": [ 1354 | "%%bash\n", 1355 | "cd test\n", 1356 | "\n", 1357 | "echo \"Some crazy idea\" > experiment.txt\n", 1358 | "git add experiment.txt\n", 1359 | "git commit -a -m\"Trying something new\"\n", 1360 | "git slog" 1361 | ] 1362 | }, 1363 | { 1364 | "cell_type": "code", 1365 | "execution_count": 28, 1366 | "metadata": { 1367 | "collapsed": false, 1368 | "slideshow": { 1369 | "slide_type": "fragment" 1370 | } 1371 | }, 1372 | "outputs": [ 1373 | { 1374 | "name": "stdout", 1375 | "output_type": "stream", 1376 | "text": [ 1377 | "* 110c1bb I like this new name better\n", 1378 | "* 43ed8dd I have made great progress on this critical matter.\n", 1379 | "* 609a459 This is our first commit\n" 1380 | ] 1381 | }, 1382 | { 1383 | "name": "stderr", 1384 | "output_type": "stream", 1385 | "text": [ 1386 | "Switched to branch 'master'\n" 1387 | ] 1388 | } 1389 | ], 1390 | "source": [ 1391 | "%%bash\n", 1392 | "cd test\n", 1393 | "\n", 1394 | "git checkout master\n", 1395 | "git slog" 1396 | ] 1397 | }, 1398 | { 1399 | "cell_type": "code", 1400 | "execution_count": 29, 1401 | "metadata": { 1402 | "collapsed": false, 1403 | "slideshow": { 1404 | "slide_type": "fragment" 1405 | } 1406 | }, 1407 | "outputs": [ 1408 | { 1409 | "name": "stdout", 1410 | "output_type": "stream", 1411 | "text": [ 1412 | "[master 0c5002e] The mainline keeps moving\n", 1413 | " 1 file changed, 1 insertion(+)\n", 1414 | "* 0c5002e The mainline keeps moving\n", 1415 | "* 110c1bb I like this new name better\n", 1416 | "* 43ed8dd I have made great progress on this critical matter.\n", 1417 | "* 609a459 This is our first commit\n" 1418 | ] 1419 | } 1420 | ], 1421 | "source": [ 1422 | "%%bash\n", 1423 | "cd test\n", 1424 | "\n", 1425 | "echo \"All the while, more work goes on in master...\" >> file-newname.txt\n", 1426 | "git commit -a -m\"The mainline keeps moving\"\n", 1427 | "git slog" 1428 | ] 1429 | }, 1430 | { 1431 | "cell_type": "code", 1432 | "execution_count": 30, 1433 | "metadata": { 1434 | "collapsed": false, 1435 | "slideshow": { 1436 | "slide_type": "fragment" 1437 | } 1438 | }, 1439 | "outputs": [ 1440 | { 1441 | "name": "stdout", 1442 | "output_type": "stream", 1443 | "text": [ 1444 | "file-newname.txt\n" 1445 | ] 1446 | } 1447 | ], 1448 | "source": [ 1449 | "%%bash\n", 1450 | "cd test\n", 1451 | "\n", 1452 | "ls" 1453 | ] 1454 | }, 1455 | { 1456 | "cell_type": "code", 1457 | "execution_count": 31, 1458 | "metadata": { 1459 | "collapsed": false, 1460 | "slideshow": { 1461 | "slide_type": "fragment" 1462 | } 1463 | }, 1464 | "outputs": [ 1465 | { 1466 | "name": "stdout", 1467 | "output_type": "stream", 1468 | "text": [ 1469 | "Merge made by the 'recursive' strategy.\n", 1470 | " experiment.txt | 1 +\n", 1471 | " 1 file changed, 1 insertion(+)\n", 1472 | " create mode 100644 experiment.txt\n", 1473 | "* 3471d04 Merge branch 'experiment'\n", 1474 | "|\\ \n", 1475 | "| * 2ac278c Trying something new\n", 1476 | "* | 0c5002e The mainline keeps moving\n", 1477 | "|/ \n", 1478 | "* 110c1bb I like this new name better\n", 1479 | "* 43ed8dd I have made great progress on this critical matter.\n", 1480 | "* 609a459 This is our first commit\n" 1481 | ] 1482 | } 1483 | ], 1484 | "source": [ 1485 | "%%bash\n", 1486 | "cd test\n", 1487 | "\n", 1488 | "git merge experiment\n", 1489 | "git slog" 1490 | ] 1491 | }, 1492 | { 1493 | "cell_type": "markdown", 1494 | "metadata": { 1495 | "slideshow": { 1496 | "slide_type": "slide" 1497 | } 1498 | }, 1499 | "source": [ 1500 | "## 3. Using remotes as a single user" 1501 | ] 1502 | }, 1503 | { 1504 | "cell_type": "markdown", 1505 | "metadata": { 1506 | "slideshow": { 1507 | "slide_type": "fragment" 1508 | } 1509 | }, 1510 | "source": [ 1511 | "We are now going to introduce the concept of a *remote repository*: a pointer to another copy of the repository that lives on a different location. This can be simply a different path on the filesystem or a server on the internet.\n", 1512 | "\n", 1513 | "For this discussion, we'll be using remotes hosted on the [GitHub.com](http://github.com) service, but you can equally use other services like [BitBucket](http://bitbucket.org) or [Gitorious](http://gitorious.org) as well as host your own.\n", 1514 | "\n", 1515 | "If you don't have a Github account, take a moment now to [sign up](https://github.com/)" 1516 | ] 1517 | }, 1518 | { 1519 | "cell_type": "markdown", 1520 | "metadata": { 1521 | "slideshow": { 1522 | "slide_type": "slide" 1523 | } 1524 | }, 1525 | "source": [ 1526 | "### ``git remote``: view/modify remote repositories" 1527 | ] 1528 | }, 1529 | { 1530 | "cell_type": "code", 1531 | "execution_count": 61, 1532 | "metadata": { 1533 | "collapsed": false, 1534 | "slideshow": { 1535 | "slide_type": "fragment" 1536 | } 1537 | }, 1538 | "outputs": [ 1539 | { 1540 | "name": "stdout", 1541 | "output_type": "stream", 1542 | "text": [ 1543 | "experiment.txt\n", 1544 | "file-newname.txt\n", 1545 | "Let's see if we have any remote repositories here:\n" 1546 | ] 1547 | } 1548 | ], 1549 | "source": [ 1550 | "%%bash\n", 1551 | "cd test\n", 1552 | "\n", 1553 | "ls\n", 1554 | "echo \"Let's see if we have any remote repositories here:\"\n", 1555 | "git remote -v" 1556 | ] 1557 | }, 1558 | { 1559 | "cell_type": "markdown", 1560 | "metadata": { 1561 | "slideshow": { 1562 | "slide_type": "fragment" 1563 | } 1564 | }, 1565 | "source": [ 1566 | "Since the above cell didn't produce any output after the `git remote -v` call, it means we have no remote repositories configured." 1567 | ] 1568 | }, 1569 | { 1570 | "cell_type": "markdown", 1571 | "metadata": { 1572 | "slideshow": { 1573 | "slide_type": "slide" 1574 | } 1575 | }, 1576 | "source": [ 1577 | "#### Configuring a remote\n", 1578 | "Log into GitHub, go to the [new repository page](https://github.com/new) and make a repository called `test`.\n", 1579 | "\n", 1580 | "Do **not** check the box that says `Initialize this repository with a README`, since we already have an existing repository here. That option is useful when you're starting first at Github and don't have a repo made already on a local computer.\n", 1581 | "\n", 1582 | "We can now follow the instructions from the next page:" 1583 | ] 1584 | }, 1585 | { 1586 | "cell_type": "code", 1587 | "execution_count": 32, 1588 | "metadata": { 1589 | "collapsed": true, 1590 | "slideshow": { 1591 | "slide_type": "fragment" 1592 | } 1593 | }, 1594 | "outputs": [ 1595 | { 1596 | "name": "stdout", 1597 | "output_type": "stream", 1598 | "text": [ 1599 | "Process is terminated.\n" 1600 | ] 1601 | } 1602 | ], 1603 | "source": [ 1604 | "%%bash\n", 1605 | "cd test\n", 1606 | "\n", 1607 | "git remote add origin https://github.com/jakevdp/test.git" 1608 | ] 1609 | }, 1610 | { 1611 | "cell_type": "markdown", 1612 | "metadata": { 1613 | "slideshow": { 1614 | "slide_type": "fragment" 1615 | } 1616 | }, 1617 | "source": [ 1618 | "Let's see the remote situation again:" 1619 | ] 1620 | }, 1621 | { 1622 | "cell_type": "code", 1623 | "execution_count": 67, 1624 | "metadata": { 1625 | "collapsed": false, 1626 | "slideshow": { 1627 | "slide_type": "fragment" 1628 | } 1629 | }, 1630 | "outputs": [ 1631 | { 1632 | "name": "stdout", 1633 | "output_type": "stream", 1634 | "text": [ 1635 | "origin\thttps://github.com/fperez/test.git (fetch)\n", 1636 | "origin\thttps://github.com/fperez/test.git (push)\n" 1637 | ] 1638 | } 1639 | ], 1640 | "source": [ 1641 | "%%bash\n", 1642 | "cd test\n", 1643 | "\n", 1644 | "git remote -v" 1645 | ] 1646 | }, 1647 | { 1648 | "cell_type": "markdown", 1649 | "metadata": { 1650 | "slideshow": { 1651 | "slide_type": "fragment" 1652 | } 1653 | }, 1654 | "source": [ 1655 | "#### Pushing changes to a remote repository\n", 1656 | "\n", 1657 | "Now push the ``master`` branch to the remote named ``origin``:" 1658 | ] 1659 | }, 1660 | { 1661 | "cell_type": "code", 1662 | "execution_count": null, 1663 | "metadata": { 1664 | "collapsed": false, 1665 | "slideshow": { 1666 | "slide_type": "fragment" 1667 | } 1668 | }, 1669 | "outputs": [], 1670 | "source": [ 1671 | "%%bash\n", 1672 | "cd test\n", 1673 | "\n", 1674 | "git push origin master" 1675 | ] 1676 | }, 1677 | { 1678 | "cell_type": "markdown", 1679 | "metadata": { 1680 | "slideshow": { 1681 | "slide_type": "fragment" 1682 | } 1683 | }, 1684 | "source": [ 1685 | "We can now [see this repository publicly on github](https://github.com/fperez/test)." 1686 | ] 1687 | }, 1688 | { 1689 | "cell_type": "markdown", 1690 | "metadata": { 1691 | "slideshow": { 1692 | "slide_type": "slide" 1693 | } 1694 | }, 1695 | "source": [ 1696 | "### Using Git to Sync Work\n", 1697 | "\n", 1698 | "Let's see how this can be useful for backup and syncing work between two different computers. I'll simulate a 2nd computer by working in a different directory..." 1699 | ] 1700 | }, 1701 | { 1702 | "cell_type": "code", 1703 | "execution_count": 34, 1704 | "metadata": { 1705 | "collapsed": false, 1706 | "slideshow": { 1707 | "slide_type": "fragment" 1708 | } 1709 | }, 1710 | "outputs": [ 1711 | { 1712 | "name": "stdout", 1713 | "output_type": "stream", 1714 | "text": [ 1715 | "Cloning into 'test2'...\n", 1716 | "Checking connectivity... done\n", 1717 | "/Users/jakevdp/Opensource/2013_fall_ASTR599/notebooks/test2\n", 1718 | "origin\thttps://github.com/jakevdp/test.git (fetch)\n", 1719 | "origin\thttps://github.com/jakevdp/test.git (push)\n" 1720 | ] 1721 | } 1722 | ], 1723 | "source": [ 1724 | "%%bash\n", 1725 | "\n", 1726 | "# Here I clone my 'test' repo but with a different name, test2, to simulate a 2nd computer\n", 1727 | "git clone https://github.com/jakevdp/test.git test2\n", 1728 | "cd test2\n", 1729 | "pwd\n", 1730 | "git remote -v" 1731 | ] 1732 | }, 1733 | { 1734 | "cell_type": "markdown", 1735 | "metadata": { 1736 | "slideshow": { 1737 | "slide_type": "fragment" 1738 | } 1739 | }, 1740 | "source": [ 1741 | "Let's now make some changes in one 'computer' and synchronize them on the second." 1742 | ] 1743 | }, 1744 | { 1745 | "cell_type": "code", 1746 | "execution_count": 35, 1747 | "metadata": { 1748 | "collapsed": false, 1749 | "slideshow": { 1750 | "slide_type": "fragment" 1751 | } 1752 | }, 1753 | "outputs": [ 1754 | { 1755 | "name": "stdout", 1756 | "output_type": "stream", 1757 | "text": [ 1758 | "[master 8852251] More work, on machine #2\n", 1759 | " 1 file changed, 1 insertion(+)\n" 1760 | ] 1761 | } 1762 | ], 1763 | "source": [ 1764 | "%%bash\n", 1765 | "cd test2 # working on computer #2\n", 1766 | "\n", 1767 | "echo \"More new content on my experiment\" >> experiment.txt\n", 1768 | "git commit -a -m\"More work, on machine #2\"" 1769 | ] 1770 | }, 1771 | { 1772 | "cell_type": "markdown", 1773 | "metadata": { 1774 | "slideshow": { 1775 | "slide_type": "fragment" 1776 | } 1777 | }, 1778 | "source": [ 1779 | "Now we put this new work up on the github server so it's available from the internet" 1780 | ] 1781 | }, 1782 | { 1783 | "cell_type": "code", 1784 | "execution_count": 39, 1785 | "metadata": { 1786 | "collapsed": false, 1787 | "slideshow": { 1788 | "slide_type": "fragment" 1789 | } 1790 | }, 1791 | "outputs": [ 1792 | { 1793 | "name": "stderr", 1794 | "output_type": "stream", 1795 | "text": [ 1796 | "Everything up-to-date\n" 1797 | ] 1798 | } 1799 | ], 1800 | "source": [ 1801 | "%%bash\n", 1802 | "cd test2\n", 1803 | "\n", 1804 | "git push origin master" 1805 | ] 1806 | }, 1807 | { 1808 | "cell_type": "markdown", 1809 | "metadata": { 1810 | "slideshow": { 1811 | "slide_type": "slide" 1812 | } 1813 | }, 1814 | "source": [ 1815 | "Now let's fetch that work from machine #1:" 1816 | ] 1817 | }, 1818 | { 1819 | "cell_type": "code", 1820 | "execution_count": 38, 1821 | "metadata": { 1822 | "collapsed": false, 1823 | "slideshow": { 1824 | "slide_type": "fragment" 1825 | } 1826 | }, 1827 | "outputs": [ 1828 | { 1829 | "name": "stdout", 1830 | "output_type": "stream", 1831 | "text": [ 1832 | "Already up-to-date.\n" 1833 | ] 1834 | }, 1835 | { 1836 | "name": "stderr", 1837 | "output_type": "stream", 1838 | "text": [ 1839 | "From https://github.com/jakevdp/test\n", 1840 | " * branch master -> FETCH_HEAD\n" 1841 | ] 1842 | } 1843 | ], 1844 | "source": [ 1845 | "%%bash\n", 1846 | "cd test\n", 1847 | "\n", 1848 | "git pull origin master" 1849 | ] 1850 | }, 1851 | { 1852 | "cell_type": "markdown", 1853 | "metadata": { 1854 | "slideshow": { 1855 | "slide_type": "slide" 1856 | } 1857 | }, 1858 | "source": [ 1859 | "## An important aside: conflict management\n", 1860 | "While git is very good at merging, if two different branches modify the same file in the same location, it simply can't decide which change should prevail. At that point, human intervention is necessary to make the decision. Git will help you by marking the location in the file that has a problem, but it's up to you to resolve the conflict. Let's see how that works by intentionally creating a conflict.\n", 1861 | "\n", 1862 | "We start by creating a branch and making a change to our experiment file:" 1863 | ] 1864 | }, 1865 | { 1866 | "cell_type": "code", 1867 | "execution_count": 40, 1868 | "metadata": { 1869 | "collapsed": false, 1870 | "slideshow": { 1871 | "slide_type": "fragment" 1872 | } 1873 | }, 1874 | "outputs": [ 1875 | { 1876 | "name": "stdout", 1877 | "output_type": "stream", 1878 | "text": [ 1879 | "[trouble d46245e] Changes in the trouble branch\n", 1880 | " 1 file changed, 1 insertion(+)\n" 1881 | ] 1882 | }, 1883 | { 1884 | "name": "stderr", 1885 | "output_type": "stream", 1886 | "text": [ 1887 | "Switched to branch 'trouble'\n" 1888 | ] 1889 | } 1890 | ], 1891 | "source": [ 1892 | "%%bash\n", 1893 | "cd test\n", 1894 | "\n", 1895 | "git branch trouble\n", 1896 | "git checkout trouble\n", 1897 | "echo \"This is going to be a problem...\" >> experiment.txt\n", 1898 | "git commit -a -m\"Changes in the trouble branch\"" 1899 | ] 1900 | }, 1901 | { 1902 | "cell_type": "markdown", 1903 | "metadata": { 1904 | "slideshow": { 1905 | "slide_type": "fragment" 1906 | } 1907 | }, 1908 | "source": [ 1909 | "And now we go back to the master branch, where we change the *same* file:" 1910 | ] 1911 | }, 1912 | { 1913 | "cell_type": "code", 1914 | "execution_count": 41, 1915 | "metadata": { 1916 | "collapsed": false, 1917 | "slideshow": { 1918 | "slide_type": "fragment" 1919 | } 1920 | }, 1921 | "outputs": [ 1922 | { 1923 | "name": "stdout", 1924 | "output_type": "stream", 1925 | "text": [ 1926 | "[master 387f3ef] Mainline work\n", 1927 | " 1 file changed, 1 insertion(+)\n" 1928 | ] 1929 | }, 1930 | { 1931 | "name": "stderr", 1932 | "output_type": "stream", 1933 | "text": [ 1934 | "Switched to branch 'master'\n" 1935 | ] 1936 | } 1937 | ], 1938 | "source": [ 1939 | "%%bash\n", 1940 | "cd test\n", 1941 | "\n", 1942 | "git checkout master\n", 1943 | "echo \"More work on the master branch...\" >> experiment.txt\n", 1944 | "git commit -a -m\"Mainline work\"" 1945 | ] 1946 | }, 1947 | { 1948 | "cell_type": "markdown", 1949 | "metadata": { 1950 | "slideshow": { 1951 | "slide_type": "slide" 1952 | } 1953 | }, 1954 | "source": [ 1955 | "### The conflict...\n", 1956 | "\n", 1957 | "So now let's see what happens if we try to merge the `trouble` branch into `master`:" 1958 | ] 1959 | }, 1960 | { 1961 | "cell_type": "code", 1962 | "execution_count": 42, 1963 | "metadata": { 1964 | "collapsed": false, 1965 | "slideshow": { 1966 | "slide_type": "fragment" 1967 | } 1968 | }, 1969 | "outputs": [ 1970 | { 1971 | "name": "stdout", 1972 | "output_type": "stream", 1973 | "text": [ 1974 | "Auto-merging experiment.txt\n", 1975 | "CONFLICT (content): Merge conflict in experiment.txt\n", 1976 | "Automatic merge failed; fix conflicts and then commit the result.\n" 1977 | ] 1978 | } 1979 | ], 1980 | "source": [ 1981 | "%%bash\n", 1982 | "cd test\n", 1983 | "\n", 1984 | "git merge trouble" 1985 | ] 1986 | }, 1987 | { 1988 | "cell_type": "markdown", 1989 | "metadata": { 1990 | "slideshow": { 1991 | "slide_type": "fragment" 1992 | } 1993 | }, 1994 | "source": [ 1995 | "Let's see what git has put into our file:" 1996 | ] 1997 | }, 1998 | { 1999 | "cell_type": "code", 2000 | "execution_count": 43, 2001 | "metadata": { 2002 | "collapsed": false, 2003 | "slideshow": { 2004 | "slide_type": "fragment" 2005 | } 2006 | }, 2007 | "outputs": [ 2008 | { 2009 | "name": "stdout", 2010 | "output_type": "stream", 2011 | "text": [ 2012 | "Some crazy idea\n", 2013 | "More new content on my experiment\n", 2014 | "<<<<<<< HEAD\n", 2015 | "More work on the master branch...\n", 2016 | "=======\n", 2017 | "This is going to be a problem...\n", 2018 | ">>>>>>> trouble\n" 2019 | ] 2020 | } 2021 | ], 2022 | "source": [ 2023 | "%%bash\n", 2024 | "cd test\n", 2025 | "\n", 2026 | "cat experiment.txt" 2027 | ] 2028 | }, 2029 | { 2030 | "cell_type": "markdown", 2031 | "metadata": { 2032 | "slideshow": { 2033 | "slide_type": "fragment" 2034 | } 2035 | }, 2036 | "source": [ 2037 | "At this point, we go into the file with a text editor, decide which changes to keep, and make a new commit that records our decision. I've now made the edits, in this case I decided that both pieces of text were useful, but integrated them with some changes:" 2038 | ] 2039 | }, 2040 | { 2041 | "cell_type": "code", 2042 | "execution_count": 44, 2043 | "metadata": { 2044 | "collapsed": false, 2045 | "slideshow": { 2046 | "slide_type": "fragment" 2047 | } 2048 | }, 2049 | "outputs": [ 2050 | { 2051 | "name": "stdout", 2052 | "output_type": "stream", 2053 | "text": [ 2054 | "Some crazy idea\n", 2055 | "More new content on my experiment\n", 2056 | "More work on the master branch...\n", 2057 | "This is going to be a problem...\n" 2058 | ] 2059 | } 2060 | ], 2061 | "source": [ 2062 | "%%bash\n", 2063 | "cd test\n", 2064 | "\n", 2065 | "cat experiment.txt" 2066 | ] 2067 | }, 2068 | { 2069 | "cell_type": "markdown", 2070 | "metadata": { 2071 | "slideshow": { 2072 | "slide_type": "fragment" 2073 | } 2074 | }, 2075 | "source": [ 2076 | "Let's then make our new commit:" 2077 | ] 2078 | }, 2079 | { 2080 | "cell_type": "code", 2081 | "execution_count": 45, 2082 | "metadata": { 2083 | "collapsed": false, 2084 | "slideshow": { 2085 | "slide_type": "fragment" 2086 | } 2087 | }, 2088 | "outputs": [ 2089 | { 2090 | "name": "stdout", 2091 | "output_type": "stream", 2092 | "text": [ 2093 | "[master 0213b88] Completed merge of trouble, fixing conflicts along the way\n", 2094 | "* 0213b88 Completed merge of trouble, fixing conflicts along the way\n", 2095 | "|\\ \n", 2096 | "| * d46245e Changes in the trouble branch\n", 2097 | "* | 387f3ef Mainline work\n", 2098 | "|/ \n", 2099 | "* 8852251 More work, on machine #2\n", 2100 | "* 3471d04 Merge branch 'experiment'\n", 2101 | "|\\ \n", 2102 | "| * 2ac278c Trying something new\n", 2103 | "* | 0c5002e The mainline keeps moving\n", 2104 | "|/ \n", 2105 | "* 110c1bb I like this new name better\n", 2106 | "* 43ed8dd I have made great progress on this critical matter.\n", 2107 | "* 609a459 This is our first commit\n" 2108 | ] 2109 | } 2110 | ], 2111 | "source": [ 2112 | "%%bash\n", 2113 | "cd test\n", 2114 | "\n", 2115 | "git commit -a -m\"Completed merge of trouble, fixing conflicts along the way\"\n", 2116 | "git slog" 2117 | ] 2118 | }, 2119 | { 2120 | "cell_type": "markdown", 2121 | "metadata": { 2122 | "slideshow": { 2123 | "slide_type": "slide" 2124 | } 2125 | }, 2126 | "source": [ 2127 | "### Merge Tools\n", 2128 | "\n", 2129 | "*Note:* While it's a good idea to understand the basics of fixing merge conflicts by hand, in some cases you may find the use of an automated tool useful.\n", 2130 | "\n", 2131 | "Git supports multiple [merge tools](https://www.kernel.org/pub/software/scm/git/docs/git-mergetool.html): a merge tool is a piece of software that conforms to a basic interface and knows how to merge two files into a new one. Since these are typically graphical tools, there are various to choose from for the different operating systems, and as long as they obey a basic command structure, git can work with any of them." 2132 | ] 2133 | }, 2134 | { 2135 | "cell_type": "markdown", 2136 | "metadata": { 2137 | "slideshow": { 2138 | "slide_type": "slide" 2139 | } 2140 | }, 2141 | "source": [ 2142 | "## 4. Collaborating on github with a small team\n", 2143 | "\n", 2144 | "Here we will set up a shared collaboration with one partner -- choose someone sitting next to you. \n", 2145 | "\n", 2146 | "We will have two people, let's call them Alice and Bob, sharing a repository. Alice will be the owner of the repo and she will give Bob write privileges. \n", 2147 | "\n", 2148 | "**Find a partner & decide who will be Alice, and who will be Bob.**\n", 2149 | "\n", 2150 | "\n", 2151 | "Note for SVN users: this is similar to the classic SVN workflow, with the distinction that commit and push are separate steps. SVN, having no local repository, commits directly to the shared central resource, so to a first approximation you can think of `svn commit` as being synonymous with `git commit; git push`." 2152 | ] 2153 | }, 2154 | { 2155 | "cell_type": "markdown", 2156 | "metadata": { 2157 | "slideshow": { 2158 | "slide_type": "slide" 2159 | } 2160 | }, 2161 | "source": [ 2162 | "### 1. Synchronization\n", 2163 | "\n", 2164 | "We begin with a simple synchronization example. Working together, follow these steps:\n", 2165 | "\n", 2166 | "#### Creating a new repository\n", 2167 | "- Alice: create a new repository on github called ``AliceBob``\n", 2168 | "- Alice: create a file ``README.md``, commit it, and push it to the remote.\n", 2169 | "- Alice: on github, go to the settings for ``AliceBob``, and add your partner to the list of collaborators\n", 2170 | "\n", 2171 | "#### Cloning your partner's repository\n", 2172 | "- Bob: clone the ``AliceBob`` repository using ``git clone [url]``\n", 2173 | "- Bob: makes changes to the ``README.md`` file and commit locally.\n", 2174 | "- Bob: push changes to github.\n", 2175 | "- Alice: pull Bob's changes to the local repository.\n", 2176 | "\n", 2177 | "Now Alice and Bob should both have the same ``README.md`` file on their own computer." 2178 | ] 2179 | }, 2180 | { 2181 | "cell_type": "markdown", 2182 | "metadata": { 2183 | "slideshow": { 2184 | "slide_type": "slide" 2185 | } 2186 | }, 2187 | "source": [ 2188 | "### 2. Dealing with conflicts\n", 2189 | "\n", 2190 | "Next, we will have both parties make non-conflicting changes each, and commit them locally. Then both try to push their changes:\n", 2191 | "\n", 2192 | "- Alice: create & commit a new file, ``alice.txt`` to the local repo\n", 2193 | "- Bob: create & commit a new file, ``bob.txt`` to the local repo\n", 2194 | "- Alice: push the latest commit to github\n", 2195 | "- Bob: try to push to github. What happens?\n", 2196 | "\n", 2197 | "The problem is that Bob's changes create a commit that conflicts with Alice's, so git refuses to apply them.\n", 2198 | "\n", 2199 | "Bob must do\n", 2200 | "\n", 2201 | " git pull origin master\n", 2202 | " \n", 2203 | "And then deal with the conflict manually, then push again." 2204 | ] 2205 | }, 2206 | { 2207 | "cell_type": "markdown", 2208 | "metadata": { 2209 | "slideshow": { 2210 | "slide_type": "slide" 2211 | } 2212 | }, 2213 | "source": [ 2214 | "## 5. Full-contact github: distributed collaboration with large teams\n", 2215 | "\n", 2216 | "On large teams, you don't always want all contributors to have access to the main repository. So how do you move forward? Using Pull Requests.\n", 2217 | "\n", 2218 | "Again, we'll do this as an exercise with your partner:" 2219 | ] 2220 | }, 2221 | { 2222 | "cell_type": "markdown", 2223 | "metadata": { 2224 | "slideshow": { 2225 | "slide_type": "fragment" 2226 | } 2227 | }, 2228 | "source": [ 2229 | "[Brief demo of how this works on scikit-learn]" 2230 | ] 2231 | }, 2232 | { 2233 | "cell_type": "markdown", 2234 | "metadata": { 2235 | "slideshow": { 2236 | "slide_type": "fragment" 2237 | } 2238 | }, 2239 | "source": [ 2240 | "We'll practice this here, by having Alice now *fork* Bob's repository.\n", 2241 | "\n", 2242 | "1. **Bob:** create a new repository named ``BobAlice`` with a ``README.md`` file, and push it to the github remote.\n", 2243 | "\n", 2244 | "2. **Alice:** go to Bob's github page and click the *fork* button. You now have your own remote version of the repository, that looks like ``http://github.com/Alice/BobAlice.git``\n", 2245 | "\n", 2246 | "3. **Alice:** use ``git clone [url]`` to get a local version of *your fork* on your own computer. \n", 2247 | "\n", 2248 | "4. **Alice:** use ``git remote add upstream [url]`` to add a pointer to Bob's remote (the original)\n", 2249 | "\n", 2250 | "5. **Alice:** type ``git remote -v``, and you should see both your own fork (called ``origin``) and Bob's fork (called ``upstream``)\n", 2251 | "\n", 2252 | "6. **Alice:** create a new branch called ``alice_changes``\n", 2253 | "\n", 2254 | "7. **Alice:** add a file called ``alice.txt`` commit, and use ``git push origin alice_changes`` to push to the remote.\n", 2255 | "\n", 2256 | "8. **Alice:** reload the github page for *your own* fork: there should now be a button that says \"compare and pull request\". Click it and fill it out.\n", 2257 | "\n", 2258 | "9. **Bob:** go to your own notifications page (the blue circle in the upper-left of GitHub) and you should see a notification of Alice's Pull request. Check the diff, add some comments, and merge the changes.\n", 2259 | "\n", 2260 | "10. **Alice:** on your computer, checkout the master branch, and update it from Bob's fork with ``git pull upstream master``\n", 2261 | "\n", 2262 | "Congratulations! You're now a collaborator!\n", 2263 | "\n", 2264 | "This is how virtually all open source collaboration proceeds on Github!" 2265 | ] 2266 | }, 2267 | { 2268 | "cell_type": "markdown", 2269 | "metadata": { 2270 | "slideshow": { 2271 | "slide_type": "slide" 2272 | } 2273 | }, 2274 | "source": [ 2275 | "## Other useful commands\n", 2276 | "- [show](http://www.kernel.org/pub/software/scm/git/docs/git-show.html)\n", 2277 | "- [reflog](http://www.kernel.org/pub/software/scm/git/docs/git-reflog.html)\n", 2278 | "- [rebase](http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html)\n", 2279 | "- [tag](http://www.kernel.org/pub/software/scm/git/docs/git-tag.html)" 2280 | ] 2281 | }, 2282 | { 2283 | "cell_type": "markdown", 2284 | "metadata": { 2285 | "slideshow": { 2286 | "slide_type": "slide" 2287 | } 2288 | }, 2289 | "source": [ 2290 | "## Git resources\n", 2291 | "### Introductory materials\n", 2292 | "There are lots of good tutorials and introductions for Git, which you\n", 2293 | "can easily find yourself; this is just a short list of things I've found\n", 2294 | "useful. For a beginner, I would recommend the following 'core' reading list, and\n", 2295 | "below I mention a few extra resources:\n", 2296 | "\n", 2297 | "1. The smallest, and in the style of this tuorial: [git - the simple guide](http://rogerdudler.github.com/git-guide)\n", 2298 | "contains 'just the basics'. Very quick read.\n", 2299 | "\n", 2300 | "1. The concise [Git Reference](http://gitref.org): compact but with\n", 2301 | " all the key ideas. If you only read one document, make it this one.\n", 2302 | "\n", 2303 | "1. In my own experience, the most useful resource was [Understanding Git\n", 2304 | "Conceptually](http://www.sbf5.com/~cduan/technical/git).\n", 2305 | "Git has a reputation for being hard to use, but I have found that with a\n", 2306 | "clear view of what is actually a *very simple* internal design, its\n", 2307 | "behavior is remarkably consistent, simple and comprehensible.\n", 2308 | "\n", 2309 | "1. For more detail, see the start of the excellent [Pro\n", 2310 | " Git](http://progit.org/book) online book, or similarly the early\n", 2311 | " parts of the [Git community book](http://book.git-scm.com). Pro\n", 2312 | " Git's chapters are very short and well illustrated; the community\n", 2313 | " book tends to have more detail and has nice screencasts at the end\n", 2314 | " of some sections.\n", 2315 | "\n", 2316 | "If you are really impatient and just want a quick start, this [visual git tutorial](http://www.ralfebert.de/blog/tools/visual_git_tutorial_1)\n", 2317 | "may be sufficient. It is nicely illustrated with diagrams that show what happens on the filesystem.\n", 2318 | "\n", 2319 | "For windows users, [an Illustrated Guide to Git on Windows](http://nathanj.github.com/gitguide/tour.html) is useful in that\n", 2320 | "it contains also some information about handling SSH (necessary to interface with git hosted on remote servers when collaborating) as well\n", 2321 | "as screenshots of the Windows interface.\n", 2322 | "\n", 2323 | "Cheat sheets\n", 2324 | ": Two different\n", 2325 | " [cheat](http://zrusin.blogspot.com/2007/09/git-cheat-sheet.html)\n", 2326 | " [sheets](http://jan-krueger.net/development/git-cheat-sheet-extended-edition)\n", 2327 | " in PDF format that can be printed for frequent reference." 2328 | ] 2329 | }, 2330 | { 2331 | "cell_type": "markdown", 2332 | "metadata": { 2333 | "slideshow": { 2334 | "slide_type": "slide" 2335 | } 2336 | }, 2337 | "source": [ 2338 | "### Beyond the basics\n", 2339 | "At some point, it will pay off to understand how git itself is *built*. These two documents, written in a similar spirit, \n", 2340 | "are probably the most useful descriptions of the Git architecture short of diving into the actual implementation. They walk you through\n", 2341 | "how you would go about building a version control system with a little story. By the end you realize that Git's model is almost\n", 2342 | "an inevitable outcome of the proposed constraints:\n", 2343 | "\n", 2344 | "* The [Git parable](http://tom.preston-werner.com/2009/05/19/the-git-parable.html) by Tom Preston-Werner.\n", 2345 | "* [Git foundations](http://matthew-brett.github.com/pydagogue/foundation.html) by Matthew Brett.\n", 2346 | "\n", 2347 | "[Git ready](http://www.gitready.com)\n", 2348 | ": A great website of posts on specific git-related topics, organized\n", 2349 | " by difficulty.\n", 2350 | "\n", 2351 | "[QGit](http://sourceforge.net/projects/qgit/): an excellent Git GUI\n", 2352 | ": Git ships by default with gitk and git-gui, a pair of Tk graphical\n", 2353 | " clients to browse a repo and to operate in it. I personally have\n", 2354 | " found [qgit](http://sourceforge.net/projects/qgit/) to be nicer and\n", 2355 | " easier to use. It is available on modern linux distros, and since it\n", 2356 | " is based on Qt, it should run on OSX and Windows.\n", 2357 | "\n", 2358 | "[Git Magic](http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html)\n", 2359 | ": Another book-size guide that has useful snippets.\n", 2360 | "\n", 2361 | "The [learning center](http://learn.github.com) at Github\n", 2362 | ": Guides on a number of topics, some specific to github hosting but\n", 2363 | " much of it of general value.\n", 2364 | "\n", 2365 | "A [port](http://cworth.org/hgbook-git/tour) of the Hg book's beginning\n", 2366 | ": The [Mercurial book](http://hgbook.red-bean.com) has a reputation\n", 2367 | " for clarity, so Carl Worth decided to\n", 2368 | " [port](http://cworth.org/hgbook-git/tour) its introductory chapter\n", 2369 | " to Git. It's a nicely written intro, which is possible in good\n", 2370 | " measure because of how similar the underlying models of Hg and Git\n", 2371 | " ultimately are.\n", 2372 | "\n", 2373 | "[Intermediate tips](http://andyjeffries.co.uk/articles/25-tips-for-intermediate-git-users)\n", 2374 | ": A set of tips that contains some very valuable nuggets, once you're\n", 2375 | " past the basics." 2376 | ] 2377 | }, 2378 | { 2379 | "cell_type": "markdown", 2380 | "metadata": { 2381 | "slideshow": { 2382 | "slide_type": "slide" 2383 | } 2384 | }, 2385 | "source": [ 2386 | "### For SVN users\n", 2387 | "If you want a bit more background on why the model of version control\n", 2388 | "used by Git and Mercurial (known as distributed version control) is such\n", 2389 | "a good idea, I encourage you to read this very well written\n", 2390 | "[post](http://www.joelonsoftware.com/items/2010/03/17.html) by Joel\n", 2391 | "Spolsky on the topic. After that post, Joel created a very nice\n", 2392 | "Mercurial tutorial, whose [first page](http://hginit.com/00.html)\n", 2393 | "applies equally well to git and is a very good 're-education' for anyone\n", 2394 | "coming from an SVN (or similar) background.\n", 2395 | "\n", 2396 | "In practice, I think you are better off following Joel's advice and\n", 2397 | "understanding git on its own merits instead of trying to bang SVN\n", 2398 | "concepts into git shapes. But for the occasional translation from SVN to\n", 2399 | "Git of a specific idiom, the [Git - SVN Crash\n", 2400 | "Course](http://git-scm.org/course/svn.html) can be handy." 2401 | ] 2402 | }, 2403 | { 2404 | "cell_type": "markdown", 2405 | "metadata": { 2406 | "slideshow": { 2407 | "slide_type": "slide" 2408 | } 2409 | }, 2410 | "source": [ 2411 | "### A few useful tips for common tasks\n", 2412 | "#### Better shell support\n", 2413 | "\n", 2414 | "Adding git branch info to your bash prompt and tab completion for git commands and branches is extremely useful. I suggest you at least copy:\n", 2415 | "\n", 2416 | "- [git-completion.bash](https://github.com/git/git/blob/master/contrib/completion/git-completion.bash)\n", 2417 | "- [git-prompt.sh](https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh)\n", 2418 | " \n", 2419 | "You can then source both of these files in your `~/.bashrc` and then set your prompt (I'll assume you named them as the originals but starting with a `.` at the front of the name):\n", 2420 | "\n", 2421 | " source $HOME/.git-completion.bash\n", 2422 | " source $HOME/.git-prompt.sh\n", 2423 | " PS1='[\\u@\\h \\W$(__git_ps1 \" (%s)\")]\\$ ' # adjust this to your prompt liking\n", 2424 | "\n", 2425 | "See the comments in both of those files for lots of extra functionality they offer." 2426 | ] 2427 | }, 2428 | { 2429 | "cell_type": "markdown", 2430 | "metadata": { 2431 | "slideshow": { 2432 | "slide_type": "slide" 2433 | } 2434 | }, 2435 | "source": [ 2436 | "#### Embedding Git information in LaTeX documents\n", 2437 | "\n", 2438 | "(Sent by [Yaroslav Halchenko](http://www.onerussian.com))\n", 2439 | "su\n", 2440 | "I use a Make rule:\n", 2441 | "\n", 2442 | " # Helper if interested in providing proper version tag within the manuscript\n", 2443 | " revision.tex: ../misc/revision.tex.in ../.git/index\n", 2444 | " GITID=$$(git log -1 | grep -e '^commit' -e '^Date:' | sed -e 's/^[^ ]* *//g' | tr '\\n' ' '); \\\n", 2445 | " echo $$GITID; \\\n", 2446 | " sed -e \"s/GITID/$$GITID/g\" $< >| $@\n", 2447 | "\n", 2448 | "in the top level `Makefile.common` which is included in all\n", 2449 | "subdirectories which actually contain papers (hence all those\n", 2450 | "`../.git`). The `revision.tex.in` file is simply:\n", 2451 | "\n", 2452 | " % Embed GIT ID revision and date\n", 2453 | " \\def\\revision{GITID}\n", 2454 | "\n", 2455 | "The corresponding `paper.pdf` depends on `revision.tex` and includes the\n", 2456 | "line `\\input{revision}` to load up the actual revision mark." 2457 | ] 2458 | }, 2459 | { 2460 | "cell_type": "markdown", 2461 | "metadata": { 2462 | "slideshow": { 2463 | "slide_type": "slide" 2464 | } 2465 | }, 2466 | "source": [ 2467 | "#### git export\n", 2468 | "\n", 2469 | "Git doesn't have a native export command, but this works just fine:\n", 2470 | "\n", 2471 | " git archive --prefix=fperez.org/ master | gzip > ~/tmp/source.tgz" 2472 | ] 2473 | } 2474 | ], 2475 | "metadata": { 2476 | "kernelspec": { 2477 | "display_name": "Python 3", 2478 | "language": "python", 2479 | "name": "python3" 2480 | }, 2481 | "language_info": { 2482 | "codemirror_mode": { 2483 | "name": "ipython", 2484 | "version": 3 2485 | }, 2486 | "file_extension": ".py", 2487 | "mimetype": "text/x-python", 2488 | "name": "python", 2489 | "nbconvert_exporter": "python", 2490 | "pygments_lexer": "ipython3", 2491 | "version": "3.3.5" 2492 | } 2493 | }, 2494 | "nbformat": 4, 2495 | "nbformat_minor": 0 2496 | } 2497 | -------------------------------------------------------------------------------- /images/HEAD_testing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakevdp/git-intro/b477915d67384e0c07d02ae8b3a37236c54385dc/images/HEAD_testing.png -------------------------------------------------------------------------------- /images/branchcommit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakevdp/git-intro/b477915d67384e0c07d02ae8b3a37236c54385dc/images/branchcommit.png -------------------------------------------------------------------------------- /images/commit_anatomy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakevdp/git-intro/b477915d67384e0c07d02ae8b3a37236c54385dc/images/commit_anatomy.png -------------------------------------------------------------------------------- /images/masterbranch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakevdp/git-intro/b477915d67384e0c07d02ae8b3a37236c54385dc/images/masterbranch.png -------------------------------------------------------------------------------- /images/mergeaftermath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakevdp/git-intro/b477915d67384e0c07d02ae8b3a37236c54385dc/images/mergeaftermath.png -------------------------------------------------------------------------------- /images/mergescenario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakevdp/git-intro/b477915d67384e0c07d02ae8b3a37236c54385dc/images/mergescenario.png -------------------------------------------------------------------------------- /images/threecommits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakevdp/git-intro/b477915d67384e0c07d02ae8b3a37236c54385dc/images/threecommits.png --------------------------------------------------------------------------------