Creating the Perfect Commit in Git

This article is part of our “Advanced Git” series. Be sure to follow Tower on Twitter or sign up for the Tower newsletter to hear about the next articles!

A commit in Git can be one of two things:

  • It can be a jumbled assortment of changes from all sorts of topics: some lines of code for a bugfix, a stab at rewriting an old module, and a couple of new files for a brand new feature.
  • Or, with a little bit of care, it can be something that helps us stay on top of things. It can be a container for related changes that belong to one and only one topic, and thereby make it easier for us to understand what happened.

In this post, we’re talking about what it takes to produce the latter type of commit or, in other words: the “perfect” commit.

Advanced Git series:

  • Part 1: Creating the Perfect Commit in Git
    You are here!
  • Part 2: Branching Strategies in Git
    Coming soon!
  • Part 3: Better Collaboration With Pull Requests
  • Part 4: Merge Conflicts
  • Part 5: Rebase vs. Merge
  • Part 6: Interactive Rebase
  • Part 7: Cherry-Picking Commits in Git
  • Part 8: Using the Reflog to Restore Lost Commits

Why clean and granular commits matter

Is it really necessary to compose commits in a careful, thoughtful way? Can’t we just treat Git as a boring backup system? Let’s revisit our example from above one more time.

If we follow the first path – where we just cram changes into commits whenever they happen – commits lose much of their value. The separation between one commit and the next becomes arbitrary: there seems to be no reason why changes were put into one and not the other commit. Looking at these commits later, e.g. when your colleagues try to make sense of what happened in that revision, is like going through the “everything drawer” that every household has: there’s everything in here that found no place elsewhere, from crayons to thumbtacks and cash slips. It’s terribly hard to find something in these drawers!

Following the second path – where we put only things (read: changes) that belong together into the same commit – requires a bit more planning and discipline. But in the end, you and your team are rewarded with something very valuable: a clean commit history! These commits help you understand what happened. They help explain the complex changes that were made in a digestible manner.

How do we go about creating better commits?

Composing better commits

One concept is central to composing better commits in Git: the Staging Area.

The Staging Area was made exactly for this purpose: to allow developers to select changes – in a very granular way – that should be part of the next commit. And, unlike other version control systems, Git forces you to make use of this Staging Area.

Unfortunately, however, it’s still easy to ignore the tidying effect of the Staging Area: a simple git add . will take all of our current local changes and mark them for the next commit.

It’s true that this can be a very helpful and valid approach sometimes. But many times, we would be better off stopping for a second and deciding if really all of our changes are actually about the same topic. Or if two or three separate commits might be a much better choice. 

In most cases, it makes a lot of sense to keep commits rather smaller than larger. Focused on an individual topic (instead of two, three, or four), they tend to be much more readable.

The Staging Area allows us to carefully pick each change that should go into the next commit: 

$ git add file1.ext file2.ext

This will only mark these two files for the next commit and leave the other changes for a future commit or further edits.

This simple act of pausing and deliberately choosing what should make it into the next commit goes a long way. But we can get even more precise than that. Because sometimes, even the changes in a single file belong to multiple topics.

Let’s look at a real-life example and take a look at the exact changes in our “index.html” file. We can either use the “git diff” command or a Git desktop GUI like Tower:

Now, we can add the -p option to git add:

$ git add -p index.html

We’re instructing Git to go through this file on a “patch” level: Git takes us by the hand and walks us through all of the changes in this file. And it asks us, for each chunk, if we want to add it to the Staging Area or not:

By typing [Y] (for “yes”) for the first chunk and [N] (for “no”) for the second chunk, we can include the first part of our changes in this file in the next commit, but leave the other changes for a later time or more edits.

The result? A more granular, more precise commit that’s focused on a single topic.

Testing your code

Since we’re talking about “the perfect commit” here, we cannot ignore the topic of testing. How exactly you “test” your code can certainly vary, but the notion that tests are important isn’t new. In fact, many teams refuse to consider a piece of code completed if it’s not properly tested.

