Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 316521

Summary: Need ability to "squash" commits from the history view
Product: [Technology] EGit Reporter: Ian Bull <irbull>
Component: UIAssignee: Project Inbox <egit.ui-inbox>
Status: RESOLVED FIXED QA Contact:
Severity: enhancement    
Priority: P3 CC: angvoz.dev, dariogiova, deepakazad, dj.houghton, eclipse, gamma32, jontejj, jwross, malaperle, markus.duft, markus.kell.r, matthias.sohn, pwebster, robin, tjwatson, tomasz.zarna, vkoskela
Version: unspecified   
Target Milestone: 3.3   
Hardware: All   
OS: All   
Whiteboard:
Bug Depends on: 396510    
Bug Blocks: 356939    

Description Ian Bull CLA 2010-06-10 15:07:39 EDT
I'm very new to Git, so I likely have some of this terminology wrong.

I've cloned a git repo and worked on it for a while. I have committed (locally) several changes. I now need a way to create a single patch of all the changes I've made.

A few people have suggested a numbers of options, including:

git rebase -i, and I 'squash" the commits together. I can then create a patch from this.  While this works from the cmd line, I think the history view should support this.


1. Select a sequence of commits
2. Right click and squash
Comment 1 Matthias Sohn CLA 2010-06-10 16:04:52 EDT
this is a feature request
Comment 2 Deepak Azad CLA 2011-10-20 09:43:52 EDT
When can we expect this feature? The 'Target milestone' is set to 0.9.0 :)
Comment 3 Markus Duft CLA 2011-11-21 09:46:04 EST
+1 i think this feature is not only great, but vital if you want to work (in a useful way) with gerrit and such, right? as i heard on eclipsecon, pushing multiple commits to gerrit is bad practice, so we'd need a way to squash them first.
Comment 4 Matthias Sohn CLA 2011-11-25 18:46:27 EST
Actually there is a way to squash the last n commits on the current
branch using EGit:
- ensure your working tree is clean (otherwise the squashed commit
   will also contain the uncommitted changes in the working tree)
- click "Reset > Soft" on the commit which is meant to be the base
   for the squashed commit. This will reset the branch pointer to the
   base commit but leave the working tree and index untouched.
- click "Team > Commit" and select all files shown by the commit
   dialog and click "Commit" or use staging view to stage everything 
  and commit all combined changes.
  
The effective result is a new commit which squashes all commits
which previously followed the base commit.

Pushing multiple commits to gerrit isn't bad practice in general.
Pushing multiple commits from the same branch to Gerrit might
be a bit more complicated to understand hence you shouldn't do
that as a beginner, when you got a bit more experienced this is
perfectly ok if these changes logically depend on each other.
If they don't depend on each other you better put them on different
local branches started from origin/master so that they can go through
the review process independently. Also commits should comprise one
logical change this way you end up with a proper history and reviewers
have an easier task when trying to understand the change they review.
Comment 5 Jonatan Jönsson CLA 2011-11-27 03:27:10 EST
 Okey great, we wanted an easy way not A way.

(In reply to comment #4)
> Actually there is a way to squash the last n commits on the current
> branch using EGit:
> - ensure your working tree is clean (otherwise the squashed commit
>    will also contain the uncommitted changes in the working tree)
> - click "Reset > Soft" on the commit which is meant to be the base
>    for the squashed commit. This will reset the branch pointer to the
>    base commit but leave the working tree and index untouched.
> - click "Team > Commit" and select all files shown by the commit
>    dialog and click "Commit" or use staging view to stage everything 
>   and commit all combined changes.
> 
> The effective result is a new commit which squashes all commits
> which previously followed the base commit.
> 
> Pushing multiple commits to gerrit isn't bad practice in general.
> Pushing multiple commits from the same branch to Gerrit might
> be a bit more complicated to understand hence you shouldn't do
> that as a beginner, when you got a bit more experienced this is
> perfectly ok if these changes logically depend on each other.
> If they don't depend on each other you better put them on different
> local branches started from origin/master so that they can go through
> the review process independently. Also commits should comprise one
> logical change this way you end up with a proper history and reviewers
> have an easier task when trying to understand the change they review.
Comment 6 Dario Giovannetti CLA 2011-11-27 10:03:06 EST
I premise I'm not a git expert either. I'm giving an example, this is the initial situation:

A---B---C---D

I want to get:

A---(B+C+D)

But the method at comment #4 seems to give me:

A---B---C---D
 \--------------(B+C+D)

What's more, master will now be in (B+C+D), but origin/master will stay in D, and every attempt to push will be rejected unless I merge or rebase (B+C+D) on D, thus practically restoring the initial situation.

Then if instead I want to get:

A---(B+C)---D

Can the method at comment #4 be applied to this situation?

Then another basic example, let's say I have this (a merged branch):

A---B---C--------E---F
     \------D---/

I want to get just this:

A---F

How can I do that?

I'm sorry for all the terminology mistakes I've made in this reply, I repeat I'm no expert at all ^^
Comment 7 Matthias Sohn CLA 2011-11-27 18:25:04 EST
(In reply to comment #6)
> I premise I'm not a git expert either. I'm giving an example, this is the
> initial situation:
> 
> A---B---C---D
> 
> I want to get:
> 
> A---(B+C+D)
> 
> But the method at comment #4 seems to give me:
> 
> A---B---C---D
> \--------------(B+C+D)

what's wrong with that ?
---B---C---D 
will no longer be visible as you moved back the branch 
to A using soft reset before committing 
(B+C+D) in one squashed commit

> What's more, master will now be in (B+C+D), but origin/master will stay in D,
> and every attempt to push will be rejected unless I merge or rebase (B+C+D) on
> D, thus practically restoring the initial situation.

if origin/master is already on D you should think twice before changing that
since modifying published commits forces everybody who fetched D before
you modified it to use "fetch -f" to follow your tweak. If they did some additional
changes based on the old D they have more work ahead.

If you really want to do this you need to forcefully push your squashed
commit (B+C+D) using push -f.

> Then if instead I want to get:
> 
> A---(B+C)---D
> 
> Can the method at comment #4 be applied to this situation?

no

> Then another basic example, let's say I have this (a merged branch):
> 
> A---B---C--------E---F
> \------D---/
> 
> I want to get just this:
> 
> A---F
> 
> How can I do that?

create a new local branch based on A and cherry-pick F

> I'm sorry for all the terminology mistakes I've made in this reply, I repeat I'm
> no expert at all ^^
Comment 8 Dario Giovannetti CLA 2011-11-28 11:21:28 EST
(In reply to comment #7)

I see, thanks, you taught me some useful tricks ;)
Comment 9 Robin Stocker CLA 2013-09-27 11:18:40 EDT
EGit now also has a squash option in the Merge dialog, which allows to merge a branch but squashing all commits.

For interactive rebase, please see bug 340967.

*** This bug has been marked as a duplicate of bug 340967 ***
Comment 10 Matthias Sohn CLA 2014-02-07 16:19:47 EST
Maik proposed a patch which provides a really simple to use solution based on interactive rebase:
- select consecutive commits in history view
- click "Modify > Squash"

https://git.eclipse.org/r/#/c/21617/
Comment 11 Matthias Sohn CLA 2014-02-11 16:30:16 EST
merged as 2cab2681962da8cb782746b972edd6af7547bb52