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>
22 my $GIT_DIR = `git rev-parse --git-dir`;
23 exit 1 if $?; # rev-parse would have given "not a git dir" message.
26 our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
27 getopts("hnfkv") || usage;
31 my (@srcArgs, @dstArgs, @srcs, @dsts);
32 my ($src, $dst, $base, $dstDir);
34 my $argCount = scalar @ARGV;
35 if (-d $ARGV[$argCount-1]) {
36 $dstDir = $ARGV[$argCount-1];
37 # remove any trailing slash
39 @srcArgs = @ARGV[0..$argCount-2];
41 foreach $src (@srcArgs) {
44 $dst = "$dstDir/". $base;
50 print "Error: moving to directory '"
52 . "' not possible; not exisiting\n";
55 @srcArgs = ($ARGV[0]);
56 @dstArgs = ($ARGV[1]);
60 my (@allfiles,@srcfiles,@dstfiles);
62 my (%overwritten, %srcForDst);
65 open(F, 'git-ls-files -z |')
66 or die "Failed to open pipe from git-ls-files: " . $!;
68 @allfiles = map { chomp; $_; } <F>;
73 while(scalar @srcArgs > 0) {
74 $src = shift @srcArgs;
75 $dst = shift @dstArgs;
79 print "Checking rename of '$src' to '$dst'\n";
82 unless (-f $src || -l $src || -d $src) {
83 $bad = "bad source '$src'";
86 $safesrc = quotemeta($src);
87 @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
89 $overwritten{$dst} = 0;
90 if (($bad eq "") && -e $dst) {
91 $bad = "destination '$dst' already exists";
93 # only files can overwrite each other: check both source and destination
94 if (-f $dst && (scalar @srcfiles == 1)) {
95 print "Warning: $bad; will overwrite!\n";
97 $overwritten{$dst} = 1;
100 $bad = "Can not overwrite '$src' with '$dst'";
105 if (($bad eq "") && ($dst =~ /^$safesrc\//)) {
106 $bad = "can not move directory '$src' into itself";
110 if (scalar @srcfiles == 0) {
111 $bad = "'$src' not under version control";
116 if (defined $srcForDst{$dst}) {
117 $bad = "can not move '$src' to '$dst'; already target of ";
118 $bad .= "'".$srcForDst{$dst}."'";
121 $srcForDst{$dst} = $src;
127 print "Warning: $bad; skipping\n";
130 print "Error: $bad\n";
137 # Final pass: rename/move
138 my (@deletedfiles,@addedfiles,@changedfiles);
140 while(scalar @srcs > 0) {
144 if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
146 if (!rename($src,$dst)) {
147 $bad = "renaming '$src' failed: $!";
149 print "Warning: skipped: $bad\n";
157 $safesrc = quotemeta($src);
158 @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
159 @dstfiles = @srcfiles;
160 s/^$safesrc(\/|$)/$dst$1/ for @dstfiles;
162 push @deletedfiles, @srcfiles;
163 if (scalar @srcfiles == 1) {
164 # $dst can be a directory with 1 file inside
165 if ($overwritten{$dst} ==1) {
166 push @changedfiles, $dstfiles[0];
169 push @addedfiles, $dstfiles[0];
173 push @addedfiles, @dstfiles;
179 print "Changed : ". join(", ", @changedfiles) ."\n";
182 print "Adding : ". join(", ", @addedfiles) ."\n";
185 print "Deleting : ". join(", ", @deletedfiles) ."\n";
190 open(H, "| git-update-index -z --stdin")
191 or die "git-update-index failed to update changed files with code $!\n";
192 foreach my $fileName (@changedfiles) {
193 print H "$fileName\0";
198 open(H, "| git-update-index --add -z --stdin")
199 or die "git-update-index failed to add new names with code $!\n";
200 foreach my $fileName (@addedfiles) {
201 print H "$fileName\0";
206 open(H, "| git-update-index --remove -z --stdin")
207 or die "git-update-index failed to remove old names with code $!\n";
208 foreach my $fileName (@deletedfiles) {
209 print H "$fileName\0";
216 print "Error: $bad\n";