Too Many (small) Git Commits!

While working on your project, you might have made commits for every little change and created a commit history that looks more like an avalanche of information as opposed to a succinct list of the changes.

Keep in mind, all exercises expect you to have run the script to create files using the scripts found on the Set Up Your Environment page.

I didn't push

If you haven’t pushed your changes, you can adjust the commits you created without worrying about causing problems for other collaborators:

  1. Ensure you are on the correct branch and enter: git log --oneline.
  2. For this example, we are going to combine the commits associated with the addition of files 4, 5, and 6. So identify the SHA-1 associated with the commit for adding file 3.
  3. Enter the following: git reset --soft SHA-1, where SHA-1 is the SHA-1 associated with the adding file 3 commit.
  4. Enter git status. You should see files 4, 5, and 6; in the Staging Area (aka ready to be committed).
  5. Enter: git commit -m "Adding files 4, 5, and 6".
  6. Enter: git log --oneline, your commit history should be modified.

Congratulations you just combined a bunch of commits into a single commit! Now, none of the other collaborators will know that you made way too many commits!

I pushed

I know that avalanche of commits looks bad, but it doesn’t need to be permanent. A lot of people unintentionally create problems by trying to use Git to fix something that has already been pushed to the remote.

Instead, let it go (for now) and use the Squash and Merge option when you are ready to merge the pull request. This will reduce that avalanche of commits down to a single snowflake on master!

Tell me why

Reset

Reset allows us to rewind our branch to look like it did at a previous point in history.

One branch, shown first as a single line with HEAD pointed to most recent commit, then shown with HEAD moved back two commits

How Reset Works

When you use git reset you are overwriting one or more of the three trees git uses to manage your work.

Three areas showing working area, staging area, and history

The trees that are overwritten are determined by the mode of reset you use.

  • --soft: The history is overwritten to look like it did at the selected point in time, but the other two trees are untouched. This means the changes you made in the commits between the old branch tip and the new branch tip will be sitting in your staging area.
  • --mixed: The history and the staging area are overwritten, but the working directory is untouched. This means your changes will be waiting in the working directory. This is the default mode of reset
  • --hard: All three trees (history, staging, and working) are re-written to look like the repository at the selected point in time. --hard can be destructive! Modified files that have not been committed will be overwritten by a hard reset.

Visualization of --soft, --medium, and --hard. By each branch, the commits being misplaced by rebase go into staging, working, and history respectively.

Are They Really Gone?

The good news is, git keeps a running log of every commit HEAD has pointed to. You can find this log with git reflog.

A couple caveats though:

  • The reflog isn’t pushed to the remote. So the only place you can access it is in your local repository.
  • The reflog only displays activity for the last 30 - 90 days. 90 days applies to any commit that is currently part of a branch. 30 days applies to commits that are “unreachable” - in other words, they are not currently on a branch.

Important Reminder

The reset command will change the commit history for your project which can cause problems for your collaborators if you have already pushed. Alternatively, revert, a command we use in other exercises, provides a non-destructive method to modify changes made to your repository and should be considered in place of reset when the commit(s) have already been pushed to the remote.

Continue