Version Control with Ben Morgan Developer Workflow Log what we did: “Add foo support” Edit Sources Add Files Compile and Test Logbook ======= 1. Initial version Logbook ======= 1. Initial version 2. Remove ‘using’ directive, use ‘std’ Logbook ======= 1. Initial version 2. Remove ‘using’ directive, use ‘std’ 3. Output command line arguments to stdout Logging via a text file? «database» Repository «commit» Working Copy Files State Files Changes +- main.cc +- README.txt 1 2->2.1 3 | 4 | 5 2.2 6<--| 7 +- main.cc +- README.txt «update» Version Control Systems Managing change and logs Centralized Version Control My Working Copy Files State Central Repository Examples Your Working Copy Files State Subversion CVS Perforce Distributed Version Control My Working Copy Files Files State Repo Repo State Your Working Copy “Central” Repository Examples Git Mercurial Bazaar A Version Control Walkthrough with Git • We haven’t actually written anything yet, and this is the perfect time to get pp6calculator under version control so you can use it through the whole course. We’ll be using git as our version control system, with github.com acting as our central repository. Why not SVN? It’s slightly more awkward to get this set up and using github.com allows all of you to see how a central repository works. • Aims of the walkthough: • Create a local repository, add files, commit changes and make tags • Show diffs and logs for the commits we’ve made • Create a central repo on GitHub, push our local changes to the new central repository Tools you’ll need 1: Project Organization First of all, we want to create a suitable directory structure to hold our project. Open a terminal session and check that you’re in the HOME directory and cd to it if not. For this project, we need a two level directory structure, the reason for which will become apparent next week. We simply create directories mpagspp6/pp6calculator.git under HOME and cd into the bottom level directory: Notes If you want to keep the mpagspp6 directory somewhere other than in HOME, that’s fine. Directories holding git repositories are often named with a .git extension. This is not required, but is helpful in noting the directory as a repository! 2: Creating the Repository As pp6calculator.git is our working copy, and git is a distributed version control system, we create the repository in our working copy. Git makes this very easy, and all we need to do is run the simple command (in the pp6calculator.git directory!): $ git init Notes All that init does is create the .git directory in the directory where it’s run. You can use ls to explore the contents of this directory, which is where git stores all you changes. For more details on the contents, see the O’Reilly text “Version Control with Git” or git-scm.com 3: Getting Help Ask us! If we’re not around though, then man git will provide plenty of useful information. Like Subversion, git also provides a fast command line help interface, so you can also just type $ git help Notes As the output of git help notes, to get help on a specific command, simply append its name to git help. It will open a man style page for the command (simply use ‘q’ to exit this). Of course, also refer to text books and online resources such as git-scm.com. 4: Viewing Repository Status As we add and edit files, it’s useful to keep track of the repository status without changing anything. With git, simply use the status command to view the current repository status: $ git status Notes Of course at the moment, there’s not much to report as we just have an empty repository. Get into the habit of running git status regularly to see what you’ve changed. 5: Adding a README file We’re going to start our project by adding a README for pp6calculator. This is a file that sits in the top level of the project and provides some basic information about what the project is, plus other information like installation instructions, authors and copyright/license details. Our README will be in plain text, using Markdown formatting. We use Markdown because it is human readable but easily convertible to other formats. Open your favourite text editor and begin to write your README, saving it as README.md Tips The example on the left shows the most basic README structure, but you can change it as you wish. We’ll be adding to it later! Underlines using ‘=’ are major sections, and those with ‘-’ are subsections. When we upload our project to github, we’ll see how these are displayed. 6: Adding the README.md File Having saved README.md, if you run git status again, you can see that git recognises a new file exists. To add this to the repository, and make hit track it in the future we use git’s add command and then the status command to see the changes $ git add README.md Notes “staged” files - Ready to be commited “unstaged” files - Changed but not staged “untracked” files - Not tracked by git yet “deleted” files - Deleted by git and ready for removal No color? See later! 7: Committing You’ll have noticed that when you ran git status after adding README.md it only says “Changes to be committed”. Git stages changes before committing them to the repository. To store the changes we use the commit command with a message describing the changes: $ git commit -m “Add skeleton README.md” Notes The staging area is a place to queue up (or remove) changes before they are committed. This is useful when we start to deal with multiple files. A “commit” is a snapshot of the repository. After the commit, status shows WC and repo in sync 8: Making Changes Now we’ve staged and committed README.md, we can make some further changes. So edit your README.md, for example, add an empty section “Installation”. Save the file and run git status again. You’ll see that git recognises we’ve made changes, but these are not yet staged. To actually update the repository, we run git add again to stage the change then git commit to update the repository. This cycle of staging and committing is the basic git workflow. Try This Make a few more edits to README.md and use git add and git commit for each to get into the feel of staging and committing. Remember to use git status regularly to see what’s happening! 9: Unstaging Changes So you’ve staged a change, and then you realise it either breaks something or you want to add something else. As you may have noticed, git status actually tells you what to do in this case, so make a change, stage it up and then use reset to unstage it: $ git reset HEAD README.md Notes If you have a change staged and simply want to add to it, simply use git add. That works even if for changes to the same file. 10: Viewing Logs We’ve now made a few commits to our repository, so how do we go back and see what we’ve done and why? Just use the log command! $ git log Notes Plain log displays everything! To get the N most recent commits, use git log -nN. You can also use git log --summary to get a more detailed overview, though it doesn’t show much as we’ve only worked with one file. 11: Viewing Changes The basic log command shows the timeline of changes, but not what changed. To see what actually changed between commits, we can use git log -p or the diff command. Without any arguments, it shows a diff between the last commit and any local changes: $ git diff Notes Git shows difference using the standard diff format for additions/removals. On the left, additions are in green, removals in red. Depending on the default configuration, the diff may be output to a pager, in which case use ‘q’ to quit. No color? See later! 12: Changes between Commits As you’ll have seen in using git log, git labels commits using a 40 character hash code (cf subversion’s revision numbers). You can use these labels to view differences between any two commits, though because hashes are unique, you don’t have to type out 80 characters! $ git diff a567 40a2 Hints The commit specifier needs to contain enough characters to uniquely identify the commit. The arguments to git diff can take a variety of forms. See man gitrevisions for more details, or the more helpful Git SCM Book! Try some of these out. 13: Writing Good Commit Messages Our edits so far have been simple and confined to one file. In these cases, a single line commit message using git commit -m “commit message” is completely sufficient (e.g. “Fixed typographic errors”). As we start to make more involved commits involving several files, then we need to provide more detail. Because of the way git works with patches and email, it tends to recommend the specific style of commit message listed below. Why? There’s a good example in the text on the left (taken from a post by Tim Pope). If you “fixed a bug” you should say which bug, and how it was fixed. You might also say (and include in the commit) that a test has been added to check for the bug in the future. 14: Configuring Git To write more involved messages, we clearly don’t want to type them out on the command line! Thankfully git is aware of modern editors, so we just need to make it aware of the one we want to use. The config command allows us to do this, as well as configure color output and so on $ git config --global <key> <value> Hints Git can use the EDITOR environment variable rather than core.editor You can configure git options globally (-global) or locally in a repository (--local) Also see the Git SCM Book and try out some options! 15: Getting Started on Github Our repository is completely isolated at present, so if you want to work with it later on another machine, you need some way of sharing it. Whilst git is completely distributed, we can create a repository to be an authoritative one. We’ll use the GitHub hosting service to do this, so if you do not have an account already, sign up for one now using the link below. Notes Similar hosting services exist for other VCS, so this is not unique to git. 16: Creating a Repository Use the create new repo tool (highlighted below), naming it as you wish and creating a useful description. Make sure it’s public (otherwise you have to pay!) and that the Initialize this repository with a README is unticked and that no .gitignore or license file is selected. We’ll add and see what these are for in a bit. When you’re happy, click the Create Repository button. Notes BE CAREFUL: DON’T create the repository with a README! That will conflict with the README in your repository! We don’t create a .gitignore file for the same reason. If we create it, then our github repo has an initial commit, and can get confused with that in our local repo. 16: Creating a Repository Use the create new repo tool (highlighted below), naming it as you wish and creating a useful description. Make sure it’s public (otherwise you have to pay!) and that the Initialize this repository with a README is unticked and that no .gitignore file is selected. We’ll add and see what this is for in a bit. When you’re happy, click the Create Repository button. Notes All being well, you should see the screen on the left, but we need to take a little detour before we can connect the repository we’ve been working with to our freshly created github repository. 17: Github and SSH Keys Whilst your repository is public, this only means others can browse your repository, but not push to it. In fact at this point, neither can you! The best way to connect to git is via ssh, and to do this we need to create an ssh keypair and make github aware of this. Github provide a very useful help system which walks you through the steps needed to do this, and this is linked below. It benefits from a little adaption, which is described in the notes. Step A Whilst github recommend https, ssh is actually a bit easier to setup, and likely to be more familiar. As you may already have some keys present, you can skip straight to Step 4 on the github page 17: Github and SSH Keys Whilst your repository is public, this only means others can browse your repository, but not push to it. In fact at this point, neither can you! The best way to connect to git is via ssh, and to do this we need to create an ssh keypair and make github aware of this. Github provide a very useful help system which walks you through the steps needed to do this, and this is linked below. It benefits from a little adaption, which is described in the notes. Step B Step 3 can be followed as is, but, it’s useful to create a unique key for github. To do this, use the -f argument to ssh-keygen with the filename you want, or change the output file interactively. 17: Github and SSH Keys Whilst your repository is public, this only means others can browse your repository, but not push to it. In fact at this point, neither can you! The best way to connect to git is via ssh, and to do this we need to create an ssh keypair and make github aware of this. Final Note: You will need to create a keypair on each machine you connect from, so Warwick users will need to repeat these steps back home! Step C Steps 4 and 5 should be followed as is. If you have issues with connecting, you can edit the ~/.ssh/config file and add the stanza Host github.com User git Hostname github.com PreferredAuthentications publickey IdentityFile ~/.ssh/github_rsa if github_rsa is your private key 18: Pushing your Repository to Github Will ssh keys set up, we can return to the repository creation page. Github has actually provided instructions on how to push our local repository to Github: “Push and existing repository from the command line”. We go through the two steps needed in the next couple of slides Notes Of course, if we were starting from scratch again, it would be easier to create the repository on Github first! We’ve done the walkthrough this way to show that you can use git without github! 18: Pushing your Repository to Github First of all we use remote to add our github repository as a remote our our local one. Of course, use the correct details after the git@github.com: to point to your repository! $ git remote add origin git@github.com:<> Notes Use ‘-v’ to list remotes. You can add as many remotes as you want. For example, you could add one of your colleagues repositories, whether local or on github. That would allow you to share changes and updates. Of course, sufficient permissions are needed! 18: Pushing your Repository to Github With a remote added, we simply push our changes to the ‘origin’ using the push command. If your github repository was created with a README.md, then you should pull (see next slide!!) before doing the following push: $ git push -u origin master Notes You must have a clean local repository first! So before you add the remote, commit any local changes first. Note that the commands on the left do everything in one step. If you’ve already added the remote, you don’t need to do it again. ‘master’ is roughly equivalent to ‘trunk’ in SVN. 18a: Fixing Errors when Pushing to Github If you accidentally created your github repo with a README file, you will see an error along the lines of “error: failed to push some refs to ...”. This is due to the remote and local repository not being in sync. To resolve this, we need to pull upstream changes, resolve conflicts, then push back to github. (git pull origin master, fix conflicts, git add, git commit, git push origin master) Notes In general, git will try to be helpful when problems arise by outputting hints on how to resolve issues. Even if you find these confusing, plugging the error message into Google or StackOverflow will provide helpful answers. 19: Pulling Remote Changes For today, we’ll be only working with our local repository and pushing to github. If changes have happened upstream on the github (or other remote), we can update our local repository with this changes using the pull command $ git pull origin master Notes The pull command takes the remote to pull from and the “refspec” of changes. Updates in git can also be done in two steps using the fetch and merge commands. These are good for cherry picking changes. pull will be important in coming weeks! 20: Viewing your Github Repository Github provides a nice web interface for viewing your repository, the files in it and the history of changes. Of course, the command line is usually the core way of interacting with your local and remote repositories, the web based viewer and other GUI tools are very helpful. Of course, similar tools exist for other version control systems! Notes Now we can see the advantage of writing our README in Markdown Github has rendered it nicely for us! There’s plenty more you can do with Markdown, 21: The .gitignore File When you run git status, git will report any files it doesn’t track (“untracked”). In some cases we’ll have files that we don’t want git to track, for example files generated by the build or text editor temporaries, but we may accidentally add them to the repository (e.g. by git add .). To make git ignore these, we’ll add a file named .gitignore in our repository. This contains a list of filename patterns that git should ignore, so open your text editor and write: Notes You can also have a global ignores file. You could have a file named .global_gitignores in your HOME directory. Git can be made aware of this file by setting the core.excludesfile variable to point to it in the global git config 21: The .gitignore File Just like any other file, .gitignore should be tracked by the repository, so add it, commit and push to the origin: Notes Once you’ve pushed to the origin, refresh the webview of the repository on github. You should see the file added! If there are extra patterns you want to ignore, simply treat .gitignore like any other file. For more information, see man gitignore 22: Tagging We’ve seen that in git, commits are described by a 40 character hash. At certain points in development, we’ll want to mark a commit as a usable, stable piece of work. The hashes aren’t an easy way of marking these points, so instead we create a “tag”. Current tags are listed via: $ git tag Notes Tags can have any name, but git convention is ‘vMAJOR.MINOR.PATCH’ for version numbers. “Annotated” tags are the best to use to begin with, as they can take extra info about the tag. Use show to see this info. 22: Tagging Like any other repository entry, tags can be pushed to a remote repository. However, push does not push tags by default. To do this, we have to either specify the tag name or use the --tags argument: $ git push origin v0.1.0 Notes You should always push tags so they appear when others pull from your remote repo (including you!). If you look on your github repository, you should see a ‘1’ next to the “Tags”. Clicking on this will take you an interface where you can download a source archive for you code at the tag! 23: And we’re done That about covers the basic usage of git and github. All of the techniques are applicable to other VCSs you may work with, of particular importance being the writing of good commit messages so you (and your collaborators) know not only what changes were done, but why! As we move through the course, remember to stage and commit your files regularly when you have got something working (you should never commit code that doesn’t work for you!). Use tags at the end of each day to record your work at those points, again, the tag should work! Don’t Forget Resources The Following Slides Describe how to Work With your Repository Outside of Birmingham! I: Cloning Your Repository If you want to work with your repository outside of the Birmingham Workstations, e.g. at Warwick, or on a laptop, then you can simply clone it from github. You will first need to set up ssh keys just as we did earlier and upload the public key to github. The use clone: $ git clone <repo> <dir> Notes If you see any problems here, check your local ssh settings and the public keys on github. You can make changes in your cloned repo without needing a network connection pushing them to github later. II: Homework and Future Weeks... Outside of the course, you can work with your repository as you wish. Birmingham people may just work locally, pushing their changes up to github. Warwick people, or anybody using a laptop can take a clone of your github repository, work on the clone and then push changes up to github. In any case, before next week, make sure you have pushed all your changes to github. Then to begin work again, simply pull the changes into your repository at Birmingham! Homework Whilst the homeworks will concentrate on coding, remember to keep your README file up to date, and make regular commits and pushes. When your homework on pp6calculator is complete, make a tag so we have a reference we can access!