惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
月光博客
月光博客
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
O
OpenAI News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Know Your Adversary
Know Your Adversary
Last Week in AI
Last Week in AI
S
Securelist
Engineering at Meta
Engineering at Meta
博客园 - 司徒正美
P
Privacy & Cybersecurity Law Blog
T
Tailwind CSS Blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
Scott Helme
Scott Helme
MyScale Blog
MyScale Blog
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
C
Cisco Blogs
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
小众软件
小众软件
U
Unit 42
Microsoft Azure Blog
Microsoft Azure Blog
Hacker News: Ask HN
Hacker News: Ask HN
Hugging Face - Blog
Hugging Face - Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
P
Proofpoint News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
Lohrmann on Cybersecurity
IT之家
IT之家
Security Archives - TechRepublic
Security Archives - TechRepublic
I
InfoQ
S
Security @ Cisco Blogs
Webroot Blog
Webroot Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Full Disclosure
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Jina AI
Jina AI
Cyberwarzone
Cyberwarzone
人人都是产品经理
人人都是产品经理
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
B
Blog RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research

Butler's Log

Agentic Version Control Benchmarks Grit: rewriting Git in Rust with agents Git Merge 2026 Agent-safe Git with GitButler We’ve raised $17M to build what comes after Git Announcing the GitButler CLI for Linux The Great CSS Expansion A couple of git nits Simplifying Git by Using GitButler Introducing the GitButler CLI GitButler 0.19 - "Commander Keen" But Head: Crafting a Custom Font MCP vs RAG: Two Very Different Ways to Gain Context Getting Started With GitButler Agents Using the GitButler MCP Server to Build Better AI-Driven Git Workflows Using GitButler With Multiple GitHub Accounts Advent of Code! Upcoming GitButler Events Use GitButler for your Gerrit workflow Integrating GitButler and GitHub Enterprise Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 3 Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 2 Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 1 Grid Happens: Because Flexbox Wasn’t Enough Using Cursor Hooks for automatic version control Deep Dive into the new Cursor Hooks A Responsive Item Counter with CSS only GitButler 0.16 - "Sweet Sixteen" GitButler's Claude Code tab GitButler's Annual Open Source Pledge Report Git Mini Summit 2025 Videos Automate Your AI Workflows with Claude Code Hooks Managing Multiple Claude Code Sessions Without Worktrees GitButler 0.15 - "Quirky Quinceañera" 20 years of Git. Still weird, still wonderful. GitButler's new patch based Code Review (Beta) Going down the rabbit hole of Git's new bundle-uri How to do patch-based review with git range-diff How Core Git Developers Configure Git Why is Git Autocorrect too fast for Formula One drivers? Stacked Branches with GitButler Git Merge 2024 Talks are Up GitButler 0.13 - "Lucky Baseball" Fearless Rebasing Git Merge 2024 Why GitHub Actually Won GitButler is joining the Open Source Pledge The New Era of Town Hall Chat The Future of Open Source GitButler is now Fair Source Git Merge 2024 GitButler 0.12 - "Stingy Baker" The Birth of THE MERGE GitButler for Windows Fixing up Git with Autosquash The Git Zeitgeist Git Worktrees and GitButler DevWorld Git Slides Git Tips and Tricks Git Tips 2: New Stuff in Git Git Tips 3: Really Large Repositories FOSDEM Git Talk Opening Up GitButler Debugging Tauri in VS Code Advent of GitButler Code Signing Commits in Git, Explained Virtual Branches Alpha Our We Are Developers Adventure Building Virtual Branches DevDays in Vilnius The Future of Software and Open Source Introducing GitButler
Git Tips 1: Oldies but Goodies
Scott Chacon · 2024-02-08 · via Butler's Log

For the first in our short series of Git tips, I wanted to start with stuff that's been around for a while, but it still seems like a lot of people don't know about or don't know how to use.

None of this is new, but I find them useful and they're arguably a little obscure. I'm just going to cover:

  • Conditional Configs
  • Git Blame and Log with Line Ranges
  • Git Blame with Following
  • Word Diff
  • Resolution Reuse

Let's dig in!

Many of you probably know this, but Git has a cool little key/value store called git config which will check in three places for values to use when it's running various commands.

Every Git user will have probably been told to run something like this when they first set up:

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

