Harness the Combinatoric Power of Command-Line Tools and Utilities

../Tutorials

Split Changes into Multiple Commits

Bash git

Published August 31, 2024

When working on a project, you might make several changes before you commit. However, these changes might relate to different features or bug fixes. For example, you might change a file to fix a bug, but you might see something else in the file that bugs you, so you fix it while you’re there.

Committing all changes at once can lead to a messy, hard-to-understand commit history or a more complex code review process. Git lets you selectively stage parts of your changes instead of adding the whole file. Using this feature, you’ll get a cleaner history with smaller units of work for peers to review, as well as a chance to deal with any out-of-scope work you still want to keep but commit elsewhere.

In this tutorial, you’ll explore this feature by creating a small HTML project and staging your changes interactively.

What You Need

Git installed on your local machine.

Create a Git project

To start, create a new directory and initialize a Git repository:

mkdir interactive-commit-demo
cd interactive-commit-demo
git init

Then create a basic HTML file called index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Interactive Commit Demo</title>
  </head>
  <body>
    <h1>Welcome to My Website</h1>
    <p>This is a paragraph.</p>
  </body>
</html>

Add and commit the file to your repository:

git add index.html
git commit -m "Initial commit with basic HTML structure"

Now make two distinct changes to the file; change the title and add a new paragraph to the body of the page:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Interactive Commit Tutorial</title>
  </head>
  <body>
    <h1>Welcome to My Website</h1>
    <p>This is a paragraph.</p>
    <p>This is a new paragraph we'll commit separately.</p>
  </body>
</html>

You made two changes to this file, but putting them in the same commit might not be best. For example, the paragraph may be a change you can get approved quickly, but the page’s title might need approval by SEO experts, and you don’t want it to block the publication of the paragraph.

Interactively add lines with git add -p

Use Git’s Interactive mode to add only the lines you need.

Run the following command to start an interactive commit:

git add -p

You’ll see the patch on the screen:

diff --git a/index.html b/index.html
index 7b6e59a..0d63f4e 100644
--- a/index.html
+++ b/index.html
@@ -3,10 +3,11 @@
   <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Interactive Commit Demo</title>
+    <title>Interactive Commit Tutorial</title>
   </head>
   <body>
     <h1>Welcome to My Website</h1>
     <p>This is a paragraph.</p>
+    <p>This is a new paragraph we'll commit separately.</p>
   </body>
 </html>
(1/1) Stage this hunk [y,n,q,a,d,s,e,?]?

Press s to split the patch into separate pieces. The screen updates to show just the title change:

Split into 2 hunks.
@@ -3,8 +3,8 @@
   <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Interactive Commit Demo</title>
+    <title>Interactive Commit Tutorial</title>
   </head>
   <body>
     <h1>Welcome to My Website</h1>
     <p>This is a paragraph.</p>
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?

Now press y to stage the title change. The next change appears, which is the change to the paragraph:

@@ -7,6 +7,7 @@
   </head>
   <body>
     <h1>Welcome to My Website</h1>
     <p>This is a paragraph.</p>
+    <p>This is a new paragraph we'll commit separately.</p>
   </body>
 </html>
(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]?

Press n to skip this change for now. You’ll return to your prompt.

Use the git status command, and you’ll see that there are staged changes as well as unstaged changes:

On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   index.html

Commit the title:

git commit -m "update title"

You’ll see one line added and one line deleted, representing the title you changed:

[main 41d01ad] update title
 1 file changed, 1 insertion(+), 1 deletion(-)

Now, use the same process again to add the paragraph change. Execute the following command:

git add -p

This time, the paragraph change patch appears:

diff --git a/index.html b/index.html
index e0059db..0d63f4e 100644
--- a/index.html
+++ b/index.html
@@ -8,5 +8,6 @@
   <body>
     <h1>Welcome to My Website</h1>
     <p>This is a paragraph.</p>
+    <p>This is a new paragraph we'll commit separately.</p>
   </body>
 </html>
(1/1) Stage this hunk [y,n,q,a,d,e,?]?

Press y to stage the change.

When you return to your prompt, commit the change:

git commit -m "add paragraph"

Verify your commits with git log:

git log --oneline

You’ll see your initial commit along with the two additional ones you made:

bb403d9 (HEAD -> main) add paragraph
41d01ad update title
aaa6f92 Initial commit with basic HTML structure

Using this approach, you were able to split the changes you made to a single file into two separate commits.

Sometimes, the lines may be too close together to use the automatic split feature, but you can manually edit the patch information. Consult the Git documentation on editing patches for more.

Conclusion

Splitting your changes into multiple commits gives you fine-grained control and lets you maintain a cleaner, more logical commit history, making your project easier to understand and manage.