From: Jeff King <peff@peff.net>
To: Steven Grimm <koreth@midwinter.com>
Cc: Avery Pennarun <apenwarr@gmail.com>,
Ittay Dror <ittayd@tikalk.com>,
git@vger.kernel.org
Subject: Re: detecting rename->commit->modify->commit
Date: Thu, 8 May 2008 14:17:24 -0400 [thread overview]
Message-ID: <20080508181723.GA30449@sigill.intra.peff.net> (raw)
In-Reply-To: <20080501231427.GD21731@sigill.intra.peff.net>
On Thu, May 01, 2008 at 07:14:27PM -0400, Jeff King wrote:
> 1. write a proof-of-concept that shows directory renaming after the
> fact (e.g., take a conflicted merge, scan the diff for directory
> renames, and then fix up the files). That way it is available, but
> doesn't impact git at all.
Here's a toy script that finds directory renames. I'm sure there are a
ton of corner cases it doesn't handle (like directory renames inside of
directory renames). My test case was the very trivial:
mkdir repo && cd repo && git init
mkdir subdir
for i in 1 2 3; do
echo content $i >subdir/file$i
done
git add subdir
git commit -m initial
git mv subdir new
git commit -m move
git checkout -b other HEAD^
echo content 4 >subdir/file4
git add subdir
git commit -m new
git merge --no-commit master
perl ../find-dir-rename.pl
git commit
At which point you should see the merged commit with new/file4.
Script is below.
-- >8 --
#!/usr/bin/perl
#
# Find renamed directories, and move any files in the "old"
# directory into the "new".
#
# usage:
# git merge --no-commit <whatever>
# find-dir-rename
# git commit
use strict;
foreach my $r (renamed_dirs()) {
move_dir_contents($r->{from}, $r->{to});
}
exit 0;
sub renamed_dirs {
my $base = `git merge-base HEAD MERGE_HEAD`;
chomp $base;
return grep {
$_->{score} == 1
} (renamed_dirs_between($base, 'HEAD'),
renamed_dirs_between($base, 'MERGE_HEAD'));
}
sub renamed_dirs_between {
my ($base, $commit) = @_;
my %sources;
foreach my $pair (renamed_files($base, $commit)) {
my $d1 = dir_of($pair->[0]);
my $d2 = dir_of($pair->[1]);
next unless defined($d1) && defined($d2);
$sources{$d1}->{total}++;
$sources{$d1}->{dests}->{$d2}++;
}
return map {
my $from = $_;
map {
{
from => $from,
to => $_,
score => $sources{$from}->{dests}->{$_} / $sources{$from}->{total},
}
} keys(%{$sources{$from}->{dests}});
} removed_directories($base, $commit);
}
sub dir_of {
local $_ = shift;
s{/[^/]+$}{} or return undef;
return $_;
}
sub renamed_files {
my ($from, $to) = @_;
open(my $fh, '-|', qw(git diff-tree -r -M), $from, $to)
or die "unable to open diff-tree: $!";
return map {
chomp;
m/ R\d+\t([^\t]+)\t(.*)/ ? [$1 => $2] : ()
} <$fh>;
}
sub removed_directories {
my ($base, $commit) = @_;
my %new_dirs = map { $_ => 1 } directories($commit);
return grep { !exists $new_dirs{$_} } directories($base);
}
sub directories {
my $commit = shift;
return uniq(
map {
s{/[^/]+$}{} ? $_ : ()
} files($commit)
);
}
sub files {
my $commit = shift;
open(my $fh, '-|', qw(git ls-tree -r), $commit)
or die "unable to open ls-tree: $!";
return map {
chomp;
s/^[^\t]*\t//;
$_
} <$fh>;
}
sub uniq {
my %seen;
return grep { !$seen{$_}++ } @_;
}
sub move_dir_contents {
my ($from, $to) = @_;
my @files = glob("$from/*");
return unless @files;
system(qw(git mv), @files, "$to/")
and die "unable to move $from/* to $to";
rmdir($from); # ignore error since there may be untracked files
}
next prev parent reply other threads:[~2008-05-08 18:18 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-01 14:10 detecting rename->commit->modify->commit Ittay Dror
2008-05-01 14:45 ` Jeff King
2008-05-01 15:08 ` Ittay Dror
2008-05-01 15:20 ` Jeff King
2008-05-01 15:30 ` Ittay Dror
2008-05-01 15:38 ` Jeff King
2008-05-01 15:47 ` Jakub Narebski
2008-05-01 20:39 ` Teemu Likonen
2008-05-01 23:09 ` Jeff King
2008-05-02 2:06 ` Sitaram Chamarty
2008-05-02 2:38 ` Junio C Hamano
2008-05-02 16:59 ` Sitaram Chamarty
2008-05-01 15:24 ` Ittay Dror
2008-05-01 15:28 ` Jeff King
2008-05-01 14:54 ` Ittay Dror
2008-05-01 15:09 ` Jeff King
2008-05-01 15:20 ` Ittay Dror
2008-05-01 15:30 ` David Tweed
2008-05-01 15:27 ` Avery Pennarun
2008-05-01 15:34 ` Jeff King
2008-05-01 15:50 ` Avery Pennarun
2008-05-01 16:48 ` Jeff King
2008-05-01 19:45 ` Avery Pennarun
2008-05-01 22:42 ` Jeff King
2008-05-01 19:12 ` Steven Grimm
2008-05-01 23:14 ` Jeff King
2008-05-03 17:56 ` merge renamed files/directories? (was: Re: detecting rename->commit->modify->commit) Ittay Dror
2008-05-03 18:11 ` Avery Pennarun
2008-05-04 6:08 ` merge renamed files/directories? Ittay Dror
2008-05-04 9:34 ` Jakub Narebski
2008-05-05 16:40 ` Avery Pennarun
2008-05-05 21:49 ` Robin Rosenberg
2008-05-05 22:20 ` Linus Torvalds
2008-05-05 23:07 ` Steven Grimm
2008-05-06 0:29 ` Linus Torvalds
2008-05-06 0:40 ` Linus Torvalds
2008-05-06 15:47 ` Theodore Tso
2008-05-06 16:10 ` Linus Torvalds
2008-05-06 16:15 ` Linus Torvalds
2008-05-06 16:32 ` Ittay Dror
2008-05-06 16:39 ` Linus Torvalds
2008-05-06 1:38 ` Avery Pennarun
2008-05-06 1:46 ` Shawn O. Pearce
2008-05-06 1:58 ` Avery Pennarun
2008-05-06 2:12 ` Shawn O. Pearce
2008-05-06 2:19 ` Linus Torvalds
2008-05-08 18:17 ` Jeff King [this message]
2008-05-01 16:39 ` detecting rename->commit->modify->commit Sitaram Chamarty
2008-05-01 18:58 ` Ittay Dror
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=20080508181723.GA30449@sigill.intra.peff.net \
--to=peff@peff.net \
--cc=apenwarr@gmail.com \
--cc=git@vger.kernel.org \
--cc=ittayd@tikalk.com \
--cc=koreth@midwinter.com \
/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 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).