While a subversion repository typically manages many projects, git is a project-centered technology. For each project I create, I want to be able to manage my local repository such that I can push production-ready versions out to remote servers. For example, several client applications are built using the Istarel Workshop frameworks: When a new stable release is ready, I want to be able to easily deploy that new version to client servers to replace the previous framework release.
Create the remote repository
I first need to create a bare repository on the remote server.
markf$ ssh user@www.istarelworkshop.com user$ mkdir -p git/fw && cd git/fw user$ git --bare init Initialized empty Git repository in /path/to/git/fw/ user$ exit
What exactly is a bare repository? Git generally assumes you want a working repository; that is, an active repository where a whole host of change-related activities will be taking place. But that isn't what I want here. I don't need all the history and file detail that a .git directory usually implies. All I need for this remote repository is the repository itself (i.e., the project files in the state as defined by a push to this remote server).
Inform the local repository
Before I can push to that remote repository on www.istarelworkshop.com, I need to modify the configuration file of my local repository. To show the evolution of our local git repository through this process, here is the initial configuration state in my working repository.
markf$ cd ~/Sites/fw markf$ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true
In order to communicate with that remote repository, the local working repository needs to know about it.
markf$ git remote add workshop ssh://user@www.istarelworkshop.com/path/to/git/fw markf$ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true [remote "workshop"] url = ssh://user@www.istarelworkshop.com/path/to/git/fw fetch = +refs/heads/*:refs/remotes/workshop/*
Create an ssh key
At this stage, remote push to my www.istarelworkshop.com repository will work just fine. However, it will require me to enter my password every time I do so. To simplify future automation of push-related processes, and to lay the foundation for more secure remote interactions, I will create a private/public ssh key.
I create the keys on my local machine and then copy the public part of the key to the remote machine.
markf$ cd ~/.ssh markf$ ssh-keygen -t dsa
Leave the passphrase empty (you will be prompted twice for the passphrase). At this point, I have created a private (~/.ssh/id_dsa) and public (~/.ssh/id_dsa.pub) key. I want to copy the public key to the remote server.
markf$ ssh user@www.istarelworkshop.com user$ mkdir .ssh && cd .ssh user$ vi authorized_keys
Paste the contents of the local public key into ~/.ssh/authorized_keys on the remote server. Note: if the .ssh directory already exists on the remote server, you may only need to append the contents of ~/.ssh/id_dsa.pub to ~/.ssh/authorized_keys.
Deploy to the remote repository
With the preliminary work complete, I can now push the Istarel Workshop frameworks out to www.istarelworkshop.com.
markf$ git push workshop master
Counting objects: 287, done.
Compressing objects: 100% (279/279), done.
Writing objects: 100% (287/287), 165.89 KiB | 84 KiB/s, done.
Total 287 (delta 68), reused 0 (delta 0)
refs/heads/master: 0000000000000000000000000000000000000000 ->
9da9ef18470740afe623966eec4dbf45cd22788b
To ssh://user@www.istarelworkshop.com/path/to/fw
* [new branch] master -> master
The last step is to clone that remote repository so that the framework files are accessible to applications.
markf$ ssh user@www.istarelworkshop.com user$ git clone git/fw fw
Installing git is always a simple procedure, but with MacPorts, it becomes a one line Unix command. I also want to set some key configuration settings for git.
markf$ sudo port install git-core markf$ git config --global user.name "Mark Fenoglio" markf$ git config --global user.email markf@istarelworkshop.com markf$ git config --global color.diff auto markf$ git config --global color.status auto markf$ git config --global color.branch auto
The first two git config commands set important defaults for identifying the author of changes to the repository. The last three commands are to provide color when git presents information in the console.
Istarel Workshop Frameworks
I intend to eventually migrate all my projects to git, but I want to start with the Istarel Workshop frameworks. This will give me a chance to establish some best practices, particularly with respect to deployment. Before I start, I want to remove all of subversion's hidden directories.
markf$ cd ~/Sites/fw markf$ find . -type d -name '.svn' -print0 | xargs -0 rm -rdf
Now I am ready to establish the git repository for my frameworks.
markf$ git init
Initialized empty Git repository in /Users/markf/Sites/fw/.git/
All that I've done at this point is create an empty working directory. Now I need to populate my local repository with the initial snapshot of the project.
markf$ git add . markf$ git commit
When the commit happens, an intermediate file is opened in your designated editor and you should create the commit message there. When that temporary file is saved, git saves the initial version of my project.
In Git, each commit is a product of all the modifications and new files added to the working copy. Unlike with Subversion, where all modified files are assumed to be part of the commit, Git requires you to explicitly add them. Fortunately, there is a handy shortcut for adding everything.
markf$ cd ~/Sites/fw markf$ git add . markf$ git status # On branch master # Changes to be committed: # (use "git reset HEAD..." to unstage) # # modified: controller/IWOrderedListController.php # modified: html/IWRequest.php # modified: html/IWURL.php # modified: navigator/IWNavigator.php # modified: test/Autoload.php # new file: test/html/IWRequestTest.php #
When you add modifications and new files in this fashion, Git also respects its own ignore list.