If you’re still on the fence about whether you should test your code or not, let’s debunk a couple of myths about testing:

  • “Tests are overrated”: The fact is that tests help you find bugs more quickly. Most importantly, they help you find them before something goes into production – which is when mistakes hurt the most. And finding bugs early is, without exaggeration, priceless!
  • “Tests cost valuable time”: After some time you will find that well-written tests make you write code faster. You waste less time hunting bugs and find that, more often, a well-structured test primes your thinking for the actual implementation, too.
  • “Testing is complicated”: While this might have been an argument a couple of years ago, this is now untrue. Most professional programming frameworks and languages come with extensive support for setting up, writing, and managing tests.

All in all, adding tests to your development habits is almost guaranteed to make your code base more robust. And, at the same time, they help you become a better programmer.

A valuable commit message

Version control with Git is not a fancy way of backing up your code. And, as we’ve already discussed, commits are not a dump of arbitrary changes. Commits exist to help you and your teammates understand what happened in a project. And a good commit message goes a long way to ensure this.

But what makes a good commit message?

  • A brief and concise subject line that summarizes the changes
  • A descriptive message body that explains the most important facts (and as concisely as possible)

Let’s start with the subject line: the goal is to get a brief summary of what happened. Brevity, of course, is a relative term; but the general rule of thumb is to (ideally) keep the subject under 50 characters. By the way, if you find yourself struggling to come up with something brief, this might be an indicator that the commit tackles too many topics! It could be worthwhile to take another look and see if you have to split it into multiple, separate ones.

If you close the subject with a line break and an additional empty line, Git understands that the following text is the message’s “body.” Here, you have more space to describe what happened. It helps to keep the following questions in mind, which your body text should aim to answer:

  • What changed in your project with this commit?
  • What was the reason for making this change?
  • Is there anything special to watch out for? Anything someone else should know about these changes?

If you keep these questions in mind when writing your commit message body, you are very likely to produce a helpful description of what happened. And this, ultimately, benefits your colleagues (and after some time: you) when trying to understand this commit.

On top of the rules I just described about the content of commit messages, many teams also care about the format: agreeing on character limits, soft or hard line wraps, etc. all help to produce better commits within a team. 

To make it easier to stick by such rules, we recently added some features to Tower, the Git desktop GUI that we make: you can now, for example, configure character counts or automatic line wraps just as you like.

A great codebase consists of great commits

Any developer will admit that they want a great code base. But there’s only one way to achieve this lofty goal: by consistently producing great commits! I hope I was able to demonstrate that (a) it’s absolutely worth pursuing this goal and (b) it’s not that hard to achieve.

If you want to dive deeper into advanced Git tools, feel free to check out my (free!) “Advanced Git Kit”: it’s a collection of short videos about topics like branching strategies, Interactive Rebase, Reflog, Submodules and much more.

Have fun creating awesome commits!

Advanced Git series:

  • Part 1: Creating the Perfect Commit in Git
    You are here!
  • Part 2: Branching Strategies in Git
    Coming soon!
  • Part 3: Better Collaboration With Pull Requests
  • Part 4: Merge Conflicts
  • Part 5: Rebase vs. Merge
  • Part 6: Interactive Rebase
  • Part 7: Cherry-Picking Commits in Git
  • Part 8: Using the Reflog to Restore Lost Commits


The post Creating the Perfect Commit in Git appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Tooltime: SCM-Manager

If you and your team are dealing with tools like Git or Subversion, you may need an administrative layer where you are able to manage user access and repositories in a comfortable way, because source control management systems (SCM) don’t bring this functionality out of the box.

Perhaps you are already familiar with popular management solutions like GitHub, GitBlit or GitLab. The main reason for their success is their huge functionality. And of course, if you plan to create your own build and deploy pipeline with an automation server like Jenkins you will need to host your own repository manager too.

UnifiedFlow: Git Branching Strategy

