61

Currently when I'm using Git, I create a branch for each job and make various commits before I'm finished. I then merge back with my master branch and push upstream. I'm likely to have several branches at any one time and also flick between them mid-job as things crop up.

But most of these commits are just save points, i.e. not that important in the grand scheme of things. So when I merge the branch, I'd like it if the branch logs didn't merge with the master logs.

Is there a way to just merge the log message for commit g below (and not commits c or e)?

a [master] 
|
b (create branch 'job')
|\
| \
|  c 
|  |
d  e
|  |
f  g (next step is to merge 'job' branch with 'master')
knittl
  • 246,190
  • 53
  • 318
  • 364
Adam
  • 1,098
  • 1
  • 8
  • 17
  • I would like to add to this question: Is there a way for `git log` to only display the messages that do *not* come from intermediate commits like `c` and `e`? – Eric O. Lebigot Nov 08 '10 at 13:32
  • 1
    @EOL: Unless I misunderstand you, that's exactly what the `--first-parent` option (mentioned by knittl) does. For a merge commit, the first parent is from the merged-into branch, and the second parent is from the merged branch, so following the first parent (generally) means effectively following the history of just the branch you're on. – Cascabel Nov 08 '10 at 17:06
  • @Jefromi: Thank you for pointing this out. I actually meant the opposite of what I wrote: how to hide `d` from `git log`? (I have a setup where the branch merged into a simply a Python 2.6 version, so that the merged into branch log is not so interesting.) – Eric O. Lebigot Nov 08 '10 at 20:30

3 Answers3

94

I consider merge --squash extremely useful when I use a "branch per feature" approach. My commit history in temporary branches is a complete garbage, absolutely meaningless. And I really want to be unable to see that history anymore, not just to be able to skip it.

When the commits go to code review, it is important not to create extra commits.

Paleo
  • 21,831
  • 4
  • 65
  • 76
Ellioh
  • 5,162
  • 2
  • 20
  • 33
  • 1
    I have to agree. If you've been pushing commits to a remote server as a WIP branch, then you can't rebase and fix the history up. For small feature branches it's perfectly legal. – Razor Aug 22 '14 at 06:52
  • That's right and it is very common workflow in middle-sized teams. – oxfn Mar 19 '15 at 13:28
  • The best I can tell, you only stated your opinion. You did not answer the OP's question of *"Is there a way to just merge the log message for commit g below (and not commits c or e)?"* – jww Aug 22 '16 at 01:55
  • 5
    The answer is "merge --squash", that's what the OP was looking for. All the other words are added to explain why "merge --squash" is not always "evil" as many people think. – Ellioh Aug 23 '16 at 12:37
24

There is, but it is nonsense. Why do you want to do that? You'll lose all branch history and information.

You could use g's commit message for your merge commit and then browse history with the --first-parent option.

If you really want to lose history from your branch use git merge --squash, i do not recommend it though

Edit

In case you are not happy because you do not consider your history very clean, you can use Git's rebase feature:

You can retroactively edit old commits and create new commits from your existing branch (in effect rewriting it). It allows you to reword commit messages, split commits, squash commits into a single commit, re-order commits, etc.

You should only use rebasing when you haven't published your branch (i.e. it is only a private branch), because it will give other developers headache and could cause merge problems later on, if someone kept working on the old (before rebased) branch.

knittl
  • 246,190
  • 53
  • 318
  • 364
  • Hi Knittl, guess I'm looking for a "best practice" really. Commit points C and E could be unfinished work and wouldn't ever be a point I'd need to roll back to. Maybe I should use git stash at those points instead... Either way my issues was that I didn't want "junk" log messages cluttering up the master log, but I've just found this git log command that will help by grouping the log messages: git log --pretty=format:'%h : %s' --topo-order --graph – Adam Nov 08 '10 at 11:04
  • @adam, you can always (interactively) rebase your branch to bring it into good shape and then merge with master – knittl Nov 08 '10 at 11:22
  • Could you expand on your "rebase your branch" thing? This sounds interesting. :) – Eric O. Lebigot Nov 08 '10 at 13:30
  • 2
    @Adam: I completely agree with knittl; you shouldn't use `merge --squash`, you should just use `log --first-parent` to avoid *viewing* the merged commits. If you want to clean it up first, `git rebase -i` (`--interactive`) is indeed the way to go - and I imagine you'll find it very intuitive. You can read docs, but the first time you try it (e.g. `git rebase -i ^ job`), it should be pretty clear what you can do. Just don't use it on a published branch! – Cascabel Nov 08 '10 at 14:50
  • 12
    I think merge --squash is perfectly reasonable, and in fact it's what I use for the same situation that the OP explains: when most of the commits on your local branch are 'save points' and nothing special that needs sharing. – joachim Nov 03 '11 at 11:38
  • 3
    You don't lose your commit history if you keep the branch you did the work in. I'm finding that when you merge a branch back into your master branch, and the commits are merged with other people's commits, it becomes difficult to go back to a previous commit somewhere in the middle and compile successfully. – Steve Warren Jul 08 '13 at 14:45
  • 3
    Is `--squash` good or evil - depends on team workflow. When "feature-branches" approach is used, detailed history is kept in particular branches and `master` only leeps merge history. – oxfn Mar 19 '15 at 13:31
  • 4
    *"there is, but it is nonsense...."* - Why would you want messages like "fix memory error" that occurred on a dev-branch to show up in Master when Master never suffered it? Inaccurate logs are an audit and C&A nightmare. – jww Aug 22 '16 at 01:49
  • 1
    I just want to add that a personal use case for using `--squash` would be for test commits I may have made on a branch (like for example making a bunch of garbage test commits when first setting up continuous integration). – writofmandamus Apr 13 '17 at 05:20
  • If your master branch history is littered with broken commits then bisecting will be a nightmare – forresthopkinsa Jun 17 '21 at 22:54
3

As mentioned in "Trimming GIT Checkins/Squashing GIT History", if your commits c and e were done with a comment prefixed with fixup!, then the rebase --interactive --autosquash (git1.7+, February 2010) can do exactly what you are after.

with the fixup! directive, you could keep that squashing "invisible" in the commit message, while still benefiting from the automatic commit reordering with the --autosquash option.

To commit with a fixup! prefix, you can define the alias

[alias]
    fixup = !sh -c 'git commit -m \"fixup! $(git log -1 --format='\\''%s'\\'' $@)\"' -
    squash = !sh -c 'git commit -m \"squash! $(git log -1 --format='\\''%s'\\'' $@)\"' -

The fixup alias would then apply for those "commits (which) are just save points, i.e. not that important in the grand scheme of things".

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250