git-mv is not able to handle big directories
[git.git] / git-mv.perl
index 28bced9..b2eace5 100755 (executable)
@@ -54,6 +54,8 @@ my ($src, $dst, $base, $dstDir);
 my $argCount = scalar @ARGV;
 if (-d $ARGV[$argCount-1]) {
        $dstDir = $ARGV[$argCount-1];
+       # remove any trailing slash
+       $dstDir =~ s/\/$//;
        @srcArgs = @ARGV[0..$argCount-2];
        
        foreach $src (@srcArgs) {
@@ -77,7 +79,7 @@ else {
 
 my (@allfiles,@srcfiles,@dstfiles);
 my $safesrc;
-my %overwritten;
+my (%overwritten, %srcForDst);
 
 $/ = "\0";
 open(F,"-|","git-ls-files","-z")
@@ -101,13 +103,22 @@ while(scalar @srcArgs > 0) {
        $bad = "bad source '$src'";
     }
 
+    $safesrc = quotemeta($src);
+    @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
+
     $overwritten{$dst} = 0;
     if (($bad eq "") && -e $dst) {
        $bad = "destination '$dst' already exists";
-       if (-f $dst && $opt_f) {
-           print "Warning: $bad; will overwrite!\n";
-           $bad = "";
-           $overwritten{$dst} = 1;
+       if ($opt_f) {
+           # only files can overwrite each other: check both source and destination
+           if (-f $dst && (scalar @srcfiles == 1)) {
+               print "Warning: $bad; will overwrite!\n";
+               $bad = "";
+               $overwritten{$dst} = 1;
+           }
+           else {
+               $bad = "Can not overwrite '$src' with '$dst'";
+           }
        }
     }
     
@@ -116,13 +127,21 @@ while(scalar @srcArgs > 0) {
     }
 
     if ($bad eq "") {
-       $safesrc = quotemeta($src);
-       @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
         if (scalar @srcfiles == 0) {
            $bad = "'$src' not under version control";
        }
     }
 
+    if ($bad eq "") {
+       if (defined $srcForDst{$dst}) {
+           $bad = "can not move '$src' to '$dst'; already target of ";
+           $bad .= "'".$srcForDst{$dst}."'";
+       }
+       else {
+           $srcForDst{$dst} = $src;
+       }
+    }
+
     if ($bad ne "") {
        if ($opt_k) {
            print "Warning: $bad; skipping\n";
@@ -154,10 +173,12 @@ while(scalar @srcs > 0) {
 
     push @deletedfiles, @srcfiles;
     if (scalar @srcfiles == 1) {
+       # $dst can be a directory with 1 file inside
        if ($overwritten{$dst} ==1) {
-           push @changedfiles, $dst;
+           push @changedfiles, $dstfiles[0];
+
        } else {
-           push @addedfiles, $dst;
+           push @addedfiles, $dstfiles[0];
        }
     }
     else {
@@ -172,14 +193,27 @@ if ($opt_n) {
        exit(1);
 }
        
-my $rc;
-if (scalar @changedfiles >0) {
-       $rc = system("git-update-index","--",@changedfiles);
-       die "git-update-index failed to update changed files with code $?\n" if $rc;
+if (@changedfiles) {
+       open(H, "| git-update-index -z --stdin")
+               or die "git-update-index failed to update changed files with code $!\n";
+       foreach my $fileName (@changedfiles) {
+               print H "$fileName\0";
+       }
+       close(H);
 }
-if (scalar @addedfiles >0) {
-       $rc = system("git-update-index","--add","--",@addedfiles);
-       die "git-update-index failed to add new names with code $?\n" if $rc;
+if (@addedfiles) {
+       open(H, "| git-update-index --add -z --stdin")
+               or die "git-update-index failed to add new names with code $!\n";
+       foreach my $fileName (@addedfiles) {
+               print H "$fileName\0";
+       }
+       close(H);
+}
+if (@deletedfiles) {
+       open(H, "| git-update-index --remove -z --stdin")
+               or die "git-update-index failed to remove old names with code $!\n";
+       foreach my $fileName (@deletedfiles) {
+               print H "$fileName\0";
+       }
+       close(H);
 }
-$rc = system("git-update-index","--remove","--",@deletedfiles);
-die "git-update-index failed to remove old names with code $?\n" if $rc;