Close modal

Blog Post

Git for absolute beginners

Development
Tue 03 May 2016
0 Comments


GIT has become almost canonical in usage with the adoption of GITHUB and linux development. It's very good solution and handles problems of branching very nicely. Let's show you how to get started.

Setup

Whether you use mac, windows or linux I recommend starting off with the command line client, although source tree has a good GUI client for mac and windows, I recommend starting off with the basics for a more complete understanding. Git is easy to get, it's available via Aptitude/et.al, Brew and windows users can check here .

Using GIT

Cloning a repository

Although we'll discuss creating a new repository below, to start with a repository already created:

git clone <GIT_URL> the_project

This checks out the master branch into a folder called 'the_project'.

Creating a new repository

To create a new git repository, we use the git init command, which when used implicitly creates a new repository within the current folder (it creates the .git folder which basically houses versioning info).

You may also create a new project folder at the same time by specifying

devbox% git init my_project
Initialized empty Git repository in ~/Projects/my_project/.git/
devbox% cd my_project
devbox% git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)
devbox%

There you have it, your first (albeit empty) repository.

Adding files

Let's add a hello world to the project.

devbox% git status
On branch master

Initial commit

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

    Program.cs
    Properties/
    my_project.csproj
    my_project.sln
    my_project.userprefs

nothing added to commit but untracked files present (use "git add" to track)

Ok, so it looks like git has seen our files but they are untracked. Git also tells us that it's 'staging' Initial Commit, above the untracked files, meaning basically anything we shove in is the initial commit. Let's tell it which files we want to track, and check the status.

devbox% git add Program.cs Properties/ my_project.csproj my_project.sln
devbox% git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   Program.cs
    new file:   Properties/AssemblyInfo.cs
    new file:   my_project.csproj
    new file:   my_project.sln

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

    my_project.userprefs

Ignoring files from GIT

We added the source files we needed, one of them is still untracked, we don't really want to version my_project.userprefs, as it's a user IDE file, so what do we do? Easy, let's ignore it, edit the .gitignore file (create it most likely), on linux this can be done in a single line:

devbox% echo "my_project.userprefs" >> .gitignore
devbox% git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   Program.cs
    new file:   Properties/AssemblyInfo.cs
    new file:   my_project.csproj
    new file:   my_project.sln

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

    .gitignore

devbox%

Low and behold it now doesn't show up, however .gitignore is not tracked, and we'd rather like to share this as it determines which files (or patterns) are not tracked. How do we do that? You guessed it, git add .gitignore.

devbox% git add .gitignore
devbox% git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   .gitignore
    new file:   Program.cs
    new file:   Properties/AssemblyInfo.cs
    new file:   my_project.csproj
    new file:   my_project.sln

