Just about any developer you meet will instantly know what you mean when you talk about Git. Git is what is known as a distributed version control system that is used to track changes in source code during any kind of development. There are a couple of different types of version control systems, but with Git and its distributed model, each developer maintains a local copy of the entire codebase complete with a history of development changes. This has the extraordinary advantage of allowing the developer to view every single change that has been made to the codebase since the second it came into existence. So how do we use it?
There are a lot of different ways to set up Git on a lot of different systems, so I’m not going to go into detail on that aspect. Instead, let’s focus on how to use Git in a typical web development project. When using Git to keep track of the codebase for a live website, the current state of that site will be maintained in what is known as the master branch of the Git repository. A developer that wishes to add a new feature to the site would then make a separate branch for that feature that is based on the current state of the master branch. Here’s how that process works:
git clone
If this is the very first time the developer has made any changes to this site, they likely don’t have a local copy of the Git repository yet. So, the first thing they need to do is clone the repository. This can be done with the following command in a terminal with Git installed.
$ git clone {repo_url} {repo_name}
Depending on the hosting service you use (GitHub, GitLab, etc.), the {repo_url} will vary. There should be an option somewhere in your hosting service to copy the repository URL. The {repo_name} is simply whatever you want your new local copy of the repository to be named. Running this command will create a local copy of the entire repository in the folder where you ran this command. Then, we can really get started.
git checkout/branch
The bread and butter of Git is the ability to fork the existing repository off into a separate branch so that you can work on and test a new feature without any fear of messing up the main code for the site. This is done with Git branching. When starting a new feature, you would enter the following command:
$ git checkout -b {feature_branch}
This command tells Git to go to the branch named {feature_branch}. The –b flag further tells Git that if the branch doesn’t exist, create it. If this branch had already existed, we could have simply run the command without the –b flag to go to that branch.
git add/commit/push
The main workflow when using Git is to add files, commit the changes, and then push them to your hosting service. I like to use the following commands:
$ git status
$ git add .
$ git commit -m “This is a commit message”
$ git push origin {feature_branch}
The command git status will show you the current state of all your files, such as what has been added/modified/deleted. Then, git add . will add all modified files to what is known as the staging area. After that, git commit –m “This is a commit message” will create what is called a commit and associate your message with that commit. Finally, git push origin {feature_branch} will push that commit to your hosting service where it will either be added to an existing merge request or you can create one. A merge request is essentially a list of all of your commits that can eventually be merged into the master branch of your repository when you’re done with your changes.
One of the coolest aspects of merge requests is that they can contain your entire work history for that feature in nicely structured little blocks. This is why it’s important to be strategic about when you commit files. A good strategy is to make multiple commits throughout the life-cycle of your feature work that represents different stages of your process. Hosting services like GitHub and GitLab allow you to view the changes associated with a single commit, so if you were to just commit everything all at once at the end of your work, you’d be left with possibly multiple files of new code with just a single commit message to describe what was done. Instead, you could commit every time you finish a small aspect of your new feature. This leaves you with a merge request that shows a detailed and stepped history of your work from start to finish, and you can jump into any of those intermediate steps and see the changes associated with it. Remember, you may know exactly what you did and what your code is for, but version control is for teams and we need to think about how our code appears to an outside observer.
git pull
Over time, we often end up adding multiple features to a Git repository. So since you already cloned the repository in the past, instead of cloning again, you would want to update the repository to reflect any changes since the last time you used it. Many projects will have multiple different people adding their own changes to a repository over a long span of time. So, you might add a feature to a repo, not touch it for a while, and then come back to find that your co-developers have added their own separate features since the last time you worked on it. This can be solved easily with the following commands:
$ git checkout master
$ git pull
First, we need to make sure we’re in the master branch. Then, we pull down all changes. After that, we can go through the usual process of creating a new branch and adding/committing/pushing until we’re done.
Other commands
There is so much more to Git than what I covered here. When you get into more complex development work that takes more time and touches more files, you may find that the work your co-developers are doing conflicts with the work you’ve done and by the time you try to merge everything seems hopeless. Git has Git rebase for situations like this, and it involves pulling any recent commits from the master branch and placing them at the start of your work. It basically rewrites the history of your branch so that it’s like that work that came after you started was always there to begin with. This often involves manually going through the files where there is conflicting work and choosing what you want to keep. There are also a lot of small-scale but helpful commands that can improve your workflow. You can use Git diff to view the changes you’ve made since your last commit. You can use Git fetch to get all the recent changes without merging them into your branch. You can also use Git log to show the history of commits associated with your branch. Here is a list of even more commands. Use them wisely and your fellow developers will thank you later.