Back to News
Advertisement
Advertisement

⚡ Community Insights

Discussion Sentiment

55% Positive

Analyzed from 14468 words in the discussion.

Trending Topics

#commit#git#commits#don#messages#more#code#log#merge#printf

Discussion (500 Comments)Read Original on HackerNews

pzmarzly•5 days ago
Jujutsu equivalents, if anyone is curious:

What Changes the Most

    jj log --no-graph -r 'ancestors(trunk()) & committer_date(after:"1 year ago")' \
      -T 'self.diff().files().map(|f| f.path() ++ "\n").join("")' \
      | sort | uniq -c | sort -nr | head -20
Who Built This

    jj log --no-graph -r 'ancestors(trunk()) & ~merges()' \
      -T 'self.author().name() ++ "\n"' \
      | sort | uniq -c | sort -nr
Where Do Bugs Cluster

    jj log --no-graph -r 'ancestors(trunk()) & description(regex:"(?i)fix|bug|broken")' \
      -T 'self.diff().files().map(|f| f.path() ++ "\n").join("")' \
      | sort | uniq -c | sort -nr | head -20
Is This Project Accelerating or Dying

    jj log --no-graph -r 'ancestors(trunk())' \
      -T 'self.committer().timestamp().format("%Y-%m") ++ "\n"' \
      | sort | uniq -c
How Often Is the Team Firefighting

    jj log --no-graph \
      -r 'ancestors(trunk()) & committer_date(after:"1 year ago") & description(regex:"(?i)revert|hotfix|emergency|rollback")'
Much more verbose, closer to programming than shell scripting. But less flags to remember.
palata•5 days ago
To me, it makes jujutsu look like the Nix of VCSes.

Not meaning to offend anyone: Nix is cool, but adds complexity. And as a disclaimer: I used jujutsu for a few months and went back to git. Mostly because git is wired in my fingers, and git is everywhere. Those examples of what jujutsu can do and not git sound nice, but in those few months I never remotely had a need for them, so it felt overkill for me.

Jenk•5 days ago
Tbf you wouldn't use/switch to jj for (because of) those kind of commands, and are quite the outlier in the grand list of reasons to use jj. However the option to use the revset language in that manner is a high-ranking reason to use jj in my opinion.

The most frequent "complex" command I use is to find commits in my name that are unsigned, and then sign them (this is owing to my workflow with agents that commit on my behalf but I'm not going to give agents my private key!)

    jj log -r 'mine() & ~signed()'

    # or if yolo mode...

    jj sign -r 'mine() & ~signed()'
I hadn't even spared a moment to consider the git equivalent but I would humbly expect it to be quite obtuse.
palata•5 days ago
Actually, signing was one of the annoying parts of jujutsu for me: I sign with a security key, and the way jujutsu handled signing was very painful to me (I know it can be configured and I tried a few different ways, but it felt inherent to how jujutsu handles commits (revisions?)).
rjh29•5 days ago
It's the dvorak of git... Maybe more efficient but incompatible with everyone else and a very loud vocal minority.

You can find this pattern again and again. How many redditors say 120fps is essential for gaming or absolutely require a mechanical keyboard?

palata•5 days ago
Yeah I think that dvorak is a good example, too.

I don't get the mechanical keyboard one, though. I am fine with any keyboard, I just like my mechanical keyboard at home. Just like I am fine with any chair, but ideally I would have a chair I like at home.

120fps I have no experience with, but I would imagine it's closer to video quality. Once you're used to watching everything in 4K, probably it feels frustrating to watch a 1080p video. But when 4K did not exist, it was not a need. I actively try to not get used to 4K because I don't want to "create the need" for it :-).

SatvikBeri•5 days ago
It's totally compatible though, and that's a big selling point. I use jj and nobody else at my work uses it and that has never been an issue.
RankingMember•5 days ago
I don't even like using "natural" keyboards despite the ergonomic advantage because it ruins my muscle memory when I'm on the (much more prevalent) "regular" keyboard.
bastardoperator•5 days ago
Looks like the Perl of Git too. Those commands are wild compared to vanilla git.
account42•4 days ago
> How many redditors say 120fps is essential for gaming or absolutely require a mechanical keyboard?

Those don't fit the others - they don't really require the user to adapt or are more complex in any way but are just nicer versions of the standard.

deno•5 days ago
I mean let's not be hasty. Mechanical keyboards used to be just normal keyboards when computers were still computers.
alper•4 days ago
Pretty much everybody who does work at the real office where I am has a mechanical keyboard by now.
alper•4 days ago
Nix does not really work in that even basic things are absurdly complicated and can take days of messing with poor libraries and documentation.

That's not been my experience with jj which after the initial hurdle is a breeze.

mamcx•5 days ago
No, jj is super simple in daily use, in contrast with git that is a constant chore (and any sane person use alias). This include stuff that in git is a total mess of complexity like dealing with rebases. So not judge the tool for this odd case.
palata•5 days ago
> in contrast with git that is a constant chore (and any sane person use alias)

I don't use aliases, I guess I'm insane?

Also 99.9% of the time, git "just works" for me. If I need to do something special once a year, I can search for it. Like I would with jujutsu.

Exoristos•5 days ago
One rarely needs more from git than `git add -A && git commit -m`.
buu700•4 days ago
I don't know about jujutsu, but I've actually found that Nix removes a lot of complexity. It's essentially just npm for tooling.

Managing a flake.nix can be a bit more complex than a package.json in practice, due to the flexibility of the format and some quirks around Nix's default caching behavior, but working with it is a breath of fresh air compared relying on globally installed tools. Having said that, you might want to check out Devbox. I haven't used it myself, but found it recently and thought it looked like a nice abstraction over raw Nix.

qudat•4 days ago
To be completely fair to JJ: you can still use git commands and any aliases with it. I daily JJ in all of my repos but I created these aliases inside of git. That's one of the great aspects of JJ: it's fully compatible with git.
stingraycharles•5 days ago
I don’t understand how people can remember all these custom scripting languages. I can’t even remember most git flags, I’m ecstatic when I remember how to iterate over arrays in “jq”, I can’t fathom how people remember these types of syntaxes.
crispyambulance•5 days ago
I am convinced that the vast majority of professionals simply don't bother to remember and, ESPECIALLY WITH GIT, just look stuff up every single time the workflow deviates from their daily usage.

At this point perhaps a million person-years have been sacrificed to the semantically incoherent shit UX of git. I have loathed git from the beginning but there's effectively no other choice.

That said, the OP's commands are useful, I am copying them (because obviously I won't ever memorize them).

freedomben•5 days ago
> I am convinced that the vast majority of professionals simply don't bother to remember and, ESPECIALLY WITH GIT, just look stuff up every single time the workflow deviates from their daily usage.

I wrote a cheat sheet in my notes of common commands, until they stuck in my head and I haven't needed it now for a decade or more. I also lean heavily on aliases and "self-documenting" things in my .bashrc file. Curious how others handle it. A search every time I need to do something would be too much friction for me to stand.

alwillis•5 days ago
> At this point perhaps a million person-years have been sacrificed to the semantically incoherent shit UX of git. I have loathed git from the beginning but there's effectively no other choice.

Yes! We mostly wouldn’t tolerate the complexity and the terrible UX of a tool we use everyday--but there's enough Stockholm Syndrome out there where most of us are willing to tolerate it.

kelvinjps•4 days ago
That's why I really like lazygit, I don't need to remember much because all the keymaps are shown in the UI. I like those kinds of Ui like whichkeys in neovim, or helix, or Doom Emacs.
dec0dedab0de•5 days ago
I just use my ide integrations for git. I absolutely love the way pycharm/jetbrains does it, and I'm starting to be ok with how vscode does. Remembering git commands besides the basics is just pointless. If I need to do something that the gui doesn't handle, I'll look it up and put it in a script.
shiroiuma•3 days ago
>I am convinced that the vast majority of professionals simply don't bother to remember and, ESPECIALLY WITH GIT, just look stuff up every single time the workflow deviates from their daily usage

Partly that, but for me at least, I have a bunch of simple bash scripts and aliases for things I do frequently. Git makes this really easy because you can set aliases for lots of custom commands in the .gitconfig file.

ngruhn•5 days ago
I don't even think git cli UX is that bad. Didn't git pioneer this sub-command style? Much better than like e.g. ffmpeg. Sure some aspects are confusing. I still don't understand why `checkout` is both for changing branches and clearing uncommitted changes. But overall I think the tool is amazing. I've not observed a bug in git once.
neonstatic•4 days ago
I think this is where LLMs shine. I experience the same difficulty with a lot of command line tools, .e.g find is a mystery to me after all these years. Whatever the syntax is, it just doesn't stick in my memory. Since recently I just tell the model what search I want and it gives me the command.
awesome_dude•5 days ago
The relevant XKCD comic https://xkcd.com/1597/

FWIW I too was once a "memorised a few commands and that was it" type of dev, then I read 3 chapters of the Git book https://git-scm.com/book/en/v2 (well really two, the first chapter was a "these are things you already know") and wow did my life with git change.

weedhopper•5 days ago
I’ve recently been looking into some tools that provide quick or painless help like pop up snippets with descriptions and cheat sheets, got any recommendations?
Cthulhu_•5 days ago
I don't, I will google things and fiddle, then put it in a git alias (with a comment on what it does and / or where I got it from) and push it to my private dotfiles repo, taking it with me between computers and projects.
dewey•5 days ago
You research it once, use it and then remember that it has "ancestor" in the command somewhere and then use ctrl + R to dig up something from your shell history.
dzaima•5 days ago
jj's template and revset languages are very simple syntactically, so once you're comfortable with the few things you do use often it's just a question of learning about the other existing functions (even if only enough to know to look them up), which slot right in and compose well with everything else you know (unlike flags which typically have each their own system).

Or, perhaps better yet, defining your own functions/helpers as you go for things you might care about, which, by virtue of having been named you, are much easier to remember (and still compose nicely).

jiggunjer•4 days ago
Really, I got stuck trying to commit all files except those containing the string abc. As for revsets it's not easy to grab a single branch?
limaoscarjuliet•5 days ago
Some things are idioms that one repeats so often they just stick, e.g. I use "grep.... | cut -c x-y | sort | uniq -c | sort -nr" to quickly grep frequency of some events from a log file.

Don't feel bad - no one remembers them all, we just remember a few idioms we use...

usrbinbash•5 days ago
> I don’t understand how people can remember all these custom scripting languages.

We can't.

Why do you think the `man` command exists?

yujiachen•4 days ago
Same here, so I wrap the post into an agent skill. Hope I can use them next time. https://github.com/yujiachen-y/codebase-recon-skill
mgfist•5 days ago
Same, but now with AI I don't have to remember that anymore
awesome_dude•5 days ago
For now - the law of enshittification means that the free/cheap access to AI will be curtailed soon enough.
gspr•5 days ago
You and me both. Git is just so prevalent and fundamental to so much these days that I forced myself to use only a cheat sheet lying on my desk until I could comfortably use a reasonably productive subset by memory. Little did I know that that would make my colleagues think I'm some sort of git sage.

But jq I use maybe once a week, and it just won't stick. Same for any git features beyond basic wrangling of the history tree (but, on the flip side, that basic wrangling has eliminated 99% of the times I have to look things up).

drob518•5 days ago
Nobody does. One person figures it out, then writes a blog post, and we all Google for it. Even git’s man pages are long and sometimes cryptic.
robrain•5 days ago
If I look something up twice, I record it in Obsidian. If I need it more than a couple of times, I'll probably make an alias, a script or a mask [1] file. Autocomplete and autosuggest are essential to my workflow. And good history search.

[1] https://github.com/jacobdeichert/mask

SoftTalker•5 days ago
Yeah especially with git. All I know is pull, add, commit, push. Everything else I have to look up.
TheRealPomax•5 days ago
If you don't have to codedive new projects all the time, there's zero reason to memorize these. If your job is to look at new codebases all the time, you probably learn to remember these commands pretty quickly.
michaelcampbell•3 days ago
`jq` and `ffmpeg` were two of my very early uses of LLM's for daily ease.
Fokamul•5 days ago
You add them into your GIT config file as shortcuts?

If you have multiple machines (/must have), just apply your user config to current machine?

PapstJL4U•4 days ago
lazygit helped me to get more into different git commands - I still don't know them by heart. but at least I use more git has to offer.

and when a new branch is one key stroe away from being created, I am more inclined to use it.

TeMPOraL•5 days ago
People naturally remember what they use frequently. For things they use infrequently, they search on-line and/or read the friendly manual.

