--- /dev/null
+git-mv(1)
+=========
+
+NAME
+----
+git-mv - Script used to move or rename a file, directory or symlink.
+
+
+SYNOPSIS
+--------
+'git-mv' [-f] [-n] <source> <destination>
+'git-mv' [-f] [-k] [-n] <source> ... <destination directory>
+
+DESCRIPTION
+-----------
+This script is used to move or rename a file, directory or symlink.
+In the first form, it renames <source>, which must exist and be either
+a file, symlink or directory, to <destination>, 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 <torvalds@osdl.org>
+Rewritten by Ryan Anderson <ryan@michonline.com>
+Move functionality added by Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
--- /dev/null
+#!/usr/bin/perl
+#
+# Copyright 2005, Ryan Anderson <ryan@michonline.com>
+# Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+#
+# 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 <<EOT;
+$0 [-f] [-n] <source> <dest>
+$0 [-f] [-k] [-n] <source> ... <dest directory>
+
+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; $_; } <F>;
+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;