[HN Gopher] Git commands I run before reading any code
___________________________________________________________________
Git commands I run before reading any code
Author : grepsedawk
Score : 1840 points
Date : 2026-04-08 08:53 UTC (18 hours ago)
HTML web link (piechowski.io)
TEXT w3m dump (piechowski.io)
| gherkinnn wrote:
| These are some helpful heuristics, thanks.
|
| This list is also one of many arguments for maintaining good Git
| discipline.
| pzmarzly wrote:
| 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 wrote:
| 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 wrote:
| 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 wrote:
| 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?)).
| arccy wrote:
| The only reasonable way to use signing in jj is with the
| sign-on-push config https://docs.jj-
| vcs.dev/latest/config/#automatically-signing... rather
| than as commits are made
| Zambyte wrote:
| Why? I have my signing behavior set to own and I haven't
| noticed any issues, but I don't actually rely on
| signatures for much.
| singron wrote:
| If you need to type in a password to unlock your keychain
| (e.g. default behavior for gpg-agent), then signing
| commits one at a time constantly is annoying.
|
| Does "own" try to sign working copy snapshot commits too?
| That would greatly increase the number and frequency of
| signatures.
| Zambyte wrote:
| Ah, I use my SSH key to sign my commits and I don't have
| a password on my SSH key.
|
| > Does "own" try to sign working copy snapshot commits
| too?
|
| Yes
| mamcx wrote:
| 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.
| Exoristos wrote:
| One rarely needs more from git than `git add -A && git
| commit -m`.
| tcoff91 wrote:
| I rebase stacked diffs all the time so jj makes my life
| so much easier because its rebasing is much more
| ergonomic than git.
| beanjuiceII wrote:
| this seems very easy in git tho how much easier can it
| get, do you have an example of each of them?
| dpatterbee wrote:
| Git rebases don't work if there are conflicts, jj doesn't
| have this problem. Also idk if you can rebase onto
| multiple parents with git but jj can do it.
| aidos wrote:
| Can you explain how conflicts are not conflicts?
|
| If I change a line of code several times and rebase on to
| a branch that changed the same lines of code, how are you
| sure what the right one is?
| sunnyps wrote:
| JJ can save conflict related state with the change so
| that you don't need to resolve a conflict in the middle
| of a stack of changes for rebasing to continue for the
| remaining changes. Concretely, it uses a "conflict
| algebra" where it can track the impact of a conflict as
| it propagates through the stack of rebased changes:
| https://docs.jj-vcs.dev/latest/technical/conflicts/
| waisbrot wrote:
| That sounds like https://git-scm.com/book/en/v2/Git-
| Tools-Rerere ?
| palata wrote:
| > 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.
| rjh29 wrote:
| 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?
| SatvikBeri wrote:
| 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.
| palata wrote:
| I think the "incompatible" was more in the dvorak sense,
| which I believe is that whenever you are on another
| computer, it most likely won't have dvorak.
|
| For jujutsu, it's fine on your own computer, but you
| probably have to use git in the CI or on remote servers.
| And you probably started with git, so moving to jujutsu
| was an added effort (similar to dvorak).
| FrankBooth wrote:
| It doesn't support submodules. So no, not totally
| compatible.
| zhengyi13 wrote:
| That's a feature, not a bug /s
| herewulf wrote:
| Reminds me of how I started using Git when it was up and
| coming: It was the best Subversion client out there and
| no one knew I was using it!
| RankingMember wrote:
| 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.
| deno wrote:
| I mean let's not be hasty. Mechanical keyboards used to be
| just normal keyboards when computers were still computers.
| rjh29 wrote:
| That is a fair argument. I don't know why they dropped
| out of favour - price? Noise?
| lamasery wrote:
| My guess would be price. Shoppers probably got more
| sensitive to the price of a keyboard as the price of
| computers dropped, and approximately none of them were
| choosing between two computer-bundles at the store with
| any regard for keyboard quality.
| deno wrote:
| Most people and companies just use the keyboard that
| shipped with the computer. I don't think noise is as much
| of an issue as people make it out be.
|
| Marketing made up this story about linear switches being
| for gamers. So now every mechanical keyboard needs to
| make unnecessary noise and offer extra resistance for
| harder bottom out or you're not a serious typist.
|
| But that's not inherent to the keyboard. Linear switches
| are not any louder than cheapo office high-profile
| membrane.
| palata wrote:
| 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 :-).
| bastardoperator wrote:
| Looks like the Perl of Git too. Those commands are wild
| compared to vanilla git.
| buu700 wrote:
| 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.
| faangguyindia wrote:
| I can't remember all of this, does anyone know of any LLM model
| trained on CLI which can be run locally?
| lamasery wrote:
| If you copy those commands into a file and use that file to
| prompt the "sh" LLM.
| stingraycharles wrote:
| That works until you need a small variation of any of these
| commands and you're lost.
| esafak wrote:
| Not a model, but a product: warp.dev
| fainpul wrote:
| Try https://cheat.sh/
| gib444 wrote:
| 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 wrote:
| 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 wrote:
| 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.
| stingraycharles wrote:
| 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.
| mgfist wrote:
| Same, but now with AI I don't have to remember that anymore
| awesome_dude wrote:
| For now - the law of enshittification means that the
| free/cheap access to AI will be curtailed soon enough.
| mgfist wrote:
| Pretty much any OS locally runnable LLM can generate this
| stuff.
| Cthulhu_ wrote:
| 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.
| crispyambulance wrote:
| 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).
| weedhopper wrote:
| 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?
| rusted_gear wrote:
| I've found tldr to be useful
|
| https://github.com/tldr-pages/tldr
| arcanemachiner wrote:
| Navi is good for generating personal cheatsheets:
|
| https://github.com/denisidoro/navi
|
| But for Git, I can't recommend lazygit enough. It's an
| incredible piece of software:
|
| https://github.com/jesseduffield/lazygit
| alwillis wrote:
| Cheaters: https://brettterpstra.com/projects/cheaters
| freedomben wrote:
| > _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.
| dheera wrote:
| I just use Claude Code as a terminal for git these days.
| It writes up better commit messages than I would write
| anyway. No more "git commit -m fix"
| freedomben wrote:
| indeed, I held off for a while but finally caved because
| I got sick of seeing commits with `git commit -m .`
| littered in there. These are personal projects so I'm the
| only one dev-ing on them, but still so nice to have
| commit messages.
| selcuka wrote:
| That could work if Claude Code made the code changes, but
| if you made them and only asked Claude to commit them,
| how does it know "why" you made those changes? Does it
| have access to your bug tracking system, for example?
| awesome_dude wrote:
| If Claude was used in the creation of the change, there's
| usually some dialogue for Claude to use.
|
| FWIW i use Claude to help with code changes, then give
| the diff to Gemini to review/ create meaningful commit
| messages
| bluGill wrote:
| I refuse to have alises and other custom commands. Either
| it is useful for everyone and so I make a change to the
| upstream project (I have never done this), or it won't
| exist next time I change my system so there is no point.
| I do have some custom tools that I am working on that
| haven't been released yet, but the long term goal is
| either delete them or release them to more people who
| will use them so I know it will be there next time I use
| a different system.
| irishcoffee wrote:
| > I refuse to have alises and other custom commands.
|
| I am the same way, and have caught much flack for it over
| the years.
|
| But when I sit down at a foreign system (foreign in the
| sense that I haven't used it before) because something is
| broken and my help was requested, I don't have any need
| to lean on aliases.
|
| I worked with someone once that had a very impressive
| bashrc, and it was very effective for them... on their
| workstation. Plop them in front of a production system,
| they can't even remember how to remount / rw because
| they've been using an alias for so long.
|
| This is also why I learned vi, having started with emacs
| 30 years ago initially, as it was first taught to me. I
| know it'll be there, and I know how to use it.
| tcoff91 wrote:
| You don't need aliases when you have fzf fuzzy history
| search with ctrl-r
| alwillis wrote:
| > 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.
| TeMPOraL wrote:
| Unless you're aware that such powerful commands are
| something you need once in a blue moon, and then you're
| grateful that the tool is flexible enough to allow them
| in the first place.
|
| Git may be sharp and unwieldy, but it's also one of the
| decreasing amount of _tools_ we still use - the trend of
| turning tools into toys consumed the regular user market
| and is eating into tech software as well.
| crispyambulance wrote:
| Tools, done right, are a joy to use and allow you to be
| expressive and precise while also saving you labor. Good
| tools promote mastery and creative inquiry.
|
| Git is NOT that.
|
| Git is something you use to get stuff done, until it
| becomes an irritating obstacle course of incidental
| complexity.
| irishcoffee wrote:
| Hg is a joy to use compared to git. Sure wish hg had won.
| skydhash wrote:
| Why should there be tolerance? You look it up once, then
| write a script or an alias if it's part of your workflow.
| Or made a note if it's worth that. I use magit and I get
| quick action and contextual help at every step of my
| interaction with git.
| dec0dedab0de wrote:
| 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.
| awesome_dude wrote:
| 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.
| ngruhn wrote:
| 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.
| jcynix wrote:
| > Didn't git pioneer this sub-command style?
|
| No, various other tools used it before git, e.g. openssl.
| kelvinjps wrote:
| 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.
| neonstatic wrote:
| 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.
| dewey wrote:
| 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.
| robrain wrote:
| 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
| TheRealPomax wrote:
| 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.
| SoftTalker wrote:
| Yeah especially with git. All I know is pull, add, commit,
| push. Everything else I have to look up.
| usrbinbash wrote:
| > I don't understand how people can remember all these custom
| scripting languages.
|
| We can't.
|
| Why do you think the `man` command exists?
| drob518 wrote:
| 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.
| Fokamul wrote:
| 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?
| dzaima wrote:
| 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).
| limaoscarjuliet wrote:
| 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...
| NoSalt wrote:
| So, how does one iterate over an array in jq? Asking for a
| friend.
| gspr wrote:
| 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).
| TeMPOraL wrote:
| 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.
| socalgal2 wrote:
| 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 wrote:
| 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 wrote:
| 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.
| robinsonb5 wrote:
| > 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.
|
| I agree with you - and yet the barcode library I used
| recently for a variable-data-printing project was last
| updated 13 hours ago, despite having been around since
| 2008!
| xp84 wrote:
| 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.
| latexr wrote:
| > 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.
| saila wrote:
| 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 wrote:
| 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.
| newsoftheday wrote:
| 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 wrote:
| 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.
| dcre wrote:
| 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 wrote:
| 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.
| cynicalsecurity wrote:
| Not interested, thank you.
| NamlchakKhandro wrote:
| Didn't ask for it thanks
| ramon156 wrote:
| > 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?
| mememememememo wrote:
| 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.
| dewey wrote:
| 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 wrote:
| Yeah same thing happens with lockfiles and CI configs. You
| end up filtering out half the list before it tells you
| anything useful.
| pydry wrote:
| 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_ wrote:
| 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.
| szszrk wrote:
| Could be also that a frequently edited file had most
| opportunity to be broken. And it was edited by the most random
| crowd.
| rbonvall wrote:
| Just like that place that's so crowded nobody goes there
| anymore.
| mchaver wrote:
| 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.
| jbjbjbjb wrote:
| 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 wrote:
| Good thing that the article contains that warning, then.
| jbjbjbjb wrote:
| 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".
| hamburglar wrote:
| The post is "here's what I do", not "here's what you
| should do and then confront the team about the results."
| It's just showing you a quick way to get some insights.
| It's not even guaranteeing it's accurate, just showing
| you some things you might be able to draw some quick
| conclusions on.
|
| I'm not sure why HN attracts this need to poke holes in
| interesting observations to "prove" they aren't actually
| interesting.
| jbjbjbjb wrote:
| It's a bit reductive to call it poking holes. The author
| shared his valuable knowledge and I shared mine.
| hamburglar wrote:
| You said this analysis "isn't strong enough" for an
| inadvisable scenario you completely invented.
| Eldt wrote:
| 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 wrote:
| 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
| mayama wrote:
| These commands are just about what files to start looking at
| to understand new codebase.
| functional_dev wrote:
| 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...
| KptMarchewa wrote:
| In my case, it's .github/CODEOWNERS.
|
| Nobody is afraid of changing it.
| mayama wrote:
| Why does github owners need frequent change? Do members in
| you team change so often?
| jollyllama wrote:
| Yeah, the truth is going to be a lot more subtle than this.
| furyofantares wrote:
| The LLM that wrote the copy is an idiot.
| jamwil wrote:
| This is such obvious LLM slop.
| berkes wrote:
| 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.
| zikani_03 wrote:
| 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.
| agumonkey wrote:
| 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.
| seba_dos1 wrote:
| > 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 wrote:
| 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 wrote:
| 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.
| zaphirplane wrote:
| 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
| duskdozer wrote:
| if you mean better messages, it's not really that. those
| junk messages _should_ be rewritten and if the commits
| don 't stand alone, merged together with rebase. it's the
| "logical chunks" the parent mentioned.
|
| it's hard to say fully, but unless a changeset is quite
| small or otherwise is basically 0% or 100%, there are
| usually smaller steps.
|
| like kind of contrived but say you have one function that
| uses a helper. if there's a bug in the function, and it
| turns out to fix that it makes a lot more sense to change
| the return type of the helper, you would make commit 1 to
| change the return type, then commit 2 fix the bug. would
| these be separate PRs? probably not to me but I guess it
| depends on your project workflow. keeping them in
| separate commits even if they're small lets you bisect
| more easily later on in case there was some unforseen or
| untested problem that was introduced, leading you to
| smaller chunks of code to check for the cause.
| orsorna wrote:
| If the code base is idempotent, I don't think showing
| commit history is helpful. It also makes rebases more
| complex than needed down the line. Thus I'd rather squash
| on merge.
|
| I've never considered how an engineer approaches a
| problem. As long as I can understand the fundamental
| change and it passes preflights/CI I don't care if it was
| scryed from a crystal ball.
|
| This does mean it is on the onus of the engineer to
| explain their change in natural language. In their own
| words of course.
| seba_dos1 wrote:
| Commits don't show "how an engineer approaches a
| problem". Commits are the unit of change that are
| supposed to go into the final repository, purposefully
| prepared by the engineer and presented for review. The
| only thing you do by squashing on merge is to
| artificially limit the review unit to a single commit to
| optimize the workflow towards people who don't know how
| to use git. Personally I don't think it's a good thing to
| optimize for.
| orsorna wrote:
| Preserving commit history pre-merge only seems useful if
| I had to revert or rebase onto an interstitial commit.
| This is at odds with treating PRs as atomic changes to
| the code base.
|
| I might have not stated my position correctly. When I
| mean "squash on merge", I mean the commit history is
| fully present in the PR for full scrutiny. Sometimes
| commits may introduce multiple changes and I can view
| commit ranges for each set of changes. But it takes the
| _summation_ of the commits to illustrate the change the
| engineer is proposing. The _summation_ is an atomic
| change, thus scrutinizing terms post-merge is
| meaningless. Squashing preserves the summation but rids
| of the terms.
|
| Versioned releases on main are tagged by these
| summations, not their component parts.
| OkayPhysicist wrote:
| If you don't care about how the problem was solved, why
| are you reviewing it at all?
| yokoprime wrote:
| 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.
| hhjinks wrote:
| You review code not to verify the actual output of the
| code, but the code itself. For bugs, for maintainability.
| Commit hygiene is part of that.
| seba_dos1 wrote:
| I have no troubles working on big FLOSS projects where
| reviews usually happen at the commit level :)
| theshrike79 wrote:
| So if a PR consists of 20 commits, they review every
| single commit linearly without looking at the end result
| first?
| seba_dos1 wrote:
| Yes, and in some projects 20 commits is not even a big
| PR, more like "regular sized". The LKML's first page is
| now full of PRs with around 20 commits, here's a random
| one as an example: https://lore.kernel.org/netdev/2026040
| 8121252.2249051-1-dhow...
|
| And here's a slightly smaller one which isn't about
| "miscellaneous fixes": https://lore.kernel.org/netdev/202
| 60408122027.80303-1-xuanzh...
|
| Some of these commits even get reviewed by different
| maintainers before being merged, which is common when a
| patchset touches several subsystems at once.
| tasuki wrote:
| > A good reviewer looks at the end-state and does not
| care about individual commits.
|
| Then I must be a bad reviewer. In a past job, I had a
| colleague who meticulously crafted his commits - his PRs
| were a joy to review because I could go commit by commit
| in logical chunks, rather than wading through a single 3k
| line diff. I tried to do the same for him and hope I
| succeeded.
| theshrike79 wrote:
| And then someone comments on a thing, they change it and
| force-push another "clean" history on top and all of your
| work is wasted because the PR is now completely different
| =)
| KptMarchewa wrote:
| Split the PR rather than force me to wade through your
| commit history. Use graphite or something else that
| allows you to stack PRs.
| jlokier wrote:
| Why is it "wade through" if there are 10 clearly distinct
| but dependent commits, but comfortable if it's 10 stacked
| PRs instead? They are basically the same thing, presented
| ever so slightly differently.
|
| I think in most teams I've worked with, the majority of
| developers (> 85%) barely undestand what Git is doing or
| what things mean inside GitHub, have never seen commit
| history as a graph, have never run something like "git
| log --oneline --graph --decorate" or "--format", and have
| never heard of "git range-diff" which is very useful for
| following commit/PR/unit changes.
|
| Personally I review using "git" itself, so I see the
| graph structure either way, and there's little difference
| between stacked PRs, commit chains in a single PR, or
| even feature branches, from that point of view. Even
| force-push branch updatea aren't difficult to review,
| because of the reflog and "git range-diff". The
| differences are mainly in what kinds of behaviour the
| web-based tooling promotes in the rest of the team, which
| does matter, and depends on the team.
|
| I agree with you if you're using Graphite instead of
| GitHub. Having a place to give feedback and/or approval
| on the individual "units" (commits in a PR, or PRs in a
| stack) is useful, grouping dependent but distinct changes
| is useful, and diff'd commit evolution within each unit
| PR in response to back-end-forth review feedback is
| useful in some collaborative settings. Though, if you
| know "git range-diff" and reflog, that shows diff'd
| commit evolution quite well.
|
| In GitHub, people are confused by stacked PRs both
| conceptually and due to the GitHub UX around them. Most
| times when I've posted a stacked PR to a GitHub project,
| other people didn't realise it was stacked, and
| occasinally someone else has merged the tip of a stack
| made by me, and been surprised to see all the dependent
| PRs merged automatically as a side effect. Usually before
| they get to reviewing those other PRs :-)
|
| People understand commit sequences in a PR, though I've
| rarely seen people treat the individual commits as units
| for review when using GitHub, unfortunately. In the Linux
| kernel world where Git was born, the PR flow is
| completely different from GitHub: Their system tends to
| result in feedback on individual commits. It also
| encourages better quality feedback, with less nitpicking,
| and better quality commits.
| mgfist wrote:
| Why are those not just separate PRs? Or if they really
| needed to be merged at once - they should still be
| separate PRs but on a feature branch
| seba_dos1 wrote:
| Why have PRs - groups of commits to pull - then if all
| you need is a single patch file?
| mgfist wrote:
| You can, but most of us work in Github and having a PR to
| dump commits to is very easy and convenient. Then, when
| you get some feedback on your PR, you can dump more
| commits and it's very easy for the reviewer to see what
| has changed since the last time they reviewed it.
|
| I feel like what you're arguing is that you should clean
| up your commits before anyone else sees them. Fair. But
| you could also clean it up right before merging to main.
| It's not that different, except the latter is much less
| annoying, particularly when going back and forth with
| people.
|
| I know this is a very github centric workflow, but that's
| where most engineers work now, and it's nice and easy.
| This wouldn't work for eg: contributing to linux, but
| that's not what most of us do.
| awesome_dude wrote:
| This is where the "Trunk based development" people live -
| I personally believe that commits should be atomic,
| because git bisect on smaller meaningful commits is a
| hang of a lot better than a monster 90 file change commit
| jfengel wrote:
| Sometimes I have to go back and fix a bug that appeared
| during another branch. Having the original commits helps
| me bisect it.
|
| Not often, but given that it costs me nothing to have it
| all in my tree, I'd rather have it than not.
| croemer wrote:
| 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.
| seba_dos1 wrote:
| You can do whatever you want with stuff nobody else looks
| at. I do too.
|
| I meant "shared place" as an open review request or a
| shared branch rather than shared underlying
| infrastructure. Shared by people's minds.
| mr_mitm wrote:
| You can always force-push a cleaned up version of your
| branch when you are ready for review, or start a new one
| and delete the WIP one.
| theshrike79 wrote:
| I hate (and fear) force-pushing and "cleaning up" git
| history as much as other people dislike squash-merging =)
|
| It just feels wrong to force push, destroying stuff that
| used to be there.
|
| And I don't have the time or energy to bisect through my
| shitty PR commits and combine them into something clean
| looking - I can just squash instead.
| seba_dos1 wrote:
| Nothing is destroyed by a force push. It just overwrites
| a single pointer, and even keeps its old value in reflog.
|
| Things that aren't referenced by anything anymore will
| eventually get garbage collected and actually destroyed,
| but you can just keep a reference somewhere to prevent
| that from happening if you need. Or even disable garbage
| collection completely.
|
| Looks like people's fears about git come just from not
| knowing what it does.
| Noumenon72 wrote:
| You can't use the remote reflog to revert what you force
| pushed, can you? But I agree that having your local
| reflog means you're never totally lost. I still just make
| a branch before major edits so I can go back.
| croemer wrote:
| You can, but instead you can also just squash merge in
| one click. And avoid that people merge there dozens of
| fixes if you allow anything but squash merge.
| theshrike79 wrote:
| 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?
| seba_dos1 wrote:
| Because it's a useful abstraction. If you only look at
| PRs and don't ever care about commits, why are they even
| being sent to reviewer in the first place? Just send a
| diff file.
|
| Having atomic commits lets you actually benefit from
| having them. Suddenly you don't have to perform weird
| dances with interconnected PRs with dependencies as "PR
| too big" is not such a problem anymore as long as commits
| are digestible; you can have things property bisectable;
| you can preserve shared authorship; you can range-diff
| and have a better view on what and how changed between
| review passes, and so on...
|
| The unit of change is commit, and PRs group commits you
| want someone to pull. If you don't want or need any of
| that, you're just sending a patch file in a needlessly
| elaborate way.
| Anon1096 wrote:
| > If you only look at PRs and don't ever care about
| commits, why are they even being sent to reviewer in the
| first place? Just send a diff file.
|
| This is in fact what hg does with amending changesets and
| yes it works far better. Keep PRs small and atomic and
| you never need to worry about what happens intra-pr. If
| you need bigger units of work that's what stacking is
| for.
| seba_dos1 wrote:
| Stacking is good for expressing dependencies, but isn't
| helpful when you need to make several distinct changes
| that aren't necessarily needed unless you take them all
| in. What's the value in having a separate PR that
| introduces a framework that you later use in another PR
| when you may not actually want to merge it if the latter
| one doesn't end up being merged as well?
|
| A PR is a group of commits, just utilize that when you
| need it.
| ipsento606 wrote:
| >Swap to diff and start reading through the changes
|
| this forces the reviewer to view the entire diff at once,
| which can greatly increase the cognitive load vs. being
| able to view diffs of logical units of work
|
| for tiny PRs it may not matter, but for substantial PRs
| it can matter a lot
| jfultz wrote:
| In some cases, reviewing PR diffs commit-by-commit (and
| with the logs as the narration of the diff-by-diff story)
| is a substantial improvement over reviewing the entire PR
| diff. Concrete examples...
|
| * A method or function that has code you realize needs to
| be shared...the code may need to be moved and also
| modified to accommodate its shared purpose. Separating
| the migration from any substantive modifications allows
| you to review the migration commit with the assistance of
| git's diff.colorMoved feature. It becomes easier to
| understand what changes are due to the migration, and
| what changes were added for more effective sharing.
|
| * PRs sometimes contain mechanical work that is easy to
| review in isolation. Added or removed arguments, function
| renames, etc. No big deal if it's two or three instances,
| but if it's dozens or hundreds of instances, it's easier
| for the humans to review all of those consistent changes
| together, rather than having them mixed in with other
| things one has to reason about.
|
| * Sometimes a flow of commits can help follow a difficult
| chain of reasoning. PR developer claims that condition X
| can never occur, but the code is complex enough that it's
| difficult to verify. However, by transforming the code in
| targeted ways that are possible to reason about, the
| complexity might be reducible to the point where the
| claim becomes obvious. One frequent example I see of this
| is of function/method arguments that are actually
| unnecessary, but it wasn't obvious until after some code
| transformations.
| Aachen wrote:
| 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 wrote:
| > 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!
| Aachen wrote:
| Seems like a lot of extra effort (save, add, commit, come
| up with some message even if it's a prayer to work now)
| only to undo it again later and create a patch or
| alternate history out of the final version. Why bother
| with the intermediate commits if you're not planning for
| it to be part of the history?
| skydhash wrote:
| If the team is using a PR workflow, the PR is a working
| place to produce one single commit. The individual
| commits are just timestamped changes and comments. Think
| of it as the equivalent of annotated diff in mailing list
| conversation.
| thi2 wrote:
| Because I might want to go back to this current messy
| state but I don't want to commit it like this (hardcoded
| test strings, debug logs, cutted corners to see if
| something works, you name it).
|
| I simply commit something like "WIP: testing xy" and if
| its working and properly implemented i can
| squash/rebase/edit the commit message and force push it
| to my feature branch. Using a Git client like Gitkraken
| makes this incredibly easy, takes seconds.
|
| This way I can leverage version control without
| committing bogus states to the final PR.
| seba_dos1 wrote:
| Git is a version control system. It does not care about
| what it versions.
|
| When I work on something, I commit often and use the
| commit graph as a undo tool on steroids. I can see what I
| tried, I can cherry-pick or revert stuff while
| experimenting, I can leave promising but unfinished stuff
| to look at later, or I can just commit to have a simple
| way to send stuff to CI, or a remote backup synced
| between machines.
|
| Once I'm done working on something, it's time to take a
| step back, look at the big picture, see how many changes
| my experiments have actually yielded, separate them,
| describe and decide whether they go to review together or
| split in some way, as sometimes working on a single thing
| requires multiple distinct changes (one PR with multiple
| commits), but sometimes working in a single session
| yields fixes for multiple unrelated issues (several PRs).
| Only then it gets presented to the reviewer.
|
| It just happens that I can do both these distinct jobs
| with a single tool.
| bguebert wrote:
| Sometimes its nice to have a history like that because
| then maybe you are thinking of trying the thing they
| tried that wouldn't work and it would save you some time
| trying it if you can tell from those commits that it
| didn't work.
| tasuki wrote:
| 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 wrote:
| 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.
| thi2 wrote:
| Why are those commits ending in the PR? Just unprofessional
| to work like that.
| joshstrange wrote:
| > "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.
| psalaun wrote:
| git bisect gets more useful because it will pin a smaller set
| of changes
| BeetleB wrote:
| 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.
| filcuk wrote:
| 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 wrote:
| 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?
| arnorhs wrote:
| 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 wrote:
| 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.
| skydhash wrote:
| 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.
| l72 wrote:
| We do. If we are building out a feature, none of its code
| is merged into main until it is complete (if this is a
| big feature, we milestone into mergeable and releasable
| units).
|
| The feature is represented by a Story in Jira and a
| feature branch for that story. Subtasks in jira are
| created and multiple developers can pick up the different
| subtasks. There is a personal branch per subtasks, and
| PRs are put up against the feature branch. Those subtasks
| are code reviewed, tested, and merged into the feature
| branch.
|
| In the end, it is the feature branch that is merged (as a
| single merge commit and complete unit) into main, and may
| well have had contributions from multiple people.
| skydhash wrote:
| I get your POV, but I've always considered that long-
| lived branches in the canonical repo (the one in the
| forge) other than the main one should be directly related
| to deployable artifacts. Anything else should be short-
| lived.
|
| There can be experiment on the side that warrants your
| approach, but the amounts of merge going back and forth
| would make this hard to investigate (especially when
| blaming) I would prefer to have one single commit with a
| message that describe every contribution.
| juped wrote:
| Somewhat Linux-like. You could probably improve it purely
| from a git perspective by letting subtask dependencies be
| many-to-many (the commit graph _is_ a dependency graph),
| but what you have is probably best for your whole Jira
| workflow.
| l72 wrote:
| 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.
| juped wrote:
| I agree.
|
| I set merge.ff = false and alias ff to merge --ff-only. I
| don't use pull but I do have pull.ff = only set, just in
| case someday I do.
|
| The graph log and the first-parent log serve different
| purposes and possibly shouldn't be the same command
| conceptually; this varies by user preference but the
| first-parent log is more of a "good default", generally.
| Merges do say "Merge" at the start, after all.
|
| This is what I advise people to do in consulting
| engagements, too, it's not one of my personal quirks.
| duskdozer wrote:
| 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 wrote:
| 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.
| mcpherrinm wrote:
| 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 wrote:
| 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
| goosejuice wrote:
| 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 wrote:
| 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 wrote:
| 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.
| juped wrote:
| No.
|
| The cases where bisect fails you are, basically, ones
| where it lands on a merge that does too much - you now
| have to manually disentangle the side that did too much
| to find out exactly what interaction caused the
| regression. But this is on the rarer side because it's
| rare for an _interaction_ to be what caused the
| regression, it 's more common that it's a _change_ -
| which will be in a non-merge commit.
|
| The squash merge workflow means _every single commit_ is
| a merge that does too much. Bisect can 't find anything
| useful for you by bisection anymore, so you have to get
| lucky about how much the merge did, unenriched by any of
| the history that you deleted.
| olejorgenb wrote:
| git bisect --first-parent
| lamasery wrote:
| 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 wrote:
| 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.
| 6thbit wrote:
| 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.
| traceroute66 wrote:
| > 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 wrote:
| 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 wrote:
| > 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 ....
| raxxorraxor wrote:
| 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 wrote:
| 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 wrote:
| 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.
| JetSetIlly wrote:
| 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.
| grepsedawk wrote:
| Good catch, that's better
| nozzlegear wrote:
| 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
| j2kun wrote:
| Similarly, we have a technical concept called "rollback" that
| is unrelated to a reverted commit.
| aa-jv wrote:
| 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.
| mattrighetti wrote:
| 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 wrote:
| 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 wrote:
| 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_ wrote:
| Not the poster, but one theory: so you only need to copy one
| file. Portability.
| mr_mitm wrote:
| Looks like the above assumes a POSIX shell, so one could
| argue a dedicated script would actually be more portable.
| TonyStr wrote:
| Looks nice. Unfortunately I don't have log-of-count-and-email,
| log-of-count-and-day or churn
| petey283 wrote:
| +1 Same.
|
| Edit. https://github.com/mattrighetti/dotfiles/blob/master/.g
| itcon...
| ape4 wrote:
| You could make a local `man` page.
| not_kurt_godel wrote:
| 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.
| croemer wrote:
| 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 wrote:
| I also feel this reads like an AI slop, but at least I learned
| 5 commands. Not too bad.
| boxed wrote:
| 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 wrote:
| 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.
| alkonaut wrote:
| 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 wrote:
| 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.
| niedbalski wrote:
| Ages ago, google released an algorithm to identify hotspots in
| code by using commit messages.
| https://github.com/niedbalski/python-bugspots
| niedbalski wrote:
| Ages ago google wrote an algorithm to detect hotspots by using
| commit messages, https://github.com/niedbalski/python-bugspots
| user20251219 wrote:
| thank you - these are useful
| whstl wrote:
| _> 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.
| nola-a wrote:
| For more insights on Git, check out
| https://github.com/nolasoft/okgit
| fzaninotto wrote:
| 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
| lpribis wrote:
| 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 wrote:
| 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 wrote:
| This is better than the post itself. Showing real output from a
| real repo.
| bsuvc wrote:
| 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).
| sigmoid10 wrote:
| 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.
| itmitica wrote:
| 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 :)
| 8cvor6j844qw_d6 wrote:
| > AI generated commit messages
|
| git log --oneline and a sprinkle of your personal sauce on
| .claude goes a long way :)
| mikepurvis wrote:
| 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 wrote:
| 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.
| bikelang wrote:
| 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.
| mikepurvis wrote:
| I agree, much as it's a loss for git as a distributed
| system (though I think that ship sailed long ago
| regardless). As far as unrelated changes, I've been
| finding that another good LLM use-case. Like hey Claude
| pull this PR <link> and break it up into three new
| branches that individually incorporate changes A, B, and
| C, and will cleanly merge in that order.
|
| One minor nuisance that can come up with GitHub in
| particular when using a short reference like #123 is that
| that link breaks if the repo is forked or merged into
| something else. For that reason, I try to give full-url
| references at least when I'm manually inserting them, and
| I wish GitHub would do the same. Or perhaps add some
| hidden metadata to the merge commit saying "hey btw that
| #123 refers to <https://github.com/fancy-org/omg-
| project/issues/123>"
| tormeh wrote:
| 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.
| ramijames wrote:
| 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.
| PUSH_AX wrote:
| 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.
| freedomben wrote:
| 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).
| two_tasty wrote:
| 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.
| munksbeer wrote:
| 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 wrote:
| 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.
| PUSH_AX wrote:
| > 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?
|
| Personally no, the code is the "truth". If I need more
| I'm going to open a dialog with the author, not spend
| time trying to interpret a 7 word commit message, "good"
| or otherwise.
| macintux wrote:
| The code can only convey what is being done (and then, in
| some cases, only superficially). It can't convey what
| decisions were made, what alternatives were discarded,
| what business motivations may have led to that code.
|
| And for old enough code, the author may not be available,
| or more likely doesn't remember.
| PUSH_AX wrote:
| Fine, but none of that is in a normal commit message,
| lets be real...
| mgfist wrote:
| Which circles back to why it's important for leadership
| to tackle this
| PUSH_AX wrote:
| Yes, but not in the form of commit messages, the parent
| comment described things better suited to jira tickets,
| documentation etc.
|
| It feels like we're trying really hard to stretch the
| utility of commit messages here...
| macintux wrote:
| Mainly I was pushing back on: the code is the "truth"
|
| I don't feel that is an accurate statement for any
| complex system.
| PUSH_AX wrote:
| I don't like complex systems, and I work hard not to
| create them.
| mgfist wrote:
| Sure but code can't capture everything. Maybe with enough
| comments I guess, but not code alone. For example, code
| won't tell you that this feature was timeboxed hence this
| edgecase was not supported
| hluska wrote:
| And a commit message would convey that?
| cratermoon wrote:
| You'll at least need the discipline to include the ticket
| ID in the message. Links to documentation are ok, but
| they will likely rot and even if they don't the content
| may change such that it no longer accurately reflects the
| commit changes.
| wreath wrote:
| And what of the original author is not there anymore?
| PUSH_AX wrote:
| The world will not end. I'll get there.
| agateau wrote:
| The code is the present truth, the commit messages can
| inform you about how it got turned into this truth.
| Interestingly, I recently wrote a short article about
| this: https://agateau.com/2026/on-commit-messages/
| cratermoon wrote:
| Your argument on conventional commits is something I've
| come to agree with. There are even tools that can
| generate release notes from conventional commits, and
| they are premised on the same mistake.
| alt_422568 wrote:
| > 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.
|
| You're thinking like someone with a mature understanding
| of version control. Plenty of developers seem set on
| going their whole careers using git like beginners.
| ryandrake wrote:
| 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.
| lossyalgo wrote:
| 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.
| scottyah wrote:
| Some of my favorite are the perhaps well-meaning but
| totally misguided log of what files they changed.
| ramijames wrote:
| 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.
| godelski wrote:
| 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
| asdfman123 wrote:
| > 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 wrote:
| 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 wrote:
| 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 wrote:
| I particularly love when the "CTO" is also the main offender.
| jillesvangurp wrote:
| 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.
| sunnyps wrote:
| > 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.
|
| Why do you think OSS projects have a high bar for change
| descriptions? It's because some things matter for the
| long run.
|
| Also, it's pretty clear from the context of this
| discussion that it's about the descriptions on pull
| requests (or other units of change like CLs) and not
| individual commits that get squashed in a PR/CL.
|
| > 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.
|
| All coding agents do that these days - they just run git
| diff and figure out what the change is when writing the
| commit message. Are you saying that writing a better
| change description is not worth the pennies it costs in
| tokens?
| hbn wrote:
| 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 wrote:
| 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.
| titanomachy wrote:
| As long as there's some record, whether it's PR or
| commit. At Google and Meta there's no distinction, each
| commit is a PR (approximately) and has a description and
| discussion linked to it. I've found this really valuable
| for understanding a piece of code, maybe it's just five
| lines but of there's 200 words of discussion giving you
| more context on why it is that way.
| ygouzerh wrote:
| It can be even enforced using hooks/pipelines that will check
| that the message follow Conventional Commits as well
| grepsedawk wrote:
| 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.
| KronisLV wrote:
| > 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.
| SoftTalker wrote:
| As noted, authorship does not if commits are squashed, which
| seems to be common (I never do it).
| heinrichhartman wrote:
| 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.
| stronglikedan wrote:
| 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.
| scottyah wrote:
| git blame's are amazing, and rely on good comments.
| mkehrt wrote:
| 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.
| travisgriggs wrote:
| 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 wrote:
| > 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.
| lopis wrote:
| If developers don't write commit messages, that's a culture
| problem. At my company we demand that of each other.
| hn_throwaway_99 wrote:
| 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/ .
| yreg wrote:
| > 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 wrote:
| 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.
| harryquach wrote:
| Commit messages are often squashed after merging a feature
| branch
| kelnos wrote:
| Bad commit messages always fail PR review for me. It requires
| will and discipline, but it's not that hard.
| loremium wrote:
| 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.
| max8539 wrote:
| Sometimes it could be just a ticket number/title
| bartvk wrote:
| I think that's pretty great, actually. You can look that up
| to see more info about the commit.
| ElijahLynn wrote:
| 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.
| skinner927 wrote:
| - fix - fix fr - fix frfr - plz - omg why - never gonna give
| you up - never gonna let you down - add missing curly braces
| tkzed49 wrote:
| 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.
| AStrangeMorrow wrote:
| 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"
| aftbit wrote:
| 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).
| renegade-otter wrote:
| 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?
| baquero wrote:
| I put it into a gist :)
|
| https://gist.github.com/aeimer/8edc0b25f3197c0986d3f2618f036...
| bullen wrote:
| 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?
| Cthulhu_ wrote:
| 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.
| pscanf wrote:
| I just finished1 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.)
|
| 1 Nothing is ever finished.
| tom-blk wrote:
| Nice! Will probably adopt this, seems to give a great overview!
| therealdeal2020 wrote:
| 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
| icedchai wrote:
| 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 wrote:
| The author does not look at counter values but rather at how
| the values changes. That reveals dynamics.
| icedchai wrote:
| 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.
| TacticalCoder wrote:
| > 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.
| blenderob wrote:
| > 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?
| Sharlin wrote:
| Something something Red Queen's race
| dan-bailey wrote:
| Projects become more stable with time? Since when?
| onion2k wrote:
| 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 wrote:
| > 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 wrote:
| 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.
| goosejuice wrote:
| With respect, this is a myopic view. Not all software is
| an "app" or a monolith. If you use a terminal, you are
| directly using many utilities that by this metric are
| considered dying or dead.
| stackedinserter wrote:
| Or you hired someone who squashes or doesn't commit every
| single change.
| ziml77 wrote:
| 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 wrote:
| Is it fair to say they are being "worked on" if nothing is
| being done?
| duckmysick wrote:
| 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.
| heresie-dabord wrote:
| 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 wrote:
| This is a neat trick for a quick visual presentation, thanks!
| goosejuice wrote:
| 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 wrote:
| 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 ...
| stackedinserter wrote:
| This should be renamed to "Git commands that I run as a new hire
| to get metrics I'll forget on day 2".
| joshstrange wrote:
| 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.
| fenaer wrote:
| 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 wrote:
| 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 wrote:
| 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 wrote:
| Also - be careful of automated workflow that uses a single
| persons credential.. skews this by a lot.
| kevstev wrote:
| 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 wrote:
| 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.
| kmacdough wrote:
| 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.
| dgunay wrote:
| 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.
| perlgeek wrote:
| 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.
| maest wrote:
| I suspect OP never actually ran these commands and this article
| was brainstormed and written by an LLM.
| yieldcrv wrote:
| blog posts are just comments that would have been torn apart if
| only posted on a forum, now masquerading as important universal
| edicts
| alaudet wrote:
| This is good stuff. Why I never think of things like this is
| beyond me. Thanks
| mikaoelitiana wrote:
| I created a small TUI based on the article
| https://github.com/mikaoelitiana/git-audit
| vladsanchez wrote:
| You beat me to it! I envisioned creating some aliases but you
| exceeded it by building a TUI. Good job Claude! LOL ;)
| guilhermeasper wrote:
| 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).
| yonatan8070 wrote:
| 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.
| StableAlkyne wrote:
| 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!
| aidenn0 wrote:
| What's the subversion equivalents to these commands?
| arthurjj wrote:
| 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 wrote:
| I can't speak for most, but the past few places I consulted or
| worked at used monorepos.
| BigTTYGothGF wrote:
| Jesus I've seen what you've done for others and want that for
| myself.
| abustamam wrote:
| ?
| atlgator wrote:
| Step 6: grep the thread count on the squash-merge debate to
| determine if the team has unresolved interpersonal conflict.
| jayd16 wrote:
| 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.
| tetromino_ wrote:
| 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.
| avazhi wrote:
| More AI slop.
|
| Wtf is happening to this website
| gpvos wrote:
| Most often, what is happening is that people are groundlessly
| accusing others of writing AI slop.
| twoodfin wrote:
| 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 wrote:
| 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 wrote:
| 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.
| heliumtera wrote:
| So you value more rushed descriptions of changes than actual
| changes. Nice
| progx wrote:
| Before, I ask AI "is this project maintained" done.
| yayadarsh wrote:
| git commands I run before reading any code:
|
| git rm -rf .
| drob518 wrote:
| Nice timing. I was just today needing some of the info that these
| commands surface. Serendipitous!
| md224 wrote:
| 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?
| lkakitani wrote:
| It is probably referring to the article linked in the "codebase
| audit" text
| dgb23 wrote:
| It's phrased in a confusing way, seems to be a mistake. It
| becomes clearer when you click the link in the sentence before.
| jlarocco wrote:
| 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.
| zdkaster wrote:
| Can't resist making it as a git command
| https://github.com/zdk/git-critique
| kittikitti wrote:
| This is a great list of commands to quickly understand a
| repository. Thank you for sharing.
| konovalov-nk wrote:
| 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
| Ultcyber wrote:
| Nice set of commands! I would suggest using --all flag with git
| log though - scans through all branches and not just the current
| one
| nextlevelwizard wrote:
| 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
| moritzwarhier wrote:
| 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 wrote:
| 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.
| pwr1 wrote:
| 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.
| giancarlostoro wrote:
| > 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 wrote:
| 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 wrote:
| 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.
| siva7 wrote:
| Thanks. What a great Skill for my Claude
| ML0037 wrote:
| i'll try to use the in an hook and test them with Claude. Thank
| you !
| gpvos wrote:
| Ah yes, good old |sort |uniq -c |sort -nr |head
| -20
|
| I use it often.
| xyst wrote:
| 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.
| jbethune wrote:
| 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.
| cratermoon wrote:
| 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.
| ivanjermakov wrote:
| 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.
| kelnos wrote:
| 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".
| fmbb wrote:
| > 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.
| ianberdin wrote:
| Well, 70% of my commits are "123".
| pvtmert wrote:
| 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...
| jwpapi wrote:
| Thats why I'm visting HN.
|
| Thank you.
| youknownothing wrote:
| 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 wrote:
| Nice to see a fellow Tornhill fan. I loved his early C
| articles.
| lavp wrote:
| 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 pa
| ttern="${GIT_DIAG_PATTERN:-fix|bug|broken|hotfix|incident|issue|p
| atch}" 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' }
| sigmonsays wrote:
| I have a strong suspicion this is AI slop. I also think this
| article draws way too many conclusions from a git log.
| Yondle wrote:
| Hey guys this was just meant to give you inspiration, its not a
| set of rules. How about use what works for you (:
| RickHull wrote:
| 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|de
| fect|regression|hotfix|broke)' --since='1 year ago'
| bugfiles = !git log --name-only --format='' -i -E --grep='(bug|bu
| gfix|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
___________________________________________________________________
(page generated 2026-04-09 03:00 UTC)