Commit 061b0df5 authored by Robert Ricci's avatar Robert Ricci
Browse files

New script to re-write history of git moves

This script is intended for use with 'git filter-branch' - it takes
a directory, finds all files that have been moved into that directory
and where they came from, and produces a script that moves (in the
filesystem sense, not the git sense) them from their old locations
to their new ones.

Then, you give this script to 'git filter-branch --tree-filter', and
it will re-write all history so that it looks like the files were
always in their new locations.

Written specifically for the move of the clientside stuff into its
own directory, and then off into its own repository.
parent 69002f5a
#!/usr/bin/perl -w
# Copyright (c) 2011 University of Utah and the Flux Group.
# All rights reserved.
# Generate a script that moves all files in a given directory from any old
# locations they may have been in into their current locations. For use with
# git filter-branch --tree-filter - the idea is that you use this script on
# a directrory that has had files moved into it, and it generates a script for
# you that re-does the moves. You then pass the generated script to
# --tree-filter, which will make the move happen in all of history, so that you
# can pretend the files were always in their current locations.
# eg.
# git-rewritemoves clientside > ~/mvscript
# git filter-branch --tree-filter 'perl ~/mvscript' HEAD
use strict;
sub get_filemoves($);
if (@ARGV != 1) {
die "Usage: $0 <dirname>\n";
my ($dirname) = @ARGV;
my @moves;
my @files = `find $dirname -type f`;
my $count = 0;
foreach my $file (@files) {
chomp $file;
print STDERR "Checking file $file ($count / " . scalar(@files) . ")\n";
my @filemoves = get_filemoves($file);
push @moves, @filemoves;
# Now, output a perl script that executes the moves
print << 'HEADER';
#!/usr/bin/perl -w
my $errors = 0;
sub move($$) {
my ($src,$dst) = @_;
my $destdir = `dirname $dst`;
chomp $destdir;
if (!-d $destdir) {
system("mkdir -p $destdir") && $errors++;
system("mv $src $dst") && $errors++;
foreach my $move (@moves) {
my ($src, $dst) = @$move;
print "if (-e \"$src\") { move(\"$src\",\"$dst\"); }\n";
print << 'FOOTER';
exit ($errors != 0);
# Get a list of moves from old locations for the given file to
# the current location. Return this as a list of array refs, each
# of which is pair of filenames
sub get_filemoves($) {
my ($file) = @_;
# Use git log to find all filenames the file has had in the past
my @log_output = `git log --name-only --pretty="format:" --follow $file`;
# Remove blank lines
@log_output = grep {$_} @log_output;
my @moves;
# We always move files to their current location, not intermediate ones
my $current_loc = shift @log_output;
my $next_loc = $current_loc;
foreach my $loc (@log_output) {
if ($loc ne $next_loc) {
# A move happened
push @moves, [$loc,$current_loc];
print STDERR " Move: $loc -> $current_loc\n";
$next_loc = $loc;
return @moves;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment