Question

The project I'm working on requires that all feature contributions be single commits, but I still like to commit my progress along the way, so I usually squash my commits as I make them.

Let's say I'm making my first new commit on the branch:

git commit -am "Added new feature"

From then on, until I submit my changes, I will do:

git commit -am "asdfasdasd"
git rebase -i HEAD~2

...and then squash my commits in interactive rebase.

I do this 10-20 times a day, and it just seems like a disproportionately high number of keypresses for the seemingly-simple effect I'm trying to get. Is there a better/faster/easier way to get the same results? If there's no single magic command to do this, then I guess what I'm looking for is the most efficient way. to pop off the most recent commit from the history (without discarding the changes it contains!), and just commit again, which would include the changes from the popped-off commit, as well as the working changes.

Was it helpful?

Solution 2

Use git commit --amend -am "message goes here" (or --amend -a—usually the previous commit message is a good starting point—or even just --amend after manually adding, etc). The --amend takes this git commit history:

...-o-X-Y   <-- branch

and in effect does a "soft reset" to make the label branch point to X so that the new commit's parent is again X, resulting in this commit history:

        Y   [no label, but still in reflog as branch@{1}]
       /
...-o-X-Z   <-- branch

When you do your commit-and-rebase you get, first:

...-o-X-Y-Z   <-- branch

(the new commit), then:

        Y-Z   [no label, but still in reflog as usual]
       /
...-o-X-Z'    <-- branch

where Z' is the squash-commit of Y and Z. So these are different, but for your purposes, probably equally useful.

OTHER TIPS

Squashing feature work into a single commit is of dubious value. Some trimming of unnecessary churn is useful. You lose important information about why each change was made and wind up with a possibly single large difficult to review blob. Part of the point of version control is so that five years later somebody can answer the question "why is this line here" and squashing loses that information. If people don't like reviewing lots of changes they can get the squash effect with git diff feature master without losing future information. But you probably can't control that.

To mitigate this problem, take the simple expedient of working on your feature in a branch. This is something you should be doing pretty much always to avoid messing up master and pushing partially completed work on other people. Work normally, commit normally. When your feature is complete, only then squash when merging.

  • git checkout -b feature/whatever
  • ...work and commit normally...
  • git checkout master
  • git merge --squash feature/whatever
  • git commit

This way you have all the benefits of a feature branch while you're working, and can still follow the squash policy.

Is there a better/faster/easier way to get the same results?

I'm not really sure if there is a faster/better/easier way to do a squash, but I'm pretty sure another great solution to fix this is:

  • V1 using the --squash flag from git merge.
  • V2 soft reset and commit
  • V3 write a alias or a script to do the work for you

V1.

Firstly, you have to reset last X commits (git reset --hard HEAD~3) then apply git merge --squash HEAD@{1} because HEAD@{1} is where the branch was before the previous command.

V2

You can check V2, probably you'll find this more neat: git reset --soft HEAD~3 && git commit but personally I don't like it.

V3

Of course there is a scenario where you can write a alias an automatize the whole process. Probably you'll find this useful:

  1. BEST ONE!: https://coderwall.com/p/-p2gla
  2. https://github.com/mozilla/pdf.js/wiki/Squashing-Commits
  3. http://inputvalidation.blogspot.ro/2010/12/automatic-squashing-of-last-git-commits.html
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top