Everyone has noticed the buzz around new trends in networking: automation and programmability.While there is a lot of debate going on about whether the new way will eventually push out old-school engineers or if it will subside eventually, it might be helpful to get familiar with some of the tools that this "brave new world" is bringing upon us. As programmability and automation suggest writing some kind of code, it is useful to store this code somewhere. But just storing it is not good enough in our day and age. What you need is a robust and flexible solution to be able to track changes in your code. You need the ability to collaborate with other team members. Even if we are not talking about code as such. If it is change template for router's config. Or a default configuration for your switch or firewall. Ultimately, that is just a text file. And Git is the tool that does it very well.
Git is a software version control software developed originally by Linus Torvalds - the creator of Linux OS. It uses the concept of a repository, which is just a collection of files that are stored together and belong to the same project. The repository can be stored locally or remotely on a server with a capability to be synchronized both ways. If you do changes in your repository locally, you can push them up to the server. If you (or someone else) make changes in files on the server, you can pull the changes down to your local repository.
There are just a handful of main actions that you can perform on a repository—I'm going to list them and then explain one by one in the order they will appear in our story So, the actions are: clone, stage, commit, branch, fork, and merge.
Let's quickly run through some of the steps in a repository life cycle. To make it more relevant to our networking audience, I'm going to suggest a scenario. A team of three network engineers (called Niff, Nuff, and Naff) are looking for a way to effectively store and manage the configuration files for their Cisco devices: switches, routers, and firewalls. So, they set up a local GitLab server, spin up their Linux laptops (of course you can have Git on Windows machines as well), and start optimizing their work.
First things first! The smartest of the three, Niff is elected as an admin of GitLab server and creates a new project on the server, called Netconfigs. By the way, a "project" is just a synonym for repository. He does it on the server, using GitLab's excellent Web GUI. Now is a good time to introduce another term: branch. If you represent the code history as a tree with root being the initial commit, a branch will be just that: a branch of that tree. Initially, there is only one branch in each repository, and it is called "master." In code development, there are situations when you need to modify some part of the program without affecting the main code, for example to test new features or fix bugs. In that case, a new branch gets created and can be modified independently of the main branch of code. For the purpose of our overview, we'll only stick with a single master branch.
Then Niff also adds Nuff and Naff to be project's maintainers, so they all have equal rights to make changes to the files in the repository.
Usually it is a good idea to have a README file in each and every repository that would give some brief details about what this repository is and what it is for. So, Niff also adds this README file. But any changes to repository don't go into it straightaway. At first, the changed files have to be staged. Staging is the process of marking files that have been changed and are candidate to be committed to repository. Committing changes is what actually adds the content to your repository. So, after the README file is created, Niff stages it and commits it to the project. Now the repository is not empty, it has gotten a very useful README file, that proudly says this repository is used by best network engineers to keep their config files.
Now, we'll jump on Naff's laptop and watch what he does for a few minutes. He's got a few switch config files to add, so he starts with configuring his Git software. Before you do anything else with Git, it is a good idea to set up some global configuration. Naff let's Git know who he is by configuring his username and his email address.
git config --global user.name "Naff Naff"
git config --global user.email email@example.com
The next thing he does is clone the remote repository. Cloning is a process of copying the remote repository to your local workstation. But apart from just copying the files, Git also copies all the changes history and keeps a logical link between the local and remote repository, which in this case is called an origin.
Then he is prompted for his username and password, and after successfully authenticating, gets his local copy of the repository:
To make sure everything is there, he checks local folder's content and sees that new folder called Netconfigs was created. This is Naff's local repository. He gets in it and lists the files. At the moment, only the README file is present. One useful thing to do is to check if the repository is fully up to date and has no pending changes. Naff checks that using "git status" command.
The status is good. We are all up to date, and no changes were made. Groovy!
Time to add the files. He copies the files from another folder. But the files are not part of the project yet. If we run "git status" command again, this time the result will be different:
The files are not tracked. Note that git gives you a hint what to do To stage them, Naff runs the next command
git add .
In this command, "." is a wildcard that simply means all files. You can add files one by one or use any OS wildcard masks. For example, you can do a command git add *.conf to only stage all the config files in local folder. Now that files are staged, they have to be committed to the repository to make them stay there permanently. To do that, Naff issues the command
git commit -m "Added files sw1.conf, sw2.conf and sw3.conf"
The -m part of the command adds a mandatory message that contains the information from commit author. If you don't specify the -m key and don't provide a message, Git will drop you into a vim-like text editor by default and let you edit it. That file will then be used as a commit information. It is usually easier and quicker to use the -m key if you don't have lot of info to add to your commit.
Now the project (repository) has some files in it. But they only exist at Naff's laptop, or in other words, in his local repository. Now he needs to synchronize remote repository with the local one. That is done with the push command.
This command pushes the local copy of the repository to the remote server. After successfully pushing, both repositories are now in sync.
Next, Nuff wants to make a change to one of the files. He needs to add a couple of ACL lines. To do that he needs to get a full copy of a repository on his local laptop. And he uses the same command as Naff did. He clones the project.
Now, having a local copy of the repository, Nuff can make changes to files. He edits sw1.conf file. Now the file is changed, but the change is not staged. Meaning, it is not going to be added to the repository yet. Executing "git status" command shows that.
But we already know what Nuff needs to do to make sure his changes are saved and synchronized:
git add, git commit and git push. After doing that, Nuff is all up to date and the repository on the server is also updated with Nuff's changes.
One thing to note here is that each file has a Last commit stamp. The only stamp that changed is the one for file sw1.conf, because Nuff has modified it.
All the other files still have their old commit stamps. Git is very efficient in that it only commits, pushes and pulls the delta between changes, not the entire repository.
But what will Naff see in his copy? Will it have the change that Nuff made? Obviously not, because Git doesn't automatically perform any synchronization. To do that, Naff needs to use another command: git pull. Git pull command pulls the latest version of files from remote repository and checks if they are newer compared to the local ones. If they are, the local files are replaced with new versions.
This command also tells you the summary of the differences between local and remote files. In this case, there was one line added to sw1.conf. However, that might not be too informative. Naff, for example, might want to know who did the change and what was the line added. To show the actual changes, he uses "git show" command. It does exactly that—it shows the change details.
Here, Naff can see that the last change was made by Nuff and he added the line highlighted in green to the sw1.conf file. Everyone is now up to date. Because Niff is using the web GUI of GitLab, he doesn't need to do anything other than refresh the page to see all the latest file versions. Naff and Nuff using the CLI Git have to pull the updates. Now, it is very useful to know who did the change and what it was exactly, but sometimes when the change is quite big and might involve many files being modified, it might also be useful to see what changes have been made BEFORE they are actually committed. And here, "git diff" command comes in handy. Here is an example: Naff modifies both sw2.conf and sw3.conf files and wants to see what he did before committing.
Here, added lines are highlighted in green and removed lines are highlighted in red. This command is used before staging the changes, so it compares the committed and uncommitted files against each other. This is a very handy and visual way to check the changes before they are committed. Naff is happy with his changes and commits them and pushes them to the server. This command can also be used to check if the local repository is not in sync with remote origin (the repository on the server). For example, after Naff made his changes, Nuff has a way to see if his local repository is up to date with the remote one. Or simply put—does Nuff need to pull anything?
And of course, because Naff have committed his changes, there are differences between Nuff's local copy and the origin. So, Nuff does need to pull to be up to date.
There are of course other commands in Git that we didn't touch in this review, but I believe it is enough to get started with Git and any of the Git-based servers, of which there are many. As you can see, the commands are simple and logical and make collaboration on projects very easy and efficient. And here is a quick list of very good resources to help you further with Git:
Git Bash - Git CLI shell for Wndows OS: https://gitforwindows.org/
Git documentation: https://git-scm.com/doc
Wonderful video series by David Bombal on youtube.com featuring Hank Preston, the Cisco's NetDevOps evangelist and automation expert.
Good luck with your source control!