blame is forensics, not accusation
The unfortunate name implies finger-pointing. The actual use case is forensics: which commit introduced this line, in what context, with what message, and what other lines came in with it? git blame answers all of these. Used well, it is the fastest way to understand why a piece of code looks the way it does — and the second-fastest way to find the conversation that justifies it.
The output of git blame file.js is one line per source line: commit hash (short), author, date, line number, and the line content. Each line tells you the most recent commit that touched it. From there, git show <hash> opens the full commit — message, full diff, and crucially the explanation of why those changes happened together. The blame line is the entry point; the commit message and surrounding diff are the evidence.
Two flags solve the most common annoyance. git blame -w ignores whitespace-only changes when assigning blame. git blame -M follows code that was moved within the same file (also -M -M for cross-file moves). Without these, a refactor that only reformatted or moved a function makes the entire region's blame point at the refactor commit, hiding the original intent. With them, blame walks past mechanical churn to the actual logic-introducing commit.
The pro move: git log -L :functionName:file.js. This shows the entire history of a single function across the project — every commit that ever changed it, in chronological order, with diffs. You see the function evolve. For tracking down "when did this method's behavior change?" or "why is this validation here?" it is dramatically faster than reading git log file.js and then opening each commit to see whether it touched the function. Add it to muscle memory.