Aside

Using Git to manage configuration files & leverage the power of Version Control.


Git for SysAdmins

Introduction : –

Git is used by millions of Software Developers across the globe to manage their code (this post is not about an introduction to Git). While it is a “must have” tool for the Software Developers/Coders, Git can also be a valuable tool for SysAdmins or non-programmers who constantly make changes to various configuration files. A more traditional way to manage configuration files is to take a backup first by appending .bkp or .orig or .date to the file-names. But things can get really complex when there are frequent edits to the files & it can be quite confusing if we have to revert to a particular edit.

We, the SysAdmins, can leverage the power of Git or Version Control to manage our configuration files so that we don’t have to mess with backing up or renaming of the files.

Lab Description : –

To show you how we can use Git to manage the configuration files, I am editing an Apache Reverse Proxy configuration file on the Mac.

So I have created a directory GitConf where I have stored my apache-reverse.proxy.conf file, which I am going to manage using Git without keeping multiple, redundant copies.

root@shashank-mbp /U/a/D/GitConf# ls
apache-reverse.proxy.conf
root@shashank-mbp /U/a/D/GitConf# git --version
git version 2.8.1

Configure Git.

We now have to add our full name & email address to Git so that every commit is associated with the proper identity of the person who is editing the file.

root@shashank-mbp /U/a/D/GitConf# git config --global user.name "Shashank Srivastava"
root@shashank-mbp /U/a/D/GitConf# git config --global user.email your-email-address

Initialise the Git repository.

The next step after configuring Git is to initialise a Git repo which will store & track all the changes made to the file.

root@shashank-mbp /U/a/D/GitConf# git init
Initialized empty Git repository in /Users/admin/Downloads/GitConf/.git/

Add the file to Git.

Now add the apache-reverse.proxy.conf file to version control to start tracking the changes.

root@shashank-mbp /U/a/D/GitConf# git add apache-reverse.proxy.conf
root@shashank-mbp /U/a/D/GitConf# git commit -am "Add apache-reverse.proxy.conf file."
[master (root-commit) e9f5902] Add apache-reverse.proxy.conf file.
1 file changed, 38 insertions(+)
create mode 100644 apache-reverse.proxy.conf
root@shashank-mbp /U/a/D/GitConf# git status
On branch master
nothing to commit, working directory clean

Edit the file.

Now edit the file to see how Git monitors the changes. For this demo, I removed all the comments from my configuration file. Then I issued git status command. This command will tell us that Git has noticed a modified file.

root@shashank-mbp /U/a/D/GitConf# git status
 On branch master
 Changes not staged for commit:
 (use "git add ..." to update what will be committed)
 (use "git checkout -- ..." to discard changes in working directory)

modified: apache-reverse.proxy.conf

no changes added to commit (use "git add" and/or "git commit -a")

Commit the change to the repo.

Now I registered the change to my repository or repo. The key here is to include a meaningful commit message so that it clearly tells you about the change you have made.

root@shashank-mbp /U/a/D/GitConf# git commit -am "Remove unnecessary commits to make conf file more readable."
 [master 8ce9afc] Remove unnecessary commits to make conf file more readable.
 1 file changed, 1 insertion(+), 17 deletions(-)

Check Git log to see the commit history.

Now it is the time for us to check the commit history. Issue git log --oneline command & it will show you the history.

root@shashank-mbp /U/a/D/GitConf# git log --oneline
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.

You can see here that there are 2 commits in the history.

Edit the file again.

I edited the file again & committed the change to my repo. You can see that I gave a clear & meaningful commit message.

I then made a few more changes & pushed the commits.

