I'm currently having a discussion about "how to git" with a team I'm working with.

What I'm realizing is that a) I've always been super pragmatic (which is an euphemism for "super sloppy") with this and b) different people value very different things in a git history.

To me, for example, the local history of a pull request is super important and I very rarely amend a commit.

Some people in that company work very differently and basically work in one commit they frequently rebase.

On the main branch, otoh, I want as few commits as possible, but ideally with very useful commit messages.

So, I squash on merge.

Some people, after finishing their work in that singular, massage the git history into atomic commits they will then merge.

I think I understand the value of atomic commits, but to me this feels backwards.

I'm willing to learn, though so I'm enjoying our discussions.

I also think that this is super context sensitive. Larger teams need to think more carefully about their git history and it's been a while I've been on larger teams.

The snark part of me wonders, though, if people who claim that "git is too complicated" are simply using git in a completely different way than me that causes their problems in the first place. Complex massaging of git histories very rarely comes up in my workflows.

@halfbyte I think we’ve also all got our personal scar tissues from things that have burnt us in the past.

Many years ago a colleague took a branch he’d been working on for something like 6 months, with hundreds of commits (many of them quite fiddly - it was work to get a codebase to run against redshift as well as postgres) and just squashed merged it.

I was super anti squash merge for many years as a result

@fglc2 Now I'm curious what made you soften on squash commits?

@halfbyte

@pointlessone @halfbyte intentional focus on PRs being small enough ( https://ruby.social/@fglc2/115383442942052868 )

I went with the flow when I joined the company and in 4 and a bit years I don’t feel like I’ve ever regretted it

fglc2 (@[email protected])

@halfbyte but the last few years I’ve been in a world where prs are intentionally very small (less than 200 lines diff usually, often a lot less) and there I’m happy with a squash merge. I do occasionally make a change, usually a small, subtle one where I wish it would make it as its own commit into the final history so that when I inevitably git blame that line in a years time I get to the explanation for it.

Ruby.social

@halfbyte but the last few years I’ve been in a world where prs are intentionally very small (less than 200 lines diff usually, often a lot less) and there I’m happy with a squash merge.

I do occasionally make a change, usually a small, subtle one where I wish it would make it as its own commit into the final history so that when I inevitably git blame that line in a years time I get to the explanation for it.

@halfbyte I’m generally happy (within reason!) to amend / tidy up commits before considering them done, etc, but there are definitely things people do with git that make me wonder why they insist on making life difficult for themselves.

(Monorepos for example. If you’ve combined everything into one repo to the point that it’s unmanageably large with git alone and you have to start building custom tools to handle it, that feels self-inflicted.)

@halfbyte as someone who really dislikes squash merges (and also had to work with them for past 3 years), the first question I'd like to ask is: why to you want as few commits as possible in your main branch? What's the value of this?

@katafrakt Just a clearer history with less noise, I guess. Again, depends a bit on the project, but I think a "commit per ticket" approach can make reading the history a lot easier.

On the flip side, which is a more indirect answer to your question, if you don't squash, you need to be much more deliberate with your local history (or massage the history before merging) and that seems wrong or at least annoying to me.

@halfbyte there are trade-offs, for sure. If people on the team do "wip, wip, fix, test, fix lint" commits, then perhaps squashing is a better solution.

But then you need some rigor as well. I used to work on a team that practiced long-living branches and when I was trying to browse file's git history to find how a given piece of code got there, I stumbled upon commits with 18k lines of changes (squashed from 200 commits). That's just useless and definitely a lot of noise in my books.

@halfbyte and for me personally squashing and 1:1 relationship between commit ant ticked discourages making ad-hoc generic improvements to the codebase, because they either get filed under a misleading commit title, or you need to create an artificial ticket or separate pull request for them.

@katafrakt Hm, interesting. I guess that's where my pragmatism would kick in and say "Rules are there to be broken". If I want to make that refactoring, I'm making that refactoring.

I think what we're seeing here is that a lot of this is actually more about company culture and collaboration than about technical merits.

Who woulda thunk. :)

@katafrakt Oh, yeah for sure. I am guilty of long-living branches on some projects but more for a lack of time - I usually try to be very deliberate of quickly delivering small, isolated changes.

I guess I find the combo of pseudo trunk based development and then still having long lived branches because people context switch so much and reviews take ages probably the worst of both worlds.

If you have good examples of public histories that you personally like, I'd love to see them.

@halfbyte for my personal projects I recently use rebase merges. Here's an example PR that, when squashed, would land as "improve tests" single label, but I prefer each reason for change to live in a separate commit:

https://github.com/katafrakt/palaver/pull/47/commits

But this is just a small, single-person project. I don't think I have an example of a larger public project at hand.

@halfbyte I was having this exact discussion on Reddit this week. I value proper git history as a way of communicating with other contributors and future me. I wish squash on merge was banned! 😆

I always work in a branch, with one or more commits grouping related changes in a logical order and frequently amending them as necessary to keep it clean. After PR approval, it's a standard merge commit which preserves the history of how that code came to be. So I get a nice graph showing related smaller commits.

@Odaeus @halfbyte Team atomic commit here, except I usually massage my local messy history at the end of the dev process.

I'd rather have one auto-squash commit than a string of wip/typo commits, although I personally squash them manually before handing it off for review. With side tasks (eg cleanup) or major dev steps, I want them and their explanation in separate commits.

This not only helps with future research but makes code reviews much easier when you can handle cohesive bits one by one.

@halfbyte I wonder what is your reasoning that local history of a PR is valuable but it's not valuable on the main?

@pointlessone Different levels of abstraction. While working on a feature, and discussing it with team members, local history is valuable. Most if it (in my experience) is only valuable while it's WIP.

I don't need to know a year from now why I refactored a particular set of methods, I only need to know the rationale for the end result.

(Again, very much IMHO and I see people disagree with me on this)

@halfbyte Right.

In my opinion history is important. Granularity might be different for WIP and final result. I think small atomic commits are valuable at both stages: development/review and a year from now when someone else is trying to figure out why this thing is the way it is.

If I had a choice I'd take “wip, fix, fix, wip, fix” history over squashed history. It is noisy but at least it shows the process and in between there are intentional commits. Squashed history loses intentionality. A squashed commit may have all the commit messages but you can't tell which changes correspond to those messages and even if they end up in the final result.

My process is somewhat sloppy while in a branch but before the merge I spend time making the history as nice as possible as a courtesy to whoever’s gonna read it. I tidy up all the fixups, sometimes split big commits if they're too messy. I rebase my branch to allow fast-forward merge (reduce conflicts and other noise). On multiple occasions nice history helped my save time and I’m trying to pay it forward.

@halfbyte yeah the single commit approach is the way Gerrit forces you to work, and I am not a fan.

I always tell people that a git history is a story you tell your future self. How many commits, the message style, squash vs rebase doesn't matter as long as you make sure you can answer the question: "Why has this change being made?"

If you ever tried to do a rails, ruby or any other larger dependency upgrade and try to reason why a change has been made 2 years after, you will thank yourself.

@tvdeyen I have one colleague having the same intentions and working the same way as me in that regard. We really enjoy reviewing each other's changes. And it's always nice hitting one of those commits later. Most other colleagues don't understand the effort because examining the git history is not their tool of choice.
This is a hen and egg problem: they don't compose useful commits because they don't use the history because the majority of our commits doesn't provide valuable insights.

@tvdeyen also crucial for git bisect to work!

And they’re not just for my future self, they’re for everyone who joins the team after I’ve left too.