Pros

  • Every branches fork from a stable state.
  • Prevent side-effects (defect/ad-hoc/config) from merging develop into feature, release and main.
  • Group stable features according to release plan.
  • Easily remove features from release.

Cons

  • Require optional merge branch if using with Pull-Request. PR will merge the target branch on your feature; may cause unknown side-effects and stall you for days to fix it.
  • Multiple merge conflicts in develop and release.

Getting Started

init: main

fork: main -> develop

Updating Data Files, Commits vs. Pull Requests

For once, I'm wondering a bit if this post can be helpful to somebody else. I believe my context is pretty specific. Anyway, just in case it might be the case, here it is.

My Jet Train project makes use of GTFS. GTFS stands for General Transit Feed Specification. It models public transportation schedules and their associated geographic information.

Simple code: Version control commits

Currently the most popular version control system is git and I'll be writing this based on git and it's functionalities and capabilities.

Git is often seen as a way to enable distributed programming i.e. multiple programmers can work on the same code repository quite easily without disturbing each others work (much). In addition to that just like other VCS's it's also a log of work but to my experience that part is often unfortunately neglected. What I will be focusing this time is the log part because I think it deserves more attention.

Why to create a meaningful log?

The git log should consist from small meaningful changesets where each commit addresses a single problem. By dividing the log to small commits it enables resilient way of working. Being resilient enables simple and fast procedures to rollbacks, reviews, tags, branching etc.

Lets say that a developer is implementing a REST API. The API needs a web layer that receives the HTTP requests, it probably has some sort of logic layer to do data transformations and validations and maybe some calculations and finally it has a data storage where the data is persisted. There are options how to record this work to the log. One option would be to implement the API and record a single commit or squash the commits before pushing the changes to remote so it would become a single commit. Another option would be to record commits every now and then while developing and finally push those commits as is to the remote repository. Yet another way would be to carefully pick what is recorded per commit in order to have a set of meaningful commits that each address a single issue.

Example of the first approach would be something like this:

JGit Library Examples in Java

Introduction

This article will cover the basic methods from the JGit library that you can use to do git actions from Java code.

Introduction to JGit: JGit library is an open-source library under the Eclipse Licence (Eclipse Distribution Licence). This library has very few dependencies and it can be easily integrated into a Java application. It was implemented in Java to handle all the SCM action commands for Git.

Gitless Cloud Systems

In most companies the single largest cost is human resources. However, by leveraging Open Source intelligently, you can significantly reduce this cost, by literally having the entirety of GitHub's user base, working for "free" for your company. This of course is a bit like what investors refers to as "China math", but GitHub has 65 million registered user accounts, most of whom we must assume are developers one way or another. If you intelligently structure your organisation around GitHub, there is literally nothing preventing you from using every single one of these developers as your own company's resource, making you a million times more productive than mega corporations such as Amazon, Facebook, and Microsoft - For a millionth of the cost these mega corporations are paying. But first let's illustrate the problem, such that the solution becomes clear ...

The problem

In one of my previous jobs somebody had cloned an open source git repository, then added its code to our own private corporate cloud's git repositories, for then to start modifying the thing (the horror!) 2 years later it took one of my developers 6 weeks to update the thing to use the latest version as created by its main developer on GitHub, trying to keep as many of our own customisations as possible in the process. Needless to say, but I was furious about the original decision, due to having responsibilities for code quality at this company.

Introduction to Git Flow

Overview

Git Flow is an abstract idea of a Git workflow. It helps with continuous software development and implementing DevOps practices. The Git Flow Workflow defines a strict branching model designed around the project release. This provides a robust framework for managing larger projects.  

Git Flow is ideally suited for projects that have a scheduled release cycle and for the DevOps best practice of continuous delivery. It assigns very specific roles to different branches and defines how and when they should interact. It uses individual branches for preparing, maintaining, and recording releases.

Top 35 Git Commands With Examples

If you are a new or experienced developer, you have to use source control. And good chances are you are using Git to manage your source code. 

