John McDonnell, July 12, 2012. [twitter] [github]
Octocat, Github's mascot.
Here, we set up a new git repo, add a file, and commit it to the repo.
mkdir /tmp/myfirstrepo cd /tmp/myfirstrepo echo "This is my first file." > myfile.txt git init ls .git # A look at what we've done. git commit -am 'Initial commit.'
Files go through the following stages as you work on your code:
Let's go through an example of this staging business. Here we'll create a new file. All files start out untracked. When we add it with "git add," it becomes staged, ready to be committed.
echo "This is my second file." > myfile2.txt git status # UNTRACKED git add myfile.txt git status # STAGED
If we modify the file, our new changes aren't staged yet.
echo "A change to this file." >> myfile2.txt # MODIFIED git status # STAGED *and* MODIFIED
git diff # Diff between unstaged vs staged changes git diff --cached # Diff between staged changes vs. commit
A commit at this point will commit the file as it was when we added it, without the later changes.
git commit -m "Any guess what gets committed here?" git status
Oops! We made a mistake there, by not adding our new changes into the commit. Fortunately for us, git can rewrite history! If we commit those changes with the "--amend" option, we're actually changing the last commit. We can also change its commit message.
echo "Forgot this file!" > forgot.txt git add forgot.txt git commit --amend -m "Here's a replacement commit message."
What if we accidentally stage something, we can unstage it with git reset. If we have untracked changes to a file that we want to discard, we can reset that file with git checkout. Bear in mind, you will lose those changes forever if you do this!
echo "Don't really need this line." > myfile.txt git add myfile.txt git reset HEAD myfile.txt # Unstage. git checkout myfile.txt # Delete change.
Just go to github's website, make an account, and follow the instructions to create a new repo! Then in your practice repo, type out the following commands:
git remote add origin firstname.lastname@example.org:johnmcdonnell/demo.git git push -u origin master
This is the process you would go through to download the repository on a new computer.
cd /tmp # Using the '/tmp' directory to keep your computer clean. git clone email@example.com:johnmcdonnell/demo.git myclone
Hopefully committing changes is old hat now. The 'push' command is what sends your data back to github.
cd /myclone echo "Changes to our file, in the clone." >> myfile.txt git commit -a -m "Remote changes made." git push origin master
Now we're going to make our own changes, before getting the changes someone else made from github. This will result in a conflict! No big deal, you just fix the file in question, then add and commit. The "-a" in "git commit -a" just means, "automatically add everything I've made changes to.
cd myrepo echo "Changes to our file, in our own repo." >> myfile.txt git commit -a -m "Local changes made." git pull origin master $EDITOR myfile.txt # fix the conflict. git commit -a git push origin master
In essence, a commit is a snapshot of the files stored in a tree, with some other metadata as well, such as the author and date.
One important piece of metadata is the "parent," which is the preceding commit that was changed to make the present commit.
The default branch is "master." If you don't ever touch branches, master will always point to the most recent commit.
HEAD can be thought of as a designtor for the "active" branch. By default, HEAD points to master. In this diagram, master points to the snapshot "f30ab".
If you type the following:
git branch testing
You will create a new branch pointed at the same commit that the HEAD branch is pointed to (here, master).
When you use the "checkout" command on a branch, as here:
git checkout testing
...you move HEAD to point to that branch. If that branch is on a different commit than your current HEAD branch, this also changes all the files in your directory to reflect that branch's snapshot.
If we make changes to branch "iss53", then also make changes to master like so:
git checkout master git commit...
We may want to merge these changes together, pulling the changes we made in iss53 into our master branch.
To do this, just check out "master" then type:
git merge iss53
If there were no conflicts, this should merge "cleanly." The ability to branch and merge so effortlessly is a key feature of git!
The following is an example of how a Psychologist might want to use these features in coding an experiment.
Imagine we're working on code for a Psychology experiment. We've just run a pilot experiment, and now we want to deploy two more experiments based on that first experiment manipulating different variables.
First we should tag our existing experiment so we can find it again later.
git tag -a pilot -m "Our initial pilot experiment"
Then we make new branches, and add our new manipulations to each:
git branch exp1 git branch exp2 git checkout exp1 echo "Exp 1 makes manipulation A" >> myfile.txt git commit -a -m "Added manipulation A" git checkout exp2 echo "Exp 2 makes manipulation B" >> myfile.txt git commit -a -m "Added manipulation B"
Now imagine we realize there's a bug in our code! With git, we can fix the bug just once, and apply it to both of our experiments. First we fix it in master:
git checkout master $EDITOR myfile.txt # Make an important bugfix git commit -a -m "Important bugfix"
...and then check out each of our new experiment branches and merge in the new changes in master:
git checkout exp1 git merge master git checkout exp2 git merge master git diff master # the only difference now is our exp2 manipulation.
Maybe at this point we want to take a look at our pilot again and see if the bug caused problems there. Thanks to our tag, taking a second look at the pilot is easy:
git show pilot # if we just want to see the note. git checkout pilot # to actually check out the snapshot.
I hope this example lets researchers see how git can be useful for their own projects.
You may want to use the following commands to configure git once you install it:
git config --global color.ui "auto"
git config --global user.rame "Your Name"
git config --global user.email "firstname.lastname@example.org"
git config --global core.editor "mate -w"
git config --global credential.helper cache