Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How best to squash old commits

Tags:

git

git-squash

A developer recently left who left a ton of commits in a repo from a few months ago that are just like 'updated'. Ideally, I'd like to squash them into a single commit but I have only done this for recently commits.

How would I do it for like the following commits (assuming the from 2 months ago means that there are hundreds of these)?

.... from 2 months ago

aabbcc updated
aabbdd updated
aabbee updated
aabbff updated

Not wanting / needing anything fancy, just a simple solution. These commits haven't been publicly shared (other than with me today) so no issue of upsetting other people's commit history.

like image 879
timpone Avatar asked Jan 11 '16 23:01

timpone


People also ask

Is squashing commits a good idea?

As a general rule, when merging a pull request from a feature branch with a messy commit history, you should squash your commits. There are exceptions, but in most cases, squashing results in a cleaner Git history that's easier for the team to read.


3 Answers

In order to do a git squash follow those steps:

// X is the number of commits you wish to squash
git rebase -i HEAD~X

Once you squash your commits - choose the s for squash = it will combine all the commits into a single commit.

enter image description here


You also have the --root flag in case you need it

try: git rebase -i --root

--root

Rebase all commits reachable from <branch>, instead of limiting them with
an <upstream>.

This allows you to rebase the root commit(s) on a branch.  
When used with --onto, it will skip changes already contained in `<newbase>`   
(instead of `<upstream>`) whereas without --onto it will operate on every 
change. When used together with both --onto and --preserve-merges, all root 
commits will be rewritten to have `<newbase>` as parent instead.`
like image 53
CodeWizard Avatar answered Oct 14 '22 02:10

CodeWizard


I know that this is already an ancient question but I needed a solution for this.

Long story short, my local git repo (on NFS, no upstream) works as a back up to certain files and I wanted it to have a maximum of 50 commits. Since there are many files and the backups are taken rather often, I needed something that automatically squashes the history, so I created a script that both backs the files up and squashes the history.

#!/bin/bash

# Max number of commits preserved
MAX_COMMITS=50

# First commit (HEAD~<number>) to be squashed
FIRST_SQUASH=$(echo "${MAX_COMMITS}-1"|bc)

# Number of commits until squash
SQUASH_LIMIT=60

# Date and time for commit message
DATE=$(date +'%F %R')

# Number of current commits
CURRENT_COMMITS=$(git log --oneline|wc -l)

if [ "${CURRENT_COMMITS}" -gt "${SQUASH_LIMIT}" ]; then

    # Checkout a new branch 'temp' with the first commit to be squashed
    git checkout -b temp HEAD~${FIRST_SQUASH}

    # Reset (soft) to the very first commit in history
    git reset $(git rev-list --max-parents=0 --abbrev-commit HEAD)

    # Add and commit (--amend) all the files
    git add -A
    git commit --amend -m "Automatic squash on ${DATE}"

    # Cherry pick all the non-squashed commits from 'master'
    git cherry-pick master~${FIRST_SQUASH}..master

    # Delete the 'master' branch and rename the 'temp' to 'master'
    git branch -D master
    git branch -m master

fi

So, what the script basically does is (I removed the back up part):

  1. If there are more than 60 commits, it squashes all the commits from 50 to 60+ into a one commit.
  2. It creates and checks out a new branch based on the commit
  3. Cherry picks the remaining commits from the master (#1 to #49) to the branch
  4. Removes the master branch
  5. Renames the new branch to master.
like image 5
jxcr0w Avatar answered Oct 14 '22 01:10

jxcr0w


The age of the commits doesn't matter, squashing commits is squashing commits.

If rebasing isn't preferable for you, or there are literally thousands of commits that you want to squash and can't be bothered with it, you could just reset softly to the first commit hash and re-commit everything:

$ git reset aabbff 
$ git commit -m "This commit now contains everything from the tip until aabbff"

You would then only have one commit, the same as rebase -> squash.

like image 4
scrowler Avatar answered Oct 14 '22 03:10

scrowler