34

I'm currently working on implementing guidelines for git usage in a fairly complex development environment, and while I think I have the basics set up pretty well, there is one question in particular I would like some input on if that's at all possible. This isn't so much a purely technical question, as in that it's more about which of the available options is most appropriate.

Basically, I'm leaning towards a system that closely mirrors the common "git flow" structure (http://nvie.com/posts/a-successful-git-branching-model/), with some exceptions to adapt it to our development environment. In short:

  • A project will have at least a 'develop' and 'master' branch
  • 'master' will contain the latest production ready code
  • 'develop' will contain the latest merged code
  • Anything else will be in either a 'feature/ticket{number}' or 'hotfix/ticket{number}' branch
  • Feature branches will be made from 'develop', hotfix branches from 'master'
  • The number in the branch name will always correspond with the ticket number in our own change/bug system
  • Features can be tested individually, but also in combination, by building the appropriate branch or merging it to 'develop' first

So far, it's really helped us streamline our development and prevent conflicts between projects. The one detail that's spawned some debate here is; should we merge feature/ticket branches back into their respective origins with the '--squash' option? I'm somewhat of a fan of this, and what I like about it:

  • The git log for develop remains clean and readable, all commits will simply state the original branch name (which tells us if it was a hotfix or a feature, and the ticket number)
  • Even after clearing out the original feature or hotfix branch, the merge can cause no confusion afterwards

Maybe these reasons won't turn out to be good enough, and maybe there's good reasons not to use '--squash' in this scenario. Any thoughts?

mephisto
  • 661
  • 1
  • 6
  • 14

2 Answers2

36

[S]hould we merge feature/ticket branches back into their respective origins with the --squash option?

It all depends how fine-grained you want the history of your repo to be. Keep in mind that version control, via commit messages, is a form of code documentation. Squashing willy-nilly is certainly not good practice. It may be fine for a hotfix branch, but rarely is for a substantial feature branch.

As an analogy, imagine if you asked me for a lend of my Lost DVD boxset (i.e. you cloned my repo), and I just gave you the box, no DVDs, and told you

Here, just read the summary of the series on the backcover. That should tell you enough about the plot.

So, by all means, squash your commits when you want to get rid of intermediate steps that are needlessly detailed or not self-contained enough, but not to the point that it obscures the evolution of your repository.


(I discuss this matter further in this Twitter thread.)

jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • 2
    That makes sense. I'm not talking about squashing just any branch blindly, of course. This would specifically be about what we consider "ticket branches". My main consideration is that it allows me to ensure that every commit that makes it into the "main" code will have a commit message that clearly specifies what ticket number it's about. Also, since most tickets I've seen here generally don't require a very large number of commits to fix, I haven't seen much reason to preserve every intermediate step once it's been tested, verified, and merged back. – mephisto Nov 19 '14 at 13:29
  • 1
    I think we're on the same page. I can see the appeal of having a commit message clearly specifying the associated ticket number; and you're right that most tickets don't require that many commits, so not so much detail would get lost in the squashing. I guess the answer to your question very much depends on the situation. In summary, squash, but with discernment. – jub0bs Nov 19 '14 at 14:01
  • 1
    Or don’t squash at all and make sure you put a ticket number into each commit message. Or change your tooling so that it can infer the ticket number from somewhere else. – Marnen Laibow-Koser Nov 09 '19 at 16:21
  • @jub0bs what if you squash with lets say a nice detailed commit message and at the footer you leave a reference from the branch you have squashed from ? this way you could have an good ordered history in your develop and if you want to check more details you could check the history of the feature branch – Yordan Kanchelov Jan 13 '20 at 14:50
  • 2
    @JordanKanchelov This would still prevent me from reversing atomic changes. That's why I prefer not to squash. – jub0bs Jan 16 '20 at 06:16
  • To eliminate quick-WIP-save commits in a local branch, you can `git rebase -i HEAD~N` (see [here](https://stackoverflow.com/q/12522565/4710226)). – ebk Nov 27 '20 at 00:40
  • @jub0bs I realize this answer is happily almost 10 years ago BUT what do you think about squashing all PR's to dev while keeping work branch history in full detail? Imo this keeps dev history short yet you can find full detail about the project in hindsight - I'm curious as to your thoughts (and potential gotchas) – Jacksonkr Mar 18 '22 at 12:44
  • 4
    @Jacksonkr No. That breaks the connection between Git commits, so Git can’t analyze the history properly and can’t track which branches have been merged. If you don’t want to see the full history, try `git log --merges` or something. Squashing preemptively throws your history away forever. Don’t do that. – Marnen Laibow-Koser Aug 10 '22 at 20:13
  • 1
    The history is better left alone and energy spent learning how to use the git log options. This lets your team take advantage of details when useful or ignore them when preferred. The log tools can virtually do your automated squash for you, so why waste potentially good intormation? With aliases its trivial to use the log commands you desire. So squashing is just throwing away information to remain ignorant of git's powerful tooling. – Allen Oliver Aug 21 '23 at 19:02
13

Don’t squash: the small commits are useful especially for later tracking down of bugs with git bisect, and anyway you don’t want to change the history much. Just use a merge commit (git merge --no-ff) to keep the history organized.

Marnen Laibow-Koser
  • 5,959
  • 1
  • 28
  • 33
  • 23
    Tracking down bugs become harder not easier when there are a lot of noisy meaningless intermediate commits. You want to make a cohesive commit that represent chunks of changes that would make sense to cherry pick from one branch to another. The project should build and be in a sensible state after applying each individual commit. – Sámal Rasmussen Mar 24 '20 at 17:17
  • 10
    @Sammi: “The project should build and be in a sensible state after applying each individual commit.” Agreed. • “ Tracking down bugs become harder not easier when there are a lot of noisy meaningless intermediate commits.” I’m not advocating meaningless commits, but I am advocating smaller ones. Since `git bisect` uses the commit as its unit of granularity, smaller (meaningful) commits make tracking down bugs *easier*. I agree that each commit should be a cohesive known-good state, but sometimes that means only changing 3 lines of code. – Marnen Laibow-Koser Mar 25 '20 at 18:57
  • 3
    @SámalRasmussen And why is it that you think tracking down bugs become harder when there are a lot of intermediate commits? When you have tracked the commit that caused the bug, you know more precisely what caused the bug if your commits are smaller, right? – HelloGoodbye Dec 19 '22 at 10:37
  • 2
    You will also have to read all the previous small intermittent commits to see what the actual state of the code is... that one small non-cohesive commit won't make any sense on it's own. While coding I often make small intermittent commits because I find it makes it easy to undo a change and get back to a previous good state after I've tried something that didn't work out. But this question is about whether you should leave these in when merging back to main. That's what my comment is about. – Sámal Rasmussen Dec 22 '22 at 19:35
  • 2
    @SámalRasmussen Why would a small commit be non-cohesive? It should be atomic. And yes, it should absolutely be preserved when merging back to main, because the original commit structure helps when tracking bugs and reconstructing the state. Sure, you might sometimes have to look at the context that the small commit was made in—and with the original commits, *you can do that*. If you squash, you’ve lost that information forever. – Marnen Laibow-Koser Dec 23 '22 at 16:38
  • 1
    We might have different experiences with commit histories. I've seen a lot of commit histories filled with non-cohesive and non-atomic commits. Those need to be squashed. – Sámal Rasmussen Dec 25 '22 at 19:07
  • 1
    @SámalRasmussen Those need to not be made. Each commit, as far as possible, should be one atomic change that transforms the codebase from one known good state to another. And each commit should generally be permanent (with some minor exceptions). Rebasing creates commits that represent untested states; squashing removes knowledge of known good states. In a well-managed Git history, it’s important to avoid doing both of these things. – Marnen Laibow-Koser Dec 26 '22 at 21:04
  • 1
    "In a well-managed Git history..." - heck of an assumption right there... – Sámal Rasmussen Dec 27 '22 at 19:23
  • 1
    @SámalRasmussen It’s not an assumption. I’m saying that if you want to manage your history well, you should neither rebase nor squash in general. – Marnen Laibow-Koser Dec 28 '22 at 21:28
  • 1
    Which is doable if you're alone and motivated... until you work with others with differing opinions on git history hygiene. Then you squash. You squash it with fire. – Sámal Rasmussen Jan 02 '23 at 11:43
  • 1
    @SámalRasmussen No, no, no. When you’re working with others, it’s even more important to keep the history, because you won’t know the context in which someone else made a commit. Good developers generally know how to produce good histories; certainly that has been my experience in the 15 years I’ve been using Git on lots of different teams. If your co-workers don’t, *help them learn to do so*. Too many commits is *usually* better than too few in Git. – Marnen Laibow-Koser Jan 12 '23 at 17:06
  • 1
    I am very happy for you that you've been so fortunate to work in such warm and fuzzy work environments. – Sámal Rasmussen Jan 13 '23 at 01:31
  • 1
    @SámalRasmussen This isn’t warm and fuzzy, it’s an uncompromising commitment to doing things right and a desire to help my colleagues succeed. – Marnen Laibow-Koser Jan 15 '23 at 22:10