diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt new file mode 100644 index 0000000000..f2d5882f48 --- /dev/null +++ b/Documentation/git-mv.txt @@ -0,0 +1,51 @@ +git-mv(1) +========= + +NAME +---- +git-mv - Script used to move or rename a file, directory or symlink. + + +SYNOPSIS +-------- +'git-mv' [-f] [-n] +'git-mv' [-f] [-k] [-n] ... + +DESCRIPTION +----------- +This script is used to move or rename a file, directory or symlink. +In the first form, it renames , which must exist and be either +a file, symlink or directory, to , which must not exist. +In the second form, the last argument has to be an existing +directory; the given sources will be moved into this directory. + +The index is updated after successful completion, but the change must still be +committed. + +OPTIONS +------- +-f:: + Force renaming or moving even targets exist +-k:: + Skip move or rename actions which would lead to an error + condition. An error happens when a source is neither existing nor + controlled by GIT, or when it would overwrite an existing + file unless '-f' is given. +-n:: + Do nothing; only show what would happen + + +Author +------ +Written by Linus Torvalds +Rewritten by Ryan Anderson +Move functionality added by Josef Weidendorfer + +Documentation +-------------- +Documentation by David Greaves, Junio C Hamano and the git-list . + +GIT +--- +Part of the gitlink:git[7] suite + diff --git a/Makefile b/Makefile index 7eacf61b3f..5bdf3cc8dd 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,7 @@ SCRIPT_SH = \ SCRIPT_PERL = \ git-archimport.perl git-cvsimport.perl git-relink.perl \ git-rename.perl git-shortlog.perl git-fmt-merge-msg.perl \ - git-findtags.perl git-svnimport.perl + git-findtags.perl git-svnimport.perl git-mv.perl SCRIPT_PYTHON = \ git-merge-recursive.py diff --git a/git-mv.perl b/git-mv.perl new file mode 100755 index 0000000000..28bced9595 --- /dev/null +++ b/git-mv.perl @@ -0,0 +1,185 @@ +#!/usr/bin/perl +# +# Copyright 2005, Ryan Anderson +# Josef Weidendorfer +# +# This file is licensed under the GPL v2, or a later version +# at the discretion of Linus Torvalds. + + +use warnings; +use strict; +use Getopt::Std; + +sub usage() { + print < +$0 [-f] [-k] [-n] ... + +In the first form, source must exist and be either a file, +symlink or directory, dest must not exist. It renames source to dest. +In the second form, the last argument has to be an existing +directory; the given sources will be moved into this directory. + +Updates the git cache to reflect the change. +Use "git commit" to make the change permanently. + +Options: + -f Force renaming/moving, even if target exists + -k Continue on error by skipping + not-existing or not revision-controlled source + -n Do nothing; show what would happen +EOT + exit(1); +} + +# Sanity checks: +my $GIT_DIR = $ENV{'GIT_DIR'} || ".git"; + +unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" && + -d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") { + print "Git repository not found."; + usage(); +} + + +our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v); +getopts("hnfkv") || usage; +usage() if $opt_h; +@ARGV >= 1 or usage; + +my (@srcArgs, @dstArgs, @srcs, @dsts); +my ($src, $dst, $base, $dstDir); + +my $argCount = scalar @ARGV; +if (-d $ARGV[$argCount-1]) { + $dstDir = $ARGV[$argCount-1]; + @srcArgs = @ARGV[0..$argCount-2]; + + foreach $src (@srcArgs) { + $base = $src; + $base =~ s/^.*\///; + $dst = "$dstDir/". $base; + push @dstArgs, $dst; + } +} +else { + if ($argCount != 2) { + print "Error: moving to directory '" + . $ARGV[$argCount-1] + . "' not possible; not exisiting\n"; + usage; + } + @srcArgs = ($ARGV[0]); + @dstArgs = ($ARGV[1]); + $dstDir = ""; +} + +my (@allfiles,@srcfiles,@dstfiles); +my $safesrc; +my %overwritten; + +$/ = "\0"; +open(F,"-|","git-ls-files","-z") + or die "Failed to open pipe from git-ls-files: " . $!; + +@allfiles = map { chomp; $_; } ; +close(F); + + +my ($i, $bad); +while(scalar @srcArgs > 0) { + $src = shift @srcArgs; + $dst = shift @dstArgs; + $bad = ""; + + if ($opt_v) { + print "Checking rename of '$src' to '$dst'\n"; + } + + unless (-f $src || -l $src || -d $src) { + $bad = "bad source '$src'"; + } + + $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 (($bad eq "") && ($src eq $dstDir)) { + $bad = "can not move directory '$src' into itself"; + } + + if ($bad eq "") { + $safesrc = quotemeta($src); + @srcfiles = grep /^$safesrc(\/|$)/, @allfiles; + if (scalar @srcfiles == 0) { + $bad = "'$src' not under version control"; + } + } + + if ($bad ne "") { + if ($opt_k) { + print "Warning: $bad; skipping\n"; + next; + } + print "Error: $bad\n"; + usage(); + } + push @srcs, $src; + push @dsts, $dst; +} + +# Final pass: rename/move +my (@deletedfiles,@addedfiles,@changedfiles); +while(scalar @srcs > 0) { + $src = shift @srcs; + $dst = shift @dsts; + + if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; } + if (!$opt_n) { + rename($src,$dst) + or die "rename failed: $!"; + } + + $safesrc = quotemeta($src); + @srcfiles = grep /^$safesrc(\/|$)/, @allfiles; + @dstfiles = @srcfiles; + s/^$safesrc(\/|$)/$dst$1/ for @dstfiles; + + push @deletedfiles, @srcfiles; + if (scalar @srcfiles == 1) { + if ($overwritten{$dst} ==1) { + push @changedfiles, $dst; + } else { + push @addedfiles, $dst; + } + } + else { + push @addedfiles, @dstfiles; + } +} + +if ($opt_n) { + print "Changed : ". join(", ", @changedfiles) ."\n"; + print "Adding : ". join(", ", @addedfiles) ."\n"; + print "Deleting : ". join(", ", @deletedfiles) ."\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 (scalar @addedfiles >0) { + $rc = system("git-update-index","--add","--",@addedfiles); + die "git-update-index failed to add new names with code $?\n" if $rc; +} +$rc = system("git-update-index","--remove","--",@deletedfiles); +die "git-update-index failed to remove old names with code $?\n" if $rc;