And yes, I'm also ecstatic when I manage to iterate over anything in `jq` without giving up and reaching for online reference. For `git`, functionality I use divides neatly into "things I do at least every week or two" and "things that make me reach for the git book every single time".

I mean, that was true until ~year or so. Now, I just have an LLM on speed dial. `howto do xyz in $tool`, `wtf is git --blah`, `oneliner for frobbing the widget`, etc.

NoSalt•5 days ago
So, how does one iterate over an array in jq? Asking for a friend.
wwader•3 days ago
Assume input is an array you can do it several ways depending on what you want:

    # output each value in the array separately 
    .[]

    # output each value but transform it in some way
    .[] | . * 2


    # map each value into a new array
    map(. * 2) 

    # same as above but manual iterate/collect
    [.[] | . * 2]
dcre•5 days ago
Saw all the replies crying over how verbose these are, clicked through to TFA expecting to see simpler commands. Nope, they're basically the same thing, just slightly shorter. I would never memorize either the jj or git versions if I planned to use them regularly; I'd make aliases.
WolfeReader•4 days ago
This is the only sane reply on this entire comment tree.

To me, the verbosity of both Git and JJ commands to do these things are an indication that neither of these tools are meant to do them.

AlexeyBelov•4 days ago
crying over? Let's not be confrontational. I could say you're "crying" with this comment, but is that a good thing to say?
dcre•3 days ago
Come on.
socalgal2•5 days ago
a project isn’t dying because of no commits. Rather it’s stable

I often feel I need to setup bots to make superfluous commits just to make it look like my useful and stable repos are “active”

One example (not mine) a a qr-code generator library. Hasn’t been updated in 10 years. It’s perfect as is. It just provides the size and the bits. You convert those bits to any representation you want. It has no need to be updated

wredcoll•5 days ago
It's rare, I think, for a project to have such a well defined and singular purpose that has not changed in 10 years nor have any bugs been discovered or its dependencies changed underneath it.

It's not impossible, of course, but if I saw even a qr library that hadn't changed in 10 years I would worry that it wouldn't build on current systems (due to dependencies) and that nobody was actually using it (due to lag of bug reports).

latexr•5 days ago
I have several of those projects. I avoid dependencies as much as possible, striving to only use things which I know ship with my target OS. I code for a level of correctness and longevity. That benefits everyone, including myself.

A QR (or barcode) library is exactly the type of thing I’d assume would still work fine, since there’s nothing new to do, the parsing rules don’t change, it’s a static, known, solved problem.

xp84•5 days ago
Well said. Even an awesome library with no bugs that has no external dependencies still depends on the stdlib. For a while, before we were using containers, we even had the issue on Mac dev machines especially, where a half dozen Rubygems would crash while building its C extensions if your Mac OS version wasn’t just what the author expected, due to changes in the compiler shipped by Apple. So a MacOS major update might on its own functionally break a gem, even if the gem itself was designed well and you were using the same Ruby version.
saila•5 days ago
This might be true for libraries or utilities that have a well-defined scope and no dependencies, but that's not what the article is focused on. When considering a company's main product, it's usually never done and patterns of activity—and especially changes in those patterns—can give you insight into potential issues.
fishpen0•5 days ago
In a real company? A private codebase at a minimum should still be getting regular security patching and dependency updates. Always eventually one of those updates requires some level of refactor. If I see a project with no commits, I run away.
latexr•5 days ago
> a project isn’t dying because of no commits. Rather it’s stable

Agreed. Assuming there are no open issues and PRs. When I find a project, if the date of the last commit is old, I next look at the issues and PRs. If there are simple-to-deal-with issues (e.g. a short question or spam) and easy-to-merge PRs (e.g. fixing a typo in the README) which have been left lingering for years, it’s probably abandoned. Looking at the maintainer’s GitHub activity graph should provide more clues.

> I often feel I need to setup bots to make superfluous commits just to make it look like my useful and stable repos are “active”

I have never done it, but a few times thought about making a “maintenance” release to bump the version number and release date, especially since I often use a variant of calendar versioning.

newsoftheday•5 days ago
I don't want to program git, I want to get stuff done so I would reject using that tool and do what the article author did running tried and true pipeable Linux/UNIX commands. It's also the same reason why I dislike Gradle and use Maven, I don't want to program my build I want to define and run my build.
nine_k•5 days ago
But the git commands in the article is also programming of the same kind, just using more terse, more obscure language. All the shell pipelines are sort, uniq, and grep.

A language that properly maps to the data model, and has readable identifiers is a boon. Git is a database, a database needs a proper query language.

gib444•5 days ago
Hah someone really looked at jq (?) and thought: "yes, more of this everywhere". I feel jq is like marmite (edit: aka vegemite, i.e. "you either love it or you hate it")
maleldil•5 days ago
It's really not that bad, although the jq comparison might be apt. You have such primitives you need to understand, and then everything just fits together nicely. I find this much easier to write and understand than git's cryptic format strings.

Disclaimer: I love jq too :)

plandis•5 days ago
It doesn't seem any more egregious than something like:

`git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --`

Which is something I see a lot of people alias in Git for viewing logs.

skydhash•4 days ago
> `git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --`

If you remove the rainbow specification, it should be

  git log --graph --pretty=format:'%h -%d %s (%cr) <%an>' --abbrev-commit --
And most programmers are used to C style formatting.
okkdev•4 days ago
Cool! Thanks :) Jujutsu is such a nice tool. I don't understand why everything has to be so divisive nowadays. Enjoy the tools you like.
NamlchakKhandro•5 days ago
Didn't ask for it thanks
cynicalsecurity•5 days ago
Not interested, thank you.
faangguyindia•5 days ago
I can't remember all of this, does anyone know of any LLM model trained on CLI which can be run locally?
lamasery•5 days ago
If you copy those commands into a file and use that file to prompt the “sh” LLM.
stingraycharles•5 days ago
That works until you need a small variation of any of these commands and you’re lost.
fainpul•5 days ago
esafak•5 days ago
Not a model, but a product: warp.dev
bsuvc•5 days ago
I love how the author thinks developers write commit messages.

All joking aside, it really is a chronic problem in the corporate world. Most codebases I encounter just have "changed stuff" or "hope this works now".

It's a small minority of developers (myself included) who consider the git commit log to be important enough to spend time writing something meaningful.

AI generated commit messages helps this a lot, if developers would actually use it (I hope they will).

ramijames•5 days ago
This is a team lead/CTO problem. A good leader will be explicit in their expectations that developers write good commit messages. I've certainly had good leaders that expect this.
ryandrake•5 days ago
Yes, and a culture problem, too. I guess I've been blessed that I've mostly only worked for "grown up" companies, but I've never encountered a workplace where people didn't write useful commit messages. At least one line description of the work done, but often multiple lines of valuable context. Only the junior devs had to be told to do it, but once they got into the habit, everyone understood why we do it and it was no big deal.

If I joined a company where people committed their code with "stuff" or "made some changes" or "asdfhlfo;ejfo;ae," that would be a red flag that I might have joined the wrong company, and I'd start to wonder what else the developers here do carelessly.

ramijames•5 days ago
Indeed. If you can't spend two minutes (MAX) writing a sentence or two explaining what the commit is for, then what are we doing as developers? Commits are for future you and your future team. They are a tool. Please, use them.
lossyalgo•5 days ago
Good commit messages would be nice but honestly I would be over the moon if our pull requests would be approved within a week without having to ping one or more people.
godelski•5 days ago
The same goes for code comments though people are much more vocal about their disdain. It's ironic given how frequent AI is used to generate docs. But docs are much better written by the person who wrote the code, the person who has all the context.

These things never take much time but people dismiss them because of that. Because each commit and each comment in isolation isn't very valuable but they are very helpful in aggregate. I'm not sure why this bias exists though, since the same is true for lines of code. It's also true about a ton of things. All the little things add up. Just because it's little now doesn't mean it's not important

scottyah•5 days ago
Some of my favorite are the perhaps well-meaning but totally misguided log of what files they changed.
asdfman123•5 days ago
> I'd start to wonder what else the developers here do carelessly

More likely you'd already know by this point because it would be staring you in the face

