How may I help you?

The journals of a front end web developer

 

Setting up Git

After using Subversion on my personal projects for years it was about time to switch to something new/different and improved. At work we are using Git, and the advantages over Subversion are many.

The most interesting difference is that you don't need a git server to use git. So having a local only Git repository of your project is perfectly OK. And you can keep it that way for ever or until you decide to share it either to other users, or between you own computers. Recommended reading about Git basics: http://progit.org/book/ch1-3.html.

When moving from my projects from Subversion to Git I did a bit of Googling on the topic and found lots of good stuff. Who da thunk it! The ones that helped me the most are listed below.

Here is the installer I used : http://code.google.com/p/git-osx-installer/

First off, lets create a new local repository with the files we are currently working on. Simply type git init in your base project directory. And voila we have a Git repo that we can commit, stash, branch stuff onto, into and from. For this step, I again turned to the tips on the Git Pro book website: http://progit.org/book/ch4-1.html.

In the terminal window it looks something like this:
~Projects/HelloWorld/>
~Projects/HelloWorld/>
~Projects/HelloWorld/> mkdir web
~Projects/HelloWorld/> mkdir web/css/
~Projects/HelloWorld/> mkdir web/gfx/
~Projects/HelloWorld/> touch web/index.html
~Projects/HelloWorld/>
~Projects/HelloWorld/> git init
Initialized empty Git repository in ~/Projects/HelloWorld/.git/
~Projects/HelloWorld/>
~Projects/HelloWorld/> emacs web/index.html
[Insert rocket science here]
~Projects/HelloWorld/>
~Projects/HelloWorld/> git add .
~Projects/HelloWorld/> git commit -am "Initial commit"
[master (root-commit) 969d8f5] Initial commit
 1 files changed, 10 insertions(+), 0 deletions(-)
 create mode 100644 web/index.html
 create mode 100644 web/index.html~
Shucks. Emacs cleverly backed up the original version of index.html as index.html~ which we don't really want Git to track. So we quickly create a .gitignore-file to match files like that. I found a good writeup about .gitignore over at gitready.com
~Projects/HelloWorld/> echo "*~" > .gitignore
~Projects/HelloWorld/> git add .gitignore
~Projects/HelloWorld/> git commit -am "Added .gitignore"
[master 092b4eb] Added .gitignore
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 .gitignore
~Projects/HelloWorld/>
~Projects/HelloWorld/> rm web/index.html~
~Projects/HelloWorld/> git commit -am "Removed that file"
[master f44b97b] Removed that file
 0 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 web/index.html~
~Projects/HelloWorld/>
Now the project is ready to be shared across the internets so that by the power of the open source community, this app will develop into the new twitter- and/or facebook-killer-app, in time for tea. Better put the kettle on then.

However, there is one snag that we may encounter ( really, there must be thousands of possible snags, but I ran into one). Lets see. First, we upload the .git-directory to a server where others can reach our project.
~Projects/HelloWorld/> scp -r .git user@server:/opt/git/HelloWorld.git
COMMIT_EDITMSG   100%   18     0.0KB/s   00:00
config           100%  213     0.2KB/s   00:00
description      100%   73     0.1KB/s   00:00
..and so on..
Then we tell git that this is not longer just a local repository, but that it has a remote origin:
~Projects/HelloWorld/> git remote add origin user@server:/opt/git/HelloWorld.git
~Projects/HelloWorld/> git remote -v
origin	user@server:/opt/git/HelloWorld.git (fetch)
origin	user@server:/opt/git/HelloWorld.git (push)
~Projects/HelloWorld/>
All righty then. It looks like the project is online. Lets try a bit of editing followed pushing.
~Projects/HelloWorld/> echo "Joimaloi" >> README.txt
~Projects/HelloWorld/> git commit -am "Added more detailed documentation"
[master a3e9ee5] Added more detailed documentation
 1 files changed, 1 insertions(+), 0 deletions(-)
