login
Header Space

 
 

Re: detecting rename->commit->modify->commit

Score:
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
To: Steven Grimm <koreth@...>
Cc: Avery Pennarun <apenwarr@...>, Ittay Dror <ittayd@...>, <git@...>
Date: Thursday, May 8, 2008 - 2:17 pm

On Thu, May 01, 2008 at 07:14:27PM -0400, Jeff King wrote:


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
}
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
detecting rename-&gt;commit-&gt;modify-&gt;commit, Ittay Dror, (Thu May 1, 10:10 am)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Sitaram Chamarty, (Thu May 1, 12:39 pm)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Avery Pennarun, (Thu May 1, 11:27 am)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Steven Grimm, (Thu May 1, 3:12 pm)
Re: detecting rename->commit->modify->commit, Jeff King, (Thu May 8, 2:17 pm)
Re: merge renamed files/directories?, Ittay Dror, (Sun May 4, 2:08 am)
Re: merge renamed files/directories?, Avery Pennarun, (Mon May 5, 12:40 pm)
Re: merge renamed files/directories?, Robin Rosenberg, (Mon May 5, 5:49 pm)
Re: merge renamed files/directories?, Linus Torvalds, (Mon May 5, 6:20 pm)
Re: merge renamed files/directories?, Avery Pennarun, (Mon May 5, 9:38 pm)
Re: merge renamed files/directories?, Linus Torvalds, (Mon May 5, 10:19 pm)
Re: merge renamed files/directories?, Shawn O. Pearce, (Mon May 5, 9:46 pm)
Re: merge renamed files/directories?, Avery Pennarun, (Mon May 5, 9:58 pm)
Re: merge renamed files/directories?, Shawn O. Pearce, (Mon May 5, 10:12 pm)
Re: merge renamed files/directories?, Steven Grimm, (Mon May 5, 7:07 pm)
Re: merge renamed files/directories?, Linus Torvalds, (Mon May 5, 8:29 pm)
Re: merge renamed files/directories?, Theodore Tso, (Tue May 6, 11:47 am)
Re: merge renamed files/directories?, Linus Torvalds, (Tue May 6, 12:10 pm)
Re: merge renamed files/directories?, Ittay Dror, (Tue May 6, 12:32 pm)
Re: merge renamed files/directories?, Linus Torvalds, (Tue May 6, 12:39 pm)
Re: merge renamed files/directories?, Linus Torvalds, (Tue May 6, 12:15 pm)
Re: merge renamed files/directories?, Linus Torvalds, (Mon May 5, 8:40 pm)
Re: merge renamed files/directories?, Jakub Narebski, (Sun May 4, 5:34 am)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Avery Pennarun, (Thu May 1, 11:50 am)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Avery Pennarun, (Thu May 1, 3:45 pm)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, David Tweed, (Thu May 1, 11:30 am)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Teemu Likonen, (Thu May 1, 4:39 pm)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Sitaram Chamarty, (Thu May 1, 10:06 pm)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Junio C Hamano, (Thu May 1, 10:38 pm)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Sitaram Chamarty, (Fri May 2, 12:59 pm)
Re: detecting rename-&gt;commit-&gt;modify-&gt;commit, Jakub Narebski, (Thu May 1, 11:47 am)
speck-geostationary