root@shashank-mbp /U/a/D/GitConf# git commit -am "Change the backend server port."
 [master f2a7201] Change the backend server port.
 1 file changed, 2 insertions(+), 2 deletions(-)
 root@shashank-mbp /U/a/D/GitConf# git log --oneline
 f2a7201 Change the backend server port.
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.
 root@shashank-mbp /U/a/D/GitConf# git commit -am "Change the backend server port again."
 [master 54e7af8] Change the backend server port again.
 1 file changed, 1 insertion(+), 1 deletion(-)
 root@shashank-mbp /U/a/D/GitConf# git log --oneline
 54e7af8 Change the backend server port again.
 f2a7201 Change the backend server port.
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.
 root@shashank-mbp /U/a/D/GitConf# git commit -am "Modify the absolute URL for backend server."
 [master f750197] Modify the absolute URL for backend server.
 1 file changed, 1 insertion(+), 1 deletion(-)
 root@shashank-mbp /U/a/D/GitConf# git log --oneline
 f750197 Modify the absolute URL for backend server.
 54e7af8 Change the backend server port again.
 f2a7201 Change the backend server port.
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.
 root@shashank-mbp /U/a/D/GitConf# git commit -am "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."
 [master ecc4a22] Replace Apache ServerName property with the actual hostname. Was previously set to IP address.
 1 file changed, 1 insertion(+), 1 deletion(-)
 root@shashank-mbp /U/a/D/GitConf# git log --oneline
 ecc4a22 Replace Apache ServerName property with the actual hostname. Was previously set to IP address.
 f750197 Modify the absolute URL for backend server.
 54e7af8 Change the backend server port again.
 f2a7201 Change the backend server port.
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.

Undoing changes in Git.

At this point, I have 6 commits to my file. Now suppose my Reverse Proxy is not working any more because of my last commit which is ecc4a22. The description of this commit says : –

ecc4a22 Replace Apache ServerName property with the actual hostname. Was previously set to IP address.

It means when I changed the ServerName property, the Reverse Proxy stopped working. So, I need to undo this changes. For this, I will use git revert HEAD command.

HEAD means the last commit. So, git revert HEAD essentially reverts/nullifies the last change that was made to the file.

root@shashank-mbp /U/a/D/GitConf# git revert HEAD
[master c5c6c2d] Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."
 1 file changed, 1 insertion(+), 1 deletion(-)

Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."

This reverts commit ecc4a2241bcf87a0afd736d3e555c2e677e7f1e3.

# Please enter the commit message for your changes. Lines starting
 # with '#' will be ignored, and an empty message aborts the commit.
 # On branch master
 # Changes to be committed:
 # modified: apache-reverse.proxy.conf

You can see that the ServerName property is now set to the IP address again.

ServerName 192.168.0.62

One more edit/commit.

I was then asked to use the new SSL key & certificate for my Reverse Proxy server as the existing certificate had expired. So, I edited the file to include the new SSL keys & certificates. Then I committed this change to the repository as well.

root@shashank-mbp /U/a/D/GitConf# git commit -am "Use new SSL keys & certificates."
 [master e4e3124] Use new SSL keys & certificates.
 1 file changed, 2 insertions(+), 2 deletions(-)
 root@shashank-mbp /U/a/D/GitConf# git log --oneline
 e4e3124 Use new SSL keys & certificates.
 c5c6c2d Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."
 ecc4a22 Replace Apache ServerName property with the actual hostname. Was previously set to IP address.
 f750197 Modify the absolute URL for backend server.
 54e7af8 Change the backend server port again.
 f2a7201 Change the backend server port.
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.

So, you can see here that the configuration file points to the new SSL key & the certificate.

SSLCertificateFile /home/shashank/ssl/ca-new.crt
SSLCertificateKeyFile /home/shashank/ssl/ca-new.key

BUT, when I restarted my Apache daemon, I noticed that the new certificate is not valid! So I decided to revert the change. I have 3 options now.

    1. Use git revert HEAD
    2. Use git checkout c5c6c2d
    3. Use git reset --hard c5c6c2d

 

Point # 1 has already been discussed so we will explore other options now.

git checkout c5c6c2d

Now, I have an option to check out the commit c5c6c2d which takes me to the point when I had my reverted the change in which I replaced IP address with the hostname. In other words, my configuration file now points to the old SSL Key & certificate & also the ServerName property is set to the IP address.

root@shashank-mbp /U/a/D/GitConf# git checkout c5c6c2d
 Note: checking out 'c5c6c2d'.

