* [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
@ 2005-11-22 20:50 Ryan Anderson
2005-11-23 0:55 ` Linus Torvalds
0 siblings, 1 reply; 7+ messages in thread
From: Ryan Anderson @ 2005-11-22 20:50 UTC (permalink / raw)
To: Junio C Hamano, git; +Cc: Ryan Anderson
Enhancements over the original example:
o Each newly created commit A' references A, and (A^1)' (The first try
referenced A^1 and (A^1)' but not A)
o Support for incrementally rewriting history is present.
Signed-off-by: Ryan Anderson <ryan@michonline.com>
---
Documentation/git-graft-ripple | 57 +++++++++++++++++
Makefile | 3 +
git-graft-ripple.perl | 137 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 196 insertions(+), 1 deletions(-)
create mode 100644 Documentation/git-graft-ripple
create mode 100755 git-graft-ripple.perl
applies-to: 92551f12af8cd77f821d066a53c4dd301d1b41f5
9bfbdd948e6c0c9a8f0383b355e5cbbb42e0a772
diff --git a/Documentation/git-graft-ripple b/Documentation/git-graft-ripple
new file mode 100644
index 0000000..2fa38cb
--- /dev/null
+++ b/Documentation/git-graft-ripple
@@ -0,0 +1,57 @@
+git-graft-ripple(1)
+===============
+
+NAME
+----
+git-graft-ripple - Rewrite history with an additional commitish as a parent.
+
+
+SYNOPSIS
+--------
+'git-log <git repository> <branch committish> <graft SHA1> [start commitish]'
+
+DESCRIPTION
+-----------
+
+git-graft-ripple rewrites a series of commit objects by adding a new parent to
+the most ancestral commit, and passing the changed history back up through the
+revision history.
+
+Proceeding in reverse merge order a new commit is created using the following
+algorithim:
+
+ If this is the first commit reached, append the graft object name to
+ the parents.
+
+ Replace each parent object name with the object name generated by this
+ algorithm earlier.
+
+ Add the original object name to the parents.
+
+If a start commitish is given, the output of git-rev-list is restricted using
+it. This allows for incremental grafting to occur.
+
+Note: No branches are modified by this operation.
+
+Files
+-----
+
+GIT_DIR/info/ripple-status contains a mapping between the original object name
+and the object name generated by this algorithm. When doing incremental
+grafting, this file is necessary to continue to rename objects. If this is not
+present, git-graft-ripple will leave the old object name in the list of
+parents, which should still allow most merges to occur cleanly.
+
+
+Author
+------
+Written by Ryan Anderson <ryan@michonline.com>
+
+Documentation
+--------------
+Documentation by Ryan Anderson.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Makefile b/Makefile
index 1109dc6..984be32 100644
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,8 @@ SCRIPT_SH = \
SCRIPT_PERL = \
git-archimport.perl git-cvsimport.perl git-relink.perl \
git-shortlog.perl git-fmt-merge-msg.perl \
- git-svnimport.perl git-mv.perl git-cvsexportcommit.perl
+ git-svnimport.perl git-mv.perl git-cvsexportcommit.perl \
+ git-graft-ripple.perl
SCRIPT_PYTHON = \
git-merge-recursive.py
diff --git a/git-graft-ripple.perl b/git-graft-ripple.perl
new file mode 100755
index 0000000..b8ec990
--- /dev/null
+++ b/git-graft-ripple.perl
@@ -0,0 +1,137 @@
+#!/usr/bin/perl
+# Copyright 2005 Ryan Anderson <ryan@michonline.com>
+#
+# GPL v2 (See COPYING)
+#
+# This file is licensed under the GPL v2, or a later version
+# at the discretion of Linus Torvalds.
+
+use strict;
+use warnings;
+
+use IPC::Open2;
+
+sub git_commit_tree {
+ my ($tree,$comments,@parents) = @_;
+
+ my @cparents;
+ foreach my $p (@parents) {
+ push @cparents,"-p",$p;
+ }
+
+ my $pid = open2(*Reader, *Writer,
+ "git-commit-tree",$tree,@cparents);
+ print Writer $comments;
+ close(Writer);
+ my $commit = <Reader>;
+
+ waitpid $pid, 0;
+ close(Reader);
+
+ chomp $commit;
+
+ return $commit;
+}
+
+my ($gittree,$branch,$graft,$start) = @ARGV;
+chdir($gittree)
+ or die sprintf("Failed to chdir to '%s': %s\n", $ARGV[0], $!);
+
+my $range = defined $start ? sprintf("%s..%s",$start,$branch) : $branch;
+
+#printf("Running git-rev-list --parents --merge-order %s\n",$range);
+open(GRL,"-|","git-rev-list","--parents", "--merge-order", $range)
+ or die "Failed to run git-rev-list: " . $!;
+
+my %csets;
+my @revs;
+while(<GRL>) {
+ chomp;
+ my ($commit,@parents) = split;
+ $csets{$commit}{parents} = \@parents;
+ push @revs, $commit;
+# printf("Investigating %s\n", $commit);
+
+ open(GCF,"-|","git-cat-file","commit",$commit)
+ or die "Failed to open git-cat-file: " . $!;
+
+ my $in_comments = 0;
+ while(<GCF>) {
+ chomp;
+ if ($in_comments) {
+ $csets{$commit}{comments} .= $_ . "\n";
+
+ } elsif (m/^tree (.+)$/) {
+ $csets{$commit}{tree} = $1;
+ #printf("tree = %s\n",$1);
+
+ } elsif (m/^parent (.+)$/) {
+ # Do nothing, we already got
+ # the parents from rev-list.
+
+ } elsif (m/^(author|committer) (.*) <(.*)> (.*)$/) {
+ #printf("%s = %s <%s> at %s\n",$1, $2,$3,$4);
+ @{$csets{$commit}{$1}}{qw(name email datetime)}
+ = ($2,$3,$4);
+
+ } elsif (length == 0) {
+ $in_comments = 1;
+ $csets{$commit}{comments} = "";
+ next;
+ }
+ }
+ close(GCF);
+
+}
+close(GRL);
+
+@revs = reverse @revs;
+shift @revs if defined $start;
+push @{$csets{$revs[0]}{parents}},$graft;
+
+my %newcsets;
+if (-f ".git/info/ripple-status") {
+ open(RSTATUS,"<",".git/info/ripple-status")
+ or die "Failed to restore status from .git/info/ripple-status: " . $!;
+
+ while (<RSTATUS>) {
+ chomp;
+ my ($k,$newcset) = split;
+ $newcsets{$k} = $newcset;
+ }
+ close(RSTATUS);
+}
+
+
+foreach my $old (@revs) {
+ printf("\nProcessing commit %s\n",$old);
+ $ENV{GIT_AUTHOR_EMAIL} = $csets{$old}{author}{email};
+ $ENV{GIT_AUTHOR_NAME} = $csets{$old}{author}{name};
+ $ENV{GIT_AUTHOR_DATE} = $csets{$old}{author}{datetime};
+ $ENV{GIT_COMMITTER_DATE} = $csets{$old}{committer}{datetime};
+ $ENV{GIT_COMMITTER_EMAIL} = $csets{$old}{committer}{email};
+ $ENV{GIT_COMMITTER_NAME} = $csets{$old}{committer}{name};
+
+ my @parents = ($old);
+ foreach my $p (@{$csets{$old}{parents}}) {
+ if (exists $newcsets{$p}) {
+ push @parents, $newcsets{$p};
+ printf("\t%s => %s\n",
+ $newcsets{$p},$p);
+ } else {
+ push @parents, $p;
+ }
+ }
+ my $commit = git_commit_tree($csets{$old}{tree},
+ $csets{$old}{comments},@parents);
+ $newcsets{$old} = $commit;
+ printf("\tNew commit: %s\n",$newcsets{$old});
+}
+
+open(RSTATUS,">",".git/info/ripple-status")
+ or die "Failed to save status in .git/info/ripple-status: " . $!;
+
+foreach my $k (keys %newcsets) {
+ printf RSTATUS "%s\t%s\n", $k, $newcsets{$k};
+}
+close(RSTATUS);
---
0.99.9.GIT
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
2005-11-22 20:50 [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree Ryan Anderson
@ 2005-11-23 0:55 ` Linus Torvalds
2005-11-23 7:22 ` Andreas Ericsson
2005-11-23 13:51 ` Ryan Anderson
0 siblings, 2 replies; 7+ messages in thread
From: Linus Torvalds @ 2005-11-23 0:55 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Junio C Hamano, git
On Tue, 22 Nov 2005, Ryan Anderson wrote:
>
> Enhancements over the original example:
>
> o Each newly created commit A' references A, and (A^1)' (The first try
> referenced A^1 and (A^1)' but not A)
>
> o Support for incrementally rewriting history is present.
How about the case of having commits that have pointers to other commits
in the comments?
For example, on the kernel do
gitk 19842d67340e4a8f616552d344e97fc7452aa37a
and see how gitk highlights the SHA1's in the commit message and makes
hyperlinks to the commits they point to..
Linus
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
2005-11-23 0:55 ` Linus Torvalds
@ 2005-11-23 7:22 ` Andreas Ericsson
2005-11-23 13:51 ` Ryan Anderson
1 sibling, 0 replies; 7+ messages in thread
From: Andreas Ericsson @ 2005-11-23 7:22 UTC (permalink / raw)
To: git
Linus Torvalds wrote:
>
> On Tue, 22 Nov 2005, Ryan Anderson wrote:
>
>>Enhancements over the original example:
>>
>> o Each newly created commit A' references A, and (A^1)' (The first try
>> referenced A^1 and (A^1)' but not A)
>>
>> o Support for incrementally rewriting history is present.
>
>
> How about the case of having commits that have pointers to other commits
> in the comments?
>
> For example, on the kernel do
>
> gitk 19842d67340e4a8f616552d344e97fc7452aa37a
>
> and see how gitk highlights the SHA1's in the commit message and makes
> hyperlinks to the commits they point to..
>
For reference, gitweb does the same.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
2005-11-23 0:55 ` Linus Torvalds
2005-11-23 7:22 ` Andreas Ericsson
@ 2005-11-23 13:51 ` Ryan Anderson
2005-11-23 14:37 ` Randal L. Schwartz
` (2 more replies)
1 sibling, 3 replies; 7+ messages in thread
From: Ryan Anderson @ 2005-11-23 13:51 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Junio C Hamano, git
On Tue, Nov 22, 2005 at 04:55:04PM -0800, Linus Torvalds wrote:
> On Tue, 22 Nov 2005, Ryan Anderson wrote:
> >
> > Enhancements over the original example:
> >
> > o Each newly created commit A' references A, and (A^1)' (The first try
> > referenced A^1 and (A^1)' but not A)
> >
> > o Support for incrementally rewriting history is present.
>
> How about the case of having commits that have pointers to other commits
> in the comments?
>
> For example, on the kernel do
>
> gitk 19842d67340e4a8f616552d344e97fc7452aa37a
>
> and see how gitk highlights the SHA1's in the commit message and makes
> hyperlinks to the commits they point to..
For some reason, my gut says that this goes too far. I'm having a hard
time pinning down a way to explain that.
I guess something (untested) like this could do it, right before I call
git_commit_tree():
my $found;
do {
$found = 0;
if ($csets{$old}{comments} =~ /\s([a-f0-9]{40})\s/ &&
exists $newcsets{$1}) {
my $tcommit = $1;
$found = 1;
$csets{$old}{comments} =~ s/$tcommit/$newcsets{$tcommit}/g;
}
} while ($found);
I'm not entirely convinced this is a good idea, but there it is.
I'll write up a patch later for this (probably switching to GetOpt in
the process.)
--
Ryan Anderson
sometimes Pug Majere
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
2005-11-23 13:51 ` Ryan Anderson
@ 2005-11-23 14:37 ` Randal L. Schwartz
2005-11-23 15:40 ` Johannes Schindelin
2005-11-23 17:07 ` Linus Torvalds
2 siblings, 0 replies; 7+ messages in thread
From: Randal L. Schwartz @ 2005-11-23 14:37 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Linus Torvalds, Junio C Hamano, git
>>>>> "Ryan" == Ryan Anderson <ryan@michonline.com> writes:
Ryan> git_commit_tree():
Ryan> my $found;
Ryan> do {
Ryan> $found = 0;
Ryan> if ($csets{$old}{comments} =~ /\s([a-f0-9]{40})\s/ &&
Ryan> exists $newcsets{$1}) {
Ryan> my $tcommit = $1;
Ryan> $found = 1;
Ryan> $csets{$old}{comments} =~ s/$tcommit/$newcsets{$tcommit}/g;
Ryan> }
Ryan> } while ($found);
I hate artificial booleans. This is better written as:
{
last unless my ($tcommit) = $csets{$old}{comments} =~ /\s([a-f0-9]{40})\s/;
last unless exists $newcsets{$tcommit};
$csets{$old}{comments} =~ s/$tcommit/$newcsets{$tcommit}/g;
redo;
}
--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
2005-11-23 13:51 ` Ryan Anderson
2005-11-23 14:37 ` Randal L. Schwartz
@ 2005-11-23 15:40 ` Johannes Schindelin
2005-11-23 17:07 ` Linus Torvalds
2 siblings, 0 replies; 7+ messages in thread
From: Johannes Schindelin @ 2005-11-23 15:40 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Linus Torvalds, Junio C Hamano, git
Hi,
On Wed, 23 Nov 2005, Ryan Anderson wrote:
> For some reason, my gut says that this goes too far. I'm having a hard
> time pinning down a way to explain that.
I can pin down what my gut says:
- the old commits still exist, so the links are not invalid
- the commit message is signed off as is
- the process to find the correct new SHA1 is not straight-forward, i.e.
one would need to introduce a recursion where now suffices a simple
linear loop.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
2005-11-23 13:51 ` Ryan Anderson
2005-11-23 14:37 ` Randal L. Schwartz
2005-11-23 15:40 ` Johannes Schindelin
@ 2005-11-23 17:07 ` Linus Torvalds
2 siblings, 0 replies; 7+ messages in thread
From: Linus Torvalds @ 2005-11-23 17:07 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Junio C Hamano, git
On Wed, 23 Nov 2005, Ryan Anderson wrote:
>
> I'm not entirely convinced this is a good idea, but there it is.
Well, quite frankly, I think the whole graft-rippling is just wrong (why
do it? The grafts are fine, and after you've rippled, you'll never be able
to merge with somebody who didn't) but if you do it, I think you should
fix it up properly and have a resulting tree that is at least as good as
the original.
Linus
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2005-11-23 17:07 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-11-22 20:50 [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree Ryan Anderson
2005-11-23 0:55 ` Linus Torvalds
2005-11-23 7:22 ` Andreas Ericsson
2005-11-23 13:51 ` Ryan Anderson
2005-11-23 14:37 ` Randal L. Schwartz
2005-11-23 15:40 ` Johannes Schindelin
2005-11-23 17:07 ` Linus Torvalds
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).