diff options
90 files changed, 2291 insertions, 1112 deletions
diff --git a/Documentation/RelNotes-1.6.4.2.txt b/Documentation/RelNotes-1.6.4.2.txt new file mode 100644 index 0000000000..c11ec0115c --- /dev/null +++ b/Documentation/RelNotes-1.6.4.2.txt @@ -0,0 +1,32 @@ +GIT v1.6.4.2 Release Notes +========================== + +Fixes since v1.6.4.1 +-------------------- + +* --date=relative output between 1 and 5 years ago rounded the number of + years when saying X years Y months ago, instead of rounding it down. + +* "git add -p" did not handle changes in executable bits correctly + (a regression around 1.6.3). + +* "git apply" did not honor GNU diff's convention to mark the creation/deletion + event with UNIX epoch timestamp on missing side. + +* "git checkout" incorrectly removed files in a directory pointed by a + symbolic link during a branch switch that replaces a directory with + a symbolic link. + +* "git clean -d -f" happily descended into a subdirectory that is managed by a + separate git repository. It now requires two -f options for safety. + +* "git fetch/push" over http transports had two rather grave bugs. + +* "git format-patch --cover-letter" did not prepare the cover letter file + for use with non-ASCII strings when there are the series contributors with + non-ASCII names. + +* "git pull origin branch" and "git fetch origin && git merge origin/branch" + left different merge messages in the resulting commit. + +Other minor documentation updates are included. diff --git a/Documentation/RelNotes-1.6.5.txt b/Documentation/RelNotes-1.6.5.txt index 856047d16f..84a84519d4 100644 --- a/Documentation/RelNotes-1.6.5.txt +++ b/Documentation/RelNotes-1.6.5.txt @@ -31,14 +31,68 @@ Updates since v1.6.4 (subsystems) + * various updates to git-svn and gitweb. + (portability) + * more improvements on mingw port. + (performance) + * On major platforms, the system can be compiled to use with Linus's + block-sha1 implementation of the SHA-1 hash algorithm, which + outperforms the default fallback implementation we borrowed from + Mozzilla. + (usability, bells and whistles) + * refs/replace/ hierarchy is designed to be usable as a replacement + of the "grafts" mechanism, with the added advantage that it can be + transferred across repositories. + + * "git am" learned to optionally ignore whitespace differences. + + * "git am" handles input e-mail files that has CRLF line endings sensibly. + + * "git commit --dry-run $args" is a new recommended way to ask "what would + happen if I try to commit with these arguments." + + * "git cvsimport" now supports password-protected pserver access. + + * "git fast-export" learned --no-data option that can be useful when + reordering commits and trees without touching the contents of + blobs. + + * "git init" learned to mkdir/chdir into a directory when given an + extra argument (i.e. "git init this"). + + * "git instaweb" optionally can use mongoose as the web server. + + * "git log --decorate" can optionally be told with --decorate=full to + give the reference name in full. + + * "git push" can be told to be --quiet. + + * informational output from "git reset" that lists the locally modified + paths is made consistent with that of "git checkout $another_branch". + + * "git status" gives more descriptive output for unmerged paths. + + * "git submodule" learned to give submodule name to scripts run with + "foreach" subcommand. + + * various subcommands to "git submodule" learned --recursive option. + + * "git submodule summary" learned --files option to compare the work + tree vs the commit bound at submodule path, instead of comparing + the index. + (developers) + * With GIT_TEST_OPTS="--root=/p/a/t/h", tests can be run outside the + source directory; using tmpfs may give faster turnaround. + + Fixes since v1.6.4 ------------------ @@ -48,4 +102,8 @@ Fixes since v1.6.4 # Here are fixes that this release has, but have not been backported to # v1.6.4.X series. - +-- +exec >/var/tmp/1 +O=v1.6.4.1-266-g235db15 +echo O=$(git describe master) +git shortlog --no-merges $O..master --not maint diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt index bc132c87e1..92444ddf10 100644 --- a/Documentation/git-archive.txt +++ b/Documentation/git-archive.txt @@ -9,7 +9,7 @@ git-archive - Create an archive of files from a named tree SYNOPSIS -------- [verse] -'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>] +'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>] [--output=<file>] [--worktree-attributes] [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish> [path...] diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index ae201deb7a..aad71dc59a 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -76,6 +76,7 @@ OPTIONS based sha1 expressions such as "<branchname>@\{yesterday}". -f:: +--force:: Reset <branchname> to <startpoint> if <branchname> exists already. Without `-f` 'git-branch' refuses to change an existing branch. @@ -209,6 +210,12 @@ but different purposes: - `--no-merged` is used to find branches which are candidates for merging into HEAD, since those branches are not fully contained by HEAD. +SEE ALSO +-------- +linkgit:git-check-ref-format[1], +linkgit:git-fetch[1], +linkgit:git-remote[1]. + Author ------ Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <gitster@pobox.com> diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index ad4b31e892..b1314b5614 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -45,9 +45,11 @@ file can be discarded to recreate the original conflicted merge result. OPTIONS ------- -q:: +--quiet:: Quiet, suppress feedback messages. -f:: +--force:: When switching branches, proceed even if the index or the working tree differs from HEAD. This is used to throw away local changes. diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index ae8938b2de..9d291bdd26 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -32,6 +32,7 @@ OPTIONS if you really want to remove such a directory. -f:: +--force:: If the git configuration specifies clean.requireForce as true, 'git-clean' will refuse to run unless given -f or -n. diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 2c63a0fbae..88ea272ee5 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -12,7 +12,7 @@ SYNOPSIS 'git clone' [--template=<template_directory>] [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-o <name>] [-u <upload-pack>] [--reference <repository>] - [--depth <depth>] [--] <repository> [<directory>] + [--depth <depth>] [--recursive] [--] <repository> [<directory>] DESCRIPTION ----------- @@ -147,6 +147,14 @@ objects from the source repository into a pack in the cloned repository. with a long history, and would want to send in fixes as patches. +--recursive:: + After the clone is created, initialize all submodules within, + using their default settings. This is equivalent to running + 'git submodule update --init --recursive' immediately after + the clone is finished. This option is ignored if the cloned + repository does not have a worktree/checkout (i.e. if any of + `--no-checkout`/`-n`, `--bare`, or `--mirror` is given) + <repository>:: The (possibly remote) repository to clone from. See the <<URLS,URLS>> section below for more information on specifying diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index b5d81be7ec..64f94cfe12 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -8,8 +8,8 @@ git-commit - Record changes to the repository SYNOPSIS -------- [verse] -'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] - [(-c | -C) <commit>] [-F <file> | -m <msg>] +'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run] + [(-c | -C) <commit>] [-F <file> | -m <msg>] [--dry-run] [--allow-empty] [--no-verify] [-e] [--author=<author>] [--cleanup=<mode>] [--] [[-i | -o ]<file>...] @@ -42,10 +42,9 @@ The content to be added can be specified in several ways: by one which files should be part of the commit, before finalizing the operation. Currently, this is done by invoking 'git-add --interactive'. -The 'git-status' command can be used to obtain a +The `--dry-run` option can be used to obtain a summary of what is included by any of the above for the next -commit by giving the same set of parameters you would give to -this command. +commit by giving the same set of parameters (options and paths). If you make a commit and then find a mistake immediately after that, you can recover from it with 'git-reset'. @@ -70,6 +69,12 @@ OPTIONS Like '-C', but with '-c' the editor is invoked, so that the user can further edit the commit message. +--dry-run:: + Do not actually make a commit, but show the list of paths + with updates in the index, paths with changes in the work tree, + and paths that are untracked, similar to the one that is given + in the commit log editor. + -F <file>:: --file=<file>:: Take the commit message from the given file. Use '-' to @@ -198,6 +203,11 @@ specified. --quiet:: Suppress commit summary message. +--dry-run:: + Do not create a commit, but show a list of paths that are + to be committed, paths with local changes that will be left + uncommitted and paths that are untracked. + \--:: Do not interpret any more arguments as options. diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt index b292e9843a..dcac8c8e29 100644 --- a/Documentation/git-gc.txt +++ b/Documentation/git-gc.txt @@ -61,7 +61,7 @@ automatic consolidation of packs. --prune=<date>:: Prune loose objects older than date (default is 2 weeks ago, - overrideable by the config variable `gc.pruneExpire`). This + overridable by the config variable `gc.pruneExpire`). This option is on by default. --no-prune:: diff --git a/Documentation/git-instaweb.txt b/Documentation/git-instaweb.txt index 22da21a54f..0771f25443 100644 --- a/Documentation/git-instaweb.txt +++ b/Documentation/git-instaweb.txt @@ -29,7 +29,7 @@ OPTIONS The HTTP daemon command-line that will be executed. Command-line options may be specified here, and the configuration file will be added at the end of the command-line. - Currently lighttpd, apache2 and webrick are supported. + Currently apache2, lighttpd, mongoose and webrick are supported. (Default: lighttpd) -m:: diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index 34cf4e5811..3d79de11ec 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -37,8 +37,12 @@ include::diff-options.txt[] and <until>, see "SPECIFYING REVISIONS" section in linkgit:git-rev-parse[1]. ---decorate:: - Print out the ref names of any commits that are shown. +--decorate[=short|full]:: + Print out the ref names of any commits that are shown. If 'short' is + specified, the ref name prefixes 'refs/heads/', 'refs/tags/' and + 'refs/remotes/' will not be printed. If 'full' is specified, the + full ref name (including prefix) will be printed. The default option + is 'short'. --source:: Print out the ref name given on the command line by which each diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt index 9c5660275b..bdcb58526e 100644 --- a/Documentation/git-mv.txt +++ b/Documentation/git-mv.txt @@ -28,6 +28,7 @@ committed. OPTIONS ------- -f:: +--force:: Force renaming or moving of a file even if the target exists -k:: Skip move or rename actions which would lead to an error diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 7dd73ae14e..5ccdd18c89 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -11,12 +11,12 @@ SYNOPSIS [verse] 'git submodule' [--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path> -'git submodule' [--quiet] status [--cached] [--] [<path>...] +'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...] 'git submodule' [--quiet] init [--] [<path>...] 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase] - [--reference <repository>] [--merge] [--] [<path>...] -'git submodule' [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...] -'git submodule' [--quiet] foreach <command> + [--reference <repository>] [--merge] [--recursive] [--] [<path>...] +'git submodule' [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...] +'git submodule' [--quiet] foreach [--recursive] <command> 'git submodule' [--quiet] sync [--] [<path>...] @@ -100,6 +100,9 @@ status:: initialized and `+` if the currently checked out submodule commit does not match the SHA-1 found in the index of the containing repository. This command is the default command for 'git-submodule'. ++ +If '--recursive' is specified, this command will recurse into nested +submodules, and show their status as well. init:: Initialize the submodules, i.e. register each submodule name @@ -122,21 +125,31 @@ update:: If the submodule is not yet initialized, and you just want to use the setting as stored in .gitmodules, you can automatically initialize the submodule with the --init option. ++ +If '--recursive' is specified, this command will recurse into the +registered submodules, and update any nested submodules within. summary:: Show commit summary between the given commit (defaults to HEAD) and working tree/index. For a submodule in question, a series of commits in the submodule between the given super project commit and the - index or working tree (switched by --cached) are shown. + index or working tree (switched by --cached) are shown. If the option + --files is given, show the series of commits in the submodule between + the index of the super project and the working tree of the submodule + (this option doesn't allow to use the --cached option or to provide an + explicit commit). foreach:: Evaluates an arbitrary shell command in each checked out submodule. - The command has access to the variables $path and $sha1: + The command has access to the variables $name, $path and $sha1: + $name is the name of the relevant submodule section in .gitmodules, $path is the name of the submodule directory relative to the superproject, and $sha1 is the commit as recorded in the superproject. Any submodules defined in the superproject but not checked out are ignored by this command. Unless given --quiet, foreach prints the name of each submodule before evaluating the command. + If --recursive is given, submodules are traversed recursively (i.e. + the given shell command is evaluated in nested submodules as well). A non-zero return from the command in any submodule causes the processing to terminate. This can be overridden by adding '|| :' to the end of the command. @@ -169,6 +182,11 @@ OPTIONS commands typically use the commit found in the submodule HEAD, but with this option, the commit stored in the index is used instead. +--files:: + This option is only valid for the summary command. This command + compares the commit in the index with that in the submodule HEAD + when this option is used. + -n:: --summary-limit:: This option is only valid for the summary command. @@ -209,6 +227,12 @@ OPTIONS *NOTE*: Do *not* use this option unless you have read the note for linkgit:git-clone[1]'s --reference and --shared options carefully. +--recursive:: + This option is only valid for foreach, update and status commands. + Traverse submodules recursively. The operation is performed not + only in the submodules of the current repo, but also + in any nested submodules inside those submodules (and so on). + <path>...:: Paths to submodule(s). When specified this will restrict the command to only operate on the submodules found at the specified paths. diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 1118ce22dc..299b04f726 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -10,17 +10,15 @@ SYNOPSIS -------- [verse] 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] - <name> [<commit> | <object>] -'git tag' -d <name>... + <tagname> [<commit> | <object>] +'git tag' -d <tagname>... 'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>] -'git tag' -v <name>... +'git tag' -v <tagname>... DESCRIPTION ----------- -Adds a 'tag' reference in `.git/refs/tags/`. The tag <name> must pass -linkgit:git-check-ref-format[1] which basicly means that control characters, -space, ~, ^, :, ?, *, [ and \ are prohibited. +Adds a tag reference in `.git/refs/tags/`. Unless `-f` is given, the tag must not yet exist in `.git/refs/tags/` directory. @@ -53,6 +51,7 @@ OPTIONS Make a GPG-signed tag, using the given key -f:: +--force:: Replace an existing tag with the given name (instead of failing) -d:: @@ -88,6 +87,12 @@ OPTIONS Implies `-a` if none of `-a`, `-s`, or `-u <key-id>` is given. +<tagname>:: + The name of the tag to create, delete, or describe. + The new tag name must pass all checks defined by + linkgit:git-check-ref-format[1]. Some of these checks + may restrict the characters allowed in a tag name. + CONFIGURATION ------------- By default, 'git-tag' in sign-with-default mode (-s) will use your @@ -252,6 +257,10 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1 ------------ +SEE ALSO +-------- +linkgit:git-check-ref-format[1]. + Author ------ Written by Linus Torvalds <torvalds@osdl.org>, diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt index d791a80819..97f7f9165e 100644 --- a/Documentation/git-verify-pack.txt +++ b/Documentation/git-verify-pack.txt @@ -25,7 +25,13 @@ OPTIONS -v:: --verbose:: After verifying the pack, show list of objects contained - in the pack. + in the pack and a histogram of delta chain length. + +-s:: +--stat-only:: + Do not verify the pack contents; only show the histogram of delta + chain length. With `--verbose`, list of objects is also shown. + \--:: Do not interpret any more arguments as options. diff --git a/Documentation/git-write-tree.txt b/Documentation/git-write-tree.txt index 26d3850e73..c8899d528a 100644 --- a/Documentation/git-write-tree.txt +++ b/Documentation/git-write-tree.txt @@ -12,7 +12,8 @@ SYNOPSIS DESCRIPTION ----------- -Creates a tree object using the current index. +Creates a tree object using the current index. The name of the new +tree object is printed to standard output. The index must be in a fully merged state. diff --git a/Documentation/git.txt b/Documentation/git.txt index a9bacfbef4..ad44cac71d 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.4.1/git.html[documentation for release 1.6.4.1] +* link:v1.6.4.2/git.html[documentation for release 1.6.4.2] * release notes for + link:RelNotes-1.6.4.2.txt[1.6.4.2], link:RelNotes-1.6.4.1.txt[1.6.4.1], link:RelNotes-1.6.4.txt[1.6.4]. @@ -16,7 +16,7 @@ all:: # when attempting to read from an fopen'ed directory. # # Define NO_OPENSSL environment variable if you do not have OpenSSL. -# This also implies MOZILLA_SHA1. +# This also implies BLK_SHA1. # # Define NO_CURL if you do not have libcurl installed. git-http-pull and # git-http-push are not built, and you cannot use http:// and https:// @@ -91,14 +91,6 @@ all:: # 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 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 NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). # # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). @@ -365,7 +357,6 @@ PROGRAMS += git-patch-id$X PROGRAMS += git-shell$X PROGRAMS += git-show-index$X PROGRAMS += git-unpack-file$X -PROGRAMS += git-update-server-info$X PROGRAMS += git-upload-pack$X PROGRAMS += git-var$X @@ -644,6 +635,7 @@ BUILTIN_OBJS += builtin-tar-tree.o BUILTIN_OBJS += builtin-unpack-objects.o BUILTIN_OBJS += builtin-update-index.o BUILTIN_OBJS += builtin-update-ref.o +BUILTIN_OBJS += builtin-update-server-info.o BUILTIN_OBJS += builtin-upload-archive.o BUILTIN_OBJS += builtin-verify-pack.o BUILTIN_OBJS += builtin-verify-tag.o @@ -757,9 +749,6 @@ ifeq ($(uname_S),SunOS) NO_C99_FORMAT = YesPlease NO_STRTOUMAX = YesPlease endif - ifdef NO_IPV6 - NEEDS_RESOLV = YesPlease - endif INSTALL = /usr/ucb/install TAR = gtar BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H @@ -928,10 +917,6 @@ else NO_PTHREADS = YesPlease endif endif -ifneq (,$(findstring arm,$(uname_M))) - ARM_SHA1 = YesPlease - NO_MKSTEMPS = YesPlease -endif -include config.mak.autogen -include config.mak @@ -1024,7 +1009,7 @@ ifndef NO_OPENSSL endif else BASIC_CFLAGS += -DNO_OPENSSL - MOZILLA_SHA1 = 1 + BLK_SHA1 = 1 OPENSSL_LIBSSL = endif ifdef NEEDS_SSL_WITH_CRYPTO @@ -1181,20 +1166,10 @@ ifdef PPC_SHA1 SHA1_HEADER = "ppc/sha1.h" LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o else -ifdef ARM_SHA1 - SHA1_HEADER = "arm/sha1.h" - LIB_OBJS += arm/sha1.o arm/sha1_arm.o -else -ifdef MOZILLA_SHA1 - SHA1_HEADER = "mozilla-sha1/sha1.h" - LIB_OBJS += mozilla-sha1/sha1.o -else SHA1_HEADER = <openssl/sha.h> EXTLIBS += $(LIB_4_CRYPTO) endif endif -endif -endif ifdef NO_PERL_MAKEMAKER export NO_PERL_MAKEMAKER endif @@ -18,7 +18,7 @@ const char *make_absolute_path(const char *path) { static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; char cwd[1024] = ""; - int buf_index = 1, len; + int buf_index = 1; int depth = MAXDEPTH; char *last_elem = NULL; @@ -50,7 +50,7 @@ const char *make_absolute_path(const char *path) die_errno ("Could not get current working directory"); if (last_elem) { - int len = strlen(buf); + size_t len = strlen(buf); if (len + strlen(last_elem) + 2 > PATH_MAX) die ("Too long path name: '%s/%s'", buf, last_elem); @@ -61,7 +61,7 @@ const char *make_absolute_path(const char *path) } if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { - len = readlink(buf, next_buf, PATH_MAX); + ssize_t len = readlink(buf, next_buf, PATH_MAX); if (len < 0) die_errno ("Invalid symlink '%s'", buf); if (PATH_MAX <= len) diff --git a/arm/sha1.c b/arm/sha1.c deleted file mode 100644 index c61ad4aff9..0000000000 --- a/arm/sha1.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SHA-1 implementation optimized for ARM - * - * Copyright: (C) 2005 by Nicolas Pitre <nico@cam.org> - * Created: September 17, 2005 - */ - -#include <string.h> -#include "sha1.h" - -extern void arm_sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W); - -void arm_SHA1_Init(arm_SHA_CTX *c) -{ - c->len = 0; - c->hash[0] = 0x67452301; - c->hash[1] = 0xefcdab89; - c->hash[2] = 0x98badcfe; - c->hash[3] = 0x10325476; - c->hash[4] = 0xc3d2e1f0; -} - -void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n) -{ - uint32_t workspace[80]; - unsigned int partial; - unsigned long done; - - partial = c->len & 0x3f; - c->len += n; - if ((partial + n) >= 64) { - if (partial) { - done = 64 - partial; - memcpy(c->buffer + partial, p, done); - arm_sha_transform(c->hash, c->buffer, workspace); - partial = 0; - } else - done = 0; - while (n >= done + 64) { - arm_sha_transform(c->hash, p + done, workspace); - done += 64; - } - } else - done = 0; - if (n - done) - memcpy(c->buffer + partial, p + done, n - done); -} - -void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c) -{ - uint64_t bitlen; - uint32_t bitlen_hi, bitlen_lo; - unsigned int i, offset, padlen; - unsigned char bits[8]; - static const unsigned char padding[64] = { 0x80, }; - - bitlen = c->len << 3; - offset = c->len & 0x3f; - padlen = ((offset < 56) ? 56 : (64 + 56)) - offset; - arm_SHA1_Update(c, padding, padlen); - - bitlen_hi = bitlen >> 32; - bitlen_lo = bitlen & 0xffffffff; - bits[0] = bitlen_hi >> 24; - bits[1] = bitlen_hi >> 16; - bits[2] = bitlen_hi >> 8; - bits[3] = bitlen_hi; - bits[4] = bitlen_lo >> 24; - bits[5] = bitlen_lo >> 16; - bits[6] = bitlen_lo >> 8; - bits[7] = bitlen_lo; - arm_SHA1_Update(c, bits, 8); - - for (i = 0; i < 5; i++) { - uint32_t v = c->hash[i]; - hash[0] = v >> 24; - hash[1] = v >> 16; - hash[2] = v >> 8; - hash[3] = v; - hash += 4; - } -} diff --git a/arm/sha1.h b/arm/sha1.h deleted file mode 100644 index b61b618486..0000000000 --- a/arm/sha1.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SHA-1 implementation optimized for ARM - * - * Copyright: (C) 2005 by Nicolas Pitre <nico@cam.org> - * Created: September 17, 2005 - */ - -#include <stdint.h> - -typedef struct { - uint64_t len; - uint32_t hash[5]; - unsigned char buffer[64]; -} arm_SHA_CTX; - -void arm_SHA1_Init(arm_SHA_CTX *c); -void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n); -void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c); - -#define git_SHA_CTX arm_SHA_CTX -#define git_SHA1_Init arm_SHA1_Init -#define git_SHA1_Update arm_SHA1_Update -#define git_SHA1_Final arm_SHA1_Final diff --git a/arm/sha1_arm.S b/arm/sha1_arm.S deleted file mode 100644 index 41e92636e0..0000000000 --- a/arm/sha1_arm.S +++ /dev/null @@ -1,183 +0,0 @@ -/* - * SHA transform optimized for ARM - * - * Copyright: (C) 2005 by Nicolas Pitre <nico@cam.org> - * Created: September 17, 2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - .text - .globl arm_sha_transform - -/* - * void sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W); - * - * note: the "data" pointer may be unaligned. - */ - -arm_sha_transform: - - stmfd sp!, {r4 - r8, lr} - - @ for (i = 0; i < 16; i++) - @ W[i] = ntohl(((uint32_t *)data)[i]); - -#ifdef __ARMEB__ - mov r4, r0 - mov r0, r2 - mov r2, #64 - bl memcpy - mov r2, r0 - mov r0, r4 -#else - mov r3, r2 - mov lr, #16 -1: ldrb r4, [r1], #1 - ldrb r5, [r1], #1 - ldrb r6, [r1], #1 - ldrb r7, [r1], #1 - subs lr, lr, #1 - orr r5, r5, r4, lsl #8 - orr r6, r6, r5, lsl #8 - orr r7, r7, r6, lsl #8 - str r7, [r3], #4 - bne 1b -#endif - - @ for (i = 0; i < 64; i++) - @ W[i+16] = ror(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 31); - - sub r3, r2, #4 - mov lr, #64 -2: ldr r4, [r3, #4]! - subs lr, lr, #1 - ldr r5, [r3, #8] - ldr r6, [r3, #32] - ldr r7, [r3, #52] - eor r4, r4, r5 - eor r4, r4, r6 - eor r4, r4, r7 - mov r4, r4, ror #31 - str r4, [r3, #64] - bne 2b - - /* - * The SHA functions are: - * - * f1(B,C,D) = (D ^ (B & (C ^ D))) - * f2(B,C,D) = (B ^ C ^ D) - * f3(B,C,D) = ((B & C) | (D & (B | C))) - * - * Then the sub-blocks are processed as follows: - * - * A' = ror(A, 27) + f(B,C,D) + E + K + *W++ - * B' = A - * C' = ror(B, 2) - * D' = C - * E' = D - * - * We therefore unroll each loop 5 times to avoid register shuffling. - * Also the ror for C (and also D and E which are successivelyderived - * from it) is applied in place to cut on an additional mov insn for - * each round. - */ - - .macro sha_f1, A, B, C, D, E - ldr r3, [r2], #4 - eor ip, \C, \D - add \E, r1, \E, ror #2 - and ip, \B, ip, ror #2 - add \E, \E, \A, ror #27 - eor ip, ip, \D, ror #2 - add \E, \E, r3 - add \E, \E, ip - .endm - - .macro sha_f2, A, B, C, D, E - ldr r3, [r2], #4 - add \E, r1, \E, ror #2 - eor ip, \B, \C, ror #2 - add \E, \E, \A, ror #27 - eor ip, ip, \D, ror #2 - add \E, \E, r3 - add \E, \E, ip - .endm - - .macro sha_f3, A, B, C, D, E - ldr r3, [r2], #4 - add \E, r1, \E, ror #2 - orr ip, \B, \C, ror #2 - add \E, \E, \A, ror #27 - and ip, ip, \D, ror #2 - add \E, \E, r3 - and r3, \B, \C, ror #2 - orr ip, ip, r3 - add \E, \E, ip - .endm - - ldmia r0, {r4 - r8} - - mov lr, #4 - ldr r1, .L_sha_K + 0 - - /* adjust initial values */ - mov r6, r6, ror #30 - mov r7, r7, ror #30 - mov r8, r8, ror #30 - -3: subs lr, lr, #1 - sha_f1 r4, r5, r6, r7, r8 - sha_f1 r8, r4, r5, r6, r7 - sha_f1 r7, r8, r4, r5, r6 - sha_f1 r6, r7, r8, r4, r5 - sha_f1 r5, r6, r7, r8, r4 - bne 3b - - ldr r1, .L_sha_K + 4 - mov lr, #4 - -4: subs lr, lr, #1 - sha_f2 r4, r5, r6, r7, r8 - sha_f2 r8, r4, r5, r6, r7 - sha_f2 r7, r8, r4, r5, r6 - sha_f2 r6, r7, r8, r4, r5 - sha_f2 r5, r6, r7, r8, r4 - bne 4b - - ldr r1, .L_sha_K + 8 - mov lr, #4 - -5: subs lr, lr, #1 - sha_f3 r4, r5, r6, r7, r8 - sha_f3 r8, r4, r5, r6, r7 - sha_f3 r7, r8, r4, r5, r6 - sha_f3 r6, r7, r8, r4, r5 - sha_f3 r5, r6, r7, r8, r4 - bne 5b - - ldr r1, .L_sha_K + 12 - mov lr, #4 - -6: subs lr, lr, #1 - sha_f2 r4, r5, r6, r7, r8 - sha_f2 r8, r4, r5, r6, r7 - sha_f2 r7, r8, r4, r5, r6 - sha_f2 r6, r7, r8, r4, r5 - sha_f2 r5, r6, r7, r8, r4 - bne 6b - - ldmia r0, {r1, r2, r3, ip, lr} - add r4, r1, r4 - add r5, r2, r5 - add r6, r3, r6, ror #2 - add r7, ip, r7, ror #2 - add r8, lr, r8, ror #2 - stmia r0, {r4 - r8} - - ldmfd sp!, {r4 - r8, pc} - -.L_sha_K: - .word 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 @@ -991,7 +991,7 @@ int bisect_next_all(const char *prefix) if (!hashcmp(bisect_rev, current_bad_sha1)) { exit_if_skipped_commits(tried, current_bad_sha1); - printf("%s is first bad commit\n", bisect_rev_hex); + printf("%s is the first bad commit\n", bisect_rev_hex); show_diff_tree(prefix, revs.commits->item); /* This means the bisection process succeeded. */ exit(10); diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c index 464cb258aa..d8934757a5 100644 --- a/block-sha1/sha1.c +++ b/block-sha1/sha1.c @@ -1,15 +1,17 @@ /* - * Based on the Mozilla SHA1 (see mozilla-sha1/sha1.c), - * optimized to do word accesses rather than byte accesses, + * SHA1 routine optimized to do word accesses rather than byte accesses, * and to avoid unnecessary copies into the context array. + * + * This was initially based on the Mozilla SHA1 implementation, although + * none of the original Mozilla code remains. */ -#include <string.h> -#include <arpa/inet.h> +/* this is only to get definitions for memcpy(), ntohl() and htonl() */ +#include "../git-compat-util.h" #include "sha1.h" -#if defined(__i386__) || defined(__x86_64__) +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) /* * Force usage of rol or ror by selecting the one with the smaller constant. @@ -54,7 +56,7 @@ #if defined(__i386__) || defined(__x86_64__) #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val)) -#elif defined(__arm__) +#elif defined(__GNUC__) && defined(__arm__) #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) #else #define setW(x, val) (W(x) = (val)) diff --git a/block-sha1/sha1.h b/block-sha1/sha1.h index c1ae74d3da..b864df623e 100644 --- a/block-sha1/sha1.h +++ b/block-sha1/sha1.h @@ -1,13 +1,15 @@ /* - * Based on the Mozilla SHA1 (see mozilla-sha1/sha1.h), - * optimized to do word accesses rather than byte accesses, + * SHA1 routine optimized to do word accesses rather than byte accesses, * and to avoid unnecessary copies into the context array. + * + * This was initially based on the Mozilla SHA1 implementation, although + * none of the original Mozilla code remains. */ typedef struct { + unsigned long long size; unsigned int H[5]; unsigned int W[16]; - unsigned long long size; } blk_SHA_CTX; void blk_SHA1_Init(blk_SHA_CTX *ctx); diff --git a/builtin-add.c b/builtin-add.c index 581a2a1748..006fd08769 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -105,8 +105,8 @@ static void refresh(int verbose, const char **pathspec) for (specs = 0; pathspec[specs]; specs++) /* nothing */; seen = xcalloc(specs, 1); - refresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET, - pathspec, seen); + refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET, + pathspec, seen, "Unstaged changes after refreshing the index:"); for (i = 0; i < specs; i++) { if (!seen[i]) die("pathspec '%s' did not match any files", pathspec[i]); diff --git a/builtin-branch.c b/builtin-branch.c index 1a03d5f356..9f57992062 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -586,7 +586,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_BIT('m', NULL, &rename, "move/rename a branch and its reflog", 1), OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2), OPT_BOOLEAN('l', NULL, &reflog, "create the branch's reflog"), - OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"), + OPT_BOOLEAN('f', "force", &force_create, "force creation (when already exists)"), { OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref, "commit", "print only not merged branches", diff --git a/builtin-checkout.c b/builtin-checkout.c index 8a9a474218..36e2116ea2 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -402,7 +402,9 @@ static int merge_working_tree(struct checkout_opts *opts, topts.dir = xcalloc(1, sizeof(*topts.dir)); topts.dir->flags |= DIR_SHOW_IGNORED; topts.dir->exclude_per_dir = ".gitignore"; - tree = parse_tree_indirect(old->commit->object.sha1); + tree = parse_tree_indirect(old->commit ? + old->commit->object.sha1 : + (unsigned char *)EMPTY_TREE_SHA1_BIN); init_tree_desc(&trees[0], tree->buffer, tree->size); tree = parse_tree_indirect(new->commit->object.sha1); init_tree_desc(&trees[1], tree->buffer, tree->size); @@ -541,14 +543,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) parse_commit(new->commit); } - if (!old.commit && !opts->force) { - if (!opts->quiet) { - warning("You appear to be on a branch yet to be born."); - warning("Forcing checkout of %s.", new->name); - } - opts->force = 1; - } - ret = merge_working_tree(opts, &old, new); if (ret) return ret; @@ -590,7 +584,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) 2), OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage", 3), - OPT_BOOLEAN('f', NULL, &opts.force, "force"), + OPT_BOOLEAN('f', "force", &opts.force, "force"), OPT_BOOLEAN('m', "merge", &opts.merge, "merge"), OPT_STRING(0, "conflict", &conflict_style, "style", "conflict style (merge or diff3)"), diff --git a/builtin-clean.c b/builtin-clean.c index 05c763cbec..28cdcd0274 100644 --- a/builtin-clean.c +++ b/builtin-clean.c @@ -41,7 +41,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) struct option options[] = { OPT__QUIET(&quiet), OPT__DRY_RUN(&show_only), - OPT_BOOLEAN('f', NULL, &force, "force"), + OPT_BOOLEAN('f', "force", &force, "force"), OPT_BOOLEAN('d', NULL, &remove_directories, "remove whole directories"), OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"), diff --git a/builtin-clone.c b/builtin-clone.c index 32dea74d78..0d2b4a8200 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -38,7 +38,7 @@ static const char * const builtin_clone_usage[] = { }; static int option_quiet, option_no_checkout, option_bare, option_mirror; -static int option_local, option_no_hardlinks, option_shared; +static int option_local, option_no_hardlinks, option_shared, option_recursive; static char *option_template, *option_reference, *option_depth; static char *option_origin = NULL; static char *option_upload_pack = "git-upload-pack"; @@ -59,6 +59,8 @@ static struct option builtin_clone_options[] = { "don't use local hardlinks, always copy"), OPT_BOOLEAN('s', "shared", &option_shared, "setup as shared repository"), + OPT_BOOLEAN(0, "recursive", &option_recursive, + "setup as shared repository"), OPT_STRING(0, "template", &option_template, "path", "path the template repository"), OPT_STRING(0, "reference", &option_reference, "repo", @@ -73,6 +75,10 @@ static struct option builtin_clone_options[] = { OPT_END() }; +static const char *argv_submodule[] = { + "submodule", "update", "--init", "--recursive", NULL +}; + static char *get_repo_path(const char *repo, int *is_bundle) { static char *suffix[] = { "/.git", ".git", "" }; @@ -608,6 +614,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1), sha1_to_hex(remote_head->old_sha1), "1", NULL); + + if (!err && option_recursive) + err = run_command_v_opt(argv_submodule, RUN_GIT_CMD); } strbuf_release(&reflog_msg); diff --git a/builtin-commit.c b/builtin-commit.c index 4bcce06fbf..200ffdaad4 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -51,7 +51,7 @@ static const char *template_file; static char *edit_message, *use_message; static char *author_name, *author_email, *author_date; static int all, edit_flag, also, interactive, only, amend, signoff; -static int quiet, verbose, no_verify, allow_empty; +static int quiet, verbose, no_verify, allow_empty, dry_run; static char *untracked_files_arg; /* * The default commit message cleanup mode will remove the lines @@ -103,6 +103,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"), OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), + OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), @@ -217,12 +218,15 @@ static void create_base_index(void) exit(128); /* We've already reported the error, finish dying */ } -static char *prepare_index(int argc, const char **argv, const char *prefix) +static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status) { int fd; struct string_list partial; const char **pathspec = NULL; + int refresh_flags = REFRESH_QUIET; + if (is_status) + refresh_flags |= REFRESH_UNMERGED; if (interactive) { if (interactive_add(argc, argv, prefix) != 0) die("interactive add failed"); @@ -253,7 +257,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) if (all || (also && pathspec && *pathspec)) { int fd = hold_locked_index(&index_lock, 1); add_files_to_cache(also ? prefix : NULL, pathspec, 0); - refresh_cache(REFRESH_QUIET); + refresh_cache(refresh_flags); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) die("unable to write new_index file"); @@ -272,7 +276,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) */ if (!pathspec || !*pathspec) { fd = hold_locked_index(&index_lock, 1); - refresh_cache(REFRESH_QUIET); + refresh_cache(refresh_flags); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(&index_lock)) die("unable to write new_index file"); @@ -339,27 +343,24 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) return false_lock.filename; } -static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn) +static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn, + struct wt_status *s) { - struct wt_status s; - - wt_status_prepare(&s); - if (wt_status_relative_paths) - s.prefix = prefix; + if (s->relative_paths) + s->prefix = prefix; if (amend) { - s.amend = 1; - s.reference = "HEAD^1"; + s->amend = 1; + s->reference = "HEAD^1"; } - s.verbose = verbose; - s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES); - s.index_file = index_file; - s.fp = fp; - s.nowarn = nowarn; + s->verbose = verbose; + s->index_file = index_file; + s->fp = fp; + s->nowarn = nowarn; - wt_status_print(&s); + wt_status_print(s); - return s.commitable; + return s->commitable; } static int is_a_merge(const unsigned char *sha1) @@ -413,7 +414,8 @@ static void determine_author_info(void) author_date = date; } -static int prepare_to_commit(const char *index_file, const char *prefix) +static int prepare_to_commit(const char *index_file, const char *prefix, + struct wt_status *s) { struct stat statbuf; int commitable, saved_color_setting; @@ -555,10 +557,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix) if (ident_shown) fprintf(fp, "#\n"); - saved_color_setting = wt_status_use_color; - wt_status_use_color = 0; - commitable = run_status(fp, index_file, prefix, 1); - wt_status_use_color = saved_color_setting; + saved_color_setting = s->use_color; + s->use_color = 0; + commitable = run_status(fp, index_file, prefix, 1, s); + s->use_color = saved_color_setting; } else { unsigned char sha1[20]; const char *parent = "HEAD"; @@ -579,7 +581,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) if (!commitable && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { - run_status(stdout, index_file, prefix, 0); + run_status(stdout, index_file, prefix, 0, s); return 0; } @@ -691,7 +693,8 @@ static const char *find_author_by_nickname(const char *name) static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], - const char *prefix) + const char *prefix, + struct wt_status *s) { int f = 0; @@ -794,11 +797,11 @@ static int parse_and_validate_options(int argc, const char *argv[], if (!untracked_files_arg) ; /* default already initialized */ else if (!strcmp(untracked_files_arg, "no")) - show_untracked_files = SHOW_NO_UNTRACKED_FILES; + s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; else if (!strcmp(untracked_files_arg, "normal")) - show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; else if (!strcmp(untracked_files_arg, "all")) - show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; else die("Invalid untracked files mode '%s'", untracked_files_arg); @@ -810,28 +813,93 @@ static int parse_and_validate_options(int argc, const char *argv[], return argc; } -int cmd_status(int argc, const char **argv, const char *prefix) +static int dry_run_commit(int argc, const char **argv, const char *prefix, + struct wt_status *s) { - const char *index_file; int commitable; + const char *index_file; - git_config(git_status_config, NULL); + index_file = prepare_index(argc, argv, prefix, 1); + commitable = run_status(stdout, index_file, prefix, 0, s); + rollback_index_files(); - if (wt_status_use_color == -1) - wt_status_use_color = git_use_color_default; + return commitable ? 0 : 1; +} - if (diff_use_color_default == -1) - diff_use_color_default = git_use_color_default; +static int parse_status_slot(const char *var, int offset) +{ + if (!strcasecmp(var+offset, "header")) + return WT_STATUS_HEADER; + if (!strcasecmp(var+offset, "updated") + || !strcasecmp(var+offset, "added")) + return WT_STATUS_UPDATED; + if (!strcasecmp(var+offset, "changed")) + return WT_STATUS_CHANGED; + if (!strcasecmp(var+offset, "untracked")) + return WT_STATUS_UNTRACKED; + if (!strcasecmp(var+offset, "nobranch")) + return WT_STATUS_NOBRANCH; + if (!strcasecmp(var+offset, "unmerged")) + return WT_STATUS_UNMERGED; + die("bad config variable '%s'", var); +} - argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix); +static int git_status_config(const char *k, const char *v, void *cb) +{ + struct wt_status *s = cb; - index_file = prepare_index(argc, argv, prefix); + if (!strcmp(k, "status.submodulesummary")) { + int is_bool; + s->submodule_summary = git_config_bool_or_int(k, v, &is_bool); + if (is_bool && s->submodule_summary) + s->submodule_summary = -1; + return 0; + } + if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { + s->use_color = git_config_colorbool(k, v, -1); + return 0; + } + if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { + int slot = parse_status_slot(k, 13); + if (!v) + return config_error_nonbool(k); + color_parse(v, k, s->color_palette[slot]); + return 0; + } + if (!strcmp(k, "status.relativepaths")) { + s->relative_paths = git_config_bool(k, v); + return 0; + } + if (!strcmp(k, "status.showuntrackedfiles")) { + if (!v) + return config_error_nonbool(k); + else if (!strcmp(v, "no")) + s->show_untracked_files = SHOW_NO_UNTRACKED_FILES; + else if (!strcmp(v, "normal")) + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + else if (!strcmp(v, "all")) + s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + else + return error("Invalid untracked files mode '%s'", v); + return 0; + } + return git_diff_ui_config(k, v, NULL); +} - commitable = run_status(stdout, index_file, prefix, 0); +int cmd_status(int argc, const char **argv, const char *prefix) +{ + struct wt_status s; - rollback_index_files(); + wt_status_prepare(&s); + git_config(git_status_config, &s); + if (s.use_color == -1) + s.use_color = git_use_color_default; + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; - return commitable ? 0 : 1; + argc = parse_and_validate_options(argc, argv, builtin_status_usage, + prefix, &s); + return dry_run_commit(argc, argv, prefix, &s); } static void print_summary(const char *prefix, const unsigned char *sha1) @@ -883,10 +951,12 @@ static void print_summary(const char *prefix, const unsigned char *sha1) static int git_commit_config(const char *k, const char *v, void *cb) { + struct wt_status *s = cb; + if (!strcmp(k, "commit.template")) return git_config_string(&template_file, k, v); - return git_status_config(k, v, cb); + return git_status_config(k, v, s); } int cmd_commit(int argc, const char **argv, const char *prefix) @@ -899,19 +969,26 @@ int cmd_commit(int argc, const char **argv, const char *prefix) struct commit_list *parents = NULL, **pptr = &parents; struct stat statbuf; int allow_fast_forward = 1; + struct wt_status s; - git_config(git_commit_config, NULL); - - if (wt_status_use_color == -1) - wt_status_use_color = git_use_color_default; + wt_status_prepare(&s); + git_config(git_commit_config, &s); - argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix); + if (s.use_color == -1) + s.use_color = git_use_color_default; - index_file = prepare_index(argc, argv, prefix); + argc = parse_and_validate_options(argc, argv, builtin_commit_usage, + prefix, &s); + if (dry_run) { + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + return dry_run_commit(argc, argv, prefix, &s); + } + index_file = prepare_index(argc, argv, prefix, 0); /* Set up everything for writing the commit object. This includes running hooks, writing the trees, and interacting with the user. */ - if (!prepare_to_commit(index_file, prefix)) { + if (!prepare_to_commit(index_file, prefix, &s)) { rollback_index_files(); return 1; } diff --git a/builtin-log.c b/builtin-log.c index 82236c531b..25e21ed415 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -35,6 +35,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, struct rev_info *rev) { int i; + int decoration_style = 0; rev->abbrev = DEFAULT_ABBREV; rev->commit_format = CMIT_FMT_DEFAULT; @@ -61,8 +62,15 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "--decorate")) { - load_ref_decorations(); - rev->show_decorations = 1; + decoration_style = DECORATE_SHORT_REFS; + } else if (!prefixcmp(arg, "--decorate=")) { + const char *v = skip_prefix(arg, "--decorate="); + if (!strcmp(v, "full")) + decoration_style = DECORATE_FULL_REFS; + else if (!strcmp(v, "short")) + decoration_style = DECORATE_SHORT_REFS; + else + die("invalid --decorate option: %s", arg); } else if (!strcmp(arg, "--source")) { rev->show_source = 1; } else if (!strcmp(arg, "-h")) { @@ -70,6 +78,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, } else die("unrecognized argument: %s", arg); } + if (decoration_style) { + rev->show_decorations = 1; + load_ref_decorations(decoration_style); + } } /* diff --git a/builtin-mv.c b/builtin-mv.c index b592c367b2..1b20028c67 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -53,7 +53,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; struct option builtin_mv_options[] = { OPT__DRY_RUN(&show_only), - OPT_BOOLEAN('f', NULL, &force, "force move/rename even if target exists"), + OPT_BOOLEAN('f', "force", &force, "force move/rename even if target exists"), OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"), OPT_END(), }; diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 9c2d634d6d..14c836b169 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -113,13 +113,15 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) argc = parse_options(argc, argv, unused_prefix, read_tree_options, read_tree_usage, 0); - if (read_cache_unmerged() && (opts.prefix || opts.merge)) - die("You need to resolve your current index first"); - prefix_set = opts.prefix ? 1 : 0; if (1 < opts.merge + opts.reset + prefix_set) die("Which one? -m, --reset, or --prefix?"); - stage = opts.merge = (opts.reset || opts.merge || prefix_set); + + if (opts.reset || opts.merge || opts.prefix) { + if (read_cache_unmerged() && (opts.prefix || opts.merge)) + die("You need to resolve your current index first"); + stage = opts.merge = 1; + } for (i = 0; i < argc; i++) { const char *arg = argv[i]; diff --git a/builtin-reset.c b/builtin-reset.c index 5fa1789d0c..0fc0b0743f 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -108,7 +108,8 @@ static int update_index_refresh(int fd, struct lock_file *index_lock, int flags) if (read_cache() < 0) return error("Could not read index"); - result = refresh_cache(flags) ? 1 : 0; + result = refresh_index(&the_index, (flags), NULL, NULL, + "Unstaged changes after reset:") ? 1 : 0; if (write_cache(fd, active_cache, active_nr) || commit_locked_index(index_lock)) return error ("Could not refresh index"); @@ -261,7 +262,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) die("Cannot do %s reset with paths.", reset_type_names[reset_type]); return read_from_tree(prefix, argv + i, sha1, - quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED); + quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN); } if (reset_type == NONE) reset_type = MIXED; /* by default */ @@ -302,7 +303,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) break; case MIXED: /* Report what has not been updated. */ update_index_refresh(0, NULL, - quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED); + quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN); break; } diff --git a/builtin-tag.c b/builtin-tag.c index a51a6d1ea2..c4790185eb 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -390,7 +390,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"), OPT_STRING('u', NULL, &keyid, "key-id", "use another key to sign the tag"), - OPT_BOOLEAN('f', NULL, &force, "replace the tag if exists"), + OPT_BOOLEAN('f', "force", &force, "replace the tag if exists"), OPT_GROUP("Tag listing options"), { diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 968fda7219..685566e0b5 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -181,10 +181,10 @@ static void write_cached_object(struct object *obj) static int check_object(struct object *obj, int type, void *data) { if (!obj) - return 0; + return 1; if (obj->flags & FLAG_WRITTEN) - return 1; + return 0; if (type != OBJ_ANY && obj->type != type) die("object type mismatch"); @@ -195,22 +195,24 @@ static int check_object(struct object *obj, int type, void *data) if (type != obj->type || type <= 0) die("object of unexpected type"); obj->flags |= FLAG_WRITTEN; - return 1; + return 0; } if (fsck_object(obj, 1, fsck_error_function)) die("Error in object"); - if (!fsck_walk(obj, check_object, NULL)) + if (fsck_walk(obj, check_object, NULL)) die("Error on reachable objects of %s", sha1_to_hex(obj->sha1)); write_cached_object(obj); - return 1; + return 0; } static void write_rest(void) { unsigned i; - for (i = 0; i < nr_objects; i++) - check_object(obj_list[i].obj, OBJ_ANY, NULL); + for (i = 0; i < nr_objects; i++) { + if (obj_list[i].obj) + check_object(obj_list[i].obj, OBJ_ANY, NULL); + } } static void added_object(unsigned nr, enum object_type type, diff --git a/builtin-update-server-info.c b/builtin-update-server-info.c new file mode 100644 index 0000000000..2b3fddcc69 --- /dev/null +++ b/builtin-update-server-info.c @@ -0,0 +1,25 @@ +#include "cache.h" +#include "builtin.h" +#include "parse-options.h" + +static const char * const update_server_info_usage[] = { + "git update-server-info [--force]", + NULL +}; + +int cmd_update_server_info(int argc, const char **argv, const char *prefix) +{ + int force = 0; + struct option options[] = { + OPT_BOOLEAN('f', "force", &force, + "update the info files from scratch"), + OPT_END() + }; + + argc = parse_options(argc, argv, prefix, options, + update_server_info_usage, 0); + if (argc > 0) + usage_with_options(update_server_info_usage, options); + + return !!update_server_info(force); +} diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c index b5bd28e959..b6079ae6cb 100644 --- a/builtin-verify-pack.c +++ b/builtin-verify-pack.c @@ -6,10 +6,14 @@ #define MAX_CHAIN 50 -static void show_pack_info(struct packed_git *p) +#define VERIFY_PACK_VERBOSE 01 +#define VERIFY_PACK_STAT_ONLY 02 + +static void show_pack_info(struct packed_git *p, unsigned int flags) { uint32_t nr_objects, i; int cnt; + int stat_only = flags & VERIFY_PACK_STAT_ONLY; unsigned long chain_histogram[MAX_CHAIN+1], baseobjects; nr_objects = p->num_objects; @@ -32,16 +36,19 @@ static void show_pack_info(struct packed_git *p) type = packed_object_info_detail(p, offset, &size, &store_size, &delta_chain_length, base_sha1); - printf("%s ", sha1_to_hex(sha1)); + if (!stat_only) + printf("%s ", sha1_to_hex(sha1)); if (!delta_chain_length) { - printf("%-6s %lu %lu %"PRIuMAX"\n", - type, size, store_size, (uintmax_t)offset); + if (!stat_only) + printf("%-6s %lu %lu %"PRIuMAX"\n", + type, size, store_size, (uintmax_t)offset); baseobjects++; } else { - printf("%-6s %lu %lu %"PRIuMAX" %u %s\n", - type, size, store_size, (uintmax_t)offset, - delta_chain_length, sha1_to_hex(base_sha1)); + if (!stat_only) + printf("%-6s %lu %lu %"PRIuMAX" %u %s\n", + type, size, store_size, (uintmax_t)offset, + delta_chain_length, sha1_to_hex(base_sha1)); if (delta_chain_length <= MAX_CHAIN) chain_histogram[delta_chain_length]++; else @@ -66,10 +73,12 @@ static void show_pack_info(struct packed_git *p) chain_histogram[0] > 1 ? "s" : ""); } -static int verify_one_pack(const char *path, int verbose) +static int verify_one_pack(const char *path, unsigned int flags) { char arg[PATH_MAX]; int len; + int verbose = flags & VERIFY_PACK_VERBOSE; + int stat_only = flags & VERIFY_PACK_STAT_ONLY; struct packed_git *pack; int err; @@ -105,14 +114,19 @@ static int verify_one_pack(const char *path, int verbose) return error("packfile %s not found.", arg); install_packed_git(pack); - err = verify_pack(pack); - if (verbose) { + if (!stat_only) + err = verify_pack(pack); + else + err = open_pack_index(pack); + + if (verbose || stat_only) { if (err) printf("%s: bad\n", pack->pack_name); else { - show_pack_info(pack); - printf("%s: ok\n", pack->pack_name); + show_pack_info(pack, flags); + if (!stat_only) + printf("%s: ok\n", pack->pack_name); } } @@ -120,17 +134,20 @@ static int verify_one_pack(const char *path, int verbose) } static const char * const verify_pack_usage[] = { - "git verify-pack [-v|--verbose] <pack>...", + "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>...", NULL }; int cmd_verify_pack(int argc, const char **argv, const char *prefix) { int err = 0; - int verbose = 0; + unsigned int flags = 0; int i; const struct option verify_pack_options[] = { - OPT__VERBOSE(&verbose), + OPT_BIT('v', "verbose", &flags, "verbose", + VERIFY_PACK_VERBOSE), + OPT_BIT('s', "stat-only", &flags, "show statistics only", + VERIFY_PACK_STAT_ONLY), OPT_END() }; @@ -140,7 +157,7 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix) if (argc < 1) usage_with_options(verify_pack_usage, verify_pack_options); for (i = 0; i < argc; i++) { - if (verify_one_pack(argv[i], verbose)) + if (verify_one_pack(argv[i], flags)) err = 1; discard_revindex(); } @@ -102,6 +102,7 @@ extern int cmd_tar_tree(int argc, const char **argv, const char *prefix); extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix); extern int cmd_update_index(int argc, const char **argv, const char *prefix); extern int cmd_update_ref(int argc, const char **argv, const char *prefix); +extern int cmd_update_server_info(int argc, const char **argv, const char *prefix); extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); extern int cmd_upload_tar(int argc, const char **argv, const char *prefix); extern int cmd_verify_tag(int argc, const char **argv, const char *prefix); @@ -330,7 +330,7 @@ static inline void remove_name_hash(struct cache_entry *ce) #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path)) #define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags)) #define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags)) -#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL) +#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL) #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options)) #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options)) #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase)) @@ -469,15 +469,15 @@ extern int index_path(unsigned char *sha1, const char *path, struct stat *st, in extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); /* "careful lstat()" */ -extern int check_path(const char *path, int len, struct stat *st); +extern int check_path(const char *path, int len, struct stat *st, int skiplen); #define REFRESH_REALLY 0x0001 /* ignore_valid */ #define REFRESH_UNMERGED 0x0002 /* allow unmerged */ #define REFRESH_QUIET 0x0004 /* be quiet about it */ #define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */ #define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */ -#define REFRESH_SAY_CHANGED 0x0020 /* say "changed" not "needs update" */ -extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen); +#define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */ +extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg); struct lock_file { struct lock_file *next; @@ -564,13 +564,13 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co while (interesting(list)) { struct commit *commit; struct commit_list *parents; - struct commit_list *n; + struct commit_list *next; int flags; commit = list->item; - n = list->next; + next = list->next; free(list); - list = n; + list = next; flags = commit->object.flags & (PARENT1 | PARENT2 | STALE); if (flags == (PARENT1 | PARENT2)) { @@ -598,11 +598,11 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co free_commit_list(list); list = result; result = NULL; while (list) { - struct commit_list *n = list->next; + struct commit_list *next = list->next; if (!(list->item->object.flags & STALE)) insert_by_date(list->item, &result); free(list); - list = n; + list = next; } return result; } diff --git a/compat/bswap.h b/compat/bswap.h new file mode 100644 index 0000000000..7246a12c6e --- /dev/null +++ b/compat/bswap.h @@ -0,0 +1,36 @@ +/* + * Let's make sure we always have a sane definition for ntohl()/htonl(). + * Some libraries define those as a function call, just to perform byte + * shifting, bringing significant overhead to what should be a simple + * operation. + */ + +/* + * Default version that the compiler ought to optimize properly with + * constant values. + */ +static inline unsigned int default_swab32(unsigned int val) +{ + return (((val & 0xff000000) >> 24) | + ((val & 0x00ff0000) >> 8) | + ((val & 0x0000ff00) << 8) | + ((val & 0x000000ff) << 24)); +} + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#define bswap32(x) ({ \ + unsigned int __res; \ + if (__builtin_constant_p(x)) { \ + __res = default_swab32(x); \ + } else { \ + __asm__("bswap %0" : "=r" (__res) : "0" (x)); \ + } \ + __res; }) + +#undef ntohl +#undef htonl +#define ntohl(x) bswap32(x) +#define htonl(x) bswap32(x) + +#endif diff --git a/configure.ac b/configure.ac index 3f1922d0bf..b09b8e446f 100644 --- a/configure.ac +++ b/configure.ac @@ -156,19 +156,11 @@ AC_MSG_NOTICE([CHECKS for site configuration]) # 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. +# This also implies BLK_SHA1. # # Define OPENSSLDIR=/foo/bar if your openssl header and library files are in # /foo/bar/include and /foo/bar/lib directories. diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index 342529db30..38438f3c4a 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -201,7 +201,7 @@ def isModeExec(mode): def isModeExecChanged(src_mode, dst_mode): return isModeExec(src_mode) != isModeExec(dst_mode) -def p4CmdList(cmd, stdin=None, stdin_mode='w+b'): +def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None): cmd = p4_build_cmd("-G %s" % (cmd)) if verbose: sys.stderr.write("Opening pipe: %s\n" % cmd) @@ -224,7 +224,10 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b'): try: while True: entry = marshal.load(p4.stdout) - result.append(entry) + if cb is not None: + cb(entry) + else: + result.append(entry) except EOFError: pass exitCode = p4.wait() @@ -950,10 +953,84 @@ class P4Sync(Command): return branches - ## Should move this out, doesn't use SELF. - def readP4Files(self, files): + # output one file from the P4 stream + # - helper for streamP4Files + + def streamOneP4File(self, file, contents): + if file["type"] == "apple": + print "\nfile %s is a strange apple file that forks. Ignoring" % \ + file['depotFile'] + return + + relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes) + if verbose: + sys.stderr.write("%s\n" % relPath) + + mode = "644" + if isP4Exec(file["type"]): + mode = "755" + elif file["type"] == "symlink": + mode = "120000" + # p4 print on a symlink contains "target\n", so strip it off + last = contents.pop() + last = last[:-1] + contents.append(last) + + if self.isWindows and file["type"].endswith("text"): + mangled = [] + for data in contents: + data = data.replace("\r\n", "\n") + mangled.append(data) + contents = mangled + + if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'): + contents = map(lambda text: re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text), contents) + elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'): + contents = map(lambda text: re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text), contents) + + self.gitStream.write("M %s inline %s\n" % (mode, relPath)) + + # total length... + length = 0 + for d in contents: + length = length + len(d) + + self.gitStream.write("data %d\n" % length) + for d in contents: + self.gitStream.write(d) + self.gitStream.write("\n") + + def streamOneP4Deletion(self, file): + relPath = self.stripRepoPath(file['path'], self.branchPrefixes) + if verbose: + sys.stderr.write("delete %s\n" % relPath) + self.gitStream.write("D %s\n" % relPath) + + # handle another chunk of streaming data + def streamP4FilesCb(self, marshalled): + + if marshalled.has_key('depotFile') and self.stream_have_file_info: + # start of a new file - output the old one first + self.streamOneP4File(self.stream_file, self.stream_contents) + self.stream_file = {} + self.stream_contents = [] + self.stream_have_file_info = False + + # pick up the new file information... for the + # 'data' field we need to append to our array + for k in marshalled.keys(): + if k == 'data': + self.stream_contents.append(marshalled['data']) + else: + self.stream_file[k] = marshalled[k] + + self.stream_have_file_info = True + + # Stream directly from "p4 files" into "git fast-import" + def streamP4Files(self, files): filesForCommit = [] filesToRead = [] + filesToDelete = [] for f in files: includeFile = True @@ -967,50 +1044,35 @@ class P4Sync(Command): filesForCommit.append(f) if f['action'] not in ('delete', 'purge'): filesToRead.append(f) + else: + filesToDelete.append(f) - filedata = [] - if len(filesToRead) > 0: - filedata = p4CmdList('-x - print', - stdin='\n'.join(['%s#%s' % (f['path'], f['rev']) - for f in filesToRead]), - stdin_mode='w+') - - if "p4ExitCode" in filedata[0]: - die("Problems executing p4. Error: [%d]." - % (filedata[0]['p4ExitCode'])); - - j = 0; - contents = {} - while j < len(filedata): - stat = filedata[j] - j += 1 - text = '' - while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'): - text += filedata[j]['data'] - del filedata[j]['data'] - j += 1 - - if not stat.has_key('depotFile'): - sys.stderr.write("p4 print fails with: %s\n" % repr(stat)) - continue + # deleted files... + for f in filesToDelete: + self.streamOneP4Deletion(f) - if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'): - text = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text) - elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'): - text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text) + if len(filesToRead) > 0: + self.stream_file = {} + self.stream_contents = [] + self.stream_have_file_info = False - contents[stat['depotFile']] = text + # curry self argument + def streamP4FilesCbSelf(entry): + self.streamP4FilesCb(entry) - for f in filesForCommit: - path = f['path'] - if contents.has_key(path): - f['data'] = contents[path] + p4CmdList("-x - print", + '\n'.join(['%s#%s' % (f['path'], f['rev']) + for f in filesToRead]), + cb=streamP4FilesCbSelf) - return filesForCommit + # do the last chunk + if self.stream_file.has_key('depotFile'): + self.streamOneP4File(self.stream_file, self.stream_contents) def commit(self, details, files, branch, branchPrefixes, parent = ""): epoch = details["time"] author = details["user"] + self.branchPrefixes = branchPrefixes if self.verbose: print "commit into %s" % branch @@ -1023,7 +1085,6 @@ class P4Sync(Command): new_files.append (f) else: sys.stderr.write("Ignoring file outside of prefix: %s\n" % path) - files = self.readP4Files(new_files) self.gitStream.write("commit %s\n" % branch) # gitStream.write("mark :%s\n" % details["change"]) @@ -1051,33 +1112,7 @@ class P4Sync(Command): print "parent %s" % parent self.gitStream.write("from %s\n" % parent) - for file in files: - if file["type"] == "apple": - print "\nfile %s is a strange apple file that forks. Ignoring!" % file['path'] - continue - - relPath = self.stripRepoPath(file['path'], branchPrefixes) - if file["action"] in ("delete", "purge"): - self.gitStream.write("D %s\n" % relPath) - else: - data = file['data'] - - mode = "644" - if isP4Exec(file["type"]): - mode = "755" - elif file["type"] == "symlink": - mode = "120000" - # p4 print on a symlink contains "target\n", so strip it off - data = data[:-1] - - if self.isWindows and file["type"].endswith("text"): - data = data.replace("\r\n", "\n") - - self.gitStream.write("M %s inline %s\n" % (mode, relPath)) - self.gitStream.write("data %s\n" % len(data)) - self.gitStream.write(data) - self.gitStream.write("\n") - + self.streamP4Files(new_files) self.gitStream.write("\n") change = int(details["change"]) diff --git a/diff-lib.c b/diff-lib.c index ad2a4cde74..0c74ef5cbe 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -162,7 +162,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (ce_uptodate(ce)) continue; - changed = check_removed(ce, &st); + /* If CE_VALID is set, don't look at workdir for file removal */ + changed = (ce->ce_flags & CE_VALID) ? 0 : check_removed(ce, &st); if (changed) { if (changed < 0) { perror(ce->name); @@ -309,22 +310,6 @@ static int show_modified(struct rev_info *revs, } /* - * This turns all merge entries into "stage 3". That guarantees that - * when we read in the new tree (into "stage 1"), we won't lose sight - * of the fact that we had unmerged entries. - */ -static void mark_merge_entries(void) -{ - int i; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - if (!ce_stage(ce)) - continue; - ce->ce_flags |= CE_STAGEMASK; - } -} - -/* * This gets a mix of an existing index and a tree, one pathname entry * at a time. The index entry may be a single stage-0 one, but it could * also be multiple unmerged entries (in which case idx_pos/idx_nr will @@ -337,6 +322,8 @@ static void do_oneway_diff(struct unpack_trees_options *o, struct rev_info *revs = o->unpack_data; int match_missing, cached; + /* if the entry is not checked out, don't examine work tree */ + cached = o->index_only || (idx && (idx->ce_flags & CE_VALID)); /* * Backward compatibility wart - "diff-index -m" does * not mean "do not ignore merges", but "match_missing". @@ -344,12 +331,11 @@ static void do_oneway_diff(struct unpack_trees_options *o, * But with the revision flag parsing, that's found in * "!revs->ignore_merges". */ - cached = o->index_only; match_missing = !revs->ignore_merges; if (cached && idx && ce_stage(idx)) { - if (tree) - diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1); + diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, + idx->sha1); return; } @@ -435,8 +421,6 @@ int run_diff_index(struct rev_info *revs, int cached) struct unpack_trees_options opts; struct tree_desc t; - mark_merge_entries(); - ent = revs->pending.objects[0].item; tree_name = revs->pending.objects[0].name; tree = parse_tree_indirect(ent->sha1); @@ -177,11 +177,15 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout /* * This is like 'lstat()', except it refuses to follow symlinks - * in the path. + * in the path, after skipping "skiplen". */ -int check_path(const char *path, int len, struct stat *st) +int check_path(const char *path, int len, struct stat *st, int skiplen) { - if (has_symlink_leading_path(path, len)) { + const char *slash = path + len; + + while (path < slash && *slash != '/') + slash--; + if (!has_dirs_only_path(path, slash - path, skiplen)) { errno = ENOENT; return -1; } @@ -201,7 +205,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t strcpy(path + len, ce->name); len += ce_namelen(ce); - if (!check_path(path, len, &st)) { + if (!check_path(path, len, &st, state->base_dir_len)) { unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID); if (!changed) return 0; diff --git a/git-bisect.sh b/git-bisect.sh index 8969553658..6f6f03966f 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -405,7 +405,7 @@ bisect_run () { exit $res fi - if grep "is first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then + if grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then echo "bisect run success" exit 0; fi diff --git a/git-compat-util.h b/git-compat-util.h index 71b5acb6fa..e5e9f39c56 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -174,6 +174,8 @@ extern char *gitbasename(char *); #endif #endif +#include "compat/bswap.h" + /* General helper functions */ extern void usage(const char *err) NORETURN; extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); diff --git a/git-instaweb.sh b/git-instaweb.sh index 5f5cac75ea..d96eddbe56 100755 --- a/git-instaweb.sh +++ b/git-instaweb.sh @@ -77,11 +77,30 @@ start_httpd () { resolve_full_httpd # don't quote $full_httpd, there can be arguments to it (-f) - $full_httpd "$fqgitdir/gitweb/httpd.conf" - if test $? != 0; then - echo "Could not execute http daemon $httpd." - exit 1 - fi + case "$httpd" in + *mongoose*) + #The mongoose server doesn't have a daemon mode so we'll have to fork it + $full_httpd "$fqgitdir/gitweb/httpd.conf" & + #Save the pid before doing anything else (we'll print it later) + pid=$! + + if test $? != 0; then + echo "Could not execute http daemon $httpd." + exit 1 + fi + + cat > "$fqgitdir/pid" <<EOF +$pid +EOF + ;; + *) + $full_httpd "$fqgitdir/gitweb/httpd.conf" + if test $? != 0; then + echo "Could not execute http daemon $httpd." + exit 1 + fi + ;; + esac } stop_httpd () { @@ -308,6 +327,31 @@ EOF fi } +mongoose_conf() { + cat > "$conf" <<EOF +# Mongoose web server configuration file. +# Lines starting with '#' and empty lines are ignored. +# For detailed description of every option, visit +# http://code.google.com/p/mongoose/wiki/MongooseManual + +root $fqgitdir/gitweb +ports $port +index_files gitweb.cgi +#ssl_cert $fqgitdir/gitweb/ssl_cert.pem +error_log $fqgitdir/gitweb/error.log +access_log $fqgitdir/gitweb/access.log + +#cgi setup +cgi_env PATH=/usr/local/bin:/usr/bin:/bin,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH +cgi_interp $PERL +cgi_ext cgi,pl + +# mimetype mapping +mime_types .gz=application/x-gzip,.tar.gz=application/x-tgz,.tgz=application/x-tgz,.tar=application/x-tar,.zip=application/zip,.gif=image/gif,.jpg=image/jpeg,.jpeg=image/jpeg,.png=image/png,.css=text/css,.html=text/html,.htm=text/html,.js=text/javascript,.c=text/plain,.cpp=text/plain,.log=text/plain,.conf=text/plain,.text=text/plain,.txt=text/plain,.dtd=text/xml,.bz2=application/x-bzip,.tbz=application/x-bzip-compressed-tar,.tar.bz2=application/x-bzip-compressed-tar +EOF +} + + script=' s#^(my|our) \$projectroot =.*#$1 \$projectroot = "'$(dirname "$fqgitdir")'";#; s#(my|our) \$gitbin =.*#$1 \$gitbin = "'$GIT_EXEC_PATH'";#; @@ -344,6 +388,9 @@ case "$httpd" in webrick) webrick_conf ;; +*mongoose*) + mongoose_conf + ;; *) echo "Unknown httpd specified: $httpd" exit 1 diff --git a/git-stash.sh b/git-stash.sh index 03e589f764..d61c9d03bc 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -162,10 +162,6 @@ show_stash () { } apply_stash () { - git update-index -q --refresh && - git diff-files --quiet --ignore-submodules || - die 'Cannot apply to a dirty working tree, please stage your changes' - unstash_index= while test $# != 0 @@ -184,18 +180,27 @@ apply_stash () { shift done - # current index state - c_tree=$(git write-tree) || - die 'Cannot apply a stash in the middle of a merge' + if test $# = 0 + then + have_stash || die 'Nothing to apply' + fi # stash records the work tree, and is a merge between the # base commit (first parent) and the index tree (second parent). - s=$(git rev-parse --verify --default $ref_stash "$@") && - w_tree=$(git rev-parse --verify "$s:") && - b_tree=$(git rev-parse --verify "$s^1:") && - i_tree=$(git rev-parse --verify "$s^2:") || + s=$(git rev-parse --quiet --verify --default $ref_stash "$@") && + w_tree=$(git rev-parse --quiet --verify "$s:") && + b_tree=$(git rev-parse --quiet --verify "$s^1:") && + i_tree=$(git rev-parse --quiet --verify "$s^2:") || die "$*: no valid stashed state found" + git update-index -q --refresh && + git diff-files --quiet --ignore-submodules || + die 'Cannot apply to a dirty working tree, please stage your changes' + + # current index state + c_tree=$(git write-tree) || + die 'Cannot apply a stash in the middle of a merge' + unstashed_index_tree= if test -n "$unstash_index" && test "$b_tree" != "$i_tree" && test "$c_tree" != "$i_tree" diff --git a/git-submodule.sh b/git-submodule.sh index ebed711da4..bfbd36b6f4 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -4,9 +4,14 @@ # # Copyright (c) 2007 Lars Hjemli -USAGE="[--quiet] [--cached] \ -[add [-b branch] <repo> <path>]|[status|init|update [-i|--init] [-N|--no-fetch] [--rebase|--merge]|summary [-n|--summary-limit <n>] [<commit>]] \ -[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]" +dashless=$(basename "$0" | sed -e 's/-/ /') +USAGE="[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path> + or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...] + or: $dashless [--quiet] init [--] [<path>...] + or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...] + or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...] + or: $dashless [--quiet] foreach [--recursive] <command> + or: $dashless [--quiet] sync [--] [<path>...]" OPTIONS_SPEC= . git-sh-setup . git-parse-remote @@ -16,8 +21,10 @@ command= branch= reference= cached= +files= nofetch= update= +prefix= # Resolve relative url by appending to parent's url resolve_relative_url () @@ -237,13 +244,43 @@ cmd_add() # cmd_foreach() { + # parse $args after "submodule ... foreach". + while test $# -ne 0 + do + case "$1" in + -q|--quiet) + GIT_QUIET=1 + ;; + --recursive) + recursive=1 + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift + done + module_list | while read mode sha1 stage path do if test -e "$path"/.git then - say "Entering '$path'" - (cd "$path" && eval "$@") || + say "Entering '$prefix$path'" + name=$(module_name "$path") + ( + prefix="$prefix$path/" + unset GIT_DIR + cd "$path" && + eval "$@" && + if test -n "$recursive" + then + cmd_foreach "--recursive" "$@" + fi + ) || die "Stopping at '$path'; script returned non-zero status." fi done @@ -316,6 +353,7 @@ cmd_init() cmd_update() { # parse $args after "submodule ... update". + orig_args="$@" while test $# -ne 0 do case "$1" in @@ -348,6 +386,10 @@ cmd_update() shift update="merge" ;; + --recursive) + shift + recursive=1 + ;; --) shift break @@ -434,6 +476,12 @@ cmd_update() die "Unable to $action '$sha1' in submodule path '$path'" say "Submodule path '$path': $msg '$sha1'" fi + + if test -n "$recursive" + then + (unset GIT_DIR; cd "$path" && cmd_update $orig_args) || + die "Failed to recurse into submodule path '$path'" + fi done } @@ -460,6 +508,7 @@ set_name_rev () { cmd_summary() { summary_limit=-1 for_status= + diff_cmd=diff-index # parse $args after "submodule ... summary". while test $# -ne 0 @@ -468,6 +517,9 @@ cmd_summary() { --cached) cached="$1" ;; + --files) + files="$1" + ;; --for-status) for_status="$1" ;; @@ -504,9 +556,17 @@ cmd_summary() { head=HEAD fi + if [ -n "$files" ] + then + test -n "$cached" && + die "--cached cannot be used with --files" + diff_cmd=diff-files + head= + fi + cd_to_toplevel # Get modified modules cared by user - modules=$(git diff-index $cached --raw $head -- "$@" | + modules=$(git $diff_cmd $cached --raw $head -- "$@" | egrep '^:([0-7]* )?160000' | while read mod_src mod_dst sha1_src sha1_dst status name do @@ -520,7 +580,7 @@ cmd_summary() { test -z "$modules" && return - git diff-index $cached --raw $head -- $modules | + git $diff_cmd $cached --raw $head -- $modules | egrep '^:([0-7]* )?160000' | cut -c2- | while read mod_src mod_dst sha1_src sha1_dst status name @@ -643,6 +703,7 @@ cmd_summary() { cmd_status() { # parse $args after "submodule ... status". + orig_args="$@" while test $# -ne 0 do case "$1" in @@ -652,6 +713,9 @@ cmd_status() --cached) cached=1 ;; + --recursive) + recursive=1 + ;; --) shift break @@ -671,22 +735,34 @@ cmd_status() do name=$(module_name "$path") || exit url=$(git config submodule."$name".url) + displaypath="$prefix$path" if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git then - say "-$sha1 $path" + say "-$sha1 $displaypath" continue; fi set_name_rev "$path" "$sha1" if git diff-files --quiet -- "$path" then - say " $sha1 $path$revname" + say " $sha1 $displaypath$revname" else if test -z "$cached" then sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD) set_name_rev "$path" "$sha1" fi - say "+$sha1 $path$revname" + say "+$sha1 $displaypath$revname" + fi + + if test -n "$recursive" + then + ( + prefix="$displaypath/" + unset GIT_DIR + cd "$path" && + cmd_status $orig_args + ) || + die "Failed to recurse into submodule path '$path'" fi done } @@ -359,6 +359,7 @@ static void handle_internal_command(int argc, const char **argv) { "unpack-objects", cmd_unpack_objects, RUN_SETUP }, { "update-index", cmd_update_index, RUN_SETUP }, { "update-ref", cmd_update_ref, RUN_SETUP }, + { "update-server-info", cmd_update_server_info, RUN_SETUP }, { "upload-archive", cmd_upload_archive }, { "verify-tag", cmd_verify_tag, RUN_SETUP }, { "version", cmd_version }, diff --git a/gitweb/INSTALL b/gitweb/INSTALL index 18c9ce35e8..b76a0cffff 100644 --- a/gitweb/INSTALL +++ b/gitweb/INSTALL @@ -123,6 +123,15 @@ GITWEB_CONFIG file: $feature{'snapshot'}{'default'} = ['zip', 'tgz']; $feature{'snapshot'}{'override'} = 1; +If you allow overriding for the snapshot feature, you can specify which +snapshot formats are globally disabled. You can also add any command line +options you want (such as setting the compression level). For instance, +you can disable Zip compressed snapshots and set GZip to run at level 6 by +adding the following lines to your $GITWEB_CONFIG: + + $known_snapshot_formats{'zip'}{'disabled'} = 1; + $known_snapshot_formats{'tgz'}{'compressor'} = ['gzip','-6']; + Gitweb repositories ------------------- diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index be7358fdeb..24b219310a 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -160,7 +160,8 @@ our %known_snapshot_formats = ( # 'suffix' => filename suffix, # 'format' => --format for git-archive, # 'compressor' => [compressor command and arguments] - # (array reference, optional)} + # (array reference, optional) + # 'disabled' => boolean (optional)} # 'tgz' => { 'display' => 'tar.gz', @@ -176,6 +177,14 @@ our %known_snapshot_formats = ( 'format' => 'tar', 'compressor' => ['bzip2']}, + 'txz' => { + 'display' => 'tar.xz', + 'type' => 'application/x-xz', + 'suffix' => '.tar.xz', + 'format' => 'tar', + 'compressor' => ['xz'], + 'disabled' => 1}, + 'zip' => { 'display' => 'zip', 'type' => 'application/x-zip', @@ -188,6 +197,7 @@ our %known_snapshot_formats = ( our %known_snapshot_format_aliases = ( 'gzip' => 'tgz', 'bzip2' => 'tbz2', + 'xz' => 'txz', # backward compatibility: legacy gitweb config support 'x-gzip' => undef, 'gz' => undef, @@ -405,7 +415,7 @@ sub gitweb_get_feature { @{$feature{$name}{'default'}}); if (!$override) { return @defaults; } if (!defined $sub) { - warn "feature $name is not overrideable"; + warn "feature $name is not overridable"; return @defaults; } return $sub->(@defaults); @@ -494,7 +504,8 @@ sub filter_snapshot_fmts { exists $known_snapshot_format_aliases{$_} ? $known_snapshot_format_aliases{$_} : $_} @fmts; @fmts = grep { - exists $known_snapshot_formats{$_} } @fmts; + exists $known_snapshot_formats{$_} && + !$known_snapshot_formats{$_}{'disabled'}} @fmts; } our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; @@ -1513,10 +1524,10 @@ sub format_subject_html { $long =~ s/[[:cntrl:]]/?/g; return $cgi->a({-href => $href, -class => "list subject", -title => to_utf8($long)}, - esc_html($short) . $extra); + esc_html($short)) . $extra; } else { return $cgi->a({-href => $href, -class => "list subject"}, - esc_html($long) . $extra); + esc_html($long)) . $extra; } } @@ -5179,6 +5190,8 @@ sub git_snapshot { die_error(400, "Invalid snapshot format parameter"); } elsif (!exists($known_snapshot_formats{$format})) { die_error(400, "Unknown snapshot format"); + } elsif ($known_snapshot_formats{$format}{'disabled'}) { + die_error(403, "Snapshot format not allowed"); } elsif (!grep($_ eq $format, @snapshot_fmts)) { die_error(403, "Unsupported snapshot format"); } @@ -291,9 +291,10 @@ static int graph_is_interesting(struct git_graph *graph, struct commit *commit) } /* - * Uninteresting and pruned commits won't be printed + * Otherwise, use get_commit_action() to see if this commit is + * interesting */ - return (commit->object.flags & (UNINTERESTING | TREESAME)) ? 0 : 1; + return get_commit_action(graph->revs, commit) == commit_show; } static struct commit_list *next_interesting_parent(struct git_graph *graph, @@ -1289,5 +1289,10 @@ void release_http_object_request(struct http_object_request *freq) free(freq->url); freq->url = NULL; } - freq->slot = NULL; + if (freq->slot != NULL) { + freq->slot->callback_func = NULL; + freq->slot->callback_data = NULL; + release_active_slot(freq->slot); + freq->slot = NULL; + } } diff --git a/log-tree.c b/log-tree.c index a3b4c0692c..1c9eefee33 100644 --- a/log-tree.c +++ b/log-tree.c @@ -25,7 +25,8 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in struct object *obj = parse_object(sha1); if (!obj) return 0; - refname = prettify_refname(refname); + if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS) + refname = prettify_refname(refname); add_name_decoration("", refname, obj); while (obj->type == OBJ_TAG) { obj = ((struct tag *)obj)->tagged; @@ -36,12 +37,12 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in return 0; } -void load_ref_decorations(void) +void load_ref_decorations(int flags) { static int loaded; if (!loaded) { loaded = 1; - for_each_ref(add_ref_decoration, NULL); + for_each_ref(add_ref_decoration, &flags); } } diff --git a/log-tree.h b/log-tree.h index 20b5caf1aa..3f7b40027b 100644 --- a/log-tree.h +++ b/log-tree.h @@ -17,7 +17,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, const char **subject_p, const char **extra_headers_p, int *need_8bit_cte_p); -void load_ref_decorations(void); +void load_ref_decorations(int flags); #define FORMAT_PATCH_NAME_MAX 64 void get_patch_filename(struct commit *commit, int nr, const char *suffix, diff --git a/mozilla-sha1/sha1.c b/mozilla-sha1/sha1.c deleted file mode 100644 index 95a4ebf496..0000000000 --- a/mozilla-sha1/sha1.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is SHA 180-1 Reference Implementation (Compact version) - * - * The Initial Developer of the Original Code is Paul Kocher of - * Cryptography Research. Portions created by Paul Kocher are - * Copyright (C) 1995-9 by Cryptography Research, Inc. All - * Rights Reserved. - * - * Contributor(s): - * - * Paul Kocher - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#include "sha1.h" - -static void shaHashBlock(moz_SHA_CTX *ctx); - -void moz_SHA1_Init(moz_SHA_CTX *ctx) { - int i; - - ctx->lenW = 0; - ctx->sizeHi = ctx->sizeLo = 0; - - /* Initialize H with the magic constants (see FIPS180 for constants) - */ - ctx->H[0] = 0x67452301; - ctx->H[1] = 0xefcdab89; - ctx->H[2] = 0x98badcfe; - ctx->H[3] = 0x10325476; - ctx->H[4] = 0xc3d2e1f0; - - for (i = 0; i < 80; i++) - ctx->W[i] = 0; -} - - -void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *_dataIn, int len) { - const unsigned char *dataIn = _dataIn; - int i; - - /* Read the data into W and process blocks as they get full - */ - for (i = 0; i < len; i++) { - ctx->W[ctx->lenW / 4] <<= 8; - ctx->W[ctx->lenW / 4] |= (unsigned int)dataIn[i]; - if ((++ctx->lenW) % 64 == 0) { - shaHashBlock(ctx); - ctx->lenW = 0; - } - ctx->sizeLo += 8; - ctx->sizeHi += (ctx->sizeLo < 8); - } -} - - -void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx) { - unsigned char pad0x80 = 0x80; - unsigned char pad0x00 = 0x00; - unsigned char padlen[8]; - int i; - - /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length - */ - padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); - padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); - padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); - padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); - padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); - padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); - padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); - padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); - moz_SHA1_Update(ctx, &pad0x80, 1); - while (ctx->lenW != 56) - moz_SHA1_Update(ctx, &pad0x00, 1); - moz_SHA1_Update(ctx, padlen, 8); - - /* Output hash - */ - for (i = 0; i < 20; i++) { - hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); - ctx->H[i / 4] <<= 8; - } - - /* - * Re-initialize the context (also zeroizes contents) - */ - moz_SHA1_Init(ctx); -} - - -#define SHA_ROT(X,n) (((X) << (n)) | ((X) >> (32-(n)))) - -static void shaHashBlock(moz_SHA_CTX *ctx) { - int t; - unsigned int A,B,C,D,E,TEMP; - - for (t = 16; t <= 79; t++) - ctx->W[t] = - SHA_ROT(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); - - A = ctx->H[0]; - B = ctx->H[1]; - C = ctx->H[2]; - D = ctx->H[3]; - E = ctx->H[4]; - - for (t = 0; t <= 19; t++) { - TEMP = SHA_ROT(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999; - E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; - } - for (t = 20; t <= 39; t++) { - TEMP = SHA_ROT(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1; - E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; - } - for (t = 40; t <= 59; t++) { - TEMP = SHA_ROT(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdc; - E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; - } - for (t = 60; t <= 79; t++) { - TEMP = SHA_ROT(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6; - E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP; - } - - ctx->H[0] += A; - ctx->H[1] += B; - ctx->H[2] += C; - ctx->H[3] += D; - ctx->H[4] += E; -} diff --git a/mozilla-sha1/sha1.h b/mozilla-sha1/sha1.h deleted file mode 100644 index aa48a46cf7..0000000000 --- a/mozilla-sha1/sha1.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is SHA 180-1 Header File - * - * The Initial Developer of the Original Code is Paul Kocher of - * Cryptography Research. Portions created by Paul Kocher are - * Copyright (C) 1995-9 by Cryptography Research, Inc. All - * Rights Reserved. - * - * Contributor(s): - * - * Paul Kocher - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -typedef struct { - unsigned int H[5]; - unsigned int W[80]; - int lenW; - unsigned int sizeHi,sizeLo; -} moz_SHA_CTX; - -void moz_SHA1_Init(moz_SHA_CTX *ctx); -void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *dataIn, int len); -void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx); - -#define git_SHA_CTX moz_SHA_CTX -#define git_SHA1_Init moz_SHA1_Init -#define git_SHA1_Update moz_SHA1_Update -#define git_SHA1_Final moz_SHA1_Final @@ -583,7 +583,7 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit) struct name_decoration *d; const char *prefix = " ("; - load_ref_decorations(); + load_ref_decorations(DECORATE_SHORT_REFS); d = lookup_decoration(&name_decoration, &commit->object); while (d) { strbuf_addstr(sb, prefix); diff --git a/read-cache.c b/read-cache.c index 4e3e272ee4..1bbaf1cffb 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1065,7 +1065,18 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, return updated; } -int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen) +static void show_file(const char * fmt, const char * name, int in_porcelain, + int * first, char *header_msg) +{ + if (in_porcelain && *first && header_msg) { + printf("%s\n", header_msg); + *first=0; + } + printf(fmt, name); +} + +int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, + char *seen, char *header_msg) { int i; int has_errors = 0; @@ -1074,11 +1085,14 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p int quiet = (flags & REFRESH_QUIET) != 0; int not_new = (flags & REFRESH_IGNORE_MISSING) != 0; int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0; + int first = 1; + int in_porcelain = (flags & REFRESH_IN_PORCELAIN); unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0; - const char *needs_update_message; + const char *needs_update_fmt; + const char *needs_merge_fmt; - needs_update_message = ((flags & REFRESH_SAY_CHANGED) - ? "locally modified" : "needs update"); + needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n"); + needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n"); for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce, *new; int cache_errno = 0; @@ -1094,7 +1108,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p i--; if (allow_unmerged) continue; - printf("%s: needs merge\n", ce->name); + show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg); has_errors = 1; continue; } @@ -1117,7 +1131,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p } if (quiet) continue; - printf("%s: %s\n", ce->name, needs_update_message); + show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg); has_errors = 1; continue; } diff --git a/revision.c b/revision.c index 9f5dac5f1d..35eca4a361 100644 --- a/revision.c +++ b/revision.c @@ -1052,7 +1052,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->simplify_by_decoration = 1; revs->limited = 1; revs->prune = 1; - load_ref_decorations(); + load_ref_decorations(DECORATE_SHORT_REFS); } else if (!strcmp(arg, "--date-order")) { revs->lifo = 0; revs->topo_order = 1; @@ -1664,7 +1664,7 @@ static inline int want_ancestry(struct rev_info *revs) return (revs->rewrite_parents || revs->children.name); } -enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) +enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit) { if (commit->object.flags & SHOWN) return commit_ignore; @@ -1692,12 +1692,23 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) if (!commit->parents || !commit->parents->next) return commit_ignore; } - if (want_ancestry(revs) && rewrite_parents(revs, commit) < 0) - return commit_error; } return commit_show; } +enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) +{ + enum commit_action action = get_commit_action(revs, commit); + + if (action == commit_show && + !revs->show_all && + revs->prune && revs->dense && want_ancestry(revs)) { + if (rewrite_parents(revs, commit) < 0) + return commit_error; + } + return action; +} + static struct commit *get_revision_1(struct rev_info *revs) { if (!revs->commits) diff --git a/revision.h b/revision.h index fb74492714..9d0dddbcbc 100644 --- a/revision.h +++ b/revision.h @@ -15,6 +15,9 @@ #define SYMMETRIC_LEFT (1u<<8) #define ALL_REV_FLAGS ((1u<<9)-1) +#define DECORATE_SHORT_REFS 1 +#define DECORATE_FULL_REFS 2 + struct rev_info; struct log_info; @@ -165,6 +168,7 @@ enum commit_action { commit_error }; +extern enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit); extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit); #endif diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh new file mode 100644 index 0000000000..845253274b --- /dev/null +++ b/t/gitweb-lib.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# +# Copyright (c) 2007 Jakub Narebski +# + +gitweb_init () { + safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')" + cat >gitweb_config.perl <<EOF +#!/usr/bin/perl + +# gitweb configuration for tests + +our \$version = 'current'; +our \$GIT = 'git'; +our \$projectroot = "$safe_pwd"; +our \$project_maxdepth = 8; +our \$home_link_str = 'projects'; +our \$site_name = '[localhost]'; +our \$site_header = ''; +our \$site_footer = ''; +our \$home_text = 'indextext.html'; +our @stylesheets = ('file:///$TEST_DIRECTORY/../gitweb/gitweb.css'); +our \$logo = 'file:///$TEST_DIRECTORY/../gitweb/git-logo.png'; +our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/git-favicon.png'; +our \$projects_list = ''; +our \$export_ok = ''; +our \$strict_export = ''; + +EOF + + cat >.git/description <<EOF +$0 test repository +EOF +} + +gitweb_run () { + GATEWAY_INTERFACE='CGI/1.1' + HTTP_ACCEPT='*/*' + REQUEST_METHOD='GET' + SCRIPT_NAME="$TEST_DIRECTORY/../gitweb/gitweb.perl" + QUERY_STRING=""$1"" + PATH_INFO=""$2"" + export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \ + SCRIPT_NAME QUERY_STRING PATH_INFO + + GITWEB_CONFIG=$(pwd)/gitweb_config.perl + export GITWEB_CONFIG + + # some of git commands write to STDERR on error, but this is not + # written to web server logs, so we are not interested in that: + # we are interested only in properly formatted errors/warnings + rm -f gitweb.log && + perl -- "$SCRIPT_NAME" \ + >gitweb.output 2>gitweb.log && + if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi + + # gitweb.log is left for debugging + # gitweb.output is used to parse http output +} + +. ./test-lib.sh + +if ! test_have_prereq PERL; then + say 'skipping gitweb tests, perl not available' + test_done +fi + +perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { + say 'skipping gitweb tests, perl version is too old' + test_done +} + +gitweb_init diff --git a/t/t1009-read-tree-new-index.sh b/t/t1009-read-tree-new-index.sh new file mode 100755 index 0000000000..59b3aa4bc4 --- /dev/null +++ b/t/t1009-read-tree-new-index.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +test_description='test read-tree into a fresh index file' + +. ./test-lib.sh + +test_expect_success setup ' + echo one >a && + git add a && + git commit -m initial +' + +test_expect_success 'non-existent index file' ' + rm -f new-index && + GIT_INDEX_FILE=new-index git read-tree master +' + +test_expect_success 'empty index file' ' + rm -f new-index && + > new-index && + GIT_INDEX_FILE=new-index git read-tree master +' + +test_done + diff --git a/t/t2000-checkout-cache-clash.sh b/t/t2000-checkout-cache-clash.sh index f7e1a735ec..de3edb5d57 100755 --- a/t/t2000-checkout-cache-clash.sh +++ b/t/t2000-checkout-cache-clash.sh @@ -48,4 +48,13 @@ test_expect_success \ 'git checkout-index conflicting paths.' \ 'test -f path0 && test -d path1 && test -f path1/file1' +test_expect_success SYMLINKS 'checkout-index -f twice with --prefix' ' + mkdir -p tar/get && + ln -s tar/get there && + echo first && + git checkout-index -a -f --prefix=there/ && + echo second && + git checkout-index -a -f --prefix=there/ +' + test_done diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh new file mode 100755 index 0000000000..c551d39a66 --- /dev/null +++ b/t/t2015-checkout-unborn.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +test_description='checkout from unborn branch protects contents' +. ./test-lib.sh + +test_expect_success 'setup' ' + mkdir parent && + (cd parent && + git init && + echo content >file && + git add file && + git commit -m base + ) && + git fetch parent master:origin +' + +test_expect_success 'checkout from unborn preserves untracked files' ' + echo precious >expect && + echo precious >file && + test_must_fail git checkout -b new origin && + test_cmp expect file +' + +test_expect_success 'checkout from unborn preserves index contents' ' + echo precious >expect && + echo precious >file && + git add file && + test_must_fail git checkout -b new origin && + test_cmp expect file && + git show :file >file && + test_cmp expect file +' + +test_expect_success 'checkout from unborn merges identical index contents' ' + echo content >file && + git add file && + git checkout -b new origin +' + +test_done diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 8b33321f8c..8e3694ed5b 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -207,6 +207,7 @@ log --root --cc --patch-with-stat --summary master log -SF master log -SF -p master log --decorate --all +log --decorate=full --all rev-list --parents HEAD rev-list --children HEAD diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all new file mode 100644 index 0000000000..903d9d9659 --- /dev/null +++ b/t/t4013/diff.log_--decorate=full_--all @@ -0,0 +1,34 @@ +$ git log --decorate=full --all +commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master) +Merge: 9a6d494 c7a2ab9 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:04:00 2006 +0000 + + Merge branch 'side' + +commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side) +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:03:00 2006 +0000 + + Side + +commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:02:00 2006 +0000 + + Third + +commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:01:00 2006 +0000 + + Second + + This is the second commit. + +commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial) +Author: A U Thor <author@example.com> +Date: Mon Jun 26 00:00:00 2006 +0000 + + Initial +$ diff --git a/t/t4039-diff-assume-unchanged.sh b/t/t4039-diff-assume-unchanged.sh new file mode 100755 index 0000000000..9d9498bd95 --- /dev/null +++ b/t/t4039-diff-assume-unchanged.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +test_description='diff with assume-unchanged entries' + +. ./test-lib.sh + +# external diff has been tested in t4020-diff-external.sh + +test_expect_success 'setup' ' + echo zero > zero && + git add zero && + git commit -m zero && + echo one > one && + echo two > two && + git add one two && + git commit -m onetwo && + git update-index --assume-unchanged one && + echo borked >> one && + test "$(git ls-files -v one)" = "h one" +' + +test_expect_success 'diff-index does not examine assume-unchanged entries' ' + git diff-index HEAD^ -- one | grep -q 5626abf0f72e58d7a153368ba57db4c673c0e171 +' + +test_expect_success 'diff-files does not examine assume-unchanged entries' ' + rm one && + test -z "$(git diff-files -- one)" +' + +test_done diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index a8c2ca2a78..18376d6608 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -139,6 +139,36 @@ test_expect_success 'fsck in shallow repo' ' ) ' +test_expect_success 'simple fetch in shallow repo' ' + ( + cd shallow && + git fetch + ) +' + +test_expect_success 'no changes expected' ' + ( + cd shallow && + git count-objects -v + ) > count.shallow.2 && + cmp count.shallow count.shallow.2 +' + +test_expect_success 'fetch same depth in shallow repo' ' + ( + cd shallow && + git fetch --depth=2 + ) +' + +test_expect_success 'no changes expected' ' + ( + cd shallow && + git count-objects -v + ) > count.shallow.3 && + cmp count.shallow count.shallow.3 +' + test_expect_success 'add two more' ' add B66 $B65 && add B67 $B66 @@ -201,4 +231,21 @@ test_expect_success 'pull in shallow repo with missing merge base' ' ) ' +test_expect_success 'additional simple shallow deepenings' ' + ( + cd shallow && + git fetch --depth=8 && + git fetch --depth=10 && + git fetch --depth=11 + ) +' + +test_expect_success 'clone shallow object count' ' + ( + cd shallow && + git count-objects -v + ) > count.shallow && + grep "^count: 52" count.shallow +' + test_done diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh new file mode 100644 index 0000000000..65d8d474bc --- /dev/null +++ b/t/t5531-deep-submodule-push.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +test_description='unpack-objects' + +. ./test-lib.sh + +test_expect_success setup ' + mkdir pub.git && + GIT_DIR=pub.git git init --bare + GIT_DIR=pub.git git config receive.fsckobjects true && + mkdir work && + ( + cd work && + git init && + mkdir -p gar/bage && + ( + cd gar/bage && + git init && + >junk && + git add junk && + git commit -m "Initial junk" + ) && + git add gar/bage && + git commit -m "Initial superproject" + ) +' + +test_expect_success push ' + ( + cd work && + git push ../pub.git master + ) +' + +test_done diff --git a/t/t6015-rev-list-show-all-parents.sh b/t/t6015-rev-list-show-all-parents.sh new file mode 100755 index 0000000000..8b146fb432 --- /dev/null +++ b/t/t6015-rev-list-show-all-parents.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +test_description='--show-all --parents does not rewrite TREESAME commits' + +. ./test-lib.sh + +test_expect_success 'set up --show-all --parents test' ' + test_commit one foo.txt && + commit1=`git rev-list -1 HEAD` && + test_commit two bar.txt && + commit2=`git rev-list -1 HEAD` && + test_commit three foo.txt && + commit3=`git rev-list -1 HEAD` + ' + +test_expect_success '--parents rewrites TREESAME parents correctly' ' + echo $commit3 $commit1 > expected && + echo $commit1 >> expected && + git rev-list --parents HEAD -- foo.txt > actual && + test_cmp expected actual + ' + +test_expect_success '--parents --show-all does not rewrites TREESAME parents' ' + echo $commit3 $commit2 > expected && + echo $commit2 $commit1 >> expected && + echo $commit1 >> expected && + git rev-list --parents --show-all HEAD -- foo.txt > actual && + test_cmp expected actual + ' + +test_done diff --git a/t/t6016-rev-list-graph-simplify-history.sh b/t/t6016-rev-list-graph-simplify-history.sh new file mode 100755 index 0000000000..27fd52b7be --- /dev/null +++ b/t/t6016-rev-list-graph-simplify-history.sh @@ -0,0 +1,276 @@ +#!/bin/sh + +# There's more than one "correct" way to represent the history graphically. +# These tests depend on the current behavior of the graphing code. If the +# graphing code is ever changed to draw the output differently, these tests +# cases will need to be updated to know about the new layout. + +test_description='--graph and simplified history' + +. ./test-lib.sh + +test_expect_success 'set up rev-list --graph test' ' + # 3 commits on branch A + test_commit A1 foo.txt && + test_commit A2 bar.txt && + test_commit A3 bar.txt && + git branch -m master A && + + # 2 commits on branch B, started from A1 + git checkout -b B A1 && + test_commit B1 foo.txt && + test_commit B2 abc.txt && + + # 2 commits on branch C, started from A2 + git checkout -b C A2 && + test_commit C1 xyz.txt && + test_commit C2 xyz.txt && + + # Octopus merge B and C into branch A + git checkout A && + git merge B C && + git tag A4 + + test_commit A5 bar.txt && + + # More commits on C, then merge C into A + git checkout C && + test_commit C3 foo.txt && + test_commit C4 bar.txt && + git checkout A && + git merge -s ours C && + git tag A6 + + test_commit A7 bar.txt && + + # Store commit names in variables for later use + A1=$(git rev-parse --verify A1) && + A2=$(git rev-parse --verify A2) && + A3=$(git rev-parse --verify A3) && + A4=$(git rev-parse --verify A4) && + A5=$(git rev-parse --verify A5) && + A6=$(git rev-parse --verify A6) && + A7=$(git rev-parse --verify A7) && + B1=$(git rev-parse --verify B1) && + B2=$(git rev-parse --verify B2) && + C1=$(git rev-parse --verify C1) && + C2=$(git rev-parse --verify C2) && + C3=$(git rev-parse --verify C3) && + C4=$(git rev-parse --verify C4) + ' + +test_expect_success '--graph --all' ' + rm -f expected && + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "|\\ " >> expected && + echo "| * $C4" >> expected && + echo "| * $C3" >> expected && + echo "* | $A5" >> expected && + echo "| | " >> expected && + echo "| \\ " >> expected && + echo "*-. \\ $A4" >> expected && + echo "|\\ \\ \\ " >> expected && + echo "| | |/ " >> expected && + echo "| | * $C2" >> expected && + echo "| | * $C1" >> expected && + echo "| * | $B2" >> expected && + echo "| * | $B1" >> expected && + echo "* | | $A3" >> expected && + echo "| |/ " >> expected && + echo "|/| " >> expected && + echo "* | $A2" >> expected && + echo "|/ " >> expected && + echo "* $A1" >> expected && + git rev-list --graph --all > actual && + test_cmp expected actual + ' + +# Make sure the graph_is_interesting() code still realizes +# that undecorated merges are interesting, even with --simplify-by-decoration +test_expect_success '--graph --simplify-by-decoration' ' + rm -f expected && + git tag -d A4 + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "|\\ " >> expected && + echo "| * $C4" >> expected && + echo "| * $C3" >> expected && + echo "* | $A5" >> expected && + echo "| | " >> expected && + echo "| \\ " >> expected && + echo "*-. \\ $A4" >> expected && + echo "|\\ \\ \\ " >> expected && + echo "| | |/ " >> expected && + echo "| | * $C2" >> expected && + echo "| | * $C1" >> expected && + echo "| * | $B2" >> expected && + echo "| * | $B1" >> expected && + echo "* | | $A3" >> expected && + echo "| |/ " >> expected && + echo "|/| " >> expected && + echo "* | $A2" >> expected && + echo "|/ " >> expected && + echo "* $A1" >> expected && + git rev-list --graph --all --simplify-by-decoration > actual && + test_cmp expected actual + ' + +# Get rid of all decorations on branch B, and graph with it simplified away +test_expect_success '--graph --simplify-by-decoration prune branch B' ' + rm -f expected && + git tag -d B2 + git tag -d B1 + git branch -d B + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "|\\ " >> expected && + echo "| * $C4" >> expected && + echo "| * $C3" >> expected && + echo "* | $A5" >> expected && + echo "* | $A4" >> expected && + echo "|\\ \\ " >> expected && + echo "| |/ " >> expected && + echo "| * $C2" >> expected && + echo "| * $C1" >> expected && + echo "* | $A3" >> expected && + echo "|/ " >> expected && + echo "* $A2" >> expected && + echo "* $A1" >> expected && + git rev-list --graph --simplify-by-decoration --all > actual && + test_cmp expected actual + ' + +test_expect_success '--graph --full-history -- bar.txt' ' + rm -f expected && + git tag -d B2 + git tag -d B1 + git branch -d B + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "|\\ " >> expected && + echo "| * $C4" >> expected && + echo "* | $A5" >> expected && + echo "* | $A4" >> expected && + echo "|\\ \\ " >> expected && + echo "| |/ " >> expected && + echo "* | $A3" >> expected && + echo "|/ " >> expected && + echo "* $A2" >> expected && + git rev-list --graph --full-history --all -- bar.txt > actual && + test_cmp expected actual + ' + +test_expect_success '--graph --full-history --simplify-merges -- bar.txt' ' + rm -f expected && + git tag -d B2 + git tag -d B1 + git branch -d B + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "|\\ " >> expected && + echo "| * $C4" >> expected && + echo "* | $A5" >> expected && + echo "* | $A3" >> expected && + echo "|/ " >> expected && + echo "* $A2" >> expected && + git rev-list --graph --full-history --simplify-merges --all \ + -- bar.txt > actual && + test_cmp expected actual + ' + +test_expect_success '--graph -- bar.txt' ' + rm -f expected && + git tag -d B2 + git tag -d B1 + git branch -d B + echo "* $A7" >> expected && + echo "* $A5" >> expected && + echo "* $A3" >> expected && + echo "| * $C4" >> expected && + echo "|/ " >> expected && + echo "* $A2" >> expected && + git rev-list --graph --all -- bar.txt > actual && + test_cmp expected actual + ' + +test_expect_success '--graph --sparse -- bar.txt' ' + rm -f expected && + git tag -d B2 + git tag -d B1 + git branch -d B + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "* $A5" >> expected && + echo "* $A4" >> expected && + echo "* $A3" >> expected && + echo "| * $C4" >> expected && + echo "| * $C3" >> expected && + echo "| * $C2" >> expected && + echo "| * $C1" >> expected && + echo "|/ " >> expected && + echo "* $A2" >> expected && + echo "* $A1" >> expected && + git rev-list --graph --sparse --all -- bar.txt > actual && + test_cmp expected actual + ' + +test_expect_success '--graph ^C4' ' + rm -f expected && + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "* $A5" >> expected && + echo "* $A4" >> expected && + echo "|\\ " >> expected && + echo "| * $B2" >> expected && + echo "| * $B1" >> expected && + echo "* $A3" >> expected && + git rev-list --graph --all ^C4 > actual && + test_cmp expected actual + ' + +test_expect_success '--graph ^C3' ' + rm -f expected && + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "|\\ " >> expected && + echo "| * $C4" >> expected && + echo "* $A5" >> expected && + echo "* $A4" >> expected && + echo "|\\ " >> expected && + echo "| * $B2" >> expected && + echo "| * $B1" >> expected && + echo "* $A3" >> expected && + git rev-list --graph --all ^C3 > actual && + test_cmp expected actual + ' + +# I don't think the ordering of the boundary commits is really +# that important, but this test depends on it. If the ordering ever changes +# in the code, we'll need to update this test. +test_expect_success '--graph --boundary ^C3' ' + rm -f expected && + echo "* $A7" >> expected && + echo "* $A6" >> expected && + echo "|\\ " >> expected && + echo "| * $C4" >> expected && + echo "* | $A5" >> expected && + echo "| | " >> expected && + echo "| \\ " >> expected && + echo "*-. \\ $A4" >> expected && + echo "|\\ \\ \\ " >> expected && + echo "| * | | $B2" >> expected && + echo "| * | | $B1" >> expected && + echo "* | | | $A3" >> expected && + echo "o | | | $A2" >> expected && + echo "|/ / / " >> expected && + echo "o | | $A1" >> expected && + echo " / / " >> expected && + echo "| o $C3" >> expected && + echo "|/ " >> expected && + echo "o $C2" >> expected && + git rev-list --graph --boundary --all ^C3 > actual && + test_cmp expected actual + ' + +test_done diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 1315bab595..def397c53a 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -175,7 +175,7 @@ test_expect_success 'bisect skip: successfull result' ' git bisect start $HASH4 $HASH1 && git bisect skip && git bisect bad > my_bisect_log.txt && - grep "$HASH2 is first bad commit" my_bisect_log.txt && + grep "$HASH2 is the first bad commit" my_bisect_log.txt && git bisect reset ' @@ -261,7 +261,7 @@ test_expect_success \ git bisect good $HASH1 && git bisect bad $HASH4 && git bisect run ./test_script.sh > my_bisect_log.txt && - grep "$HASH3 is first bad commit" my_bisect_log.txt && + grep "$HASH3 is the first bad commit" my_bisect_log.txt && git bisect reset' # We want to automatically find the commit that @@ -274,7 +274,7 @@ test_expect_success \ chmod +x test_script.sh && git bisect start $HASH4 $HASH1 && git bisect run ./test_script.sh > my_bisect_log.txt && - grep "$HASH4 is first bad commit" my_bisect_log.txt && + grep "$HASH4 is the first bad commit" my_bisect_log.txt && git bisect reset' # $HASH1 is good, $HASH5 is bad, we skip $HASH3 @@ -287,14 +287,14 @@ test_expect_success 'bisect skip: add line and then a new test' ' git bisect start $HASH5 $HASH1 && git bisect skip && git bisect good > my_bisect_log.txt && - grep "$HASH5 is first bad commit" my_bisect_log.txt && + grep "$HASH5 is the first bad commit" my_bisect_log.txt && git bisect log > log_to_replay.txt && git bisect reset ' test_expect_success 'bisect skip and bisect replay' ' git bisect replay log_to_replay.txt > my_bisect_log.txt && - grep "$HASH5 is first bad commit" my_bisect_log.txt && + grep "$HASH5 is the first bad commit" my_bisect_log.txt && git bisect reset ' @@ -335,7 +335,7 @@ test_expect_success 'bisect run & skip: find first bad' ' chmod +x test_script.sh && git bisect start $HASH7 $HASH1 && git bisect run ./test_script.sh > my_bisect_log.txt && - grep "$HASH6 is first bad commit" my_bisect_log.txt + grep "$HASH6 is the first bad commit" my_bisect_log.txt ' test_expect_success 'bisect skip only one range' ' @@ -385,7 +385,7 @@ test_expect_success 'bisect does not create a "bisect" branch' ' rev_hash6=$(git rev-parse --verify HEAD) && test "$rev_hash6" = "$HASH6" && git bisect good > my_bisect_log.txt && - grep "$HASH7 is first bad commit" my_bisect_log.txt && + grep "$HASH7 is the first bad commit" my_bisect_log.txt && git bisect reset && rev_hash6=$(git rev-parse --verify bisect) && test "$rev_hash6" = "$HASH6" && @@ -534,7 +534,7 @@ test_expect_success 'restricting bisection on one dir' ' para1=$(git rev-parse --verify HEAD) && test "$para1" = "$PARA_HASH1" && git bisect bad > my_bisect_log.txt && - grep "$PARA_HASH1 is first bad commit" my_bisect_log.txt + grep "$PARA_HASH1 is the first bad commit" my_bisect_log.txt ' test_expect_success 'restricting bisection on one dir and a file' ' @@ -552,7 +552,7 @@ test_expect_success 'restricting bisection on one dir and a file' ' para1=$(git rev-parse --verify HEAD) && test "$para1" = "$PARA_HASH1" && git bisect good > my_bisect_log.txt && - grep "$PARA_HASH4 is first bad commit" my_bisect_log.txt + grep "$PARA_HASH4 is the first bad commit" my_bisect_log.txt ' test_expect_success 'skipping away from skipped commit' ' diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh new file mode 100755 index 0000000000..1044aa6549 --- /dev/null +++ b/t/t7060-wtstatus.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +test_description='basic work tree status reporting' + +. ./test-lib.sh + +test_expect_success setup ' + test_commit A && + test_commit B oneside added && + git checkout A^0 && + test_commit C oneside created +' + +test_expect_success 'A/A conflict' ' + git checkout B^0 && + test_must_fail git merge C +' + +test_expect_success 'Report path with conflict' ' + git diff --cached --name-status >actual && + echo "U oneside" >expect && + test_cmp expect actual +' + +test_expect_success 'Report new path with conflict' ' + git diff --cached --name-status HEAD^ >actual && + echo "U oneside" >expect && + test_cmp expect actual +' + +cat >expect <<EOF +# On branch side +# Unmerged paths: +# (use "git reset HEAD <file>..." to unstage) +# (use "git add <file>..." to mark resolution) +# +# deleted by us: foo +# +no changes added to commit (use "git add" and/or "git commit -a") +EOF + +test_expect_success 'M/D conflict does not segfault' ' + mkdir mdconflict && + ( + cd mdconflict && + git init && + test_commit initial foo "" && + test_commit modify foo foo && + git checkout -b side HEAD^ && + git rm foo && + git commit -m delete && + test_must_fail git merge master && + test_must_fail git status > ../actual + ) && + test_cmp expect actual +' + +test_done diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index e637c7d4db..e85ff02c3e 100755 --- a/t/t7102-reset.sh +++ b/t/t7102-reset.sh @@ -419,7 +419,8 @@ test_expect_success 'resetting an unmodified path is a no-op' ' ' cat > expect << EOF -file2: locally modified +Unstaged changes after reset: +M file2 EOF test_expect_success '--mixed refreshes the index' ' diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index 61498293b9..6cc16c39fe 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -56,6 +56,15 @@ test_expect_success 'modified submodule(forward)' " EOF " +test_expect_success 'modified submodule(forward), --files' " + git submodule summary --files >actual && + diff actual - <<-EOF +* sm1 $head1...$head2 (1): + > Add foo3 + +EOF +" + commit_file sm1 && cd sm1 && git reset --hard HEAD~2 >/dev/null && @@ -114,6 +123,15 @@ test_expect_success 'typechanged submodule(submodule->blob), --cached' " EOF " +test_expect_success 'typechanged submodule(submodule->blob), --files' " + git submodule summary --files >actual && + diff actual - <<-EOF +* sm1 $head5(blob)->$head4(submodule) (3): + > Add foo5 + +EOF +" + rm -rf sm1 && git checkout-index sm1 test_expect_success 'typechanged submodule(submodule->blob)' " @@ -205,4 +223,8 @@ test_expect_success '--for-status' " EOF " +test_expect_success 'fail when using --files together with --cached' " + test_must_fail git submodule summary --files --cached +" + test_done diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh new file mode 100755 index 0000000000..2a527750ce --- /dev/null +++ b/t/t7407-submodule-foreach.sh @@ -0,0 +1,237 @@ +#!/bin/sh +# +# Copyright (c) 2009 Johan Herland +# + +test_description='Test "git submodule foreach" + +This test verifies that "git submodule foreach" correctly visits all submodules +that are currently checked out. +' + +. ./test-lib.sh + + +test_expect_success 'setup a submodule tree' ' + echo file > file && + git add file && + test_tick && + git commit -m upstream + git clone . super && + git clone super submodule && + ( + cd super && + git submodule add ../submodule sub1 && + git submodule add ../submodule sub2 && + git submodule add ../submodule sub3 && + git config -f .gitmodules --rename-section \ + submodule.sub1 submodule.foo1 && + git config -f .gitmodules --rename-section \ + submodule.sub2 submodule.foo2 && + git config -f .gitmodules --rename-section \ + submodule.sub3 submodule.foo3 && + git add .gitmodules + test_tick && + git commit -m "submodules" && + git submodule init sub1 && + git submodule init sub2 && + git submodule init sub3 + ) && + ( + cd submodule && + echo different > file && + git add file && + test_tick && + git commit -m "different" + ) && + ( + cd super && + ( + cd sub3 && + git pull + ) && + git add sub3 && + test_tick && + git commit -m "update sub3" + ) +' + +sub1sha1=$(cd super/sub1 && git rev-parse HEAD) +sub3sha1=$(cd super/sub3 && git rev-parse HEAD) + +cat > expect <<EOF +Entering 'sub1' +foo1-sub1-$sub1sha1 +Entering 'sub3' +foo3-sub3-$sub3sha1 +EOF + +test_expect_success 'test basic "submodule foreach" usage' ' + git clone super clone && + ( + cd clone && + git submodule update --init -- sub1 sub3 && + git submodule foreach "echo \$name-\$path-\$sha1" > ../actual + ) && + test_cmp expect actual +' + +test_expect_success 'setup nested submodules' ' + git clone submodule nested1 && + git clone submodule nested2 && + git clone submodule nested3 && + ( + cd nested3 && + git submodule add ../submodule submodule && + test_tick && + git commit -m "submodule" && + git submodule init submodule + ) && + ( + cd nested2 && + git submodule add ../nested3 nested3 && + test_tick && + git commit -m "nested3" && + git submodule init nested3 + ) && + ( + cd nested1 && + git submodule add ../nested2 nested2 && + test_tick && + git commit -m "nested2" && + git submodule init nested2 + ) && + ( + cd super && + git submodule add ../nested1 nested1 && + test_tick && + git commit -m "nested1" && + git submodule init nested1 + ) +' + +test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' ' + git clone super clone2 && + ( + cd clone2 && + test ! -d sub1/.git && + test ! -d sub2/.git && + test ! -d sub3/.git && + test ! -d nested1/.git && + git submodule update --init && + test -d sub1/.git && + test -d sub2/.git && + test -d sub3/.git && + test -d nested1/.git && + test ! -d nested1/nested2/.git && + git submodule foreach "git submodule update --init" && + test -d nested1/nested2/.git && + test ! -d nested1/nested2/nested3/.git + ) +' + +test_expect_success 'use "foreach --recursive" to checkout all submodules' ' + ( + cd clone2 && + git submodule foreach --recursive "git submodule update --init" && + test -d nested1/nested2/nested3/.git && + test -d nested1/nested2/nested3/submodule/.git + ) +' + +cat > expect <<EOF +Entering 'nested1' +Entering 'nested1/nested2' +Entering 'nested1/nested2/nested3' +Entering 'nested1/nested2/nested3/submodule' +Entering 'sub1' +Entering 'sub2' +Entering 'sub3' +EOF + +test_expect_success 'test messages from "foreach --recursive"' ' + ( + cd clone2 && + git submodule foreach --recursive "true" > ../actual + ) && + test_cmp expect actual +' + +cat > expect <<EOF +nested1-nested1 +nested2-nested2 +nested3-nested3 +submodule-submodule +foo1-sub1 +foo2-sub2 +foo3-sub3 +EOF + +test_expect_success 'test "foreach --quiet --recursive"' ' + ( + cd clone2 && + git submodule foreach -q --recursive "echo \$name-\$path" > ../actual + ) && + test_cmp expect actual +' + +test_expect_success 'use "update --recursive" to checkout all submodules' ' + git clone super clone3 && + ( + cd clone3 && + test ! -d sub1/.git && + test ! -d sub2/.git && + test ! -d sub3/.git && + test ! -d nested1/.git && + git submodule update --init --recursive && + test -d sub1/.git && + test -d sub2/.git && + test -d sub3/.git && + test -d nested1/.git && + test -d nested1/nested2/.git && + test -d nested1/nested2/nested3/.git && + test -d nested1/nested2/nested3/submodule/.git + ) +' + +nested1sha1=$(cd clone3/nested1 && git rev-parse HEAD) +nested2sha1=$(cd clone3/nested1/nested2 && git rev-parse HEAD) +nested3sha1=$(cd clone3/nested1/nested2/nested3 && git rev-parse HEAD) +submodulesha1=$(cd clone3/nested1/nested2/nested3/submodule && git rev-parse HEAD) +sub1sha1=$(cd clone3/sub1 && git rev-parse HEAD) +sub2sha1=$(cd clone3/sub2 && git rev-parse HEAD) +sub3sha1=$(cd clone3/sub3 && git rev-parse HEAD) +sub1sha1_short=$(cd clone3/sub1 && git rev-parse --short HEAD) +sub2sha1_short=$(cd clone3/sub2 && git rev-parse --short HEAD) + +cat > expect <<EOF + $nested1sha1 nested1 (heads/master) + $nested2sha1 nested1/nested2 (heads/master) + $nested3sha1 nested1/nested2/nested3 (heads/master) + $submodulesha1 nested1/nested2/nested3/submodule (heads/master) + $sub1sha1 sub1 ($sub1sha1_short) + $sub2sha1 sub2 ($sub2sha1_short) + $sub3sha1 sub3 (heads/master) +EOF + +test_expect_success 'test "status --recursive"' ' + ( + cd clone3 && + git submodule status --recursive > ../actual + ) && + test_cmp expect actual +' + +test_expect_success 'use "git clone --recursive" to checkout all submodules' ' + git clone --recursive super clone4 && + test -d clone4/.git && + test -d clone4/sub1/.git && + test -d clone4/sub2/.git && + test -d clone4/sub3/.git && + test -d clone4/nested1/.git && + test -d clone4/nested1/nested2/.git && + test -d clone4/nested1/nested2/nested3/.git && + test -d clone4/nested1/nested2/nested3/submodule/.git +' + +test_done diff --git a/t/t8005/iso8859-5.txt b/t/t8005/iso8859-5.txt deleted file mode 100644 index 2e4b80c8df..0000000000 --- a/t/t8005/iso8859-5.txt +++ /dev/null @@ -1,2 +0,0 @@ -ISO8859_5_NAME="Иван Петрович Сидоров" -ISO8859_5_MSG="Тестовое сообщение" diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 627518108a..2fc7fdb124 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -9,73 +9,8 @@ This test runs gitweb (git web interface) as CGI script from commandline, and checks that it would not write any errors or warnings to log.' -gitweb_init () { - safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')" - cat >gitweb_config.perl <<EOF -#!/usr/bin/perl - -# gitweb configuration for tests - -our \$version = "current"; -our \$GIT = "git"; -our \$projectroot = "$safe_pwd"; -our \$project_maxdepth = 8; -our \$home_link_str = "projects"; -our \$site_name = "[localhost]"; -our \$site_header = ""; -our \$site_footer = ""; -our \$home_text = "indextext.html"; -our @stylesheets = ("file:///$TEST_DIRECTORY/../gitweb/gitweb.css"); -our \$logo = "file:///$TEST_DIRECTORY/../gitweb/git-logo.png"; -our \$favicon = "file:///$TEST_DIRECTORY/../gitweb/git-favicon.png"; -our \$projects_list = ""; -our \$export_ok = ""; -our \$strict_export = ""; -EOF - - cat >.git/description <<EOF -$0 test repository -EOF -} - -gitweb_run () { - GATEWAY_INTERFACE="CGI/1.1" - HTTP_ACCEPT="*/*" - REQUEST_METHOD="GET" - SCRIPT_NAME="$TEST_DIRECTORY/../gitweb/gitweb.perl" - QUERY_STRING=""$1"" - PATH_INFO=""$2"" - export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \ - SCRIPT_NAME QUERY_STRING PATH_INFO - - GITWEB_CONFIG=$(pwd)/gitweb_config.perl - export GITWEB_CONFIG - - # some of git commands write to STDERR on error, but this is not - # written to web server logs, so we are not interested in that: - # we are interested only in properly formatted errors/warnings - rm -f gitweb.log && - perl -- "$SCRIPT_NAME" \ - >/dev/null 2>gitweb.log && - if grep "^[[]" gitweb.log >/dev/null 2>&1; then false; else true; fi - - # gitweb.log is left for debugging -} - -. ./test-lib.sh - -if ! test_have_prereq PERL; then - say 'skipping gitweb tests, perl not available' - test_done -fi - -perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || { - say 'skipping gitweb tests, perl version is too old' - test_done -} - -gitweb_init +. ./gitweb-lib.sh # ---------------------------------------------------------------------- # no commits (empty, just initialized repository) diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh new file mode 100644 index 0000000000..d0ff21d426 --- /dev/null +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2009 Mark Rada +# + +test_description='gitweb as standalone script (http status tests). + +This test runs gitweb (git web interface) as a CGI script from the +commandline, and checks that it returns the expected HTTP status +code and message.' + + +. ./gitweb-lib.sh + +# ---------------------------------------------------------------------- +# snapshot settings + +test_commit \ + 'SnapshotTests' \ + 'i can has snapshot?' + +cat >>gitweb_config.perl <<\EOF +$feature{'snapshot'}{'override'} = 0; +EOF + +test_expect_success \ + 'snapshots: tgz only default format enabled' \ + 'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" && + grep "Status: 200 OK" gitweb.output && + gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tbz2" && + grep "403 - Unsupported snapshot format" gitweb.output && + gitweb_run "p=.git;a=snapshot;h=HEAD;sf=txz" && + grep "403 - Snapshot format not allowed" gitweb.output && + gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" && + grep "403 - Unsupported snapshot format" gitweb.output' +test_debug 'cat gitweb.output' + + +cat >>gitweb_config.perl <<\EOF +$feature{'snapshot'}{'default'} = ['tgz','tbz2','txz','zip']; +EOF + +test_expect_success \ + 'snapshots: all enabled in default, use default disabled value' \ + 'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" && + grep "Status: 200 OK" gitweb.output && + gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tbz2" && + grep "Status: 200 OK" gitweb.output && + gitweb_run "p=.git;a=snapshot;h=HEAD;sf=txz" && + grep "403 - Snapshot format not allowed" gitweb.output && + gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" && + grep "Status: 200 OK" gitweb.output' +test_debug 'cat gitweb.output' + + +cat >>gitweb_config.perl <<\EOF +$known_snapshot_formats{'zip'}{'disabled'} = 1; +EOF + +test_expect_success \ + 'snapshots: zip explicitly disabled' \ + 'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" && + grep "403 - Snapshot format not allowed" gitweb.output' +test_debug 'cat gitweb.output' + + +cat >>gitweb_config.perl <<\EOF +$known_snapshot_formats{'tgz'}{'disabled'} = 0; +EOF + +test_expect_success \ + 'snapshots: tgz explicitly enabled' \ + 'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" && + grep "Status: 200 OK" gitweb.output' +test_debug 'cat gitweb.output' + + +test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index a5b8d03db0..f2ca536472 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -685,6 +685,21 @@ do esac done +# Provide an implementation of the 'yes' utility +yes () { + if test $# = 0 + then + y=y + else + y="$*" + fi + + while echo "$y" + do + : + done +} + # Fix some commands on Windows case $(uname -s) in *MINGW*) diff --git a/transport.c b/transport.c index faee154c38..f7e1663d18 100644 --- a/transport.c +++ b/transport.c @@ -1059,11 +1059,12 @@ const struct ref *transport_get_remote_refs(struct transport *transport) int transport_fetch_refs(struct transport *transport, const struct ref *refs) { int rc; - int nr_heads = 0, nr_alloc = 0; + int nr_heads = 0, nr_alloc = 0, nr_refs = 0; const struct ref **heads = NULL; const struct ref *rm; for (rm = refs; rm; rm = rm->next) { + nr_refs++; if (rm->peer_ref && !hashcmp(rm->peer_ref->old_sha1, rm->old_sha1)) continue; @@ -1071,6 +1072,19 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs) heads[nr_heads++] = rm; } + if (!nr_heads) { + /* + * When deepening of a shallow repository is requested, + * then local and remote refs are likely to still be equal. + * Just feed them all to the fetch method in that case. + * This condition shouldn't be met in a non-deepening fetch + * (see builtin-fetch.c:quickfetch()). + */ + heads = xmalloc(nr_refs * sizeof(*heads)); + for (rm = refs; rm; rm = rm->next) + heads[nr_heads++] = rm; + } + rc = transport->fetch(transport, nr_heads, heads); free(heads); return rc; diff --git a/update-server-info.c b/update-server-info.c deleted file mode 100644 index 7b38fd867b..0000000000 --- a/update-server-info.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "cache.h" -#include "exec_cmd.h" - -static const char update_server_info_usage[] = -"git update-server-info [--force]"; - -int main(int ac, char **av) -{ - int i; - int force = 0; - for (i = 1; i < ac; i++) { - if (av[i][0] == '-') { - if (!strcmp("--force", av[i]) || - !strcmp("-f", av[i])) - force = 1; - else - usage(update_server_info_usage); - } - } - if (i != ac) - usage(update_server_info_usage); - - git_extract_argv0_path(av[0]); - - setup_git_directory(); - - return !!update_server_info(force); -} diff --git a/wt-status.c b/wt-status.c index 47735d8129..63598ce40c 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1,6 +1,5 @@ #include "cache.h" #include "wt-status.h" -#include "color.h" #include "object.h" #include "dir.h" #include "commit.h" @@ -11,38 +10,18 @@ #include "run-command.h" #include "remote.h" -int wt_status_relative_paths = 1; -int wt_status_use_color = -1; -static int wt_status_submodule_summary; -static char wt_status_colors[][COLOR_MAXLEN] = { +static char default_wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */ GIT_COLOR_RED, /* WT_STATUS_CHANGED */ GIT_COLOR_RED, /* WT_STATUS_UNTRACKED */ GIT_COLOR_RED, /* WT_STATUS_NOBRANCH */ + GIT_COLOR_RED, /* WT_STATUS_UNMERGED */ }; -enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; - -static int parse_status_slot(const char *var, int offset) -{ - if (!strcasecmp(var+offset, "header")) - return WT_STATUS_HEADER; - if (!strcasecmp(var+offset, "updated") - || !strcasecmp(var+offset, "added")) - return WT_STATUS_UPDATED; - if (!strcasecmp(var+offset, "changed")) - return WT_STATUS_CHANGED; - if (!strcasecmp(var+offset, "untracked")) - return WT_STATUS_UNTRACKED; - if (!strcasecmp(var+offset, "nobranch")) - return WT_STATUS_NOBRANCH; - die("bad config variable '%s'", var); -} - -static const char *color(int slot) +static const char *color(int slot, struct wt_status *s) { - return wt_status_use_color > 0 ? wt_status_colors[slot] : ""; + return s->use_color > 0 ? s->color_palette[slot] : ""; } void wt_status_prepare(struct wt_status *s) @@ -51,16 +30,35 @@ void wt_status_prepare(struct wt_status *s) const char *head; memset(s, 0, sizeof(*s)); + memcpy(s->color_palette, default_wt_status_colors, + sizeof(default_wt_status_colors)); + s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + s->use_color = -1; + s->relative_paths = 1; head = resolve_ref("HEAD", sha1, 0, NULL); s->branch = head ? xstrdup(head) : NULL; s->reference = "HEAD"; s->fp = stdout; s->index_file = get_index_file(); + s->change.strdup_strings = 1; + s->untracked.strdup_strings = 1; +} + +static void wt_status_print_unmerged_header(struct wt_status *s) +{ + const char *c = color(WT_STATUS_HEADER, s); + color_fprintf_ln(s->fp, c, "# Unmerged paths:"); + if (!s->is_initial) + color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference); + else + color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)"); + color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to mark resolution)"); + color_fprintf_ln(s->fp, c, "#"); } static void wt_status_print_cached_header(struct wt_status *s) { - const char *c = color(WT_STATUS_HEADER); + const char *c = color(WT_STATUS_HEADER, s); color_fprintf_ln(s->fp, c, "# Changes to be committed:"); if (!s->is_initial) { color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference); @@ -73,7 +71,7 @@ static void wt_status_print_cached_header(struct wt_status *s) static void wt_status_print_dirty_header(struct wt_status *s, int has_deleted) { - const char *c = color(WT_STATUS_HEADER); + const char *c = color(WT_STATUS_HEADER, s); color_fprintf_ln(s->fp, c, "# Changed but not updated:"); if (!has_deleted) color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to update what will be committed)"); @@ -85,7 +83,7 @@ static void wt_status_print_dirty_header(struct wt_status *s, static void wt_status_print_untracked_header(struct wt_status *s) { - const char *c = color(WT_STATUS_HEADER); + const char *c = color(WT_STATUS_HEADER, s); color_fprintf_ln(s->fp, c, "# Untracked files:"); color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to include in what will be committed)"); color_fprintf_ln(s->fp, c, "#"); @@ -93,23 +91,63 @@ static void wt_status_print_untracked_header(struct wt_status *s) static void wt_status_print_trailer(struct wt_status *s) { - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); } #define quote_path quote_path_relative -static void wt_status_print_filepair(struct wt_status *s, - int t, struct diff_filepair *p) +static void wt_status_print_unmerged_data(struct wt_status *s, + struct string_list_item *it) { - const char *c = color(t); + const char *c = color(WT_STATUS_UNMERGED, s); + struct wt_status_change_data *d = it->util; + struct strbuf onebuf = STRBUF_INIT; + const char *one, *how = "bug"; + + one = quote_path(it->string, -1, &onebuf, s->prefix); + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); + switch (d->stagemask) { + case 1: how = "both deleted:"; break; + case 2: how = "added by us:"; break; + case 3: how = "deleted by them:"; break; + case 4: how = "added by them:"; break; + case 5: how = "deleted by us:"; break; + case 6: how = "both added:"; break; + case 7: how = "both modified:"; break; + } + color_fprintf(s->fp, c, "%-20s%s\n", how, one); + strbuf_release(&onebuf); +} + +static void wt_status_print_change_data(struct wt_status *s, + int change_type, + struct string_list_item *it) +{ + struct wt_status_change_data *d = it->util; + const char *c = color(change_type, s); + int status = status; + char *one_name; + char *two_name; const char *one, *two; struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT; - one = quote_path(p->one->path, -1, &onebuf, s->prefix); - two = quote_path(p->two->path, -1, &twobuf, s->prefix); + one_name = two_name = it->string; + switch (change_type) { + case WT_STATUS_UPDATED: + status = d->index_status; + if (d->head_path) + one_name = d->head_path; + break; + case WT_STATUS_CHANGED: + status = d->worktree_status; + break; + } - color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); - switch (p->status) { + one = quote_path(one_name, -1, &onebuf, s->prefix); + two = quote_path(two_name, -1, &twobuf, s->prefix); + + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); + switch (status) { case DIFF_STATUS_ADDED: color_fprintf(s->fp, c, "new file: %s", one); break; @@ -135,64 +173,114 @@ static void wt_status_print_filepair(struct wt_status *s, color_fprintf(s->fp, c, "unmerged: %s", one); break; default: - die("bug: unhandled diff status %c", p->status); + die("bug: unhandled diff status %c", status); } fprintf(s->fp, "\n"); strbuf_release(&onebuf); strbuf_release(&twobuf); } -static void wt_status_print_updated_cb(struct diff_queue_struct *q, - struct diff_options *options, - void *data) +static void wt_status_collect_changed_cb(struct diff_queue_struct *q, + struct diff_options *options, + void *data) { struct wt_status *s = data; - int shown_header = 0; int i; + + if (!q->nr) + return; + s->workdir_dirty = 1; for (i = 0; i < q->nr; i++) { - if (q->queue[i]->status == 'U') - continue; - if (!shown_header) { - wt_status_print_cached_header(s); - s->commitable = 1; - shown_header = 1; + struct diff_filepair *p; + struct string_list_item *it; + struct wt_status_change_data *d; + + p = q->queue[i]; + it = string_list_insert(p->one->path, &s->change); + d = it->util; + if (!d) { + d = xcalloc(1, sizeof(*d)); + it->util = d; } - wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]); + if (!d->worktree_status) + d->worktree_status = p->status; } - if (shown_header) - wt_status_print_trailer(s); } -static void wt_status_print_changed_cb(struct diff_queue_struct *q, - struct diff_options *options, - void *data) +static int unmerged_mask(const char *path) +{ + int pos, mask; + struct cache_entry *ce; + + pos = cache_name_pos(path, strlen(path)); + if (0 <= pos) + return 0; + + mask = 0; + pos = -pos-1; + while (pos < active_nr) { + ce = active_cache[pos++]; + if (strcmp(ce->name, path) || !ce_stage(ce)) + break; + mask |= (1 << (ce_stage(ce) - 1)); + } + return mask; +} + +static void wt_status_collect_updated_cb(struct diff_queue_struct *q, + struct diff_options *options, + void *data) { struct wt_status *s = data; int i; - if (q->nr) { - int has_deleted = 0; - s->workdir_dirty = 1; - for (i = 0; i < q->nr; i++) - if (q->queue[i]->status == DIFF_STATUS_DELETED) { - has_deleted = 1; - break; - } - wt_status_print_dirty_header(s, has_deleted); + + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p; + struct string_list_item *it; + struct wt_status_change_data *d; + + p = q->queue[i]; + it = string_list_insert(p->two->path, &s->change); + d = it->util; + if (!d) { + d = xcalloc(1, sizeof(*d)); + it->util = d; + } + if (!d->index_status) + d->index_status = p->status; + switch (p->status) { + case DIFF_STATUS_COPIED: + case DIFF_STATUS_RENAMED: + d->head_path = xstrdup(p->one->path); + break; + case DIFF_STATUS_UNMERGED: + d->stagemask = unmerged_mask(p->two->path); + break; + } } - for (i = 0; i < q->nr; i++) - wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]); - if (q->nr) - wt_status_print_trailer(s); } -static void wt_status_print_updated(struct wt_status *s) +static void wt_status_collect_changes_worktree(struct wt_status *s) { struct rev_info rev; + + init_revisions(&rev, NULL); + setup_revisions(0, NULL, &rev, NULL); + rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; + rev.diffopt.format_callback = wt_status_collect_changed_cb; + rev.diffopt.format_callback_data = s; + run_diff_files(&rev, 0); +} + +static void wt_status_collect_changes_index(struct wt_status *s) +{ + struct rev_info rev; + init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference); rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; - rev.diffopt.format_callback = wt_status_print_updated_cb; + rev.diffopt.format_callback = wt_status_collect_updated_cb; rev.diffopt.format_callback_data = s; rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 200; @@ -200,15 +288,155 @@ static void wt_status_print_updated(struct wt_status *s) run_diff_index(&rev, 1); } +static void wt_status_collect_changes_initial(struct wt_status *s) +{ + int i; + + for (i = 0; i < active_nr; i++) { + struct string_list_item *it; + struct wt_status_change_data *d; + struct cache_entry *ce = active_cache[i]; + + it = string_list_insert(ce->name, &s->change); + d = it->util; + if (!d) { + d = xcalloc(1, sizeof(*d)); + it->util = d; + } + if (ce_stage(ce)) { + d->index_status = DIFF_STATUS_UNMERGED; + d->stagemask |= (1 << (ce_stage(ce) - 1)); + } + else + d->index_status = DIFF_STATUS_ADDED; + } +} + +static void wt_status_collect_untracked(struct wt_status *s) +{ + int i; + struct dir_struct dir; + + if (!s->show_untracked_files) + return; + memset(&dir, 0, sizeof(dir)); + if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES) + dir.flags |= + DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; + setup_standard_excludes(&dir); + + fill_directory(&dir, NULL); + for(i = 0; i < dir.nr; i++) { + struct dir_entry *ent = dir.entries[i]; + if (!cache_name_is_other(ent->name, ent->len)) + continue; + s->workdir_untracked = 1; + string_list_insert(ent->name, &s->untracked); + } +} + +void wt_status_collect(struct wt_status *s) +{ + wt_status_collect_changes_worktree(s); + + if (s->is_initial) + wt_status_collect_changes_initial(s); + else + wt_status_collect_changes_index(s); + wt_status_collect_untracked(s); +} + +static void wt_status_print_unmerged(struct wt_status *s) +{ + int shown_header = 0; + int i; + + for (i = 0; i < s->change.nr; i++) { + struct wt_status_change_data *d; + struct string_list_item *it; + it = &(s->change.items[i]); + d = it->util; + if (!d->stagemask) + continue; + if (!shown_header) { + wt_status_print_unmerged_header(s); + shown_header = 1; + } + wt_status_print_unmerged_data(s, it); + } + if (shown_header) + wt_status_print_trailer(s); + +} + +static void wt_status_print_updated(struct wt_status *s) +{ + int shown_header = 0; + int i; + + for (i = 0; i < s->change.nr; i++) { + struct wt_status_change_data *d; + struct string_list_item *it; + it = &(s->change.items[i]); + d = it->util; + if (!d->index_status || + d->index_status == DIFF_STATUS_UNMERGED) + continue; + if (!shown_header) { + wt_status_print_cached_header(s); + s->commitable = 1; + shown_header = 1; + } + wt_status_print_change_data(s, WT_STATUS_UPDATED, it); + } + if (shown_header) + wt_status_print_trailer(s); +} + +/* + * -1 : has delete + * 0 : no change + * 1 : some change but no delete + */ +static int wt_status_check_worktree_changes(struct wt_status *s) +{ + int i; + int changes = 0; + + for (i = 0; i < s->change.nr; i++) { + struct wt_status_change_data *d; + d = s->change.items[i].util; + if (!d->worktree_status || + d->worktree_status == DIFF_STATUS_UNMERGED) + continue; + changes = 1; + if (d->worktree_status == DIFF_STATUS_DELETED) + return -1; + } + return changes; +} + static void wt_status_print_changed(struct wt_status *s) { - struct rev_info rev; - init_revisions(&rev, ""); - setup_revisions(0, NULL, &rev, NULL); - rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; - rev.diffopt.format_callback = wt_status_print_changed_cb; - rev.diffopt.format_callback_data = s; - run_diff_files(&rev, 0); + int i; + int worktree_changes = wt_status_check_worktree_changes(s); + + if (!worktree_changes) + return; + + wt_status_print_dirty_header(s, worktree_changes < 0); + + for (i = 0; i < s->change.nr; i++) { + struct wt_status_change_data *d; + struct string_list_item *it; + it = &(s->change.items[i]); + d = it->util; + if (!d->worktree_status || + d->worktree_status == DIFF_STATUS_UNMERGED) + continue; + wt_status_print_change_data(s, WT_STATUS_CHANGED, it); + } + wt_status_print_trailer(s); } static void wt_status_print_submodule_summary(struct wt_status *s) @@ -228,7 +456,7 @@ static void wt_status_print_submodule_summary(struct wt_status *s) NULL }; - sprintf(summary_limit, "%d", wt_status_submodule_summary); + sprintf(summary_limit, "%d", s->submodule_summary); snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file); memset(&sm_summary, 0, sizeof(sm_summary)); @@ -243,32 +471,20 @@ static void wt_status_print_submodule_summary(struct wt_status *s) static void wt_status_print_untracked(struct wt_status *s) { - struct dir_struct dir; int i; - int shown_header = 0; struct strbuf buf = STRBUF_INIT; - memset(&dir, 0, sizeof(dir)); - - if (!s->untracked) - dir.flags |= - DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; - setup_standard_excludes(&dir); + if (!s->untracked.nr) + return; - fill_directory(&dir, NULL); - for(i = 0; i < dir.nr; i++) { - struct dir_entry *ent = dir.entries[i]; - if (!cache_name_is_other(ent->name, ent->len)) - continue; - if (!shown_header) { - s->workdir_untracked = 1; - wt_status_print_untracked_header(s); - shown_header = 1; - } - color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); - color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s", - quote_path(ent->name, ent->len, - &buf, s->prefix)); + wt_status_print_untracked_header(s); + for (i = 0; i < s->untracked.nr; i++) { + struct string_list_item *it; + it = &(s->untracked.items[i]); + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t"); + color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s", + quote_path(it->string, strlen(it->string), + &buf, s->prefix)); } strbuf_release(&buf); } @@ -310,15 +526,15 @@ static void wt_status_print_tracking(struct wt_status *s) return; for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1) - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# %.*s", (int)(ep - cp), cp); - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); } void wt_status_print(struct wt_status *s) { unsigned char sha1[20]; - const char *branch_color = color(WT_STATUS_HEADER); + const char *branch_color = color(WT_STATUS_HEADER, s); s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0; if (s->branch) { @@ -328,26 +544,29 @@ void wt_status_print(struct wt_status *s) branch_name += 11; else if (!strcmp(branch_name, "HEAD")) { branch_name = ""; - branch_color = color(WT_STATUS_NOBRANCH); + branch_color = color(WT_STATUS_NOBRANCH, s); on_what = "Not currently on any branch."; } - color_fprintf(s->fp, color(WT_STATUS_HEADER), "# "); + color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# "); color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name); if (!s->is_initial) wt_status_print_tracking(s); } + wt_status_collect(s); + if (s->is_initial) { - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit"); - color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit"); + color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); } + wt_status_print_unmerged(s); wt_status_print_updated(s); wt_status_print_changed(s); - if (wt_status_submodule_summary) + if (s->submodule_summary) wt_status_print_submodule_summary(s); - if (show_untracked_files) + if (s->show_untracked_files) wt_status_print_untracked(s); else if (s->commitable) fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n"); @@ -361,53 +580,13 @@ void wt_status_print(struct wt_status *s) ; /* nothing */ else if (s->workdir_dirty) printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"); - else if (s->workdir_untracked) + else if (s->untracked.nr) printf("nothing added to commit but untracked files present (use \"git add\" to track)\n"); else if (s->is_initial) printf("nothing to commit (create/copy files and use \"git add\" to track)\n"); - else if (!show_untracked_files) + else if (!s->show_untracked_files) printf("nothing to commit (use -u to show untracked files)\n"); else printf("nothing to commit (working directory clean)\n"); } } - -int git_status_config(const char *k, const char *v, void *cb) -{ - if (!strcmp(k, "status.submodulesummary")) { - int is_bool; - wt_status_submodule_summary = git_config_bool_or_int(k, v, &is_bool); - if (is_bool && wt_status_submodule_summary) - wt_status_submodule_summary = -1; - return 0; - } - if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { - wt_status_use_color = git_config_colorbool(k, v, -1); - return 0; - } - if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { - int slot = parse_status_slot(k, 13); - if (!v) - return config_error_nonbool(k); - color_parse(v, k, wt_status_colors[slot]); - return 0; - } - if (!strcmp(k, "status.relativepaths")) { - wt_status_relative_paths = git_config_bool(k, v); - return 0; - } - if (!strcmp(k, "status.showuntrackedfiles")) { - if (!v) - return config_error_nonbool(k); - else if (!strcmp(v, "no")) - show_untracked_files = SHOW_NO_UNTRACKED_FILES; - else if (!strcmp(v, "normal")) - show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; - else if (!strcmp(v, "all")) - show_untracked_files = SHOW_ALL_UNTRACKED_FILES; - else - return error("Invalid untracked files mode '%s'", v); - return 0; - } - return git_diff_ui_config(k, v, cb); -} diff --git a/wt-status.h b/wt-status.h index 78add09bd6..a0e75177be 100644 --- a/wt-status.h +++ b/wt-status.h @@ -2,13 +2,16 @@ #define STATUS_H #include <stdio.h> +#include "string-list.h" +#include "color.h" enum color_wt_status { - WT_STATUS_HEADER, + WT_STATUS_HEADER = 0, WT_STATUS_UPDATED, WT_STATUS_CHANGED, WT_STATUS_UNTRACKED, WT_STATUS_NOBRANCH, + WT_STATUS_UNMERGED, }; enum untracked_status_type { @@ -16,7 +19,13 @@ enum untracked_status_type { SHOW_NORMAL_UNTRACKED_FILES, SHOW_ALL_UNTRACKED_FILES }; -extern enum untracked_status_type show_untracked_files; + +struct wt_status_change_data { + int worktree_status; + int index_status; + int stagemask; + char *head_path; +}; struct wt_status { int is_initial; @@ -24,8 +33,13 @@ struct wt_status { const char *reference; int verbose; int amend; - int untracked; int nowarn; + int use_color; + int relative_paths; + int submodule_summary; + enum untracked_status_type show_untracked_files; + char color_palette[WT_STATUS_UNMERGED+1][COLOR_MAXLEN]; + /* These are computed during processing of the individual sections */ int commitable; int workdir_dirty; @@ -33,12 +47,12 @@ struct wt_status { const char *index_file; FILE *fp; const char *prefix; + struct string_list change; + struct string_list untracked; }; -int git_status_config(const char *var, const char *value, void *cb); -extern int wt_status_use_color; -extern int wt_status_relative_paths; void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); +void wt_status_collect(struct wt_status *s); #endif /* STATUS_H */ diff --git a/xdiff/xutils.c b/xdiff/xutils.c index 04ad468702..bc12f29895 100644 --- a/xdiff/xutils.c +++ b/xdiff/xutils.c @@ -190,48 +190,66 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) { int i1, i2; + if (!(flags & XDF_WHITESPACE_FLAGS)) + return s1 == s2 && !memcmp(l1, l2, s1); + + i1 = 0; + i2 = 0; + + /* + * -w matches everything that matches with -b, and -b in turn + * matches everything that matches with --ignore-space-at-eol. + * + * Each flavor of ignoring needs different logic to skip whitespaces + * while we have both sides to compare. + */ if (flags & XDF_IGNORE_WHITESPACE) { - for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) { - if (isspace(l1[i1])) - while (isspace(l1[i1]) && i1 < s1) - i1++; - if (isspace(l2[i2])) - while (isspace(l2[i2]) && i2 < s2) - i2++; - if (i1 < s1 && i2 < s2 && l1[i1++] != l2[i2++]) + goto skip_ws; + while (i1 < s1 && i2 < s2) { + if (l1[i1++] != l2[i2++]) return 0; + skip_ws: + while (i1 < s1 && isspace(l1[i1])) + i1++; + while (i2 < s2 && isspace(l2[i2])) + i2++; } - return (i1 >= s1 && i2 >= s2); } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) { - for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) { - if (isspace(l1[i1])) { - if (!isspace(l2[i2])) - return 0; - while (isspace(l1[i1]) && i1 < s1) - i1++; - while (isspace(l2[i2]) && i2 < s2) - i2++; - } else if (l1[i1++] != l2[i2++]) - return 0; - } - return (i1 >= s1 && i2 >= s2); - } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) { - for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) { - if (l1[i1] != l2[i2]) { + while (i1 < s1 && i2 < s2) { + if (isspace(l1[i1]) && isspace(l2[i2])) { + /* Skip matching spaces and try again */ while (i1 < s1 && isspace(l1[i1])) i1++; while (i2 < s2 && isspace(l2[i2])) i2++; - if (i1 < s1 || i2 < s2) - return 0; - return 1; + continue; } + if (l1[i1++] != l2[i2++]) + return 0; + } + } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) { + while (i1 < s1 && i2 < s2 && l1[i1++] == l2[i2++]) + ; /* keep going */ + } + + /* + * After running out of one side, the remaining side must have + * nothing but whitespace for the lines to match. Note that + * ignore-whitespace-at-eol case may break out of the loop + * while there still are characters remaining on both lines. + */ + if (i1 < s1) { + while (i1 < s1 && isspace(l1[i1])) i1++; + if (s1 != i1) + return 0; + } + if (i2 < s2) { + while (i2 < s2 && isspace(l2[i2])) i2++; - } - return i1 >= s1 && i2 >= s2; - } else - return s1 == s2 && !memcmp(l1, l2, s1); + return (s2 == i2); + } + return 1; } static unsigned long xdl_hash_record_with_whitespace(char const **data, @@ -242,18 +260,20 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data, for (; ptr < top && *ptr != '\n'; ptr++) { if (isspace(*ptr)) { const char *ptr2 = ptr; + int at_eol; while (ptr + 1 < top && isspace(ptr[1]) && ptr[1] != '\n') ptr++; + at_eol = (top <= ptr + 1 || ptr[1] == '\n'); if (flags & XDF_IGNORE_WHITESPACE) ; /* already handled */ else if (flags & XDF_IGNORE_WHITESPACE_CHANGE - && ptr[1] != '\n') { + && !at_eol) { ha += (ha << 5); ha ^= (unsigned long) ' '; } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL - && ptr[1] != '\n') { + && !at_eol) { while (ptr2 != ptr + 1) { ha += (ha << 5); ha ^= (unsigned long) *ptr2; |