You are in 'detached HEAD' state. You can look around, make experimental
 changes and commit them, and you can discard any commits you make in this
 state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
 do so (now or later) by using -b with the checkout command again. Example:

git checkout -b

HEAD is now at c5c6c2d... Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."

Checking out puts the repository in a detached HEAD state which means there is no any branch where we are working. We can freely make changes to the file & commit those changes. You can see below that the configuration file now contains the reference to the old, working SSL key & certificate.

SSLCertificateFile /home/shashank/ssl/ca.crt
SSLCertificateKeyFile /home/shashank/ssl/ca.key

One thing worth noting here is that the changes committed in the detached HEAD state are not monitored & Git’s garbage control will delete any such commits as per its schedule. So here is the trick! We can create a new branch now where these commits can be stored permanently. It is also a good way to segregate the environments. For example, we can create a branch prod which will contain the working configuration file, ready to be used in Production. It will be a separate branch & we can tweak the file as per our liking. You can see below that the commit history of this branch no longer contains the reference to the commit e4e3124.

root@shashank-mbp /U/a/D/GitConf# git checkout -b prod
 Switched to a new branch 'prod'
root@shashank-mbp /U/a/D/GitConf# git log --oneline
 c5c6c2d Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."
 ecc4a22 Replace Apache ServerName property with the actual hostname. Was previously set to IP address.
 f750197 Modify the absolute URL for backend server.
 54e7af8 Change the backend server port again.
 f2a7201 Change the backend server port.
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.

One thing worth remembering is that you still have all the commits in your master branch. You can go back to the master branch by issuing git checkout master command. But this command will take you back to the last commit e4e3124 which had broken the Apache configuration.

git reset –hard c5c6c2d

Another approach to go back to any commit in the repository is to use git reset.

git reset command changes your repository state to the commit you specify. See below how I have used git reset to change my repository state to the commit c5c6c2d. This commit contains the working configuration file.

root@shashank-mbp /U/a/D/GitConf# git reset --hard c5c6c2d
 HEAD is now at c5c6c2d Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."
 root@shashank-mbp /U/a/D/GitConf# git log --oneline
 c5c6c2d Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."
 ecc4a22 Replace Apache ServerName property with the actual hostname. Was previously set to IP address.
 f750197 Modify the absolute URL for backend server.
 54e7af8 Change the backend server port again.
 f2a7201 Change the backend server port.
 8ce9afc Remove unnecessary commits to make conf file more readable.
 e9f5902 Add apache-reverse.proxy.conf file.

All the commits in the master branch after c5c6c2d will vanish & you can continue to edit the file as & when required.

See the edits.

To see the changes you have made in the file or compare the changes between various commits, you can use git diff command. For example, let’s check what commits we currently have in our branch.

root@shashank-mbp /U/a/D/GitConf# git log --oneline
c5c6c2d Revert "Replace Apache ServerName property with the actual hostname. Was previously set to IP address."
ecc4a22 Replace Apache ServerName property with the actual hostname. Was previously set to IP address.
f750197 Modify the absolute URL for backend server.
54e7af8 Change the backend server port again.
f2a7201 Change the backend server port.
8ce9afc Remove unnecessary commits to make conf file more readable.
e9f5902 Add apache-reverse.proxy.conf file.

Now, I want to see what change I had made between the last commit & ecc4a22. So I will issue this command.

root@shashank-mbp /U/a/D/GitConf# git diff ecc4a22
diff --git a/apache-reverse.proxy.conf b/apache-reverse.proxy.conf
index 3166121..e39791f 100644
--- a/apache-reverse.proxy.conf
+++ b/apache-reverse.proxy.conf
@@ -1,5 +1,5 @@
 
- ServerName reverse-proxy-server
+ ServerName 192.168.0.62
 AllowEncodedSlashes On
 ProxyPreserveHost On
 ProxyPass / http://192.168.0.68:8080

You can see that the difference between the two commits is that ServerName property was modified.

That’s all for this post 🙂 I hope you find the post informative & useful. If there are any suggestions, please let me know through your comments 🙂