Browse Source
* js/read-tree: (107 commits) read-tree: move merge functions to the library read-trees: refactor the unpack_trees() part tar-tree: illustrate an obscure feature better git.c: allow alias expansion without a git directory setup_git_directory_gently: do not barf when GIT_DIR is given. Build on Debian GNU/kFreeBSD Call setup_git_directory() much earlier Call setup_git_directory() early Display an error from update-ref if target ref name is invalid. Fix http-fetch t4103: fix binary patch application test. git-apply -R: binary patches are irreversible for now. Teach git-apply about '-R' Makefile: ssh-pull.o depends on ssh-fetch.c log and diff family: honor config even from subdirectories git-reset: detect update-ref error and report it. lost-found: use fsck-objects --full Teach git-http-fetch the --stdin switch Teach git-local-fetch the --stdin switch Make pull() support fetching multiple targets at once ...maint
Junio C Hamano
19 years ago
103 changed files with 2902 additions and 1668 deletions
@ -0,0 +1,297 @@
@@ -0,0 +1,297 @@
|
||||
/* |
||||
* "git mv" builtin command |
||||
* |
||||
* Copyright (C) 2006 Johannes Schindelin |
||||
*/ |
||||
#include <fnmatch.h> |
||||
|
||||
#include "cache.h" |
||||
#include "builtin.h" |
||||
#include "dir.h" |
||||
#include "cache-tree.h" |
||||
#include "path-list.h" |
||||
|
||||
static const char builtin_mv_usage[] = |
||||
"git-mv [-n] [-f] (<source> <destination> | [-k] <source>... <destination>)"; |
||||
|
||||
static const char **copy_pathspec(const char *prefix, const char **pathspec, |
||||
int count, int base_name) |
||||
{ |
||||
const char **result = xmalloc((count + 1) * sizeof(const char *)); |
||||
memcpy(result, pathspec, count * sizeof(const char *)); |
||||
result[count] = NULL; |
||||
if (base_name) { |
||||
int i; |
||||
for (i = 0; i < count; i++) { |
||||
const char *last_slash = strrchr(result[i], '/'); |
||||
if (last_slash) |
||||
result[i] = last_slash + 1; |
||||
} |
||||
} |
||||
return get_pathspec(prefix, result); |
||||
} |
||||
|
||||
static void show_list(const char *label, struct path_list *list) |
||||
{ |
||||
if (list->nr > 0) { |
||||
int i; |
||||
printf("%s", label); |
||||
for (i = 0; i < list->nr; i++) |
||||
printf("%s%s", i > 0 ? ", " : "", list->items[i].path); |
||||
putchar('\n'); |
||||
} |
||||
} |
||||
|
||||
static const char *add_slash(const char *path) |
||||
{ |
||||
int len = strlen(path); |
||||
if (path[len - 1] != '/') { |
||||
char *with_slash = xmalloc(len + 2); |
||||
memcpy(with_slash, path, len); |
||||
strcat(with_slash + len, "/"); |
||||
return with_slash; |
||||
} |
||||
return path; |
||||
} |
||||
|
||||
static struct lock_file lock_file; |
||||
|
||||
int cmd_mv(int argc, const char **argv, const char *prefix) |
||||
{ |
||||
int i, newfd, count; |
||||
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; |
||||
const char **source, **destination, **dest_path; |
||||
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes; |
||||
struct stat st; |
||||
struct path_list overwritten = {NULL, 0, 0, 0}; |
||||
struct path_list src_for_dst = {NULL, 0, 0, 0}; |
||||
struct path_list added = {NULL, 0, 0, 0}; |
||||
struct path_list deleted = {NULL, 0, 0, 0}; |
||||
struct path_list changed = {NULL, 0, 0, 0}; |
||||
|
||||
git_config(git_default_config); |
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file()); |
||||
if (newfd < 0) |
||||
die("unable to create new index file"); |
||||
|
||||
if (read_cache() < 0) |
||||
die("index file corrupt"); |
||||
|
||||
for (i = 1; i < argc; i++) { |
||||
const char *arg = argv[i]; |
||||
|
||||
if (arg[0] != '-') |
||||
break; |
||||
if (!strcmp(arg, "--")) { |
||||
i++; |
||||
break; |
||||
} |
||||
if (!strcmp(arg, "-n")) { |
||||
show_only = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "-f")) { |
||||
force = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "-k")) { |
||||
ignore_errors = 1; |
||||
continue; |
||||
} |
||||
die(builtin_mv_usage); |
||||
} |
||||
count = argc - i - 1; |
||||
if (count < 1) |
||||
usage(builtin_mv_usage); |
||||
|
||||
source = copy_pathspec(prefix, argv + i, count, 0); |
||||
modes = xcalloc(count, sizeof(enum update_mode)); |
||||
dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0); |
||||
|
||||
if (!lstat(dest_path[0], &st) && |
||||
S_ISDIR(st.st_mode)) { |
||||
dest_path[0] = add_slash(dest_path[0]); |
||||
destination = copy_pathspec(dest_path[0], argv + i, count, 1); |
||||
} else { |
||||
if (count != 1) |
||||
usage(builtin_mv_usage); |
||||
destination = dest_path; |
||||
} |
||||
|
||||
/* Checking */ |
||||
for (i = 0; i < count; i++) { |
||||
const char *bad = NULL; |
||||
|
||||
if (show_only) |
||||
printf("Checking rename of '%s' to '%s'\n", |
||||
source[i], destination[i]); |
||||
|
||||
if (lstat(source[i], &st) < 0) |
||||
bad = "bad source"; |
||||
|
||||
if (S_ISDIR(st.st_mode)) { |
||||
const char *dir = source[i], *dest_dir = destination[i]; |
||||
int first, last, len = strlen(dir); |
||||
|
||||
if (lstat(dest_dir, &st) == 0) { |
||||
bad = "cannot move directory over file"; |
||||
goto next; |
||||
} |
||||
|
||||
modes[i] = WORKING_DIRECTORY; |
||||
|
||||
first = cache_name_pos(source[i], len); |
||||
if (first >= 0) |
||||
die ("Huh? %s/ is in index?", dir); |
||||
|
||||
first = -1 - first; |
||||
for (last = first; last < active_nr; last++) { |
||||
const char *path = active_cache[last]->name; |
||||
if (strncmp(path, dir, len) || path[len] != '/') |
||||
break; |
||||
} |
||||
|
||||
if (last - first < 1) |
||||
bad = "source directory is empty"; |
||||
else if (!bad) { |
||||
int j, dst_len = strlen(dest_dir); |
||||
|
||||
if (last - first > 0) { |
||||
source = realloc(source, |
||||
(count + last - first) |
||||
* sizeof(char *)); |
||||
destination = realloc(destination, |
||||
(count + last - first) |
||||
* sizeof(char *)); |
||||
modes = realloc(modes, |
||||
(count + last - first) |
||||
* sizeof(enum update_mode)); |
||||
} |
||||
|
||||
dest_dir = add_slash(dest_dir); |
||||
|
||||
for (j = 0; j < last - first; j++) { |
||||
const char *path = |
||||
active_cache[first + j]->name; |
||||
source[count + j] = path; |
||||
destination[count + j] = |
||||
prefix_path(dest_dir, dst_len, |
||||
path + len); |
||||
modes[count + j] = INDEX; |
||||
} |
||||
count += last - first; |
||||
} |
||||
|
||||
goto next; |
||||
} |
||||
|
||||
if (!bad && lstat(destination[i], &st) == 0) { |
||||
bad = "destination exists"; |
||||
if (force) { |
||||
/* |
||||
* only files can overwrite each other: |
||||
* check both source and destination |
||||
*/ |
||||
if (S_ISREG(st.st_mode)) { |
||||
fprintf(stderr, "Warning: %s;" |
||||
" will overwrite!\n", |
||||
bad); |
||||
bad = NULL; |
||||
path_list_insert(destination[i], |
||||
&overwritten); |
||||
} else |
||||
bad = "Cannot overwrite"; |
||||
} |
||||
} |
||||
|
||||
if (!bad && |
||||
!strncmp(destination[i], source[i], strlen(source[i]))) |
||||
bad = "can not move directory into itself"; |
||||
|
||||
if (!bad && cache_name_pos(source[i], strlen(source[i])) < 0) |
||||
bad = "not under version control"; |
||||
|
||||
if (!bad) { |
||||
if (path_list_has_path(&src_for_dst, destination[i])) |
||||
bad = "multiple sources for the same target"; |
||||
else |
||||
path_list_insert(destination[i], &src_for_dst); |
||||
} |
||||
|
||||
next: |
||||
if (bad) { |
||||
if (ignore_errors) { |
||||
if (--count > 0) { |
||||
memmove(source + i, source + i + 1, |
||||
(count - i) * sizeof(char *)); |
||||
memmove(destination + i, |
||||
destination + i + 1, |
||||
(count - i) * sizeof(char *)); |
||||
} |
||||
} else |
||||
die ("%s, source=%s, destination=%s", |
||||
bad, source[i], destination[i]); |
||||
} |
||||
} |
||||
|
||||
for (i = 0; i < count; i++) { |
||||
if (show_only || verbose) |
||||
printf("Renaming %s to %s\n", |
||||
source[i], destination[i]); |
||||
if (!show_only && modes[i] != INDEX && |
||||
rename(source[i], destination[i]) < 0 && |
||||
!ignore_errors) |
||||
die ("renaming %s failed: %s", |
||||
source[i], strerror(errno)); |
||||
|
||||
if (modes[i] == WORKING_DIRECTORY) |
||||
continue; |
||||
|
||||
if (cache_name_pos(source[i], strlen(source[i])) >= 0) { |
||||
path_list_insert(source[i], &deleted); |
||||
|
||||
/* destination can be a directory with 1 file inside */ |
||||
if (path_list_has_path(&overwritten, destination[i])) |
||||
path_list_insert(destination[i], &changed); |
||||
else |
||||
path_list_insert(destination[i], &added); |
||||
} else |
||||
path_list_insert(destination[i], &added); |
||||
} |
||||
|
||||
if (show_only) { |
||||
show_list("Changed : ", &changed); |
||||
show_list("Adding : ", &added); |
||||
show_list("Deleting : ", &deleted); |
||||
} else { |
||||
for (i = 0; i < changed.nr; i++) { |
||||
const char *path = changed.items[i].path; |
||||
int i = cache_name_pos(path, strlen(path)); |
||||
struct cache_entry *ce = active_cache[i]; |
||||
|
||||
if (i < 0) |
||||
die ("Huh? Cache entry for %s unknown?", path); |
||||
refresh_cache_entry(ce, 0); |
||||
} |
||||
|
||||
for (i = 0; i < added.nr; i++) { |
||||
const char *path = added.items[i].path; |
||||
add_file_to_index(path, verbose); |
||||
} |
||||
|
||||
for (i = 0; i < deleted.nr; i++) { |
||||
const char *path = deleted.items[i].path; |
||||
remove_file_from_cache(path); |
||||
} |
||||
|
||||
if (active_cache_changed) { |
||||
if (write_cache(newfd, active_cache, active_nr) || |
||||
close(newfd) || |
||||
commit_lock_file(&lock_file)) |
||||
die("Unable to write new index file"); |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
# git Makefile configuration, included in main Makefile |
||||
# @configure_input@ |
||||
|
||||
CC = @CC@ |
||||
AR = @AR@ |
||||
TAR = @TAR@ |
||||
#INSTALL = @INSTALL@ # needs install-sh or install.sh in sources |
||||
|
||||
prefix = @prefix@ |
||||
exec_prefix = @exec_prefix@ |
||||
bindir = @bindir@ |
||||
#gitexecdir = @libexecdir@/git-core/ |
||||
datarootdir = @datarootdir@ |
||||
template_dir = @datadir@/git-core/templates/ |
||||
GIT_PYTHON_DIR = @datadir@/git-core/python |
||||
|
||||
mandir=@mandir@ |
||||
|
||||
srcdir = @srcdir@ |
||||
VPATH = @srcdir@ |
||||
|
||||
export exec_prefix mandir |
||||
export srcdir VPATH |
||||
|
@ -0,0 +1,183 @@
@@ -0,0 +1,183 @@
|
||||
# -*- Autoconf -*- |
||||
# Process this file with autoconf to produce a configure script. |
||||
|
||||
AC_PREREQ(2.59) |
||||
AC_INIT([git], [1.4.1], [git@vger.kernel.org]) |
||||
|
||||
AC_CONFIG_SRCDIR([git.c]) |
||||
|
||||
config_file=config.mak.autogen |
||||
config_append=config.mak.append |
||||
config_in=config.mak.in |
||||
|
||||
echo "# ${config_append}. Generated by configure." > "${config_append}" |
||||
|
||||
|
||||
## Definitions of macros |
||||
# GIT_CONF_APPEND_LINE(LINE) |
||||
# -------------------------- |
||||
# Append LINE to file ${config_append} |
||||
AC_DEFUN([GIT_CONF_APPEND_LINE], |
||||
[echo "$1" >> "${config_append}"])# GIT_CONF_APPEND_LINE |
||||
|
||||
|
||||
## Checks for programs. |
||||
AC_MSG_NOTICE([CHECKS for programs]) |
||||
# |
||||
AC_PROG_CC |
||||
#AC_PROG_INSTALL # needs install-sh or install.sh in sources |
||||
AC_CHECK_TOOL(AR, ar, :) |
||||
AC_CHECK_PROGS(TAR, [gtar tar]) |
||||
# |
||||
# Define NO_PYTHON if you want to lose all benefits of the recursive merge. |
||||
|
||||
|
||||
## Checks for libraries. |
||||
AC_MSG_NOTICE([CHECKS for libraries]) |
||||
# |
||||
# Define NO_OPENSSL environment variable if you do not have OpenSSL. |
||||
# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). |
||||
AC_CHECK_LIB([ssl], [SHA1_Init],[], |
||||
[AC_CHECK_LIB([crypto], [SHA1_INIT], |
||||
[GIT_CONF_APPEND_LINE(NEEDS_SSL_WITH_CRYPTO=YesPlease)], |
||||
[GIT_CONF_APPEND_LINE(NO_OPENSSL=YesPlease)])]) |
||||
# |
||||
# Define NO_CURL if you do not have curl installed. git-http-pull and |
||||
# git-http-push are not built, and you cannot use http:// and https:// |
||||
# transports. |
||||
AC_CHECK_LIB([curl], [curl_global_init],[], |
||||
[GIT_CONF_APPEND_LINE(NO_CURL=YesPlease)]) |
||||
# |
||||
# Define NO_EXPAT if you do not have expat installed. git-http-push is |
||||
# not built, and you cannot push using http:// and https:// transports. |
||||
AC_CHECK_LIB([expat], [XML_ParserCreate],[], |
||||
[GIT_CONF_APPEND_LINE(NO_EXPAT=YesPlease)]) |
||||
# |
||||
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). |
||||
AC_CHECK_LIB([c], [iconv],[], |
||||
[AC_CHECK_LIB([iconv],[iconv], |
||||
[GIT_CONF_APPEND_LINE(NEEDS_LIBICONV=YesPlease)],[])]) |
||||
# |
||||
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS, |
||||
# Patrick Mauritz). |
||||
AC_CHECK_LIB([c], [socket],[], |
||||
[AC_CHECK_LIB([socket],[socket], |
||||
[GIT_CONF_APPEND_LINE(NEEDS_SOCKET=YesPlease)],[])]) |
||||
|
||||
|
||||
## Checks for header files. |
||||
|
||||
|
||||
## Checks for typedefs, structures, and compiler characteristics. |
||||
AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics]) |
||||
# |
||||
# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent. |
||||
AC_CHECK_MEMBER(struct dirent.d_ino,[], |
||||
[GIT_CONF_APPEND_LINE(NO_D_INO_IN_DIRENT=YesPlease)], |
||||
[#include <dirent.h>]) |
||||
# |
||||
# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks |
||||
# d_type in struct dirent (latest Cygwin -- will be fixed soonish). |
||||
AC_CHECK_MEMBER(struct dirent.d_type,[], |
||||
[GIT_CONF_APPEND_LINE(NO_D_TYPE_IN_DIRENT=YesPlease)], |
||||
[#include <dirent.h>]) |
||||
# |
||||
# Define NO_SOCKADDR_STORAGE if your platform does not have struct |
||||
# sockaddr_storage. |
||||
AC_CHECK_TYPE(struct sockaddr_storage,[], |
||||
[GIT_CONF_APPEND_LINE(NO_SOCKADDR_STORAGE=YesPlease)], |
||||
[#include <netinet/in.h>]) |
||||
|
||||
|
||||
## Checks for library functions. |
||||
## (in default C library and libraries checked by AC_CHECK_LIB) |
||||
AC_MSG_NOTICE([CHECKS for library functions]) |
||||
# |
||||
# Define NO_STRCASESTR if you don't have strcasestr. |
||||
AC_CHECK_FUNC(strcasestr,[], |
||||
[GIT_CONF_APPEND_LINE(NO_STRCASESTR=YesPlease)]) |
||||
# |
||||
# Define NO_STRLCPY if you don't have strlcpy. |
||||
AC_CHECK_FUNC(strlcpy,[], |
||||
[GIT_CONF_APPEND_LINE(NO_STRLCPY=YesPlease)]) |
||||
# |
||||
# Define NO_SETENV if you don't have setenv in the C library. |
||||
AC_CHECK_FUNC(setenv,[], |
||||
[GIT_CONF_APPEND_LINE(NO_SETENV=YesPlease)]) |
||||
# |
||||
# Define NO_MMAP if you want to avoid mmap. |
||||
# |
||||
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). |
||||
# |
||||
# Define NO_ICONV if your libc does not properly support iconv. |
||||
|
||||
|
||||
## Other checks. |
||||
# Define USE_PIC if you need the main git objects to be built with -fPIC |
||||
# in order to build and link perl/Git.so. x86-64 seems to need this. |
||||
# |
||||
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link. |
||||
# Enable it on Windows. By default, symrefs are still used. |
||||
# |
||||
# Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3. |
||||
# |
||||
# Define NO_ACCURATE_DIFF if your diff program at least sometimes misses |
||||
# a missing newline at the end of the file. |
||||
|
||||
|
||||
## Site configuration |
||||
## --with-PACKAGE[=ARG] and --without-PACKAGE |
||||
# Define NO_SVN_TESTS if you want to skip time-consuming SVN interopability |
||||
# tests. These tests take up a significant amount of the total test time |
||||
# but are not needed unless you plan to talk to SVN repos. |
||||
# |
||||
# Define MOZILLA_SHA1 environment variable when running make to make use of |
||||
# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast |
||||
# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default |
||||
# choice) has very fast version optimized for i586. |
||||
# |
||||
# Define PPC_SHA1 environment variable when running make to make use of |
||||
# a bundled SHA1 routine optimized for PowerPC. |
||||
# |
||||
# Define ARM_SHA1 environment variable when running make to make use of |
||||
# a bundled SHA1 routine optimized for ARM. |
||||
# |
||||
# Define NO_OPENSSL environment variable if you do not have OpenSSL. |
||||
# This also implies MOZILLA_SHA1. |
||||
# |
||||
# Define NO_CURL if you do not have curl installed. git-http-pull and |
||||
# git-http-push are not built, and you cannot use http:// and https:// |
||||
# transports. |
||||
# |
||||
# Define CURLDIR=/foo/bar if your curl header and library files are in |
||||
# /foo/bar/include and /foo/bar/lib directories. |
||||
# |
||||
# Define NO_EXPAT if you do not have expat installed. git-http-push is |
||||
# not built, and you cannot push using http:// and https:// transports. |
||||
# |
||||
# Define NO_MMAP if you want to avoid mmap. |
||||
# |
||||
# Define NO_PYTHON if you want to loose all benefits of the recursive merge. |
||||
# |
||||
## --enable-FEATURE[=ARG] and --disable-FEATURE |
||||
# Define COLLISION_CHECK below if you believe that SHA1's |
||||
# 1461501637330902918203684832716283019655932542976 hashes do not give you |
||||
# sufficient guarantee that no collisions between objects will ever happen. |
||||
# |
||||
# Define USE_NSEC below if you want git to care about sub-second file mtimes |
||||
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and |
||||
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely |
||||
# randomly break unless your underlying filesystem supports those sub-second |
||||
# times (my ext3 doesn't). |
||||
# |
||||
# Define USE_STDEV below if you want git to care about the underlying device |
||||
# change being considered an inode change from the update-cache perspective. |
||||
|
||||
|
||||
## Output files |
||||
AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"]) |
||||
AC_OUTPUT |
||||
|
||||
|
||||
## Cleanup |
||||
rm -f "${config_append}" |
@ -1,250 +0,0 @@
@@ -1,250 +0,0 @@
|
||||
#!/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> <destination> |
||||
$0 [-f] [-n] [-k] <source> ... <destination directory> |
||||
EOT |
||||
exit(1); |
||||
} |
||||
|
||||
our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v); |
||||
getopts("hnfkv") || usage; |
||||
usage() if $opt_h; |
||||
@ARGV >= 1 or usage; |
||||
|
||||
my $GIT_DIR = `git rev-parse --git-dir`; |
||||
exit 1 if $?; # rev-parse would have given "not a git dir" message. |
||||
chomp($GIT_DIR); |
||||
|
||||
my (@srcArgs, @dstArgs, @srcs, @dsts); |
||||
my ($src, $dst, $base, $dstDir); |
||||
|
||||
# remove any trailing slash in arguments |
||||
for (@ARGV) { s/\/*$//; } |
||||
|
||||
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: need at least two arguments\n"; |
||||
exit(1); |
||||
} |
||||
if ($argCount > 2) { |
||||
print "Error: moving to directory '" |
||||
. $ARGV[$argCount-1] |
||||
. "' not possible; not existing\n"; |
||||
exit(1); |
||||
} |
||||
@srcArgs = ($ARGV[0]); |
||||
@dstArgs = ($ARGV[1]); |
||||
$dstDir = ""; |
||||
} |
||||
|
||||
my $subdir_prefix = `git rev-parse --show-prefix`; |
||||
chomp($subdir_prefix); |
||||
|
||||
# run in git base directory, so that git-ls-files lists all revisioned files |
||||
chdir "$GIT_DIR/.."; |
||||
|
||||
# normalize paths, needed to compare against versioned files and update-index |
||||
# also, this is nicer to end-users by doing ".//a/./b/.//./c" ==> "a/b/c" |
||||
for (@srcArgs, @dstArgs) { |
||||
# prepend git prefix as we run from base directory |
||||
$_ = $subdir_prefix.$_; |
||||
s|^\./||; |
||||
s|/\./|/| while (m|/\./|); |
||||
s|//+|/|g; |
||||
# Also "a/b/../c" ==> "a/c" |
||||
1 while (s,(^|/)[^/]+/\.\./,$1,); |
||||
} |
||||
|
||||
my (@allfiles,@srcfiles,@dstfiles); |
||||
my $safesrc; |
||||
my (%overwritten, %srcForDst); |
||||
|
||||
$/ = "\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 = ""; |
||||
|
||||
for ($src, $dst) { |
||||
# Be nicer to end-users by doing ".//a/./b/.//./c" ==> "a/b/c" |
||||
s|^\./||; |
||||
s|/\./|/| while (m|/\./|); |
||||
s|//+|/|g; |
||||
# Also "a/b/../c" ==> "a/c" |
||||
1 while (s,(^|/)[^/]+/\.\./,$1,); |
||||
} |
||||
|
||||
if ($opt_v) { |
||||
print "Checking rename of '$src' to '$dst'\n"; |
||||
} |
||||
|
||||
unless (-f $src || -l $src || -d $src) { |
||||
$bad = "bad source '$src'"; |
||||
} |
||||
|
||||
$safesrc = quotemeta($src); |
||||
@srcfiles = grep /^$safesrc(\/|$)/, @allfiles; |
||||
|
||||
$overwritten{$dst} = 0; |
||||
if (($bad eq "") && -e $dst) { |
||||
$bad = "destination '$dst' already exists"; |
||||
if ($opt_f) { |
||||
# only files can overwrite each other: check both source and destination |
||||
if (-f $dst && (scalar @srcfiles == 1)) { |
||||
print "Warning: $bad; will overwrite!\n"; |
||||
$bad = ""; |
||||
$overwritten{$dst} = 1; |
||||
} |
||||
else { |
||||
$bad = "Can not overwrite '$src' with '$dst'"; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (($bad eq "") && ($dst =~ /^$safesrc\//)) { |
||||
$bad = "can not move directory '$src' into itself"; |
||||
} |
||||
|
||||
if ($bad eq "") { |
||||
if (scalar @srcfiles == 0) { |
||||
$bad = "'$src' not under version control"; |
||||
} |
||||
} |
||||
|
||||
if ($bad eq "") { |
||||
if (defined $srcForDst{$dst}) { |
||||
$bad = "can not move '$src' to '$dst'; already target of "; |
||||
$bad .= "'".$srcForDst{$dst}."'"; |
||||
} |
||||
else { |
||||
$srcForDst{$dst} = $src; |
||||
} |
||||
} |
||||
|
||||
if ($bad ne "") { |
||||
if ($opt_k) { |
||||
print "Warning: $bad; skipping\n"; |
||||
next; |
||||
} |
||||
print "Error: $bad\n"; |
||||
exit(1); |
||||
} |
||||
push @srcs, $src; |
||||
push @dsts, $dst; |
||||
} |
||||
|
||||
# Final pass: rename/move |
||||
my (@deletedfiles,@addedfiles,@changedfiles); |
||||
$bad = ""; |
||||
while(scalar @srcs > 0) { |
||||
$src = shift @srcs; |
||||
$dst = shift @dsts; |
||||
|
||||
if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; } |
||||
if (!$opt_n) { |
||||
if (!rename($src,$dst)) { |
||||
$bad = "renaming '$src' failed: $!"; |
||||
if ($opt_k) { |
||||
print "Warning: skipped: $bad\n"; |
||||
$bad = ""; |
||||
next; |
||||
} |
||||
last; |
||||
} |
||||
} |
||||
|
||||
$safesrc = quotemeta($src); |
||||
@srcfiles = grep /^$safesrc(\/|$)/, @allfiles; |
||||
@dstfiles = @srcfiles; |
||||
s/^$safesrc(\/|$)/$dst$1/ for @dstfiles; |
||||
|
||||
push @deletedfiles, @srcfiles; |
||||
if (scalar @srcfiles == 1) { |
||||
# $dst can be a directory with 1 file inside |
||||
if ($overwritten{$dst} ==1) { |
||||
push @changedfiles, $dstfiles[0]; |
||||
|
||||
} else { |
||||
push @addedfiles, $dstfiles[0]; |
||||
} |
||||
} |
||||
else { |
||||
push @addedfiles, @dstfiles; |
||||
} |
||||
} |
||||
|
||||
if ($opt_n) { |
||||
if (@changedfiles) { |
||||
print "Changed : ". join(", ", @changedfiles) ."\n"; |
||||
} |
||||
if (@addedfiles) { |
||||
print "Adding : ". join(", ", @addedfiles) ."\n"; |
||||
} |
||||
if (@deletedfiles) { |
||||
print "Deleting : ". join(", ", @deletedfiles) ."\n"; |
||||
} |
||||
} |
||||
else { |
||||
if (@changedfiles) { |
||||
open(H, "| git-update-index -z --stdin") |
||||
or die "git-update-index failed to update changed files with code $!\n"; |
||||
foreach my $fileName (@changedfiles) { |
||||
print H "$fileName\0"; |
||||
} |
||||
close(H); |
||||
} |
||||
if (@addedfiles) { |
||||
open(H, "| git-update-index --add -z --stdin") |
||||
or die "git-update-index failed to add new names with code $!\n"; |
||||
foreach my $fileName (@addedfiles) { |
||||
print H "$fileName\0"; |
||||
} |
||||
close(H); |
||||
} |
||||
if (@deletedfiles) { |
||||
open(H, "| git-update-index --remove -z --stdin") |
||||
or die "git-update-index failed to remove old names with code $!\n"; |
||||
foreach my $fileName (@deletedfiles) { |
||||
print H "$fileName\0"; |
||||
} |
||||
close(H); |
||||
} |
||||
} |
||||
|
||||
if ($bad ne "") { |
||||
print "Error: $bad\n"; |
||||
exit(1); |
||||
} |
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Copyright (c) 2006 Eric Wong |
||||
# |
||||
|
||||
test_description='git-apply should not get confused with type changes. |
||||
|
||||
' |
||||
|
||||
. ./test-lib.sh |
||||
|
||||
test_expect_success 'setup repository and commits' ' |
||||
echo "hello world" > foo && |
||||
echo "hi planet" > bar && |
||||
git update-index --add foo bar && |
||||
git commit -m initial && |
||||
git branch initial && |
||||
rm -f foo && |
||||
ln -s bar foo && |
||||
git update-index foo && |
||||
git commit -m "foo symlinked to bar" && |
||||
git branch foo-symlinked-to-bar && |
||||
rm -f foo && |
||||
echo "how far is the sun?" > foo && |
||||
git update-index foo && |
||||
git commit -m "foo back to file" && |
||||
git branch foo-back-to-file && |
||||
rm -f foo && |
||||
git update-index --remove foo && |
||||
mkdir foo && |
||||
echo "if only I knew" > foo/baz && |
||||
git update-index --add foo/baz && |
||||
git commit -m "foo becomes a directory" && |
||||
git branch "foo-becomes-a-directory" && |
||||
echo "hello world" > foo/baz && |
||||
git update-index foo/baz && |
||||
git commit -m "foo/baz is the original foo" && |
||||
git branch foo-baz-renamed-from-foo |
||||
' |
||||
|
||||
test_expect_success 'file renamed from foo to foo/baz' ' |
||||
git checkout -f initial && |
||||
git diff-tree -M -p HEAD foo-baz-renamed-from-foo > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_expect_success 'file renamed from foo/baz to foo' ' |
||||
git checkout -f foo-baz-renamed-from-foo && |
||||
git diff-tree -M -p HEAD initial > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_expect_success 'directory becomes file' ' |
||||
git checkout -f foo-becomes-a-directory && |
||||
git diff-tree -p HEAD initial > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_expect_success 'file becomes directory' ' |
||||
git checkout -f initial && |
||||
git diff-tree -p HEAD foo-becomes-a-directory > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_expect_success 'file becomes symlink' ' |
||||
git checkout -f initial && |
||||
git diff-tree -p HEAD foo-symlinked-to-bar > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_expect_success 'symlink becomes file' ' |
||||
git checkout -f foo-symlinked-to-bar && |
||||
git diff-tree -p HEAD foo-back-to-file > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_expect_success 'symlink becomes directory' ' |
||||
git checkout -f foo-symlinked-to-bar && |
||||
git diff-tree -p HEAD foo-becomes-a-directory > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_expect_success 'directory becomes symlink' ' |
||||
git checkout -f foo-becomes-a-directory && |
||||
git diff-tree -p HEAD foo-symlinked-to-bar > patch && |
||||
git apply --index < patch |
||||
' |
||||
test_debug 'cat patch' |
||||
|
||||
|
||||
test_done |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh |
||||
|
||||
test_description='git-rev-list trivial path optimization test' |
||||
|
||||
. ./test-lib.sh |
||||
|
||||
test_expect_success setup ' |
||||
echo Hello > a && |
||||
git add a && |
||||
git commit -m "Initial commit" a |
||||
' |
||||
|
||||
test_expect_success path-optimization ' |
||||
commit=$(echo "Unchanged tree" | git-commit-tree "HEAD^{tree}" -p HEAD) && |
||||
test $(git-rev-list $commit | wc -l) = 2 && |
||||
test $(git-rev-list $commit -- . | wc -l) = 1 |
||||
' |
||||
|
||||
test_done |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue