git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Git on Windows, CRLF issues

From
Jeff King <peff@peff.net>
Date
Apr 23, 2008, 08:08 UTC
Message-ID
<20080423080826.GA11935@sigill.intra.peff.net>
In-Reply-To
<32541b130804220951p224c9be7ya4e8de5056481fd1@mail.gmail.com>
On Tue, Apr 22, 2008 at 12:51:14PM -0400, Avery Pennarun wrote:
Show 5 quoted lines
> Do you think git would benefit from having a generalized version of
> this script?  Basically, the user provides a "munge" script on the
> command line, and there's a git-filter-branch mode for auto-munging
> (with a cache) every file in every checkin.  Even if it's *only* ever
> used for CRLF, I can imagine this being useful to a lot of people.
It was easy enough to work up the patch below, which allows
  git filter-branch --blob-filter 'tr a-z A-Z'

However, it's _still_ horribly slow. Shell script is nice and flexible, but running a tight loop like this is just painful. I suspect filter-branch in something like perl would be a lot faster and just as flexible (you could even do it in C, but you'd probably have to invent a little domain-specific scripting language).

It is still much better performance than a tree filter, though:
  $ cd git && time git filter-branch --tree-filter '
      find . -type f | while read f; do
        tr a-z A-Z <"$f" >tmp
        mv tmp "$f"
      done
    ' HEAD~10..HEAD
  real    4m38.626s
  user    1m32.726s
  sys     2m51.163s
  $ cd git && git filter-branch --blob-filter 'tr a-z A-Z' HEAD~10..HEAD
  real    1m40.809s
  user    0m36.822s
  sys     1m14.273s

Lots of system time in both. I'm sure we spend a fair bit of time hitting our very large map and blob-cache directories, which would be much more nicely implemented as associative arrays in memory (if we were using a more featureful language).

Anyway, here is the patch. I don't know if it is even worth applying, since it is still painfully slow.

---
 git-filter-branch.sh |   30 ++++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 333f6a8..0602b25 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -54,6 +54,23 @@ EOF
 
 eval "$functions"
 
+munge_blobs() {
+	while read mode sha1 stage path
+	do
+		if ! test -r "$workdir/../blob-cache/$sha1"
+		then
+			new=`git cat-file blob $sha1 |
+			     eval "$filter_blob" |
+			     git hash-object -w --stdin`
+			printf $new >$workdir/../blob-cache/$sha1
+		fi
+		printf "%s %s\t%s\n" \
+			"$mode" \
+			$(cat "$workdir/../blob-cache/$sha1") \
+			"$path"
+	done
+}
+
 # When piped a commit, output a script to set the ident of either
 # "author" or "committer
 
@@ -105,6 +122,7 @@ tempdir=.git-rewrite
 filter_env=
 filter_tree=
 filter_index=
+filter_blob=
 filter_parent=
 filter_msg=cat
 filter_commit='git commit-tree "$@"'
@@ -150,6 +168,9 @@ do
 	--index-filter)
 		filter_index="$OPTARG"
 		;;
+	--blob-filter)
+		filter_blob="$OPTARG"
+		;;
 	--parent-filter)
 		filter_parent="$OPTARG"
 		;;
@@ -227,6 +248,9 @@ ret=0
 # map old->new commit ids for rewriting parents
 mkdir ../map || die "Could not create map/ directory"
 
+# cache rewritten blobs for blob filter
+mkdir ../blob-cache || die "Could not create blob-cache/ directory"
+
 case "$filter_subdir" in
 "")
 	git rev-list --reverse --topo-order --default HEAD \
@@ -295,6 +319,12 @@ while read commit parents; do
 	eval "$filter_index" < /dev/null ||
 		die "index filter failed: $filter_index"
 
+	if test -n "$filter_blob"; then
+		git ls-files --stage |
+		munge_blobs |
+		git update-index --index-info
+	fi
+
 	parentstr=
 	for parent in $parents; do
 		for reparent in $(map "$parent"); do
-- 
1.5.5.1.144.g4c416.dirty
Previous: Johannes SixtNext: Johannes Schindelin
Message 11 of 30 in “Git on Windows, CRLF issues”
  1. Peter KarlssonApr 21, 2008
  2. Johannes SchindelinApr 21, 2008
  3. Avery PennarunApr 21, 2008
  4. Jeff KingApr 22, 2008
  5. Avery PennarunApr 22, 2008
  6. Peter KarlssonApr 23, 2008
  7. Jeff KingApr 23, 2008
  8. Peter KarlssonApr 23, 2008
  9. Johan HerlandApr 23, 2008
  10. Johannes SixtApr 23, 2008
  11. Jeff KingApr 23, 2008
  12. Johannes SchindelinApr 23, 2008
  13. Jeff KingApr 23, 2008
  14. Johannes SixtApr 23, 2008
  15. Jeff KingApr 23, 2008
  16. Johannes SixtApr 23, 2008
  17. Jeff KingApr 23, 2008
  18. Junio C HamanoApr 23, 2008
  19. Avery PennarunApr 23, 2008
  20. Johannes SchindelinApr 24, 2008
  21. Avery PennarunApr 24, 2008
  22. Jeff KingApr 24, 2008
  23. Avery PennarunApr 23, 2008
  24. Johannes SixtApr 24, 2008
  25. Johannes SixtApr 22, 2008
  26. Jakub NarebskiApr 21, 2008
  27. Peter KarlssonApr 22, 2008
  28. Johannes SixtApr 22, 2008
  29. Johannes SixtApr 22, 2008
  30. Peter KarlssonApr 22, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.