That adds the user.name value to your ~.gitconfig file. But there is also --system (which probably none of you have used) which writes it to a system-wide config file and --local (the default) that writes it to .git/config in whatever project you're currently in.

When Git looks for a value, it will look in that order - local, global, system - for a definition.

However, there is a secret fourth place that Git can look. If you add to your global config something that looks like this:

[includeIf "gitdir:~/projects/oss"]
    path = ~/.gitconfig-oss

Then Git will look in the ~/.gitconfig-oss files for values only if the project you are currently working in matches ~/projects/oss . So, you could have a "work" directory and have work-specific values there (company email address, gpg signing key, etc) and an "oss" directory with values for your open source projects, etc.

But gitdir is not the only filter you can use. You can also put branch name specific values as a include filter with onbranch or you can only include config files if the project you are currently in has a remote matching a specific URL with hasconfig:remote.*.url . So like if you have GitHub org specific keys or something.

Check out the docs for more.

Git Blame and Log with Line Ranges

There are a couple of interesting options that you can use with git blame that most people don't know about and nearly none of the existing GUIs implement.

One is the line range option, -L. A lot of times, if you're running blame on the command line, you just page the whole file and find the part you're looking for. However, if you want to just display a subsection of your file, you can give it a line range, like git blame -L 28,43 path/to/file

git blame -L

You can also use a semi-strange : syntax to give Git a pattern to find the beginning of a block and only blame that block. So in this same situation, I can get the same result by running git blame -L :'class LocalFile' gitbutler-ui/src/lib/vbranches/types.ts

Typically you can use a function name or something for that string.

The other thing you can do to see similar information in a different way, is to run git log with similar options. This will give you all the commits filtered to those that last touched this region of the file. So for example, git log -L28,43:gitbutler-ui/src/lib/vbranches/types.ts will give you something like this:

So instead of being ordered by lines, it sort of gathers all the commits that are shown in the blame and then shows you those commits with code that modified that block in each commit. Basically the same data, but in a different format, more like a story of how that code was put together.

One thing that is really not great about using blame in GUI tools is that the CLI has much more powerful tooling for finding something closer to the real story behind your code.

There are many scenarios where this is really valuable. The first is ignoring whitespace changes. Some of the GUIs do that, but not all of them. So if you go and implement a prettierrc file, BLAM, now you're the owner of tons of lines of code. The git blame -w option will ignore these types of whitespace changes.

The other great option is -C which will look for code movement between files in a commit. So if you refactor a function from one file to another, the normal git blame will simply show you as the author in the new file, but the -C option will follow that movement and show the last person to actually change those lines of code. Either of these scenarios could be what you're looking for, but I would argue that more often it's the latter.

If you want Git to try even harder (look for movement in multiple commits or in all of your commits) you can pass -C up to three times.

Also, your GUI does not do this (most likely, I can't speak for all of them).

So, let's look at the VS Code GitLens blame output of the previous example:

git blame in GitLens VS Code plugin

Ok, looks good. Kiril wrote most of this code it appears. Let's now look at the same block with git blame -w -C -C -C

git blame -C -C -C

Now we can see that Git has followed this hunk of code from file to file over the course of multiple renames.

Also, Kiril only really owns a few lines of code, Mattias actually wrote big hunks of it. If we want to know about those lines, it's much better to ask Mattias rather than Kiril, as our GUI blame would suggest.

This is incredibly minor, and some GUIs have nice versions of this (I find GitHub's better than what I'm about to show you, since it subtly does both) but if you ARE running git diff on the command line and there is a line change where something small changed within it, you can change Git's default format to word-based rather than line based with the --word-diff option.

normal, line-based git diff

super cool git diff --word-diff

Finally, if you're rebasing or cherry-picking a lot and you've ever run into the same conflict more than once, you can turn on a feature where Git memorizes the conflict and the resolution to it. If it ever sees that same conflict again, it will automatically re-solve it for you.

You can easily turn it on with the config setting rerere.enabled and you can further ask it to automatically stage it for you with rerere.autoUpdate

$ git config --global rerere.enabled true
$ git config --global rerere.autoUpdate true

a conflict... always remembers

Then, the next time you get a merge conflict that it's seen before, magic!

automatically fix it the next time

Again, all of this has been in Git for a while, but if you don't know... now you know.

Next up is New Stuff in Git.