Live data from Hacker News

Git commands I run before reading any code

piechowski.io

391–400 of 546 posts

Re: Git commands I run before reading any code

#391

Earlier quoted context omitted.

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.

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…

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.

Re: Git commands I run before reading any code

#392
post #90

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 de…

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).

Re: Git commands I run before reading any code

#393

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 wa…

I suspect OP never actually ran these commands and this article was brainstormed and written by an LLM.

Re: Git commands I run before reading any code

#394
post #373

Earlier quoted context omitted.

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.

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?

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/

Re: Git commands I run before reading any code

#395
post #363

Earlier quoted context omitted.

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)

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…

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.

Re: Git commands I run before reading any code

#396

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...

Nice to see a fellow Tornhill fan. I loved his early C articles.

Re: Git commands I run before reading any code

#397
I made a bash function to turn these commands into a one page diagnostics report so that you can use this in your `.bashrc`:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Re: Git commands I run before reading any code

#398

Earlier quoted context omitted.

I particularly love when the “CTO” is also the main offender.

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 add…

> 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?

Re: Git commands I run before reading any code

#399
post #266

Earlier quoted context omitted.

> 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 h…

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"

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?

Re: Git commands I run before reading any code

#400
post #336
post #3

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-grap…

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.

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.

Post reply on HN