You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

svn2git迁移后实现$Revision$关键字展开及git describe性能评估咨询

SVN $Revision$ Keyword Expansion in Git: 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-r pattern
  • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:04:54