{"id":15483,"date":"2026-04-10T17:47:58","date_gmt":"2026-04-10T15:47:58","guid":{"rendered":"https:\/\/monodes.com\/predaelli\/?p=15483"},"modified":"2026-04-10T17:47:59","modified_gmt":"2026-04-10T15:47:59","slug":"the-git-commands-i-run-before-reading-any-code","status":"publish","type":"post","link":"https:\/\/monodes.com\/predaelli\/2026\/04\/10\/the-git-commands-i-run-before-reading-any-code\/","title":{"rendered":"The Git Commands I Run Before Reading Any Code"},"content":{"rendered":"\n<p><a href=\"https:\/\/piechowski.io\/post\/git-commands-before-reading-code\/\">The Git Commands I Run Before Reading Any Code<\/a><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>What Changes the Most <\/li>\n\n\n\n<li>Who Built This<\/li>\n\n\n\n<li>Where Do Bugs Cluster<\/li>\n\n\n\n<li>Is This Project Accelerating or Dying<\/li>\n\n\n\n<li>How Often Is the Team Firefighting<\/li>\n<\/ol>\n\n\n\n<!--more-->\n\n\n\n<!--nextpage-->\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<h1 class=\"wp-block-heading\">The Git Commands I Run Before Reading Any Code<\/h1>\n\n\n\n<p>Five git commands that tell you where a codebase hurts before you open a single file. Churn hotspots, bus factor, bug clusters, and crisis patterns.<small> Ally Piechowski \u00b7 <time datetime=\"2026-04-08\">Apr 8, 2026<\/time> \u00b7 4 min read<\/small><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/piechowski.io\/tags\/development\">development<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/piechowski.io\/tags\/git\">git<\/a><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/piechowski.io\/post\/git-commands-before-reading-code\/cover_hu3f66e25b7571f7e32d40f355f31a2ca9_56928_1500x0_resize_q75_h2_box_2.webp?w=910&#038;ssl=1\" alt=\"The Git Commands I Run Before Reading Any Code\"\/><\/figure>\n\n\n\n<p>The first thing I usually do when I pick up a new codebase isn\u2019t opening the code. It\u2019s opening a terminal and running a handful of git commands. Before I look at a single file, the commit history gives me a diagnostic picture of the project: who built it, where the problems cluster, whether the team is shipping with confidence or tiptoeing around land mines.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-changes-the-most\">What Changes the Most<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">git log --format=format: --name-only --since=&quot;1 year ago&quot; | sort | uniq -c | sort -nr | head -20\n<\/code><\/pre>\n\n\n\n<p>The 20 most-changed files in the last year. The file at the top is almost always the one people warn me about. \u201cOh yeah, that file. Everyone\u2019s afraid to touch it.\u201d<\/p>\n\n\n\n<p>High churn on a file doesn\u2019t mean it\u2019s bad. Sometimes it\u2019s just active development. But high churn on a file that nobody wants to own is the clearest signal of codebase drag I know. That\u2019s the file where every change is a patch on a patch. The blast radius of a small edit is unpredictable. The team pads their estimates because they know it\u2019s going to fight back.<\/p>\n\n\n\n<p>A <a href=\"https:\/\/www.microsoft.com\/en-us\/research\/publication\/use-of-relative-code-churn-measures-to-predict-system-defect-density\/\">2005 Microsoft Research study<\/a> found churn-based metrics predicted defects more reliably than complexity metrics alone. I take the top 5 files from this list and cross-reference them against the bug hotspot command below. A file that\u2019s high-churn <em>and<\/em> high-bug is your single biggest risk.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"who-built-this\">Who Built This<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">git shortlog -sn --no-merges\n<\/code><\/pre>\n\n\n\n<p>Every contributor ranked by commit count. If one person accounts for 60% or more, that\u2019s your bus factor. If they left six months ago, it\u2019s a crisis. If the top contributor from the overall shortlog doesn\u2019t appear in a 6-month window (<code class=\"\" data-line=\"\">git shortlog -sn --no-merges --since=&quot;6 months ago&quot;<\/code>), I flag that to the client immediately.<\/p>\n\n\n\n<p>I also look at the tail. Thirty contributors but only three active in the last year. The people who built this system aren\u2019t the people maintaining it.<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"where-do-bugs-cluster\">Where Do Bugs Cluster<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">git log -i -E --grep=&quot;fix|bug|broken&quot; --name-only --format=&#039;&#039; | sort | uniq -c | sort -nr | head -20\n<\/code><\/pre>\n\n\n\n<p>Same shape as the churn command, filtered to commits with bug-related keywords. Compare this list against the churn hotspots. Files that appear on both are your highest-risk code: they keep breaking and keep getting patched, but never get properly fixed.<\/p>\n\n\n\n<p>This depends on commit message discipline. If the team writes \u201cupdate stuff\u201d for every commit, you\u2019ll get nothing. But even a rough map of bug density is better than no map.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"is-this-project-accelerating-or-dying\">Is This Project Accelerating or Dying<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">git log --format=&#039;%ad&#039; --date=format:&#039;%Y-%m&#039; | sort | uniq -c\n<\/code><\/pre>\n\n\n\n<p>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? Usually someone left. A declining curve over 6 to 12 months tells you the team is losing momentum. Periodic spikes followed by quiet months means the team batches work into releases instead of shipping continuously.<\/p>\n\n\n\n<p>I once showed a CTO their commit velocity chart and they said \u201cthat\u2019s when we lost our second senior engineer.\u201d They hadn\u2019t connected the timeline before. This is team data, not code data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"how-often-is-the-team-firefighting\">How Often Is the Team Firefighting<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\" data-line=\"\">git log --oneline --since=&quot;1 year ago&quot; | grep -iE &#039;revert|hotfix|emergency|rollback&#039;\n<\/code><\/pre>\n\n\n\n<p>Revert and hotfix frequency. A handful over a year is normal. Reverts every couple of weeks means the team doesn\u2019t trust its deploy process. They\u2019re evidence of a <a href=\"https:\/\/piechowski.io\/post\/codebase-drag-audit\/#2-deploy-fear\">deeper issue<\/a>: unreliable tests, missing staging, or a deploy pipeline that makes rollbacks harder than they should be. Zero results is also a signal; either the team is stable, or nobody writes descriptive commit messages.<\/p>\n\n\n\n<p>Crisis patterns are easy to read. Either they\u2019re there or they\u2019re not.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>These five commands take a couple minutes to run. They won\u2019t tell you everything. But you\u2019ll know which code to read first, and what to look for when you get there. That\u2019s the difference between spending your first day reading the codebase methodically and spending it wandering.<\/p>\n\n\n\n<p>This is the first hour of what I do in a <a href=\"https:\/\/piechowski.io\/post\/how-i-audit-a-legacy-rails-codebase\/\">codebase audit<\/a>. Here\u2019s what the rest of the week looks like.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p class=\"excerpt\">The Git Commands I Run Before Reading Any Code<\/p>\n<p class=\"more-link-p\"><a class=\"more-link\" href=\"https:\/\/monodes.com\/predaelli\/2026\/04\/10\/the-git-commands-i-run-before-reading-any-code\/\">Read more &rarr;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"link","meta":{"inline_featured_image":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"federated","footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[278],"tags":[],"class_list":["post-15483","post","type-post","status-publish","format-link","hentry","category-tricks","post_format-post-format-link"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6daft-41J","jetpack-related-posts":[{"id":11688,"url":"https:\/\/monodes.com\/predaelli\/2024\/06\/01\/never-use-git-pull-youtube\/","url_meta":{"origin":15483,"position":0},"title":"Never* use git pull &#8211; YouTube","author":"Paolo Redaelli","date":"2024-06-01","format":"video","excerpt":"https:\/\/www.youtube.com\/watch?v=xN1-2p06Urc Just a quick summary mostly for myself: How to use git pull --rebase to keep your team's commit history clean. Command for creating the 'git pr' alias (so you can copy-paste): git config --global alias.pr \"pull --rebase\" Always try git pull --rebase first. It if works, you're done! If\u2026","rel":"","context":"In &quot;Tricks&quot;","block_context":{"text":"Tricks","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/tricks\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/img.youtube.com\/vi\/xN1-2p06Urc\/0.jpg?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":7515,"url":"https:\/\/monodes.com\/predaelli\/2020\/09\/04\/7-command-line-tools-that-make-your-life-easier\/","url_meta":{"origin":15483,"position":1},"title":"7 Command-Line Tools That Make Your Life Easier","author":"Paolo Redaelli","date":"2020-09-04","format":"link","excerpt":"Of those 7 Command-Line Tools That Make Your Life Easier | by Daan I've found 4 really useful Enhancd memorizes all directories visited by a user and use it for the pathname resolution. Thefuck is a great tool that corrects errors in previous console commands. Git stats Autojump keeps track\u2026","rel":"","context":"In &quot;Software&quot;","block_context":{"text":"Software","link":"https:\/\/monodes.com\/predaelli\/category\/software\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":11167,"url":"https:\/\/monodes.com\/predaelli\/2024\/01\/10\/lets-clone-simplemobiletools\/","url_meta":{"origin":15483,"position":2},"title":"Let&#8217;s clone SimpleMobileTools","author":"Paolo Redaelli","date":"2024-01-10","format":false,"excerpt":"Since SimpleMobileTools has been sold by its creator to a company notorious for buying apps from developers and repacking them with ads, putting a \"no-ads\" subscription to remove it for $15 a week, the time is ripe to clone its repositories! Join me, I already did it!: git clone https:\/\/github.com\/SimpleMobileTools\/Simple-App-Launcher\u2026","rel":"","context":"In &quot;Ethics&quot;","block_context":{"text":"Ethics","link":"https:\/\/monodes.com\/predaelli\/category\/ethics\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2024\/01\/may-the-source-be-with-you-0.webp?fit=750%2C1000&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2024\/01\/may-the-source-be-with-you-0.webp?fit=750%2C1000&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2024\/01\/may-the-source-be-with-you-0.webp?fit=750%2C1000&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/monodes.com\/predaelli\/wp-content\/uploads\/sites\/4\/2024\/01\/may-the-source-be-with-you-0.webp?fit=750%2C1000&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":915,"url":"https:\/\/monodes.com\/predaelli\/2016\/01\/21\/find-and-restore-a-deleted-file-in-a-git-repository\/","url_meta":{"origin":15483,"position":3},"title":"Find and restore a deleted file in a Git repository","author":"Paolo Redaelli","date":"2016-01-21","format":false,"excerpt":"Use git log --diff-filter=D --summary to get all the commits which have deleted files and the files deleted;Use git checkout $commit~1 filename to restore the deleted file. Sorgente: Find and restore a deleted file in a Git repository - Stack Overflow","rel":"","context":"In &quot;Documentations&quot;","block_context":{"text":"Documentations","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":11886,"url":"https:\/\/monodes.com\/predaelli\/2024\/09\/01\/git-copy-a-file-or-directory-from-another-repository-preserving-the-history\/","url_meta":{"origin":15483,"position":4},"title":"Git: Copy a file or directory from another repository preserving the history","author":"Paolo Redaelli","date":"2024-09-01","format":"quote","excerpt":"How to copy a file or directory from another GIT repository while preserving its history? Internet is full of magic formulas each one more complex. Here I\u2019m proposing a much simpler and faster one that is to make a git format-patch for the entire history of the file or subdirectory\u2026","rel":"","context":"In &quot;Tricks&quot;","block_context":{"text":"Tricks","link":"https:\/\/monodes.com\/predaelli\/category\/documentations\/tricks\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2449,"url":"https:\/\/monodes.com\/predaelli\/2017\/05\/11\/versionpress-git-for-wordpress-sites\/","url_meta":{"origin":15483,"position":5},"title":"VersionPress \u2013 Git for WordPress sites","author":"Paolo Redaelli","date":"2017-05-11","format":"link","excerpt":"VersionPress WordPress + Git = \u2661","rel":"","context":"In &quot;Senza categoria&quot;","block_context":{"text":"Senza categoria","link":"https:\/\/monodes.com\/predaelli\/category\/senza-categoria\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/15483","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/comments?post=15483"}],"version-history":[{"count":1,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/15483\/revisions"}],"predecessor-version":[{"id":15484,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/posts\/15483\/revisions\/15484"}],"wp:attachment":[{"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/media?parent=15483"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/categories?post=15483"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/monodes.com\/predaelli\/wp-json\/wp\/v2\/tags?post=15483"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}