{"thread":{"id":"8405","subject":"[PATCH] Add git-filter-branch","startedAt":"2007-06-03T00:31:28Z","lastAt":"2007-06-06T18:38:35Z","messageCount":27,"participants":["Johannes Schindelin","Jakub Narebski","Steven Grimm","Johannes Sixt","Jonas Fonseca","David Kastrup","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"43839","messageId":"Pine.LNX.4.64.0706030129110.4046@racer.site","threadId":"8405","inReplyTo":null,"subject":"[PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-03T00:31:28Z","receivedAt":"2007-06-03T00:31:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis script is derived from Pasky's cg-admin-rewritehist.\n\nIn fact, it _is_ the same script, minimally adapted to work without cogito.\nIt _should_ be able to perform the same tasks, even if only relying on\ncore-git programs.\n\nAll the work is Pasky's, just the adaption is mine.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nHopefully-signed-off-by: Petr \"cogito master\" Baudis <pasky@suse.cz>\n---\n\n\tI will not have time to work on this for at least 24 hours. So, if \n\tpeople want to go wild with enhancing the test case (and fixing the \n\tscript), go wild!\n\n\tIMHO this should go into core-git, as one of the many, many, many \n\tenhancements that cogito brought to us.\n\n\tSo really, this is a way of thanks to Pasky, rather than just \n\tsaying good-bye to cogito.\n\n\tThanks, Pasky.\n\n Makefile                 |    3 +-\n git-filter-branch.sh     |  430 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t7003-filter-branch.sh |   47 +++++\n 3 files changed, 479 insertions(+), 1 deletions(-)\n create mode 100644 git-filter-branch.sh\n create mode 100755 t/t7003-filter-branch.sh\n\ndiff --git a/Makefile b/Makefile\nindex 7ecd8f0..da271ec 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -213,7 +213,8 @@ SCRIPT_SH = \\\n \tgit-am.sh \\\n \tgit-merge.sh git-merge-stupid.sh git-merge-octopus.sh \\\n \tgit-merge-resolve.sh git-merge-ours.sh \\\n-\tgit-lost-found.sh git-quiltimport.sh git-submodule.sh\n+\tgit-lost-found.sh git-quiltimport.sh git-submodule.sh \\\n+\tgit-filter-branch.sh\n \n SCRIPT_PERL = \\\n \tgit-add--interactive.perl \\\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nnew file mode 100644\nindex 0000000..c0a7680\n--- /dev/null\n+++ b/git-filter-branch.sh\n@@ -0,0 +1,430 @@\n+#!/bin/sh\n+#\n+# Rewrite revision history\n+# Copyright (c) Petr Baudis, 2006\n+# Minimal changes to \"port\" it to core-git (c) Johannes Schindelin, 2007\n+#\n+# Lets you rewrite GIT revision history by creating a new branch from\n+# your current branch by applying custom filters on each revision.\n+# Those filters can modify each tree (e.g. removing a file or running\n+# a perl rewrite on all files) or information about each commit.\n+# Otherwise, all information (including original commit times or merge\n+# information) will be preserved.\n+#\n+# The command takes the new branch name as a mandatory argument and\n+# the filters as optional arguments. If you specify no filters, the\n+# commits will be recommitted without any changes, which would normally\n+# have no effect and result with the new branch pointing to the same\n+# branch as your current branch. (Nevertheless, this may be useful in\n+# the future for compensating for some Git bugs or such, therefore\n+# such a usage is permitted.)\n+#\n+# WARNING! The rewritten history will have different ids for all the\n+# objects and will not converge with the original branch. You will not\n+# be able to easily push and distribute the rewritten branch. Please do\n+# not use this command if you do not know the full implications, and\n+# avoid using it anyway - do not do what a simple single commit on top\n+# of the current version would fix.\n+#\n+# Always verify that the rewritten version is correct before disposing\n+# the original branch.\n+#\n+# Note that since this operation is extensively I/O expensive, it might\n+# be a good idea to do it off-disk, e.g. on tmpfs. Reportedly the speedup\n+# is very noticeable.\n+#\n+# OPTIONS\n+# -------\n+# -d TEMPDIR:: The path to the temporary tree used for rewriting\n+#\tWhen applying a tree filter, the command needs to temporary\n+#\tcheckout the tree to some directory, which may consume\n+#\tconsiderable space in case of large projects. By default it\n+#\tdoes this in the '.git-rewrite/' directory but you can override\n+#\tthat choice by this parameter.\n+#\n+# -r STARTREV:: The commit id to start the rewrite at\n+#\tNormally, the command will rewrite the entire history. If you\n+#\tpass this argument, though, this will be the first commit it\n+#\twill rewrite and keep the previous commits intact.\n+#\n+# -k KEEPREV:: A commit id until which _not_ to rewrite history\n+#\tIf you pass this argument, this commit and all of its\n+#\tpredecessors are kept intact.\n+#\n+# Filters\n+# ~~~~~~~\n+# The filters are applied in the order as listed below. The COMMAND\n+# argument is always evaluated in shell using the 'eval' command.\n+# The $GIT_COMMIT environment variable is permanently set to contain\n+# the id of the commit being rewritten. The author/committer environment\n+# variables are set before the first filter is run.\n+#\n+# A 'map' function is available that takes an \"original sha1 id\" argument\n+# and outputs a \"rewritten sha1 id\" if the commit has been already\n+# rewritten, fails otherwise; the 'map' function can return several\n+# ids on separate lines if your commit filter emitted multiple commits\n+# (see below).\n+#\n+# --env-filter COMMAND:: The filter for modifying environment\n+#\tThis is the filter for modifying the environment in which\n+#\tthe commit will be performed. Specifically, you might want\n+#\tto rewrite the author/committer name/email/time environment\n+#\tvariables (see `git-commit` for details). Do not forget to\n+#\tre-export the variables.\n+#\n+# --tree-filter COMMAND:: The filter for rewriting tree (and its contents)\n+#\tThis is the filter for rewriting the tree and its contents.\n+#\tThe COMMAND argument is evaluated in shell with the working\n+#\tdirectory set to the root of the checked out tree. The new tree\n+#\tis then used as-is (new files are auto-added, disappeared files\n+#\tare auto-removed - .gitignore files nor any other ignore rules\n+#\tHAVE NO EFFECT!).\n+#\n+# --index-filter COMMAND:: The filter for rewriting index\n+#\tThis is the filter for rewriting the Git's directory index.\n+#\tIt is similar to the tree filter but does not check out the\n+#\ttree, which makes it much faster. However, you must use the\n+#\tlowlevel Git index manipulation commands to do your work.\n+#\n+# --parent-filter COMMAND:: The filter for rewriting parents\n+#\tThis is the filter for rewriting the commit's parent list.\n+#\tIt will receive the parent string on stdin and shall output\n+#\tthe new parent string on stdout. The parent string is in\n+#\tformat accepted by `git-commit-tree`: empty for initial\n+#\tcommit, \"-p parent\" for a normal commit and \"-p parent1\n+#\t-p parent2 -p parent3 ...\" for a merge commit.\n+#\n+# --msg-filter COMMAND:: The filter for rewriting commit message\n+#\tThis is the filter for rewriting the commit messages.\n+#\tThe COMMAND argument is evaluated in shell with the original\n+#\tcommit message on standard input; its standard output is\n+#\tis used as the new commit message.\n+#\n+# --commit-filter COMMAND:: The filter for performing the commit\n+#\tIf this filter is passed, it will be called instead of the\n+#\t`git-commit-tree` command, with those arguments:\n+#\n+#\t\tTREE_ID [-p PARENT_COMMIT_ID]...\n+#\n+#\tand the log message on stdin. The commit id is expected on\n+#\tstdout. As a special extension, the commit filter may emit\n+#\tmultiple commit ids; in that case, all of them will be used\n+#\tas parents instead of the original commit in further commits.\n+#\n+# --tag-name-filter COMMAND:: The filter for rewriting tag names.\n+#\tIf this filter is passed, it will be called for every tag ref\n+#\tthat points to a rewritten object (or to a tag object which\n+#\tpoints to a rewritten object). The original tag name is passed\n+#\tvia standard input, and the new tag name is expected on standard\n+#\toutput.\n+#\t\n+#\tThe original tags are not deleted, but can be overwritten;\n+#\tuse \"--tag-name-filter=cat\" to simply update the tags. In this\n+#\tcase, be very careful and make sure you have the old tags\n+#\tbacked up in case the conversion has run afoul.\n+#\n+#\tNote that there is currently no support for proper rewriting of\n+#\ttag objects; in layman terms, if the tag has a message or signature\n+#\tattached, the rewritten tag won't have it. Sorry. (It is by\n+#\tdefinition impossible to preserve signatures at any rate, though.)\n+#\n+# EXAMPLE USAGE\n+# -------------\n+# Suppose you want to remove a file (containing confidential information\n+# or copyright violation) from all commits:\n+#\n+#\tgit-filter-branch --tree-filter 'rm filename' newbranch\n+#\n+# A significantly faster version:\n+#\n+#\tgit-filter-branch --index-filter 'git-update-index --remove filename' newbranch\n+#\n+# Now, you will get the rewritten history saved in the branch 'newbranch'\n+# (your current branch is left untouched).\n+#\n+# To \"etch-graft\" a commit to the revision history (set a commit to be\n+# the parent of the current initial commit and propagate that):\n+#\n+#\tgit-filter-branch --parent-filter sed\\ 's/^$/-p graftcommitid/' newbranch\n+#\n+# (if the parent string is empty - therefore we are dealing with the\n+# initial commit - add graftcommit as a parent). Note that this assumes\n+# history with a single root (that is, no git-merge without common ancestors\n+# happened). If this is not the case, use:\n+#\n+#\tgit-filter-branch --parent-filter 'cat; [ \"$GIT_COMMIT\" = \"COMMIT\" ] && echo \"-p GRAFTCOMMIT\"' newbranch\n+#\n+# To remove commits authored by \"Darl McBribe\" from the history:\n+#\n+#\tgit-filter-branch --commit-filter 'if [ \"$GIT_AUTHOR_NAME\" = \"Darl McBribe\" ]; then shift; while [ -n \"$1\" ]; do shift; echo \"$1\"; shift; done; else git-commit-tree \"$@\"; fi' newbranch\n+#\n+# (the shift magic first throws away the tree id and then the -p\n+# parameters). Note that this handles merges properly! In case Darl\n+# committed a merge between P1 and P2, it will be propagated properly\n+# and all children of the merge will become merge commits with P1,P2\n+# as their parents instead of the merge commit.\n+#\n+# To restrict rewriting to only part of the history, use -r or -k or both.\n+# Consider this history:\n+#\n+#\t     D--E--F--G--H\n+#\t    /     /\n+#\tA--B-----C\n+#\n+# To rewrite only commits F,G,H, use:\n+#\n+#\tgit-filter-branch -r F ...\n+#\n+# To rewrite commits E,F,G,H, use one of these:\n+#\n+#\tgit-filter-branch -r E -k C ...\n+#\tgit-filter-branch -k D -k C ...\n+\n+# Testsuite: TODO\n+\n+set -e\n+\n+USAGE=\"git-filter-branch [-d TEMPDIR] [-r STARTREV]... [-k KEEPREV]... [-s SRCBRANCH] [FILTERS] DESTBRANCH\"\n+. git-sh-setup\n+\n+map()\n+{\n+\t[ -r \"$workdir/../map/$1\" ] || return 1\n+\tcat \"$workdir/../map/$1\"\n+}\n+\n+# When piped a commit, output a script to set the ident of either\n+# \"author\" or \"committer\n+\n+set_ident () {\n+\tlid=\"$(echo \"$1\" | tr \"A-Z\" \"a-z\")\"\n+\tuid=\"$(echo \"$1\" | tr \"a-z\" \"A-Z\")\"\n+\tpick_id_script='\n+\t\t/^'$lid' /{\n+\t\t\ts/'\\''/'\\''\\\\'\\'\\''/g\n+\t\t\th\n+\t\t\ts/^'$lid' \\([^<]*\\) <[^>]*> .*$/\\1/\n+\t\t\ts/'\\''/'\\''\\'\\'\\''/g\n+\t\t\ts/.*/export GIT_'$uid'_NAME='\\''&'\\''/p\n+\n+\t\t\tg\n+\t\t\ts/^'$lid' [^<]* <\\([^>]*\\)> .*$/\\1/\n+\t\t\ts/'\\''/'\\''\\'\\'\\''/g\n+\t\t\ts/.*/export GIT_'$uid'_EMAIL='\\''&'\\''/p\n+\n+\t\t\tg\n+\t\t\ts/^'$lid' [^<]* <[^>]*> \\(.*\\)$/\\1/\n+\t\t\ts/'\\''/'\\''\\'\\'\\''/g\n+\t\t\ts/.*/export GIT_'$uid'_DATE='\\''&'\\''/p\n+\n+\t\t\tq\n+\t\t}\n+\t'\n+\n+\tLANG=C LC_ALL=C sed -ne \"$pick_id_script\"\n+\t# Ensure non-empty id name.\n+\techo \"[ -n \\\"\\$GIT_${uid}_NAME\\\" ] || export GIT_${uid}_NAME=\\\"\\${GIT_${uid}_EMAIL%%@*}\\\"\"\n+}\n+\n+# list all parent's object names for a given commit\n+get_parents () {\n+\tgit-rev-list -1 --parents \"$1\" | sed \"s/^[0-9a-f]*//\"\n+}\n+\n+tempdir=.git-rewrite\n+unchanged=\" \"\n+filter_env=\n+filter_tree=\n+filter_index=\n+filter_parent=\n+filter_msg=cat\n+filter_commit='git-commit-tree \"$@\"'\n+filter_tag_name=\n+srcbranch=HEAD\n+while case \"$#\" in 0) usage;; esac\n+do\n+\tcase \"$1\" in\n+\t--)\n+\t\tshift\n+\t\tbreak\n+\t\t;;\n+\t-*)\n+\t\t;;\n+\t*)\n+\t\tbreak;\n+\tesac\n+\n+\t# all switches take one argument\n+\tARG=\"$1\"\n+\tcase \"$#\" in 1) usage ;; esac\n+\tshift\n+\tOPTARG=\"$1\"\n+\tshift\n+\n+\tcase \"$ARG\" in\n+\t-d)\n+\t\ttempdir=\"$OPTARG\"\n+\t\t;;\n+\t-r)\n+\t\tunchanged=\"$(get_parents \"$OPTARG\") $unchanged\"\n+\t\t;;\n+\t-k)\n+\t\tunchanged=\"$(git-rev-parse \"$OPTARG\"^{commit}) $unchanged\"\n+\t\t;;\n+\t--env-filter)\n+\t\tfilter_env=\"$OPTARG\"\n+\t\t;;\n+\t--tree-filter)\n+\t\tfilter_tree=\"$OPTARG\"\n+\t\t;;\n+\t--index-filter)\n+\t\tfilter_index=\"$OPTARG\"\n+\t\t;;\n+\t--parent-filter)\n+\t\tfilter_parent=\"$OPTARG\"\n+\t\t;;\n+\t--msg-filter)\n+\t\tfilter_msg=\"$OPTARG\"\n+\t\t;;\n+\t--commit-filter)\n+\t\tfilter_commit=\"$OPTARG\"\n+\t\t;;\n+\t--tag-name-filter)\n+\t\tfilter_tag_name=\"$OPTARG\"\n+\t\t;;\n+\t-s)\n+\t\tsrcbranch=\"$OPTARG\"\n+\t\t;;\n+\t*)\n+\t\tusage\n+\t\t;;\n+\tesac\n+done\n+\n+dstbranch=\"$1\"\n+test -n \"$dstbranch\" || die \"missing branch name\"\n+git-show-ref \"refs/heads/$dstbranch\" 2> /dev/null &&\n+\tdie \"branch $dstbranch already exists\"\n+\n+test ! -e \"$tempdir\" || die \"$tempdir already exists, please remove it\"\n+mkdir -p \"$tempdir/t\"\n+cd \"$tempdir/t\"\n+workdir=\"$(pwd)\"\n+\n+case \"$GIT_DIR\" in\n+/*)\n+\t;;\n+*)\n+\texport GIT_DIR=\"$(pwd)/../../$GIT_DIR\"\n+\t;;\n+esac\n+\n+export GIT_INDEX_FILE=\"$(pwd)/../index\"\n+git-read-tree # seed the index file\n+\n+ret=0\n+\n+\n+mkdir ../map # map old->new commit ids for rewriting parents\n+\n+# seed with identity mappings for the parents where we start off\n+for commit in $unchanged; do\n+\techo $commit > ../map/$commit\n+done\n+\n+git-rev-list --reverse --topo-order $srcbranch --not $unchanged >../revs\n+commits=$(cat ../revs | wc -l | tr -d \" \")\n+\n+test $commits -eq 0 && die \"Found nothing to rewrite\"\n+\n+i=0\n+while read commit; do\n+\ti=$((i+1))\n+\tprintf \"$commit ($i/$commits) \"\n+\n+\tgit-read-tree -i -m $commit\n+\n+\texport GIT_COMMIT=$commit\n+\tgit-cat-file commit \"$commit\" >../commit\n+\n+\teval \"$(set_ident AUTHOR <../commit)\"\n+\teval \"$(set_ident COMMITTER <../commit)\"\n+\teval \"$filter_env\"\n+\n+\tif [ \"$filter_tree\" ]; then\n+\t\tgit-checkout-index -f -u -a\n+\t\t# files that $commit removed are now still in the working tree;\n+\t\t# remove them, else they would be added again\n+\t\tgit-ls-files -z --others | xargs -0 rm -f\n+\t\teval \"$filter_tree\"\n+\t\tgit-diff-index -r $commit | cut -f 2- | tr '\\n' '\\0' | \\\n+\t\t\txargs -0 git-update-index --add --replace --remove\n+\t\tgit-ls-files -z --others | \\\n+\t\t\txargs -0 git-update-index --add --replace --remove\n+\tfi\n+\n+\teval \"$filter_index\"\n+\n+\tparentstr=\n+\tfor parent in $(get_parents $commit); do\n+\t\tif [ -r \"../map/$parent\" ]; then\n+\t\t\tfor reparent in $(cat \"../map/$parent\"); do\n+\t\t\t\tparentstr=\"$parentstr -p $reparent\"\n+\t\t\tdone\n+\t\telse\n+\t\t\tdie \"assertion failed: parent $parent for commit $commit not found in rewritten ones\"\n+\t\tfi\n+\tdone\n+\tif [ \"$filter_parent\" ]; then\n+\t\tparentstr=\"$(echo \"$parentstr\" | eval \"$filter_parent\")\"\n+\tfi\n+\n+\tsed -e '1,/^$/d' <../commit | \\\n+\t\teval \"$filter_msg\" | \\\n+\t\tsh -c \"$filter_commit\" git-commit-tree $(git-write-tree) $parentstr | \\\n+\t\ttee ../map/$commit\n+done <../revs\n+\n+git-update-ref refs/heads/\"$dstbranch\" $(head -n 1 ../map/$(tail -n 1 ../revs))\n+if [ \"$(cat ../map/$(tail -n 1 ../revs) | wc -l)\" -gt 1 ]; then\n+\techo \"WARNING: Your commit filter caused the head commit to expand to several rewritten commits. Only the first such commit was recorded as the current $dstbranch head but you will need to resolve the situation now (probably by manually merging the other commits). These are all the commits:\" >&2\n+\tsed 's/^/\t/' ../map/$(tail -n 1 ../revs) >&2\n+\tret=1\n+fi\n+\n+if [ \"$filter_tag_name\" ]; then\n+\tgit-for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |\n+\twhile read sha1 type ref; do\n+\t\tref=\"${ref#refs/tags/}\"\n+\t\t# XXX: Rewrite tagged trees as well?\n+\t\tif [ \"$type\" != \"commit\" -a \"$type\" != \"tag\" ]; then\n+\t\t\tcontinue;\n+\t\tfi\n+\n+\t\tif [ \"$type\" = \"tag\" ]; then\n+\t\t\t# Dereference to a commit\n+\t\t\tsha1t=\"$sha1\"\n+\t\t\tsha1=\"$(git-rev-parse \"$sha1\"^{commit} 2>/dev/null)\" || continue\n+\t\tfi\n+\n+\t\t[ -f \"../map/$sha1\" ] || continue\n+\t\tnew_sha1=\"$(cat \"../map/$sha1\")\"\n+\t\texport GIT_COMMIT=\"$sha1\"\n+\t\tnew_ref=\"$(echo \"$ref\" | eval \"$filter_tag_name\")\"\n+\n+\t\techo \"$ref -> $new_ref ($sha1 -> $new_sha1)\"\n+\n+\t\tif [ \"$type\" = \"tag\" ]; then\n+\t\t\t# Warn that we are not rewriting the tag object itself.\n+\t\t\twarn \"unreferencing tag object $sha1t\"\n+\t\tfi\n+\n+\t\tgit-update-ref \"refs/tags/$new_ref\" \"$new_sha1\"\n+\tdone\n+fi\n+\n+cd ../..\n+rm -rf \"$tempdir\"\n+echo \"Rewritten history saved to the $dstbranch branch\"\n+\n+exit $ret\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nnew file mode 100755\nindex 0000000..9a4dae4\n--- /dev/null\n+++ b/t/t7003-filter-branch.sh\n@@ -0,0 +1,47 @@\n+#!/bin/sh\n+\n+test_description='git-filter-branch'\n+. ./test-lib.sh\n+\n+make_commit () {\n+\tlower=$(echo $1 | tr A-Z a-z)\n+\techo $lower > $lower\n+\tgit add $lower\n+\tgit commit -m $1\n+\tgit tag $1\n+}\n+\n+test_expect_success 'setup' '\n+\tmake_commit A\n+\tmake_commit B\n+\tgit checkout -b branch B\n+\tmake_commit D\n+\tmake_commit E\n+\tgit checkout master\n+\tmake_commit C\n+\tgit checkout branch\n+\tgit merge C\n+\tgit tag F\n+\tmake_commit G\n+\tmake_commit H\n+'\n+\n+H=$(git-rev-parse H)\n+\n+test_expect_success 'rewrite identically' '\n+\tgit-filter-branch H2\n+'\n+\n+test_expect_success 'result is really identical' '\n+\ttest $H = $(git-rev-parse H2)\n+'\n+\n+test_expect_success 'rewrite, renaming a specific file' '\n+\tgit-filter-branch --tree-filter \"mv d doh || :\" H3\n+'\n+\n+test_expect_success 'test that the file was renamed' '\n+\ttest d = $(git show H3:doh)\n+'\n+\n+test_done\n-- \n1.5.2.2663.gd77e7-dirty\n"},{"id":"43840","messageId":"f3t2mm$f0$1@sea.gmane.org","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706030129110.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-03T00:46:15Z","receivedAt":"2007-06-03T00:46:15Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Johannes Schindelin wrote:\n\n> This script is derived from Pasky's cg-admin-rewritehist.\n> \n> In fact, it _is_ the same script, minimally adapted to work without cogito.\n> It _should_ be able to perform the same tasks, even if only relying on\n> core-git programs.\n> \n> All the work is Pasky's, just the adaption is mine.\n\nI was thinking about rewriting cg-adin-rewritehist as git-rewritehist\nusing Perl (IIRC it needs bash, not only POSIX shell), and make it\nuse git-fast-import.\n\nBut that was in planning (read: it would be nice...) phase...\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"43842","messageId":"Pine.LNX.4.64.0706030147520.4046@racer.site","threadId":"8405","inReplyTo":"f3t2mm$f0$1@sea.gmane.org","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-03T00:50:16Z","receivedAt":"2007-06-03T00:50:16Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\n[thank you for not including me in the Cc: list]\n\nOn Sun, 3 Jun 2007, Jakub Narebski wrote:\n\n> Johannes Schindelin wrote:\n> \n> > This script is derived from Pasky's cg-admin-rewritehist.\n> > \n> > In fact, it _is_ the same script, minimally adapted to work without cogito.\n> > It _should_ be able to perform the same tasks, even if only relying on\n> > core-git programs.\n> > \n> > All the work is Pasky's, just the adaption is mine.\n> \n> I was thinking about rewriting cg-adin-rewritehist as git-rewritehist\n> using Perl (IIRC it needs bash, not only POSIX shell), and make it\n> use git-fast-import.\n\nFirst, it does not need Perl.\n\nSecond, it does not even need bash.\n\nAt least that is what I tried to make sure. I replaced the only instance \nof a bashim I was aware, namely the arrayism of $unchanged. It can be a \nstring just as well, as we are only storing object names in it.\n\nTell me if it does not work for you.\n\nOr even better, provide me with a test case that fails for you.\n\nCiao,\nDscho\n"},{"id":"43891","messageId":"200706031228.58779.jnareb@gmail.com","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706030147520.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-03T10:28:58Z","receivedAt":"2007-06-03T10:28:58Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Sun, 3 Jun 2007, Johannes Schindelin wrote:\n> On Sun, 3 Jun 2007, Jakub Narebski wrote:\n>> Johannes Schindelin wrote:\n>> \n>>> This script is derived from Pasky's cg-admin-rewritehist.\n>>> \n>>> In fact, it _is_ the same script, minimally adapted to work without cogito.\n>>> It _should_ be able to perform the same tasks, even if only relying on\n>>> core-git programs.\n>>> \n>>> All the work is Pasky's, just the adaption is mine.\n>> \n>> I was thinking about rewriting cg-adin-rewritehist as git-rewritehist\n>> using Perl (IIRC it needs bash, not only POSIX shell), and make it\n>> use git-fast-import.\n\nBy the way, why did you change name to git-filter-branch, instead of\nleaving it [almost] as is, i.e. git-rewritehist. Or if you wanted to\nemphasize that it rewrites only one branch at a time, git-rewrite-branch?\n\nNote that history (branch) gets rewritten also in absence of filters,\nif there are any grafts in place. But I might be mistaken.\n\n> First, it does not need Perl.\n> \n> Second, it does not even need bash.\n\nIf I remember correctly (but I can be wrong here) Pasky said that he had\nto use arrays in cg-admin-rewritehist. Because introducing dependency on\nbash would be bad, that was the cause of thought to rewrite it in Perl\n(which we depend on anyway). \n\nSee below.\n\n> At least that is what I tried to make sure. I replaced the only instance \n> of a bashim I was aware, namely the arrayism of $unchanged. It can be a \n> string just as well, as we are only storing object names in it.\n\nI'm sorry, I haven't reviewed your patch carefully enough, it seems like.\nIf you can translate cg-admin-rewritehist to POSIX shell, more power\nto you.\n\n                          -- \" --\n\nFew notes of lesser importance (meaning they can go into subsequent\ncommits).\n\n1. Documentation: Cogito had documentation together with the command\n   described, similarly to Perl POD, or LaTeX doc package + DocStrip,\n   etc. It has IIRC rules in Makefile to extract documentation.\n\n   In git we have documentation in separate files. The commands\n   themselves have only usage, and sometimes long usage embedded.\n   It would be nice of git-filter-branch / git-rewrite-branch also\n   followed this convention.\n\n2. Using fast-import.\n\n   >> +# Note that since this operation is extensively I/O expensive, it might\n   >> +# be a good idea to do it off-disk, e.g. on tmpfs. Reportedly the speedup\n   >> +# is very noticeable.\n\n   Would it be possible to use git-fast-import to reduce I/O in this\n   command? Cogito didn't use it because it is quite new, but there\n   is no reason to not to use it now, I think.\n\n-- \nJakub Narebski\nPoland\n"},{"id":"43895","messageId":"46630A31.5090104@midwinter.com","threadId":"8405","inReplyTo":"200706031228.58779.jnareb@gmail.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Steven Grimm","fromEmail":"koreth@midwinter.com","sentAt":"2007-06-03T18:36:33Z","receivedAt":"2007-06-03T18:36:33Z","isPatch":true,"sender":{"key":"koreth@midwinter.com","avatar":"https://gravatar.com/avatar/71b4d2e8b62f168bdc9e9205341159e3567003b4f9e2127c617c5fa0a1f5bad2?d=mp&s=160"},"body":"Jakub Narebski wrote:\n> By the way, why did you change name to git-filter-branch, instead of\n> leaving it [almost] as is, i.e. git-rewritehist. Or if you wanted to\n> emphasize that it rewrites only one branch at a time, git-rewrite-branch?\n>   \n\nOne argument against the name change is that one could easily imagine \nthis tool being extended in the future to filter all branches rather \nthan just one. For example, the \"get rid of copyrighted file X in my \nrepository\" use case is a bit of a pain right now using \ncg-admin-rewritehist if the file was introduced early in the history of \na large repo; in that scenario you want to be able to say, \"filter this \nfile out of my entire repo\" without particularly caring which branches \nit appeared in (and without losing any of the branch structure in your \nhistory.)\n\n-Steve\n"},{"id":"43924","messageId":"Pine.LNX.4.64.0706040006470.4046@racer.site","threadId":"8405","inReplyTo":"200706031228.58779.jnareb@gmail.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-03T23:07:52Z","receivedAt":"2007-06-03T23:07:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 3 Jun 2007, Jakub Narebski wrote:\n\n> On Sun, 3 Jun 2007, Johannes Schindelin wrote:\n> > On Sun, 3 Jun 2007, Jakub Narebski wrote:\n> >> Johannes Schindelin wrote:\n> >> \n> >>> This script is derived from Pasky's cg-admin-rewritehist.\n> >>> \n> >>> In fact, it _is_ the same script, minimally adapted to work without cogito.\n> >>> It _should_ be able to perform the same tasks, even if only relying on\n> >>> core-git programs.\n> >>> \n> >>> All the work is Pasky's, just the adaption is mine.\n> >> \n> >> I was thinking about rewriting cg-adin-rewritehist as git-rewritehist\n> >> using Perl (IIRC it needs bash, not only POSIX shell), and make it\n> >> use git-fast-import.\n> \n> By the way, why did you change name to git-filter-branch, instead of\n> leaving it [almost] as is, i.e. git-rewritehist. Or if you wanted to\n> emphasize that it rewrites only one branch at a time, git-rewrite-branch?\n\nIt does not rewrite the branch. It writes a filtered _copy_. That is what \nI wanted to make clear by that renaming.\n\n> Note that history (branch) gets rewritten also in absence of filters, if \n> there are any grafts in place. But I might be mistaken.\n\nActually, if you check the first non-setup test in the provide test \nscript, no. It is not _really_ rewritten. As the commit names stay exactly \nthe same.\n\n> > First, it does not need Perl.\n> > \n> > Second, it does not even need bash.\n> \n> If I remember correctly (but I can be wrong here) Pasky said that he had\n> to use arrays in cg-admin-rewritehist. Because introducing dependency on\n> bash would be bad, that was the cause of thought to rewrite it in Perl\n> (which we depend on anyway). \n\nI rewrote the only instance where arrays were used:\n\n> > At least that is what I tried to make sure. I replaced the only \n> > instance of a bashim I was aware, namely the arrayism of $unchanged. \n> > It can be a string just as well, as we are only storing object names \n> > in it.\n> \n> I'm sorry, I haven't reviewed your patch carefully enough, it seems \n> like. If you can translate cg-admin-rewritehist to POSIX shell, more \n> power to you.\n\nActually, that is my understanding.\n\n> Few notes of lesser importance (meaning they can go into subsequent \n> commits).\n> \n> 1. Documentation: Cogito had documentation together with the command\n>    described, similarly to Perl POD, or LaTeX doc package + DocStrip,\n>    etc. It has IIRC rules in Makefile to extract documentation.\n> \n>    In git we have documentation in separate files. The commands\n>    themselves have only usage, and sometimes long usage embedded.\n>    It would be nice of git-filter-branch / git-rewrite-branch also\n>    followed this convention.\n\nYes, I did not plan to provide documentation with the first patch, since I \nwanted to encourage _review_ of the patch. Obviously, I failed ;-)\n\n> 2. Using fast-import.\n> \n>    >> +# Note that since this operation is extensively I/O expensive, it might\n>    >> +# be a good idea to do it off-disk, e.g. on tmpfs. Reportedly the speedup\n>    >> +# is very noticeable.\n> \n>    Would it be possible to use git-fast-import to reduce I/O in this\n>    command? Cogito didn't use it because it is quite new, but there\n>    is no reason to not to use it now, I think.\n\nIt is overkill, usually.\n\nThe only thing that could benefit from it, would be complicated tree \nfilters.\n\nBut _the_ main usage for this script (in my expectation, at least) will be \nto split projects into subprojects.\n\nFor this, we _still_ don't need fast-import, but maybe a better \ntree-filter (something like --subdir-filter, which only checks out the \nsubdir (in the root), and also only takes those revisions into account \nthat actually touch that subdir).\n\nCiao,\nDscho\n"},{"id":"43946","messageId":"4663BCDA.F1BADDD8@eudaptics.com","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706030129110.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Sixt","fromEmail":"j.sixt@eudaptics.com","sentAt":"2007-06-04T07:18:50Z","receivedAt":"2007-06-04T07:18:50Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Schindelin wrote:\n> \n> This script is derived from Pasky's cg-admin-rewritehist.\n> \n> In fact, it _is_ the same script, minimally adapted to work without cogito.\n> It _should_ be able to perform the same tasks, even if only relying on\n> core-git programs.\n> \n> All the work is Pasky's, just the adaption is mine.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> Hopefully-signed-off-by: Petr \"cogito master\" Baudis <pasky@suse.cz>\n\nIf you hadn't done that, I'd done it sooner or later. Thanks!\n\n> +       -r)\n> +               unchanged=\"$(get_parents \"$OPTARG\") $unchanged\"\n> +               ;;\n> +       -k)\n> +               unchanged=\"$(git-rev-parse \"$OPTARG\"^{commit}) $unchanged\"\n> +               ;;\n\nThese two (-r and -k) together with...\n\n> +# seed with identity mappings for the parents where we start off\n> +for commit in $unchanged; do\n> +       echo $commit > ../map/$commit\n> +done\n\n... this and ...\n\n> +               if [ -r \"../map/$parent\" ]; then\n> +                       for reparent in $(cat \"../map/$parent\"); do\n> +                               parentstr=\"$parentstr -p $reparent\"\n> +                       done\n> +               else\n> +                       die \"assertion failed: parent $parent for commit $commit not found in rewritten ones\"\n\n... this, means that any simple command like \n\n  git filter-branch -k orgin/master origin/next new-next\n\nof your git.git clone will fail with the \"assertion failed\". (I haven't\ntried your script, yet, but cg-admin-rewritehist fails.)\n\nI propose that you just get rid of the \"seed\" stance and don't fail if a\ncommit cannot be mapped - just use it unchanged (don't forget to adjust\nthe map() function, too). Then you can get rid of -r and use -k to\nspecify everything you want under \"--not\" in the rev-list.\n\n-- Hannes\n"},{"id":"43954","messageId":"4663C66C.3C5603B7@eudaptics.com","threadId":"8405","inReplyTo":"4663BCDA.F1BADDD8@eudaptics.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Sixt","fromEmail":"j.sixt@eudaptics.com","sentAt":"2007-06-04T07:59:40Z","receivedAt":"2007-06-04T07:59:40Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Sixt wrote:\n> ... this, means that any simple command like\n> \n>   git filter-branch -k orgin/master origin/next new-next\n\nMake this:\n\n   git filter-branch -k orgin/master -s origin/next new-next\n\n-- Hannes\n"},{"id":"43987","messageId":"Pine.LNX.4.64.0706041711500.4046@racer.site","threadId":"8405","inReplyTo":"4663BCDA.F1BADDD8@eudaptics.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-04T16:11:59Z","receivedAt":"2007-06-04T16:11:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 4 Jun 2007, Johannes Sixt wrote:\n\n> [...] any simple command like \n> \n>   git filter-branch -k orgin/master origin/next new-next\n> \n> of your git.git clone will fail with the \"assertion failed\". (I haven't\n> tried your script, yet, but cg-admin-rewritehist fails.)\n\nAs you mentioned yourself, you should say \"-s origin/next\". \ncg-admin-rewritehist will only rewrite the current branch (since cogito \nstarted out as one-branch-per-repo).\n\n> I propose that you just get rid of the \"seed\" stance and don't fail if a\n> commit cannot be mapped - just use it unchanged (don't forget to adjust\n> the map() function, too).\n\nIt is as much for debug reasons as for consistency, so I'd rather keep it. \nOne more safety valve for catching bugs.\n\n> Then you can get rid of -r and use -k to specify everything you want \n> under \"--not\" in the rev-list.\n\nActually, -r is quite useful. It means \"start rewriting with this commit\", \nand saying \"--not <commit>^\" is _not_ the same when <commit> is a merge.\n\nCiao,\nDscho\n"},{"id":"43990","messageId":"46643F2D.7C896CBC@eudaptics.com","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706041711500.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Sixt","fromEmail":"j.sixt@eudaptics.com","sentAt":"2007-06-04T16:34:53Z","receivedAt":"2007-06-04T16:34:53Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Schindelin wrote:\n> \n> Hi,\n> \n> On Mon, 4 Jun 2007, Johannes Sixt wrote:\n> > I propose that you just get rid of the \"seed\" stance and don't fail if a\n> > commit cannot be mapped - just use it unchanged (don't forget to adjust\n> > the map() function, too).\n> \n> It is as much for debug reasons as for consistency, so I'd rather keep it.\n> One more safety valve for catching bugs.\n> \n> > Then you can get rid of -r and use -k to specify everything you want\n> > under \"--not\" in the rev-list.\n> \n> Actually, -r is quite useful. It means \"start rewriting with this commit\",\n> and saying \"--not <commit>^\" is _not_ the same when <commit> is a merge.\n\nBut this makes only sense if you have a linear history. Consider this\nhistory, where you want to rewrite the commits that are only on branch\n'next':\n\n--A--B--C--D--E--F--G--H       <- master\n   \\  \\  \\  \\  \\  \\  \\  \\\n    X--o--o--o--o--o--o--o--o  <- next\n\nHow would you go about with the current calling convention? It's\nunpractical to say the least:\n\n   git filter-branch -r X -k B -k C -k D ... -k H new-next\n\nIf you don't give all the -k, then you get the \"assertion failed\" error\nbecause the parents B..H are not registered in the commit id map. This\nis not something I'd like to try on a history like git.git's.\n\nOTOH, rev-list can easily restrict the commits regardless of how many\nmerges there are in 'next':\n\n   git rev-list next --not master\n\nWhy not use its powers?\n\n-- Hannes\n"},{"id":"43994","messageId":"Pine.LNX.4.64.0706041850350.4046@racer.site","threadId":"8405","inReplyTo":"46643F2D.7C896CBC@eudaptics.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-04T17:55:31Z","receivedAt":"2007-06-04T17:55:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 4 Jun 2007, Johannes Sixt wrote:\n\n> Johannes Schindelin wrote:\n> > \n> > Hi,\n> > \n> > On Mon, 4 Jun 2007, Johannes Sixt wrote:\n> > > I propose that you just get rid of the \"seed\" stance and don't fail if a\n> > > commit cannot be mapped - just use it unchanged (don't forget to adjust\n> > > the map() function, too).\n> > \n> > It is as much for debug reasons as for consistency, so I'd rather keep it.\n> > One more safety valve for catching bugs.\n> > \n> > > Then you can get rid of -r and use -k to specify everything you want\n> > > under \"--not\" in the rev-list.\n> > \n> > Actually, -r is quite useful. It means \"start rewriting with this commit\",\n> > and saying \"--not <commit>^\" is _not_ the same when <commit> is a merge.\n> \n> But this makes only sense if you have a linear history. Consider this\n> history, where you want to rewrite the commits that are only on branch\n> 'next':\n> \n> --A--B--C--D--E--F--G--H       <- master\n>    \\  \\  \\  \\  \\  \\  \\  \\\n>     X--o--o--o--o--o--o--o--o  <- next\n> \n> How would you go about with the current calling convention?\n\nAre you actually sure that this scenario makes sense? When is the last \ntime you wanted to filter a branch?\n\nIn any case, for such a degenerated test case I would rather try to limit \nfiltering in the filter expression. Remember: you don't have to change \n_every_ commit.\n\nOf course, if I am the only one defending this behaviour, I'll change it.\n\nCiao,\nDscho\n"},{"id":"44041","messageId":"46650A58.4934C07C@eudaptics.com","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706041850350.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Sixt","fromEmail":"j.sixt@eudaptics.com","sentAt":"2007-06-05T07:01:44Z","receivedAt":"2007-06-05T07:01:44Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Schindelin wrote:\n> On Mon, 4 Jun 2007, Johannes Sixt wrote:\n> > But this makes only sense if you have a linear history. Consider this\n> > history, where you want to rewrite the commits that are only on branch\n> > 'next':\n> >\n> > --A--B--C--D--E--F--G--H       <- master\n> >    \\  \\  \\  \\  \\  \\  \\  \\\n> >     X--o--o--o--o--o--o--o--o  <- next\n> >\n> > How would you go about with the current calling convention?\n> \n> Are you actually sure that this scenario makes sense? When is the last\n> time you wanted to filter a branch?\n\nOh, this makes a lot of sense. For example after I've imported a CVS\nrepository I had installed grafts for a number of merges that were made\nin CVS (but we all know that CVS doesn't record them, so I did that\nmanually this way). That would be the merge commits in 'next' of the\nexample above. Now a simple\n\n   git filter-branch -k master new-next\n\ncould \"implant\" the grafts into the commits. In this scenario I don't\nneed to rewrite 'master' because I know in advance that nothing would\nactually be rewritten.\n\n(Since 'master' was about 8000 commits I really didn't want to wait\nuntil the no-ops would be completed, so I did it by actually fixing\ncg-admin-rewritehist to not complain about the unmapped parents.)\n\n> In any case, for such a degenerated test case I would rather try to limit\n> filtering in the filter expression. Remember: you don't have to change\n> _every_ commit.\n\nI don't think that this is a degenerate case. See the example above.\n\nPlease observe that the only reasonable way to limit the commits to\nrewrite is by giving some --not arguments to the rev-list. The filter\nscriptlets themselves have no easy way to tell whether a commit should\nbe rewritten or not. They just rewrite - with the final result perhaps\nending up identical to the original; but no labor was saved.\n\n-- Hannes\n"},{"id":"44056","messageId":"20070605101845.GA16160@diku.dk","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706030147520.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2007-06-05T10:18:45Z","receivedAt":"2007-06-05T10:18:45Z","isPatch":true,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote Sun, Jun 03, 2007:\n> Second, it does not even need bash.\n> \n> At least that is what I tried to make sure. I replaced the only instance \n> of a bashim I was aware, namely the arrayism of $unchanged. It can be a \n> string just as well, as we are only storing object names in it.\n> \n> Tell me if it does not work for you.\n> \n> Or even better, provide me with a test case that fails for you.\n\nI found a small problem when /bin/sh is linked to dash.\n\n$ /bin/dash t*-filter-branch.sh\n*   ok 1: setup\n* FAIL 2: rewrite identically\n\n                git-filter-branch H2\n\n* FAIL 3: result is really identical\n\n                test $H = $(git-rev-parse H2)\n\n* FAIL 4: rewrite, renaming a specific file\n\n                git-filter-branch --tree-filter \"mv d doh || :\" H3\n\n* FAIL 5: test that the file was renamed\n\n                test d = $(git show H3:doh)\n\n* failed 4 among 5 test(s)\n$ cd trash/\n$ rm -rf .git-rewrite/\n$ git filter-branch H2\n/home/fonseca/bin/git-filter-branch: 386: arith: syntax error: \"i+1\"\n$\n\nA possible fix that makes the test pass for me.\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 0c8a7df..5cf9d3c 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -339,7 +339,7 @@ test $commits -eq 0 && die \"Found nothing to rewrite\"\n \n i=0\n while read commit; do\n-\ti=$((i+1))\n+\ti=$(echo i+1 | bc)\n \tprintf \"$commit ($i/$commits) \"\n \n \tgit-read-tree -i -m $commit\n\n-- \nJonas Fonseca\n"},{"id":"44059","messageId":"868xayofy7.fsf@lola.quinscape.zz","threadId":"8405","inReplyTo":"20070605101845.GA16160@diku.dk","subject":"Re: [PATCH] Add git-filter-branch","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-06-05T10:26:08Z","receivedAt":"2007-06-05T10:26:08Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Jonas Fonseca <fonseca@diku.dk> writes:\n\n> A possible fix that makes the test pass for me.\n>\n> diff --git a/git-filter-branch.sh b/git-filter-branch.sh\n> index 0c8a7df..5cf9d3c 100644\n> --- a/git-filter-branch.sh\n> +++ b/git-filter-branch.sh\n> @@ -339,7 +339,7 @@ test $commits -eq 0 && die \"Found nothing to rewrite\"\n>  \n>  i=0\n>  while read commit; do\n> -\ti=$((i+1))\n> +\ti=$(echo i+1 | bc)\n\nWould not work.  You need $i instead.\n\n>  \tprintf \"$commit ($i/$commits) \"\n>  \n>  \tgit-read-tree -i -m $commit\n\nMore portable would be\n\n        i=`expr $i + 1`\n\nsince not everything has bc installed.  Is $(...) available generally?\nI thought it was a bashism, too.\n\n\n-- \nDavid Kastrup\n"},{"id":"44060","messageId":"7vzm3ebsnk.fsf@assigned-by-dhcp.cox.net","threadId":"8405","inReplyTo":"20070605101845.GA16160@diku.dk","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-05T10:30:07Z","receivedAt":"2007-06-05T10:30:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonas Fonseca <fonseca@diku.dk> writes:\n\n> $ git filter-branch H2\n> /home/fonseca/bin/git-filter-branch: 386: arith: syntax error: \"i+1\"\n> $\n>\n> A possible fix that makes the test pass for me.\n>\n> diff --git a/git-filter-branch.sh b/git-filter-branch.sh\n> index 0c8a7df..5cf9d3c 100644\n> --- a/git-filter-branch.sh\n> +++ b/git-filter-branch.sh\n> @@ -339,7 +339,7 @@ test $commits -eq 0 && die \"Found nothing to rewrite\"\n>  \n>  i=0\n>  while read commit; do\n> -\ti=$((i+1))\n> +\ti=$(echo i+1 | bc)\n\nAre you sure this is not \"echo $i+1\"???\n\nThere are quite a few $((arithmetic)) already in our shell code,\nso I was initially a bit surprised.  However, upon closer\ninspection, this particular use is not kosher at all.\n\nThe portable ones we already have in the code say things like:\n\n\tmsgnum=$(($msgnum+1))\n\nThe one in filter-branch that bit you does not dereference 'i'.\nI am reasonably sure if you fix it to read:\n\n\ti=$(( $i+1 ))\n\ndash would grok it.\n"},{"id":"44062","messageId":"20070605103421.GB16160@diku.dk","threadId":"8405","inReplyTo":"7vzm3ebsnk.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2007-06-05T10:34:22Z","receivedAt":"2007-06-05T10:34:22Z","isPatch":true,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"Junio C Hamano <gitster@pobox.com> wrote Tue, Jun 05, 2007:\n> Jonas Fonseca <fonseca@diku.dk> writes:\n> \n> > $ git filter-branch H2\n> > /home/fonseca/bin/git-filter-branch: 386: arith: syntax error: \"i+1\"\n> > $\n> >\n> > A possible fix that makes the test pass for me.\n> >\n> > diff --git a/git-filter-branch.sh b/git-filter-branch.sh\n> > index 0c8a7df..5cf9d3c 100644\n> > --- a/git-filter-branch.sh\n> > +++ b/git-filter-branch.sh\n> > @@ -339,7 +339,7 @@ test $commits -eq 0 && die \"Found nothing to rewrite\"\n> >  \n> >  i=0\n> >  while read commit; do\n> > -\ti=$((i+1))\n> > +\ti=$(echo i+1 | bc)\n> \n> Are you sure this is not \"echo $i+1\"???\n\nYes, I noticed this right after sending the mail. People on this list\nare just too damn fast for me to send a correction. ;)\n\n> There are quite a few $((arithmetic)) already in our shell code,\n> so I was initially a bit surprised.  However, upon closer\n> inspection, this particular use is not kosher at all.\n> \n> The portable ones we already have in the code say things like:\n> \n> \tmsgnum=$(($msgnum+1))\n\nYes, I should have investigated before sending.\n\n> The one in filter-branch that bit you does not dereference 'i'.\n> I am reasonably sure if you fix it to read:\n> \n> \ti=$(( $i+1 ))\n> \n> dash would grok it.\n\nThis works here. Even without the spaces.\n\n-- \nJonas Fonseca\n"},{"id":"44074","messageId":"Pine.LNX.4.64.0706051454210.4046@racer.site","threadId":"8405","inReplyTo":"20070605103421.GB16160@diku.dk","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-05T13:55:11Z","receivedAt":"2007-06-05T13:55:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 5 Jun 2007, Jonas Fonseca wrote:\n\n> Junio C Hamano <gitster@pobox.com> wrote Tue, Jun 05, 2007:\n>\n> > The one in filter-branch that bit you does not dereference 'i'.\n> > I am reasonably sure if you fix it to read:\n> > \n> > \ti=$(( $i+1 ))\n> > \n> > dash would grok it.\n> \n> This works here. Even without the spaces.\n\nThanks for fixing up so quickly after me.\n\nCiao,\nDscho\n"},{"id":"44076","messageId":"Pine.LNX.4.64.0706051537360.4046@racer.site","threadId":"8405","inReplyTo":"46650A58.4934C07C@eudaptics.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-05T15:58:13Z","receivedAt":"2007-06-05T15:58:13Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 5 Jun 2007, Johannes Sixt wrote:\n\n> Johannes Schindelin wrote:\n> > On Mon, 4 Jun 2007, Johannes Sixt wrote:\n> > > But this makes only sense if you have a linear history. Consider this\n> > > history, where you want to rewrite the commits that are only on branch\n> > > 'next':\n> > >\n> > > --A--B--C--D--E--F--G--H       <- master\n> > >    \\  \\  \\  \\  \\  \\  \\  \\\n> > >     X--o--o--o--o--o--o--o--o  <- next\n> > >\n> > > How would you go about with the current calling convention?\n> > \n> > Are you actually sure that this scenario makes sense? When is the last\n> > time you wanted to filter a branch?\n> \n> Oh, this makes a lot of sense. For example after I've imported a CVS\n> repository I had installed grafts for a number of merges that were made\n> in CVS (but we all know that CVS doesn't record them, so I did that\n> manually this way). That would be the merge commits in 'next' of the\n> example above. Now a simple\n> \n>    git filter-branch -k master new-next\n> \n> could \"implant\" the grafts into the commits. In this scenario I don't\n> need to rewrite 'master' because I know in advance that nothing would\n> actually be rewritten.\n> \n> (Since 'master' was about 8000 commits I really didn't want to wait\n> until the no-ops would be completed, so I did it by actually fixing\n> cg-admin-rewritehist to not complain about the unmapped parents.)\n\nOkay, then. Are you okay with keeping the same options? (See proposed \npatch below.)\n\nJust out of curiousity, do you have any timing data?\n\nCiao,\nDscho\n\n-- snipsnap --\n[PATCH] filter-branch: fix behaviour of '-k'\n\nThe option '-k' says that the given commit and _all_ of its ancestors\nare kept as-is.\n\nHowever, if a to-be-rewritten commit branched from an ancestor of an\nancestor of a commit given with '-k', filter-branch would fail.\n\nExample:\n\n\tA - B\n\t  \\\n\t    C\n\nIf filter-branch was called with '-k B -s C', it would actually keep\nB (and A as its parent), but would rewrite C, and its parent.\n\nNoticed by Johannes Sixt.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-filter-branch.sh     |   29 +++++++++++++++++------------\n t/t7003-filter-branch.sh |    9 +++++++++\n 2 files changed, 26 insertions(+), 12 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 0c8a7df..6807782 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -327,11 +327,6 @@ ret=0\n \n mkdir ../map # map old->new commit ids for rewriting parents\n \n-# seed with identity mappings for the parents where we start off\n-for commit in $unchanged; do\n-\techo $commit > ../map/$commit\n-done\n-\n git-rev-list --reverse --topo-order $srcbranch --not $unchanged >../revs\n commits=$(cat ../revs | wc -l | tr -d \" \")\n \n@@ -372,7 +367,8 @@ while read commit; do\n \t\t\t\tparentstr=\"$parentstr -p $reparent\"\n \t\t\tdone\n \t\telse\n-\t\t\tdie \"assertion failed: parent $parent for commit $commit not found in rewritten ones\"\n+\t\t\t# if it was not rewritten, take the original\n+\t\t\tparentstr=\"$parentstr -p $parent\"\n \t\tfi\n \tdone\n \tif [ \"$filter_parent\" ]; then\n@@ -385,12 +381,21 @@ while read commit; do\n \t\ttee ../map/$commit\n done <../revs\n \n-git-update-ref refs/heads/\"$dstbranch\" $(head -n 1 ../map/$(tail -n 1 ../revs))\n-if [ \"$(cat ../map/$(tail -n 1 ../revs) | wc -l)\" -gt 1 ]; then\n-\techo \"WARNING: Your commit filter caused the head commit to expand to several rewritten commits. Only the first such commit was recorded as the current $dstbranch head but you will need to resolve the situation now (probably by manually merging the other commits). These are all the commits:\" >&2\n-\tsed 's/^/\t/' ../map/$(tail -n 1 ../revs) >&2\n-\tret=1\n-fi\n+src_head=$(tail -n 1 ../revs)\n+target_head=$(head -n 1 ../map/$src_head)\n+case \"$target_head\" in\n+'')\n+\techo Nothing rewritten\n+\t;;\n+*)\n+\tgit-update-ref refs/heads/\"$dstbranch\" $target_head\n+\tif [ $(cat ../map/$src_head | wc -l) -gt 1 ]; then\n+\t\techo \"WARNING: Your commit filter caused the head commit to expand to several rewritten commits. Only the first such commit was recorded as the current $dstbranch head but you will need to resolve the situation now (probably by manually merging the other commits). These are all the commits:\" >&2\n+\t\tsed 's/^/\t/' ../map/$src_head >&2\n+\t\tret=1\n+\tfi\n+\t;;\n+esac\n \n if [ \"$filter_tag_name\" ]; then\n \tgit-for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nindex 9a4dae4..520963a 100755\n--- a/t/t7003-filter-branch.sh\n+++ b/t/t7003-filter-branch.sh\n@@ -44,4 +44,13 @@ test_expect_success 'test that the file was renamed' '\n \ttest d = $(git show H3:doh)\n '\n \n+git tag oldD H3~4\n+test_expect_success 'rewrite one branch, keeping a side branch' '\n+\tgit-filter-branch --tree-filter \"mv b boh || :\" -k D -s oldD modD\n+'\n+\n+test_expect_success 'common ancestor is still common (unchanged)' '\n+\ttest \"$(git-merge-base modD D)\" = \"$(git-rev-parse B)\"\n+'\n+\n test_done\n-- \n1.5.2.1.2627.g8eec-dirty\n"},{"id":"44131","messageId":"466665AD.CF5B85DF@eudaptics.com","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706051537360.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Sixt","fromEmail":"j.sixt@eudaptics.com","sentAt":"2007-06-06T07:43:41Z","receivedAt":"2007-06-06T07:43:41Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Schindelin wrote:\n> Okay, then. Are you okay with keeping the same options? (See proposed\n> patch below.)\n\nI can live with it. But what do you think of this in addtion? It\nreplaces -k, -r, -s in favor of rev-list arguments.\n\n> Just out of curiousity, do you have any timing data?\n\nI did one test run through 8118 commits which took 18 minutes. But it\nturns out that I have a buglet here in git-commit-tree, which would\nnot accept committer dates before 2000-1-1 00:00:01 UTC, but since the\nfirst commit is from 1999, this test rewrote the entire history, which\nwas not intended.\n\n--- 8< ---\nFrom: Johannes Sixt <johannes.sixt@telecom.at>\n\nfilter-branch: Use rev-list arguments to specify revision ranges.\n\nA subset of commits in a branch used to be specified by options (-k, -r)\nas well as the branch tip itself (-s). It is more natural (for git users)\nto specify revision ranges like 'master..next' instead. This makes it so.\nIf no range is specified it defaults to 'HEAD'.\n\nAs a consequence, the new name of the filtered branch must be the first\nnon-option argument. All remaining arguments are passed to 'git rev-list'\nunmodified.\n\nThe tip of the branch that gets filtered is implied: It is the first\ncommit that git rev-list would print for the specified range.\n\nSigned-off-by: Johannes Sixt <johannes.sixt@telecom.at>\n---\n git-filter-branch.sh     |   39 ++++++++++++---------------------------\n t/t7003-filter-branch.sh |    2 +-\n 2 files changed, 13 insertions(+), 28 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 9e12a6c..190a492 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -42,15 +42,6 @@\n #\tdoes this in the '.git-rewrite/' directory but you can override\n #\tthat choice by this parameter.\n #\n-# -r STARTREV:: The commit id to start the rewrite at\n-#\tNormally, the command will rewrite the entire history. If you\n-#\tpass this argument, though, this will be the first commit it\n-#\twill rewrite and keep the previous commits intact.\n-#\n-# -k KEEPREV:: A commit id until which _not_ to rewrite history\n-#\tIf you pass this argument, this commit and all of its\n-#\tpredecessors are kept intact.\n-#\n # Filters\n # ~~~~~~~\n # The filters are applied in the order as listed below. The COMMAND\n@@ -164,27 +155,31 @@\n # and all children of the merge will become merge commits with P1,P2\n # as their parents instead of the merge commit.\n #\n-# To restrict rewriting to only part of the history, use -r or -k or both.\n+# To restrict rewriting to only part of the history, specify a revision\n+# range in addition to the new branch name. The new branch name will\n+# point to the top-most revision that a 'git rev-list' of this range\n+# will print.\n+#\n # Consider this history:\n #\n #\t     D--E--F--G--H\n #\t    /     /\n #\tA--B-----C\n #\n-# To rewrite only commits F,G,H, use:\n+# To rewrite commits D,E,F,G,H, use:\n #\n-#\tgit-filter-branch -r F ...\n+#\tgit-filter-branch ... new-H C..H\n #\n # To rewrite commits E,F,G,H, use one of these:\n #\n-#\tgit-filter-branch -r E -k C ...\n-#\tgit-filter-branch -k D -k C ...\n+#\tgit-filter-branch ... new-H C..H --not D\n+#\tgit-filter-branch ... new-H D..H --not C\n \n # Testsuite: TODO\n \n set -e\n \n-USAGE=\"git-filter-branch [-d TEMPDIR] [-r STARTREV]... [-k KEEPREV]... [-s SRCBRANCH] [FILTERS] DESTBRANCH\"\n+USAGE=\"git-filter-branch [-d TEMPDIR] [FILTERS] DESTBRANCH [REV-RANGE]\"\n . git-sh-setup\n \n map()\n@@ -233,7 +228,6 @@ get_parents () {\n }\n \n tempdir=.git-rewrite\n-unchanged=\" \"\n filter_env=\n filter_tree=\n filter_index=\n@@ -241,7 +235,6 @@ filter_parent=\n filter_msg=cat\n filter_commit='git-commit-tree \"$@\"'\n filter_tag_name=\n-srcbranch=HEAD\n while case \"$#\" in 0) usage;; esac\n do\n \tcase \"$1\" in\n@@ -266,12 +259,6 @@ do\n \t-d)\n \t\ttempdir=\"$OPTARG\"\n \t\t;;\n-\t-r)\n-\t\tunchanged=\"$(get_parents \"$OPTARG\") $unchanged\"\n-\t\t;;\n-\t-k)\n-\t\tunchanged=\"$(git-rev-parse \"$OPTARG\"^{commit}) $unchanged\"\n-\t\t;;\n \t--env-filter)\n \t\tfilter_env=\"$OPTARG\"\n \t\t;;\n@@ -293,9 +280,6 @@ do\n \t--tag-name-filter)\n \t\tfilter_tag_name=\"$OPTARG\"\n \t\t;;\n-\t-s)\n-\t\tsrcbranch=\"$OPTARG\"\n-\t\t;;\n \t*)\n \t\tusage\n \t\t;;\n@@ -303,6 +287,7 @@ do\n done\n \n dstbranch=\"$1\"\n+shift\n test -n \"$dstbranch\" || die \"missing branch name\"\n git-show-ref \"refs/heads/$dstbranch\" 2> /dev/null &&\n \tdie \"branch $dstbranch already exists\"\n@@ -328,7 +313,7 @@ ret=0\n \n mkdir ../map # map old->new commit ids for rewriting parents\n \n-git-rev-list --reverse --topo-order $srcbranch --not $unchanged >../revs\n+git-rev-list --reverse --topo-order --default HEAD \"$@\" >../revs\n commits=$(cat ../revs | wc -l | tr -d \" \")\n \n test $commits -eq 0 && die \"Found nothing to rewrite\"\ndiff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh\nindex 520963a..89b405b 100755\n--- a/t/t7003-filter-branch.sh\n+++ b/t/t7003-filter-branch.sh\n@@ -46,7 +46,7 @@ test_expect_success 'test that the file was renamed' '\n \n git tag oldD H3~4\n test_expect_success 'rewrite one branch, keeping a side branch' '\n-\tgit-filter-branch --tree-filter \"mv b boh || :\" -k D -s oldD modD\n+\tgit-filter-branch --tree-filter \"mv b boh || :\" modD D..oldD\n '\n \n test_expect_success 'common ancestor is still common (unchanged)' '\n-- \n1.5.2.1.114.gc6c36\n"},{"id":"44138","messageId":"7vy7ix5wf6.fsf@assigned-by-dhcp.cox.net","threadId":"8405","inReplyTo":"466665AD.CF5B85DF@eudaptics.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-06T08:17:33Z","receivedAt":"2007-06-06T08:17:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <J.Sixt@eudaptics.com> writes:\n\n> Johannes Schindelin wrote:\n>> Okay, then. Are you okay with keeping the same options? (See proposed\n>> patch below.)\n>\n> I can live with it. But what do you think of this in addtion? It\n> replaces -k, -r, -s in favor of rev-list arguments.\n> ...\n> A subset of commits in a branch used to be specified by options (-k, -r)\n> as well as the branch tip itself (-s). It is more natural (for git users)\n> to specify revision ranges like 'master..next' instead. This makes it so.\n> If no range is specified it defaults to 'HEAD'.\n\nFWIW, I find this much more sensible and gittish ;-)\n"},{"id":"44166","messageId":"Pine.LNX.4.64.0706061600060.4046@racer.site","threadId":"8405","inReplyTo":"466665AD.CF5B85DF@eudaptics.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-06T15:00:27Z","receivedAt":"2007-06-06T15:00:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 6 Jun 2007, Johannes Sixt wrote:\n\n> It is more natural (for git users) to specify revision ranges like \n> 'master..next' instead. This makes it so. If no range is specified it \n> defaults to 'HEAD'.\n> \n> As a consequence, the new name of the filtered branch must be the first\n> non-option argument. All remaining arguments are passed to 'git rev-list'\n> unmodified.\n\nI was really close to do this myself. But I thought there was a \nproblem to infer the correct source branch.\n\nBut you're right, this is more gittish. (Consider that an ACK from me.)\n\nOf course, it would be even more so if the target branch name was \n\"filtered\", overrideable by \"--target <name>\".\n\nCiao,\nDscho\n"},{"id":"44167","messageId":"4666D143.32BC9693@eudaptics.com","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706061600060.4046@racer.site","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Sixt","fromEmail":"j.sixt@eudaptics.com","sentAt":"2007-06-06T15:22:43Z","receivedAt":"2007-06-06T15:22:43Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Johannes Schindelin wrote:\n> Of course, it would be even more so if the target branch name was\n> \"filtered\", overrideable by \"--target <name>\".\n\nMy plan for this is:\n\n1. run the rev-list args (\"$@\") through rev-parse\n2. pick only the positive ones (/^[a-z0-9]{40}$/)\n3. filter show-ref against the result of 2.\n4. foreach ref in the result of 3. install a refs/rewritten/$ref\n   with the mapped id if and only if the mapped id is different\n   from the original id of $ref.\n\nThen you can, for example, 'git filter-branch --all' to rewrite all\nbranches.\n\n-- Hannes\n"},{"id":"44168","messageId":"Pine.LNX.4.64.0706061620540.4046@racer.site","threadId":"8405","inReplyTo":"20070605103421.GB16160@diku.dk","subject":"[PATCH] filter-branch: use $(($i+1)) instead of $((i+1))","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-06T15:24:07Z","receivedAt":"2007-06-06T15:24:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThe expression $((i+1)) is not portable at all: even some bash versions\ndo not grok it. So do not use it.\n\nNoticed by Jonas Fonseca.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tOn Tue, 5 Jun 2007, Jonas Fonseca wrote:\n\t\n\t> Junio C Hamano <gitster@pobox.com> wrote Tue, Jun 05, 2007:\n\t> > Jonas Fonseca <fonseca@diku.dk> writes:\n\t> > \n\t> > > $ git filter-branch H2\n\t> > > /home/fonseca/bin/git-filter-branch: 386: arith: syntax error: \"i+1\"\n\t> > > $\n\t> > >\n\t> > > A possible fix that makes the test pass for me.\n\t> >\n\t> > [...]\n\t> >\n\t> > The portable ones we already have in the code say things like:\n\t> > \n\t> > \tmsgnum=$(($msgnum+1))\n\t> \n\t> Yes, I should have investigated before sending.\n\t> \n\t> > The one in filter-branch that bit you does not dereference 'i'.\n\t> > I am reasonably sure if you fix it to read:\n\t> > \n\t> > \ti=$(( $i+1 ))\n\t> > \n\t> > dash would grok it.\n\t> \n\t> This works here. Even without the spaces.\n\n\tVoila.\n\n git-filter-branch.sh |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex 6807782..f89cfe1 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -334,7 +334,7 @@ test $commits -eq 0 && die \"Found nothing to rewrite\"\n \n i=0\n while read commit; do\n-\ti=$((i+1))\n+\ti=$(($i+1))\n \tprintf \"$commit ($i/$commits) \"\n \n \tgit-read-tree -i -m $commit\n-- \n1.5.2.1.2656.g1921f\n"},{"id":"44169","messageId":"1181144191777-git-send-email-johannes.sixt@telecom.at","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706051537360.4046@racer.site","subject":"[PATCH] filter-branch: also don't fail in map() if a commit cannot be mapped","fromName":"Johannes Sixt","fromEmail":"johannes.sixt@telecom.at","sentAt":"2007-06-06T15:36:31Z","receivedAt":"2007-06-06T15:36:31Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"The map() function can be used by filters to map a commit id to its\nrewritten id. Such a mapping may not exist, in which case the identity\nmapping is used (the commit is returned unchanged).\n\nIn the rewrite loop, this mapping is also needed, but was done\nexplicitly in the same way. Use the map() function instead.\n\nSigned-off-by: Johannes Sixt <johannes.sixt@telecom.at>\n---\n git-filter-branch.sh |   14 +++++---------\n 1 files changed, 5 insertions(+), 9 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex fbbb044..9e12a6c 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -189,7 +189,8 @@ USAGE=\"git-filter-branch [-d TEMPDIR] [-r STARTREV]... [-k KEEPREV]... [-s SRCBR\n \n map()\n {\n-\t[ -r \"$workdir/../map/$1\" ] || return 1\n+\t# if it was not rewritten, take the original\n+\t[ -r \"$workdir/../map/$1\" ] || echo \"$1\"\n \tcat \"$workdir/../map/$1\"\n }\n \n@@ -362,14 +363,9 @@ while read commit; do\n \n \tparentstr=\n \tfor parent in $(get_parents $commit); do\n-\t\tif [ -r \"../map/$parent\" ]; then\n-\t\t\tfor reparent in $(cat \"../map/$parent\"); do\n-\t\t\t\tparentstr=\"$parentstr -p $reparent\"\n-\t\t\tdone\n-\t\telse\n-\t\t\t# if it was not rewritten, take the original\n-\t\t\tparentstr=\"$parentstr -p $parent\"\n-\t\tfi\n+\t\tfor reparent in $(map \"$parent\"); do\n+\t\t\tparentstr=\"$parentstr -p $reparent\"\n+\t\tdone\n \tdone\n \tif [ \"$filter_parent\" ]; then\n \t\tparentstr=\"$(echo \"$parentstr\" | eval \"$filter_parent\")\"\n-- \n1.5.2.1.120.gd732\n"},{"id":"44173","messageId":"Pine.LNX.4.64.0706061850220.4046@racer.site","threadId":"8405","inReplyTo":"1181144191777-git-send-email-johannes.sixt@telecom.at","subject":"Re: [PATCH] filter-branch: also don't fail in map() if a commit cannot be mapped","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-06T17:50:36Z","receivedAt":"2007-06-06T17:50:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 6 Jun 2007, Johannes Sixt wrote:\n\n> -\t[ -r \"$workdir/../map/$1\" ] || return 1\n> +\t# if it was not rewritten, take the original\n> +\t[ -r \"$workdir/../map/$1\" ] || echo \"$1\"\n\nMaybe \"test\" instead of \"[\"? Otherwise, ACK from me.\n\nCiao,\nDscho\n"},{"id":"44178","messageId":"Pine.LNX.4.64.0706061854330.4046@racer.site","threadId":"8405","inReplyTo":"4666D143.32BC9693@eudaptics.com","subject":"Re: [PATCH] Add git-filter-branch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-06T17:59:06Z","receivedAt":"2007-06-06T17:59:06Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 6 Jun 2007, Johannes Sixt wrote:\n\n> Johannes Schindelin wrote:\n> > Of course, it would be even more so if the target branch name was\n> > \"filtered\", overrideable by \"--target <name>\".\n> \n> My plan for this is:\n> \n> 1. run the rev-list args (\"$@\") through rev-parse\n> 2. pick only the positive ones (/^[a-z0-9]{40}$/)\n> 3. filter show-ref against the result of 2.\n> 4. foreach ref in the result of 3. install a refs/rewritten/$ref\n>    with the mapped id if and only if the mapped id is different\n>    from the original id of $ref.\n> \n> Then you can, for example, 'git filter-branch --all' to rewrite all\n> branches.\n\nThat sounds really sensible. For (2), I suggest \"git-rev-parse \n--symbolic\", though. And maybe you want to make sure that there were no \ninvalid branch names, i.e. \"git-filter-branch next~2\". (Otherwise, you \nwould try to create refs/filtered/next~2 after filtering all commits.)\n\nCiao,\nDscho\n"},{"id":"44179","messageId":"200706062038.36093.johannes.sixt@telecom.at","threadId":"8405","inReplyTo":"Pine.LNX.4.64.0706061850220.4046@racer.site","subject":"[PATCH v2] filter-branch: also don't fail in map() if a commit cannot be mapped","fromName":"Johannes Sixt","fromEmail":"johannes.sixt@telecom.at","sentAt":"2007-06-06T18:38:35Z","receivedAt":"2007-06-06T18:38:35Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"The map() function can be used by filters to map a commit id to its\nrewritten id. Such a mapping may not exist, in which case the identity\nmapping is used (the commit is returned unchanged).\n\nIn the rewrite loop, this mapping is also needed, but was done\nexplicitly in the same way. Use the map() function instead.\n\nSigned-off-by: Johannes Sixt <johannes.sixt@telecom.at>\n---\nOn Wednesday 06 June 2007 19:50, Johannes Schindelin wrote:\n> On Wed, 6 Jun 2007, Johannes Sixt wrote:\n> > -\t[ -r \"$workdir/../map/$1\" ] || return 1\n> > +\t# if it was not rewritten, take the original\n> > +\t[ -r \"$workdir/../map/$1\" ] || echo \"$1\"\n>\n> Maybe \"test\" instead of \"[\"? Otherwise, ACK from me.\n\nRight!\n\n git-filter-branch.sh |   14 +++++---------\n 1 files changed, 5 insertions(+), 9 deletions(-)\n\ndiff --git a/git-filter-branch.sh b/git-filter-branch.sh\nindex fbbb044..15e9b46 100644\n--- a/git-filter-branch.sh\n+++ b/git-filter-branch.sh\n@@ -189,7 +189,8 @@ USAGE=\"git-filter-branch [-d TEMPDIR] [-r STARTREV]... [-k KEEPREV]... [-s SRCBR\n \n map()\n {\n-\t[ -r \"$workdir/../map/$1\" ] || return 1\n+\t# if it was not rewritten, take the original\n+\ttest -r \"$workdir/../map/$1\" || echo \"$1\"\n \tcat \"$workdir/../map/$1\"\n }\n \n@@ -362,14 +363,9 @@ while read commit; do\n \n \tparentstr=\n \tfor parent in $(get_parents $commit); do\n-\t\tif [ -r \"../map/$parent\" ]; then\n-\t\t\tfor reparent in $(cat \"../map/$parent\"); do\n-\t\t\t\tparentstr=\"$parentstr -p $reparent\"\n-\t\t\tdone\n-\t\telse\n-\t\t\t# if it was not rewritten, take the original\n-\t\t\tparentstr=\"$parentstr -p $parent\"\n-\t\tfi\n+\t\tfor reparent in $(map \"$parent\"); do\n+\t\t\tparentstr=\"$parentstr -p $reparent\"\n+\t\tdone\n \tdone\n \tif [ \"$filter_parent\" ]; then\n \t\tparentstr=\"$(echo \"$parentstr\" | eval \"$filter_parent\")\"\n-- \n1.5.2\n"}]}