{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Revision control software"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "J.R. Johansson (jrjohansson at gmail.com)\n",
    "\n",
    "The latest version of this [IPython notebook](http://ipython.org/notebook.html) lecture is available at [http://github.com/jrjohansson/scientific-python-lectures](http://github.com/jrjohansson/scientific-python-lectures).\n",
    "\n",
    "The other notebooks in this lecture series are indexed at [http://jrjohansson.github.io](http://jrjohansson.github.io)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from IPython.display import Image"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In any software development, one of the most important tools are revision control software (RCS).\n",
    "\n",
    "They are used in virtually all software development and in all environments, by everyone and everywhere (no kidding!)\n",
    "\n",
    "RCS can used on almost any digital content, so it is not only restricted to software development, and is also very useful for manuscript files, figures, data and notebooks!\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## There are two main purposes of RCS systems:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. Keep track of changes in the source code.\n",
    "    * Allow reverting back to an older revision if something goes wrong.\n",
    "    * Work on several \"branches\" of the software concurrently.\n",
    "    * Tags revisions to keep track of which version of the software that was used for what (for example, \"release-1.0\", \"paper-A-final\", ...)\n",
    "2. Make it possible for several people to collaboratively work on the same code base simultaneously.\n",
    "    * Allow many authors to make changes to the code.\n",
    "    * Clearly communicating and visualizing changes in the code base to everyone involved."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic principles and terminology for RCS systems"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In an RCS, the source code or digital content is stored in a **repository**. \n",
    "\n",
    "* The repository does not only contain the latest version of all files, but the complete history of all changes to the files since they were added to the repository. \n",
    "\n",
    "* A user can **checkout** the repository, and obtain a local working copy of the files. All changes are made to the files in the local working directory, where files can be added, removed and updated. \n",
    "\n",
    "* When a task has been completed, the changes to the local files are **commited** (saved to the repository).\n",
    "\n",
    "* If someone else has been making changes to the same files, a **conflict** can occur. In many cases conflicts can be **resolved** automatically by the system, but in some cases we might manually have to **merge** different changes together.\n",
    "\n",
    "* It is often useful to create a new **branch** in a repository, or a **fork** or **clone** of an entire repository, when we doing larger experimental development. The main branch in a repository is called often **master** or **trunk**. When work on a branch or fork is completed, it can be merged in to the master branch/repository.\n",
    "\n",
    "* With distributed RCSs such as GIT or Mercurial, we can **pull** and **push** changesets between different repositories. For example, between a local copy of there repository to a central online repository (for example on a community repository host site like github.com)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Some good RCS software"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. GIT (`git`) : http://git-scm.com/\n",
    "2. Mercurial (`hg`) : http://mercurial.selenic.com/\n",
    "\n",
    "In the rest of this lecture we will look at `git`, although `hg` is just as good and work in almost exactly the same way."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Installing git"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On Linux:\n",
    "    \n",
    "    $ sudo apt-get install git\n",
    "\n",
    "On Mac (with macports):\n",
    "\n",
    "    $ sudo port install git\n",
    "\n",
    "The first time you start to use git, you'll need to configure your author information:\n",
    "\n",
    "    $ git config --global user.name 'Robert Johansson'\n",
    "    $ git config --global user.email robert@riken.jp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating and cloning a repository"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To create a brand new empty repository, we can use the command `git init repository-name`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Reinitialized existing Git repository in /home/rob/Desktop/scientific-python-lectures/gitdemo/.git/\r\n"
     ]
    }
   ],
   "source": [
    "# create a new git repository called gitdemo:\n",
    "!git init gitdemo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we want to fork or clone an existing repository, we can use the command `git clone repository`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cloning into 'qutip'...\n",
      "remote: Counting objects: 7425, done.\n",
      "remote: Compressing objects: 100% (2013/2013), done.\n",
      "remote: Total 7425 (delta 5386), reused 7420 (delta 5381)\n",
      "Receiving objects: 100% (7425/7425), 2.25 MiB | 696 KiB/s, done.\n",
      "Resolving deltas: 100% (5386/5386), done.\n"
     ]
    }
   ],
   "source": [
    "!git clone https://github.com/qutip/qutip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Git clone can take a URL to a public repository, like above, or a path to a local directory:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cloning into 'gitdemo2'...\r\n",
      "warning: You appear to have cloned an empty repository.\r\n",
      "done.\r\n"
     ]
    }
   ],
   "source": [
    "!git clone gitdemo gitdemo2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also clone private repositories over secure protocols such as SSH:\n",
    "\n",
    "    $ git clone ssh://myserver.com/myrepository"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using the command `git status` we get a summary of the current status of the working directory. It shows if we have modified, added or removed files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "#\r\n",
      "# Initial commit\r\n",
      "#\r\n",
      "# Untracked files:\r\n",
      "#   (use \"git add <file>...\" to include in what will be committed)\r\n",
      "#\r\n",
      "#\tLecture-7-Revision-Control-Software.ipynb\r\n",
      "nothing added to commit but untracked files present (use \"git add\" to track)\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this case, only the current ipython notebook has been added. It is listed as an untracked file, and is therefore not in the repository yet."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding files and committing changes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To add a new file to the repository, we first create the file and then use the `git add filename` command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing README\n"
     ]
    }
   ],
   "source": [
    "%%file README\n",
    "\n",
    "A file with information about the gitdemo repository."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "#\r\n",
      "# Initial commit\r\n",
      "#\r\n",
      "# Untracked files:\r\n",
      "#   (use \"git add <file>...\" to include in what will be committed)\r\n",
      "#\r\n",
      "#\tLecture-7-Revision-Control-Software.ipynb\r\n",
      "#\tREADME\r\n",
      "nothing added to commit but untracked files present (use \"git add\" to track)\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After having added the file `README`, the command `git status` list it as an *untracked* file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!git add README"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "#\r\n",
      "# Initial commit\r\n",
      "#\r\n",
      "# Changes to be committed:\r\n",
      "#   (use \"git rm --cached <file>...\" to unstage)\r\n",
      "#\r\n",
      "#\tnew file:   README\r\n",
      "#\r\n",
      "# Untracked files:\r\n",
      "#   (use \"git add <file>...\" to include in what will be committed)\r\n",
      "#\r\n",
      "#\tLecture-7-Revision-Control-Software.ipynb\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that it has been added, it is listed as a *new file* that has not yet been commited to the repository."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[master (root-commit) 1f26ad6] Added a README file\r\n",
      " 1 file changed, 2 insertions(+)\r\n",
      " create mode 100644 README\r\n"
     ]
    }
   ],
   "source": [
    "!git commit -m \"Added a README file\" README"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!git add Lecture-7-Revision-Control-Software.ipynb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[master da8b6e9] added notebook file\r\n",
      " 1 file changed, 2047 insertions(+)\r\n",
      " create mode 100644 Lecture-7-Revision-Control-Software.ipynb\r\n"
     ]
    }
   ],
   "source": [
    "!git commit -m \"added notebook file\" Lecture-7-Revision-Control-Software.ipynb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "nothing to commit (working directory clean)\r\n"
     ]
    }
   ],
   "source": [
    "!git status "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After *committing* the change to the repository from the local working directory, `git status` again reports that working directory is clean."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Commiting changes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When files that is tracked by GIT are changed, they are listed as *modified* by `git status`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting README\n"
     ]
    }
   ],
   "source": [
    "%%file README\n",
    "\n",
    "A file with information about the gitdemo repository.\n",
    "\n",
    "A new line."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "# Changes not staged for commit:\r\n",
      "#   (use \"git add <file>...\" to update what will be committed)\r\n",
      "#   (use \"git checkout -- <file>...\" to discard changes in working directory)\r\n",
      "#\r\n",
      "#\tmodified:   README\r\n",
      "#\r\n",
      "no changes added to commit (use \"git add\" and/or \"git commit -a\")\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Again, we can commit such changes to the repository using the `git commit -m \"message\"` command."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[master b6db712] added one more line in README\r\n",
      " 1 file changed, 3 insertions(+), 1 deletion(-)\r\n"
     ]
    }
   ],
   "source": [
    "!git commit -m \"added one more line in README\" README"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "nothing to commit (working directory clean)\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Removing files"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To remove file that has been added to the repository, use `git rm filename`, which works similar to `git add filename`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing tmpfile\n"
     ]
    }
   ],
   "source": [
    "%%file tmpfile\n",
    "\n",
    "A short-lived file."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Add it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!git add tmpfile"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[master 44ed840] adding file tmpfile\r\n",
      " 1 file changed, 2 insertions(+)\r\n",
      " create mode 100644 tmpfile\r\n"
     ]
    }
   ],
   "source": [
    "!git commit -m \"adding file tmpfile\" tmpfile "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remove it again:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rm 'tmpfile'\r\n"
     ]
    }
   ],
   "source": [
    "!git rm tmpfile"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[master a9dc0a4] remove file tmpfile\r\n",
      " 1 file changed, 2 deletions(-)\r\n",
      " delete mode 100644 tmpfile\r\n"
     ]
    }
   ],
   "source": [
    "!git commit -m \"remove file tmpfile\" tmpfile "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Commit logs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The messages that are added to the commit command are supposed to give a short (often one-line) description of the changes/additions/deletions in the commit. If the `-m \"message\"` is omitted when invoking the `git commit` message an editor will be opened for you to type a commit message (for example useful when a longer commit message is required). \n",
    "\n",
    "We can look at the revision log by using the command `git log`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "commit a9dc0a4b68e8b1b6d973be8f7e7b8f1c92393c17\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:41 2012 +0100\r\n",
      "\r\n",
      "    remove file tmpfile\r\n",
      "\r\n",
      "commit 44ed840422571c62db55eabd8e8768be6c7784e4\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:31 2012 +0100\r\n",
      "\r\n",
      "    adding file tmpfile\r\n",
      "\r\n",
      "commit b6db712506a45a68001c768a6cf6e15e11c62f89\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:26 2012 +0100\r\n",
      "\r\n",
      "    added one more line in README\r\n",
      "\r\n",
      "commit da8b6e92b34fe3838873bdd27a94402ecc121c43\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:20 2012 +0100\r\n",
      "\r\n",
      "    added notebook file\r\n",
      "\r\n",
      "commit 1f26ad648a791e266fbb951ef5c49b8d990e6461\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:19 2012 +0100\r\n",
      "\r\n",
      "    Added a README file\r\n"
     ]
    }
   ],
   "source": [
    "!git log"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the commit log, each revision is shown with a timestampe, a unique has tag that, and author information and the commit message."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Diffs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All commits results in a changeset, which has a \"diff\" describing the changes to the file associated with it. We can use `git diff` so see what has changed in a file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting README\n"
     ]
    }
   ],
   "source": [
    "%%file README\n",
    "\n",
    "A file with information about the gitdemo repository.\n",
    "\n",
    "README files usually contains installation instructions, and information about how to get started using the software (for example)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "diff --git a/README b/README\r\n",
      "index 4f51868..d3951c6 100644\r\n",
      "--- a/README\r\n",
      "+++ b/README\r\n",
      "@@ -1,4 +1,4 @@\r\n",
      " \r\n",
      " A file with information about the gitdemo repository.\r\n",
      " \r\n",
      "-A new line.\r\n",
      "\\ No newline at end of file\r\n",
      "+README files usually contains installation instructions, and information about how to get started using the software (for example).\r\n",
      "\\ No newline at end of file\r\n"
     ]
    }
   ],
   "source": [
    "!git diff README"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That looks quite cryptic but is a standard form for describing changes in files. We can use other tools, like graphical user interfaces or web based systems to get a more easily understandable diff.\n",
    "\n",
    "In github (a web-based GIT repository hosting service) it can look like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 146184 characters]",
      "text/plain": [
       "<IPython.core.display.Image at 0x1ce7590>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image(filename='images/github-diff.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Discard changes in the working directory"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To discard a change (revert to the latest version in the repository) we can use the `checkout` command like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!git checkout -- README"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "nothing to commit (working directory clean)\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Checking out old revisions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we want to get the code for a specific revision, we can use \"git checkout\" and giving it the hash code for the revision we are interested as argument:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "commit a9dc0a4b68e8b1b6d973be8f7e7b8f1c92393c17\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:41 2012 +0100\r\n",
      "\r\n",
      "    remove file tmpfile\r\n",
      "\r\n",
      "commit 44ed840422571c62db55eabd8e8768be6c7784e4\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:31 2012 +0100\r\n",
      "\r\n",
      "    adding file tmpfile\r\n",
      "\r\n",
      "commit b6db712506a45a68001c768a6cf6e15e11c62f89\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:26 2012 +0100\r\n",
      "\r\n",
      "    added one more line in README\r\n",
      "\r\n",
      "commit da8b6e92b34fe3838873bdd27a94402ecc121c43\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:20 2012 +0100\r\n",
      "\r\n",
      "    added notebook file\r\n",
      "\r\n",
      "commit 1f26ad648a791e266fbb951ef5c49b8d990e6461\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:19 2012 +0100\r\n",
      "\r\n",
      "    Added a README file\r\n"
     ]
    }
   ],
   "source": [
    "!git log"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Note: checking out '1f26ad648a791e266fbb951ef5c49b8d990e6461'.\r\n",
      "\r\n",
      "You are in 'detached HEAD' state. You can look around, make experimental\r\n",
      "changes and commit them, and you can discard any commits you make in this\r\n",
      "state without impacting any branches by performing another checkout.\r\n",
      "\r\n",
      "If you want to create a new branch to retain commits you create, you may\r\n",
      "do so (now or later) by using -b with the checkout command again. Example:\r\n",
      "\r\n",
      "  git checkout -b new_branch_name\r\n",
      "\r\n",
      "HEAD is now at 1f26ad6... Added a README file\r\n"
     ]
    }
   ],
   "source": [
    "!git checkout 1f26ad648a791e266fbb951ef5c49b8d990e6461"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now the content of all the files like in the revision with the hash code listed above (first revision)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "A file with information about the gitdemo repository."
     ]
    }
   ],
   "source": [
    "!cat README"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can move back to \"the latest\" (master) with the command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Previous HEAD position was 1f26ad6... Added a README file\r\n",
      "Switched to branch 'master'\r\n"
     ]
    }
   ],
   "source": [
    "!git checkout master "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "A file with information about the gitdemo repository.\r\n",
      "\r\n",
      "A new line."
     ]
    }
   ],
   "source": [
    "!cat README"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "nothing to commit (working directory clean)\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tagging and branching"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tags"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tags are named revisions. They are useful for marking particular revisions for later references. For example, we can tag our code with the tag \"paper-1-final\" when when simulations for \"paper-1\" are finished and the paper submitted. Then we can always retrieve exactly the code used for that paper even if we continue to work on and develop the code for future projects and papers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "commit a9dc0a4b68e8b1b6d973be8f7e7b8f1c92393c17\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:41 2012 +0100\r\n",
      "\r\n",
      "    remove file tmpfile\r\n",
      "\r\n",
      "commit 44ed840422571c62db55eabd8e8768be6c7784e4\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:31 2012 +0100\r\n",
      "\r\n",
      "    adding file tmpfile\r\n",
      "\r\n",
      "commit b6db712506a45a68001c768a6cf6e15e11c62f89\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:26 2012 +0100\r\n",
      "\r\n",
      "    added one more line in README\r\n",
      "\r\n",
      "commit da8b6e92b34fe3838873bdd27a94402ecc121c43\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:20 2012 +0100\r\n",
      "\r\n",
      "    added notebook file\r\n",
      "\r\n",
      "commit 1f26ad648a791e266fbb951ef5c49b8d990e6461\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:19 2012 +0100\r\n",
      "\r\n",
      "    Added a README file\r\n"
     ]
    }
   ],
   "source": [
    "!git log"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!git tag -a demotag1 -m \"Code used for this and that purpuse\" "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "demotag1\r\n"
     ]
    }
   ],
   "source": [
    "!git tag -l "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tag demotag1\r\n",
      "Tagger: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:57:25 2012 +0100\r\n",
      "\r\n",
      "Code used for this and that purpuse\r\n",
      "\r\n",
      "commit a9dc0a4b68e8b1b6d973be8f7e7b8f1c92393c17\r\n",
      "Author: Robert Johansson <jrjohansson@gmail.com>\r\n",
      "Date:   Mon Dec 10 06:54:41 2012 +0100\r\n",
      "\r\n",
      "    remove file tmpfile\r\n",
      "\r\n",
      "diff --git a/tmpfile b/tmpfile\r\n",
      "deleted file mode 100644\r\n",
      "index ee4c1e7..0000000\r\n",
      "--- a/tmpfile\r\n",
      "+++ /dev/null\r\n",
      "@@ -1,2 +0,0 @@\r\n",
      "-\r\n",
      "-A short-lived file.\r\n",
      "\\ No newline at end of file\r\n"
     ]
    }
   ],
   "source": [
    "!git show demotag1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To retrieve the code in the state corresponding to a particular tag, we can use the `git checkout tagname` command:\n",
    "\n",
    "    $ git checkout demotag1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Branches"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With branches we can create diverging code bases in the same repository. They are for example useful for experimental development that requires a lot of code changes that could break the functionality in the master branch. Once the development of a branch has reached a stable state it can always be merged back into the trunk. Branching-development-merging is a good development strategy when several people are involved in working on the same code base. But even in single author repositories it can often be useful to always keep the master branch in a working state, and always branch/fork before implementing a new feature, and later merge it back into the main trunk.\n",
    "\n",
    "In GIT, we can create a new branch like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!git branch expr1 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can list the existing branches like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  expr1\r\n",
      "* master\r\n"
     ]
    }
   ],
   "source": [
    "!git branch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And we can switch between branches using `checkout`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Switched to branch 'expr1'\r\n"
     ]
    }
   ],
   "source": [
    "!git checkout expr1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Make a change in the new branch."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting README\n"
     ]
    }
   ],
   "source": [
    "%%file README\n",
    "\n",
    "A file with information about the gitdemo repository.\n",
    "\n",
    "README files usually contains installation instructions, and information about how to get started using the software (for example).\n",
    "\n",
    "Experimental addition."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[expr1 a6dc24f] added a line in expr1 branch\r\n",
      " 1 file changed, 3 insertions(+), 1 deletion(-)\r\n"
     ]
    }
   ],
   "source": [
    "!git commit -m \"added a line in expr1 branch\" README"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* expr1\r\n",
      "  master\r\n"
     ]
    }
   ],
   "source": [
    "!git branch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Switched to branch 'master'\r\n"
     ]
    }
   ],
   "source": [
    "!git checkout master"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  expr1\r\n",
      "* master\r\n"
     ]
    }
   ],
   "source": [
    "!git branch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can merge an existing branch and all its changesets into another branch (for example the master branch) like this:\n",
    "\n",
    "First change to the target branch:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Switched to branch 'master'\r\n"
     ]
    }
   ],
   "source": [
    "!git checkout master"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Updating a9dc0a4..a6dc24f\r\n",
      "Fast-forward\r\n",
      " README |    4 +++-\r\n",
      " 1 file changed, 3 insertions(+), 1 deletion(-)\r\n"
     ]
    }
   ],
   "source": [
    "!git merge expr1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  expr1\r\n",
      "* master\r\n"
     ]
    }
   ],
   "source": [
    "!git branch "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can delete the branch `expr1` now that it has been merged into the master:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Deleted branch expr1 (was a6dc24f).\r\n"
     ]
    }
   ],
   "source": [
    "!git branch -d expr1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* master\r\n"
     ]
    }
   ],
   "source": [
    "!git branch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\r\n",
      "A file with information about the gitdemo repository.\r\n",
      "\r\n",
      "README files usually contains installation instructions, and information about how to get started using the software (for example).\r\n",
      "\r\n",
      "Experimental addition."
     ]
    }
   ],
   "source": [
    "!cat README"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## pulling and pushing changesets between repositories"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the repository has been cloned from another repository, for example on github.com, it automatically remembers the address of the parent repository (called origin):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "origin\r\n"
     ]
    }
   ],
   "source": [
    "!git remote"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "* remote origin\r\n",
      "  Fetch URL: git@github.com:jrjohansson/scientific-python-lectures.git\r\n",
      "  Push  URL: git@github.com:jrjohansson/scientific-python-lectures.git\r\n",
      "  HEAD branch: master\r\n",
      "  Remote branch:\r\n",
      "    master tracked\r\n",
      "  Local branch configured for 'git pull':\r\n",
      "    master merges with remote master\r\n",
      "  Local ref configured for 'git push':\r\n",
      "    master pushes to master (up to date)\r\n"
     ]
    }
   ],
   "source": [
    "!git remote show origin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### pull"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can retrieve updates from the origin repository by \"pulling\" changesets from \"origin\" to our repository:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Already up-to-date.\r\n"
     ]
    }
   ],
   "source": [
    "!git pull origin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can register addresses to many different repositories, and pull in different changesets from different sources, but the default source is the origin from where the repository was first cloned (and the work origin could have been omitted from the line above)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### push"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After making changes to our local repository, we can push changes to a remote repository using `git push`. Again, the default target repository is `origin`, so we can do:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# On branch master\r\n",
      "# Untracked files:\r\n",
      "#   (use \"git add <file>...\" to include in what will be committed)\r\n",
      "#\r\n",
      "#\tLecture-7-Revision-Control-Software.ipynb\r\n",
      "nothing added to commit but untracked files present (use \"git add\" to track)\r\n"
     ]
    }
   ],
   "source": [
    "!git status"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "!git add Lecture-7-Revision-Control-Software.ipynb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[master d0d6a70] added lecture notebook about RCS\r\n",
      " 1 file changed, 2114 insertions(+)\r\n",
      " create mode 100644 Lecture-7-Revision-Control-Software.ipynb\r\n"
     ]
    }
   ],
   "source": [
    "!git commit -m \"added lecture notebook about RCS\" Lecture-7-Revision-Control-Software.ipynb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Counting objects: 4, done.\n",
      "Delta compression using up to 4 threads.\n",
      "Compressing objects: 100% (3/3), done.\n",
      "Writing objects: 100% (3/3), 118.94 KiB, done.\n",
      "Total 3 (delta 1), reused 0 (delta 0)\n",
      "To git@github.com:jrjohansson/scientific-python-lectures.git\n",
      "   2495af4..d0d6a70  master -> master\n"
     ]
    }
   ],
   "source": [
    "!git push"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Hosted repositories"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Github.com is a git repository hosting site that is very popular with both open source projects (for which it is free) and private repositories (for which a subscription might be needed).\n",
    "\n",
    "With a hosted repository it is easy to collaborate with colleagues on the same code base, and you get a graphical user interface where you can browse the code and look at commit logs, track issues etc. \n",
    "\n",
    "Some good hosted repositories are\n",
    "\n",
    "* Github : http://www.github.com\n",
    "* Bitbucket: http://www.bitbucket.org"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 156344 characters]",
      "text/plain": [
       "<IPython.core.display.Image at 0x2a43e50>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image(filename='images/github-project-page.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Graphical user interfaces"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are also a number of graphical users interfaces for GIT. The available options vary a little bit from platform to platform:\n",
    "\n",
    "http://git-scm.com/downloads/guis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 199688 characters]",
      "text/plain": [
       "<IPython.core.display.Image at 0x2a51150>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Image(filename='images/gitk.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Further reading"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* http://git-scm.com/book\n",
    "* http://www.vogella.com/articles/Git/article.html\n",
    "* http://cheat.errtheblog.com/s/git"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
