svn2git迁移后实现$Revision$关键字展开及git describe性能评估咨询
git describe Performance Analysis & Optimizations Hey there, let's break down your setup and the performance question you've got about using git describe in a smudge filter. First, let's recap what you've already put in place—you're on the right track for approximating SVN's $Revision$ behavior after migrating with svn2git:
Your Current Configuration
1. .git/attributes
* filter=revsion # Quick note: Looks like there's a tiny typo here—"revsion" should probably be "revision" to avoid confusion later!
2. .git/config
[filter "revsion"] smudge = /bin/sed -e 's/\$Revision\$/$Revision: '$(GIT_EXEC_PATH=/usr/lib/git-core/ /usr/bin/git describe --match svn-r)'$/g' clean = /bin/sed -e 's/\$Revision: [^$]*\$/\$Revision\$/g'
Performance of git describe in Smudge Filters
Now, onto the core question: how much overhead does this add?
Why git describe Can Be Slow
git describe --match svn-r does more work than you might think:
- It traverses your commit history backwards to find the most recent tag matching the
svn-rpattern - It calculates the number of commits since that tag, plus the short SHA of your current commit
This isn't a problem for a single run, but smudge filters trigger every time Git checks out a file to your working directory. If you have dozens or hundreds of files with $Revision$, you'll spawn a new git describe process for each one—even though the result is identical for all files in the same checkout. For large repositories with long commit histories, this can add up to noticeable lag during checkouts.
Test the Baseline Cost
To get a concrete number, run this in your repo to measure how long a single git describe call takes:
time git describe --match svn-r
For small repos, this might be 10-50ms. For large repos with 10k+ commits and lots of tags, it could jump to 200ms or more. Multiply that by 100 files, and you're looking at 20+ seconds of extra checkout time—definitely something to optimize.
Optimizations to Speed Things Up
Here are three ways to cut down overhead while keeping the approximate $Revision$ behavior:
1. Cache the git describe Result
Since the result is the same for all files in a checkout, we can cache it once instead of running it per file. Create a small shell script (e.g., ~/.git-smudge-revision.sh):
#!/bin/bash # Cache the result in a repo-specific temp file CACHE_FILE=".git/revision-cache" CURRENT_HEAD=$(git rev-parse HEAD) # Only regenerate if HEAD changed or cache doesn't exist if [ ! -f "$CACHE_FILE" ] || [ "$(head -n1 "$CACHE_FILE")" != "$CURRENT_HEAD" ]; then REV=$(git describe --match svn-r) echo "$CURRENT_HEAD" > "$CACHE_FILE" echo "$REV" >> "$CACHE_FILE" else REV=$(tail -n1 "$CACHE_FILE") fi sed -e "s/\$Revision\$/\\\$Revision: $REV\\\$/g"
Then update your .git/config to use this script:
[filter "revsion"] smudge = /bin/bash ~/.git-smudge-revision.sh clean = /bin/sed -e 's/\$Revision: [^$]*\$/\$Revision\$/g'
Now git describe only runs once per checkout (when your HEAD changes), not per file.
2. Use a Lighter-Weight Git Command
If you don't strictly need the tag-based string (e.g., svn-r1234-5-gabcdef), replace git describe with a faster command like git rev-parse --short HEAD (gives just the short SHA of your current commit). It's way faster because it doesn't traverse history for tags.
Update your smudge command:
[filter "revsion"] smudge = /bin/sh -c 'sed -e "s/\$Revision\$/\\\$Revision: $(git rev-parse --short HEAD)\\\$/g"' clean = /bin/sed -e 's/\$Revision: [^$]*\$/\$Revision\$/g'
3. Precompute the Revision with a Git Hook
Another option is to generate a static revision file whenever you checkout or commit, then have the smudge filter read from that file.
Add a post-checkout hook (.git/hooks/post-checkout):
#!/bin/bash git describe --match svn-r > .revision
Then update your smudge filter to read from .revision:
[filter "revsion"] smudge = /bin/sh -c 'REV=$(cat .revision); sed -e "s/\$Revision\$/\\\$Revision: $REV\\\$/g"' clean = /bin/sed -e 's/\$Revision: [^$]*\$/\$Revision\$/g'
Don't forget to add .revision to your .gitignore so it doesn't get committed.
Final Quick Tip
Fix that typo in your filter name (revsion → revision)—it'll save you headaches if you ever need to debug or modify the setup later.
内容的提问来源于stack exchange,提问作者Chen Levy

