Step-by-Step with Git: Advanced Commit Strategies

Let’s use a practical example to guide us through this process. By the end of this tutorial, you'll understand how to commit changes selectively, review modifications, and manage staged and unstaged changes.

Step-by-Step with Git: Advanced Commit Strategies
Photo by Farhat Altaf / Unsplash

In this post, we’ll dive deep into advanced committing in Git. We'll explore how to create and merge local commits effectively while maintaining clarity and organization in your codebase. Let’s use a practical example to guide us through this process. By the end of this tutorial, you'll understand how to commit changes selectively, review modifications, and manage staged and unstaged changes.

This post takes a more hands-on approach to mastering advanced Git commits. Rather than diving into theory, we'll explore practical examples to show how to create, manage, and refine local commits effectively in real-world scenarios. Let's get our hands dirty with Git!

1. Setting Up the Playground

We begin by setting up a sample Git repository to demonstrate advanced committing techniques.

1.1 Reviewing the Project Directory

Let’s first list the contents of our project folder:

$ ls -la 
total 9 
drwxr-xr-x 1 CZC1PR 1049089  0 Nov 30 09:18 ./ 
drwxr-xr-x 1 CZC1PR 1049089  0 Nov  9 09:27 ../ 
drwxr-xr-x 1 CZC1PR 1049089  0 Dec  1 08:46 .git/ 
drwxr-xr-x 1 CZC1PR 1049089  0 Nov 30 09:18 devops/ 
-rw-r--r-- 1 CZC1PR 1049089 32 Nov 30 09:12 README.md

The repository contains:

  • A README.md file.
  • A devops/ folder for Jenkins job examples.

1.2 Creating a Temporary Folder

For this session, let’s create a new tmp/ folder and add two files:

$ mkdir tmp
$ touch tmp/file01 tmp/file02

Verify the contents:

$ ls -la tmp/ 
total 0 
drwxr-xr-x 1 CZC1PR 1049089 0 Dec 12 08:35 ./ 
drwxr-xr-x 1 CZC1PR 1049089 0 Dec 12 08:34 ../ 
-rw-r--r-- 1 CZC1PR 1049089 0 Dec 12 08:35 file01 
-rw-r--r-- 1 CZC1PR 1049089 0 Dec 12 08:35 file02

2. Adding Content to Files

Add content to these files using the echo command:

$ echo "This is new file #1" > tmp/file01
$ echo "This is new file #2" > tmp/file02

Check the contents of the files:

$ cat tmp/file01
This is new file #1

$ cat tmp/file02
This is new file #2

3. Staging Changes

3.1 Initial git status

Run git status to see the current state of the repository:

$ git status
On branch main 
Your branch is up to date with 'origin/main'. 
Untracked files: 
  (use "git add <file>..." to include in what will be committed) 
        tmp/

3.2 Adding the tmp/ Folder to Staging

Add the folder to the Git repository:

$ git add tmp/

Now, check the status again:

$ git status 
On branch main 
Your branch is up to date with 'origin/main'. 
Changes to be committed: 
  (use "git restore --staged <file>..." to unstage) 
        new file:   tmp/file01 
        new file:   tmp/file02

3.3 Committing the Staged Changes

Commit the changes with a meaningful message:

$ git commit -m "Added tmp folder with initial files"
[main 891defa] Added tmp folder with initial files 
 2 files changed, 2 insertions(+)
 create mode 100644 tmp/file01
 create mode 100644 tmp/file02

4. Making and Staging Changes Selectively

4.1 Modifying file01

Add a new line to file01:

$ echo "This is new line for file #1" >> tmp/file01

Verify the content:

$ cat tmp/file01
This is new file #1
This is new line for file #1

Check the status:

$ git status 
On branch main 
Your branch is ahead of 'origin/main' by 1 commit. 
Changes not staged for commit: 
  (use "git add <file>..." to update what will be committed) 
        modified:   tmp/file01

4.2 Using git diff

View the differences:

$ git diff
diff --git a/tmp/file01 b/tmp/file01 
index 350b4fc..6335f6d 100644 
--- a/tmp/file01 
+++ b/tmp/file01 
@@ -1 +1,2 @@ 
 This is new file #1 
+This is new line for file #1

5. Selective Commit with git add --patch

Now let’s modify file02 to demonstrate selective staging:

$ echo "This is new line for file #2" >> tmp/file02

Run git diff again:

$ git diff
diff --git a/tmp/file01 b/tmp/file01 
@@ -1 +1,2 @@ 
 This is new file #1 
+This is new line for file #1
diff --git a/tmp/file02 b/tmp/file02 
@@ -1 +1,2 @@ 
 This is new file #2 
+This is new line for file #2

5.1 Interactive Staging with --patch

Use the --patch option to stage changes interactively:

$ git add --patch
diff --git a/tmp/file01 b/tmp/file01
@@ -1 +1,2 @@
 This is new file #1
+This is new line for file #1
(1/1) Stage this hunk [y,n,q,a,d,e,?]? y

diff --git a/tmp/file02 b/tmp/file02
@@ -1 +1,2 @@
 This is new file #2
+This is new line for file #2
(1/1) Stage this hunk [y,n,q,a,d,e,?]? n

5.2 Checking Staged and Unstaged Changes

Check the status:

$ git status
Changes to be committed:
        modified:   tmp/file01

Changes not staged for commit:
        modified:   tmp/file02

5.3 Committing Changes

Commit the staged changes:

$ git commit -m "Updated file01 with additional line"

6. Best Practices for Advanced Committing

  • Use git add --patch to stage changes selectively.
  • Keep commits small and focused on a single purpose.
  • Write descriptive commit messages to improve project traceability.
  • Use git diff and git diff --staged to review changes before committing.

Conclusion

Selective staging and advanced committing in Git are invaluable tools for managing complex projects. By breaking changes into logical commits, you make your history cleaner, debugging easier, and collaboration smoother. With practice, you’ll master these techniques, elevating your Git workflow to the next level.

Read next

Annotated vs. Lightweight Tags in Git: Which One Should You Use?

Git tags are crucial for marking important points in your repository's history, such as version releases. But not all tags in Git are created equal. There are two types of tags you can use: annotated and lightweight tags. Understanding the differences between these tags is vital.

Using Git Tags to Mark Version Releases

Git tags are an essential part of software versioning and release management. They allow you to mark specific points in your repository's history as important milestones, such as a version release. Unlike branches, which continue to evolve over time, tags are immutable and serve as fixed pointers.

Pros and Cons of Squashing Commits in Feature Branches

In the world of software development, maintaining a clean commit history is essential for collaboration and future maintenance. One of the effective ways to achieve this is through squashing commits. This technique allows developers to condense multiple commits into a single, cohesive commit.