Comitting changes (or the staged index as it's known)

Great, look at that - we have our first commit ready. At this point I need to point out how GIT works. Unlike some other methods such as CVS, SVN etc, the .git folder is a full repository being able to contain the full revision history and branches (when synced). So it is infact possible (and quite often useful) to commit only to your local 'working copy' (the term for the repository sitting on your machine, as it has a remote somewhere usually).

To that end, first we must commit - to create the point in time our revision is saved (along with a commit message that's courtesously useful) and then push that commit so our changes are sent to the remote/origin (basically the server where the rest of the team or world will access the files). I need to mention at this point (but only to touch on it), that if two people are working at the same time, your commit must be up to date before merging (if they've made changes you'll need to pull those changes first and then re-commit/upload).

Those who use a console editor like VIM have it easy and enter a message here:

devbox% git commit

Will yield an editor like:

Initial Commit.
I added the hello world project and it compiles nicely.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
#
# Initial commit
#
# Changes to be committed:
#       new file:   .gitignore
#       new file:   Program.cs
#       new file:   Properties/AssemblyInfo.cs
#       new file:   my_project.csproj
#       new file:   my_project.sln
#

Pressing save and exit will then show the following:

[master (root-commit) 3fa7106] Initial Commit. I added the hello world project and it compiles nicely.
 5 files changed, 94 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Program.cs
 create mode 100644 Properties/AssemblyInfo.cs
 create mode 100644 my_project.csproj
 create mode 100644 my_project.sln

That's our commit done, check out the history by going:

devbox% git log
commit 3fa71060cbd28e37f6be5fbc5b8d9571ddaf0757
Author: John Appleseed <[email protected]>
Date:   Tue May 3 12:02:16 2016 +1000

    Initial Commit.
    I added the hello world project and it compiles nicely.

Pushing commits (and the remote/origin)

For this step, you'll need a remote repository, there are many ways to get one, even freely. For open source projects GitHub is a great choice. For closed source personal projects atlassian bitbucket will do nicely, and even if you're a company team looking for somewhere to host, you can fairly easily host GitLab yourself or subscribe to one of the professional plans of the above mentioned providors, Assembla offers some free level of repository too. In this example I'll be using GitLab

So far we have only one commit and that's shown there. Now that our precious work is saved, let's immortalise it on the internet by uploading it to our chosen server.

devbox% git push
fatal: No configured push destination.
Either specify the URL from the command-line or configure a remote repository using

    git remote add <name> <url>

and then push using the remote name

    git push <name>

Oh dear, we don't have a remote server! In this example I'll use the instructions provided by gitlab, to gitlab, however only the specifics vary - we'll also use https as it avoids compatability issues, especially with windows and key management.

git remote add origin http://<my_server>/[some_extra_paths]/helloworld.git
git push -u origin master

Now you may be asked to login the first time, but GIT will usually cache your credentials/access where possible unless directed otherwise.

This will show the following output:

Counting objects: 8, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (8/8), 1.96 KiB | 0 bytes/s, done.
Total 8 (delta 0), reused 0 (delta 0)
To http://<my_server>/[some_extra_paths]/helloworld.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

Checking for changes

Well done, we've just pushed our first commit out there.

Let's see if anyone else (or in this case even us) has made any changes that are sitting on the remote but not pulled locally.

To update our local repository without actually changing the source files yet, we use git fetch, think of it like peeking through a door without actually going through; this let's us see what's changed and take any actions if needed.

devbox% git fetch
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From http://<my_server>/[some_extra_paths]/helloworld
   3fa7106..0d0e808  master     -> origin/master

From that rather busy blob of text, we can surmise that yes, indeed there were changes - as running git fetch again would be silently complete with no output. Let's see what's new, a handy usage of the git log command can actually show us changes that are listed remotely but not locally.

devbox% git log master..origin/master
commit 0d0e8080adac00b02bf3a4228a853d3563375975
Author: John Appleseed <[email protected]>
Date:   Tue May 3 12:17:49 2016 +1000

    Added the README.md so that users can be informed about the project before checking it out.

Ok, since we don't have any pending changes - let's pull in what's new.

devbox% git pull
Updating 3fa7106..0d0e808
Fast-forward
 README.md | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 README.md

Now do an ls or dir depending on your OS flavour and see the contents of the project.

devbox% ls  
Program.cs      Properties      README.md       bin         my_project.csproj   my_project.sln      my_project.userprefs    obj

We can now see there's a README.md file sitting in our path (this is a good file to have anyway, it's basically a first port of call for what the project does and is written in the highly portable markdown format supported by most GIT hosting interfaces).

Notes on merging/conflicts.

This has all been pretty clean and smooth, let's change that. When you wish to pull, you cannot have any changes inside your repository - you have three options essetially:

  • Discard them with git reset
  • Commit them locally (can not push until you've accepted any incoming changes)
  • Stash them (set them aside until you 'restore' them later

Mostly you'll use the option to commit or stash, depending if you're ready to send them out yet, it's considered bad etiquette to commit too frequently (although later we'll discuss feature branches and squashing commits during merge requests).

As you know how to commit already here is how to stash with git stash(if you have changes of course):

devbox% git stash
Saved working directory and index state WIP on master: 0d0e808 Added the README.md so that users can be informed about the project before checking it out.
HEAD is now at 0d0e808 Added the README.md so that users can be informed about the project before checking it out.

That brings us back to square one, i.e. a clean working copy ready to accept incoming updates from remote. If you're ready to re-apply those stashed changes then it's quite simple and uses git stash apply which implicitly will restore the last stash (but it can also be specified)

devbox% git stash apply
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")

We'll leave it there for now. This is a lot to process, but hopefully introduces you to the world of GIT, and how truly useful (And necessary) source control is. Next time we'll talk about conflict resolving and branching as the true flexibility of GIT will become apparent.