* Retroactively change email signature?
@ 2008-01-02 20:37 Stephen Sinclair
2008-01-02 21:17 ` Jakub Narebski
2008-01-02 21:24 ` Linus Torvalds
0 siblings, 2 replies; 9+ messages in thread
From: Stephen Sinclair @ 2008-01-02 20:37 UTC (permalink / raw)
To: git
Hi,
I imagine that changing old commits is considered one of the great
evils of source control, but I have a small problem:
I have a habit of testing my code on several different computers and
operating systems. Sometimes when setting up a new computer for
testing (and thus, for development, since testing always results in a
few commits), I have forgotten to use git-config to configure my name
and email address.
Since git doesn't warn when I've forgotten to do this, my git-log is
now sprinkled with various email addresses, some which are just my
username@hostname. This is completely useless to people who might
view my public repository.
Is it possible to retroactively change the author and email of several
commits? Perhaps some sort of search-and-replace for the commit
metadata? Even for older commits, I'd like to change the email
addresses to my current address.
If it's not possible it's not the end of the world, but I thought it
wouldn't hurt to ask.
thanks,
Steve
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature?
2008-01-02 20:37 Retroactively change email signature? Stephen Sinclair
@ 2008-01-02 21:17 ` Jakub Narebski
2008-01-02 21:24 ` Linus Torvalds
1 sibling, 0 replies; 9+ messages in thread
From: Jakub Narebski @ 2008-01-02 21:17 UTC (permalink / raw)
To: Stephen Sinclair; +Cc: git
"Stephen Sinclair" <radarsat1@gmail.com> writes:
> I imagine that changing old commits is considered one of the great
> evils of source control, but I have a small problem:
> I have a habit of testing my code on several different computers and
> operating systems. Sometimes when setting up a new computer for
> testing (and thus, for development, since testing always results in a
> few commits), I have forgotten to use git-config to configure my name
> and email address.
>
> Since git doesn't warn when I've forgotten to do this, my git-log is
> now sprinkled with various email addresses, some which are just my
> username@hostname. This is completely useless to people who might
> view my public repository.
This most certainly should get addressed IMHO.
> Is it possible to retroactively change the author and email of several
> commits? Perhaps some sort of search-and-replace for the commit
> metadata? Even for older commits, I'd like to change the email
> addresses to my current address.
>
> If it's not possible it's not the end of the world, but I thought it
> wouldn't hurt to ask.
You can use git-filter-branch(1), but please remember that it is
practically rewriting whole repository, so you should do this _before_
you publish any changes.
--
Jakub Narebski
Poland
ShadeHawk on #git
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature?
2008-01-02 20:37 Retroactively change email signature? Stephen Sinclair
2008-01-02 21:17 ` Jakub Narebski
@ 2008-01-02 21:24 ` Linus Torvalds
2008-01-02 22:06 ` Stephen Sinclair
2008-01-03 5:52 ` Retroactively change email signature? [resend] Sam Vilain
1 sibling, 2 replies; 9+ messages in thread
From: Linus Torvalds @ 2008-01-02 21:24 UTC (permalink / raw)
To: Stephen Sinclair; +Cc: git
On Wed, 2 Jan 2008, Stephen Sinclair wrote:
>
> Is it possible to retroactively change the author and email of several
> commits? Perhaps some sort of search-and-replace for the commit
> metadata? Even for older commits, I'd like to change the email
> addresses to my current address.
See
man git-filter-branch
and the "--env-filter" flag (and "--msg-filter" if you also want to change
things like Sign-off's etc in the message text itself)
BUT! See also the big bold-face warning: using "filter-branch" will not
change old commits, it will create a series of *new* commits that bear a
striking resemblance to the old ones, but are not the same. So you'll have
a totally new history.
That matters for things like
- if you've already publicised the old history, you need to tell people
that they should fetch things anew
- if you refer to the commit SHA1's elsewhere (like in commit messages
that revert previous commits), those SHA1's are still "valid", but they
refer to the *old* history, not the new history you created.
(I don't think git-filter-branch even exposes any easy way to remap the
"revert commit xyz" messages in the message format. It's not technically
hard to use a --msg-filter for it, but it seems a big bother).
Linus
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature?
2008-01-02 21:24 ` Linus Torvalds
@ 2008-01-02 22:06 ` Stephen Sinclair
2008-01-03 0:53 ` David Brown
2008-01-03 5:52 ` Retroactively change email signature? [resend] Sam Vilain
1 sibling, 1 reply; 9+ messages in thread
From: Stephen Sinclair @ 2008-01-02 22:06 UTC (permalink / raw)
To: git
Thanks, I was able to use git-filter-branch to accomplish what I wanted.
I should have mentioned in the original email that it is not a widely
distributed repo, so I'm not too worried about breaking things at this
point. I guess for a larger project it might be a problem, so I
probably just wouldn't do it.
> BUT! See also the big bold-face warning: using "filter-branch" will not
> change old commits, it will create a series of *new* commits that bear a
> striking resemblance to the old ones, but are not the same. So you'll have
> a totally new history.
Got it, thanks.
I'll just have to remember to git-config properly next time I do this.
One thing that's a bit odd for me is that I use a different email
address for this particular project..
Conveniently I'm able to use git-config to set an email address
locally for this repo, however I have to remember to do this every
time I clone it somewhere. Not a problem, necessarily, but perhaps
just a matter of training myself.
For example, I have a clone of this repo on a Linux, Windows, and OS X
machine, and also another clone for each on my laptop.. git is
actually turning out to be great for doing all this swapping between
machines, but it does take a little training to remember to set the
configuration, since there's no central repo to ask me for my username
and password before I can commit.
cheers,
Steve
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature?
2008-01-02 22:06 ` Stephen Sinclair
@ 2008-01-03 0:53 ` David Brown
0 siblings, 0 replies; 9+ messages in thread
From: David Brown @ 2008-01-03 0:53 UTC (permalink / raw)
To: Stephen Sinclair; +Cc: git
On Wed, Jan 02, 2008 at 05:06:37PM -0500, Stephen Sinclair wrote:
>For example, I have a clone of this repo on a Linux, Windows, and OS X
>machine, and also another clone for each on my laptop.. git is
>actually turning out to be great for doing all this swapping between
>machines, but it does take a little training to remember to set the
>configuration, since there's no central repo to ask me for my username
>and password before I can commit.
You can set the user.email and user.name globally with 'git config --global
user.email ...' and the likes, but that only works if you use the same ID.
It'd be nice if there was something that could be put in the global
user.email to require each repository to override that. On one machine, my
password file doesn't have my name in it, and I kind of get this behavior
by default, but it be nice to be able to do it for real.
Anyone have ideas on how this could be done?
Dave
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature? [resend]
2008-01-02 21:24 ` Linus Torvalds
2008-01-02 22:06 ` Stephen Sinclair
@ 2008-01-03 5:52 ` Sam Vilain
2008-01-04 18:34 ` Linus Torvalds
1 sibling, 1 reply; 9+ messages in thread
From: Sam Vilain @ 2008-01-03 5:52 UTC (permalink / raw)
To: Junio Hamano; +Cc: git
Linus Torvalds wrote:
> (I don't think git-filter-branch even exposes any easy way to remap the
> "revert commit xyz" messages in the message format. It's not technically
> hard to use a --msg-filter for it, but it seems a big bother).
Assuming, of course, that the commit you refer to in a message like that
is in your history. If it's referring to another commit in a different
branch, which may be being re-written, you've got two problems:
1. rewriting the commit
2. making sure that git-filter-branch processes the two commits in the
right order.
The first is easily fixable; the second requires a hook in
git-filter-branch to customize the tournament.
Subject: [PATCH] git-filter-branch: allow a custom tournament for rewrite ordering
The topological sort by git rev-list may be inconvenient for history
modification where commit IDs are used in comments to refer to other
changes. So, allow for a program that can take a list of commits, and
return that list in the order that the rewriter must follow. Borrow
"Tournament" term from Graph Theory.
Signed-off-by: Sam Vilain <sam.vilain@catalyst.net.nz>
---
Documentation/git-filter-branch.txt | 18 ++++
contrib/filter-branch/msg-links.perl | 50 +++++++++
contrib/filter-branch/tournament-links.perl | 148 +++++++++++++++++++++++++++
git-filter-branch.sh | 11 ++
t/t7003-filter-branch.sh | 21 ++++
5 files changed, 248 insertions(+), 0 deletions(-)
create mode 100755 contrib/filter-branch/msg-links.perl
create mode 100755 contrib/filter-branch/tournament-links.perl
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 895d750..ed3a839 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -118,6 +118,24 @@ convenience functions, too. For example, calling 'skip_commit "$@"'
will leave out the current commit (but not its changes! If you want
that, use gitlink:git-rebase[1] instead).
+--tournament <command>::
+ This command is responsible for re-ordering the commit history
+ after it is retrieved from the input list. It is passed on
+ standard input the deduced list based upon a regular
+ topological search, and the command is expected to print to
+ standard output a list in the same form.
++
+Again, this can't be used to re-order patches like
+gitlink:git-rebase[1] does, as the tree IDs of the original positions
+will remain untouched, so the differences between revisions will be
+scrambled.
++
+However, it is required when you need to refer to a commit by ID in a
+commit message, where the commit you are referring to is on an
+unrelated branch. See the contributed filters in the Git distribution
+for an example script that can let you preserve such referential
+integrity during a rewrite.
+
--tag-name-filter <command>::
This is the filter for rewriting tag names. When passed,
it will be called for every tag ref that points to a rewritten
diff --git a/contrib/filter-branch/msg-links.perl b/contrib/filter-branch/msg-links.perl
new file mode 100755
index 0000000..1ff780c
--- /dev/null
+++ b/contrib/filter-branch/msg-links.perl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl -nl
+#
+# msg-links.perl
+#
+# This is the companion script to tournament-links.perl, it is
+# configured in the same way. If you want this script, you will
+# probably also want the other one.
+#
+# What it does is rewrites all commit IDs of at least 12 digits long
+# to the post-rewritten version. Note that this works only for
+# commits seen by the current git-filter-branch run! If you need to
+# correct "dead" links from a previous run, then supply the rewrite
+# file.
+#
+# You don't need the tournament filter if all of the commits IDs you
+# are changing to are "ancient" history, or if you are rewriting
+# history that is a straight line.
+
+no strict;
+no warnings;
+
+use constant REV_MIN_LENGTH => $ENV{MSG_LINK_MIN} || 12;
+
+BEGIN {
+ $mlr = "$ENV{GITDIR}/msg-link-rewrite";
+ if ( -e $mlr ) {
+ open FH, "<", $mlr or die $!;
+ local($/);
+ %remap = m{([0-9a-f]{40})}g while <FH>;
+ }
+ ( -d "../map" ) or die "can't see the git-filter-branch map dir";
+}
+
+my $old = $_;
+s{([0-9a-f]{${\(REV_MIN_LENGTH)},40})}{substr(($remap{$1}?do {
+ print STDERR " Remapped: $1 => $remap{$1} (rule)\n";
+ $remap{$1}; }
+ : $1), 0, length($1))}eg;
+
+s{([0-9a-f]{${\(REV_MIN_LENGTH)},40})}{substr((-e "../map/$1" ? do {
+ $x = `cat ../map/$1`; chomp($x);
+ print STDERR " Remapped: $1 => $x (ripple)\n";
+ $x}
+: $1),0,length($1))}eg;
+
+if ( $old ne $_ ) {
+ print STDERR "*** filtered: pre: \n$old\n post:\n$_\n";
+}
+
+print;
diff --git a/contrib/filter-branch/tournament-links.perl b/contrib/filter-branch/tournament-links.perl
new file mode 100755
index 0000000..479a28f
--- /dev/null
+++ b/contrib/filter-branch/tournament-links.perl
@@ -0,0 +1,148 @@
+#!/usr/bin/perl
+#
+# tournament-links.perl: a tournament that allows simple re-ordering.
+#
+# This provides the requirement of getting the commits in the right
+# order if there are any (full length) commitids in the commit
+# messages. It also provides for some remapping along the way (if,
+# say, a referenced commit ID was wrong). To do that, put it in a
+# file in GIT_DIR called "msg-link-rewrite".
+#
+# The format of msg-link-rewrite is very simple - any full-length
+# SHA1s that are seen in the file are put into a single hash. So,
+# every other item is a key, starting with the first. Everything
+# else in the file is ignored. This is combined with the remapping
+# that the current git-filter-branch run has performed.
+#
+# This script is only called once, at the beginning of the run, and
+# can be relatively expensive on this basis. This one is practically
+# guaranteed to feed quicksort it's worst nightmare every time.
+#
+# Example:
+# $ cat > .git/msg-link-rewrite <<EOF
+# Rewrite the commit ID 123456789012 to
+# '92712632981923'
+# EOF
+# $ path=$ENV{HOME}/src/git/contrib/filter-branch
+# $ git-filter-branch --tournament $path/tournament.perl \
+# --msg-filter $path/msg-links.perl
+#
+
+no strict;
+no warnings;
+# use sort '_mergesort'; # Perl 5.10+ - use a mergesort instead
+
+use constant WATCH_BATTLE => $ENV{WATCH_BATTLE};
+use constant TOURNAMENT_RESULTS => $ENV{TOURNAMENT_RESULTS};
+use constant REV_MIN_LENGTH => $ENV{MSG_LINK_MIN} || 12;
+
+BEGIN {
+ $mlr = "$ENV{GITDIR}/msg-link-rewrite";
+ if ( -e $mlr ) {
+ open FH, "<", $mlr or die $!;
+ local($/);
+ %remap = m{([0-9a-f]{${\(REV_MIN_LENGTH)},40})}g while <FH>;
+ }
+ ( -d "../map" ) or die "can't see the git-filter-branch map dir";
+}
+
+@commits = <>;
+%refers;
+
+# shorten a commit ID to something human-readable for display to
+# STDERR only
+sub n{
+ my $commitid = shift;
+ substr($commitid, 0, 12);
+}
+
+print STDERR "tournament: read ".@commits." commit IDs\n"
+ if TOURNAMENT_RESULTS;
+
+for my $line ( @commits ) {
+ chomp($line);
+ my ($commit, @parents) = split " ", $line;
+ my @refers_commitids;
+ open COMMIT, "-|", qw(git cat-file commit), $commit;
+ while ( <COMMIT> ) {
+ push @refers_commitids, $1 if m{^parent (.*)$};
+ last if m{^\s*$};
+ }
+
+ my $msg = join "", <COMMIT>;
+
+ my @refers_commitids = map {
+ my ($match) = $remap{$_} ? ($remap{$_})
+ : map { $remap{$_} } grep m{^$_}, keys %remap;
+ if ( $match ) {
+ print STDERR "msg-link in ".n($commit).": "
+ .n($_)." treated as ".n($match)."\n"
+ if WATCH_BATTLE;
+ $match;
+ }
+ elsif ( do { $match = `git rev-parse $_`; !$? } ) {
+ chomp($match);
+ print STDERR "msg-link seen in ".n($commit)
+ ." to ".n($match)."\n"
+ if WATCH_BATTLE;
+ $match;
+ }
+ else {
+ print STDERR "dead msg-link seen in ".n($commit)
+ ." to ".n($_)."\n";
+ $_;
+ }
+ } ($msg =~ m{([0-9a-f]{${\(REV_MIN_LENGTH)},40})}g);
+
+ warn("$commit is not an extant revision\n"), next if $?;
+
+ $refers{$commit} = { map { $_ => 1 } @refers_commitids, @parents };
+}
+print STDERR "tournament: read ".@commits." commits\n"
+ if TOURNAMENT_RESULTS;
+
+my $O;
+
+# returns 1 if source refers to target, or target is a parent of
+# anything referred to by source.
+my $refers = sub {
+ my $source = shift;
+ my $target = shift;
+ my @todo = keys %{ $refers{$source}||{} };
+ my %seen = map { $_ => 1 } @todo;
+ while ( my $commit = shift @todo ) {
+ $O++;
+ do {
+ print STDERR n($source)." refers to ".n($target)."\n"
+ if WATCH_BATTLE;
+ return 1;
+ } if $commit eq $target;
+ push @todo, grep { $O++; !$seen{$_}++ }
+ keys %{ $refers{$commit} || {} };
+ }
+ print STDERR n($source)." does not refer to ".n($target)."\n"
+ if WATCH_BATTLE;
+ return 0;
+};
+
+# It's tournament time!
+print "$_\n" for sort {
+ (my $_a = $a) =~ s{ .*}{};
+ (my $_b = $b) =~ s{ .*}{};
+ my $cmp_val = 0;
+ if ( $refers->($_a, $_b) ) {
+ ++$cmp_val;
+ }
+ elsif ( $refers->($_b, $_a) ) {
+ --$cmp_val;
+ }
+ print STDERR n($a)." ".
+ (($cmp_val == 0 ? "EQUIVALENT TO" :
+ $cmp_val == -1 ? "COMES BEFORE" :
+ $cmp_val == 1 ? "COMES AFTER" : "TSNH")
+ ." ".n($b)."\n")
+ if WATCH_BATTLE;
+ $cmp_val;
+} @commits;
+
+print STDERR "tournament-links.perl: O(".@commits.") = ".$O."\n";
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index ae29f47..6c099ea 100755
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -110,6 +110,7 @@ filter_msg=cat
filter_commit='git commit-tree "$@"'
filter_tag_name=
filter_subdir=
+tournament=
orig_namespace=refs/original/
force=
while :
@@ -166,6 +167,9 @@ do
--subdirectory-filter)
filter_subdir="$OPTARG"
;;
+ --tournament)
+ tournament="$OPTARG"
+ ;;
--original)
orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/
;;
@@ -254,6 +258,13 @@ commits=$(wc -l <../revs | tr -d " ")
test $commits -eq 0 && die "Found nothing to rewrite"
+if [ -n "$tournament" ]
+then
+ cat ../revs | (eval "$tournament") > ../revs.sorted
+ mv ../revs ../revs.pre-sorted
+ mv ../revs.sorted ../revs
+fi
+
# Rewrite the commits
i=0
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index 5f60b22..8d5679d 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -165,4 +165,25 @@ test_expect_success '"map" works in commit filter' '
git rev-parse --verify master
'
+test_expect_success "Specifying a custom tournament" '
+ git checkout -b custom-tournament &&
+ echo "Hello">&2
+ echo j > j &&
+ git add j &&
+ echo "There">&2
+ git commit -m j j &&
+ echo z > z &&
+ git add z &&
+ echo "Dude">&2
+ git commit -m z &&
+ echo x > x &&
+ git add x &&
+ echo "Dude">&2
+ git commit -m x &&
+ git-filter-branch -f --parent-filter cat --tournament "cat > foo; fp=\$(head -1 foo | awk \"{print \\\$2}\"); ( head -2 foo | tac; tail -1 foo ) | awk \"{print \\\$1}\" | while read x y; do echo \$x \$fp; fp=\$x; done" master..HEAD &&
+ order=$(git-log --pretty=format:"%s" master...custom-tournament | xargs) &&
+ echo "order is <$order>" &&
+ test "$order" = "x j z"
+'
+
test_done
--
1.5.3.5
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature? [resend]
2008-01-03 5:52 ` Retroactively change email signature? [resend] Sam Vilain
@ 2008-01-04 18:34 ` Linus Torvalds
2008-01-04 23:04 ` Sam Vilain
0 siblings, 1 reply; 9+ messages in thread
From: Linus Torvalds @ 2008-01-04 18:34 UTC (permalink / raw)
To: Sam Vilain; +Cc: Junio Hamano, git
On Thu, 3 Jan 2008, Sam Vilain wrote:
>
> Assuming, of course, that the commit you refer to in a message like that
> is in your history. If it's referring to another commit in a different
> branch, which may be being re-written, you've got two problems:
I don't care. If some commit refers to another commit that isn't its
ancestor, then that is undefined *anyway*.
So the only case that really matters is when you refer to your own strict
ancestor.
This is one reason why it was so crazy that "git cherry-pick" used to have
"-x" by default - appending the original SHA1 (which is generally *not* an
ancestor) is meaningless and stupid.
But in the case of "git revert", it should be an ancestor (or the _user_
is just insane, in which case it doesn't matter - insane people can do
insane things)
Linus
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature? [resend]
2008-01-04 18:34 ` Linus Torvalds
@ 2008-01-04 23:04 ` Sam Vilain
2008-01-04 23:08 ` Sam Vilain
0 siblings, 1 reply; 9+ messages in thread
From: Sam Vilain @ 2008-01-04 23:04 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Junio Hamano, git
Linus Torvalds wrote:
> I don't care. If some commit refers to another commit that isn't its
> ancestor, then that is undefined *anyway*.
>
> So the only case that really matters is when you refer to your own strict
> ancestor.
>
> This is one reason why it was so crazy that "git cherry-pick" used to have
> "-x" by default - appending the original SHA1 (which is generally *not* an
> ancestor) is meaningless and stupid.
Not stupid at all. It gives you an easily clickable link to the
previous version of the patch, which may be of interest, and is
otherwise irretrievable information if the patch needed resolving.
Sam.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Retroactively change email signature? [resend]
2008-01-04 23:04 ` Sam Vilain
@ 2008-01-04 23:08 ` Sam Vilain
0 siblings, 0 replies; 9+ messages in thread
From: Sam Vilain @ 2008-01-04 23:08 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Junio Hamano, git
Sam Vilain wrote:
> Linus Torvalds wrote:
>> I don't care. If some commit refers to another commit that isn't its
>> ancestor, then that is undefined *anyway*.
>>
>> So the only case that really matters is when you refer to your own strict
>> ancestor.
>>
>> This is one reason why it was so crazy that "git cherry-pick" used to have
>> "-x" by default - appending the original SHA1 (which is generally *not* an
>> ancestor) is meaningless and stupid.
>
> Not stupid at all. It gives you an easily clickable link to the
> previous version of the patch, which may be of interest, and is
> otherwise irretrievable information if the patch needed resolving.
footnote: of course it is entirely meaningless if the referred SHA1 is
not published anywhere, so I agree with the cherry-pick default setting.
Sam.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-01-04 23:08 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-02 20:37 Retroactively change email signature? Stephen Sinclair
2008-01-02 21:17 ` Jakub Narebski
2008-01-02 21:24 ` Linus Torvalds
2008-01-02 22:06 ` Stephen Sinclair
2008-01-03 0:53 ` David Brown
2008-01-03 5:52 ` Retroactively change email signature? [resend] Sam Vilain
2008-01-04 18:34 ` Linus Torvalds
2008-01-04 23:04 ` Sam Vilain
2008-01-04 23:08 ` Sam Vilain
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).