When you start programming, you’ll immediately hear that you should learn Git. That’s good advice. Git is an essential tool in our industry—it’s the most common version control system, and it’s used for managing the codebase in teams of all sizes.
As a person learning to program, you will experience only one part of Git : version control for a solo developer. When you are alone on the project, your daily Git usage can be limited to:
You could experiment with different branches, but this is mostly it. What are the aspects of working with Git that can surprise you once you start working in a team?
First and foremost: the remote repository—origin—will be busy with other developers’ changes. You will not only push your changes, but you will need to get the changes of others too. This will require you to use other Git commands, such as:
git fetch—To get changes from a remote repository, without changing the local working copy
git rebase—To move the whole branch from the place where it started and reapply the changes on top of another commit. This changes the branch history and can cause headaches in case of conflicts, but it allows for keeping history linear.
git merge—Joins two branches. Doing this keeps branch history intact and generates fewer conflicts, but it produces a git tree that is more complicated to follow.
Another command that is often used is
git pull. Depending on your settings, it’s just a combination of:
git merge—the default one, or
git rebase—one you can switch to via setting:
$ git config --global pull.rebase true
If you are a bit lost with the commands I mention above, you can catch up with LearnGitBranching—a great, free course that explains those commands with a visually pleasant interface:
Branches are one of the basic concepts in Git. On a technical level, they are just references to commits, but they are used by teams to organize changes in the repository. One of the common patterns is to have one main branch—often called main, master, or development—which is more or less stable, and new work is done in branches.
Thanks to branches, you can have multiple people working on different features in parallel. As each feature becomes stable, they are merged into the main branch, and the project moves forward.
You can use branches in a solo project, but usually, there is not that much need for it. At most, you can use branches to do some experiments with code and keep changes for picking back up later.
Separate branches are very useful for doing code review. In well-organized teams, every change is read by some other developer besides the author of the change. The goals of doing this:
- catching bugs before they get merged into the stable branch
- keeping another person in the team up to date with changes
- letting developers discuss technical details of implementation
- getting new colleagues up to speed with the team’s guidelines
As a new developer, code reviews are a great way to speed up your learning. And for people on all levels, it’s a great way of keeping code consistent and making sure people can share workloads when needed.
Code review is typically a feature offered by the Git hosting service. Depending on the git hosting provider, this process may be called:
- pull requests—often abbreviated as PRs, on GitHub and many others,
- merge requests—or MRs, on GitLab
When you have many people changing the same codebase, there will be some changes that Git cannot resolve automatically. In those cases, some developers will need to manually integrate changes in one of the branches. When you work in a team, at some point you will need to learn how to do it yourself.
There are some tricks to minimize risk of conflicts:
- using tools to apply code style automatically,
- merging branches fast
- trying to avoid making overlapping changes at the same time as other colleagues
When you join an established programming team for the first time, you may be surprised with how much attention other people pay to what happens in the Git repository. This can be confusing at first, but there is a good reason to care about how the Git history looks. In a programming career, you often have to investigate changes in the codebase done years ago made by people you’ve never met. Thus, having a clear Git history makes a lot of difference in those cases.
A lot has been written about patterns for Git messages. You even have projects to validate commit messages automatically. It would be an understatement to say that people care about how messages are written.
As an example, I provided feedback at work about:
- the length of the first line of the message
- the possibility of making commit message span many lines
- editing work-in-progress messages into one consistent commit message while squashing many commits into one
- the place where the verb should appear in the message
- grammatical “person” (e.g., first vs. third person) and tense used in the message
All that can be a bit shocking when it happens to you for the first time.
Unix has a convention of ending text files with a new line—it works nice when tools like
cat display many files one after another. Most text editors don’t display this newline, but they keep it in the file. If your editor removes the line, Git recognize it as a change and shows the change as:
+++ b/hello @@ -0,0 +1 @@ +Hello \ No newline at end of file
If you add it to the repository, it’s very likely someone will ask you to add the new line there; and change the configuration of your editor.
Good commits are atomic commits: commits that contain all the code changes related to change that is supposed to happen in the project, and nothing besides that. So, for example, mixing some unrelated changes (fixing the login logic and the color of the button) would be breaking this rule.
Why is it important? If you ever need to revert some of the changes, you wouldn’t want to revert more than necessary. So in our example, you don’t need to revert the button's color just because the login logic had to go back to what was there before.
In a team environment, it’s often the more senior people doing the reverts—and they will insist on juniors to commit changes in a way that it will be to do the cleanup if necessary.
Another common temptation is to mix code style changes with meaningful changes in the logic. This can cause the problems discussed above, plus it makes it very likely to cause conflicts.
The person who does a code review of your changes can have no idea about what you are doing and why. The easiest way to get them up to speed is to have your branch tell a story—for example, to have multiple commits with messages like this:
- do some preparation refactoring
- resolve a minor issue in the logic
- implement the main change in the logic
- fix related styling issue
With a branch history, it’s effortless to understand why each of the changes was made.
Some teams have branch naming patterns that you will be expected to follow. Things I’ve seen in projects:
Those things help a lot if you have a project with many people, and it continues for many years.
You shouldn’t publish your passwords, or any other types of secrets. If you add an AWS key, hosting password, ssh key, or anything else to the repository and push it outside, then you should assume this secret is compromised, and it should be recreated. It would be a headache in a private project, but in companies it can be both dangerous and expensive—often there are many integrations that depend on a given secret, and it’s not always documented.
Only removing the value from the repository, or even its history, is not enough—not from the security point of view.
There is no need for us all to see the local settings for your code editor, temporary files created by your operating system, or any other thing not related to the project. You should create
.gitignore files to keep those things away from the repository. I covered it in my last article.
Git is a powerful tool that gives you plenty of options for use in a project. To put some structure to all those possibilities, there are many Git workflows—recipes on how branches should be used in teams. You can find a nice summary of some of those approaches in this article.
Some developers have strong opinions or preferences regarding workflows. As a beginner, or simply as a more practical developer, you don’t have to care that much about them—just use the workflow of your team as a guideline for how things should be done.
Git is a programming tool that solves technical issues. However, it takes on a social aspect as soon as you start working within a team. What surprised you when you started using Git with other people?