As a system administrator, and as a developer, you can and should take advantage of a version control system (VCS). Many exist, and have various features that might lure you into using it. Here at Guru Labs, we make extensive use of Git. As such, I’ve setup Git on my own home server, for keeping track of my dot config files in my home directory, special config files in my /etc directory, and even a DVD inventory application I’m writing using Python using Django.
Now, I’m no Git expert, that’s for sure. So, I won’t be getting into the reasons on why you should or should not setup a VCS, nor will I cover the more intermediate or advanced features of Git. However, setting up a Git repository is easy, and I’ll show how you can manage your own config files using Git.
The latest versions of Debian and Ubuntu, as well as Fedora and openSUSE, all have Git available in their repositories. Third-party packages are available for RHEL, and you can grab a package for SLES at their build service.
Ok, so let’s get Git installed. I’m going to use Git through an SSH server, which means you’ll need to have an already installed SSH server that you can remotely access. Once that is setup, then we will need to run the following on both our remote SSH server, and our local machine. I’ll refer to the remote SSH server as “remote”, the local box as “local” and both machines as “both”. Also, I’ll use the “#” for root commands, and “$” for regular user commands. So, on my Ubuntu systems as root:
both# aptitude install git-core git-doc
You should always install the documentation package, if it exists, when dealing with new software. In this case, the Git developers have done a great job in this area, so you can be more effective in your development.
After installed, we need to setup the repositories. One of the selling features for me with Git, is the fact that a Git repository s 100% self-contained. This means, that if you make some flaw setting it up, or it becomes severely corrupted and you can restore from backup, then all you need to remove is the .git directory recursively, and your repository is gone. No fiddling with config files throughout the system, or running obscure commands. When a Git repository is setup, it creates a .git directory, and it’s all managed there. So, on the remote machine, let’s create a repository in our home directory, where our central repository will be managed:
remote$ mkdir ~/my_repo remote$ cd $_ remote$ git init Initialized empty Git repository in /home/aaron/my_repo/.git/
Now, let’s do the same thing on our local machine. However, I generally deal with source code in my ~/src directory, so that’s where I’ll put my configs:
local$ mkdir ~/src local$ cd $_ local$ git init Initialized empty Git repository in /home/aaron/src/.git/
We have now created two empty Git repositories- one on the remote machine behind SSH, and the other on our local machine. The unique thing with Git, is that it doesn’t follow the standard “server/client” architecture. In other words, there’s no such thing as a “git server” and “git client”. Git was developed by filesystem developers with filesystem attributes in mind. So, instead, we have a remote Git repository we call the “origin” and a local Git repository (I’m not sure if it has an appropriate name. Maybe “git trunk”?). Both are contained in the .git directory. The only difference is, one will be holding the files and directories, while the other will be managing deltas on the files and directories.
So, let’s continue. On the local machine now, I need to start doing my developing. Because my repository is keeping track of local dot config files in my home directory, I’m going to copy my .zshrc file to the Git repository on the local machine:
local$ cp ~/.zshrc ~/src local$ cd $_ local$ git status # On branch master # # Initial commit # # Untracked files: # (use "git add
..." to include in what will be committed) # # .zshrc nothing added to commit but untracked files present (use "git add" to track) local$ git add .zshrc local$ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached ..." to unstage) # # new file: .zshrc # local$ git commit -a -m "initial commit for .zshrc" Created initial commit 0614613: initial commit for .zshrc 1 files changed, 23 insertions(+), 0 deletions(-) create mode 100644 .zshrc local$ git status # On branch master nothing to commit (working directory clean)
So, if you paid close attention, all we’ve done so far is copy my .zshrc from my home directory into my src directory. It’s best practice to get into the habit of running “git status” and “git commit” often. This will prevent any future headache you may encounter. So, upon initial discovery, I find out that I need to add my newly copied .zshrc file. After “git add .zshrc”, I then need to commit it to the branch I’m working on, which in this case is called “master”. As it sits now, the status of my Git repository is clean. So, all I need to do now, is push it to the remote system:
local$ git push ssh://myserver.com/~/my_repo master Counting objects: 3, done. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 671 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To ssh://myserver.com/~/my_repo * [new branch] master -> master
Seeing “master -> master” is a good sign. This is telling me the push was successful, and now my remote SSH server has a copy of my repository. Now, to show that it does in fact exist, let’s remove our .git directory, and clone it;
local$ cd ~ local$ rm -rf src local$ mkdir src local$ cd $_ local$ git clone ssh://myserver.com/~/my_repo Initialized empty Git repository in /home/aaron/src/my_repo/.git/ remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. Receiving objects: 100% (3/3), 671 bytes, done. remote: Total 3 (delta 0), reused 0 (delta 0) local$ ls -a . .. my_repo lcoal$ ls -a my_repo . .. .git .zshrc
Further, check out our ~/.git/config file on our local machine:
local$ cat ~/src/my_repo/.git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote "origin"] url = ssh://myserver.com/~/my_repo fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master
Notice the “remote origin” line. The url is set to our server that we cloned from. This means, that when I want to push my local repository changes to the remote server, I can execute the following instead:
local$ git push origin master
So there it is: setting up a simple Git repository for managing config files. No need for Gitosis, or other “applications” to make it possible. However, this was a simple demonstration, and doesn’t cover allowed users to work on the repository, who can push and who can’t and so forth. But, it does get us started on the right foot.
Happy Git hacking!