berkes•5 days ago
I once tutored an intern. Who thought he was The Best Programmer On Earth (didn't we all at that age?). He refused to use revision control, it slowed him down.

So we told him to commit at least once every day, with a relevant commit message, or else fail his internship.

He worked 21 more days. There were 21 commits: "17:00, time to go home".

vntok•5 days ago
This reads like the intern was left to his own devices and his output not checked at all for three weeks straight. Actual tutoring would have surfaced the issue after 1 or 2 days tops.
drums8787•5 days ago
I particularly love when the “CTO” is also the main offender.
jillesvangurp•5 days ago
I am a CTO and I actually have very little patience for people that obsess over minor formatting issues (use a linter if you care), commit messages, and other fringe issues. If that's the biggest issue you have in a team, amazing. You are doing great. But you probably have bigger issues. The focus of the CTO is on the big picture stuff. Like staying on top of technical debt and correcting people when they keep on adding more of it. And making sure people learn from their mistakes, focus on the important things first, etc.

The thing with commit messages is that they are mostly never going to get a lot of scrutiny. But there are exceptions to this; especially if there are audits involved or external contributors. And of course when making a pull request to an OSS project, it is good form to make a bit of an effort. It depends on the context. I tend to focus more on diffs and pull requests. Not on the cryptic one liners that may or may not describe some of the changes. The right unit of change is a pull request, not individual commits.

And all this of course was when I was still able to keep on top of the massive volume of change. With AI that's simply no longer the case and the volume of change is only going to increase over time. Human reviews are now the main bottleneck to getting code merged. AIs probably should be doing a lot of the reviewing, gatekeeping testing, vetting, etc. Especially when AIs also produce most of the change. It's likely a lot of things will slip through unless you get your house in order on guard rails and process that your AI agents need to follow. As a CTO, guarding quality without becoming a human bottleneck is now the main challenge and removing bottlenecks responsibly is part of the job.

BTW. making AI tools write good commit messages is actually be a bit expensive. Many AI tools default to just summarizing the first message of a chat session under the assumption that just one thing changed over the course of a session. Making the AI look at the actual diff is of course possible and not that hard (just ask). And it definitely yields better descriptions when you do that. But it also takes more time and the token cost goes up as well. I'm not sure that's actually worth the expense in tokens. I tend to not bother with this. But again; depends on the context.

PUSH_AX•5 days ago
I think it's a stretch to measure leadership quality on something so minor, a lot of teams find them pretty useless no matter how good they are.
munksbeer•5 days ago
I don't agree. These things actually matter. A developer who isn't told otherwise is just going to do whatever they feel like, so if there is nothing or no-one enforcing the standards, then the failure isn't on the individual developer, it is on the team lead. Someone needs to be setting the standards.

In the company I work for, there is a team that has isolated itself to some extent from other teams and works at a furious pace to keep their particular section of the business happy. We're lucky enough that they spun up their own repo to do their work on, so they don't actually impact other teams, but if the quality of the commit messages is anything to go by, I am 100% certain they're going to end up in a huge mess, if they aren't already. The team lead encourages this, and certainly doesn't care about commit messages etc.

Developers who care about other developers tend to write better quality code, because they care what other developers think of them. If you care about other developers, you will most likely write decent quality commit messages too.

I have seen over many years the types of developers who only care about moving their own code into production as fast as possible and getting to the next thing. There is a very high correlation with a mess at the end, which they inevitably won't have to tidy up because they'll be doing the next thing. These types of developers hate owning stuff in production, so they don't do it, so they don't actually care how maintainable their "clever" code is. I am very certain that a number of people reading this will be those types of developers.

xp84•5 days ago
Useless? So you never use “git annotate” or your IDE to see who wrote a line of code whose purpose puzzles you, and go to the commit message to see what they were trying to accomplish? This is invaluable to me as long as commit messages are clear.

As a manager, one of the first things I do is make sure that the PR titles (the PR text becomes the commit messages in squash-merging workflows) at minimum begin with a ticket number. Then we can later read both the intention and the commentary on it.

two_tasty•5 days ago
I partially disagree. Technical leadership at the micro/mid level should be able to set and enforce standards like "you must have semi-meaningful or meaningful commit messages." If and only if they set those standards, and the team does not follow them, then we can say that either the leadership is lacking, or there is a structural barrier/disincentive to following the rules. Within that framework, I do think using process-smells like this is valid for judging technical leadership.

To the point of other commenters however, I wouldn't lay something this micro at the foot of the CTO in all but the smallest of organizations.

freedomben•5 days ago
It's a stretch to lay at the CTOs feet, but not the team lead or even Head/VP of Engineering IMHO. It's also easy to "enforce" if you're already doing peer review (which you definitely should be, even if not required for compliance).
hbn•5 days ago
One of the best developers I work with commits everything with the message "changes"

(This is not an endorsement to do that, he's a good developer in spite of his shitty commit messages)

mewpmewp2•5 days ago
Obviously a very unpopular opinion, but I guess for my own sake it's hard to write commit messages, because for me it's that I have never really even found use of other people commit messages, and I rarely even attempt to. Ultimately code is code and I don't care about how it got to how it is. I got same issue with documentation and comments or really anything that isn't building stuff. I don't like writing it, don't like reading it either... ADHD?

So, before AI came and saved me from writing commit messages I had alias that ran the whole git add . && git commit -m ... && git push with a fixed commit message. But of course we had squashing so PR title was the one to eventually go there, so maybe that part is fine. But all my side projects had just that.

ygouzerh•4 days ago
It can be even enforced using hooks/pipelines that will check that the message follow Conventional Commits as well
account42•4 days ago
> Conventional Commits

I though we were talking about good commit messages.

mikepurvis•5 days ago
In codebases where PRs are squashed on merge, the commit messages on the main branch end up being the PR body description text, and that's actually reviewed so tends to be much better I find.
bob1029•5 days ago
And in every codebase I've been in charge of, each PR has one or more issue # linked which describe every possible antagonizing detail behind that work.

I understand this isn't inline with traditional git scm, but it's a very powerful workflow if you are OK with some hybridization.

rightofcourse•4 days ago
It works until you migrate to a new system. In 5 years we are on our 3rd. I saw that at FAANG and startup alike. Then someone might dump the contents in JSON or just PDF for archival but much easier to have the commit msg have the relevant info - only relevant, losts of small details can be still on the issue and if someone really needs them can search those archives.
bikelang•5 days ago
I personally find this to be a substantially better pattern. That squashed commit also becomes the entire changeset - so from a code archeology perspective it becomes much easier to understand what and why. Especially if you have a team culture that values specific PRs that don’t include unrelated changes. I also find it thoroughly helpful to be able to see the PR discussions since the link is in the commit message.
tormeh•5 days ago
I've seen it be the concatenated individual git commit messages way too often. Just a full screen scroll of "my hands are writing letters" and "afkifrj". Still better than if we had those commits individually of course, but dear god.

The gold standard is rebased linear unsquashed history with literary commits, but I'll take merged and squashed PR commits with sensible commit messages without complaint.

lopis•5 days ago
If developers don't write commit messages, that's a culture problem. At my company we demand that of each other.
hn_throwaway_99•4 days ago
Totally agree. One thing I really like about HN is it reminds you that nobody's individual experience is indicative of the industry at large.

The parent comment stated "Most codebases I encounter just have "changed stuff" or "hope this works now"." I worked at 6 tech companies in my career and a slew of contracting gigs, and I literally never encountered the problem of commit messages being uninformative. Most of the companies developed strict rules for commit comments like always including an issue number (with occasional [NO-ISSUE] tags allowed for minor changes) or something like Conventional Commits, https://www.conventionalcommits.org/en/v1.0.0/ .

ElijahLynn•5 days ago
And in a squash and merge workflow, which are most teams I've been on the past 8 years, it really is the title of the pull request or merge request. That is what really matters.

And I really like that because it leaves room to let the developer do whatever kind of commit messages they want to that makes sense to them. Because nobody's really ever going to read those again after it squashed and merged.

tkzed49•5 days ago
Every time I hear about commit messages on HN, this is my first thought. I can't imagine not working in a squash workflow. No matter how good your commit messages are, I do not want to read all of them. The squashed commit will direct me to the original PR in case I need more detail.
skinner927•5 days ago
- fix - fix fr - fix frfr - plz - omg why - never gonna give you up - never gonna let you down - add missing curly braces
grepsedawk•5 days ago
Only two of the five depend on commit messages. Churn, authorship, and velocity work regardless. Even teams with terrible hygiene write "fix" when something breaks.
SoftTalker•5 days ago
As noted, authorship does not if commits are squashed, which seems to be common (I never do it).
KronisLV•5 days ago
> Even teams with terrible hygiene write "fix" when something breaks.

They might not include anything but the Jira ticket number, if the environment is truly lacking.

yreg•5 days ago
> It's a small minority

Is it really a small minority? I have never worked on a project that didn't have commit messages that at least tried to be descriptive (sometimes people fail at it but its very different to an outright "changed stuff").

I don't remember any friend mentioning to me them encountering a work project where the messages were totally neglected either.

brabel•5 days ago
Never seen that in any company I worked at either and I can’t believe professional developers seem to think that it would be ok to write meaningless commit messages. That’s just so sloppy.
parasti•4 days ago
When your boss looks only at the business output and your most prolific developer writes "save" for commit messages, it gets real hard to enforce a commit message policy. "It's hard to review"? Your boss doesn't care about that and it slows the 10x guy down. These days I just run an LLM on the commits to annotate them (via git notes) based on context.
alper•4 days ago
> developers write commit messages

The people who don't write commit messages for us are the non developers.

Writing commit messages shouldn't take any time at all. If it does, then you probably have a range of other professional issues.

aftbit•4 days ago
We have a hard division between "Core" repos (those which are deployed to production / customer sites) and everything else. The expectation in Core repos is that everything goes through a PR process where the pull request message is intended to explain the what and why of the change (perhaps with reference to a ticket, but with the key information restated in the PR), and goes through a review just like the code. Changes are then either squashed with that as the commit message or (if they're larger and benefit from a clear separation of commits), may be rebased with `git rebase -i` assuming the final PR body ends up in one of the commit messages.

Non-Core repos are absolute free-form anything goes. You can commit 8 times a day without a PR as long as you're not deploying to production. This is excellent for things like test harnesses, CI/CD nonsense, one-off experiments, demos, prototypes, etc.

My last Core commit had something like 20 to 1 ratio between lines of commit message to lines of code (small change touching something deep that required a lot of explanation). My last non-Core commit message was "hope this works" (it did not).

travisgriggs•5 days ago
Our small team has a lot of commit messages like this. For a while, we had a guy on the team who had come from a site that expected more. The pet peeve he brought along was that commit messages end with a period (my guess is that someone at their previous work place had reasoned that forcing periods encouraged developers to actually write meaningful sentences). When I look at that period of development, I see lots of messages like “stuff changed.” And “more stuff changed.” And then it goes back to just “stuff changed” around the time they moved on.
gcarvalho•5 days ago
> my guess is that someone at their previous work place had reasoned that forcing periods encouraged developers to actually write meaningful sentences

I have actually seen proper capitalization and correct conventional-commit types to correlate very well with the author being intentional and the patch being of good quality.

e.g.

- (a) chore: update some_module to include new_func

- (b) feat: Add new_func to handle XYZ case

Where:

(a) is not a chore, as it changes functionality, is uncapitalized and is so low-signal I can probably write a 10 line script to reliably generate similar titles.

(b) is using the correct "feat" commit type, capitalized and describe what this is for. I expect the body to explain "why", as well, and not to reiterate the "how" in natural language.

This is just my experience, but I've seen commit messages where people actually put in some effort to usually come with a good patch, and vice-versa.

zimpenfish•4 days ago
> Most codebases I encounter just have "changed stuff" or "hope this works now".

I have been told off several times at different jobs for writing commit messages that are "too big". Also for writing too much commentary in my code changes. Also also for complaining that other people aren't doing these things.

(Not that it stops me, mind, but it does make working relationships fractious.)

mystickphoenix•3 days ago
Likely my own personal bias, but I have never once found git log/commit messages to be useful when debugging or understanding what happened. I'm sure that others do so I try to write useful commits (conventional commits syntax is helpful here) but I'd much rather spend my time and effort understanding the current state of the codebase instead of trying to diagnose how "fixed bug related to file naming" relates to a website going down.
kelnos•5 days ago
Bad commit messages always fail PR review for me. It requires will and discipline, but it's not that hard.
HeinrichAQS•4 days ago
One big problem about commit messages is, that you write them from your perspective. If you write them while activly engaged with the topic and changes you are very heavily biased and might miss things which are obvious to you but not to future readers with less knowledge. I think abstracting your personal opinion is quite hard - I agree that LLMs are perfectly fitting for writing this since they just dont have a "personal opinion". Atleast I made the mistake in the past many times focusing on the things which were not obvious to me but then leaving out the non obvious things for others.
AStrangeMorrow•5 days ago
I also like meaningful commit names. But am sometimes guilty of “hope this works now” commits, but they always follow a first fix that it turns out didn’t cut it.

I work on a lot of 2D system, and the only way to debug is often to plot 1000s of results and visually check it behaves as expected. Sometimes I will fix an issue, look at the results, and it seems resolved (was present is say 100 cases) only to realize that actually there are still 5 cases where it is still present. Sure I could amend the last commit, but I actually keep it as a trace of “careful this first version mostly did the job but actually not quite”

heinrichhartman•5 days ago
I personally use git commit -m "." for: "Just snapshots this state real quick" on a feature branch.

main branch is advanced on PR level, with squashed commits.

So the "." should never make it to main, and have PR description as commit message.

renegade-otter•4 days ago
Many organizations squash their commit messages from PR, where most commits actually happen. Unless everyone is committing to trunk all the time, which almost never happens on a real job, I highly doubt the value of this.

Showing my Git ignorance here, of course - does "ancestors(trunk)" pull in all the commit messages?

smallpipe•4 days ago
I do not approve PRs from junior devs until the commit message is useful.
sigmoid10•5 days ago
Only two of the five insights are based on commit messages and the author acknowledges that they won't work in projects without message discipline. But the remaining ones will give you valuable insights even into the most lazy project department.
loremium•5 days ago
tbh I'm not convinced that a git log history should be treated as a group journal because it's not.

relying on git commit messages assumes they're correct by convention since there is no technical constraint to enforce it. and it assumes no work in progress commits, sometimes it's just necessary to hit the save button real quick or move a workspace from one device to another.

my point is: git is a way of storing and loading files at its core.

harryquach•5 days ago
Commit messages are often squashed after merging a feature branch
max8539•5 days ago
Sometimes it could be just a ticket number/title
bartvk•5 days ago
I think that's pretty great, actually. You can look that up to see more info about the commit.
8cvor6j844qw_d6•5 days ago
> AI generated commit messages

git log --oneline and a sprinkle of your personal sauce on .claude goes a long way :)

stronglikedan•5 days ago
It's because the vast majority of commit messages are never read by anyone, and there's other ways to fund out what happened in the handful of cases where you would need to.
mkehrt•5 days ago
I read commit messages all the time to figure out what a change was about.

For small personal projects I often write one phrase messages with `-m`, but if you're working with other people you should be writing good commit messages.

scottyah•5 days ago
git blame's are amazing, and rely on good comments.
itmitica•5 days ago
I love how the commentator thinks a developer makes decisions based on commit messages.

Random, subjective, or written in a state of mental exhaustion commit messages.

I also love the switcheroo the author made: git not logs. But hey :)

joshstrange•5 days ago
I ran these commands on a number of codebases I work on and I have to say they paint a very different picture than the reality I know to be true.

> git shortlog -sn --no-merges

Is the most egregious. In one codebase there is a developer's name at the top of the list who outpaced the number 2 by almost 3x the number of commits. That developer no longer works at the company? Crisis? Nope, the opposite. The developer was a net-negative to the team in more ways than one, didn't understand the codebase very well at all, and just happened to commit every time they turned around for some reason.

kmacdough•5 days ago
Everything in context. This is one of many reasons I'm a proponent of squash-and-merge. If a change really needs more than one permanent commit, it should probably be split up or if absolutely necessary should be on a feature branch maintaining similar process. Under this process, feature branches are not squashed.

This leaves developers to commit locally and comment as much or little as they like.

maest•4 days ago
I suspect OP never actually ran these commands and this article was brainstormed and written by an LLM.
dawnerd•4 days ago
There's some giveaways that it was too. "It's not x, its y."
pacaro•4 days ago
I'm getting a mixed reading, the most egregious flags aren't present, but there are a couple.

As you identified there is a lot of parallel sentence structure.

They also have a bunch of lists of 3-5 items which is a classic.

It doesn't have the anodyne rambling never getting to the point style common to LLMs

Timwi•2 days ago
I'm starting to feel that this line of reasoning has turned into pseudoscientific divination. And it's really unfair to writers who put effort into blog posts.
dawnerd•4 days ago
Same. Someone we brought on that worked for about a month and vibe coded to hell caused a lot of damage in terms of tech debt and that list shows. Looks like he managed 124 commits in a single week. The same repo, our top dev only has around 500 in its entirety.

Also important to have a plan for code review and merges when a lead is out of town. I found out I needed to reevaluate how that's handed when I was gone for two weeks.

michaelcampbell•3 days ago
Not to diminish your lived experience, but this is sort of a management issue, no? There should be some expectations set and/or gates that need to be opened during PR about commit expectations. Some teams like a lot of commits to be a (messy) reflection of actual reality/history, others want the well-curated "story" with a bunch of squashes and rebases.
perlgeek•5 days ago
I think OP's context is: they get called to help troubled projects. Often the people that hired them might not know where exactly the trouble comes from.

If you look at a code base that's not really in trouble, these commands don't reveal the source of the trouble, because there might be none.

fenaer•5 days ago
So that person, on one central codebase at a company I work for, is me.

Assuming I'm not ego-mad, I like to think this is because I built the project from the ground up before handing it over to the rest of the team.

These days other people commit more often than I do, but my name is still dominant, and probably will be for some time.

joshstrange•5 days ago
I'm not saying more commits = bad developer. In my example that happened to be the case but not because they had a lot of commits but because they were bad at their job. I was just trying to warn that taking these git snippets at face-value does not paint the full picture.

If someone came to me and said "I ran these and I see XXX was the most prolific committer and they left X months ago, what will be do???" I'd have to work hard not to laugh.

Since these snippets are self-described as ways to get familiar with the code/projects I wanted to provide the counter point. Most of those snippets do not at all paint the real picture and for all the repos I tested it on they paint the opposite of reality.

I know these codebases like the back of my hand, the purported purpose of these snippets is to better understand the codebase, I can tell you they don't work for anything I tested them on. Maybe they work for other codebases but the sample size I have access to says they don't work for me.

troyvit•5 days ago
I haven't finished the article yet but I think your point is an important one, and that's to run the commands with a context in mind. The article seems to be coming from the perspective of somebody who is brand new to the project, and as your experience indicates, interviewing teams and leads before running those commands might add more understanding to what they're telling you.
Aperocky•5 days ago
Also - be careful of automated workflow that uses a single persons credential.. skews this by a lot.
kevstev•5 days ago
Once word got out that a report was going up to a department head around commit frequency, a few of us started to make "backup commits" to boost our stats. Whether it be dev server config files (just in case!), local dev setups, whatever.. just something that changed enough on its own but would produce a steady stream of commits, while having some potential use case, however unlikely it was to actually be needed.

Modern problems require modern solutions and all...

joshstrange•5 days ago
Been there. At a company where KPIs became all the rage they asked each department to come up with KPIs to report on. The eng/dev department pushed back a bit saying there aren't any easy KPIs to surface and anything we did would either be trivial to game and/or would result in a bunch of extra work to track (like needing to add a ton of metadata to various tickets/processes to tie it all together). They didn't care and we settled on a bunch of BS metrics that we all knew were BS and trivial to game.
dgunay•5 days ago
Yeah. I am the top committer at my current workplace, but I'd say that a majority of that gap is because my particular workflow results in many smaller commits than my coworkers.
RickHull•4 days ago
Thanks for this. My updated relevant portion of ~/.gitconfig:

    [alias]
        st = status
        ci = commit
        co = checkout
        br = branch
        df = diff
        dfs = diff --stat
        dfc = diff --cached
        dfh = diff --histogram
        dfn = diff --name-status
        rs = restore
        rsc = restore --staged
        last = log -1 HEAD
        lg = log --graph --decorate --oneline --abbrev-commit
        cm = commit -m
        ca = commit --amend
        cane = commit --amend --no-edit
        who = shortlog -sn --no-merges HEAD
        dmg = log --oneline -i -E --grep='(incident|outage|downtime|rollback|revert|mitigate|mitigation|hotfix|broke|prod)' --since='1 year ago'
        bugs = log --oneline -i -E --grep='(bug|bugfix|fix|fixed|fixes|defect|regression|hotfix|broke)' --since='1 year ago'
        bugfiles = !git log --name-only --format='' -i -E --grep='(bug|bugfix|fix|fixed|fixes|defect|regression|hotfix|broke)' --since='1 year ago' | sort | uniq -c | sort -nr
        monthly = !git log --since='1 year ago' --format='%ad' --date=format:'%Y-%m' | sort | uniq -c
        churn = !git log --format='' --name-only --diff-filter=AM --since='1 year ago' | sort | uniq -c | sort -nr | head -20
ramon156•5 days ago
> The 20 most-changed files in the last year. The file at the top is almost always the one people warn me about. “Oh yeah, that file. Everyone’s afraid to touch it.”

The most changed file is the one people are afraid of touching?

rbonvall•5 days ago
Just like that place that's so crowded nobody goes there anymore.
dewey•5 days ago
I've just tried this, and the most touched files are also the most irrelevant or boring files (auto generated, entry-point of the service etc.) in my tests.
nulltrace•5 days ago
Yeah same thing happens with lockfiles and CI configs. You end up filtering out half the list before it tells you anything useful.
pydry•5 days ago
I just tried it too and it basically just flagged a handful of 1500+ line files which probably ought to be broken up eventually but arent causing any serious problems.
Cthulhu_•5 days ago
If it's (like in my case) dependency management, localization or config files, breaking them up will likely only cause more issues. Make sure that it's an actual improvement before breaking things up.
mememememememo•3 days ago
I'd only look at human/AI edited files (i.e. that require some kind of reasoning) not generated ones (where the reasoning is in the generator).

Generation is precompilation.

Entry point is interesting. Lots of scope to become a scary file.

jbjbjbjb•5 days ago
This command needs a warning. Using this command and drawing too many conclusions from it, especially if you’re new, will make you look stupid in front of your team mates.

I ran this on the repo I have open and after I filtered out the non code files it really can only tell me which features we worked on in the last year. It says more about how we decided to split up the features into increments than anything to do with bugs and “churn”.

Pay08•5 days ago
Good thing that the article contains that warning, then.
jbjbjbjb•5 days ago
Not really strong enough in a post about what to do in a codebase you’re not familiar with. In that situation you’re probably new to the team and organisation and likely to get off on the wrong foot with people if you assume their code “hurts”.
Eldt•5 days ago
Better for people to know they're just blindly copying tools and parroting their output as if it's automatically meaningfully. Any warning against that should be built into the individual, for their own sake
thiisguy•5 days ago
Right? Some of these comments feel “you gave me commands to run and I should be able to turn my brain off to interpret the outputs”. These aren’t newbie commands so the assumption would be that you kinda know what you’re doing at least a little bit. If not, then don’t run them… similar to how you should approach all commands/things from the internet
functional_dev•5 days ago
I found it interesting, that Git itself has built in similarity notion... when it packs objects, it groups files by path+size, runs delta cmpression to find which are close.

Very different from just counting commits - https://vectree.io/c/delta-compression-heuristics-and-packfi...

mayama•5 days ago
These commands are just about what files to start looking at to understand new codebase.
berkes•5 days ago
Plotting Churn against Complexity is far more useful than merely churn.

It shows places that are problematic much better. High churn, low complexity: fine. Its recognized and optimizef that this is worked on a lot (e.g. some mapping file, a dsl, business rules etc). Low churn high complexity: fine too. Its a mess, but no-one has to be there. But both? Thats probably where most bugs originate, where PRs block, where test coverage is poor and where everyone knows time is needed to refactor.

In fact, quite often I found that a teams' call "to rewrite the app from scratch" was really about those few high-churn-high-complexity modules, files or classes.

Complexity is a deep topic, but even simple checks like how nested smt is, or how many statements can do.

mememememememo•5 days ago
Yes. Because the fear is butressed with necessity. You have to edit the file, and so does everyone else and that is a recipe for a lot of mess. I can think back over years of files like this. Usually kilolines of impossible to reason about doeverything.
mchaver•5 days ago
Definitely not in my experience. The most changed are the change logs, files with version numbers and readmes. I don't think anyone is afraid of keeping those up to date.
furyofantares•5 days ago
The LLM that wrote the copy is an idiot.
jamwil•5 days ago
This is such obvious LLM slop.
agumonkey•5 days ago
Maybe it's a start to find conflict-prone regions ?

otherwise you're right, it could be a long linear list of appends where people are happy to contribute.

KptMarchewa•5 days ago
In my case, it's .github/CODEOWNERS.

Nobody is afraid of changing it.

mayama•5 days ago
Why does github owners need frequent change? Do members in you team change so often?
Izkata•4 days ago
If it works like gitlab (which a quick search looks like yes), you can specify down to individual files and use it to automatically determine who needs to approve merge requests.
jollyllama•5 days ago
Yeah, the truth is going to be a lot more subtle than this.
szszrk•5 days ago
Could be also that a frequently edited file had most opportunity to be broken. And it was edited by the most random crowd.
zikani_03•5 days ago
pom.xml and package.json came up on couple of separate projects I ran the commands on. Which makes sense because the versions get bumped rather frequently. I guess context matters, as usual.
mememememememo•3 days ago
I hate that rn looks like m
mattrighetti•5 days ago
I have a summary alias that kind of does similar things

  # summary: print a helpful summary of some typical metrics
  summary = "!f() { \
    printf \"Summary of this branch...\n\"; \
    printf \"%s\n\" $(git rev-parse --abbrev-ref HEAD); \
    printf \"%s first commit timestamp\n\" $(git log --date-order --format=%cI | tail -1); \
    printf \"%s latest commit timestamp\n\" $(git log -1 --date-order --format=%cI); \
    printf \"%d commit count\n\" $(git rev-list --count HEAD); \
    printf \"%d date count\n\" $(git log --format=oneline --format=\"%ad\" --date=format:\"%Y-%m-%d\" | awk '{a[$0]=1}END{for(i in a){n++;} print n}'); \
    printf \"%d tag count\n\" $(git tag | wc -l); \
    printf \"%d author count\n\" $(git log --format=oneline --format=\"%aE\" | awk '{a[$0]=1}END{for(i in a){n++;} print n}'); \
    printf \"%d committer count\n\" $(git log --format=oneline --format=\"%cE\" | awk '{a[$0]=1}END{for(i in a){n++;} print n}'); \
    printf \"%d local branch count\n\" $(git branch | grep -v \" -> \" | wc -l); \
    printf \"%d remote branch count\n\" $(git branch -r | grep -v \" -> \" | wc -l); \
    printf \"\nSummary of this directory...\n\"; \
    printf \"%s\n\" $(pwd); \
    printf \"%d file count via git ls-files\n\" $(git ls-files | wc -l); \
    printf \"%d file count via find command\n\" $(find . | wc -l); \
    printf \"%d disk usage\n\" $(du -s | awk '{print $1}'); \
    printf \"\nMost-active authors, with commit count and %%...\n\"; git log-of-count-and-email | head -7; \
    printf \"\nMost-active dates, with commit count and %%...\n\"; git log-of-count-and-day | head -7; \
    printf \"\nMost-active files, with churn count\n\"; git churn | head -7; \
  }; f"
EDIT: props to https://github.com/GitAlias/gitalias
duskdozer•5 days ago
Curious - why write it as a function in presumably .gitconfig and not just a git-summary script in your path? Just seems like a lot of extra escapes and quotes and stuff
mattrighetti•5 days ago
It's a very old config that I copied from someone many years ago, agree that it's a bit hard to parse visually.
Cthulhu_•5 days ago
Not the poster, but one theory: so you only need to copy one file. Portability.
mr_mitm•5 days ago
Looks like the above assumes a POSIX shell, so one could argue a dedicated script would actually be more portable.
TonyStr•5 days ago
Looks nice. Unfortunately I don't have log-of-count-and-email, log-of-count-and-day or churn
ape4•5 days ago
You could make a local `man` page.
not_kurt_godel•4 days ago
I was going to say, the OP's assertion that "they" are typing all these commands out by hand each time without an alias is just one of many tells that this post is AI slop. Nobody that proficient with shell commands should be typing any of those by hand more than once or twice without aliasing for reuse.
JetSetIlly•5 days ago
Some nice ideas but the regexes should include word boundaries. For example:

git log -i -E --grep="\b(fix|fixed|fixes|bug|broken)\b" --name-only --format='' | sort | uniq -c | sort -nr | head -20

I have a project with a large package named "debugger". The presence of "bug" within "debugger" causes the original command to go crazy.

nozzlegear•5 days ago
This needs a small tweak to work on macOS, where git uses the POSIX version of grep (which doesn't support `\b`). You need to use the Perl Regexp option by switching -E with -P:

git log -i -P --grep="\b(fix|fixed|fixes|bug|broken)\b" --name-only --format='' | sort | uniq -c | gsort -nr | head -20

grepsedawk•4 days ago
Good catch. The word boundary syntax isn't portable across platforms. I reverted to the simpler version that works everywhere.
j2kun•4 days ago
Similarly, we have a technical concept called "rollback" that is unrelated to a reverted commit.
grepsedawk•5 days ago
Good catch, that's better
Timwi•2 days ago
Word boundaries are one way to address that, but they require you to list all the inflections (and you missed “fixing”). Another way is to say (?<!de)bug.
icedchai•5 days ago
I wouldn't trust "commit counts." The quality and content of a "commit" can vary widely between developers. I have one guy on my team who commits only working code that has been thoroughly tested locally, another guy who commits one line changes that often don't work, only to be followed by fixes, and more fixes. His "commits" have about 1/100th of the value of the first guy.
fpoling•5 days ago
The author does not look at counter values but rather at how the values changes. That reveals dynamics.
icedchai•5 days ago
My comment still seems relevant? Do frequent commits to correct mistakes imply more "value" than infrequent, but well tested, commits, or what? I don't think it is a reliable signal.
michaelcampbell•3 days ago
It isn't. $COMPANY I've worked for use commit counts as a metric, and you can bet all the money in your pockets they've skyrocketed with no change to actual output after they did.

LLM's make it even easier; "Commit all the outstanding code in as many commits as you can, as long as the tests pass after each one". (Sometimes that second clause is ommitted, too.)

Zardoz84•4 days ago
I agree with you. Also, there is people (like me) that like to small commits (that don't break stuf) instead of huge mega commits. If I do something like small broken/wip commits, are only under my working bramch and I do a interactive rebase to merge on good cohesive commits.
whstl•5 days ago
> One caveat: squash-merge workflows compress authorship. If the team squashes every PR into a single commit, this output reflects who merged, not who wrote. Worth asking about the merge strategy before drawing conclusions.

In my experience, when the team doesn't squash, this will reflect the messiest members of the team.

The top committer on the repository I maintain has 8x more commits than the second one. They were fired before I joined and nobody even remembers what they did. Git itself says: not much, just changing the same few files over and over.

Of course if nobody is making a mess in their own commits, this is not an issue. But if they are, squash can be quite more truthful.

croemer•5 days ago
Rather than using an LLM to write fluffy paragraphs explaining what each command does and what it tells them, the author should have shown their output (truncated if necessary)
markus_zhang•5 days ago
I also feel this reads like an AI slop, but at least I learned 5 commands. Not too bad.
aa-jv•5 days ago
Great tips, added to notes.txt for future use ..

Another one I do, is:

    $alias gss='git for-each-ref --sort=-committerdate'

    $gss

    ce652ca83817e83f6041f7e5cd177f2d023a5489 commit refs/heads/project-feature-development
    ce652ca83817e83f6041f7e5cd177f2d023a5489 commit refs/remotes/origin/project-feature-development
    1ef272ea1d3552b59c3d22478afa9819d90dfb39 commit refs/remotes/origin/feature/feature-removal-from-good-state
    c30b4c67298a5fa944d0b387119c1e5ddaf551f1 commit refs/remotes/origin/feature/feature-removal
    eda340eb2c9e75eeb650b5a8850b1879b6b1f704 commit refs/remotes/origin/HEAD
    eda340eb2c9e75eeb650b5a8850b1879b6b1f704 commit refs/remotes/origin/main
    3f874b24fd49c1011e6866c8ec0f259991a24c94 commit refs/heads/project-bugfix-emergency
    ...

This way I can see right away which branches are 'ahead' of the pack, what 'the pack' looks like, and what is up and coming for future reference ... in fact I use the 'gss' alias to find out whats going on, regularly, i.e. "git fetch --all && gss" - doing this regularly, and even historically logging it to a file on login, helps see activity in the repo without too much digging. I just watch the hashes.
Advertisement
blenderob•5 days ago
> Is This Project Accelerating or Dying > > git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c

If the commit frequency goes down, does it really mean that the project is dying? Maybe it is just becoming stable?

heresie-dabord•5 days ago
For this command in particular, one can add a cheap bar chart with awk:

git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c | awk '{printf $2" "; for (i=1;i<=$1;i++){printf "-";} print ""; }'

zikani_03•5 days ago
This is a neat trick for a quick visual presentation, thanks!
goosejuice•5 days ago
Yeah, this one demonstrates a particularly pernicious view of software development. One where growth, no matter how artificial, is the only sign of success.

If you work with service oriented software, the projects that are "dying" may very well be the most successful if it's a key component. Even from a business perspective having to write less code can also be a sign of success.

I don't know why this was overlooked when the churn metric is right there.

BeetleB•5 days ago
Bad memories at my former big tech company.

Whenever we initiated a new (internal) SW project, it had to go through an audit. One of the items in the checklist for any dependency was "Must have releases in the last 2 years"

I think the rationale was the risk of security vulnerabilities not being addressed, but still ...

ziml77•5 days ago
That was my question too. I have plenty of projects I've worked on where they rarely get touched anymore. They don't need new features and nothing is broken.
SoftTalker•5 days ago
Is it fair to say they are being "worked on" if nothing is being done?
duckmysick•5 days ago
Sometimes you need to bump a dependency version, adjust the code to a changed API endpoint, or update a schema. Even if the core features stay the same, there's some expected maintenance. I'd still call that being worked on, in a sense that someone has to do it.
dan-bailey•5 days ago
Projects become more stable with time? Since when?
stackedinserter•5 days ago
Or you hired someone who squashes or doesn't commit every single change.
Sharlin•5 days ago
Something something Red Queen's race
onion2k•5 days ago
Technically you're correct that change frequency doesn't necessarily mean dead, but the number of projects that are receiving very few updates because they're 'done' is a fraction of a fraction of a percent compared to the number that are just plain dead. I'm certain you can use change frequency as a proxy and never be wrong.
Supermancho•5 days ago
> I'm certain you can use change frequency as a proxy and never be wrong.

I (largely) wrote a corporate application 8 years ago, with 2 others. There was one change 2 years ago from another dev.

Lots of programs are functionally done in a relatively short amount of time.

"Accelerating or Dying" sounds like private equity's lazy way to describe opportunity, not as a metric to describe software.

onion2k•5 days ago
That sort of project exists in an ocean of abandoned and dead projects though. For every app that's finished and getting one update every few years there are thousands of projects that are utterly broken and undeployable, or abandoned on Github in an unfinished state, or sitting on someone's HDD never be to touched again. Assuming a low change frequency is a proxy for 'dead' is almost always correct, to the extent that it's a reasonable proxy for dead.

I know people win the lottery every week, but I also believe that buying a lottery ticket is essentially the same as losing. It's the same principle.

youknownothing•4 days ago
I like the mindset, it reminds me of "Your code as a crime scene" by Adam Tornhill: https://www.adamtornhill.com/articles/crimescene/codeascrime...

Also, very tangentially, to the notion of the Developer's Legacy Index: https://www.javaadvent.com/2021/12/using-jgit-to-analyse-the...

suprjami•4 days ago
Nice to see a fellow Tornhill fan. I loved his early C articles.
aledevv•4 days ago
> Commit count by month, for the entire history of the repo. I scan the output looking for shapes. A steady rhythm is healthy. But what does it look like when the count drops by half in a single month?

Let's NOT jump to conclusions; it could mean many things. For example, a period with other priorities, different urgencies, other issues external to the project itself and beyond our control, vacations, illnesses, or anything else that could impact the commit history.

I think these considerations and the others expressed in this article can easily lead to hasty conclusions and erroneous deductions, too simplistic.

Coding flow, like business needs, cannot always be objectively and deterministically measured.

StableAlkyne•5 days ago
Biggest life changer for me has been:

git clone --depth 1 --branch $SomeReleaseTag $SomeRepoURL

If you only want to build something, it only downloads what you need to build it. I've probably saved a few terabytes at this point!

fzaninotto•5 days ago
Instead of focusing on the top 20 files, you can map the entire codebase with data taken from git log using ArcheoloGit [1].

[1]: https://github.com/marmelab/ArcheoloGit

bullen•5 days ago
Dying or stabilizing?

Most good projects end up solving a problem permanently and if there is no salary to protect with bogus new features it is then to be considered final?

moritzwarhier•5 days ago
Interesting ideas, but some to me seem very overgeneralizef, e.g.:

> How Often Is the Team Firefighting

> git log --oneline --since="1 year ago" | grep -iE 'revert|hotfix|emergency|rollback

> Crisis patterns are easy to read. Either they’re there or they’re not.

I disagree with the last two quoted sentences, and also, they sound like an LLM.

dgunay•5 days ago
This one was funny to me because sure, it was accurate for my particular codebase, but also anyone paying attention to the company Slack would already know how often fires happen.
kelnos•5 days ago
I really wanted to like this. The author presents a well-thought-out rationale for what conclusions to draw, but I'm skeptical. Commit counts aren't a great signal: yes, the person with the highest night be the person who built it or knows the most about it, but that could also be the person who is sloppy with commits (when they don't squash), or someone who makes a lot of mistakes and has to go back and fix them.

The grep for bugs is not particularly comprehensive: it will pick up some things that aren't bugs, and will miss a bunch of things too.

The "project accelerating or dying" seems odd to me. By definition, the bulk of commits/changes will be at the very beginning of history. And regardless, "stability" doesn't mean "dying".

ivanjermakov•5 days ago
When at work we migrated to monorepo, there was an implicit decision to drop commit history. I was the loudest one to make everyone understand how important it is.
gherkinnn•5 days ago
These are some helpful heuristics, thanks.

This list is also one of many arguments for maintaining good Git discipline.

Advertisement
alaudet•5 days ago
This is good stuff. Why I never think of things like this is beyond me. Thanks
Cthulhu_•5 days ago
For "what changes the most", in my project it's package.json / lock (because of automatic dependency updates) and translation / localization files; I'd argue that's pretty normal and healthy.

For the "bus factor", there's one guy and then there's me, but I stopped being a primary contributor to this project nearly two years ago, lol.

fmbb•5 days ago
> One caveat: squash-merge workflows compress authorship. If the team squashes every PR into a single commit, this output reflects who merged, not who wrote. Worth asking about the merge strategy before drawing conclusions.

Well isn't it typical that the person who wrote is also the person that merged? I have never worked in a place where that is not the norm for application code.

Even if you are one of those insane teams that do not squash merge because keeping everyone's spelling fixes and "try CI again" commits is important for some reason, you will still not see who _wrote_ the code, you will only see who committed the code. And if the person that wrote the code is not also the person that merges the code, I see no reason to trust that the person making commits is also the person writing the code.

TacticalCoder•5 days ago
> The 20 most-changed files in the last year. The file at the top is almost always the one people warn me about. “Oh yeah, that file. Everyone’s afraid to touch it.”

I've got my Emacs set up to display next to every file that is versioned the number of commits that file has been modified in (for the curious: using a modified all-the-icons-ivy-rich + custom elisp code + custom Bash scripts I wrote and it's trickier than it seems to do in a way that doesn't slows everything down). For example in the menu to open a file or open a recently visited file etc.: basically in every file list, in addition to its size, owner, permissions, etc. I also add the number of commits if it's a versioned file.

I like the fix/bug/broken search in TFA to see where the bugs gather.

niedbalski•5 days ago
Ages ago, google released an algorithm to identify hotspots in code by using commit messages. https://github.com/niedbalski/python-bugspots
arthurjj•5 days ago
These were interesting but I don't know if they'd work on most or any of the places I've worked. Most places and teams I've worked at have 2-3 small repos per project. Are most places working with monorepos these days?
abustamam•5 days ago
I can't speak for most, but the past few places I consulted or worked at used monorepos.
BigTTYGothGF•5 days ago
Jesus I've seen what you've done for others and want that for myself.
abustamam•5 days ago
?
niedbalski•5 days ago
Ages ago google wrote an algorithm to detect hotspots by using commit messages, https://github.com/niedbalski/python-bugspots
alkonaut•5 days ago
Trusting the messages to contain specific keywords seems optimistic. I don't think I used "emergency" or "hotfix" ever. "Revert" is some times automatically created by some tools (E.g. un-merging a PR).
ziml77•5 days ago
For the stuff I've worked on, if you want to know about bugfixes and emergency releases, you'd go to Jira where those values are formalized as fields. Someone else in the comments here had a suggestion which just looks for the word "fix" which would definitely capture some bugfix releases, but is more likely to catch fixes that were done during development of a feature.
alkonaut•4 days ago
Yes for a meaningful context you should need both the source repo and the work tracking system. But today most systems have apis (jira, ADO, gh, ...) so this should be fairly doable, especially using a bot like copilot cli. But it's not doable as a little shell script.
dawnerd•4 days ago
We use branch names like `hotfix/some-hotfix-name`, don't think I've seen many commits mention hotfix directly.
pscanf•5 days ago
I just finishedÂą building an experimental tool that tries to figure out if a repo is slopware or not just by looking at it's git history (plus some GitHub activity data).

The takeaway from my experiment is that you can really tell a lot by how / when / what people commit, but conclusions are very hard to generalize.

For example, I've also stumbled upon the "merge vs squash" issue, where squashes compress and mostly hide big chunks of history, so drawing conclusions from a squashed commit is basically just wild guessing.

(The author of course has also flagged this. But I just wanted to add my voice: yeah, careful to generalize.)

Âą Nothing is ever finished.

yonatan8070•5 days ago
My team usually uses "Squash and merge" when we finish PRs, so I feel that would skew the results significantly as it hides 99% of the commit messages inside the long description of the single squashed merge commit.
Advertisement
amai•1 day ago
Is there a git command to find the developer who deleted the most lines of code? That is the best developer in the team.
konovalov-nk•5 days ago
To me all of these are symptoms of the problem that I outlined in my recent blog post: https://news.ycombinator.com/item?id=47606192

and it touches in detail what exactly commit standards should be, and even how to automate this on CI level.

And then I also have idea/vision how to connect commits to actual product/technical/infra specs, and how to make it all granular and maintainable, and also IDE support.

I would love to see any feedback on my efforts. If you decide to go through my entire 3 posts I wrote, thank you

seba_dos1•5 days ago
> If the team squashes every PR into a single commit, this output reflects who merged, not who wrote.

Squash-merge workflows are stupid (you lose information without gaining anything in return as it was easily filterable at retrieval anyway) and only useful as a workaround for people not knowing how to use git, but git stores the author and committer names separately, so it doesn't matter who merged, but rather whether the squashed patchset consisted of commits with multiple authors (and even then you could store it with Co-authored-by trailers, but that's harder to use in such oneliners).

theshrike79•5 days ago
Can you explain to me (an avid squash-merger) what extra information do you gain by having commits that say "argh, let's see if this works", "crap, the CI is failing again, small fix to see if it works", "pushing before leaving for vacation" in the main git history?

With a squash merge one PR is one commit, simple, clean and easy to roll back or cherry-pick to another branch.

seba_dos1•5 days ago
These commits reaching the reviewer are a sign of either not knowing how to use git or not respecting their time. You clean things up and split into logical chunks when you get ready to push into a shared place.
theshrike79•5 days ago
Why would the reviewer look at the commit messages instead of the code?

1. Open PR page in whatever tool you're using

2. Read title + description to see what's up

3. Swap to diff and start reading through the changes

4. Comment and/or approve

I've never heard anyone bothering to read the previous commit messages for a second, why would they care?

zaphirplane•5 days ago
What are examples of better ones. I don’t get the let me show the world my work and I’m not a fan of large PR
croemer•5 days ago
What if the shared place is the place where you run a bunch of CI? Then you push your work early to a branch to see the results, fix them etc.
yokoprime•5 days ago
Haha, good luck working with a team with more than 2 people. A good reviewer looks at the end-state and does not care about individual commits. If im curious about a specific change i just look at the blame.
Aachen•5 days ago
If someone uses git commits like the save function of their editor and doesn't write messages intended for reading by anyone else, it makes sense to want to hide them

For other cases, you lose the information about why things are this way. It's too verbose to //comment on every like with how it came to be this way but on (non-rare in total, but rare per line) occasion it's useful to see what the change was that made the line be like this, or even just who to potentially ask for help (when >1 person worked on a feature branch, which I'd say is common)

seba_dos1•5 days ago
> If someone uses git commits like the save function of their editor

I use it like that too and yet the reviewers don't get to see these commits. Git has very powerful tools for manipulating the commit graph that many people just don't bother to learn. Imagine if I sent a patchset to the Linux Kernel Mailing List containing such "fix typo", "please work now", "wtf" patches - my shamelessness has its limits!

tasuki•5 days ago
You gain the extra information by having reasonable commit messages rather than the ones you mentioned. To fix CI you force push.

Can you explain to me what an avid squash-merger puts into the commit message of the squashed commit composed of commits "argh, let's see if this works", "crap, the CI is failing again, small fix to see if it works", and "pushing before leaving for vacation" ?

theshrike79•5 days ago
The squashed commit from the PR -> main will have a clean title + description that says what was added.

Usually pretty close to what the PR title + description are actually, just without the videos and screenshots.

Example:

feat(ui): Add support for tagging users

* Users can be tagged via the user page * User tags visible in search results (configurable)

etc..

I don't need to spend extra time cleaning up my git commits and force-pushing on the PR branch, losing context for code reviews etc. Nor does anyone have to see my shitty angry commits when I tried to figure out why Playwright tests ran on my machine and failed in the CI for 10 commits.

joshstrange•5 days ago
> "argh, let's see if this works", "crap, the CI is failing again, small fix to see if it works", "pushing before leaving for vacation"

These are all bad commits IMHO. Aside from the CI one, I understand that message. I have commits like that on personal projects but for professional projects I'd be frustrated if people were committing messages like that.

Personally I'm a "one commit" type of guy, I don't like committing things in a broken state even on a side branch unless I have to (to share the code or test a CI). Occasionally I will make multiple commits at the very end to make review easier or once I have everything working but I want to try something different but I have a bunch of options of saving code that don't involving committing:

- Stash

- Shevle (IDEA)

- Backblaze

- Time Machine

- Local History (IDEA)

The idea of committing WIP before leaving for a vacation just feels so wrong to me.

I once worked for someone who wanted developers to commit code before the end of every day as a safety measure. His reasoning was in case the developer's computer died or similar. I found that silly at the time and still do now. That's what backups are for, I dislike when people use git as a backup like that in a professional setting.

BeetleB•5 days ago
Trivial and not too silly example:

Part of new feature you had working in an intermediate commit, but broke somewhere along the way and is not working in your last commit when you squashed.

If you catch it early enough, I suppose it's in your reflog, but otherwise you're screwed.

It sounds like a silly example, but I bet most developers have run into this at some point.

With mercurial/jujutsu, you get the best of both worlds: The "argh, let's see if this works" commits are what I call "microcommits", and the squashed versions are the real/public commits. With jujutsu, you get both. Your log shows only the "real" commits (equivalent of squashing all the commits between that and the prior "real" commit). But if you want to drill down into the microcommits, the information is always there.

Let's acknowledge the reality. Many people use git not just for version control, but for backup ("Let me commit this so I don't lose it"). Let's ensure the VC tool supports both and doesn't force you to pick one over the other.

thi2•5 days ago
Why are those commits ending in the PR? Just unprofessional to work like that.
psalaun•5 days ago
git bisect gets more useful because it will pin a smaller set of changes
ric2b•4 days ago
But it will run into so many more broken commits...
mcpherrinm•5 days ago
Squash merge is the only reasonable way to use GitHub:

If you update a PR with review feedback, you shouldn’t change existing commits because GitHub’s tools for showing you what has changed since your last review assume you are pushing new commits.

But then you don’t want those multiple commits addressing PR feedback to merge as they’re noise.

So sure, there’s workflows with Git that doesn’t need squashing. But they’re incompatible with GitHub, which is at least where I keep my code today.

Is it perfect? No. But neither is git, and I live in the world I am given.

mgfist•5 days ago
Yes, I think people who are anti squash merge are those who don't work in Github and use a patch based system or something different. If you're sending a patch for linux, yes it makes sense that you want to send one complete, well described patch. But Github's tooling is based around the squash merge. It works well and I don't know anyone in real life who has issues with it.

And to counter some specific points:

* In a github PR, you write the main commit msg and description once per PR, then you tack on as many commits as you want, and everyone knows they're all just pieces of work towards the main goal of the eventually squashed commit

* Forcing a clean up every time you make a new commit is not only annoying extra work, but it also overwrites history that might be important for the review of that PR (but not important for what ends up in main branch).

* When follow up is requested, you can just tack on new commits, and reviewers can easily see what new code was added since their last review. If you had to force overwrite your whole commit chain for the PR, this becomes very annoying and not useful to reviewers.

* In the end, squash merge means you clean up things once, instead of potentially many times

seba_dos1•3 days ago
> If you had to force overwrite your whole commit chain for the PR, this becomes very annoying and not useful to reviewers.

I'd say that optimizing for reviewers who don't know "git range-diff" exists has even less merit that optimizing for contributors who don't know how to edit their commit graph.

I'm regularly using GitHub, GitLab, Gerrit, Phabricator and mailing lists and while some make it more pleasant than others, none of them really put any actual obstacles on your path when manipulating the commit graph mid-review.

goosejuice•5 days ago
Forcing a single commit per PR is the issue imo. It's a lazy solution. Rebase locally into sensible commits that work independently and push with lease. Reviewers can reset to remote if needed.
l72•5 days ago
If your goal here is to have linear history, then just use a merge commit when merging the PR to main and always use `git log --first-parent`. That will only show commits directly on main, and gives you a clean, linear history.

If you want to dig down into the subcommits from a merge, then you still can. This is useful if you are going back and bisecting to find a bug, as those individual commits may hold value.

You can also cherry pick or rollback the single merge commit, as it holds everything under it as a single unit.

This avoids changing history, and importantly, allows stacked PRs to exist cleanly.

mcpherrinm•5 days ago
Git bisect is one of the important reasons IMO to always squash-merge pull requests: Because the unit of review is the pull request.

I think this is all Github's fault, in the end, but I think we need to get Github to change and until then will keep using squash-merges.

Izkata•4 days ago
> But then you don’t want those multiple commits addressing PR feedback to merge as they’re noise.

They're not noise, they tell future maintainers why something is the way it is. If it's done in an unusual way they can see in the blame that a couple of lines were changed separately from the rest and immediately get an explanation by checking that commit.

arnorhs•5 days ago
The author is talking about the case where you have coherent commits, probably from multiple PRs/merges, that get merged into a main branch as a single commit.

Yeah, I can imagine it being annoying that sqashing in that case wipes the author attribution, when not everybody is doing PRs against the main branch.

However, calling all squash-merge workflows "stupid" without any nuance.. well that's "stupid" :)

seba_dos1•5 days ago
I don't think there's much nuance in the "I don't know --first-parent exists" workflow. Yes, you may sometimes squash-merge a contribution coming from someone who can't use git well when you realize that it will just be simpler for everyone to do that than to demand them to clean their stuff up, but that's pretty much the only time you actually have a good reason to do that.
l72•5 days ago
I really, really wish git changed two defaults:

  * git merge ALWAYS does a merge and git pull ALWAYS does a fast forward.
  * git log --first-parent is the default. Have a git log --deep if you want to go down into branches.
If you use a workflow that always merges a PR with a merge commit, then git log --first-parent gives you a very nice linear history. I feel like if this was the default, so many arguments about squashing or rebasing workflows wouldn't be necessary to get our "linear history", everyone would just be doing merges and be happy with it. You get a clean top level history and you can dig down into the individual commits in a merge if you are bisecting for a bug.
skydhash•5 days ago
Do people actually share PR as in different people contributing to the same branch?

Also I can understand not squashing if the contribution comes from outside the organization. But in that case, I would expect a cleaned up history. But if every contribution is from members of the team, who can merge their own PR, squash merge is an easy way to get a clean history. Especially when most PR should be a single commit.

duskdozer•5 days ago
I think the point is that if you have to squash, the PR-maker was already gitting wrong. They should have "squashed" on their end to one or more smaller, logically coherent commits, and then submitted that result.
skydhash•5 days ago
It’s not “having to squash”. The intent was already for a PR to be a single commit. I could squash it on my end and merge by rebasing, but any alteration would then need to be force-pushed. So I don’t bother. I squash-merge when it’s ready and delete the branch.
lamasery•5 days ago
Squash-merge is entirely fine for small PRs. Cleaning up the commits in advance (probably to just squash them to one or two anyway) is extra work, and anything that discourages people from pushing often (to get the code off their local machine) needs to be well-justified. Just review the (smallish!) total outcome of all the commits and squash after review. A few well-placed messages on the commit, attached to relevant lines, are more helpful and less work than cleaning up the commit history of a smallish PR.

For really large PRs, I’m more inclined to agree with you, but those should probably have their own small-PR-and-squash-merge flow that naturally cleans up their git history, anyway.

I categorically disagree that squash-merge is “stupid” but agree there are many ways to skin this cat.

LinXitoW•5 days ago
How does not squash merging deal with the fact that branches disappear when merging? What I mean is that the information "this commit happened in the context of this PR or this overarching goal" goes missing. When you squash, you use the one central unit of information management in Git: the commit.
seba_dos1•4 days ago
The commit graph is a full-blown DAG that you can operate on and form in any way you like that helps you achieve your goals. When merging something in you get back pointers to (at least) two parents that let you see what came from which branch, and a merge commit has its own commit message that lets you describe overarching goals. Even when doing rebase-before-merge flow you can still group things by merge commits, which are often used to have PRs referenced in the repository while keeping the history effectively linear and easy to browse. This way you keep the one central unit of information management in Git representing what it's supposed to - the atomic unit of change that you can build upon and traverse in various ways depending on context, rather than force larger things to squeeze into it for no good reason.

(and if you hadn't squashed on merge, short-lived branches wouldn't even "disappear" in the first place as you would still see them decorated in "git log" on commits that were merged in)

filcuk•5 days ago
Having the tree easy to filter doesn't matter if it returns hundreds of commits you have to sift through for no reason.
seba_dos1•5 days ago
Having the commit graph easy to filter means exactly that you don't have to sift through hundreds of commits for no reason. What else did you think it would mean?
6thbit•5 days ago
Calling squash stupid sounds like a case of Dunning-Kruger.

If you've worked on a large team without squashing and without increasing frustration I'd be greatly interested to hear about it.

mikaoelitiana•5 days ago
I created a small TUI based on the article https://github.com/mikaoelitiana/git-audit
vladsanchez•5 days ago
You beat me to it! I envisioned creating some aliases but you exceeded it by building a TUI. Good job Claude! LOL ;)
grepsedawk•4 days ago
Wrapping these in a TUI is on my list. Haven't built it yet.
nola-a•5 days ago
For more insights on Git, check out https://github.com/nolasoft/okgit
nextlevelwizard•5 days ago
These are actually fun to run. Just checked from work who makes most commits and found I have as many commits in past 2 years as 3 next people.

That probably isn’t a good sign

pvtmert•5 days ago
The best is: You know that you have a major issue when the data (especially ones around commit messages) is empty or noisy.

Plus, adding an extra point: When you run git log --oneline --graph and the pattern on the left is more complex than the Persian carpet patterns or Ancient Egyptian writings in the Great Pyramid of Giza, you know it's engineering & process quality issue than the code itself...

traceroute66•5 days ago
> The 20 most-changed files in the last year. The file at the top is almost always the one people warn me about.

What a weird check and assumption.

I mean, surely most of the "20 most-changed files" will be README and docs, plus language-specific lock-files etc. ?

So if you're not accounting for those in your git/jj syntax you're going to end up with an awful lot of false-positive noise.

theshrike79•5 days ago
Why would you touch the README file hundreds of times a year?

You're right about package.json, pnpm-lock etc though, but those are easy to filter out if the project in question uses them.

traceroute66•5 days ago
> Why would you touch the README file hundreds of times a year?

You're right, perhaps I should have said CHANGELOG etc.

Although some projects e.g. bump version numbers in README or add extra one-liner examples ....

mosselman•1 day ago
Just look at the second file in the list then I guess.

This post is about exploring code, not documentation. Nobody is going to warn you about the README unless it is super outdated.

raxxorraxor•5 days ago
Some readme files include changelogs. But aside from that I think this can still net some useful information. I like to look at the most recently changed files in a repo as well.
jbjbjbjb•5 days ago
It’s easy enough to filter those out with grep. It still is relatively meaningless. If the team incrementally adds things then it’s just going to show what additions were made. It isn’t churn at all.
grepsedawk•5 days ago
Fair point. I skip lockfiles, changelogs, and generated code. The first application file on the list is the one that matters. Should have been explicit about that in the post.
boxed•5 days ago
Just looking at how often a file changes without knowing how big the file is seems a bit silly. Surely it should be changes/line or something?
grepsedawk•5 days ago
Sure, normalizing by size would be more precise. But this is a quick gut check to know which files to look at first, not a metric.
fishbacon•4 days ago
Excellent set of commands.

Of course the two most useful ones would never be useful in the code base I am currently working on.

"fix" might be the single most common commit message, and after that comes "."

Trying for two years, to get people to include at least some information in their commit messages, has exhausted me.

Advertisement
Yondle•4 days ago
Hey guys this was just meant to give you inspiration, its not a set of rules. How about use what works for you (:
segfault_james•4 days ago
The churn + bug hotspot cross-reference is underrated. I've used a similar approach and the overlap between those two lists is almost always where the team's morale problems live too — not just the technical debt.
youre-wrong3•2 days ago
This was written today but isn’t stuff anyone cares about now with the age of ai.

A truth no one wants to hear. Everyone in denial.

jlarocco•5 days ago
I'm so used to magit, it seems kind of primitive to pipe git output around like this.

Anyway, I can glean a lot of this information in a few minutes scrolling through and filtering the log in magit, and it doesn't require memorizing a bunch of command line arguments.

constantius•4 days ago
I understand some people only have Emacs for magit, and I think it's very much justified: probably 95% of the use cases described here are straightforward (and flexible) operations in magit.
guilhermeasper•5 days ago
These commands are very useful, but adapting them to the codebase makes a huge difference.

For most, I added some filters and slightly changed the regex, and it showed the reality of the codebase (I already knew the reality, I just wanted to see if it matched, and it did).

tetromino_•5 days ago
Out of curiosity, I ran the 5 command on my project's public git tree. The only informative one was #4 ("Is This Project Accelerating or Dying") - it showed cliffs when significant pieces of logic were decoupled and moved to other repos.
xyst•5 days ago
might be useful if there’s an established commit message formatting. But for a majority of Fortune 500 to small businesses that I have worked for this is not the case. Usually you see shit like this:

On main:

2020-01-01: "Changes"

2020-01-05: "Changes"

2020-01-06: "merge <ref to jira/gh issue>"

2020-01-07: "revert <ref to unrelated jira/gh issue from 2 yrs ago>"

Then there’s the people that include merge commits despite agreeing on rebasing.

Occasionally see sprinkles of decent, consistently formatted commit messages.

I think this is only useful on medium to large _open source_ projects. Clearly established CONTRIBUTING.md/README.md and commit formatting/merging guide.

baquero•5 days ago
jbethune•5 days ago
Saved. Very useful. Normally I just dig around the Github UI to see what I can glean from contributor graphs and issues but these git commands are a pretty elegant solution as well.
zdkaster•5 days ago
Can't resist making it as a git command https://github.com/zdk/git-critique
Advertisement
giancarlostoro•5 days ago
> One caveat: squash-merge workflows compress authorship. If the team squashes every PR into a single commit, this output reflects who merged, not who wrote. Worth asking about the merge strategy before drawing conclusions.

I abhor squash merging for this and a few other reasons. I literally have to go out of my way to re-check out a branch. Someone who wants to use my current branch cannot do so if I merge my changes a month later, because the squash rewrites history, and now git is very confused. I don't get the obsession with "cleaning up the history" as if we're all always constantly running out of storage over 2 more commits.

stetrain•5 days ago
For me the benefit is that I can revert or cherry-pick things one entire PR at a time, and I don't have to care if the author implemented their PR with a bunch of small "work in progress" commits.

And GitHub at least sets the author of the squashed commit as the one who opened the PR, not the one who merged it.

I can definitely see where it wouldn't work well for other workflows but I've had it work well on several teams and it seems easier than trying to get everyone to clean up their commits into nice, clean, well-titled histories before putting up a PR.

ball_of_lint•5 days ago
You don't have to rewrite the source branch to squash merge?

I wouldn't describe it as "cleaning up the history". And the goal isn't to save space, it's to keep a linear history where things ought to be working at each commit (to enable tools like git bisect and similar).

I personally don't ensure everything is working every time I commit - That's what CI is for. The exact process I work through while writing a PR shouldn't impact other people's workflows, so when I merge back into a central branch it should really only reveal the granularity at which I assert 'this code is working and good', which is NOT every intermediate commit I make. Squash merge is a way to do that that fits nicely with existing engineering workflows, like code review.

uniqid•3 days ago
Thanks for sharing! The firefighting definitely pushed a button for me, I'll give all of these a try.
cratermoon•5 days ago
This is the premise of the excellent book Your Code as a Crime Scene. The history and structure of the codebase reveals a wealth of information.
md224•5 days ago
The last sentence of the article is "Here’s what the rest of the week looks like." and then it just stops. Am I missing something?
dgb23•5 days ago
It’s phrased in a confusing way, seems to be a mistake. It becomes clearer when you click the link in the sentence before.
lkakitani•5 days ago
It is probably referring to the article linked in the "codebase audit" text
Ultcyber•5 days ago
Nice set of commands! I would suggest using --all flag with git log though - scans through all branches and not just the current one
pwr1•5 days ago
Solid list. I'd add git log --all --oneline --graph pretty early on — gives you a quick sense of how active different branches are and whether this is a "one person commits everything" project or actually distributed. Helped me a ton on a job where I inheritied a monolith with like 4 years of history.

The git blame tip is underrated. People treat it like a gotcha tool but its maybe the fastest way to find the PR/ticket that explains a weird decision.

stackedinserter•5 days ago
This should be renamed to "Git commands that I run as a new hire to get metrics I'll forget on day 2".
therealdeal2020•5 days ago
superficial. If I have to unfuck the backend 10 times a week in our API adapter, then these commands will show me constantly changing the API adapter, although it's the backend team constantly fixing their own bugs
tom-blk•5 days ago
Nice! Will probably adopt this, seems to give a great overview!
aidenn0•5 days ago
What's the subversion equivalents to these commands?
Advertisement
yieldcrv•5 days ago
blog posts are just comments that would have been torn apart if only posted on a forum, now masquerading as important universal edicts
herrmaier•4 days ago
Made a claude skill! This is gold
siva7•5 days ago
Thanks. What a great Skill for my Claude
ianberdin•5 days ago
Well, 70% of my commits are “123”.
atlgator•5 days ago
Step 6: grep the thread count on the squash-merge debate to determine if the team has unresolved interpersonal conflict.
jayd16•5 days ago
No searching the codebase/commits for "fuck" and shit"? That will give you an idea what what was put in under stressful circumstances like a late night during a crunch.
user20251219•5 days ago
thank you - these are useful
drob518•5 days ago
Nice timing. I was just today needing some of the info that these commands surface. Serendipitous!
ML0037•5 days ago
i’ll try to use the in an hook and test them with Claude. Thank you !
hahooh•4 days ago
only works with teams that have proper commit messages.
Advertisement
kittikitti•5 days ago
This is a great list of commands to quickly understand a repository. Thank you for sharing.
kilbey1•4 days ago
Agreed.
sigmonsays•4 days ago
I have a strong suspicion this is AI slop. I also think this article draws way too many conclusions from a git log.
heliumtera•5 days ago
So you value more rushed descriptions of changes than actual changes. Nice
jwpapi•5 days ago
Thats why I’m visting HN.

Thank you.

progx•5 days ago
Before, I ask AI "is this project maintained" done.
lavp•4 days ago
I made a bash function to turn these commands into a one page diagnostics report so that you can use this in your `.bashrc`:

Diagnostics function, colorized (I tried to add guards so it is portable with terminals that do not support color):

  git_diag() {
    local since="${1:-1 year ago}"
    local root repo branch

    # --- patterns ---
    local pattern="${GIT_DIAG_PATTERN:-fix|bug|broken|hotfix|incident|issue|patch}"
    local firefight_pattern="revert|hotfix|emergency|rollback"

    # --- colors ---
    local GREP_COLOR_MODE='never'
    if [[ -z "${NO_COLOR:-}" ]] && [[ -t 1 ]] && [[ "${TERM:-}" != "dumb" ]] && [[ "$(tput colors 2>/dev/null || echo 0)" -ge 8 ]]; then
      local BLACK=$(tput setaf 0)
      local RED=$(tput setaf 1)
      local GREEN=$(tput setaf 2)
      local YELLOW=$(tput setaf 3)
      local BLUE=$(tput setaf 4)
      local MAGENTA=$(tput setaf 5)
      local CYAN=$(tput setaf 6)
      local WHITE=$(tput setaf 7)
      local BOLD=$(tput bold)
      local DIM=$(tput dim 2>/dev/null || true)
      local RESET=$(tput sgr0)
      GREP_COLOR_MODE='always'
    else
      local BLACK='' RED='' GREEN='' YELLOW='' BLUE='' MAGENTA='' CYAN='' WHITE=''
      local BOLD='' DIM='' RESET=''
    fi

    local TITLE="$CYAN"
    local COLOR_COUNT="$CYAN"
    local COLOR_FILE="$YELLOW"

    if ! root="$(git rev-parse --show-toplevel 2>/dev/null)"; then
      printf 'git_diag: not inside a Git repository\n' >&2
      return 1
    fi

    repo="${root##*/}"
    branch="$(git branch --show-current 2>/dev/null)"
    branch="${branch:-DETACHED}"

    _git_diag_fmt_count() {
      local count_color="$1"
      local text_color="$2"

      awk -v count_color="$count_color" -v text_color="$text_color" -v reset="$RESET" '{
        c=$1
        $1=""
        sub(/^ +/, "")
        printf "  %s%10d%s  %s%s%s\n", count_color, c, reset, text_color, $0, reset
      }'
    }

    printf '%s%sGit repo diagnostics%s\n' "$BOLD" "$TITLE" "$RESET"
    printf '%s%-11s%s %s\n' "$BOLD" "Repo:"      "$RESET" "$repo"
    printf '%s%-11s%s %s\n' "$BOLD" "Branch:"    "$RESET" "$branch"
    printf '%s%-11s%s %s\n' "$BOLD" "Timeframe:" "$RESET" "$since → now"
    printf '\n\n'

    printf '%s%s1) Most changed files%s\n' "$BOLD" "$TITLE" "$RESET"
    git log --since="$since" --format='' --name-only \
      | awk 'NF' \
      | sort \
      | uniq -c \
      | sort -nr \
      | head -n 10 \
      | _git_diag_fmt_count "$COLOR_COUNT" "$COLOR_FILE"

    printf '\n%s%s2) Top contributors%s\n' "$BOLD" "$TITLE" "$RESET"
    git shortlog -sn --no-merges --since="$since" \
      | head -n 10 \
      | awk -v count_color="$COLOR_COUNT" -v reset="$RESET" '{
          printf "  %s%10d%s  %s\n", count_color, $1, reset, substr($0, index($0,$2))
        }'

    printf '\n%s%s3) Bug/fix hotspots%s %s(pattern: %s)%s\n' "$BOLD" "$TITLE" "$RESET" "$DIM" "$pattern" "$RESET"
    git log --since="$since" --format='' --name-only -i -E --grep="$pattern" \
      | awk 'NF' \
      | sort \
      | uniq -c \
      | sort -nr \
      | head -n 10 \
      | _git_diag_fmt_count "$COLOR_COUNT" "$COLOR_FILE"

    printf '\n%s%s4) Commit count by month%s\n' "$BOLD" "$TITLE" "$RESET"
    git log --since="$since" --format='%ad' --date=format:'%Y-%m' \
      | sort \
      | uniq -c \
      | sort -k2r \
      | awk -v count_color="$COLOR_COUNT" -v mag="$MAGENTA" -v reset="$RESET" '
        {
          data[NR,1] = $2
          data[NR,2] = $1
          if (length($1) > max) max = length($1)
        }
        END {
          for (i = 1; i <= NR; i++) {
            printf "  %s%10s%s  %s%*d commits%s\n",
              mag, data[i,1], reset,
              count_color, max, data[i,2], reset
          }
        }
      '

    printf '\n%s%s5) Firefighting commits%s %s(pattern: %s)%s\n' "$BOLD" "$TITLE" "$RESET" "$DIM" "$firefight_pattern" "$RESET"
    git log --since="$since" -i -E \
      --grep="$firefight_pattern" \
      --date=short \
      --pretty=format:'%ad %h %s' \
      | head -n 10 \
      | awk -v mag="$MAGENTA" -v dim="$DIM" -v reset="$RESET" '{
          date=$1
          hash=$2
          $1=$2=""
          sub(/^  */, "")
          printf "  %s%-10s%s  %s%-12s%s  %s\n",
            mag, date, reset,
            dim, hash, reset,
            $0
        }' \
      | GREP_COLORS='ms=01;31' grep --color="$GREP_COLOR_MODE" -i -E "$firefight_pattern"
  }
Uncolorized diagnostics function (same, but without the colors):

  git_diag() {
    local since="${1:-1 year ago}"
    local pattern="${GIT_DIAG_PATTERN:-fix|bug|broken|hotfix|incident|issue|patch}"
    local root repo branch

    if ! root="$(git rev-parse --show-toplevel 2>/dev/null)"; then
      printf 'git_diag: not inside a Git repository\n' >&2
      return 1
    fi

    repo="${root##*/}"
    branch="$(git branch --show-current 2>/dev/null)"
    branch="${branch:-DETACHED}"

    _git_diag_fmt_count() {
      awk '{
        c=$1
        $1=""
        sub(/^ +/, "")
        printf "  %10d  %s\n", c, $0
      }'
    }

    printf '============================================================\n'
    printf 'Git repo diagnostics\n'
    printf '%-11s%as\n' 'Repo:'      "$repo"
    printf '%-11s%s\n' 'Branch:'    "$branch"
    printf '%-11s%s\n' 'Timeframe:' "$since"
    printf '============================================================\n\n'

    printf '1) Most changed files (top 10)\n'
    git log --since="$since" --format='' --name-only \
      | awk 'NF' \
      | sort \
      | uniq -c \
      | sort -nr \
      | head -n 10 \
      | _git_diag_fmt_count

    printf '\n2) Top 10 contributors (no merges, since %s)\n' "$since"
    git shortlog -sn --no-merges --since="$since" \
      | head -n 10 \
      | _git_diag_fmt_count

    printf '\n3) Bug/fix hotspots (top 10, matching: %s)\n' "$pattern"
    git log --since="$since" --format='' --name-only -i -E --grep="$pattern" \
      | awk 'NF' \
      | sort \
      | uniq -c \
      | sort -nr \
      | head -n 10 \
      | _git_diag_fmt_count

    printf '\n4) Commit count by month (since %s)\n' "$since"
    git log --since="$since" --format='%ad' --date=format:'%Y-%m' \
      | sort \
      | uniq -c \
      | sort -k2r \
      | awk '
        {
          data[NR,1] = $2
          data[NR,2] = $1
          if (length($1) > max) max = length($1)
        }
        END {
          for (i = 1; i <= NR; i++) {
            printf "  %10s  %*d commits\n", data[i,1], max, data[i,2]
          }
        }
      '

    printf '\n5) 10 most recent firefighting commits (revert|hotfix|emergency|rollback)\n'
    git log --since="$since" -i -E \
      --grep='revert|hotfix|emergency|rollback' \
      --date=short \
      --pretty=format:'%ad %h %s' \
      | head -n 10 \
      | awk '{
          date=$1
          hash=$2
          $1=$2=""
          sub(/^  */, "")
          printf "  %-10s  %-12s  %s\n", date, hash, $0
        }' \
      | GREP_COLORS='ms=01;31' grep --color=always -i -E 'revert|hotfix|emergency|rollback'
  }
