diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index dc7d3d17b1..ab7293351d 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -128,7 +128,12 @@ objects from the source repository into a pack in the cloned repository. configuration variables are created. --mirror:: - Set up a mirror of the remote repository. This implies `--bare`. + Set up a mirror of the source repository. This implies `--bare`. + Compared to `--bare`, `--mirror` not only maps local branches of the + source to local branches of the target, it maps all refs (including + remote branches, notes etc.) and sets up a refspec configuration such + that all these refs are overwritten by a `git remote update` in the + target repository. --origin :: -o :: diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index 4b84d08fc8..be8a51fd06 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -56,6 +56,8 @@ COMMANDS as well, they take precedence. --no-metadata;; Set the 'noMetadata' option in the [svn-remote] config. + This option is not recommended, please read the 'svn.noMetadata' + section of this manpage before using this option. --use-svm-props;; Set the 'useSvmProps' option in the [svn-remote] config. --use-svnsync-props;; @@ -597,13 +599,22 @@ svn.noMetadata:: svn-remote..noMetadata:: This gets rid of the 'git-svn-id:' lines at the end of every commit. + -If you lose your .git/svn/git-svn/.rev_db file, 'git svn' will not -be able to rebuild it and you won't be able to fetch again, -either. This is fine for one-shot imports. +This option can only be used for one-shot imports as 'git svn' +will not be able to fetch again without metadata. Additionally, +if you lose your .git/svn/**/.rev_map.* files, 'git svn' will not +be able to rebuild them. + The 'git svn log' command will not work on repositories using this, either. Using this conflicts with the 'useSvmProps' option for (hopefully) obvious reasons. ++ +This option is NOT recommended as it makes it difficult to track down +old references to SVN revision numbers in existing documentation, bug +reports and archives. If you plan to eventually migrate from SVN to git +and are certain about dropping SVN history, consider +linkgit:git-filter-branch[1] instead. filter-branch also allows +reformating of metadata for ease-of-reading and rewriting authorship +info for non-"svn.authorsFile" users. svn.useSvmProps:: svn-remote..useSvmProps:: diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 2e680d7a7a..e243d9d22e 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -161,7 +161,7 @@ static void use(int bytes) input_offset += bytes; /* make sure off_t is sufficiently large not to wrap */ - if (consumed_bytes > consumed_bytes + bytes) + if (signed_add_overflows(consumed_bytes, bytes)) die("pack too large for current definition of off_t"); consumed_bytes += bytes; } diff --git a/builtin/init-db.c b/builtin/init-db.c index 0271285fad..9d4886c716 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -294,11 +294,26 @@ static int create_default_files(const char *template_path) return reinit; } +static void create_object_directory(void) +{ + const char *object_directory = get_object_directory(); + int len = strlen(object_directory); + char *path = xmalloc(len + 40); + + memcpy(path, object_directory, len); + + safe_create_dir(object_directory, 1); + strcpy(path+len, "/pack"); + safe_create_dir(path, 1); + strcpy(path+len, "/info"); + safe_create_dir(path, 1); + + free(path); +} + int init_db(const char *template_dir, unsigned int flags) { - const char *sha1_dir; - char *path; - int len, reinit; + int reinit; safe_create_dir(get_git_dir(), 0); @@ -313,16 +328,7 @@ int init_db(const char *template_dir, unsigned int flags) reinit = create_default_files(template_dir); - sha1_dir = get_object_directory(); - len = strlen(sha1_dir); - path = xmalloc(len + 40); - memcpy(path, sha1_dir, len); - - safe_create_dir(sha1_dir, 1); - strcpy(path+len, "/pack"); - safe_create_dir(path, 1); - strcpy(path+len, "/info"); - safe_create_dir(path, 1); + create_object_directory(); if (shared_repository) { char buf[10]; diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 3756cf36ee..d5a8db1bb6 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -431,7 +431,7 @@ static int write_one(struct sha1file *f, written_list[nr_written++] = &e->idx; /* make sure off_t is sufficiently large not to wrap */ - if (*offset > *offset + size) + if (signed_add_overflows(*offset, size)) die("pack too large for current definition of off_t"); *offset += size; return 1; diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index 685566e0b5..f63973c914 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -83,7 +83,7 @@ static void use(int bytes) offset += bytes; /* make sure off_t is sufficiently large not to wrap */ - if (consumed_bytes > consumed_bytes + bytes) + if (signed_add_overflows(consumed_bytes, bytes)) die("pack too large for current definition of off_t"); consumed_bytes += bytes; } diff --git a/cache.h b/cache.h index 2ef2fa3a5e..3d5ed51989 100644 --- a/cache.h +++ b/cache.h @@ -277,9 +277,16 @@ static inline int ce_to_dtype(const struct cache_entry *ce) else return DT_UNKNOWN; } -#define canon_mode(mode) \ - (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \ - S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK) +static inline unsigned int canon_mode(unsigned int mode) +{ + if (S_ISREG(mode)) + return S_IFREG | ce_permissions(mode); + if (S_ISLNK(mode)) + return S_IFLNK; + if (S_ISDIR(mode)) + return S_IFDIR; + return S_IFGITLINK; +} #define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7) #define cache_entry_size(len) flexible_size(cache_entry,len) diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index 84195e47aa..38570999c3 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -269,9 +269,8 @@ static void diffcore_pickaxe_count(struct diff_options *o) diff_free_filepair(p); } - if (opts & DIFF_PICKAXE_REGEX) { + if (opts & DIFF_PICKAXE_REGEX) regfree(®ex); - } free(q->queue); *q = outq; diff --git a/environment.c b/environment.c index 2d0c315379..de5581fe51 100644 --- a/environment.c +++ b/environment.c @@ -64,7 +64,7 @@ char *git_work_tree_cfg; static char *work_tree; static const char *git_dir; -static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; +static char *git_object_dir, *git_index_file, *git_graft_file; /* * Repository-local GIT_* environment variables @@ -87,8 +87,10 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = { static void setup_git_env(void) { git_dir = getenv(GIT_DIR_ENVIRONMENT); - if (!git_dir) + if (!git_dir) { git_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT); + git_dir = git_dir ? xstrdup(git_dir) : NULL; + } if (!git_dir) git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; git_object_dir = getenv(DB_ENVIRONMENT); @@ -96,8 +98,6 @@ static void setup_git_env(void) git_object_dir = xmalloc(strlen(git_dir) + 9); sprintf(git_object_dir, "%s/objects", git_dir); } - git_refs_dir = xmalloc(strlen(git_dir) + 6); - sprintf(git_refs_dir, "%s/refs", git_dir); git_index_file = getenv(INDEX_ENVIRONMENT); if (!git_index_file) { git_index_file = xmalloc(strlen(git_dir) + 7); diff --git a/git-compat-util.h b/git-compat-util.h index 81883e7270..2af8d3edbe 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -28,6 +28,18 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) +#define maximum_signed_value_of_type(a) \ + (INTMAX_MAX >> (bitsizeof(intmax_t) - bitsizeof(a))) + +/* + * Signed integer overflow is undefined in C, so here's a helper macro + * to detect if the sum of two integers will overflow. + * + * Requires: a >= 0, typeof(a) equals typeof(b) + */ +#define signed_add_overflows(a, b) \ + ((b) > maximum_signed_value_of_type(a) - (a)) + #ifdef __GNUC__ #define TYPEOF(x) (__typeof__(x)) #else diff --git a/git-svn.perl b/git-svn.perl index 9b046b693f..18cfb2466d 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1513,7 +1513,8 @@ sub cmt_sha2rev_batch { sub working_head_info { my ($head, $refs) = @_; - my @args = ('log', '--no-color', '--first-parent', '--pretty=medium'); + my @args = qw/log --no-color --no-decorate --first-parent + --pretty=medium/; my ($fh, $ctx) = command_output_pipe(@args, $head); my $hash; my %max; @@ -3118,9 +3119,10 @@ sub _rev_list { sub check_cherry_pick { my $base = shift; my $tip = shift; + my $parents = shift; my @ranges = @_; my %commits = map { $_ => 1 } - _rev_list("--no-merges", $tip, "--not", $base); + _rev_list("--no-merges", $tip, "--not", $base, @$parents); for my $range ( @ranges ) { delete @commits{_rev_list($range)}; } @@ -3296,6 +3298,7 @@ sub find_extra_svn_parents { # double check that there are no missing non-merge commits my (@incomplete) = check_cherry_pick( $merge_base, $merge_tip, + $parents, @$ranges, ); diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh index a7d8187169..ca01053bcc 100755 --- a/t/t3020-ls-files-error-unmatch.sh +++ b/t/t3020-ls-files-error-unmatch.sh @@ -26,4 +26,3 @@ test_expect_success \ 'git ls-files --error-unmatch foo bar' test_done -1 diff --git a/t/t9157-git-svn-fetch-merge.sh b/t/t9157-git-svn-fetch-merge.sh new file mode 100644 index 0000000000..da582c5382 --- /dev/null +++ b/t/t9157-git-svn-fetch-merge.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# +# Copyright (c) 2010 Steven Walter +# + +test_description='git svn merge detection' +. ./lib-git-svn.sh + +test_expect_success 'initialize source svn repo' ' + svn_cmd mkdir -m x "$svnrepo"/trunk && + svn_cmd mkdir -m x "$svnrepo"/branches && + svn_cmd co "$svnrepo"/trunk "$SVN_TREE" && + ( + cd "$SVN_TREE" && + touch foo && + svn add foo && + svn commit -m "initial commit" && + svn cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 && + touch bar && + svn add bar && + svn commit -m x && + svn cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch2 && + svn switch "$svnrepo"/branches/branch1 && + touch baz && + svn add baz && + svn commit -m x && + svn switch "$svnrepo"/trunk && + svn merge "$svnrepo"/branches/branch1 && + svn commit -m "merge" && + svn switch "$svnrepo"/branches/branch1 && + svn commit -m x && + svn switch "$svnrepo"/branches/branch2 && + svn merge "$svnrepo"/branches/branch1 && + svn commit -m "merge branch1" && + svn switch "$svnrepo"/trunk && + svn merge "$svnrepo"/branches/branch2 && + svn resolved baz && + svn commit -m "merge branch2" + ) && + rm -rf "$SVN_TREE" +' + +test_expect_success 'clone svn repo' ' + git svn init -s "$svnrepo" && + git svn fetch +' + +test_expect_success 'verify merge commit' 'git rev-parse HEAD^2' + +test_done diff --git a/xdiff/xmacros.h b/xdiff/xmacros.h index 8ef232cfad..165a895a93 100644 --- a/xdiff/xmacros.h +++ b/xdiff/xmacros.h @@ -30,6 +30,7 @@ #define XDL_MAX(a, b) ((a) > (b) ? (a): (b)) #define XDL_ABS(v) ((v) >= 0 ? (v): -(v)) #define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9') +#define XDL_ISSPACE(c) (isspace((unsigned char)(c))) #define XDL_ADDBITS(v,b) ((v) + ((v) >> (b))) #define XDL_MASKBITS(b) ((1UL << (b)) - 1) #define XDL_HASHLONG(v,b) (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b)) diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c index 6d6fc1bc5e..9e13b25abc 100644 --- a/xdiff/xmerge.c +++ b/xdiff/xmerge.c @@ -336,7 +336,7 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m, static int line_contains_alnum(const char *ptr, long size) { while (size--) - if (isalnum(*(ptr++))) + if (isalnum((unsigned char)*(ptr++))) return 1; return 0; } diff --git a/xdiff/xutils.c b/xdiff/xutils.c index 22f9bd692c..ab6503460f 100644 --- a/xdiff/xutils.c +++ b/xdiff/xutils.c @@ -211,18 +211,18 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) if (l1[i1++] != l2[i2++]) return 0; skip_ws: - while (i1 < s1 && isspace(l1[i1])) + while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; - while (i2 < s2 && isspace(l2[i2])) + while (i2 < s2 && XDL_ISSPACE(l2[i2])) i2++; } } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) { while (i1 < s1 && i2 < s2) { - if (isspace(l1[i1]) && isspace(l2[i2])) { + if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) { /* Skip matching spaces and try again */ - while (i1 < s1 && isspace(l1[i1])) + while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; - while (i2 < s2 && isspace(l2[i2])) + while (i2 < s2 && XDL_ISSPACE(l2[i2])) i2++; continue; } @@ -241,13 +241,13 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) * while there still are characters remaining on both lines. */ if (i1 < s1) { - while (i1 < s1 && isspace(l1[i1])) + while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; if (s1 != i1) return 0; } if (i2 < s2) { - while (i2 < s2 && isspace(l2[i2])) + while (i2 < s2 && XDL_ISSPACE(l2[i2])) i2++; return (s2 == i2); } @@ -260,10 +260,10 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data, char const *ptr = *data; for (; ptr < top && *ptr != '\n'; ptr++) { - if (isspace(*ptr)) { + if (XDL_ISSPACE(*ptr)) { const char *ptr2 = ptr; int at_eol; - while (ptr + 1 < top && isspace(ptr[1]) + while (ptr + 1 < top && XDL_ISSPACE(ptr[1]) && ptr[1] != '\n') ptr++; at_eol = (top <= ptr + 1 || ptr[1] == '\n');