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> <dest>
17 $0 [-f] [-k] [-n] <source> ... <dest directory>
19 In the first form, source must exist and be either a file,
20 symlink or directory, dest must not exist. It renames source to dest.
21 In the second form, the last argument has to be an existing
22 directory; the given sources will be moved into this directory.
24 Updates the git cache to reflect the change.
25 Use "git commit" to make the change permanently.
28 -f Force renaming/moving, even if target exists
29 -k Continue on error by skipping
30 not-existing or not revision-controlled source
31 -n Do nothing; show what would happen
37 my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
39 unless ( -d
$GIT_DIR && -d
$GIT_DIR . "/objects" &&
40 -d
$GIT_DIR . "/objects/" && -d
$GIT_DIR . "/refs") {
41 print "Git repository not found.";
46 our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
47 getopts
("hnfkv") || usage
;
51 my (@srcArgs, @dstArgs, @srcs, @dsts);
52 my ($src, $dst, $base, $dstDir);
54 my $argCount = scalar @ARGV;
55 if (-d
$ARGV[$argCount-1]) {
56 $dstDir = $ARGV[$argCount-1];
57 # remove any trailing slash
59 @srcArgs = @ARGV[0..$argCount-2];
61 foreach $src (@srcArgs) {
64 $dst = "$dstDir/". $base;
70 print "Error: moving to directory '"
72 . "' not possible; not exisiting\n";
75 @srcArgs = ($ARGV[0]);
76 @dstArgs = ($ARGV[1]);
80 my (@allfiles,@srcfiles,@dstfiles);
82 my (%overwritten, %srcForDst);
85 open(F
,"-|","git-ls-files","-z")
86 or die "Failed to open pipe from git-ls-files: " . $!;
88 @allfiles = map { chomp; $_; } <F
>;
93 while(scalar @srcArgs > 0) {
94 $src = shift @srcArgs;
95 $dst = shift @dstArgs;
99 print "Checking rename of '$src' to '$dst'\n";
102 unless (-f
$src || -l
$src || -d
$src) {
103 $bad = "bad source '$src'";
106 $safesrc = quotemeta($src);
107 @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
109 $overwritten{$dst} = 0;
110 if (($bad eq "") && -e
$dst) {
111 $bad = "destination '$dst' already exists";
113 # only files can overwrite each other: check both source and destination
114 if (-f
$dst && (scalar @srcfiles == 1)) {
115 print "Warning: $bad; will overwrite!\n";
117 $overwritten{$dst} = 1;
120 $bad = "Can not overwrite '$src' with '$dst'";
125 if (($bad eq "") && ($src eq $dstDir)) {
126 $bad = "can not move directory '$src' into itself";
130 if (scalar @srcfiles == 0) {
131 $bad = "'$src' not under version control";
136 if (defined $srcForDst{$dst}) {
137 $bad = "can not move '$src' to '$dst'; already target of ";
138 $bad .= "'".$srcForDst{$dst}."'";
141 $srcForDst{$dst} = $src;
147 print "Warning: $bad; skipping\n";
150 print "Error: $bad\n";
157 # Final pass: rename/move
158 my (@deletedfiles,@addedfiles,@changedfiles);
159 while(scalar @srcs > 0) {
163 if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
166 or die "rename failed: $!";
169 $safesrc = quotemeta($src);
170 @srcfiles = grep /^$safesrc(\/|$)/, @allfiles;
171 @dstfiles = @srcfiles;
172 s/^$safesrc(\/|$)/$dst$1/ for @dstfiles;
174 push @deletedfiles, @srcfiles;
175 if (scalar @srcfiles == 1) {
176 # $dst can be a directory with 1 file inside
177 if ($overwritten{$dst} ==1) {
178 push @changedfiles, $dstfiles[0];
181 push @addedfiles, $dstfiles[0];
185 push @addedfiles, @dstfiles;
190 print "Changed : ". join(", ", @changedfiles) ."\n";
191 print "Adding : ". join(", ", @addedfiles) ."\n";
192 print "Deleting : ". join(", ", @deletedfiles) ."\n";
197 open(H
, "| git-update-index -z --stdin")
198 or die "git-update-index failed to update changed files with code $!\n";
199 foreach my $fileName (@changedfiles) {
200 print H
"$fileName\0";
205 open(H
, "| git-update-index --add -z --stdin")
206 or die "git-update-index failed to add new names with code $!\n";
207 foreach my $fileName (@addedfiles) {
208 print H
"$fileName\0";
213 open(H
, "| git-update-index --remove -z --stdin")
214 or die "git-update-index failed to remove old names with code $!\n";
215 foreach my $fileName (@deletedfiles) {
216 print H
"$fileName\0";