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.
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.
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.
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.`
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):
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With