3 # Copyright 2005, Ryan Anderson <ryan@michonline.com>
4 # Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
6 # This file is licensed under the GPL v2, or a later version
7 # at the discretion of Linus Torvalds.
16 $0 [-f] [-n] <source> <destination>
17 $0 [-f] [-n] [-k] <source> ... <destination directory>
23 my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
25 unless ( -d
$GIT_DIR && -d
$GIT_DIR . "/objects" &&
26 -d
$GIT_DIR . "/objects/" && -d
$GIT_DIR . "/refs") {
27 print "Error: git repository not found.";
32 our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
33 getopts
("hnfkv") || usage
;
37 my (@srcArgs, @dstArgs, @srcs, @dsts);
38 my ($src, $dst, $base, $dstDir);
40 my $argCount = scalar @ARGV;
41 if (-d
$ARGV[$argCount-1]) {
42 $dstDir = $ARGV[$argCount-1];
43 # remove any trailing slash
45 @srcArgs = @ARGV[0..$argCount-2];
47 foreach $src (@srcArgs) {
50 $dst = "$dstDir/". $base;
56 print "Error: moving to directory '"
58 . "' not possible; not exisiting\n";
61 @srcArgs = ($ARGV[0]);
62 @dstArgs = ($ARGV[1]);
66 my (@allfiles,@srcfiles,@dstfiles);
68 my (%overwritten, %srcForDst);
71 open(F
,"-|","git-ls-files","-z")
72 or die "Failed to open pipe from git-ls-files: " . $!;
74 @allfiles = map { chomp; $_; } <F
>;
79 while(scalar @srcArgs > 0) {
80 $src = shift @srcArgs;
81 $dst = shift @dstArgs;
85 print "Checking rename of '$src' to '$dst'\n";
88 unless (-f
$src || -l
$src || -d
$src) {
89 $bad = "bad source '$src'";
92 $safesrc = quotemeta($src);
93 @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
95 $overwritten{$dst} = 0;
96 if (($bad eq "") && -e
$dst) {
97 $bad = "destination '$dst' already exists";
99 # only files can overwrite each other: check both source and destination
100 if (-f
$dst && (scalar @srcfiles == 1)) {
101 print "Warning: $bad; will overwrite!\n";
103 $overwritten{$dst} = 1;
106 $bad = "Can not overwrite '$src' with '$dst'";
111 if (($bad eq "") && ($src eq $dstDir)) {
112 $bad = "can not move directory '$src' into itself";
116 if (scalar @srcfiles == 0) {
117 $bad = "'$src' not under version control";
122 if (defined $srcForDst{$dst}) {
123 $bad = "can not move '$src' to '$dst'; already target of ";
124 $bad .= "'".$srcForDst{$dst}."'";
127 $srcForDst{$dst} = $src;
133 print "Warning: $bad; skipping\n";
136 print "Error: $bad\n";
143 # Final pass: rename/move
144 my (@deletedfiles,@addedfiles,@changedfiles);
146 while(scalar @srcs > 0) {
150 if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
152 if (!rename($src,$dst)) {
153 $bad = "renaming '$src' failed: $!";
158 $safesrc = quotemeta($src);
159 @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
160 @dstfiles = @srcfiles;
161 s/^$safesrc(\/|$)/$dst$1/ for @dstfiles;
163 push @deletedfiles, @srcfiles;
164 if (scalar @srcfiles == 1) {
165 # $dst can be a directory with 1 file inside
166 if ($overwritten{$dst} ==1) {
167 push @changedfiles, $dstfiles[0];
170 push @addedfiles, $dstfiles[0];
174 push @addedfiles, @dstfiles;
180 print "Changed : ". join(", ", @changedfiles) ."\n";
183 print "Adding : ". join(", ", @addedfiles) ."\n";
186 print "Deleting : ". join(", ", @deletedfiles) ."\n";
191 open(H
, "| git-update-index -z --stdin")
192 or die "git-update-index failed to update changed files with code $!\n";
193 foreach my $fileName (@changedfiles) {
194 print H
"$fileName\0";
199 open(H
, "| git-update-index --add -z --stdin")
200 or die "git-update-index failed to add new names with code $!\n";
201 foreach my $fileName (@addedfiles) {
202 print H
"$fileName\0";
207 open(H
, "| git-update-index --remove -z --stdin")
208 or die "git-update-index failed to remove old names with code $!\n";
209 foreach my $fileName (@deletedfiles) {
210 print H
"$fileName\0";
217 print "Error: $bad\n";