An introduction to using Git and GitHub for revision control.
After participating in part 1 of this intro, you should be able to:
-
Create a new repository in GitHub
-
Edit a text file using the GitHub browser interface
-
View a file’s history and find out who changed what lines
-
Clone a repository to your local desktop
-
Edit files in your desktop and commit locally
-
Fix typos in commit messages
-
Push changes from your desktop to GitHub
-
Ignoring files
-
Understand the problems with editing both in desktop and GitHub
-
Fix problems caused by editing in both places
-
Making releases
In the time available, we won’t be able to cover these topics. A follow-on class will address these.
-
Forking a GitHub repository
-
Submitting pull requests
-
Responding to pull requests
-
Participate in a Shared GitHub Repository (not forked)
-
Branching and merging
-
Rebasing and rewriting history
-
Using the stash
-
The GitHub issue tracking system
-
The Wiki associated with a GitHub repository
-
Git workflows
Git is a revision control system that was created in 2005 to support the Linux project, replacing an earlier non-free, commercial system. It is designed to be fast, simple, free, and to support parallel development by many distributed developers. In addition, it supports both small and very large projects equally well.
GitHub is a cloud-based hosting service since 2007 for Git repositories. It supports all the features of Git and adds new, web-based features such as issue tracking and Wikis.
A revision control system keeps track of your files over time, retaining all versions of each file and allowing you to see the history of changes. You can see what was changed when, and see the details about exactly what was changed.
The Git revision control system essentially keeps track of snapshots of your files over time. And any point you can recover an older version or see what changes you made.
In addition, a revision control system acts as an online back of your files. Cloud-based revision control systems such as GitHub back up your files on remote servers, aiding in disaster recovery.
-
High performance
-
Local copy of entire history
-
Ability to work off-line
-
Support for large projects and many collaborators
You can use Git with other online hosting providers. Some popular providers are:
-
GitHub—Free for public repositories
-
BitBucket—Provided by Atlassian, free for repositories with 5 or fewer developers.
-
SourceForge—Popular free repository, supports other revision control systems, too.
Most GitHub repositories are publicly available, to promote sharing, and can be viewed in a web browser. You can also search for repositories using the search box at the top of the GitHub page. As an example, let’s search for “RobotsForKids.”
Each result shows both the user name (RobotGarden
, for example) and the repository name (RobotsForKids
). You can click on either part, to see all the repositories for that user, or to see only the repository.
If we go to a repository, we see a list of files and directories in that repository, plus the contents of a "`README'" file, if it exists.
Many things are clickable on this page:
- File names
-
go to that file to view contents and history, or to edit the file on GitHub
-
get notified of changes
-
add to your starred repositories (favorites), accessed by Your stars menu item in upper-right dropdown
- Issues
-
link to issue tracking system
- Wiki
-
link to Wiki pages for this repository
- Settings
-
change repository name, add collaborators, delete repository, and more
- commits
-
see all changes
- branch
-
see branches, separate lines of work
- releases
-
access released versions
- contributors
-
see all who have made commits
In addition, there are other buttons for getting information or manipulating the repository:
On GitHub, any directory may have a README file. If it does, the contents of that file are shown when navigating into the directory on GitHub. The README file may have any of these names:
README.md
-
A formatted README file using Markdown syntax. (Most common on GitHub.)
README.asciidoc
-
A formatted README file using Asciidoc syntax. May instead use the
.adoc
extension. (My favorite. Used to write the Git user manual.) README.txt
-
A plain text README file.
README
-
A plain text README file.
Recommendation: Create either README.md
or README.asciidoc
in the root directory of every repository. Learn enough of either Markdown (.md
) or Asciidoc (.asciidoc
) syntax to write useful documentation.
Repositories usually also contain a license file, usually called LICENSE
, although this is not required. There is a good reason for this: in the USA, if you create any written document, it is automatically copyrighted (unless you specify otherwise) and all rights are reserved to you. Therefore, unless you provide a license, no one can reuse your work, unless they break the law. (If you publish in GitHub or other repository where there are “Terms of Service” agreements, you probably are granting certain rights automatically, however.)
Recommendation: Add a license file to the top of every repository. Use the license that most appropriately describes how others may reuse your work.
Choosing a license is beyond the scope of this class, but here are a few ideas:
-
For code repositories, the most popular licenses are:
-
Commercial-friendly: Apache, BSD, MIT, and LGPL
-
Commercial-restricted: GPL
-
-
For text and artwork repositories, the most popular is the Creative Commons license.
-
If you want to put your work in the public domain, use something like the Unilicense.
There are other options, too. Perl uses the Artistic License, the Eclipse organization uses the Eclipse Public License, and the Mozilla organization uses the Mozilla Public License. The only license I’d recommend against is the Eclipse Public License, because lawyers at two firms I’ve worked for would not allow us to use any library using that license. Also see sites like http://choosealicense.com/ for more information.
In a browser, log on to your GitHub account and in the search box at the top type "`arduino'" and press Search. There should be tens of thousands of results, but the first should be called arduino/Arduino
. Click on it to go to that repository.
-
Does the repository display README information below the list of files? If so, what format is it written in, Markdown (
.md
) or Asciidoc (.asciidoc
)? -
Go to the README file and show its history. When was the last change in 2014?
-
Show the “blame” history for the README file. Who last modified line 20, and when?
-
What is the latest release of the Arduino repository, and when was it released?
-
What license does the Arduino project use?
-
Go to the file
arduino-core/src/cc/arduino/Compiler.java
. What line was changed on October 26, 2015?
When viewing a text file, you can click the edit button to begin editing the file within the browser. When you are finished editing you can either press cancel
to abandon your changes or scroll to the bottom of the page where you can fill out the “Commit Changes” form to commit your change to the repository.
Normally you should type a short description in the first line (recommended no more 50 characters) and a longer description, if needed, in the large text box. Then press the "`Commit Changes'" button to finish the commit. You can also commit to a new branch, but that is beyond the scope of this introduction.
When editing text files, such as the README, you will normally use one of the two main lightweight markup syntaxes, Markdown or Asciidoc. You can choose either. Both Markdown and Asciidoc allow you to type plain text which will be converted automatically into HTML to render in the browser. They also support special conventions for adding section headers and text formatting.
There are a lot of features in both which we won’t cover here, but here is a very brief cheat-sheet.
Markdown | Asciidoc | Result |
---|---|---|
# header ## header ### header ... |
= header == header === header ... |
document title, section header, subsection, etc. |
Blank lines delimit paragraphs. Like this. |
Blank lines delimit paragraphs. Like this. |
Blank lines delimit paragraphs. Like this. |
some **bold** text, *italic* text, and `code`. |
some *bold* text, _italic_ text, and `code`. |
some bold text, italic text, and |
Indent lines to make them code blocks sum = a + b diff = a - b |
Indent lines to make them code blocks sum = a + b diff = a - b |
Indent lines to make them code blocks sum = a + b diff = a - b |
A bulleted list: * one * two A numbered list: 1. first 1. second |
A bulleted list: * one * two A numbered list: . first . second |
A bulleted list:
A numbered list:
|
Note
|
Asciidoc requires a blank line after headers, while Markdown does not. |
You can also press the New File button to add a text file to the repository. You will be able to edit the contents of the new file immediately. Use a file extension of .md
or .asciidoc
if you want GitHub to render the file as HTML content automatically.
To complete the file addition, fill out the commit form at the bottom of the page just as you would when editing an existing file.
-
Using your GitHub account, create a new repository.
-
Add a README file to your repository, using either Markdown or Asciidoc format, and add a descriptive paragraph, a section header, and another sentence or two. Then commit the changes.
-
Create a new file called
events.md
(orevents.asciidoc
). Add to the file a list of major US holidays. Then commit the change. -
Edit the README file, adding a line that says to look at the events page for major holidays, and commit the change. (For extra credit: figure out how to create a hyperlink to the events page from the README page.)
-
What is the commit ID for the commit in which you added the README file?
The GitHub GUI is handy for creating and editing documentation files in Markdown or Asciidoc format, but has a lot of limitations. In particular, you cannot add binary files such as images. But also, if you are writing code you want to edit the files locally, not on GitHub. For that reason you need a Git client. The two clients we will use are SourceTree, a GUI client, and the Git command line client.
For this class you should use either SourceTree or the command-line Git client. (You can try both, if you’re ambitious.)
SourceTree is a free product from Atlassian, the company that makes the Jira issue tracking system, the Confluence Wiki, and the Bamboo continuous integration server software. It requires a free registration after 30 days of use. (I have not had any spam from them after registrating, but YMMV.)
Download and install SourceTree from the SourceTree site:
The first time you run SourceTree it will prompt you to connect with an exsiting repository account.
Select GitHub from the dropdown account list and enter your credentials. Then press Continue. (You can choose to skip this step for now, if you prefer.)
You will then be asked if you want to "`Clone'" your first repository from your remote account.
Select the repository you created earlier. SourceTree will suggest a default directory location for the local copy. Change it if you like. Then press Continue. You should then see the SourceTree window for your repository:
There are several parts to this window:
- Left sidebar
-
Allows you to switch between the branch view and the working copy, or to switch branches, among other things.
- Top button bar
-
Allows you to pull or push changes to the remote server, among many other things.
- Commit list
-
Shows all commits.
- Commit details panel
-
Details the commit selected in the commit list.
Before you make changes using SourceTree, it’s important to configure your name and email address to accompany your commits. Go to the Preferences dialog and enter your name and email in the boxes shown:
While you are there, you may want to go to the Update tab and turn on automatic checking for updates to SourceTree.
The Git command-line client can be downloaded, for Windows and OS X, from the Git web site:
For Linux, it is better to use the package manager for your Linux system. (And Git may already be installed.) For example, for Ubuntu you could install Git via:
sudo apt-get install git
Once installed, the first thing you should do is configure your name and email address. (See https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup)
$ git config --global user.name "John Doe" $ git config --global user.email [email protected]
The Git configuration is stored in a file called .gitconfig
, usually in your home directory. It is a text file that you can edit, although it is safer to use the git
command to change settings.
Note
|
You can view all your settings through the command
git config --global --list . There is also a --local configuration file specific to a single repository. Local configurations override global configurations.
|
The Git command line will spawn an editor to edit commit messages. On Linux this is nano
, by default, a newer, popular editor for Linux configuration files. If you don’t want nano
, or if you are using Windows, you will need to configure your editor. For example,
C:\Desktop> git config core.editor notepad
or
$ git config core.editor vim
To use your GitHub repository locally, you must clone it. First, go to your repository in GitHub and copy the URL using the button: .
Then, in a shell or command window, move to the parent directory where you want to clone your repository. Clone it by using the git clone
command:
git clone https://github.com/your-user-name/repository-name
In SourceTree, when looking at the master
branch, you see a complete list of changes that have been made. You can click on any change to see details of what was changed in each file.
You’ll notice that the selected view in the left sidebar is master under Branches. This is because we are working on a single branch, which is by default called master.
From the command line, you use git log
to see changes.
$ git log commit 3a668e2600c4f8285590782998555056c5a96afb Author: Mark Rose <[email protected]> Date: Thu Dec 10 14:35:42 2015 -0800 Added more class materials. Clarified what is covered, improved references, and added information on viewing a Git Repository. commit 5d5a238e3cbe51a87de418832d980a049ccd744f Author: Mark Rose <[email protected]> Date: Thu Dec 10 02:18:00 2015 -0800 Added the initial version of the class materials, and updated the outline in the README. commit 688626bccdd665f01a52158fcf8c348a35f5e239 Author: Mark Rose <[email protected]> Date: Mon Dec 7 11:28:12 2015 -0800 Converted to Asciidoc format. Added Makefile for creating local HTML previews through asciidoctor. commit 328c44121fa576e4580806a55d93bcf78588ebef Author: Mark Rose <[email protected]> Date: Mon Dec 7 09:27:01 2015 -0800 ... $
And if you want to see the actual changes, you have to use the commit ID, such as 5d5a238e3cbe51a87de418832d980a049ccd744f
. Thankfully, Git allows you to use at least the first four characters, such as 5d5a
. This command will show the changes between the last two commits—in other words, the latest changes.
git diff 5d5a 3a66
There is also another shorthand: HEAD
means the latest commit, HEAD~1
means one before the latest, HEAD~2
means two before, etc. So this command is equivalent to that above:
git diff HEAD~1 HEAD
From within SourceTree, the Menu option Help > SourceTree Help launches a window allowing you to navigate through the available SourceTree documentation. Other menu items allow you to ask questions, raise issues, or request a new feature.
In addition, there is a SourceTree/Git tutorial, also listed in Other Resources, above.
Git has built-in command-line help which is pretty good.
git help
gives general information about command-line options and available commands.
git help command
gives help on a single command.
For example, here is an excerpt of help for the git clone
command:
$ git help clone GIT-CLONE(1) Git Manual GIT-CLONE(1) NAME git-clone - Clone a repository into a new directory SYNOPSIS git clone [--template=<template_directory>] [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>] [--dissociate] [--separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--recursive | --recurse-submodules] [--] <repository> [<directory>] DESCRIPTION Clones a repository into a newly created directory, creates remote-tracking branches for each branch in the cloned repository ...
In addition, I have found this cheet-sheat helpful. And the Pro Git online book is a detailed introduction to all aspects of Git.
The files in your repository are stored in three different ways. First, a working copy is stored as normal files. The layout exactly matches what you will see on the GitHub server.
Second, after you make changes to a file you must stage the changes before committing. This copies the file to a staging area. If you change your mind before commiting, you can unstage the file as well, deleting the staged copy.
Finally, you can commit changes from the staging area to the local repository. The local repository is a complete copy of what is on the GitHub server, except for any changes you have not yet pushed to the server, or any changes made on the server that you have not yet pulled to your local copy. Any other users working in the same repository will also have a complete copy of all versions.
Note
|
The staging area and local copy of the repository are stored in a .git directory. You should rarely, if ever, manipulate any of those files directly.
|
To make changes to a file, simply edit it. (Or copy a new file on top of it.) There is no “checkout” process in Git—all files are always editable.
Once you edit a file or create a new file you will see a number after the Working Copy link in the left sidebar. This shows how many files have been changed or added, but not yet committed. If you go to that view, you see the files in the Unstaged area.
If you have made changes and don’t yet see them in the Working Copy view, use ^R
or Command-R to refresh the view.
You can move files back and forth between the staged and unstaged areas by using the checkboxes, or dragging, or right-clicking and choosing a menu option, or by using ellipsis menu button . Once you are satisfied with the changes you can commit them by clicking in the Commit message box and filling out the commit form:
From the command line there are several commands that do the equivalent of the various SourceTree panels.
Command | Purpose |
---|---|
|
Shows the status of the working and staging areas |
|
Shows the changes that have not yet been staged |
|
Shows the changes that are already staged |
|
Adds a file to the staging area |
|
Unstages a file without losing changes |
|
Discard changes in a modified file in the working area |
You can also use a shorthand: git add -A
adds all new files, changed files, and removed files to the staging area.
You’ll notice if you do git status
that it shows the branch we are working on in the first line of output.
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: README.md no changes added to commit (use "git add" and/or "git commit -a") $
Once you stage the files to be committed, you perform the actual commit via the command git commit
. There are two forms.
git commit -m "your commit message"
-
Commits with the given message
git commit
-
Spawns your configured editor to edit a commit message, and commits when you exit the editor
You can commit once or many times locally, but eventually you will want to synchronize your changes with the copy on GitHub. In SourceTree, to push your changes, press the Push button . You will be asked which branch to push, but this will default to master, the only branch. Once you click OK
, any local commits not present on the server will be pushed to GitHub. Afterward, you will see that the local master branch is on the same commit as origin/master
and origin/HEAD
, which are the SourceTree indications of the remote (GitHub) state.
You can see the list of remote locations corresponding to your local repository (equivalent to the Remotes list in the SourceTree sidebar) via:
$ git remote -v origin https://github.com/merose/git-class-test.git (fetch) origin https://github.com/merose/git-class-test.git (push) $
To push the local changes to the remote:
$ git push origin master
This pushes to the remote named origin
any changes on the master
branch that are not present in the remote repository.
If your repository is for code, then you will probably create files during a build that you don’t want to commit. You may have entire directories, such as build
or target
which should not be commited. To make Git ignore these files and directories, you can create a special file called .gitignore
.
If there is a file in your Working Copy that is showing as changed, but should not be commited, right-click on the file and select Ignore. You will then get a dialog box allowing you to select whether to ignore just that file, all files with that extension, etc. SourceTree will write the .gitignore
file for you.
-
Install SourceTree or the Git command-line tools, if not already installed. Then clone the repository you created in Exercise 2.
-
Edit the README file, adding this new content:
## Feelin' Groovy Slow down, you move too fast, you got to make the morning last, just kickin' down the cobblestones.
-
Move the README file to the staging area and commit the changes. Verify that the log shows a new commit.
-
Push the new changes to the remote on GitHub. Verify that the local master branch and the origin/master branch are in synch.
-
Create a new file called
hello.md
with this content:# Hello, There This is a test of the emergency broadcast system. If this had been an actual emergency, you would have been informed where to tune...
-
Add the new file
hello.md
to the staging area. -
Modify
hello.md
again, adding this new section:## Another Section When in the course of human events, it becomes necessary...
-
Notice that there is now a copy in the staging area, with the original content, and also a copy that is not staged, with the newer content. Add the newer copy to the staging area.
-
Commit the changes.
-
Edit the README file and modify the text as follows:
Old text:
just kickin' down the cobblestones.
New text:
just kickin' down the cobblestones, lookin' for fun and feeling groovy.
-
Stage the changes to the README and commit. You should notice that your local repository is now 2 commits ahead of the remote.
-
Push both commits to the GitHub origin. Verify that both the local master and origin/master are on the same commit.
To remove a file, you can simply delete it. After this, you must stage the removal, either in the SourceTree Working Copy view or using git add file
(kind of counter-intuitive).
Alternatively, from the command line you can use git rm file
from the command line. This removes the file and stages it in one step.
To rename a file it is a little trickier. If you just rename using the shell, the file explorer, or the finder, Git—and SourceTree—cannot tell the difference from a remove and an add. So you must tell Git or SourceTree to rename the file for you.
- Renaming a file in SourceTree
-
In the Working Copy view, change the view from Pending files, sorted by path to All files, sorted by path by clicking and selecting All files. Then, right-click on the file and select Move…. You can then type a new name for the file.
Renaming a file in the command line:
Use git mv file newname
. This tells Git to rename the file and stage the change.
Normally, you should either edit files locally or on GitHub, but never in both places. However, it’s easy to forget and make changes both locally and remotely. If you do this without synching, you will cause the two locations to diverge. In that case, you will have to merge the changes, sometimes using manual edits.
-
Edit a file locally, commit changes, but don’t push to the origin.
-
Edit the same file remotely, on GitHub.
-
In SourceTree, click the Fetch button. Or, from the command line, use
git fetch
.
At this point the local master branch and the origin/master branch both have changes. The two lines have diverged. You can see this in SourceTree as a fork in the commit list.
From the command line, git status
tells you the same thing:
$ git status On branch master Your branch and 'origin/master' have diverged, and have 27 and 2 different commits each, respectively. (use "git pull" to merge the remote branch into yours) nothing to commit, working directory clean $
In SourceTree, use the Pull button to pull the remote changes into your local master branch. If Git can determine that the changes don’t overlap, it will merge them automatically.
If Git/SourceTree cannot merge the changes automatically, you will get this warning:
Once you click OK, you can see that the changes listed show both changes, bracked by <<< and >>>, and separated by ===.
You can edit the file in a text editor or launch an external merge tool, if you have one configured. On OS X, if you have XCode installed, SourceTree will automatically use the XCode merge tool. Otherwise you can install the free tool P4Merge on either OS X or Windows. You can invoke the merge tool by right-clicking on the conflicting file and selecting Resolve Conflicts > Launch External Merge Tool.
Once you resolve the conflicts, stage the change and commit. SourceTree will suggest a commit message, but you can edit it.
-
On your local machine, edit the README file, adding this text to the bottom:
## Our Land This land is your land, this land is my land...
-
Commit the change to your local repository, but do not commit to the remote.
-
On GitHub, edit the README again, adding this to the bottom:
## Hobo Go to sleep my weary hobo, let the towns drift slowly by.
-
Commit the change on GitHub.
-
In SourceTree, fetch remote changes by pressing the fetch button, , and clicking OK. Or, from the command line, use
git fetch
and thengit status
. -
As you can see in the commit list for the master branch, the two development lines are split. You must merge the changes on the server. Either use the Pull button, or click Merge and then select the commit on the server to merge into your local Master. Or, from the command line, use
git merge origin/master
._ -
Resolve the conflicts and commit.
-
Push the changes to the remote on GitHub.
Sometimes you make a commit and then want to change something, such as a typo in the commit message. If you have not yet pushed your changes to the remote, you still have a chance to amend the commit.
In SourceTree, select the menu option Repository > Interactive Rebase. (The reason it is called rebase is because editing a commit is a subset of what you can do through the rebase features of Git, which are beyond the scope of this intro.) From this dialog you can do any of these things:
-
Double-click on a commit to change the commit message.
-
Select a commit and combine with the prior commit by pressing Squash with previous.
-
Delete a commit.
-
Reorder commits by dragging them around. (This can cause merge conflicts that you will have to resolve!)
Why would you want to squash commits together? Some say never, but others like to structure the commits they push to the origin to match intent rather than fact. So you may make many small commits while you are developing, but squash them together into a smaller number that reflect the features you are adding rather than the order you did work.
For code repositories, and sometimes for other repositories, it may be beneficial to package a snapshot up as a ZIP or tar file and make it available for downloading. GitHub has a feature that performs this operation. From the main page of your repository, click the releases link. You should get this page.
At this point, click Create a new release. You should get this form for assigning a tag to the release.
Enter a tag with a version number, such as v1.0
. You can also indicate that the release is a Prerelease by checking a box at the bottom. When you click Publish release, GitHub will create two packages, a .zip
file and a .tar.gz
file containing a snapshot of the current repository state. As well, it adds your tag to the repository, which you can see in the commit list in SourceTree or by using git tag
.