lpribis•5 days ago
I was curious what information I could glean from these for some popular repos. Caveat: I'm primarily an low-level embedded developer so I don't interface with large open source projects at the source level very often (other than occasionally the linux kernel). I chose some projects at random that I use.

*Mainline linux*

Most changed files: pretty much what I expected for 1 and 2... the "cutting edge" of Linux development over other OSes -- bpf and containers. The bpf verifier and AMD GPU driver might get a boost in this list due to sheer LoCs in those files (26K and 14K respectively). An intel equivalent of amdgpu_dm is #21 in the list (drivers/gpu/drm/i915/display/intel_display.c) and nvidia is nowhere to be seen (presumably due to out-of-tree modules/blobs?).

    186 kernel/bpf/verifier.c
    174 fs/namespace.c
    162 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
    161 kernel/sched/ext.c
    159 fs/f2fs/f2fs.h
Bus factor: obviously none. The top 4

    10399 Christoph Hellwig -> I only know his name because of drama last year regarding rust bindings to DMA subsystem
     8481 Mauro Carvalho Chehab -> I also know his name from the classic "Mauro, shut the fuck up!" Linus rant
     8413 Takashi Iwai -> Listed as maintainer for sound subsystem, I think he manages ALSA
     8072 Al Viro -> His name is all over bunch of filesystem code
