From: Ryan Anderson <ryan@michonline.com>
To: Junio C Hamano <junkio@cox.net>, git@vger.kernel.org
Cc: Ryan Anderson <ryan@michonline.com>
Subject: [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree.
Date: Tue, 22 Nov 2005 15:50:50 -0500 [thread overview]
Message-ID: <11326926501602-git-send-email-ryan@michonline.com> (raw)
In-Reply-To:
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
next reply other threads:[~2005-11-22 20:50 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-11-22 20:50 Ryan Anderson [this message]
2005-11-23 0:55 ` [PATCH] Add git-graft-ripple, a tool for permanently grafting history into a tree 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11326926501602-git-send-email-ryan@michonline.com \
--to=ryan@michonline.com \
--cc=git@vger.kernel.org \
--cc=junkio@cox.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.