Know Your Git


I've been praising Git for about as long as I've been using it. I've been wanting to write about it for several months now, but these is already a whole lot of information out there, tutorials on nearly every tech site you can think of, and I think it's really something you cannot learn about or really see the benefits of without hands-on experience. It also seems pretty intimidating when you look at all of the commands it has to offer, so I want to begin this post by making it perfectly clear that there are some excellent GUI clients available that should be more than good enough for most users.


The Command-Line version of Git



This post will be about the full, command-line version of Git though. If your prefer something a little prettier with buttons and all of that instead of typing commands into a terminal window, there is probably a button to click. So, when I say something like git push, just look for this instead . There are too many clients available and on too many Operating Systems. Plus, once you get used to it, nothing beats the command-line version of Git!

What is Git?


So, those of you unfamiliar with Git would now be wondering just what it is that I won't seem to shut up about. To say that Git is a distributed VCS probably wouldn't answer the question for you since it requires knowing what Git is in order to understand what that means.

Git provides several features that are universally valuable to programmers:
  • It records changes to files along with a description you give.
  • It can be used to help you focus on a given feature or bug without fear of breaking your stable/production code.
  • It allows for you to revert files individually or in batch.
  • Your description of changes can be viewed as a log of your work.
  • It provides an easy means to synchronize and distribute code.
  • It serves as a medium for collaboration without working on the same copy and without emailing files back and forth.

There is a whole lot more that Git does, and there are some creative applications for things it was never really meant to do. In it's simplest form however, Git records changes to files, allows you to revert to any state which it has recorded, and provides an easy method of distributing your work.

The basics

These are the basic commands you will need to learn. There aren't too many, and they are rather self-descriptive.

  • git init
    Create an empty Git repository or reinitialize an existing one

  • git clone
    Clone a repository into a new directory

  • git status
    Show the working tree status

  • git diff
    Show changes between commits, commit and working tree, etc
  • git log
    Show commit logs

  • git add
    Add file contents to the index
  • git stage
    Add file contents to the staging area
  • git commit
    Record changes to the repository
  • git push
    Update remote refs along with associated objects
  • git pull
    Fetch from and integrate with another repository or a local branch

That might seem like a lot of commands for just the basics, but it really becomes simpler and clearer in a full example rather than just as a list and description.

A whole lot of this is output. I am giving a full example here, and the majority of the information can safely be ignored. Mostly, pay attention to the lines beginning with $.
$ indicates a command entered.
# indicates a comment.
# Change directory to wherever you want project to exist 
$ cd /path/to/project

# If the project exists elsewhere, clone it.
# Otherwise, if you're starting from scratch, initialize it
# with "git init"

$ git clone git://github.com/shgysk8zer0/chriszuber.git

Cloning into 'chriszuber'...
remote: Counting objects: 5948, done.
remote: Compressing objects: 100% (213/213), done.
remote: Total 5948 (delta 103), reused 0 (delta 0)
Receiving objects: 100% (5948/5948), 4.35 MiB | 752.00 KiB/s, done.
Resolving deltas: 100% (3465/3465), done.
Checking connectivity... done.

# View the current status of the repository
$ git status

On branch master
nothing to commit, working directory clean

# View the log to see recent changes
$ git log
commit {some random seeming string of characters}
Author: Chris Zuber <shgysk8zer0@gmail.com>
Date: Thu Dec 18 00:50:14 2014 -0800

Commit summary

Detailed commit message
...

# Make a change
$ vim index.html

# Type, type, type...

# Create a new file
$ touch new_file.js

# Check the status again
$ git status

On branch 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: index.html

Untracked files:
(use "git add <file>..." to include in what will be committed)

new_file.js

no changes added to commit (use "git add" and/or "git commit -a")

#See detailed difference of changes
$ git diff -- index.html
diff --git a/index.html b/index.html
index 6d823fd..df10f38 100644
--- a/index.html
+++ b/index.html

@@ -1,9 +1,10 @@
+ {added lines}
- {deleted lines}

# Aside from the + & - lines, most of this is not very useful
# for now.
# Now let's prepare our changes with either stage or add

$ git stage index.html
$ git add new_file.js

# Check status once again
$ git status
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: index.html
new file: new_file.js


# All modifications are prepared, now to commit
$ git commit
{commit summary}

{commit message goes here}
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# modified: index.html
# new file: new_file.js


# Next, get any changes that occurred while working
$ git pull

Already up-to-date.

# Nothing changed. If there were changes, they would have
# been merged with my changes automatically.
# And finally, to submit my contributions!

$ git push

Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 310 bytes | 0 bytes/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To git@github.com:shgysk8zer0/chriszuber.git
0c847f2..798348c master -> master

This was a fairly detailed example, but the process is short and simple

  1. Clone or initialize repository (only needs to be done once).
  2. Create or edit some files.
  3. Stage and commit your changes.
  4. Push back to remote repository (generally a good idea to pull first).

Some slightly more advanced stuff

One of the greatest strengths of Git is working with branches. Think of branches as deviations from your trunk code. By default, all repositories have a branch named master. Master is supposed to be your main branch, and branches are meant to created temporarily for working on new features or fixing bugs before being merged into master. Example follows:

# From master branch, create a new branch named "feature/1"
$ git branch feature/

# Creating a branch like this does not switch to it
# automatically. You need to do a "checkout"
# You can also use "git checkout -b feature/1" to do both steps
# at once, but I'm giving another full example here


$ git checkout feature/1

Switched to branch 'feature/1'

# Now, make changes as needed.
$ vim some_file.ext

# type, type, type
#
# Stage, commit as needed like above code example
# While on this branch, all changes are being made to
# the branch named "feature/1" and not to master, so you
# do not need to worry about breaking anything. Once
# you checkout master again, it will be exactly as you left it!


$ git checkout master

Switched to branch 'master'

# Now we are back on our master branch and ready to merge our
# changes. If the attempt at whatever feature or bug fix
# failed, we could instead either reset feature/1 or delete it.
# That's another example for another time, however. We're
# going to assume the edits were good and mere into master

$ git merge feature/1

Updating 5b59625..fe59801
Fast-forward
index.html | 1 -
1 file changed, 1 deletion(-)

# The output of this gives you a brief summary of changes,
# including which files changed and how many lines were
# changed in each.
#
# Once completed with the work, we may now push our
# master branch

Tips for ease-of-use and productivity

  • Create branches often and work on those. Keep your master branch intact!
  • Come up with a naming scheme for branches. I.E. a category (feature, bug) prefix followed by a / and then a number (works well combined with Issues on GitHub).
  • Create branches for specific purposes. No generic branches, and keep work done on them specific to that purpose.
  • Make your commits related and relevant — work on one thing, commit your changes, then move on to the next.
  • Be brief in your summaries but verbose in your commit messages. Just like in documentation, you will want to use this for future reference, and a detailed commit message allows you to know what changes were made and for what purpose.
  • In short, be purposeful and verbose with your commits!

I hope that you found this post useful. I plan on writing about some more advanced features of Git in the near future. Until then, if you would like to learn more about Git, there is a free eBook available from the Git website. The website also contains quite a bit of documentation.

I have found Git to be one of the most useful tools I have ever learned, and it is the one thing that I can take with me even if I switch to an entirely new project in a new language. It can help new programmers dealing with the stress of breaking something and not knowing how to fix it, and it can help experienced developers deal with organization.