Buggy files: Intel comes out on top of GPU drivers this time (twice). Along with KVM for x86(64), the main allocator, and BTRFS.

    1477 drivers/gpu/drm/i915/intel_display.c
    1406 MAINTAINERS
    1390 sound/pci/hda/patch_realtek.c
    1102 drivers/gpu/drm/i915/i915_drv.h
     943 arch/x86/kvm/x86.c
     928 mm/page_alloc.c
     871 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
     862 drivers/gpu/drm/i915/i915_reg.h
     840 fs/btrfs/inode.c
*GCC*

Most changed files: IR autovectorization code, riscv heuristics tables, and C++ template handling (pt.c is "paramaterized types").

    152 gcc/tree-vect-stmts.cc
    145 gcc/config/riscv/riscv.cc
    131 gcc/tree-vect-loop.cc
    116 gcc/cp/pt.cc
Buggy files: DWARF debuginfo generation, x86 heuristics tables, RS6000(?!) heuristic tables. I had to look up RS6000, it's an IBM instruction set from the 90s lol. cp-tree.h is an interesting file, it seems be the main C(++) AST datastructures.

   1017 gcc/dwarf2out.c
    885 gcc/config/i386/i386.c
    796 gcc/cp/cp-tree.h
    740 gcc/config/rs6000/rs6000.c
    720 gcc/cp/pt.c