~Projects/HelloWorld/> git push
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 342 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To user@server:/opt/git/HelloWorld.git
 ! [remote rejected] HEAD -> master (branch is currently checked out)
error: failed to push some refs to 'user@server:/opt/git/HelloWorld.git'
~Projects/HelloWorld/>
Oh noes! I can't has push? The reason that this happens, AFAIU, is that when we did the git init we created a non-bare, or a working repository with both the files we actually work on AND the repository with all its magic index-stuff inside the .git directory. This somehow confuses git when pushing to the remote. ONE way fix this, we have to head over to the server where we put the remote repo and and run this magic command mentioned on StackOverflow inside the git-repository.
~Projects/HelloWorld/> ssh user@server
Ubuntu 10.04.3 LTS
Welcome to Ubuntu!
user@server:~$ cd /opt/git/HelloWorld.git/
user@server:/opt/git/HelloWorld.git$ git config --bool core.bare true
user@server:/opt/git/HelloWorld.git$ exit
logout
Connection to server closed.
~Projects/HelloWorld/> git push
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 342 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To user@server:/opt/git/HelloWorld.git
   f44b97b..a3e9ee5  HEAD -> master
~Projects/HelloWorld/>
Another, and much easier solution is to do a slightly different push the first time around. Read slightly more about that on GitHub. So instead of the simple push and the fix above we do this:
~Projects/HelloWorld/> git push -u origin master
Branch master set up to track remote branch master from origin.
Everything up-to-date
Hurray! Success! I can haz a remote git repo!

Now you, and anyone with access to your git repo, can clone it and start pushing code. More information about creating shared repos can be found here on ServerFault and here on Patrick Debois blog.

Here is how you clone your project:
~/Projects/>
~/Projects/> git clone user@server:/opt/git/HelloWorld.git HelloClonedWorld
Cloning into HelloClonedWorld...
remote: Counting objects: 17, done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 17 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (17/17), done.
Resolving deltas: 100% (2/2), done.
~/Projects/> cd HelloClonedWorld/
~/Projects/HelloClonedWorld/> dir
total 16
drwxr-xr-x   6 andreasoverland  1333597109  204 Mar  8 00:00 .
drwxr-xr-x  10 andreasoverland  1333597109  340 Mar  8 00:00 ..
drwxr-xr-x  13 andreasoverland  1333597109  442 Mar  8 00:00 .git
-rw-r--r--   1 andreasoverland  1333597109    3 Mar  8 00:00 .gitignore
-rw-r--r--   1 andreasoverland  1333597109   14 Mar  8 00:00 README.txt
drwxr-xr-x   3 andreasoverland  1333597109  102 Mar  8 00:00 web
~/Projects/HelloClonedWorld/>
So a quick, short version recap:
~/Projects/>
~/Projects/> mkdir RecapProject
~/Projects/> cd RecapProject/
~/Projects/RecapProject/> echo "Quick recap" > README.txt
~/Projects/RecapProject/> git init
Initialized empty Git repository in ~/Projects/RecapProject/.git/
~/Projects/RecapProject/> git add README.txt
~/Projects/RecapProject/> git commit -am "Initial commit"
[master (root-commit) 8f5c019] Initial commit
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 README.txt
~/Projects/RecapProject/> git remote add origin user@server:/opt/git/RecapProject.git
~/Projects/RecapProject/> scp -r .git user@server:/opt/git/RecapProject.git
[files get transferred]
~/Projects/RecapProject/> git push -u origin master
Branch master set up to track remote branch master from origin.
Everything up-to-date
~/Projects/RecapProject/>
And thats about it.
Except of course for all the branching and merging capabilities that are quite remarkable, perhaps even unique in Git. They come into play with larger development project and are very very handy for keeping the quality of the code ship shape. Good luck.
blog comments powered by Disqus
 

Archive