14 ms·
Git commands I run before reading any code
- deleted 6mo ago[deleted]
- gherkinnn 6mo agoThese are some helpful heuristics, thanks. This list is also one of many arguments for maintaining good Git discipline.
- pzmarzly 6mo agoJujutsu 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.
- faangguyindia 6mo agoI can't remember all of this, does anyone know of any LLM model trained on CLI which can be run locally?
- lamasery 6mo agoIf you copy those commands into a file and use that file to prompt the “sh” LLM.
- stingraycharles 6mo agoThat works until you need a small variation of any of these commands and you’re lost.
- esafak 6mo agoNot a model, but a product: warp.dev
- fainpul 6mo agoTry https://cheat.sh/ https://cheat.sh/
- palata 6mo agoTo 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 6mo agoTbf 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 6mo agoActually, 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 6mo agoThe only reasonable way to use signing in jj is with the sign-on-push config https://docs.jj-vcs.dev/latest/config/#automatically-signing-commits https://docs.jj-vcs.dev/latest/config/#automatically-signing... rather than as commits are made
- Zambyte 6mo agoWhy? 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.
- gib444 6mo agoHah 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 6mo agoIt'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 6mo agoIt doesn't seem any more egregious than something like: `git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --` Which is something I see a lot of people alias in Git for viewing logs.
- skydhash 6mo ago> `git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --` If you remove the rainbow specification, it should be git log --graph --pretty=format:'%h -%d %s (%cr) <%an>' --abbrev-commit -- And most programmers are used to C style formatting.
- stingraycharles 6mo agoI 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 6mo agoSame, but now with AI I don't have to remember that anymore
- awesome_dude 6mo agoFor now - the law of enshittification means that the free/cheap access to AI will be curtailed soon enough.
- mgfist 6mo agoPretty much any OS locally runnable LLM can generate this stuff.
- Cthulhu_ 6mo agoI 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 6mo agoI 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).
- 6mo ago
- huflungdung 6mo ago[dead]
- socalgal2 6mo agoa 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 6mo agoIt'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 6mo agoI 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 6mo ago> 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 6mo agoWell 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.
- newsoftheday 6mo agoI 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 6mo agoBut 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 6mo agoSaw 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 6mo agoThis is the only sane reply on this entire comment tree. To me, the verbosity of both Git and JJ commands to do these things are an indication that neither of these tools are meant to do them.
- AlexeyBelov 6mo agocrying over? Let's not be confrontational. I could say you're "crying" with this comment, but is that a good thing to say?
- dcre 6mo agoCome on.
- cynicalsecurity 6mo agoNot interested, thank you.
- NamlchakKhandro 6mo agoDidn't ask for it thanks
- okkdev 6mo agoCool! Thanks :) Jujutsu is such a nice tool. I don't understand why everything has to be so divisive nowadays. Enjoy the tools you like.
- ramon156 6mo ago> The 20 most-changed files in the last year. The file at the top is almost always the one people warn me about. “Oh yeah, that file. Everyone’s afraid to touch it.” The most changed file is the one people are afraid of touching?
- mememememememo 6mo agoYes. 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 6mo agoI'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 6mo agoYeah same thing happens with lockfiles and CI configs. You end up filtering out half the list before it tells you anything useful.
- deleted 6mo ago[deleted]
- pydry 6mo agoI 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_ 6mo agoIf 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.
- seba_dos1 6mo ago> If the team squashes every PR into a single commit, this output reflects who merged, not who wrote. Squash-merge workflows are stupid (you lose information without gaining anything in return as it was easily filterable at retrieval anyway) and only useful as a workaround for people not knowing how to use git, but git stores the author and committer names separately, so it doesn't matter who merged, but rather whether the squashed patchset consisted of commits with multiple authors (and even then you could store it with Co-authored-by trailers, but that's harder to use in such oneliners).
- theshrike79 6mo agoCan 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 6mo agoThese 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 6mo agoWhat 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 6mo agoif 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.
- traceroute66 6mo ago> The 20 most-changed files in the last year. The file at the top is almost always the one people warn me about. What a weird check and assumption. I mean, surely most of the "20 most-changed files" will be README and docs, plus language-specific lock-files etc. ? So if you're not accounting for those in your git/jj syntax you're going to end up with an awful lot of false-positive noise.
- theshrike79 6mo agoWhy 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 6mo ago> Why would you touch the README file hundreds of times a year? You're right, perhaps I should have said CHANGELOG etc. Although some projects e.g. bump version numbers in README or add extra one-liner examples ....
- mosselman 6mo agoJust look at the second file in the list then I guess. This post is about exploring code, not documentation. Nobody is going to warn you about the README unless it is super outdated.
- raxxorraxor 6mo agoSome 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 6mo agoIt’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.
- JetSetIlly 6mo agoSome 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 6mo agoGood catch, that's better
- nozzlegear 6mo agoThis needs a small tweak to work on macOS, where git uses the POSIX version of grep (which doesn't support `\b`). You need to use the Perl Regexp option by switching -E with -P: git log -i -P --grep="\b(fix|fixed|fixes|bug|broken)\b" --name-only --format='' | sort | uniq -c | gsort -nr | head -20
- grepsedawk 6mo agoGood catch. The word boundary syntax isn't portable across platforms. I reverted to the simpler version that works everywhere.
- j2kun 6mo agoSimilarly, we have a technical concept called "rollback" that is unrelated to a reverted commit.
- Timwi 6mo agoWord boundaries are one way to address that, but they require you to list all the inflections (and you missed “fixing”). Another way is to say (?<!de)bug.
- T3RMINATED 6mo ago[dead]
- aa-jv 6mo agoGreat 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.
- T3RMINATED 6mo ago[dead]
- mattrighetti 6mo agoI 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 https://github.com/GitAlias/gitalias
- duskdozer 6mo agoCurious - 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 6mo agoIt's a very old config that I copied from someone many years ago, agree that it's a bit hard to parse visually.
- deleted 6mo ago[deleted]
- croemer 6mo agoRather 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)
- deleted 6mo ago[deleted]
- markus_zhang 6mo agoI also feel this reads like an AI slop, but at least I learned 5 commands. Not too bad.
- boxed 6mo agoJust 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 6mo agoSure, 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 6mo agoTrusting 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 6mo agoFor the stuff I've worked on, if you want to know about bugfixes and emergency releases, you'd go to Jira where those values are formalized as fields. Someone else in the comments here had a suggestion which just looks for the word "fix" which would definitely capture some bugfix releases, but is more likely to catch fixes that were done during development of a feature.
- alkonaut 6mo agoYes for a meaningful context you should need both the source repo and the work tracking system. But today most systems have apis (jira, ADO, gh, ...) so this should be fairly doable, especially using a bot like copilot cli. But it's not doable as a little shell script.
- dawnerd 6mo agoWe use branch names like `hotfix/some-hotfix-name`, don't think I've seen many commits mention hotfix directly.
- youre-wrong3 6mo ago[flagged]
- niedbalski 6mo agoAges ago, google released an algorithm to identify hotspots in code by using commit messages. https://github.com/niedbalski/python-bugspots https://github.com/niedbalski/python-bugspots
- deleted 6mo ago[deleted]
- niedbalski 6mo agoAges ago google wrote an algorithm to detect hotspots by using commit messages, https://github.com/niedbalski/python-bugspots https://github.com/niedbalski/python-bugspots
- user20251219 6mo agothank you - these are useful
- whstl 6mo ago> One caveat: squash-merge workflows compress authorship. If the team squashes every PR into a single commit, this output reflects who merged, not who wrote. Worth asking about the merge strategy before drawing conclusions. In my experience, when the team doesn't squash, this will reflect the messiest members of the team. The top committer on the repository I maintain has 8x more commits than the second one. They were fired before I joined and nobody even remembers what they did. Git itself says: not much, just changing the same few files over and over. Of course if nobody is making a mess in their own commits, this is not an issue. But if they are, squash can be quite more truthful.
- nola-a 6mo agoFor more insights on Git, check out https://github.com/nolasoft/okgit https://github.com/nolasoft/okgit
- fzaninotto 6mo agoInstead 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 https://github.com/marmelab/ArcheoloGit
- lpribis 6mo agoI 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.
- bsuvc 6mo agoI 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 6mo agoOnly 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 6mo agoI 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 6mo ago> AI generated commit messages git log --oneline and a sprinkle of your personal sauce on .claude goes a long way :)
- mikepurvis 6mo agoIn 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 6mo agoAnd 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.
- strimoza 6mo ago[dead]
- baquero 6mo agoI put it into a gist :) https://gist.github.com/aeimer/8edc0b25f3197c0986d3f2618f036f63 https://gist.github.com/aeimer/8edc0b25f3197c0986d3f2618f036...
- bullen 6mo agoDying 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_ 6mo agoFor "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 6mo agoI just finished¹ building an experimental tool that tries to figure out if a repo is slopware or not just by looking at it's git history (plus some GitHub activity data). The takeaway from my experiment is that you can really tell a lot by how / when / what people commit, but conclusions are very hard to generalize. For example, I've also stumbled upon the "merge vs squash" issue, where squashes compress and mostly hide big chunks of history, so drawing conclusions from a squashed commit is basically just wild guessing. (The author of course has also flagged this. But I just wanted to add my voice: yeah, careful to generalize.) ¹ Nothing is ever finished.
- tom-blk 6mo agoNice! Will probably adopt this, seems to give a great overview!
- therealdeal2020 6mo agosuperficial. 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
- tracerbits 6mo ago[dead]
- icedchai 6mo agoI 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 6mo agoThe author does not look at counter values but rather at how the values changes. That reveals dynamics.
- icedchai 6mo agoMy 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.
- Zardoz84 6mo agoI agree with you. Also, there is people (like me) that like to small commits (that don't break stuf) instead of huge mega commits. If I do something like small broken/wip commits, are only under my working bramch and I do a interactive rebase to merge on good cohesive commits.
- michaelcampbell 6mo agoIt isn't. $COMPANY I've worked for use commit counts as a metric, and you can bet all the money in your pockets they've skyrocketed with no change to actual output after they did. LLM's make it even easier; "Commit all the outstanding code in as many commits as you can, as long as the tests pass after each one". (Sometimes that second clause is ommitted, too.)
- TacticalCoder 6mo ago> The 20 most-changed files in the last year. The file at the top is almost always the one people warn me about. “Oh yeah, that file. Everyone’s afraid to touch it.” I've got my Emacs set up to display next to every file that is versioned the number of commits that file has been modified in (for the curious: using a modified all-the-icons-ivy-rich + custom elisp code + custom Bash scripts I wrote and it's trickier than it seems to do in a way that doesn't slows everything down). For example in the menu to open a file or open a recently visited file etc.: basically in every file list, in addition to its size, owner, permissions, etc. I also add the number of commits if it's a versioned file. I like the fix/bug/broken search in TFA to see where the bugs gather.
- blenderob 6mo ago> Is This Project Accelerating or Dying > > git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c If the commit frequency goes down, does it really mean that the project is dying? Maybe it is just becoming stable?
- stackedinserter 6mo agoOr you hired someone who squashes or doesn't commit every single change.
- Sharlin 6mo agoSomething something Red Queen's race
- dan-bailey 6mo agoProjects become more stable with time? Since when?
- onion2k 6mo agoTechnically 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 6mo ago> I'm certain you can use change frequency as a proxy and never be wrong. I (largely) wrote a corporate application 8 years ago, with 2 others. There was one change 2 years ago from another dev. Lots of programs are functionally done in a relatively short amount of time. "Accelerating or Dying" sounds like private equity's lazy way to describe opportunity, not as a metric to describe software.
- onion2k 6mo agoThat 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.
- stackedinserter 6mo agoThis should be renamed to "Git commands that I run as a new hire to get metrics I'll forget on day 2".
- joshstrange 6mo agoI 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 6mo agoSo 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 6mo agoI'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 6mo agoI 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.
- yieldcrv 6mo agoblog posts are just comments that would have been torn apart if only posted on a forum, now masquerading as important universal edicts
- deleted 6mo ago[deleted]
- alaudet 6mo agoThis is good stuff. Why I never think of things like this is beyond me. Thanks
- mikaoelitiana 6mo agoI created a small TUI based on the article https://github.com/mikaoelitiana/git-audit https://github.com/mikaoelitiana/git-audit
- grepsedawk 6mo agoWrapping these in a TUI is on my list. Haven't built it yet.
- vladsanchez 6mo agoYou beat me to it! I envisioned creating some aliases but you exceeded it by building a TUI. Good job Claude! LOL ;)
- guilhermeasper 6mo agoThese 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 6mo agoMy 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.
- aidenn0 6mo agoWhat's the subversion equivalents to these commands?
- StableAlkyne 6mo agoBiggest 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!
- arthurjj 6mo agoThese 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 6mo agoI can't speak for most, but the past few places I consulted or worked at used monorepos.
- BigTTYGothGF 6mo agoJesus I've seen what you've done for others and want that for myself.
- abustamam 6mo ago?
- atlgator 6mo agoStep 6: grep the thread count on the squash-merge debate to determine if the team has unresolved interpersonal conflict.
- jayd16 6mo agoNo 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_ 6mo agoOut 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 6mo agoMore AI slop. Wtf is happening to this website
- gpvos 6mo agoMost often, what is happening is that people are groundlessly accusing others of writing AI slop.
- twoodfin 6mo agoThis is 100% AI slop. It’s really not obvious to you? Look at the rest of this blog: https://piechowski.io/post/ 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 6mo agoI'd be curious to see if my blog posts/titles feel like AI slop to you. https://alexhans.github.io/ 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".
- twoodfin 6mo agoNo, they don't, and I don't try to judge a book by its cover, anyway. TBC, I don't dislike LLM-written articles because I think the author is being lazy, and I can even live with the LLM-isms. I dislike LLM-written articles in the main because they're lousy at serving their purpose of communicating some interesting human thought to other humans. They are very good at creating the illusion that's what's happening, hence all the upvotes.
- heliumtera 6mo agoSo you value more rushed descriptions of changes than actual changes. Nice
- progx 6mo agoBefore, I ask AI "is this project maintained" done.
- yayadarsh 6mo agogit commands I run before reading any code: git rm -rf .
- drob518 6mo agoNice timing. I was just today needing some of the info that these commands surface. Serendipitous!
- md224 6mo agoThe 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?
- jlarocco 6mo agoI'm so used to magit, it seems kind of primitive to pipe git output around like this. Anyway, I can glean a lot of this information in a few minutes scrolling through and filtering the log in magit, and it doesn't require memorizing a bunch of command line arguments.
- constantius 6mo agoI understand some people only have Emacs for magit, and I think it's very much justified: probably 95% of the use cases described here are straightforward (and flexible) operations in magit.
- zdkaster 6mo agoCan't resist making it as a git command https://github.com/zdk/git-critique https://github.com/zdk/git-critique
- kittikitti 6mo agoThis is a great list of commands to quickly understand a repository. Thank you for sharing.
- kilbey1 6mo agoAgreed.
- konovalov-nk 6mo agoTo me all of these are symptoms of the problem that I outlined in my recent blog post: https://news.ycombinator.com/item?id=47606192 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 6mo agoNice set of commands! I would suggest using --all flag with git log though - scans through all branches and not just the current one
- nextlevelwizard 6mo agoThese 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 6mo agoInteresting 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 6mo agoThis 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.
- deleted 6mo ago[deleted]
- pwr1 6mo agoSolid 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 6mo ago> One caveat: squash-merge workflows compress authorship. If the team squashes every PR into a single commit, this output reflects who merged, not who wrote. Worth asking about the merge strategy before drawing conclusions. I abhor squash merging for this and a few other reasons. I literally have to go out of my way to re-check out a branch. Someone who wants to use my current branch cannot do so if I merge my changes a month later, because the squash rewrites history, and now git is very confused. I don't get the obsession with "cleaning up the history" as if we're all always constantly running out of storage over 2 more commits.
- stetrain 6mo agoFor 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 6mo agoYou 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 6mo agoThanks. What a great Skill for my Claude
- ML0037 6mo agoi’ll try to use the in an hook and test them with Claude. Thank you !
- gpvos 6mo agoAh yes, good old |sort |uniq -c |sort -nr |head -20 I use it often.
- xyst 6mo agomight 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 6mo agoSaved. 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 6mo agoThis 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 6mo agoWhen 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 6mo agoI 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 6mo ago> One caveat: squash-merge workflows compress authorship. If the team squashes every PR into a single commit, this output reflects who merged, not who wrote. Worth asking about the merge strategy before drawing conclusions. Well isn't it typical that the person who wrote is also the person that merged? I have never worked in a place where that is not the norm for application code. Even if you are one of those insane teams that do not squash merge because keeping everyone's spelling fixes and "try CI again" commits is important for some reason, you will still not see who _wrote_ the code, you will only see who committed the code. And if the person that wrote the code is not also the person that merges the code, I see no reason to trust that the person making commits is also the person writing the code.
- mrunkel 6mo agoCode merges are made by reviewers in my org, not by the author. Spend time educating your team about `git commit --amend` and `git push --force` on their own branches and you don't have to see any of that ugliness.
- fmbb 6mo agoSquash merges have two upsides: 1. I don’t have to see that ugliness. 2. Nobody has to force push and micro manage commits. If I recall correctly most code forges will add co-author trailers if someone other than the author squash merges.
- ianberdin 6mo agoWell, 70% of my commits are “123”.
- pvtmert 6mo agoThe 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 6mo agoThats why I’m visting HN. Thank you.
- youknownothing 6mo agoI like the mindset, it reminds me of "Your code as a crime scene" by Adam Tornhill: https://www.adamtornhill.com/articles/crimescene/codeascrimescene.htm 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-legacy-of-individual-developers.html https://www.javaadvent.com/2021/12/using-jgit-to-analyse-the...
- suprjami 6mo agoNice to see a fellow Tornhill fan. I loved his early C articles.
- kabir_daki 6mo ago[dead]
- lavp 6mo agoI made a bash function to turn these commands into a one page diagnostics report so that you can use this in your `.bashrc`: Diagnostics function, colorized (I tried to add guards so it is portable with terminals that do not support color): git_diag() { local since="${1:-1 year ago}" local root repo branch # --- patterns --- local pattern="${GIT_DIAG_PATTERN:-fix|bug|broken|hotfix|incident|issue|patch}" local firefight_pattern="revert|hotfix|emergency|rollback" # --- colors --- local GREP_COLOR_MODE='never' if [[ -z "${NO_COLOR:-}" ]] && [[ -t 1 ]] && [[ "${TERM:-}" != "dumb" ]] && [[ "$(tput colors 2>/dev/null || echo 0)" -ge 8 ]]; then local BLACK=$(tput setaf 0) local RED=$(tput setaf 1) local GREEN=$(tput setaf 2) local YELLOW=$(tput setaf 3) local BLUE=$(tput setaf 4) local MAGENTA=$(tput setaf 5) local CYAN=$(tput setaf 6) local WHITE=$(tput setaf 7) local BOLD=$(tput bold) local DIM=$(tput dim 2>/dev/null || true) local RESET=$(tput sgr0) GREP_COLOR_MODE='always' else local BLACK='' RED='' GREEN='' YELLOW='' BLUE='' MAGENTA='' CYAN='' WHITE='' local BOLD='' DIM='' RESET='' fi local TITLE="$CYAN" local COLOR_COUNT="$CYAN" local COLOR_FILE="$YELLOW" if ! root="$(git rev-parse --show-toplevel 2>/dev/null)"; then printf 'git_diag: not inside a Git repository\n' >&2 return 1 fi repo="${root##*/}" branch="$(git branch --show-current 2>/dev/null)" branch="${branch:-DETACHED}" _git_diag_fmt_count() { local count_color="$1" local text_color="$2" awk -v count_color="$count_color" -v text_color="$text_color" -v reset="$RESET" '{ c=$1 $1="" sub(/^ +/, "") printf " %s%10d%s %s%s%s\n", count_color, c, reset, text_color, $0, reset }' } printf '%s%sGit repo diagnostics%s\n' "$BOLD" "$TITLE" "$RESET" printf '%s%-11s%s %s\n' "$BOLD" "Repo:" "$RESET" "$repo" printf '%s%-11s%s %s\n' "$BOLD" "Branch:" "$RESET" "$branch" printf '%s%-11s%s %s\n' "$BOLD" "Timeframe:" "$RESET" "$since → now" printf '\n\n' printf '%s%s1) Most changed files%s\n' "$BOLD" "$TITLE" "$RESET" git log --since="$since" --format='' --name-only \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count "$COLOR_COUNT" "$COLOR_FILE" printf '\n%s%s2) Top contributors%s\n' "$BOLD" "$TITLE" "$RESET" git shortlog -sn --no-merges --since="$since" \ | head -n 10 \ | awk -v count_color="$COLOR_COUNT" -v reset="$RESET" '{ printf " %s%10d%s %s\n", count_color, $1, reset, substr($0, index($0,$2)) }' printf '\n%s%s3) Bug/fix hotspots%s %s(pattern: %s)%s\n' "$BOLD" "$TITLE" "$RESET" "$DIM" "$pattern" "$RESET" git log --since="$since" --format='' --name-only -i -E --grep="$pattern" \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count "$COLOR_COUNT" "$COLOR_FILE" printf '\n%s%s4) Commit count by month%s\n' "$BOLD" "$TITLE" "$RESET" git log --since="$since" --format='%ad' --date=format:'%Y-%m' \ | sort \ | uniq -c \ | sort -k2r \ | awk -v count_color="$COLOR_COUNT" -v mag="$MAGENTA" -v reset="$RESET" ' { data[NR,1] = $2 data[NR,2] = $1 if (length($1) > max) max = length($1) } END { for (i = 1; i <= NR; i++) { printf " %s%10s%s %s%*d commits%s\n", mag, data[i,1], reset, count_color, max, data[i,2], reset } } ' printf '\n%s%s5) Firefighting commits%s %s(pattern: %s)%s\n' "$BOLD" "$TITLE" "$RESET" "$DIM" "$firefight_pattern" "$RESET" git log --since="$since" -i -E \ --grep="$firefight_pattern" \ --date=short \ --pretty=format:'%ad %h %s' \ | head -n 10 \ | awk -v mag="$MAGENTA" -v dim="$DIM" -v reset="$RESET" '{ date=$1 hash=$2 $1=$2="" sub(/^ */, "") printf " %s%-10s%s %s%-12s%s %s\n", mag, date, reset, dim, hash, reset, $0 }' \ | GREP_COLORS='ms=01;31' grep --color="$GREP_COLOR_MODE" -i -E "$firefight_pattern" } Uncolorized diagnostics function (same, but without the colors): git_diag() { local since="${1:-1 year ago}" local pattern="${GIT_DIAG_PATTERN:-fix|bug|broken|hotfix|incident|issue|patch}" local root repo branch if ! root="$(git rev-parse --show-toplevel 2>/dev/null)"; then printf 'git_diag: not inside a Git repository\n' >&2 return 1 fi repo="${root##*/}" branch="$(git branch --show-current 2>/dev/null)" branch="${branch:-DETACHED}" _git_diag_fmt_count() { awk '{ c=$1 $1="" sub(/^ +/, "") printf " %10d %s\n", c, $0 }' } printf '============================================================\n' printf 'Git repo diagnostics\n' printf '%-11s%as\n' 'Repo:' "$repo" printf '%-11s%s\n' 'Branch:' "$branch" printf '%-11s%s\n' 'Timeframe:' "$since" printf '============================================================\n\n' printf '1) Most changed files (top 10)\n' git log --since="$since" --format='' --name-only \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count printf '\n2) Top 10 contributors (no merges, since %s)\n' "$since" git shortlog -sn --no-merges --since="$since" \ | head -n 10 \ | _git_diag_fmt_count printf '\n3) Bug/fix hotspots (top 10, matching: %s)\n' "$pattern" git log --since="$since" --format='' --name-only -i -E --grep="$pattern" \ | awk 'NF' \ | sort \ | uniq -c \ | sort -nr \ | head -n 10 \ | _git_diag_fmt_count printf '\n4) Commit count by month (since %s)\n' "$since" git log --since="$since" --format='%ad' --date=format:'%Y-%m' \ | sort \ | uniq -c \ | sort -k2r \ | awk ' { data[NR,1] = $2 data[NR,2] = $1 if (length($1) > max) max = length($1) } END { for (i = 1; i <= NR; i++) { printf " %10s %*d commits\n", data[i,1], max, data[i,2] } } ' printf '\n5) 10 most recent firefighting commits (revert|hotfix|emergency|rollback)\n' git log --since="$since" -i -E \ --grep='revert|hotfix|emergency|rollback' \ --date=short \ --pretty=format:'%ad %h %s' \ | head -n 10 \ | awk '{ date=$1 hash=$2 $1=$2="" sub(/^ */, "") printf " %-10s %-12s %s\n", date, hash, $0 }' \ | GREP_COLORS='ms=01;31' grep --color=always -i -E 'revert|hotfix|emergency|rollback' }
- sigmonsays 6mo agoI have a strong suspicion this is AI slop. I also think this article draws way too many conclusions from a git log.
- neuzhou 6mo ago[dead]
- Yondle 6mo agoHey guys this was just meant to give you inspiration, its not a set of rules. How about use what works for you (:
- RickHull 6mo agoThanks for this. My updated relevant portion of ~/.gitconfig: [alias] st = status ci = commit co = checkout br = branch df = diff dfs = diff --stat dfc = diff --cached dfh = diff --histogram dfn = diff --name-status rs = restore rsc = restore --staged last = log -1 HEAD lg = log --graph --decorate --oneline --abbrev-commit cm = commit -m ca = commit --amend cane = commit --amend --no-edit who = shortlog -sn --no-merges HEAD dmg = log --oneline -i -E --grep='(incident|outage|downtime|rollback|revert|mitigate|mitigation|hotfix|broke|prod)' --since='1 year ago' bugs = log --oneline -i -E --grep='(bug|bugfix|fix|fixed|fixes|defect|regression|hotfix|broke)' --since='1 year ago' bugfiles = !git log --name-only --format='' -i -E --grep='(bug|bugfix|fix|fixed|fixes|defect|regression|hotfix|broke)' --since='1 year ago' | sort | uniq -c | sort -nr monthly = !git log --since='1 year ago' --format='%ad' --date=format:'%Y-%m' | sort | uniq -c churn = !git log --format='' --name-only --diff-filter=AM --since='1 year ago' | sort | uniq -c | sort -nr | head -20
- mailcraftai 6mo ago[dead]
- mailcraftai 6mo ago[dead]
- maxaravind 6mo ago[dead]
- hahooh 6mo agoonly works with teams that have proper commit messages.
- fishbacon 6mo agoExcellent set of commands. Of course the two most useful ones would never be useful in the code base I am currently working on. "fix" might be the single most common commit message, and after that comes "." Trying for two years, to get people to include at least some information in their commit messages, has exhausted me.
- aledevv 6mo ago> Commit count by month, for the entire history of the repo. I scan the output looking for shapes. A steady rhythm is healthy. But what does it look like when the count drops by half in a single month? Let's NOT jump to conclusions; it could mean many things. For example, a period with other priorities, different urgencies, other issues external to the project itself and beyond our control, vacations, illnesses, or anything else that could impact the commit history. I think these considerations and the others expressed in this article can easily lead to hasty conclusions and erroneous deductions, too simplistic. Coding flow, like business needs, cannot always be objectively and deterministically measured.
- herrmaier 6mo agoMade a claude skill! This is gold
- kilbey1 6mo ago[dead]
- merlin1de 6mo ago[dead]
- segfault_james 6mo agoThe churn + bug hotspot cross-reference is underrated. I've used a similar approach and the overlap between those two lists is almost always where the team's morale problems live too — not just the technical debt.
- sarrietav 6mo ago[dead]
- Serhii-Set 6mo ago[dead]
- atlasagentsuite 6mo ago[dead]
- uniqid 6mo agoThanks for sharing! The firefighting definitely pushed a button for me, I'll give all of these a try.
- youre-wrong3 6mo agoThis was written today but isn’t stuff anyone cares about now with the age of ai. A truth no one wants to hear. Everyone in denial.
- amai 6mo agoIs there a git command to find the developer who deleted the most lines of code? That is the best developer in the team.
- juliob 6mo agoThere's also https://github.com/hjr265/gittop https://github.com/hjr265/gittop, which provides a lot more useful views