Tuesday 26 June 2012

HOWTO: Simple Git Repository

This is by no means a comprehensive guide to the Git version control system but is rather a few of the basic operations that I use to maintain a few small projects and scripts.

It is also worth understanding that unlike svn, git is a peer to peer based version control system where every "client" is a repository in its own right which can also push and pull from a "master" repository as required.

The first thing to do of course is to install git on your server. In my case this will be a PC named "jupiter". You will also require ssh server so we will also install that;

For Debian/Ubuntu/Mint;

$ sudo apt-get install git openssh-server

or for Redhat/CentOS/Mandriva/Suse

$ sudo yum install git openssh-server

I will be assuming that the user account that you logged in as will be the account that has access to the repository. Fine grained user control is not covered in this document.

Before we begin building a repository, we should configure git for our user account (change the following commands to suit own your user details).

$ git config --global user.name "brett"
git config --global user.email "brett_AT_tuxnetworks.com"
git config --global core.autocrlf input
git config --global core.safecrlf true


This will create a ".gitconfig" file in your home directory. Edit this file;

$ vi ~/.gitconfig

Add some aliases to the end of the file;

[alias]
  co = checkout
  ci = commit
  st = status
  br = branch
  hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short
  type = cat-file -t
  dump = cat-file -p


Let's create a test project directory for our base repository and change to it;

$ mkdir -p ~/repository/project

# cd ~/repository/project


OK, now we will create a "bare" repository. You can think of this as the master "shared" repository.

$ git --bare init
Initialized empty Git repository in /home/brett/repository/project/.git/


Do a directory listing and you will see this;

$ ls -al
total 40
drwxrwxr-x 7 brett brett 4096 Jun 26 11:24 .
drwxrwxr-x 3 brett brett 4096 Jun 26 11:24 ..
drwxrwxr-x 2 brett brett 4096 Jun 26 11:24 branches
-rw-rw-r-- 1 brett brett   66 Jun 26 11:24 config
-rw-rw-r-- 1 brett brett   73 Jun 26 11:24 description
-rw-rw-r-- 1 brett brett   23 Jun 26 11:24 HEAD
drwxrwxr-x 2 brett brett 4096 Jun 26 11:24 hooks
drwxrwxr-x 2 brett brett 4096 Jun 26 11:24 info
drwxrwxr-x 4 brett brett 4096 Jun 26 11:24 objects
drwxrwxr-x 4 brett brett 4096 Jun 26 11:24 refs


Surprisingly, that is all that is required on the master repository.

Now, we move to the client which will do the initial code push to the repository.

Note: This can be the same host as the server or a different one altogether. In this case I will log on to a different host which is configured with the same user account details as well as ssh key authorization. 

To save configuring git again on this host, you can simply copy the git config file over from my server "jupiter";

scp jupiter:.gitconfig ~

Create a folder for your project in your home directory;

$ mkdir ~/project

$ cd ~/project


Initialize a local repository, this time without the "--bare" option

$ git init
Initialized empty Git repository in /home/brett/project/.git/


This time if we take a look we will see the directory is totally different than before (on the master);

t$ ls -al
total 12
drwxrwxr-x  3 brett brett 4096 Jun 26 11:23 .
drwxr-xr-x 16 brett brett 4096 Jun 26 11:24 ..
drwxrwxr-x  7 brett brett 4096 Jun 26 11:27 .git


Now we tell our local repository to track the master repository on jupiter;

$ git remote add --track master repo brett@jupiter:repository/project

Note: This command tells git that the branch is the master, and assigns the repository the name "repo". Other guides and examples you come across will generally use the name "origin" in place of "repo" by convention. I use "repo" but you can also have multiple remotes and give them all different names like "staging", "testing", "production" etc.

Of course we will need to have a file to be version managed by git. Create one now;

$ echo "This is my source file" > source.file

Tell git to manage the source file;

git add source.file

The "status" command can be used to see what state our local repository is in;

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached ..." to unstage)
#
#    new file:   source.file

We can see that source.file is a new, uncommited file.

Let's commit it to the local repository now;

$ git commit -m "This is my first commit"
[master (root-commit) 4714b45] This is my first commit
 1 file changed, 1 insertion(+)
 create mode 100644 source.file


At the moment our file is only commited to the local repository. We need to push it to the master;
$ git push --tags repo master
Counting objects: 3, done.
Writing objects: 100% (3/3), 250 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To jupiter:repository/project
 * [new branch]      master -> master

Note: For subsequent pushes and pulls, you may omit the "master" parameter as we configured the repository to track the master branch using "--track master" when we set it up. It is required for the first push though I'm not sure why.

We can take a look at the history using the "hist" alias (we configured that in .gitconfig earlier)

$ git hist
* 4714b45 2012-06-26 | This is my first commit (HEAD, repo/master, master) [brett]


Cool. If we want to "pull" the source out of the repository then use the "pull" command insted of "push"

$ git pull repo

So there you have it, a rudimentary git setup.

Here are a few other commands that are useful;

Cancel an uncommited change;
$ git reset HEAD
$ git checkout


Add a tag;
$ git tag "v1.0"

Push tags;
$ git push --tags repo
Total 0 (delta 0), reused 0 (delta 0)
To jupiter:repository/project
 * [new tag]         v1.0 -> v1.0


Remove a tag;
$ git tag -d "v1.0"
Deleted tag 'v1.0' (was 4714b45)


Push deleted tags;
$ git push repo :refs/tags/"v1.0"
To jupiter:repository/project
 - [deleted]         v1.0





No comments: