Whether it’s code, artwork, or documents… most creatives deal with files. Have you ever made a change to a file only to regret it later? Have you created multiple versions of the same file just by using different filenames? What about when you are sharing and working on a file with someone else?
A brief history of version control
As far back at the 60′s, computer programmers realized there needed to be a way to track and control file changes. These original systems are generically known as “revision control systems” or RCS. The early systems were crude locking and logging style arrangements. One person would lock a file to work in it and then log their changes they made before unlocking it. This wasn’t very handy for collaborative large efforts, so “concurrent version control” (CVS) came into popularity around the late 1980′s. The CVS systems still had the downside of requiring a centralized master file system that tracked everyone’s changes. As an answer to this problem as well as the usability barriers, Linus Torvalds of Linux fame developed Git in 2005.
Git essentially creates a database in your filesystem to track your changes. As you ‘commit’ changes to git, it takes a snapshot of the filesystem along with your notes on what changed. You can then push your database to another git database where others can pull from to get your changes.
Let’s get set up
You’re going to need to be familiar with the command line of your preferred operating system. LifeHacker has a decent primer however I would ignore the suggestion to use Cygwin on Windows. The Windows Command Prompt is plenty sufficient for using Git.
This intro also touches on using GitHub. A GitHub account isn’t required to use Git on your own files, but you may find GitHub rather handy so you may as well create a free profile for yourself.
Next you’ll need to install git. Alternatively, you can install the GitHub app for Mac or Windows. Windows users should consider the the GitHub installer as it also installs some handy utilities that allow you to enter the same command line options as Linux and Mac.
Basic commands: Init, Status, Add, Commit
Open a command line. We have to do some up front configuration if you never used git before. The most important part is telling Git your name and email address:
git config --global user.name <Your Name> git config --global user.email <email@example.com>
OK now we’re ready to go. On Linux or Mac, type ‘pwd’ to see what directory you’re currently in. Use the ‘cd’ command to change to a directory where you won’t mess anything up. Then ‘mkdir’ a directoy called ‘gitintro’ and change into that directory. Next you will enter ‘git init’ to tell Git to set up a new, empty database in your directory.
mkdir gitintro cd git git init
Now what? Well get to work! Create files, edit your files, whatevs. But the sake of demonstration, we’re going to do some fake work. Enter these commands into your command line:
echo "Here's some text" > myawesomefile.txt echo "More words" > anotherfile.txt
This should have created 2 text files in your gitintro directory. Git only watches files that you have told it to track and it is not yet tracking these files. You can tell if you type ‘git status’ in the command line. To have git track a file, you need to ‘add’ them:
git add myawesomefile.txt
If you run ‘git status’ again you will see that git is now tracking that file. For a shortcut you can type:
git add .
…that will add all untracked files in the current directory. The ‘git add’ command isn’t just for new files. It is used to “stage” the next commit. This gives you control over which files are included in your commit. Now when you run ‘git status’ you will see that git is tracking the files and they are staged to be new. We want to take a snapshot of the files in their current original state. So let’s commit the current files to the database and make a little note about the change.
git commit -m "Created these awesome files"
Git will let you know what it has made a snapshot of for this commit. You can run ‘git status’ to see how that looks when there’s no new files changes being tracked. You can also run ‘git log’ to get a list of the recent commits along with their commit messages (this is why commit messages are handy). Now let’s change a file:
echo "Here's some NEW text" > myawesomefile.txt
This changes the contents of the text file. You could have also opened the file in a text editor to make changes. A status check will show you that git has detected that the file has been modified. As a shortcut, if you want to commit all of the staged changes for already tracked files, you can use the ‘-a’ option:
git commit -a -m "Made more changes to the files"
I use this all the time because it combines the staging and commit process but it doesn’t work on brand new files that haven’t been added to the git repo previously. You can have git ignore certain files you don’t want to ever be tracked or staged but that’s outside the scope of this intro.
“Branch early, branch often.”
Branching allows you create a new working copy of the file system without actually copying the files to another directory and creating a whole new repo. It opens a whole new set of possibilities for working with your files without multiple disparate copies floating around. Branching is best explained by a demonstration.
You may have noticed in the earlier commands with Git that it mentions “master.” The master branch is created by default. You can see all of the branches in a repo by running ‘git branch’ … the asterisk indicates which branch you are working in. Let’s create a new branch that starts with the files in their most recent committed state. First run ‘git status’ to see if there’s any outstanding file changes that need to be committed. Then let’s make a branch called “alternate”
git branch alternate
This creates the branch but we must actually switch over to working in that branch:
git checkout alternate
Now let’s create a new file, stage and commit it:
echo "There's a snake in my boots" > woody.txt git commit -a -m "Added woody"
OK so all of this just happened in the alternate branch. Let’s switch over to the master branch:
git checkout master
If you run a directory listing command (‘ls’ on Linux/Mac, ‘dir’ on Windows) you will see the woody.txt isn’t there! Switch over to the alternate branch and check the directory listing again, you will see the file is back. Any changes made in the alternate branch will not affect the master branch. This is very handy if you’re looking to do experimental work or making big changes that you aren’t sure you want in the master branch. Let’s say you’re happy with how the alternate branch turned out and want to merge the work into the master branch…
git checkout master git merge alternate
All done with the alternate branch? Just delete it:
git branch -d alternate
How would a software developer use branching? Here’s an excellent example.
Remotes & GitHub
There’s one last fundamental aspect of git you should be familiar with and that’s remotes. Until now we’ve been only doing things in you local working copy of the files. A remote is another copy of the repository that you can ‘push’ or ‘pull’ to and it’s the primary way developers share files with each other. Remotes are nothing more than a file path or a URL that point to a git repository. We are going to demonstrate remotes with GitHub. First step is to create a new repository on GitHub and call it “gitintro”. The next screen that comes up shows you the URL of your new git repo.
For the sake of keeping this tutorial introductory, select the HTTP option and copy the repo URL. Using this URL will cause Git to ask for your GitHub username and password any time you push your repo to GitHub. The preferred option is using the SSH. But that requires some extra set up and I want to keep things moving along for the presentation.
Now go back to your command line and add a remote to your repo:
git remote add origin <PASTE YOUR REPO URL HERE>
You have now created a remote called “origin” that you can push and pull your master branch to:
git push origin master
Now if you view your repo on GitHub, you’ll see your files and all of your commit history. If you were working with a team of people, each team member could pull from the remote:
git pull origin master
And receive everyone else’s pushed commits!
Forking & Contributing to GitHub
The beauty of GitHub is how much people are sharing their work on it and how easy it makes contributing to improve that work. For example, let’s say you find a project on GitHub that you’re interested in building off of or using. GitHub offers ways to just download the files if you’d like…but what if we want to add something or fix a problem and contribute our work back to the original source? You fork it!
Normally, it’s code you will find but we’re going to mix it up a little bit and use a class syllabus as an example. Go to this page where I’m hosting a public repo and click the “Fork” button in the upper right corner. When the fork is complete you will have instructions from GitHub on how to set up your local working copy (use the HTTP option for now). Before following those instructions I recommend going back to your command line you’ve been working in, changing out of the “gitintro” directory and creating a new working directory:
cd .. mkdir syllabus cd syllabus git init git remote add origin <YOUR GIT REPO URL>
There’s also a handy one-liner to do all this work for you including creating the directory and remote. Don’t be mad at me for not sharing it first, but now you know how it works!
git clone <YOUR GIT REPO URL>
So let’s say you’ve fixed a typo in the text and you really think the original repo you forked from should merge it into their master branch. You simply go to the web page and click the Pull Request button at the top of the page and follow the steps. Essentially, you’re asking that repo owner to pull from your repo into theirs. Hence, “Pull Request.” You could also add a second remote to pull the latest changes from the original repo you forked from. There’s more details here on GitHub.