Version Control with
Ben Morgan
Edit Sources Add Files
Log what we did:
“Add foo support”
Compile and Test
Developer
Workflow
Logging via a text file?
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
Managing change and logs
Version Control Systems
Repository
«database»
Files Changes
+- main.cc +- README.txt
1
2->2.1 3 | 4 | 5 2.2 6<--|
7
Working Copy
+- main.cc +- README.txt
Files State
«commit»
«update»
Centralized Version Control
Central Repository My Working Copy
State Files
Your Working Copy State Files
Examples
Subversion CVS
Perforce
Distributed Version Control
“Central” Repository My Working Copy
State
Files
Your Working Copy Files
Examples
Git
Mercurial Bazaar
Repo
State
Repo
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
gitas our version control system, with
github.comacting as our central repository. Why not SVN? It’s slightly more awkward to get this set up and using
github.comallows 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
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!
Notes
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:
1: Project Organization
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
Notes
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
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.
Notes
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
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.
Notes
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
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.
Tips
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
“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!
Notes
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
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
Notes
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”
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!
Try This
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.
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.
Notes
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
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.
Notes
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
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!
Notes
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
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.
Hints
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
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.
Why?
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.
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!
Hints
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>
Similar hosting services
exist for other VCS, so this is not unique to git.
Notes
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.
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.
Notes
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.
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.
Notes
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.
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
Step A
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 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.
Step B
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.
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
which
Step C
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!
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!
Notes
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
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!
Notes
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 [email protected]: to point to your repository!
$ git remote add origin [email protected]:<>
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.
Notes
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
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.
Notes
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)
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!
Notes
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
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,
Notes
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!
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
Notes
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:
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
Notes
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:
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.
Notes
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
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!
Notes
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
Don’t Forget Resources
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!
The Following Slides Describe
how to Work With your Repository
Outside of Birmingham!
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.
Notes
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>
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!
Homework
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!