*xfwm4* Most changed files: the list is dominated by *.po localizations. I filtered these out. Even after this, I discovered there is very little active development in the last few years. If I extend to 4 years ago, I get: 1. src/client.c - Realizing this project is too "small" to glean much from this. client.c is just the core X client management code. Makes sense. 2. src/placement.c - Other core window management code.

This has not told me much other than where most of the functionality of this project lies.

Bus factor: Pretty huge. Not really an issue in this case due to lack of development I guess.

    3298  Olivier Fourdan
     530  Anonymous
     319  Xfce Bot
     121  Jasper Huijsmans

Files with bug commits: Very similar distribution to most changed files. Not enough datapoints in this one to draw any big conclusions.

I think these massive open projects (excl xfwm) are generally pretty consistent code quality across the heavily trodden areas because of the amount of manpower available to refactor the pain points. I've yet to see an example of "god help you if you have to change that file" in e.g. linux, but I have of course seen that situation many times in large proprietary codebases.

grepsedawk•5 days ago
Big projects tend to self-correct. These commands hit differently on private codebases with 3-10 contributors, where high-churn usually means one person patching the same thing repeatedly.
croemer•5 days ago
This is better than the post itself. Showing real output from a real repo.
gpvos•5 days ago
Ah yes, good old

    |sort |uniq -c |sort -nr |head -20
I use it often.
avazhi•5 days ago
More AI slop.

Wtf is happening to this website

gpvos•5 days ago
Most often, what is happening is that people are groundlessly accusing others of writing AI slop.
twoodfin•5 days ago
This is 100% AI slop. It’s really not obvious to you?

Look at the rest of this blog:

https://piechowski.io/post/

Almost no posts since 2020, then a swarm of LLM-style clickbait titles…

Oh wait, the 2020 one also has a clickbait title… and it was substantially rewritten in 2026!!

alexhans•5 days ago
I'd be curious to see if my blog posts/titles feel like AI slop to you.

https://alexhans.github.io/

No need to read them, just a vibe check would be insightful. It's weird how branding, even before AI had a lot of the same catchy patterns, and now it's hard to define what is the right prose (engineers might want one thing and other role families others) and sometimes you're trying to write almost with the "everyone else bag in mind" because that's the personal connections you link your "here's what I often repeat in written form".

gpvos•5 days ago
Maybe it is. But the comments complaining about it are worse than the posts themselves. And as I wrote, many of them are wrong. Downvote or ignore, and move on, please.
yayadarsh•5 days ago
git commands I run before reading any code:

git rm -rf .

Advertisement