And to use Git to its full potential, you need to know Git commands. Here you will learn the most helpful Git commands that will take you from one level to another. 

Git Reset HEAD

Recently, I published a detailed guide about Git reset HEAD. In case you need a downloadable pdf copy, you can get it here.

In this Git HEAD guide, I will explain all about the basics. You will learn about the detached head and how you can reset it with a few simple git commands.

Get a Jump Into GitHub Actions

On January 27, 2021, Angie Jones of Applitools hosted Brian Douglas, aka "bdougie", a Staff Developer Advocate at GitHub, for a webinar to help you jump into GitHub Actions. You can watch the entire webinar on YouTube. This article goes through the highlights for you.

Introduction

Brian Douglas and Angie Jones infographic.

Angie Jones serves as Senior Director of Test Automation University and as Principal Developer Advocate at Applitools. She tweets at @techgirl1908, and her website here

How Do You Delete a Local Branch in Git?

At its core, the branching model offered by Git is intended to help you avoid merging unstable code into the main codebase. Working with branches in Git is a breeze, especially if you’re working with the GitKraken Git client to visualize your repository.

How to Delete a Git Branch Locally Using the Command Line

To delete a local branch in Git using the terminal, you’re going to run the git branch command and pass in the -d flag. Next, you will pass in the name of the branch you wish to delete.

Anypoint CLI With MuleSoft

Introduction

Anypoint CLI is a command-line interface used with Anypoint Platform and Anypoint Platform PCE. Anypoint CLI works with

  • Runtime Manager
  • Anypoint Exchange
  • VPCs
  • DLBs
  • Design Center
  • API Manager
  • Access Management

Prerequisites

  • Download and Install NodeJS
  • Install npm package for Anypoint CLI using the below command.
Plain Text
 




x


 
1
$ npm install -g anypoint-cli@latest



Multi-Module Gradle Configuration With Git X-Modules

Developing an application and a few libraries in parallel could be quite painful.

On one hand, it makes sense to create a separate Git repository (and a separate Gradle project) for each library and for the app itself. Then the libraries and the app would be connected via Gradle dependencies. So if a bug in the app is caused by a bug in one of the libraries, to fix it one has to

Detecting Credentials In Source Code: Solutions Guide

In modern software development, we rely on hundreds, sometimes thousands of different building blocks. The glue that connects all the different building blocks are collectively known as secrets. These are typically API keys, credentials, security certificates, and URIs. These are the modern-day master keys. They can provide access to cloud infrastructure, payment systems, internal messaging, and user information to name a few. Once an attacker has a secret, they can move laterally between systems to uncover additional information and secrets, and because they are authenticated, they look and appear like valid users, making it extremely difficult to detect.

But even having established how sensitive these secrets are and why they should be tightly wrapped, this next statement may surprise you:

How to Use Kotlin to Create a Secure Ktor Application

Today I will be showing you how to use a modern JVM stack to build your own Nano Blogging Service, or nabl. You will be using the Ktor web framework, Kotlin programming language, and securing it with Okta. Your users will be able to sign up/login, as well as browse chronological feeds and post updates without the inclusion of ads.

Often Kotlin is described as a better alternative to Java due to its efficient Java interoperability. This is important as it then allows for you to employ the largest ecosystem of existing libraries written and designed for Java, as well as JVM frameworks in your Kotlin application, or vice-versa. Kotlin also is compatible with Spring Boot, Jersey, Dropwizard, and more. Any framework that is “Kotlin-native” provides high-level language support, additional type-safety, and other competitive advantages. 

Git branch naming conventions

We use git branches at DeepSource to organize ongoing work to ensure that software delivery stays effective. If you use git today, there are high chances that you're either using the famed git-flow or the more recent GitHub flow. Both these workflows depend extensively on using branches effectively — and naming a new branch is something many developers struggle with.

A consistent branch naming convention is part of code review best practices, and can make life much more easier for anyone who’s collaborating and reviewing your code, in addition to using static analysis tools.