/etc/gitattributes; core.attributesfile configuration variable can
be used to customize the path to this file.
+ * Bash completion script in contrib/ has been adjusted to be also
+ usable by zsh.
+
+ * "git daemon" can take more than one --listen option to listen to
+ multiple addresses.
+
* "git diff" and "git grep" learned how functions and subroutines
in Fortran look like.
+ * "git mergetool" tells vim/gvim to show three-way diff by default
+ (use vimdiff2/gvimdiff2 as the tool name for old behaviour).
+
* "git log -G<pattern>" limits the output to commits whose change has
added or deleted lines that match the given pattern.
deprecated; we might want to remove it in the future. Users can
use the new --empty option to be more explicit instead.
+ * "git repack -f" does not spend cycles to recompress objects in the
+ non-delta representation anymore (use -F if you really mean it when
+ e.g. you changed the compression level).
+
* "git merge --log" used to limit the resulting merge log to 20
entries; this is now customizable by giving e.g. "--log=47".
+ * The default "recursive" merge strategy learned --rename-threshold
+ option to influence the rename detection, similar to the -M option
+ of "git diff". E.g. "git merge -Xrename-threshold=50% ..." to use
+ this.
+
+ * The "recursive" strategy also learned to ignore various whitespace
+ changes; the most notable is -Xignore-space-at-eol.
+
+ * "git send-email" learned "--to-cmd", similar to "--cc-cmd", to read
+ recipient list from a command output.
+
+ * "git send-email" learned to read and use "To:" from its input files.
+
* you can extend "git shell", which is often used on boxes that allow
git-only login over ssh as login shell, with custom set of
commands.
+ * "git submodule sync" updates metainformation for all submodules,
+ not just the ones that have been checked out.
+
+ * gitweb can use custom 'highlight' command with its configuration file.
+
+
Also contains various documentation updates.
All of the fixes in v1.7.3.X maintenance series are included in this
release, unless otherwise noted.
+ * "diff" and friends incorrectly applied textconv filters to symlinks
+ (d391c0ff).
+
+ * "git apply" segfaulted when a bogus input is fed to it (24305cd70).
+
+ * Running "git cherry-pick --ff" on a root commit segfaulted (6355e50).
+
* "git log --author=me --author=her" did not find commits written by
me or by her; instead it looked for commits written by me and by
her, which is impossible.
+ * "git merge-file" can be called from within a subdirectory now
+ (55846b9a).
+
+ * "git push --progress" shows progress indicators now.
+
+ * "git repack" places its temporary packs under $GIT_OBJECT_DIRECTORY/pack
+ instead of $GIT_OBJECT_DIRECTORY/ to avoid cross directory renames.
+
+ * "git rev-list --format="...%x00..." incorrectly chopped its output
+ at NUL (9130ac9fe).
+
+ * "git submodule update --recursive --other-flags" passes flags down
+ to its subinvocations.
---
exec >/var/tmp/1
-O=v1.7.3
-O=v1.7.3.1-42-g34289ec
+O=v1.7.3.2-245-g03276d9
echo O=$(git describe master)
git shortlog --no-merges ^maint ^$O master
Detect copies as well as renames. See also `--find-copies-harder`.
If `n` is specified, it has the same meaning as for `-M<n>`.
-ifndef::git-format-patch[]
---diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]::
- Select only files that are Added (`A`), Copied (`C`),
- Deleted (`D`), Modified (`M`), Renamed (`R`), have their
- type (i.e. regular file, symlink, submodule, ...) changed (`T`),
- are Unmerged (`U`), are
- Unknown (`X`), or have had their pairing Broken (`B`).
- Any combination of the filter characters (including none) can be used.
- When `*` (All-or-none) is added to the combination, all
- paths are selected if there is any file that matches
- other criteria in the comparison; if there is no file
- that matches other criteria, nothing is selected.
-endif::git-format-patch[]
-
--find-copies-harder::
For performance reasons, by default, `-C` option finds copies only
if the original file of the copy was modified in the same
number.
ifndef::git-format-patch[]
+--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]::
+ Select only files that are Added (`A`), Copied (`C`),
+ Deleted (`D`), Modified (`M`), Renamed (`R`), have their
+ type (i.e. regular file, symlink, submodule, ...) changed (`T`),
+ are Unmerged (`U`), are
+ Unknown (`X`), or have had their pairing Broken (`B`).
+ Any combination of the filter characters (including none) can be used.
+ When `*` (All-or-none) is added to the combination, all
+ paths are selected if there is any file that matches
+ other criteria in the comparison; if there is no file
+ that matches other criteria, nothing is selected.
+
-S<string>::
Look for differences that introduce or remove an instance of
<string>. Note that this is different than the string simply
behavior for a remote may be specified with the remote.<name>.tagopt
setting. See linkgit:git-config[1].
+ifndef::git-pull[]
-t::
--tags::
Most of the tags are fetched automatically as branch
downloaded. The default behavior for a remote may be
specified with the remote.<name>.tagopt setting. See
linkgit:git-config[1].
+endif::git-pull[]
-u::
--update-head-ok::
--inetd::
Have the server run as an inetd service. Implies --syslog.
- Incompatible with --port, --listen, --user and --group options.
+ Incompatible with --detach, --port, --listen, --user and --group
+ options.
--listen=<host_or_ipaddr>::
Listen on a specific IP address or hostname. IP addresses can
-m <msg>::
Set the commit message to be used for the merge commit (in
case one is created).
-
- If `--log` is specified, a shortlog of the commits being merged
- will be appended to the specified message.
-
- The 'git fmt-merge-msg' command can be
- used to give a good default for automated 'git merge'
- invocations.
++
+If `--log` is specified, a shortlog of the commits being merged
+will be appended to the specified message.
++
+The 'git fmt-merge-msg' command can be
+used to give a good default for automated 'git merge'
+invocations.
--rerere-autoupdate::
--no-rerere-autoupdate::
:git-pull: 1
--rebase::
- Instead of a merge, perform a rebase after fetching. If
- there is a remote ref for the upstream branch, and this branch
- was rebased since last fetched, the rebase uses that information
- to avoid rebasing non-local changes. To make this the default
- for branch `<name>`, set configuration `branch.<name>.rebase`
- to `true`.
+ Rebase the current branch on top of the upstream branch after
+ fetching. If there is a remote-tracking branch corresponding to
+ the upstream branch and the upstream branch was rebased since last
+ fetched, the rebase uses that information to avoid rebasing
+ non-local changes.
++
+See `branch.<name>.rebase` in linkgit:git-config[1] if you want to make
+`git pull` always use `{litdd}rebase` instead of merging.
+
[NOTE]
This is a potentially _dangerous_ mode of operation.
git show v1.0.0^\{tree\}::
Shows the tree pointed to by the tag `v1.0.0`.
+git show -s --format=%s v1.0.0^\{commit\}::
+ Shows the subject of the commit pointed to by the
+ tag `v1.0.0`.
+
git show next~10:Documentation/README::
Shows the contents of the file `Documentation/README` as
they were current in the 10th last commit of the branch
to be printed in between commits, in order for the graph history
to be drawn properly.
+
+This enables parent rewriting, see 'History Simplification' below.
++
This implies the '--topo-order' option by default, but the
'--date-order' option may also be specified.
-t::
Show the tree objects in the diff output. This implies '-r'.
+
+-s::
+ Suppress diff output.
endif::git-rev-list[]
Commit Limiting
--- /dev/null
+sigchain API
+============
+
+Code often wants to set a signal handler to clean up temporary files or
+other work-in-progress when we die unexpectedly. For multiple pieces of
+code to do this without conflicting, each piece of code must remember
+the old value of the handler and restore it either when:
+
+ 1. The work-in-progress is finished, and the handler is no longer
+ necessary. The handler should revert to the original behavior
+ (either another handler, SIG_DFL, or SIG_IGN).
+
+ 2. The signal is received. We should then do our cleanup, then chain
+ to the next handler (or die if it is SIG_DFL).
+
+Sigchain is a tiny library for keeping a stack of handlers. Your handler
+and installation code should look something like:
+
+------------------------------------------
+ void clean_foo_on_signal(int sig)
+ {
+ clean_foo();
+ sigchain_pop(sig);
+ raise(sig);
+ }
+
+ void other_func()
+ {
+ sigchain_push_common(clean_foo_on_signal);
+ mess_up_foo();
+ clean_foo();
+ }
+------------------------------------------
+
+Handlers are given the typdef of sigchain_fun. This is the same type
+that is given to signal() or sigaction(). It is perfectly reasonable to
+push SIG_DFL or SIG_IGN onto the stack.
+
+You can sigchain_push and sigchain_pop individual signals. For
+convenience, sigchain_push_common will push the handler onto the stack
+for many common signals.
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS += $(EXTRA_PROGRAMS)
+PROGRAM_OBJS += daemon.o
PROGRAM_OBJS += fast-import.o
PROGRAM_OBJS += imap-send.o
PROGRAM_OBJS += shell.o
LIB_H += compat/cygwin.h
LIB_H += compat/mingw.h
LIB_H += compat/win32/pthread.h
+LIB_H += compat/win32/syslog.h
+LIB_H += compat/win32/sys/poll.h
LIB_H += csum-file.h
LIB_H += decorate.h
LIB_H += delta.h
NO_SVN_TESTS = YesPlease
NO_PERL_MAKEMAKER = YesPlease
RUNTIME_PREFIX = YesPlease
- NO_POSIX_ONLY_PROGRAMS = YesPlease
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease
NO_CURL = YesPlease
NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease
+ NO_POSIX_GOODIES = UnfortunatelyYes
NATIVE_CRLF = YesPlease
CC = compat/vcbuild/scripts/clink.pl
AR = compat/vcbuild/scripts/lib.pl
CFLAGS =
BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
- COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o
+ COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o compat/win32/syslog.o compat/win32/sys/poll.o
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
NO_SVN_TESTS = YesPlease
NO_PERL_MAKEMAKER = YesPlease
RUNTIME_PREFIX = YesPlease
- NO_POSIX_ONLY_PROGRAMS = YesPlease
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease
NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease
ETAGS_TARGET = ETAGS
+ NO_INET_PTON = YesPlease
+ NO_INET_NTOP = YesPlease
+ NO_POSIX_GOODIES = UnfortunatelyYes
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
- compat/win32/pthread.o
+ compat/win32/pthread.o compat/win32/syslog.o \
+ compat/win32/sys/poll.o
EXTLIBS += -lws2_32
PTHREAD_LIBS =
X = .exe
endif
EXTLIBS += -lz
-ifndef NO_POSIX_ONLY_PROGRAMS
- PROGRAM_OBJS += daemon.o
-endif
ifndef NO_OPENSSL
OPENSSL_LIBSSL = -lssl
ifdef OPENSSLDIR
endif
ifdef NO_INET_NTOP
LIB_OBJS += compat/inet_ntop.o
+ BASIC_CFLAGS += -DNO_INET_NTOP
endif
ifdef NO_INET_PTON
LIB_OBJS += compat/inet_pton.o
+ BASIC_CFLAGS += -DNO_INET_PTON
endif
ifdef NO_ICONV
BASIC_CFLAGS += -DNO_DEFLATE_BOUND
endif
+ifdef NO_POSIX_GOODIES
+ BASIC_CFLAGS += -DNO_POSIX_GOODIES
+endif
+
ifdef BLK_SHA1
SHA1_HEADER = "block-sha1/sha1.h"
LIB_OBJS += block-sha1/sha1.o
git-imap-send$X: imap-send.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
+ $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
extern int check_pager_config(const char *cmd);
-extern int textconv_object(const char *path, const unsigned char *sha1, char **buf, unsigned long *buf_size);
+extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);
extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
unsigned long len;
void *dst;
+ if (!fragment)
+ return error("missing binary patch data for '%s'",
+ patch->new_name ?
+ patch->new_name :
+ patch->old_name);
+
/* Binary patch is irreversible without the optional second hunk */
if (apply_in_reverse) {
if (!fragment->next)
struct commit *commit;
mmfile_t file;
unsigned char blob_sha1[20];
+ unsigned mode;
char path[FLEX_ARRAY];
};
* Return 1 if the conversion succeeds, 0 otherwise.
*/
int textconv_object(const char *path,
+ unsigned mode,
const unsigned char *sha1,
char **buf,
unsigned long *buf_size)
struct userdiff_driver *textconv;
df = alloc_filespec(path);
- fill_filespec(df, sha1, S_IFREG | 0664);
+ fill_filespec(df, sha1, mode);
textconv = get_textconv(df);
if (!textconv) {
free_filespec(df);
num_read_blob++;
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
- textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size))
+ textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
;
else
file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
* for an origin is also used to pass the blame for the entire file to
* the parent to detect the case where a child's blob is identical to
* that of its parent's.
+ *
+ * This also fills origin->mode for corresponding tree path.
*/
-static int fill_blob_sha1(struct origin *origin)
+static int fill_blob_sha1_and_mode(struct origin *origin)
{
- unsigned mode;
if (!is_null_sha1(origin->blob_sha1))
return 0;
if (get_tree_entry(origin->commit->object.sha1,
origin->path,
- origin->blob_sha1, &mode))
+ origin->blob_sha1, &origin->mode))
goto error_out;
if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
goto error_out;
return 0;
error_out:
hashclr(origin->blob_sha1);
+ origin->mode = S_IFINVALID;
return -1;
}
/*
* If the origin was newly created (i.e. get_origin
* would call make_origin if none is found in the
- * scoreboard), it does not know the blob_sha1,
+ * scoreboard), it does not know the blob_sha1/mode,
* so copy it. Otherwise porigin was in the
- * scoreboard and already knows blob_sha1.
+ * scoreboard and already knows blob_sha1/mode.
*/
- if (porigin->refcnt == 1)
+ if (porigin->refcnt == 1) {
hashcpy(porigin->blob_sha1, cached->blob_sha1);
+ porigin->mode = cached->mode;
+ }
return porigin;
}
/* otherwise it was not very useful; free it */
/* The path is the same as parent */
porigin = get_origin(sb, parent, origin->path);
hashcpy(porigin->blob_sha1, origin->blob_sha1);
+ porigin->mode = origin->mode;
} else {
/*
* Since origin->path is a pathspec, if the parent
case 'M':
porigin = get_origin(sb, parent, origin->path);
hashcpy(porigin->blob_sha1, p->one->sha1);
+ porigin->mode = p->one->mode;
break;
case 'A':
case 'T':
cached = make_origin(porigin->commit, porigin->path);
hashcpy(cached->blob_sha1, porigin->blob_sha1);
+ cached->mode = porigin->mode;
parent->util = cached;
}
return porigin;
!strcmp(p->two->path, origin->path)) {
porigin = get_origin(sb, parent, p->one->path);
hashcpy(porigin->blob_sha1, p->one->sha1);
+ porigin->mode = p->one->mode;
break;
}
}
norigin = get_origin(sb, parent, p->one->path);
hashcpy(norigin->blob_sha1, p->one->sha1);
+ norigin->mode = p->one->mode;
fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
if (!file_p.ptr)
continue;
switch (st.st_mode & S_IFMT) {
case S_IFREG:
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
- textconv_object(read_from, null_sha1, &buf.buf, &buf_len))
+ textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len))
buf.len = buf_len;
else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
die_errno("cannot open or read '%s'", read_from);
}
else {
o = get_origin(&sb, sb.final, path);
- if (fill_blob_sha1(o))
+ if (fill_blob_sha1_and_mode(o))
die("no such path %s in %s", path, final_commit_name);
if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
- textconv_object(path, o->blob_sha1, (char **) &sb.final_buf,
+ textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
&sb.final_buf_size))
;
else
die("git cat-file --textconv %s: <object> must be <sha1:path>",
obj_name);
- if (!textconv_object(obj_context.path, sha1, &buf, &size))
+ if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
die("git cat-file --textconv: unable to run textconv on %s",
obj_name);
break;
{
int i;
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
- int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
+ int ignored_only = 0, config_set = 0, errors = 0;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
if (pathspec) {
memset(seen, 0, argc > 0 ? argc : 1);
matches = match_pathspec(pathspec, ent->name, len,
- baselen, seen);
+ 0, seen);
}
if (S_ISDIR(st.st_mode)) {
printf("Removing %s\n", qname);
if (remove_dir_recursively(&directory,
rm_flags) != 0) {
- warning("failed to remove '%s'", qname);
+ warning("failed to remove %s", qname);
errors++;
}
} else if (show_only) {
printf("Removing %s\n", qname);
}
if (unlink(ent->name) != 0) {
- warning("failed to remove '%s'", qname);
+ warning("failed to remove %s", qname);
errors++;
}
}
xmparam_t xmp = {{0}};
int ret = 0, i = 0, to_stdout = 0;
int quiet = 0;
+ int prefixlen = 0;
struct option options[] = {
OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
"%s\n", strerror(errno));
}
+ if (prefix)
+ prefixlen = strlen(prefix);
+
for (i = 0; i < 3; i++) {
+ const char *fname = prefix_filename(prefix, prefixlen, argv[i]);
if (!names[i])
names[i] = argv[i];
- if (read_mmfile(mmfs + i, argv[i]))
+ if (read_mmfile(mmfs + i, fname))
return -1;
if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
return error("Cannot merge binary files: %s\n",
}
} else {
if (revs->commit_format != CMIT_FMT_USERFORMAT ||
- buf.len)
- printf("%s%c", buf.buf, info->hdr_termination);
+ buf.len) {
+ fwrite(buf.buf, 1, buf.len, stdout);
+ putchar(info->hdr_termination);
+ }
}
strbuf_release(&buf);
} else {
NULL,
NULL,
NULL,
+ NULL,
};
struct child_process po;
int i;
argv[i++] = "--delta-base-offset";
if (args->quiet)
argv[i++] = "-q";
+ if (args->progress)
+ argv[i++] = "--progress";
memset(&po, 0, sizeof(po));
po.argv = argv;
po.in = -1;
}
if (finish_command(&po))
- return error("pack-objects died with strange error");
+ return -1;
return 0;
}
#include <errno.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+
+#include "../git-compat-util.h"
+
#include <stdio.h>
#include <string.h>
* Paul Vixie, 1996.
*/
static const char *
-inet_ntop4(src, dst, size)
- const u_char *src;
- char *dst;
- size_t size;
+inet_ntop4(const u_char *src, char *dst, size_t size)
{
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
* Paul Vixie, 1996.
*/
static const char *
-inet_ntop6(src, dst, size)
- const u_char *src;
- char *dst;
- size_t size;
+inet_ntop6(const u_char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* Paul Vixie, 1996.
*/
const char *
-inet_ntop(af, src, dst, size)
- int af;
- const void *src;
- char *dst;
- size_t size;
+inet_ntop(int af, const void *src, char *dst, size_t size)
{
switch (af) {
case AF_INET:
#include <errno.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+
+#include "../git-compat-util.h"
+
#include <stdio.h>
#include <string.h>
*/
static int inet_pton4(const char *src, unsigned char *dst);
+#ifndef NO_IPV6
static int inet_pton6(const char *src, unsigned char *dst);
+#endif
/* int
* inet_pton4(src, dst)
*/
static int do_lstat(int follow, const char *file_name, struct stat *buf)
{
+ int err;
WIN32_FILE_ATTRIBUTE_DATA fdata;
- if (!(errno = get_file_attr(file_name, &fdata))) {
+ if (!(err = get_file_attr(file_name, &fdata))) {
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
}
return 0;
}
+ errno = err;
return -1;
}
return 0;
}
-int poll(struct pollfd *ufds, unsigned int nfds, int timeout)
-{
- int i, pending;
-
- if (timeout >= 0) {
- if (nfds == 0) {
- Sleep(timeout);
- return 0;
- }
- return errno = EINVAL, error("poll timeout not supported");
- }
-
- /* When there is only one fd to wait for, then we pretend that
- * input is available and let the actual wait happen when the
- * caller invokes read().
- */
- if (nfds == 1) {
- if (!(ufds[0].events & POLLIN))
- return errno = EINVAL, error("POLLIN not set");
- ufds[0].revents = POLLIN;
- return 0;
- }
-
-repeat:
- pending = 0;
- for (i = 0; i < nfds; i++) {
- DWORD avail = 0;
- HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd);
- if (h == INVALID_HANDLE_VALUE)
- return -1; /* errno was set */
-
- if (!(ufds[i].events & POLLIN))
- return errno = EINVAL, error("POLLIN not set");
-
- /* this emulation works only for pipes */
- if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) {
- int err = GetLastError();
- if (err == ERROR_BROKEN_PIPE) {
- ufds[i].revents = POLLHUP;
- pending++;
- } else {
- errno = EINVAL;
- return error("PeekNamedPipe failed,"
- " GetLastError: %u", err);
- }
- } else if (avail) {
- ufds[i].revents = POLLIN;
- pending++;
- } else
- ufds[i].revents = 0;
- }
- if (!pending) {
- /* The only times that we spin here is when the process
- * that is connected through the pipes is waiting for
- * its own input data to become available. But since
- * the process (pack-objects) is itself CPU intensive,
- * it will happily pick up the time slice that we are
- * relinquishing here.
- */
- Sleep(0);
- goto repeat;
- }
- return 0;
-}
-
struct tm *gmtime_r(const time_t *timep, struct tm *result)
{
/* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
return strcasecmp(*ea, *eb);
}
+struct pinfo_t {
+ struct pinfo_t *next;
+ pid_t pid;
+ HANDLE proc;
+} pinfo_t;
+struct pinfo_t *pinfo = NULL;
+CRITICAL_SECTION pinfo_cs;
+
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
const char *dir,
int prepend_cmd, int fhin, int fhout, int fherr)
return -1;
}
CloseHandle(pi.hThread);
- return (pid_t)pi.hProcess;
+
+ /*
+ * The process ID is the human-readable identifier of the process
+ * that we want to present in log and error messages. The handle
+ * is not useful for this purpose. But we cannot close it, either,
+ * because it is not possible to turn a process ID into a process
+ * handle after the process terminated.
+ * Keep the handle in a list for waitpid.
+ */
+ EnterCriticalSection(&pinfo_cs);
+ {
+ struct pinfo_t *info = xmalloc(sizeof(struct pinfo_t));
+ info->pid = pi.dwProcessId;
+ info->proc = pi.hProcess;
+ info->next = pinfo;
+ pinfo = info;
+ }
+ LeaveCriticalSection(&pinfo_cs);
+
+ return (pid_t)pi.dwProcessId;
}
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
mingw_execve(cmd, argv, environ);
}
+int mingw_kill(pid_t pid, int sig)
+{
+ if (pid > 0 && sig == SIGTERM) {
+ HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+
+ if (TerminateProcess(h, -1)) {
+ CloseHandle(h);
+ return 0;
+ }
+
+ errno = err_win_to_posix(GetLastError());
+ CloseHandle(h);
+ return -1;
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
static char **copy_environ(void)
{
char **env;
const struct addrinfo *hints,
struct addrinfo **res)
{
- struct hostent *h = gethostbyname(node);
+ struct hostent *h = NULL;
struct addrinfo *ai;
struct sockaddr_in *sin;
- if (!h)
- return WSAGetLastError();
+ if (node) {
+ h = gethostbyname(node);
+ if (!h)
+ return WSAGetLastError();
+ }
ai = xmalloc(sizeof(struct addrinfo));
*res = ai;
ai->ai_flags = 0;
ai->ai_family = AF_INET;
- ai->ai_socktype = hints->ai_socktype;
- switch (hints->ai_socktype) {
+ ai->ai_socktype = hints ? hints->ai_socktype : 0;
+ switch (ai->ai_socktype) {
case SOCK_STREAM:
ai->ai_protocol = IPPROTO_TCP;
break;
break;
}
ai->ai_addrlen = sizeof(struct sockaddr_in);
- ai->ai_canonname = strdup(h->h_name);
+ if (hints && (hints->ai_flags & AI_CANONNAME))
+ ai->ai_canonname = h ? strdup(h->h_name) : NULL;
+ else
+ ai->ai_canonname = NULL;
sin = xmalloc(ai->ai_addrlen);
memset(sin, 0, ai->ai_addrlen);
sin->sin_family = AF_INET;
+ /* Note: getaddrinfo is supposed to allow service to be a string,
+ * which should be looked up using getservbyname. This is
+ * currently not implemented */
if (service)
sin->sin_port = htons(atoi(service));
- sin->sin_addr = *(struct in_addr *)h->h_addr;
+ if (h)
+ sin->sin_addr = *(struct in_addr *)h->h_addr;
+ else if (hints && (hints->ai_flags & AI_PASSIVE))
+ sin->sin_addr.s_addr = INADDR_ANY;
+ else
+ sin->sin_addr.s_addr = INADDR_LOOPBACK;
ai->ai_addr = (struct sockaddr *)sin;
ai->ai_next = 0;
return 0;
int mingw_socket(int domain, int type, int protocol)
{
int sockfd;
- SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0);
+ SOCKET s;
+
+ ensure_socket_initialization();
+ s = WSASocket(domain, type, protocol, NULL, 0, 0);
if (s == INVALID_SOCKET) {
/*
* WSAGetLastError() values are regular BSD error codes
return connect(s, sa, sz);
}
+#undef bind
+int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
+{
+ SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+ return bind(s, sa, sz);
+}
+
+#undef setsockopt
+int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
+{
+ SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+ return setsockopt(s, lvl, optname, (const char*)optval, optlen);
+}
+
+#undef listen
+int mingw_listen(int sockfd, int backlog)
+{
+ SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+ return listen(s, backlog);
+}
+
+#undef accept
+int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
+{
+ int sockfd2;
+
+ SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
+ SOCKET s2 = accept(s1, sa, sz);
+
+ /* convert into a file descriptor */
+ if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
+ int err = errno;
+ closesocket(s2);
+ return error("unable to make a socket file descriptor: %s",
+ strerror(err));
+ }
+ return sockfd2;
+}
+
#undef rename
int mingw_rename(const char *pold, const char *pnew)
{
return strbuf_detach(&buf, NULL);
}
+pid_t waitpid(pid_t pid, int *status, unsigned options)
+{
+ HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
+ FALSE, pid);
+ if (!h) {
+ errno = ECHILD;
+ return -1;
+ }
+
+ if (pid > 0 && options & WNOHANG) {
+ if (WAIT_OBJECT_0 != WaitForSingleObject(h, 0)) {
+ CloseHandle(h);
+ return 0;
+ }
+ options &= ~WNOHANG;
+ }
+
+ if (options == 0) {
+ struct pinfo_t **ppinfo;
+ if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
+ CloseHandle(h);
+ return 0;
+ }
+
+ if (status)
+ GetExitCodeProcess(h, (LPDWORD)status);
+
+ EnterCriticalSection(&pinfo_cs);
+
+ ppinfo = &pinfo;
+ while (*ppinfo) {
+ struct pinfo_t *info = *ppinfo;
+ if (info->pid == pid) {
+ CloseHandle(info->proc);
+ *ppinfo = info->next;
+ free(info);
+ break;
+ }
+ ppinfo = &info->next;
+ }
+
+ LeaveCriticalSection(&pinfo_cs);
+
+ CloseHandle(h);
+ return pid;
+ }
+ CloseHandle(h);
+
+ errno = EINVAL;
+ return -1;
+}
+
#ifndef NO_MINGW_REPLACE_READDIR
/* MinGW readdir implementation to avoid extra lstats for Git */
struct mingw_DIR
typedef int pid_t;
typedef int uid_t;
+typedef int socklen_t;
#define hstrerror strerror
#define S_IFLNK 0120000 /* Symbolic link */
#define F_SETFD 2
#define FD_CLOEXEC 0x1
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ECONNABORTED WSAECONNABORTED
+
struct passwd {
char *pw_name;
char *pw_gecos;
extern char *getpass(const char *prompt);
-#ifndef POLLIN
-struct pollfd {
- int fd; /* file descriptor */
- short events; /* requested events */
- short revents; /* returned events */
-};
-#define POLLIN 1
-#define POLLHUP 2
-#endif
-
typedef void (__cdecl *sig_handler_t)(int);
struct sigaction {
sig_handler_t sa_handler;
}
#define unlink mingw_unlink
-static inline pid_t waitpid(pid_t pid, int *status, unsigned options)
-{
- if (options == 0)
- return _cwait(status, pid, 0);
- errno = EINVAL;
- return -1;
-}
+#define WNOHANG 1
+pid_t waitpid(pid_t pid, int *status, unsigned options);
+
+#define kill mingw_kill
+int mingw_kill(pid_t pid, int sig);
#ifndef NO_OPENSSL
#include <openssl/ssl.h>
unsigned int sleep (unsigned int seconds);
int mkstemp(char *template);
int gettimeofday(struct timeval *tv, void *tz);
-int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
struct tm *localtime_r(const time_t *timep, struct tm *result);
int getpagesize(void); /* defined in MinGW's libgcc.a */
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
#define connect mingw_connect
+int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
+#define bind mingw_bind
+
+int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
+#define setsockopt mingw_setsockopt
+
+int mingw_listen(int sockfd, int backlog);
+#define listen mingw_listen
+
+int mingw_accept(int sockfd, struct sockaddr *sa, socklen_t *sz);
+#define accept mingw_accept
+
int mingw_rename(const char*, const char*);
#define rename mingw_rename
static int mingw_main(); \
int main(int argc, const char **argv) \
{ \
+ extern CRITICAL_SECTION pinfo_cs; \
_fmode = _O_BINARY; \
_setmode(_fileno(stdin), _O_BINARY); \
_setmode(_fileno(stdout), _O_BINARY); \
_setmode(_fileno(stderr), _O_BINARY); \
argv[0] = xstrdup(_pgmptr); \
+ InitializeCriticalSection(&pinfo_cs); \
return mingw_main(argc, argv); \
} \
static int mingw_main(c,v)
--- /dev/null
+/* Emulation for poll(2)
+ Contributed by Paolo Bonzini.
+
+ Copyright 2001-2003, 2006-2010 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Tell gcc not to warn about the (nfd < 0) tests, below. */
+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+#include <malloc.h>
+
+#include <sys/types.h>
+#include "poll.h"
+#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WIN32_NATIVE
+# include <winsock2.h>
+# include <windows.h>
+# include <io.h>
+# include <stdio.h>
+# include <conio.h>
+#else
+# include <sys/time.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include <time.h>
+
+#ifndef INFTIM
+# define INFTIM (-1)
+#endif
+
+/* BeOS does not have MSG_PEEK. */
+#ifndef MSG_PEEK
+# define MSG_PEEK 0
+#endif
+
+#ifdef WIN32_NATIVE
+
+#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle (HANDLE h)
+{
+ WSANETWORKEVENTS ev;
+
+ if (IsConsoleHandle (h))
+ return FALSE;
+
+ /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+ WSAEnumNetworkEvents instead distinguishes the two correctly. */
+ ev.lNetworkEvents = 0xDEADBEEF;
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ return ev.lNetworkEvents != 0xDEADBEEF;
+}
+
+/* Declare data structures for ntdll functions. */
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+ ULONG NamedPipeType;
+ ULONG NamedPipeConfiguration;
+ ULONG MaximumInstances;
+ ULONG CurrentInstances;
+ ULONG InboundQuota;
+ ULONG ReadDataAvailable;
+ ULONG OutboundQuota;
+ ULONG WriteQuotaAvailable;
+ ULONG NamedPipeState;
+ ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+typedef struct _IO_STATUS_BLOCK
+{
+ union {
+ DWORD Status;
+ PVOID Pointer;
+ } u;
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FilePipeLocalInformation = 24
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef DWORD (WINAPI *PNtQueryInformationFile)
+ (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
+
+# ifndef PIPE_BUF
+# define PIPE_BUF 512
+# endif
+
+/* Compute revents values for file handle H. If some events cannot happen
+ for the handle, eliminate them from *P_SOUGHT. */
+
+static int
+win32_compute_revents (HANDLE h, int *p_sought)
+{
+ int i, ret, happened;
+ INPUT_RECORD *irbuffer;
+ DWORD avail, nbuffer;
+ BOOL bRet;
+ IO_STATUS_BLOCK iosb;
+ FILE_PIPE_LOCAL_INFORMATION fpli;
+ static PNtQueryInformationFile NtQueryInformationFile;
+ static BOOL once_only;
+
+ switch (GetFileType (h))
+ {
+ case FILE_TYPE_PIPE:
+ if (!once_only)
+ {
+ NtQueryInformationFile = (PNtQueryInformationFile)
+ GetProcAddress (GetModuleHandle ("ntdll.dll"),
+ "NtQueryInformationFile");
+ once_only = TRUE;
+ }
+
+ happened = 0;
+ if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
+ {
+ if (avail)
+ happened |= *p_sought & (POLLIN | POLLRDNORM);
+ }
+ else if (GetLastError () == ERROR_BROKEN_PIPE)
+ happened |= POLLHUP;
+
+ else
+ {
+ /* It was the write-end of the pipe. Check if it is writable.
+ If NtQueryInformationFile fails, optimistically assume the pipe is
+ writable. This could happen on Win9x, where NtQueryInformationFile
+ is not available, or if we inherit a pipe that doesn't permit
+ FILE_READ_ATTRIBUTES access on the write end (I think this should
+ not happen since WinXP SP2; WINE seems fine too). Otherwise,
+ ensure that enough space is available for atomic writes. */
+ memset (&iosb, 0, sizeof (iosb));
+ memset (&fpli, 0, sizeof (fpli));
+
+ if (!NtQueryInformationFile
+ || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
+ FilePipeLocalInformation)
+ || fpli.WriteQuotaAvailable >= PIPE_BUF
+ || (fpli.OutboundQuota < PIPE_BUF &&
+ fpli.WriteQuotaAvailable == fpli.OutboundQuota))
+ happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ }
+ return happened;
+
+ case FILE_TYPE_CHAR:
+ ret = WaitForSingleObject (h, 0);
+ if (!IsConsoleHandle (h))
+ return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
+
+ nbuffer = avail = 0;
+ bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
+ if (bRet)
+ {
+ /* Input buffer. */
+ *p_sought &= POLLIN | POLLRDNORM;
+ if (nbuffer == 0)
+ return POLLHUP;
+ if (!*p_sought)
+ return 0;
+
+ irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
+ bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
+ if (!bRet || avail == 0)
+ return POLLHUP;
+
+ for (i = 0; i < avail; i++)
+ if (irbuffer[i].EventType == KEY_EVENT)
+ return *p_sought;
+ return 0;
+ }
+ else
+ {
+ /* Screen buffer. */
+ *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
+ return *p_sought;
+ }
+
+ default:
+ ret = WaitForSingleObject (h, 0);
+ if (ret == WAIT_OBJECT_0)
+ return *p_sought & ~(POLLPRI | POLLRDBAND);
+
+ return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+ }
+}
+
+/* Convert fd_sets returned by select into revents values. */
+
+static int
+win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
+{
+ int happened = 0;
+
+ if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
+ {
+ int r, error;
+
+ char data[64];
+ WSASetLastError (0);
+ r = recv (h, data, sizeof (data), MSG_PEEK);
+ error = WSAGetLastError ();
+ WSASetLastError (0);
+
+ if (r > 0 || error == WSAENOTCONN)
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ /* Distinguish hung-up sockets from other errors. */
+ else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
+ || error == WSAECONNABORTED || error == WSAENETRESET)
+ happened |= POLLHUP;
+
+ else
+ happened |= POLLERR;
+ }
+
+ if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
+ happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+ if (lNetworkEvents & FD_OOB)
+ happened |= (POLLPRI | POLLRDBAND) & sought;
+
+ return happened;
+}
+
+#else /* !MinGW */
+
+/* Convert select(2) returned fd_sets into poll(2) revents values. */
+static int
+compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
+{
+ int happened = 0;
+ if (FD_ISSET (fd, rfds))
+ {
+ int r;
+ int socket_errno;
+
+# if defined __MACH__ && defined __APPLE__
+ /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
+ for some kinds of descriptors. Detect if this descriptor is a
+ connected socket, a server socket, or something else using a
+ 0-byte recv, and use ioctl(2) to detect POLLHUP. */
+ r = recv (fd, NULL, 0, MSG_PEEK);
+ socket_errno = (r < 0) ? errno : 0;
+ if (r == 0 || socket_errno == ENOTSOCK)
+ ioctl (fd, FIONREAD, &r);
+# else
+ char data[64];
+ r = recv (fd, data, sizeof (data), MSG_PEEK);
+ socket_errno = (r < 0) ? errno : 0;
+# endif
+ if (r == 0)
+ happened |= POLLHUP;
+
+ /* If the event happened on an unconnected server socket,
+ that's fine. */
+ else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
+ happened |= (POLLIN | POLLRDNORM) & sought;
+
+ /* Distinguish hung-up sockets from other errors. */
+ else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
+ || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
+ happened |= POLLHUP;
+
+ else
+ happened |= POLLERR;
+ }
+
+ if (FD_ISSET (fd, wfds))
+ happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+ if (FD_ISSET (fd, efds))
+ happened |= (POLLPRI | POLLRDBAND) & sought;
+
+ return happened;
+}
+#endif /* !MinGW */
+
+int
+poll (pfd, nfd, timeout)
+ struct pollfd *pfd;
+ nfds_t nfd;
+ int timeout;
+{
+#ifndef WIN32_NATIVE
+ fd_set rfds, wfds, efds;
+ struct timeval tv;
+ struct timeval *ptv;
+ int maxfd, rc;
+ nfds_t i;
+
+# ifdef _SC_OPEN_MAX
+ static int sc_open_max = -1;
+
+ if (nfd < 0
+ || (nfd > sc_open_max
+ && (sc_open_max != -1
+ || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+# else /* !_SC_OPEN_MAX */
+# ifdef OPEN_MAX
+ if (nfd < 0 || nfd > OPEN_MAX)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+# endif /* OPEN_MAX -- else, no check is needed */
+# endif /* !_SC_OPEN_MAX */
+
+ /* EFAULT is not necessary to implement, but let's do it in the
+ simplest case. */
+ if (!pfd)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+
+ /* convert timeout number into a timeval structure */
+ if (timeout == 0)
+ {
+ ptv = &tv;
+ ptv->tv_sec = 0;
+ ptv->tv_usec = 0;
+ }
+ else if (timeout > 0)
+ {
+ ptv = &tv;
+ ptv->tv_sec = timeout / 1000;
+ ptv->tv_usec = (timeout % 1000) * 1000;
+ }
+ else if (timeout == INFTIM)
+ /* wait forever */
+ ptv = NULL;
+ else
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* create fd sets and determine max fd */
+ maxfd = -1;
+ FD_ZERO (&rfds);
+ FD_ZERO (&wfds);
+ FD_ZERO (&efds);
+ for (i = 0; i < nfd; i++)
+ {
+ if (pfd[i].fd < 0)
+ continue;
+
+ if (pfd[i].events & (POLLIN | POLLRDNORM))
+ FD_SET (pfd[i].fd, &rfds);
+
+ /* see select(2): "the only exceptional condition detectable
+ is out-of-band data received on a socket", hence we push
+ POLLWRBAND events onto wfds instead of efds. */
+ if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
+ FD_SET (pfd[i].fd, &wfds);
+ if (pfd[i].events & (POLLPRI | POLLRDBAND))
+ FD_SET (pfd[i].fd, &efds);
+ if (pfd[i].fd >= maxfd
+ && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
+ | POLLRDNORM | POLLRDBAND
+ | POLLWRNORM | POLLWRBAND)))
+ {
+ maxfd = pfd[i].fd;
+ if (maxfd > FD_SETSIZE)
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ }
+ }
+
+ /* examine fd sets */
+ rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
+ if (rc < 0)
+ return rc;
+
+ /* establish results */
+ rc = 0;
+ for (i = 0; i < nfd; i++)
+ if (pfd[i].fd < 0)
+ pfd[i].revents = 0;
+ else
+ {
+ int happened = compute_revents (pfd[i].fd, pfd[i].events,
+ &rfds, &wfds, &efds);
+ if (happened)
+ {
+ pfd[i].revents = happened;
+ rc++;
+ }
+ }
+
+ return rc;
+#else
+ static struct timeval tv0;
+ static HANDLE hEvent;
+ WSANETWORKEVENTS ev;
+ HANDLE h, handle_array[FD_SETSIZE + 2];
+ DWORD ret, wait_timeout, nhandles;
+ fd_set rfds, wfds, xfds;
+ BOOL poll_again;
+ MSG msg;
+ int rc = 0;
+ nfds_t i;
+
+ if (nfd < 0 || timeout < -1)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!hEvent)
+ hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+ handle_array[0] = hEvent;
+ nhandles = 1;
+ FD_ZERO (&rfds);
+ FD_ZERO (&wfds);
+ FD_ZERO (&xfds);
+
+ /* Classify socket handles and create fd sets. */
+ for (i = 0; i < nfd; i++)
+ {
+ int sought = pfd[i].events;
+ pfd[i].revents = 0;
+ if (pfd[i].fd < 0)
+ continue;
+ if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
+ | POLLPRI | POLLRDBAND)))
+ continue;
+
+ h = (HANDLE) _get_osfhandle (pfd[i].fd);
+ assert (h != NULL);
+ if (IsSocketHandle (h))
+ {
+ int requested = FD_CLOSE;
+
+ /* see above; socket handles are mapped onto select. */
+ if (sought & (POLLIN | POLLRDNORM))
+ {
+ requested |= FD_READ | FD_ACCEPT;
+ FD_SET ((SOCKET) h, &rfds);
+ }
+ if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
+ {
+ requested |= FD_WRITE | FD_CONNECT;
+ FD_SET ((SOCKET) h, &wfds);
+ }
+ if (sought & (POLLPRI | POLLRDBAND))
+ {
+ requested |= FD_OOB;
+ FD_SET ((SOCKET) h, &xfds);
+ }
+
+ if (requested)
+ WSAEventSelect ((SOCKET) h, hEvent, requested);
+ }
+ else
+ {
+ /* Poll now. If we get an event, do not poll again. Also,
+ screen buffer handles are waitable, and they'll block until
+ a character is available. win32_compute_revents eliminates
+ bits for the "wrong" direction. */
+ pfd[i].revents = win32_compute_revents (h, &sought);
+ if (sought)
+ handle_array[nhandles++] = h;
+ if (pfd[i].revents)
+ timeout = 0;
+ }
+ }
+
+ if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
+ {
+ /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
+ no need to call select again. */
+ poll_again = FALSE;
+ wait_timeout = 0;
+ }
+ else
+ {
+ poll_again = TRUE;
+ if (timeout == INFTIM)
+ wait_timeout = INFINITE;
+ else
+ wait_timeout = timeout;
+ }
+
+ for (;;)
+ {
+ ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
+ wait_timeout, QS_ALLINPUT);
+
+ if (ret == WAIT_OBJECT_0 + nhandles)
+ {
+ /* new input of some other kind */
+ BOOL bRet;
+ while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+ else
+ break;
+ }
+
+ if (poll_again)
+ select (0, &rfds, &wfds, &xfds, &tv0);
+
+ /* Place a sentinel at the end of the array. */
+ handle_array[nhandles] = NULL;
+ nhandles = 1;
+ for (i = 0; i < nfd; i++)
+ {
+ int happened;
+
+ if (pfd[i].fd < 0)
+ continue;
+ if (!(pfd[i].events & (POLLIN | POLLRDNORM |
+ POLLOUT | POLLWRNORM | POLLWRBAND)))
+ continue;
+
+ h = (HANDLE) _get_osfhandle (pfd[i].fd);
+ if (h != handle_array[nhandles])
+ {
+ /* It's a socket. */
+ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+ WSAEventSelect ((SOCKET) h, 0, 0);
+
+ /* If we're lucky, WSAEnumNetworkEvents already provided a way
+ to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
+ if (FD_ISSET ((SOCKET) h, &rfds)
+ && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
+ ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
+ if (FD_ISSET ((SOCKET) h, &wfds))
+ ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
+ if (FD_ISSET ((SOCKET) h, &xfds))
+ ev.lNetworkEvents |= FD_OOB;
+
+ happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
+ ev.lNetworkEvents);
+ }
+ else
+ {
+ /* Not a socket. */
+ int sought = pfd[i].events;
+ happened = win32_compute_revents (h, &sought);
+ nhandles++;
+ }
+
+ if ((pfd[i].revents |= happened) != 0)
+ rc++;
+ }
+
+ return rc;
+#endif
+}
--- /dev/null
+/* Header for poll(2) emulation
+ Contributed by Paolo Bonzini.
+
+ Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _GL_POLL_H
+#define _GL_POLL_H
+
+/* fake a poll(2) environment */
+#define POLLIN 0x0001 /* any readable data available */
+#define POLLPRI 0x0002 /* OOB/Urgent readable data */
+#define POLLOUT 0x0004 /* file descriptor is writeable */
+#define POLLERR 0x0008 /* some poll error occurred */
+#define POLLHUP 0x0010 /* file descriptor was "hung up" */
+#define POLLNVAL 0x0020 /* requested events "invalid" */
+#define POLLRDNORM 0x0040
+#define POLLRDBAND 0x0080
+#define POLLWRNORM 0x0100
+#define POLLWRBAND 0x0200
+
+struct pollfd
+{
+ int fd; /* which file descriptor to poll */
+ short events; /* events we are interested in */
+ short revents; /* events found on return */
+};
+
+typedef unsigned long nfds_t;
+
+extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
+
+/* Define INFTIM only if doing so conforms to POSIX. */
+#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
+#define INFTIM (-1)
+#endif
+
+#endif /* _GL_POLL_H */
--- /dev/null
+#include "../../git-compat-util.h"
+#include "../../strbuf.h"
+
+static HANDLE ms_eventlog;
+
+void openlog(const char *ident, int logopt, int facility)
+{
+ if (ms_eventlog)
+ return;
+
+ ms_eventlog = RegisterEventSourceA(NULL, ident);
+
+ if (!ms_eventlog)
+ warning("RegisterEventSource() failed: %lu", GetLastError());
+}
+
+void syslog(int priority, const char *fmt, ...)
+{
+ struct strbuf sb = STRBUF_INIT;
+ struct strbuf_expand_dict_entry dict[] = {
+ {"1", "% 1"},
+ {NULL, NULL}
+ };
+ WORD logtype;
+ char *str;
+ int str_len;
+ va_list ap;
+
+ if (!ms_eventlog)
+ return;
+
+ va_start(ap, fmt);
+ str_len = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ if (str_len < 0) {
+ warning("vsnprintf failed: '%s'", strerror(errno));
+ return;
+ }
+
+ str = malloc(str_len + 1);
+ va_start(ap, fmt);
+ vsnprintf(str, str_len + 1, fmt, ap);
+ va_end(ap);
+ strbuf_expand(&sb, str, strbuf_expand_dict_cb, &dict);
+ free(str);
+
+ switch (priority) {
+ case LOG_EMERG:
+ case LOG_ALERT:
+ case LOG_CRIT:
+ case LOG_ERR:
+ logtype = EVENTLOG_ERROR_TYPE;
+ break;
+
+ case LOG_WARNING:
+ logtype = EVENTLOG_WARNING_TYPE;
+ break;
+
+ case LOG_NOTICE:
+ case LOG_INFO:
+ case LOG_DEBUG:
+ default:
+ logtype = EVENTLOG_INFORMATION_TYPE;
+ break;
+ }
+
+ ReportEventA(ms_eventlog, logtype, 0, 0, NULL, 1, 0,
+ (const char **)&sb.buf, NULL);
+
+ strbuf_release(&sb);
+}
--- /dev/null
+#ifndef SYSLOG_H
+#define SYSLOG_H
+
+#define LOG_PID 0x01
+
+#define LOG_EMERG 0
+#define LOG_ALERT 1
+#define LOG_CRIT 2
+#define LOG_ERR 3
+#define LOG_WARNING 4
+#define LOG_NOTICE 5
+#define LOG_INFO 6
+#define LOG_DEBUG 7
+
+#define LOG_DAEMON (3<<3)
+
+void openlog(const char *ident, int logopt, int facility);
+void syslog(int priority, const char *fmt, ...);
+
+#endif /* SYSLOG_H */
if (config_parameters)
found += 1;
- if (found == 0)
- return -1;
- return ret;
+ return ret == 0 ? found : ret;
}
/*
branch = os.path.basename(refname)
# Compute a shortnane for the revision
- rev = do("git describe ${merged} 2>/dev/null") or merged[:12]
+ rev = do("git describe '"+ merged +"' 2>/dev/null") or merged[:12]
# Extract the neta-information for the commit
rawcommit = do("git cat-file commit " + merged)
done
}
-# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
+# __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments
+# presence of 2nd argument means use the guess heuristic employed
+# by checkout for tracking branches
__git_refs ()
{
- local i is_hash=y dir="$(__gitdir "${1-}")"
+ local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
local cur="${COMP_WORDS[COMP_CWORD]}" format refs
if [ -d "$dir" ]; then
case "$cur" in
refs|refs/*)
format="refname"
refs="${cur%/*}"
+ track=""
;;
*)
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
esac
git --git-dir="$dir" for-each-ref --format="%($format)" \
$refs
+ if [ -n "$track" ]; then
+ # employ the heuristic used by git checkout
+ # Try to find a remote branch that matches the completion word
+ # but only output if the branch name is unique
+ local ref entry
+ git --git-dir="$dir" for-each-ref --shell --format="ref=%(refname:short)" \
+ "refs/remotes/" | \
+ while read entry; do
+ eval "$entry"
+ ref="${ref#*/}"
+ if [[ "$ref" == "$cur"* ]]; then
+ echo "$ref"
+ fi
+ done | uniq -u
+ fi
return
fi
for i in $(git ls-remote "$dir" 2>/dev/null); do
: ${__git_porcelain_commands:=$(__git_list_porcelain_commands)}
}
+__git_pretty_aliases ()
+{
+ local i IFS=$'\n'
+ for i in $(git --git-dir="$(__gitdir)" config --get-regexp "pretty\..*" 2>/dev/null); do
+ case "$i" in
+ pretty.*)
+ i="${i#pretty.}"
+ echo "${i/ */}"
+ ;;
+ esac
+ done
+}
+
__git_aliases ()
{
local i IFS=$'\n'
local subcommands="start bad good skip reset visualize replay log run"
local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
- __gitcomp "$subcommands"
+ if [ -f "$(__gitdir)"/BISECT_START ]; then
+ __gitcomp "$subcommands"
+ else
+ __gitcomp "replay start"
+ fi
return
fi
case "$subcommand" in
- bad|good|reset|skip)
+ bad|good|reset|skip|start)
__gitcomp "$(__git_refs)"
;;
*)
"
;;
*)
- __gitcomp "$(__git_refs)"
+ # check if --track, --no-track, or --no-guess was specified
+ # if so, disable DWIM mode
+ local flags="--track --no-track --no-guess" track=1
+ if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
+ track=''
+ fi
+ __gitcomp "$(__git_refs '' $track)"
;;
esac
}
fi
case "$cur" in
--pretty=*)
- __gitcomp "$__git_log_pretty_formats
+ __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
" "" "${cur##--pretty=}"
return
;;
--format=*)
- __gitcomp "$__git_log_pretty_formats
+ __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
" "" "${cur##--format=}"
return
;;
_git_notes ()
{
- local subcommands="edit show"
- if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
- __gitcomp "$subcommands"
- return
- fi
+ local subcommands='add append copy edit list prune remove show'
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
+ local cur="${COMP_WORDS[COMP_CWORD]}"
- case "${COMP_WORDS[COMP_CWORD-1]}" in
- -m|-F)
- COMPREPLY=()
+ case "$subcommand,$cur" in
+ ,--*)
+ __gitcomp '--ref'
+ ;;
+ ,*)
+ case "${COMP_WORDS[COMP_CWORD-1]}" in
+ --ref)
+ __gitcomp "$(__git_refs)"
+ ;;
+ *)
+ __gitcomp "$subcommands --ref"
+ ;;
+ esac
+ ;;
+ add,--reuse-message=*|append,--reuse-message=*)
+ __gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}"
+ ;;
+ add,--reedit-message=*|append,--reedit-message=*)
+ __gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}"
+ ;;
+ add,--*|append,--*)
+ __gitcomp '--file= --message= --reedit-message=
+ --reuse-message='
+ ;;
+ copy,--*)
+ __gitcomp '--stdin'
+ ;;
+ prune,--*)
+ __gitcomp '--dry-run --verbose'
+ ;;
+ prune,*)
;;
*)
- __gitcomp "$(__git_refs)"
+ case "${COMP_WORDS[COMP_CWORD-1]}" in
+ -m|-F)
+ ;;
+ *)
+ __gitcomp "$(__git_refs)"
+ ;;
+ esac
;;
esac
}
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--pretty=*)
- __gitcomp "$__git_log_pretty_formats
+ __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
" "" "${cur##--pretty=}"
return
;;
--format=*)
- __gitcomp "$__git_log_pretty_formats
+ __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
" "" "${cur##--format=}"
return
;;
{
local i c=1 command __git_dir
- if [[ -n $ZSH_VERSION ]]; then
+ if [[ -n ${ZSH_VERSION-} ]]; then
emulate -L bash
setopt KSH_TYPESET
fi
_gitk ()
{
- if [[ -n $ZSH_VERSION ]]; then
+ if [[ -n ${ZSH_VERSION-} ]]; then
emulate -L bash
setopt KSH_TYPESET
fi
|| complete -o default -o nospace -F _git git.exe
fi
-if [[ -n $ZSH_VERSION ]]; then
+if [[ -n ${ZSH_VERSION-} ]]; then
shopt () {
local option
if [ $# -ne 2 ]; then
;;; Code:
(eval-when-compile (require 'cl)) ; to use `push', `pop'
+(require 'format-spec)
(defface git-blame-prefix-face
'((((background dark)) (:foreground "gray"
submitTemplate = self.prepareLogMessage(template, logMessage)
if os.environ.has_key("P4DIFF"):
del(os.environ["P4DIFF"])
- diff = p4_read_pipe("diff -du ...")
+ diff = ""
+ for editedFile in editedFiles:
+ diff += p4_read_pipe("diff -du %r" % editedFile)
newdiff = ""
for newFile in filesToAdd:
#include "strbuf.h"
#include "string-list.h"
-#include <syslog.h>
-
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 256
#endif
" [--strict-paths] [--base-path=<path>] [--base-path-relaxed]\n"
" [--user-path | --user-path=<path>]\n"
" [--interpolated-path=<path>]\n"
-" [--reuseaddr] [--detach] [--pid-file=<file>]\n"
+" [--reuseaddr] [--pid-file=<file>]\n"
" [--(enable|disable|allow-override|forbid-override)=<service>]\n"
" [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
-" [--user=<user> [--group=<group>]]\n"
+" [--detach] [--user=<user> [--group=<group>]]\n"
" [<directory>...]";
/* List of acceptable pathname prefixes */
syslog(priority, "%s", buf);
} else {
/*
- * Since stderr is set to linebuffered mode, the
+ * Since stderr is set to buffered mode, the
* logging of different processes will not overlap
+ * unless they overflow the (rather big) buffers.
*/
fprintf(stderr, "[%"PRIuMAX"] ", (uintmax_t)getpid());
vfprintf(stderr, err, params);
fputc('\n', stderr);
+ fflush(stderr);
}
}
}
-static int execute(struct sockaddr *addr)
+static int execute(void)
{
static char line[1000];
int pktlen, len, i;
+ char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT");
- if (addr) {
- char addrbuf[256] = "";
- int port = -1;
-
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin_addr = (void *) addr;
- inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
- port = ntohs(sin_addr->sin_port);
-#ifndef NO_IPV6
- } else if (addr && addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6_addr = (void *) addr;
-
- char *buf = addrbuf;
- *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
- inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
- strcat(buf, "]");
-
- port = ntohs(sin6_addr->sin6_port);
-#endif
- }
- loginfo("Connection from %s:%d", addrbuf, port);
- setenv("REMOTE_ADDR", addrbuf, 1);
- }
- else {
- unsetenv("REMOTE_ADDR");
- }
+ if (addr)
+ loginfo("Connection from %s:%s", addr, port);
alarm(init_timeout ? init_timeout : timeout);
pktlen = packet_read_line(0, line, sizeof(line));
static struct child {
struct child *next;
- pid_t pid;
+ struct child_process cld;
struct sockaddr_storage address;
} *firstborn;
-static void add_child(pid_t pid, struct sockaddr *addr, int addrlen)
+static void add_child(struct child_process *cld, struct sockaddr *addr, socklen_t addrlen)
{
struct child *newborn, **cradle;
newborn = xcalloc(1, sizeof(*newborn));
live_children++;
- newborn->pid = pid;
+ memcpy(&newborn->cld, cld, sizeof(*cld));
memcpy(&newborn->address, addr, addrlen);
for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next)
if (!addrcmp(&(*cradle)->address, &newborn->address))
*cradle = newborn;
}
-static void remove_child(pid_t pid)
-{
- struct child **cradle, *blanket;
-
- for (cradle = &firstborn; (blanket = *cradle); cradle = &blanket->next)
- if (blanket->pid == pid) {
- *cradle = blanket->next;
- live_children--;
- free(blanket);
- break;
- }
-}
-
/*
* This gets called if the number of connections grows
* past "max_connections".
for (; (next = blanket->next); blanket = next)
if (!addrcmp(&blanket->address, &next->address)) {
- kill(blanket->pid, SIGTERM);
+ kill(blanket->cld.pid, SIGTERM);
break;
}
}
int status;
pid_t pid;
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
- const char *dead = "";
- remove_child(pid);
- if (!WIFEXITED(status) || (WEXITSTATUS(status) > 0))
- dead = " (with error)";
- loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
- }
+ struct child **cradle, *blanket;
+ for (cradle = &firstborn; (blanket = *cradle);)
+ if ((pid = waitpid(blanket->cld.pid, &status, WNOHANG)) > 1) {
+ const char *dead = "";
+ if (status)
+ dead = " (with error)";
+ loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead);
+
+ /* remove the child */
+ *cradle = blanket->next;
+ live_children--;
+ free(blanket);
+ } else
+ cradle = &blanket->next;
}
-static void handle(int incoming, struct sockaddr *addr, int addrlen)
+static char **cld_argv;
+static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
{
- pid_t pid;
+ struct child_process cld = { 0 };
+ char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
+ char *env[] = { addrbuf, portbuf, NULL };
if (max_connections && live_children >= max_connections) {
kill_some_child();
}
}
- if ((pid = fork())) {
- close(incoming);
- if (pid < 0) {
- logerror("Couldn't fork %s", strerror(errno));
- return;
- }
+ if (addr->sa_family == AF_INET) {
+ struct sockaddr_in *sin_addr = (void *) addr;
+ inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf + 12,
+ sizeof(addrbuf) - 12);
+ snprintf(portbuf, sizeof(portbuf), "REMOTE_PORT=%d",
+ ntohs(sin_addr->sin_port));
+#ifndef NO_IPV6
+ } else if (addr && addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6_addr = (void *) addr;
- add_child(pid, addr, addrlen);
- return;
+ char *buf = addrbuf + 12;
+ *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
+ inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf,
+ sizeof(addrbuf) - 13);
+ strcat(buf, "]");
+
+ snprintf(portbuf, sizeof(portbuf), "REMOTE_PORT=%d",
+ ntohs(sin6_addr->sin6_port));
+#endif
}
- dup2(incoming, 0);
- dup2(incoming, 1);
- close(incoming);
+ cld.env = (const char **)env;
+ cld.argv = (const char **)cld_argv;
+ cld.in = incoming;
+ cld.out = dup(incoming);
- exit(execute(addr));
+ if (start_command(&cld))
+ logerror("unable to fork");
+ else
+ add_child(&cld, addr, addrlen);
+ close(incoming);
}
static void child_handler(int signo)
for (i = 0; i < socklist->nr; i++) {
if (pfd[i].revents & POLLIN) {
- struct sockaddr_storage ss;
- unsigned int sslen = sizeof(ss);
- int incoming = accept(pfd[i].fd, (struct sockaddr *)&ss, &sslen);
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sai;
+#ifndef NO_IPV6
+ struct sockaddr_in6 sai6;
+#endif
+ } ss;
+ socklen_t sslen = sizeof(ss);
+ int incoming = accept(pfd[i].fd, &ss.sa, &sslen);
if (incoming < 0) {
switch (errno) {
case EAGAIN:
die_errno("accept returned");
}
}
- handle(incoming, (struct sockaddr *)&ss, sslen);
+ handle(incoming, &ss.sa, sslen);
}
}
}
close(fd);
}
+#ifdef NO_POSIX_GOODIES
+
+struct credentials;
+
+static void drop_privileges(struct credentials *cred)
+{
+ /* nothing */
+}
+
+static void daemonize(void)
+{
+ die("--detach not supported on this platform");
+}
+
+static struct credentials *prepare_credentials(const char *user_name,
+ const char *group_name)
+{
+ die("--user not supported on this platform");
+}
+
+#else
+
+struct credentials {
+ struct passwd *pass;
+ gid_t gid;
+};
+
+static void drop_privileges(struct credentials *cred)
+{
+ if (cred && (initgroups(cred->pass->pw_name, cred->gid) ||
+ setgid (cred->gid) || setuid(cred->pass->pw_uid)))
+ die("cannot drop privileges");
+}
+
+static struct credentials *prepare_credentials(const char *user_name,
+ const char *group_name)
+{
+ static struct credentials c;
+
+ c.pass = getpwnam(user_name);
+ if (!c.pass)
+ die("user not found - %s", user_name);
+
+ if (!group_name)
+ c.gid = c.pass->pw_gid;
+ else {
+ struct group *group = getgrnam(group_name);
+ if (!group)
+ die("group not found - %s", group_name);
+
+ c.gid = group->gr_gid;
+ }
+
+ return &c;
+}
+
static void daemonize(void)
{
switch (fork()) {
close(2);
sanitize_stdfds();
}
+#endif
static void store_pid(const char *path)
{
die_errno("failed to write pid file '%s'", path);
}
-static int serve(struct string_list *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
+static int serve(struct string_list *listen_addr, int listen_port,
+ struct credentials *cred)
{
struct socketlist socklist = { NULL, 0, 0 };
die("unable to allocate any listen sockets on port %u",
listen_port);
- if (pass && gid &&
- (initgroups(pass->pw_name, gid) || setgid (gid) ||
- setuid(pass->pw_uid)))
- die("cannot drop privileges");
+ drop_privileges(cred);
return service_loop(&socklist);
}
{
int listen_port = 0;
struct string_list listen_addr = STRING_LIST_INIT_NODUP;
- int inetd_mode = 0;
+ int serve_mode = 0, inetd_mode = 0;
const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
int detach = 0;
- struct passwd *pass = NULL;
- struct group *group;
- gid_t gid = 0;
+ struct credentials *cred = NULL;
int i;
git_extract_argv0_path(argv[0]);
continue;
}
}
+ if (!strcmp(arg, "--serve")) {
+ serve_mode = 1;
+ continue;
+ }
if (!strcmp(arg, "--inetd")) {
inetd_mode = 1;
log_syslog = 1;
set_die_routine(daemon_die);
} else
/* avoid splitting a message in the middle */
- setvbuf(stderr, NULL, _IOLBF, 0);
+ setvbuf(stderr, NULL, _IOFBF, 4096);
- if (inetd_mode && (group_name || user_name))
- die("--user and --group are incompatible with --inetd");
+ if (inetd_mode && (detach || group_name || user_name))
+ die("--detach, --user and --group are incompatible with --inetd");
if (inetd_mode && (listen_port || (listen_addr.nr > 0)))
die("--listen= and --port= are incompatible with --inetd");
if (group_name && !user_name)
die("--group supplied without --user");
- if (user_name) {
- pass = getpwnam(user_name);
- if (!pass)
- die("user not found - %s", user_name);
-
- if (!group_name)
- gid = pass->pw_gid;
- else {
- group = getgrnam(group_name);
- if (!group)
- die("group not found - %s", group_name);
-
- gid = group->gr_gid;
- }
- }
+ if (user_name)
+ cred = prepare_credentials(user_name, group_name);
if (strict_paths && (!ok_paths || !*ok_paths))
die("option --strict-paths requires a whitelist");
base_path);
if (inetd_mode) {
- struct sockaddr_storage ss;
- struct sockaddr *peer = (struct sockaddr *)&ss;
- socklen_t slen = sizeof(ss);
-
if (!freopen("/dev/null", "w", stderr))
die_errno("failed to redirect stderr to /dev/null");
-
- if (getpeername(0, peer, &slen))
- peer = NULL;
-
- return execute(peer);
}
+ if (inetd_mode || serve_mode)
+ return execute();
+
if (detach) {
daemonize();
loginfo("Ready to rumble");
if (pid_file)
store_pid(pid_file);
- return serve(&listen_addr, listen_port, pass, gid);
+ /* prepare argv for serving-processes */
+ cld_argv = xmalloc(sizeof (char *) * (argc + 2));
+ for (i = 0; i < argc; ++i)
+ cld_argv[i] = argv[i];
+ cld_argv[argc] = "--serve";
+ cld_argv[argc+1] = NULL;
+
+ return serve(&listen_addr, listen_port, cred);
}
static void diff_filespec_load_driver(struct diff_filespec *one)
{
- if (!one->driver)
+ /* Use already-loaded driver */
+ if (one->driver)
+ return;
+
+ if (S_ISREG(one->mode))
one->driver = userdiff_find_by_path(one->path);
+
+ /* Fallback to default settings */
if (!one->driver)
one->driver = userdiff_find_by_name("default");
}
{
if (!DIFF_FILE_VALID(one))
return NULL;
- if (!S_ISREG(one->mode))
- return NULL;
+
diff_filespec_load_driver(one);
if (!one->driver->textconv)
return NULL;
xpp.flags = 0;
xecfg.ctxlen = 3;
- xecfg.flags = XDL_EMIT_FUNCNAMES;
+ xecfg.flags = 0;
xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
&xpp, &xecfg);
}
if (x->flags & EXC_FLAG_MUSTBEDIR) {
if (!dtype) {
- if (!prefixcmp(pathname, exclude))
+ if (!prefixcmp(pathname, exclude) &&
+ pathname[x->patternlen] == '/')
return to_exclude;
else
continue;
*)
usage ;;
esac
- git checkout "$branch" -- && bisect_clean_state
+ if git checkout "$branch" -- ; then
+ bisect_clean_state
+ else
+ die "Could not check out original HEAD '$branch'." \
+ "Try 'git bisect reset <commit>'."
+ fi
}
bisect_clean_state() {
}
bisect_replay () {
+ test "$#" -eq 1 || die "No logfile given"
test -r "$1" || die "cannot read $1 for replaying"
bisect_reset
while read git bisect command rev
done
}
+bisect_log () {
+ test -s "$GIT_DIR/BISECT_LOG" || die "We are not bisecting."
+ cat "$GIT_DIR/BISECT_LOG"
+}
case "$#" in
0)
replay)
bisect_replay "$@" ;;
log)
- cat "$GIT_DIR/BISECT_LOG" ;;
+ bisect_log ;;
run)
bisect_run "$@" ;;
*)
#include <assert.h>
#include <regex.h>
#include <utime.h>
+#include <syslog.h>
+#include <sys/poll.h>
#ifndef __MINGW32__
#include <sys/wait.h>
-#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <termios.h>
}
#endif
+#ifdef NO_INET_PTON
+int inet_pton(int af, const char *src, void *dst);
+#endif
+
+#ifdef NO_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+
extern void release_pack_memory(size_t, int);
typedef void (*try_to_free_t)(size_t);
puts stderr "source $name"
uplevel 1 real__source $name
}
+ if {[tk windowingsystem] eq "win32"} { console show }
}
######################################################################
set _nice [_which nice]
if {[catch {exec $_nice git version}]} {
set _nice {}
+ } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} {
+ set _nice {}
}
}
if {$_nice ne {}} {
if {[is_Windows]} {
wm iconbitmap . -default $oguilib/git-gui.ico
set ::tk::AlwaysShowSelection 1
+ bind . <Control-F2> {console show}
# Spoof an X11 display for SSH
if {![info exists env(DISPLAY)]} {
exit 1
}
+proc get_trimmed_version {s} {
+ set r {}
+ foreach x [split $s -._] {
+ if {[string is integer -strict $x]} {
+ lappend r $x
+ } else {
+ break
+ }
+ }
+ return [join $r .]
+}
set _real_git_version $_git_version
-regsub -- {[\-\.]dirty$} $_git_version {} _git_version
-regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
-regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
-regsub {\.GIT$} $_git_version {} _git_version
-regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
+set _git_version [get_trimmed_version $_git_version]
if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
catch {wm withdraw .}
# _gitdir exists, so try loading the config
load_config 0
apply_config
-# try to set work tree from environment, falling back to core.worktree
-if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
- set _gitworktree [get_config core.worktree]
- if {$_gitworktree eq ""} {
- set _gitworktree [file dirname [file normalize $_gitdir]]
+
+# v1.7.0 introduced --show-toplevel to return the canonical work-tree
+if {[package vsatisfies $_git_version 1.7.0]} {
+ set _gitworktree [git rev-parse --show-toplevel]
+} else {
+ # try to set work tree from environment, core.worktree or use
+ # cdup to obtain a relative path to the top of the worktree. If
+ # run from the top, the ./ prefix ensures normalize expands pwd.
+ if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+ set _gitworktree [get_config core.worktree]
+ if {$_gitworktree eq ""} {
+ set _gitworktree [file normalize ./[git rev-parse --show-cdup]]
+ }
}
}
+
if {$_prefix ne {}} {
if {$_gitworktree eq {}} {
regsub -all {[^/]+/} $_prefix ../ cdup
set s "usage: $::argv0 $::subcommand $::subcommand_args"
if {[tk windowingsystem] eq "win32"} {
wm withdraw .
- tk_messageBox -icon info -title "Usage" -message $s
+ tk_messageBox -icon info -message $s \
+ -title [mc "Usage"]
} else {
puts stderr $s
}
if {[catch {
set head [git rev-parse --verify $head]
} err]} {
- puts stderr $err
+ if {[tk windowingsystem] eq "win32"} {
+ tk_messageBox -icon error -title [mc Error] -message $err
+ } else {
+ puts stderr $err
+ }
exit 1
}
}
citool -
gui {
if {[llength $argv] != 0} {
- puts -nonewline stderr "usage: $argv0"
- if {$subcommand ne {gui}
- && [file tail $argv0] ne "git-$subcommand"} {
- puts -nonewline stderr " $subcommand"
- }
- puts stderr {}
- exit 1
+ usage
}
# fall through to setup UI for commits
}
default {
- puts stderr "usage: $argv0 \[{blame|browser|citool}\]"
+ set err "usage: $argv0 \[{blame|browser|citool}\]"
+ if {[tk windowingsystem] eq "win32"} {
+ wm withdraw .
+ tk_messageBox -icon error -message $err \
+ -title [mc "Usage"]
+ } else {
+ puts stderr $err
+ }
exit 1
}
}
-xscrollcommand {.vpane.lower.diff.body.sbx set} \
-yscrollcommand {.vpane.lower.diff.body.sby set} \
-state disabled
+catch {$ui_diff configure -tabstyle wordprocessor}
${NS}::scrollbar .vpane.lower.diff.body.sbx -orient horizontal \
-command [list $ui_diff xview]
${NS}::scrollbar .vpane.lower.diff.body.sby -orient vertical \
pack .vpane.lower.diff.header -side top -fill x
pack .vpane.lower.diff.body -side bottom -fill both -expand 1
+foreach {n c} {0 black 1 red4 2 green4 3 yellow4 4 blue4 5 magenta4 6 cyan4 7 grey60} {
+ $ui_diff tag configure clr4$n -background $c
+ $ui_diff tag configure clri4$n -foreground $c
+ $ui_diff tag configure clr3$n -foreground $c
+ $ui_diff tag configure clri3$n -background $c
+}
+$ui_diff tag configure clr1 -font font_diffbold
+
$ui_diff tag conf d_cr -elide true
-$ui_diff tag conf d_@ -foreground blue -font font_diffbold
+$ui_diff tag conf d_@ -font font_diffbold
$ui_diff tag conf d_+ -foreground {#00a000}
$ui_diff tag conf d_- -foreground red
return 1
}
- grid $w.rename.oldname_l $w.rename.oldname_m -sticky w -padx {0 5}
+ grid $w.rename.oldname_l $w.rename.oldname_m -sticky we -padx {0 5}
grid $w.rename.newname_l $w.rename.newname_t -sticky we -padx {0 5}
grid columnconfigure $w.rename 1 -weight 1
pack $w.rename -anchor nw -fill x -pady 5 -padx 5
}
lappend cmd -p
- lappend cmd --no-color
+ lappend cmd --color
if {$repo_config(gui.diffcontext) >= 1} {
lappend cmd "-U$repo_config(gui.diffcontext)"
}
fileevent $fd readable [list read_diff $fd $cont_info]
}
+proc parse_color_line {line} {
+ set start 0
+ set result ""
+ set markup [list]
+ set regexp {\033\[((?:\d+;)*\d+)?m}
+ while {[regexp -indices -start $start $regexp $line match code]} {
+ foreach {begin end} $match break
+ append result [string range $line $start [expr {$begin - 1}]]
+ lappend markup [string length $result] \
+ [eval [linsert $code 0 string range $line]]
+ set start [incr end]
+ }
+ append result [string range $line $start end]
+ if {[llength $markup] < 4} {set markup {}}
+ return [list $result $markup]
+}
+
proc read_diff {fd cont_info} {
global ui_diff diff_active is_submodule_diff
global is_3way_diff is_conflict_diff current_diff_header
$ui_diff conf -state normal
while {[gets $fd line] >= 0} {
+ foreach {line markup} [parse_color_line $line] break
+ set line [string map {\033 ^} $line]
+
# -- Cleanup uninteresting diff header lines.
#
if {$::current_diff_inheader} {
}
}
}
+ set mark [$ui_diff index "end - 1 line linestart"]
$ui_diff insert end $line $tags
if {[string index $line end] eq "\r"} {
$ui_diff tag add d_cr {end - 2c}
}
$ui_diff insert end "\n" $tags
+
+ foreach {posbegin colbegin posend colend} $markup {
+ set prefix clr
+ foreach style [split $colbegin ";"] {
+ if {$style eq "7"} {append prefix i; continue}
+ if {$style < 30 || $style > 47} {continue}
+ set a "$mark linestart + $posbegin chars"
+ set b "$mark linestart + $posend chars"
+ catch {$ui_diff tag add $prefix$style $a $b}
+ }
+ }
}
$ui_diff conf -state disabled
esac
strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")"
do_merge=t
- if test -n "$strategy"
- then
- strategy=recursive
- fi
;;
-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
--strateg=*|--strategy=*|\
esac
PACKDIR="$GIT_OBJECT_DIRECTORY/pack"
-PACKTMP="$GIT_OBJECT_DIRECTORY/.tmp-$$-pack"
+PACKTMP="$PACKDIR/.tmp-$$-pack"
rm -f "$PACKTMP"-*
trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15
;;
esac
+mkdir -p "$PACKDIR" || exit
+
args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra"
names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
exit 1
fi
# Ok we have prepared all new packfiles.
-mkdir -p "$PACKDIR" || exit
# First see if there are packs of the same name and if so
# if we can move them out of the way (this can happen if we
sub send_message {
my @recipients = unique_email_list(@to);
@cc = (grep { my $cc = extract_valid_address($_);
- not grep { $cc eq $_ } @recipients
+ not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
}
map { sanitize_address($_) }
@cc);
cmd_update()
{
# parse $args after "submodule ... update".
- orig_args="$@"
+ orig_flags=
while test $# -ne 0
do
case "$1" in
-q|--quiet)
- shift
GIT_QUIET=1
;;
-i|--init)
init=1
- shift
;;
-N|--no-fetch)
- shift
nofetch=1
;;
-r|--rebase)
- shift
update="rebase"
;;
--reference)
case "$2" in '') usage ;; esac
reference="--reference=$2"
- shift 2
+ orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
+ shift
;;
--reference=*)
reference="$1"
- shift
;;
-m|--merge)
- shift
update="merge"
;;
--recursive)
- shift
recursive=1
;;
--)
break
;;
esac
+ orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
+ shift
done
if test -n "$init"
if test -n "$recursive"
then
- (clear_local_git_env; cd "$path" && cmd_update $orig_args) ||
+ (clear_local_git_env; cd "$path" && eval cmd_update "$orig_flags") ||
die "Failed to recurse into submodule path '$path'"
fi
done
cmd_status()
{
# parse $args after "submodule ... status".
- orig_args="$@"
+ orig_flags=
while test $# -ne 0
do
case "$1" in
break
;;
esac
+ orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")"
shift
done
prefix="$displaypath/"
clear_local_git_env
cd "$path" &&
- cmd_status $orig_args
+ eval cmd_status "$orig_args"
) ||
die "Failed to recurse into submodule path '$path'"
fi
;;
esac
+ say "Synchronizing submodule url for '$name'"
+ git config submodule."$name".url "$url"
+
if test -e "$path"/.git
then
(
- say "Synchronizing submodule url for '$name'"
- git config submodule."$name".url "$url"
clear_local_git_env
cd "$path"
remote=$(get_default_remote)
# include user config
-include ../config.mak.autogen
-include ../config.mak
+-include config.mak
# determine version
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
chmod +x $@+ && \
mv $@+ $@
+### Testing rules
+
+test:
+ $(MAKE) -C ../t gitweb-test
+
+test-installed:
+ GITWEB_TEST_INSTALLED='$(DESTDIR_SQ)$(gitwebdir_SQ)' \
+ $(MAKE) -C ../t gitweb-test
+
### Installation rules
install: all
clean:
$(RM) gitweb.cgi static/gitweb.min.js static/gitweb.min.css GITWEB-BUILD-OPTIONS
-.PHONY: all clean install .FORCE-GIT-VERSION-FILE FORCE
+.PHONY: all clean install test test-installed .FORCE-GIT-VERSION-FILE FORCE
evaluate_uri();
evaluate_gitweb_config();
+ evaluate_git_version();
check_loadavg();
# $projectroot and $projects_list might be set in gitweb config file
sub run {
evaluate_argv();
- evaluate_git_version();
$pre_listen_hook->()
if $pre_listen_hook;
if (old_name == NULL) {
debug_mm("mailmap: adding (simple) entry for %s at index %d\n", old_email, index);
/* Replace current name and new email for simple entry */
- free(me->name);
- free(me->email);
- if (new_name)
+ if (new_name) {
+ free(me->name);
me->name = xstrdup(new_name);
- if (new_email)
+ }
+ if (new_email) {
+ free(me->email);
me->email = xstrdup(new_email);
+ }
} else {
struct mailmap_info *mi = xmalloc(sizeof(struct mailmap_info));
debug_mm("mailmap: adding (complex) entry for %s at index %d\n", old_email, index);
unsigned verbose:1,
quiet:1,
porcelain:1,
+ progress:1,
send_mirror:1,
force_update:1,
use_thin_pack:1,
{
static char path[PATH_MAX];
#ifndef WIN32
- if (!pfx || !*pfx || is_absolute_path(arg))
+ if (!pfx_len || is_absolute_path(arg))
return arg;
memcpy(path, pfx, pfx_len);
strcpy(path + pfx_len, arg);
/* don't add prefix to absolute paths, but still replace '\' by '/' */
if (is_absolute_path(arg))
pfx_len = 0;
- else
+ else if (pfx_len)
memcpy(path, pfx, pfx_len);
strcpy(path + pfx_len, arg);
for (p = path + pfx_len; *p; p++)
struct cache_entry *ce;
int pos;
if (namelen > 2 && name[1] == '/')
+ /* don't need mode for commit */
return get_sha1_oneline(name + 2, sha1);
if (namelen < 3 ||
name[2] != ':' ||
break;
if (ce_stage(ce) == stage) {
hashcpy(sha1, ce->sha1);
+ oc->mode = ce->ce_mode;
return 0;
}
pos++;
PERL_PATH ?= /usr/bin/perl
TAR ?= $(TAR)
RM ?= rm -f
+PROVE ?= prove
+DEFAULT_TEST_TARGET ?= test
# Shell quote;
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
TSVN = $(wildcard t91[0-9][0-9]-*.sh)
+TGITWEB = $(wildcard t95[0-9][0-9]-*.sh)
-all: pre-clean
+all: $(DEFAULT_TEST_TARGET)
+
+test: pre-clean
$(MAKE) aggregate-results-and-cleanup
+prove: pre-clean
+ @echo "*** prove ***"; GIT_CONFIG=.git/config $(PROVE) --exec '$(SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
+ $(MAKE) clean
+
$(T):
@echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
$(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
$(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8
+gitweb-test:
+ $(MAKE) $(TGITWEB)
+
valgrind:
GIT_TEST_OPTS=--valgrind $(MAKE)
# Repeat until no more failures
$ prove -j 15 --state=failed,save ./t[0-9]*.sh
+You can give DEFAULT_TEST_TARGET=prove on the make command (or define it
+in config.mak) to cause "make test" to run tests under prove.
+GIT_PROVE_OPTS can be used to pass additional options, e.g.
+
+ $ make DEFAULT_TEST_TARGET=prove GIT_PROVE_OPTS='--timer --jobs 16' test
+
You can also run each test individually from command line, like this:
$ sh ./t3010-ls-files-killed-modified.sh
test ...
That way all of the commands in your tests will succeed or fail. If
- you must ignore the return value of something (e.g., the return
- after unsetting a variable that was already unset is unportable) it's
- best to indicate so explicitly with a semicolon:
-
- unset HLAGH;
- git merge hla &&
- git push gh &&
- test ...
+ you must ignore the return value of something, consider using a
+ helper function (e.g. use sane_unset instead of unset, in order
+ to avoid unportable return value for unsetting a variable that was
+ already unset), or prepending the command with test_might_fail or
+ test_must_fail.
- Check the test coverage for your tests. See the "Test coverage"
below.
Like test_expect_success this function can optionally use a three
argument invocation with a prerequisite as the first argument.
- - test_expect_code [<prereq>] <code> <message> <script>
-
- Analogous to test_expect_success, but pass the test if it exits
- with a given exit <code>
-
- test_expect_code 1 'Merge with d/f conflicts' 'git merge "merge msg" B master'
-
- test_debug <script>
This takes a single argument, <script>, and evaluates it only
'Perl API' \
"$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl
+ - test_expect_code <exit-code> <command>
+
+ Run a command and ensure that it exits with the given exit code.
+ For example:
+
+ test_expect_success 'Merge with d/f conflicts' '
+ test_expect_code 1 git merge "merge msg" B master
+ '
+
- test_must_fail <git-command>
Run a git command and ensure it fails in a controlled way. Use
<expected> file. This behaves like "cmp" but produces more
helpful output when the test is run with "-v" option.
+ - test_line_count (= | -lt | -ge | ...) <length> <file>
+
+ Check whether a file has the length it is expected to.
+
- test_path_is_file <file> [<diagnosis>]
test_path_is_dir <dir> [<diagnosis>]
test_path_is_missing <path> [<diagnosis>]
'prepare reference tree' \
'echo "1A quick brown fox jumps over the" >file &&
echo "lazy dog" >>file &&
- git add file
+ git add file &&
GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
test_expect_success \
cat >.git/description <<EOF
$0 test repository
EOF
+
+ # You can set the GITWEB_TEST_INSTALLED environment variable to
+ # the gitwebdir (the directory where gitweb is installed / deployed to)
+ # of an existing gitweb instalation to test that installation,
+ # or simply to pathname of installed gitweb script.
+ if test -n "$GITWEB_TEST_INSTALLED" ; then
+ if test -d $GITWEB_TEST_INSTALLED; then
+ SCRIPT_NAME="$GITWEB_TEST_INSTALLED/gitweb.cgi"
+ else
+ SCRIPT_NAME="$GITWEB_TEST_INSTALLED"
+ fi
+ test -f "$SCRIPT_NAME" ||
+ error "Cannot find gitweb at $GITWEB_TEST_INSTALLED."
+ say "# Testing $SCRIPT_NAME"
+ else # normal case, use source version of gitweb
+ SCRIPT_NAME="$GIT_BUILD_DIR/gitweb/gitweb.perl"
+ fi
+ export SCRIPT_NAME
}
gitweb_run () {
GATEWAY_INTERFACE='CGI/1.1'
HTTP_ACCEPT='*/*'
REQUEST_METHOD='GET'
- SCRIPT_NAME="$GIT_BUILD_DIR/gitweb/gitweb.perl"
QUERY_STRING=""$1""
PATH_INFO=""$2""
export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
- SCRIPT_NAME QUERY_STRING PATH_INFO
+ QUERY_STRING PATH_INFO
GITWEB_CONFIG=$(pwd)/gitweb_config.perl
export GITWEB_CONFIG
test_done
fi
-perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
+perl -MEncode -e '$e="";decode_utf8($e, Encode::FB_CROAK)' >/dev/null 2>&1 || {
skip_all='skipping gitweb tests, perl version is too old'
test_done
}
--- /dev/null
+#!/bin/sh
+
+test_expect_success 'set up terminal for tests' '
+ if
+ test_have_prereq PERL &&
+ "$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl \
+ sh -c "test -t 1 && test -t 2"
+ then
+ test_set_prereq TTY &&
+ test_terminal () {
+ if ! test_declared_prereq TTY
+ then
+ echo >&4 "test_terminal: need to declare TTY prerequisite"
+ return 127
+ fi
+ "$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl "$@"
+ }
+ fi
+'
test_when_finished clean=yes
'
-cleaner=no
-test_expect_code 1 'tests clean up even after a failure' '
- test_when_finished cleaner=yes &&
- (exit 1)
-'
-
-if test $clean$cleaner != yesyes
+if test $clean != yes
then
- say "bug in test framework: cleanup commands do not work reliably"
+ say "bug in test framework: basic cleanup command does not work reliably"
exit 1
fi
-test_expect_code 2 'failure to clean up causes the test to fail' '
- test_when_finished "(exit 2)"
+test_expect_success 'tests clean up even on failures' "
+ mkdir failing-cleanup &&
+ (cd failing-cleanup &&
+ cat >failing-cleanup.sh <<EOF &&
+#!$SHELL_PATH
+
+test_description='Failing tests with cleanup commands'
+
+# Point to the t/test-lib.sh, which isn't in ../ as usual
+TEST_DIRECTORY=\"$TEST_DIRECTORY\"
+. \"\$TEST_DIRECTORY\"/test-lib.sh
+
+test_expect_success 'tests clean up even after a failure' '
+ touch clean-after-failure &&
+ test_when_finished rm clean-after-failure &&
+ (exit 1)
+'
+
+test_expect_success 'failure to clean up causes the test to fail' '
+ test_when_finished \"(exit 2)\"
'
+test_done
+EOF
+ chmod +x failing-cleanup.sh &&
+ test_must_fail ./failing-cleanup.sh >out 2>err &&
+ ! test -s err &&
+ ! test -f \"trash directory.failing-cleanup/clean-after-failure\" &&
+sed -e 's/Z$//' >expect <<\EOF &&
+not ok - 1 tests clean up even after a failure
+# Z
+# touch clean-after-failure &&
+# test_when_finished rm clean-after-failure &&
+# (exit 1)
+# Z
+not ok - 2 failure to clean up causes the test to fail
+# Z
+# test_when_finished \"(exit 2)\"
+# Z
+# failed 2 among 2 test(s)
+1..2
+EOF
+ test_cmp expect out)
+"
+
################################################################
# Basics of the basics
test_expect_success 'plain' '
(
- unset GIT_DIR GIT_WORK_TREE
+ sane_unset GIT_DIR GIT_WORK_TREE &&
mkdir plain &&
cd plain &&
git init
test_expect_success 'plain with GIT_WORK_TREE' '
if (
- unset GIT_DIR
+ sane_unset GIT_DIR &&
mkdir plain-wt &&
cd plain-wt &&
GIT_WORK_TREE=$(pwd) git init
test_expect_success 'plain bare' '
(
- unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+ sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG &&
mkdir plain-bare-1 &&
cd plain-bare-1 &&
git --bare init
test_expect_success 'plain bare with GIT_WORK_TREE' '
if (
- unset GIT_DIR GIT_CONFIG
+ sane_unset GIT_DIR GIT_CONFIG &&
mkdir plain-bare-2 &&
cd plain-bare-2 &&
GIT_WORK_TREE=$(pwd) git --bare init
test_expect_success 'GIT_DIR bare' '
(
- unset GIT_CONFIG
+ sane_unset GIT_CONFIG &&
mkdir git-dir-bare.git &&
GIT_DIR=git-dir-bare.git git init
) &&
test_expect_success 'init --bare' '
(
- unset GIT_DIR GIT_WORK_TREE GIT_CONFIG
+ sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG &&
mkdir init-bare.git &&
cd init-bare.git &&
git init --bare
test_expect_success 'GIT_DIR non-bare' '
(
- unset GIT_CONFIG
+ sane_unset GIT_CONFIG &&
mkdir non-bare &&
cd non-bare &&
GIT_DIR=.git git init
test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' '
(
- unset GIT_CONFIG
+ sane_unset GIT_CONFIG &&
mkdir git-dir-wt-1.git &&
GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init
) &&
test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' '
if (
- unset GIT_CONFIG
+ sane_unset GIT_CONFIG &&
mkdir git-dir-wt-2.git &&
GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-2.git git --bare init
)
test_expect_success 'reinit' '
(
- unset GIT_CONFIG GIT_WORK_TREE GIT_CONFIG
+ sane_unset GIT_CONFIG GIT_WORK_TREE GIT_CONFIG &&
mkdir again &&
cd again &&
git config -f "$test_config" init.templatedir "${HOME}/templatedir-source" &&
mkdir templatedir-set &&
cd templatedir-set &&
- unset GIT_CONFIG_NOGLOBAL &&
- unset GIT_TEMPLATE_DIR &&
+ sane_unset GIT_CONFIG_NOGLOBAL &&
+ sane_unset GIT_TEMPLATE_DIR &&
NO_SET_GIT_TEMPLATE_DIR=t &&
export NO_SET_GIT_TEMPLATE_DIR &&
git init
test_expect_success 'init --bare/--shared overrides system/global config' '
(
test_config="$HOME"/.gitconfig &&
- unset GIT_CONFIG_NOGLOBAL &&
+ sane_unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" core.bare false &&
git config -f "$test_config" core.sharedRepository 0640 &&
mkdir init-bare-shared-override &&
test_expect_success 'init honors global core.sharedRepository' '
(
test_config="$HOME"/.gitconfig &&
- unset GIT_CONFIG_NOGLOBAL &&
+ sane_unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" core.sharedRepository 0666 &&
mkdir shared-honor-global &&
cd shared-honor-global &&
) >a/b/.gitattributes
(
echo "global test=global"
- ) >$HOME/global-gitattributes
+ ) >"$HOME"/global-gitattributes
'
test_expect_success 'attribute test: read paths from stdin' '
- cat <<EOF > expect
+ cat <<EOF > expect &&
f: test: f
a/f: test: f
a/c/f: test: f
git rm .gitattributes &&
echo "contentsQ" | q_to_cr > .file2 &&
git add .file2 &&
- git commit -m third
+ git commit -m third &&
git checkout master~1 &&
git checkout master &&
test_expect_success setup '
- git config core.autocrlf true
+ git config core.autocrlf true &&
printf "CRLF line ending\r\nAnd another\r\n" > sample &&
git add sample &&
test_expect_success 'tar archive' '
git archive --format=tar HEAD |
- ( mkdir untarred && cd untarred && "$TAR" -xf - )
+ ( mkdir untarred && cd untarred && "$TAR" -xf - ) &&
test_cmp sample untarred/sample
git config core.autocrlf false &&
- echo "one text" > .gitattributes
+ echo "one text" > .gitattributes &&
for w in Hello world how are you; do echo $w; done >one &&
for w in I am very very fine thank you; do echo $w; done >two &&
no_symlinks=
test_expect_success 'see what we expect' '
- test_case=test_expect_success
- test_unicode=test_expect_success
+ test_case=test_expect_success &&
+ test_unicode=test_expect_success &&
mkdir junk &&
echo good >junk/CamelCase &&
echo bad >junk/camelcase &&
if test "$(cat junk/CamelCase)" != good
then
- test_case=test_expect_failure
+ test_case=test_expect_failure &&
case_insensitive=t
fi &&
rm -fr junk &&
>junk/"$auml" &&
case "$(cd junk && echo *)" in
"$aumlcdiar")
- test_unicode=test_expect_failure
+ test_unicode=test_expect_failure &&
unibad=t
;;
*) ;;
{
ln -s x y 2> /dev/null &&
test -h y 2> /dev/null ||
- no_symlinks=1
+ no_symlinks=1 &&
rm -f y
}
'
cd unicode &&
touch "$aumlcdiar" &&
git add "$aumlcdiar" &&
- git commit -m initial
+ git commit -m initial &&
git tag initial &&
git checkout -b topic &&
git mv $aumlcdiar tmp &&
test_expect_success \
'6 - must not exist in O && !A && !B case' "
rm -f .git/index DD &&
- echo DD >DD
+ echo DD >DD &&
git update-index --add DD &&
test_must_fail git read-tree -m $tree_O $tree_A $tree_B
"
git checkout-index -u -f -q -a &&
git update-index --add yomin &&
read_tree_twoway $treeH $treeM &&
- git ls-files --stage >4.out || return 1
- git diff --no-index M.out 4.out >4diff.out
+ git ls-files --stage >4.out &&
+ test_must_fail git diff --no-index M.out 4.out >4diff.out &&
compare_change 4diff.out expected &&
check_cache_at yomin clean'
git update-index --add yomin &&
echo yomin yomin >yomin &&
read_tree_twoway $treeH $treeM &&
- git ls-files --stage >5.out || return 1
- git diff --no-index M.out 5.out >5diff.out
+ git ls-files --stage >5.out &&
+ test_must_fail git diff --no-index M.out 5.out >5diff.out &&
compare_change 5diff.out expected &&
check_cache_at yomin dirty'
echo nitfol nitfol >nitfol &&
git update-index --add nitfol &&
read_tree_twoway $treeH $treeM &&
- git ls-files --stage >14.out || return 1
- git diff --no-index M.out 14.out >14diff.out
+ git ls-files --stage >14.out &&
+ test_must_fail git diff --no-index M.out 14.out >14diff.out &&
compare_change 14diff.out expected &&
check_cache_at nitfol clean'
git update-index --add nitfol &&
echo nitfol nitfol nitfol >nitfol &&
read_tree_twoway $treeH $treeM &&
- git ls-files --stage >15.out || return 1
- git diff --no-index M.out 15.out >15diff.out
+ git ls-files --stage >15.out &&
+ test_must_fail git diff --no-index M.out 15.out >15diff.out &&
compare_change 15diff.out expected &&
check_cache_at nitfol dirty'
git ls-files --stage >treeM.out &&
rm -f a &&
- mkdir a
+ mkdir a &&
: >a/b &&
git update-index --add --remove a a/b &&
treeH=`git write-tree` &&
echo >file-a &&
echo >file-b &&
git add file-a file-b &&
- git commit -a -m "test for correct modified tree"
+ git commit -a -m "test for correct modified tree" &&
git branch initial-mod &&
echo b >file-b &&
git commit -a -m "B" &&
echo nitfol nitfol >nitfol &&
git update-index --add nitfol &&
git read-tree -m -u $treeH $treeM &&
- git ls-files --stage >14.out || return 1
- git diff -U0 --no-index M.out 14.out >14diff.out
+ git ls-files --stage >14.out &&
+ test_must_fail git diff -U0 --no-index M.out 14.out >14diff.out &&
compare_change 14diff.out expected &&
sum bozbar frotz >actual14.sum &&
grep -v nitfol M.sum > expected14.sum &&
git update-index --add nitfol &&
echo nitfol nitfol nitfol >nitfol &&
git read-tree -m -u $treeH $treeM &&
- git ls-files --stage >15.out || return 1
- git diff -U0 --no-index M.out 15.out >15diff.out
+ git ls-files --stage >15.out &&
+ test_must_fail git diff -U0 --no-index M.out 15.out >15diff.out &&
compare_change 15diff.out expected &&
check_cache_at nitfol dirty &&
sum bozbar frotz >actual15.sum &&
# Also make sure we did not break DF vs DF/DF case.
test_expect_success \
'DF vs DF/DF case setup.' \
- 'rm -f .git/index
+ 'rm -f .git/index &&
echo DF >DF &&
git update-index --add DF &&
treeDF=`git write-tree` &&
cat >expected <<-\EOF &&
100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0 init.t
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 sub/added
+ 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 subsub/added
EOF
cat >expected.swt <<-\EOF &&
H init.t
H sub/added
+ H subsub/added
EOF
test_commit init &&
echo modified >>init.t &&
- mkdir sub &&
- touch sub/added &&
- git add init.t sub/added &&
+ mkdir sub subsub &&
+ touch sub/added subsub/added &&
+ git add init.t sub/added subsub/added &&
git commit -m "modified and added" &&
git tag top &&
git rm sub/added &&
'
test_expect_success 'read-tree with .git/info/sparse-checkout but disabled' '
- echo >.git/info/sparse-checkout
+ echo >.git/info/sparse-checkout &&
git read-tree -m -u HEAD &&
git ls-files -t >result &&
test_cmp expected.swt result &&
cat >expected.swt-noinit <<-\EOF &&
S init.t
H sub/added
+ S subsub/added
EOF
echo sub/ > .git/info/sparse-checkout &&
cat >expected.swt-nosub <<-\EOF &&
H init.t
S sub/added
+ S subsub/added
EOF
echo init.t >.git/info/sparse-checkout &&
'
test_expect_success 'tree' '
- tree=$(git write-tree 2>/dev/null)
+ tree=$(git write-tree 2>/dev/null) &&
test 8988da15d077d4829fc51d8544c097def6644dbb = $tree
'
test_expect_success 'working --list' \
'git config --list > output && cmp output expect'
+cat > expect << EOF
+EOF
+
+test_expect_success '--list without repo produces empty output' '
+ git --git-dir=nonexistent config --list >output &&
+ test_cmp expect output
+'
+
cat > expect << EOF
beta.noindent sillyValue
nextsection.nonewline wow2 for me
'
+test_expect_success 'nonexistent configuration' '
+ (
+ GIT_CONFIG=doesnotexist &&
+ export GIT_CONFIG &&
+ test_must_fail git config --list &&
+ test_must_fail git config test.xyzzy
+ )
+'
+
+test_expect_success SYMLINKS 'symlink to nonexistent configuration' '
+ ln -s doesnotexist linktonada &&
+ ln -s linktonada linktolinktonada &&
+ (
+ GIT_CONFIG=linktonada &&
+ export GIT_CONFIG &&
+ test_must_fail git config --list &&
+ GIT_CONFIG=linktolinktonada &&
+ test_must_fail git config --list
+ )
+'
+
test_expect_success 'check split_cmdline return' "
git config alias.split-cmdline-fix 'echo \"' &&
test_must_fail git split-cmdline-fix &&
(
cd test2 &&
git config core.repositoryformatversion >../actual
- )
+ ) &&
test_cmp expect actual
'
test_expect_success \
"fail to create $n" \
- "touch .git/$n_dir
- git update-ref $n $A >out 2>err"'
- test $? != 0'
+ "touch .git/$n_dir &&
+ test_must_fail git update-ref $n $A >out 2>err"
rm -f .git/$n_dir out err
test_expect_success \
ld="Thu, 26 May 2005 18:43:00 -0500"
test_expect_success \
'Query "master@{May 25 2005}" (before history)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{May 25 2005}" >o 2>e &&
test '"$C"' = $(cat o) &&
test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"'
test_expect_success \
"Query master@{2005-05-25} (before history)" \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify master@{2005-05-25} >o 2>e &&
test '"$C"' = $(cat o) &&
echo test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"'
test_expect_success \
'Query "master@{May 26 2005 23:31:59}" (1 second before history)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{May 26 2005 23:31:59}" >o 2>e &&
test '"$C"' = $(cat o) &&
test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"'
test_expect_success \
'Query "master@{May 26 2005 23:32:00}" (exactly history start)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e &&
test '"$C"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{May 26 2005 23:32:30}" (first non-creation change)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{May 26 2005 23:32:30}" >o 2>e &&
test '"$A"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-26 23:33:01}" (middle of history with gap)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e &&
test '"$B"' = $(cat o) &&
test "warning: Log .git/logs/'"$m has gap after $gd"'." = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-26 23:38:00}" (middle of history)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e &&
test '"$Z"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-26 23:43:00}" (exact end of history)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e &&
test '"$E"' = $(cat o) &&
test "" = "$(cat e)"'
test_expect_success \
'Query "master@{2005-05-28}" (past end of history)' \
- 'rm -f o e
+ 'rm -f o e &&
git rev-parse --verify "master@{2005-05-28}" >o 2>e &&
test '"$D"' = $(cat o) &&
test "warning: Log .git/logs/'"$m unexpectedly ended on $ld"'." = "$(cat e)"'
git add F &&
GIT_AUTHOR_DATE="2005-05-26 23:30" \
GIT_COMMITTER_DATE="2005-05-26 23:30" git commit -m add -a &&
- h_TEST=$(git rev-parse --verify HEAD)
+ h_TEST=$(git rev-parse --verify HEAD) &&
echo The other day this did not work. >M &&
echo And then Bob told me how to fix it. >>M &&
echo OTHER >F &&
reset_to_sane
test_expect_success 'symbolic-ref refuses bare sha1' '
- echo content >file && git add file && git commit -m one
+ echo content >file && git add file && git commit -m one &&
test_must_fail git symbolic-ref HEAD `git rev-parse HEAD`
'
reset_to_sane
T=$(git write-tree) &&
sha1=$(echo A | git commit-tree $T) &&
git update-ref refs/heads/master $sha1 &&
- git update-ref refs/remotes/origin/master $sha1
+ git update-ref refs/remotes/origin/master $sha1 &&
git checkout master &&
git checkout origin/master &&
git checkout master &&
T=$(git write-tree) &&
sha1=$(echo A | git commit-tree $T) &&
git update-ref refs/heads/master $sha1 &&
- git update-ref refs/remotes/origin/master $sha1
+ git update-ref refs/remotes/origin/master $sha1 &&
git checkout master &&
git checkout origin/master &&
git checkout master &&
test_tick &&
git commit -m tiger C &&
- HEAD_entry_count=$(git reflog | wc -l)
- master_entry_count=$(git reflog show master | wc -l)
+ HEAD_entry_count=$(git reflog | wc -l) &&
+ master_entry_count=$(git reflog show master | wc -l) &&
test $HEAD_entry_count = 5 &&
test $master_entry_count = 5 &&
test $HEAD_entry_count = $(git reflog | wc -l) &&
! grep ox < output &&
- master_entry_count=$(wc -l < output)
+ master_entry_count=$(wc -l < output) &&
git reflog delete HEAD@{1} &&
test $(($HEAD_entry_count -1)) = $(git reflog | wc -l) &&
test $master_entry_count = $(git reflog show master | wc -l) &&
- HEAD_entry_count=$(git reflog | wc -l)
+ HEAD_entry_count=$(git reflog | wc -l) &&
git reflog delete master@{07.04.2005.15:15:00.-0700} &&
git reflog show master > output &&
sha=$(echo blob | git hash-object -w --stdin) &&
old=$(echo $sha | sed "s+^..+&/+") &&
new=$(dirname $old)/ffffffffffffffffffffffffffffffffffffff &&
- sha="$(dirname $new)$(basename $new)"
+ sha="$(dirname $new)$(basename $new)" &&
mv .git/objects/$old .git/objects/$new &&
test_when_finished "remove_object $sha" &&
git update-index --add --cacheinfo 100644 $sha foo &&
'
test_expect_success 'tag pointing to nonexistent' '
- cat >invalid-tag <<-\EOF
+ cat >invalid-tag <<-\EOF &&
object ffffffffffffffffffffffffffffffffffffffff
type commit
tag invalid
EOF
test_expect_success 'test --parseopt help output' '
- git rev-parse --parseopt -- -h > output < optionspec
+ test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec &&
test_cmp expect output
'
}
test_fail() {
- test_expect_code 128 "$1: prefix" \
- "git rev-parse --show-prefix"
+ test_expect_success "$1: prefix" '
+ test_expect_code 128 git rev-parse --show-prefix
+ '
}
TRASH_ROOT="$PWD"
git branch side &&
echo goodbye >nitfol &&
- git add nitfol
+ git add nitfol &&
test_tick &&
git commit -m "master adds file nitfol" &&
'
test_expect_success PERL 'git checkout -p with staged changes' '
- set_state dir/foo work index
+ set_state dir/foo work index &&
(echo n; echo y) | git checkout -p &&
verify_saved_state bar &&
verify_state dir/foo index index
test_expect_success 'Setup' '
echo "Initial" >"$TEST_FILE" &&
git add "$TEST_FILE" &&
- git commit -m "First Commit"
+ git commit -m "First Commit" &&
test_tick &&
echo "State 1" >>"$TEST_FILE" &&
git add "$TEST_FILE" &&
test_expect_success 'post-commit hook used ordinarily' '
echo initial >top &&
-git add top
+git add top &&
git commit -m initial &&
test -r "${COMMIT_FILE}"
'
rm -rf "${COMMIT_FILE}"
test_expect_success 'post-commit-hook from sub dir' '
-echo changed again >top
+echo changed again >top &&
cd subdir &&
git --git-dir .git --work-tree .. add ../top &&
git --git-dir .git --work-tree .. commit -m subcommit &&
echo hello world >dir1/file3 &&
echo goodbye people >file2 &&
git update-index --add file2 dir1/file3 &&
- echo hello everybody >file2
+ echo hello everybody >file2 &&
echo happy >dir1/file3 &&
git update-index --again &&
git ls-files -s >current &&
echo initial >dir1/sub2 &&
echo initial >dir2/sub3 &&
git add check dir1 dir2 top foo &&
- test_tick
+ test_tick &&
git commit -m initial &&
echo changed >check &&
test_expect_success 'trailing slash in exclude forces directory match (1)' '
- >two
+ >two &&
git ls-files --others --exclude=two/ >output &&
grep "^two" output
echo "100644 $o0 0 c"
echo "100644 $o1 0 d/e"
) >expected &&
- test_cmp expected actual
+ test_cmp expected actual &&
git read-tree --prefix=z/ master &&
git ls-files -s >actual &&
cd sub &&
git init &&
>subfile &&
- git add subfile
+ git add subfile &&
git commit -m "subproject commit #1"
) &&
- >mainfile
+ >mainfile &&
git add sub mainfile &&
test_tick &&
git commit -m "superproject commit #1"
'
test_expect_success 'make branches' '
- git branch branch-one
+ git branch branch-one &&
git branch branch-two HEAD^
'
test_expect_success 'make remote branches' '
- git update-ref refs/remotes/origin/branch-one branch-one
- git update-ref refs/remotes/origin/branch-two branch-two
+ git update-ref refs/remotes/origin/branch-one branch-one &&
+ git update-ref refs/remotes/origin/branch-two branch-two &&
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/branch-one
'
test_cmp expected current'
test_expect_success TABS_IN_FILENAMES 'setup expect' '
-t0=`git write-tree`
-echo "$t0" >t0
+t0=`git write-tree` &&
+echo "$t0" >t0 &&
cat > expected <<\EOF
just space
test_cmp expected current'
test_expect_success TABS_IN_FILENAMES 'setup expect' '
-t1=`git write-tree`
-echo "$t1" >t1
+t1=`git write-tree` &&
+echo "$t1" >t1 &&
cat > expected <<\EOF
just space
# 1 indicates caught gracefully by die, 128 means git-show barked
test_expect_success 'handle empty notes gracefully' '
- git notes show ; test 1 = $?
+ test_expect_code 1 git notes show
'
test_expect_success 'show non-existent notes entry with %N' '
test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '
git config core.notesRef refs/notes/other &&
- echo "Note on a tree" > expect
+ echo "Note on a tree" > expect &&
git notes add -m "Note on a tree" HEAD: &&
git notes show HEAD: > actual &&
test_cmp expect actual &&
- echo "Note on a blob" > expect
+ echo "Note on a blob" > expect &&
filename=$(git ls-tree --name-only HEAD | head -n1) &&
git notes add -m "Note on a blob" HEAD:$filename &&
git notes show HEAD:$filename > actual &&
test_cmp expect actual &&
- echo "Note on a tag" > expect
+ echo "Note on a tag" > expect &&
git tag -a -m "This is an annotated tag" foobar HEAD^ &&
git notes add -m "Note on a tag" foobar &&
git notes show foobar > actual &&
'
test_expect_success 'example 2: binary notes' '
- cp "$TEST_DIRECTORY"/test4012.png .
+ cp "$TEST_DIRECTORY"/test4012.png . &&
git checkout B &&
blob=$(git hash-object -w test4012.png) &&
git notes --ref=logo add -C "$blob" &&
esac
'
+test_expect_success 'rebase -s funny -Xopt' '
+ test_when_finished "rm -fr test-bin funny.was.run" &&
+ mkdir test-bin &&
+ cat >test-bin/git-merge-funny <<-EOF &&
+ #!$SHELL_PATH
+ case "\$1" in --opt) ;; *) exit 2 ;; esac
+ shift &&
+ >funny.was.run &&
+ exec git merge-recursive "\$@"
+ EOF
+ chmod +x test-bin/git-merge-funny &&
+ git reset --hard &&
+ git checkout -b test-funny master^ &&
+ test_commit funny &&
+ (
+ PATH=./test-bin:$PATH
+ git rebase -s funny -Xopt master
+ ) &&
+ test -f funny.was.run
+'
+
test_done
This test runs git rebase "interactively", by faking an edit, and verifies
that the result still makes sense.
+
+Initial setup:
+
+ one - two - three - four (conflict-branch)
+ /
+ A - B - C - D - E (master)
+ | \
+ | F - G - H (branch1)
+ | \
+ |\ I (branch2)
+ | \
+ | J - K - L - M (no-conflict-branch)
+ \
+ N - O - P (no-ff-branch)
+
+ where A, B, D and G all touch file1, and one, two, three, four all
+ touch file "conflict".
'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
+test_cmp_rev () {
+ git rev-parse --verify "$1" >expect.rev &&
+ git rev-parse --verify "$2" >actual.rev &&
+ test_cmp expect.rev actual.rev
+}
+
set_fake_editor
-# Set up the repository like this:
-#
-# one - two - three - four (conflict-branch)
-# /
-# A - B - C - D - E (master)
-# | \
-# | F - G - H (branch1)
-# | \
-# |\ I (branch2)
-# | \
-# | J - K - L - M (no-conflict-branch)
-# \
-# N - O - P (no-ff-branch)
-#
-# where A, B, D and G all touch file1, and one, two, three, four all
-# touch file "conflict".
-#
# WARNING: Modifications to the initial repository can change the SHA ID used
# in the expect2 file for the 'stop on conflicting pick' test.
-
test_expect_success 'setup' '
test_commit A file1 &&
test_commit B file1 &&
test_commit G file1 &&
test_commit H file5 &&
git checkout -b branch2 F &&
- test_commit I file6
+ test_commit I file6 &&
git checkout -b conflict-branch A &&
- for n in one two three four
- do
- test_commit $n conflict
- done &&
+ test_commit one conflict &&
+ test_commit two conflict &&
+ test_commit three conflict &&
+ test_commit four conflict &&
git checkout -b no-conflict-branch A &&
- for n in J K L M
- do
- test_commit $n file$n
- done &&
+ test_commit J fileJ &&
+ test_commit K fileK &&
+ test_commit L fileL &&
+ test_commit M fileM &&
git checkout -b no-ff-branch A &&
- for n in N O P
- do
- test_commit $n file$n
- done
+ test_commit N fileN &&
+ test_commit O fileO &&
+ test_commit P fileP
'
# "exec" commands are ran with the user shell by default, but this may
test_path_is_file touch-one &&
test_path_is_file touch-two &&
test_path_is_missing touch-three " (should have stopped before)" &&
- test $(git rev-parse C) = $(git rev-parse HEAD) || {
- echo "Stopped at wrong revision:"
- echo "($(git describe --tags HEAD) instead of C)"
- false
- } &&
+ test_cmp_rev C HEAD &&
git rebase --continue &&
test_path_is_file touch-three &&
test_path_is_file "touch-file name with spaces" &&
test_path_is_file touch-after-semicolon &&
- test $(git rev-parse master) = $(git rev-parse HEAD) || {
- echo "Stopped at wrong revision:"
- echo "($(git describe --tags HEAD) instead of master)"
- false
- } &&
+ test_cmp_rev master HEAD &&
rm -f touch-*
'
export FAKE_LINES &&
test_must_fail git rebase -i HEAD^
) &&
- test $(git rev-parse master^) = $(git rev-parse HEAD) || {
- echo "Stopped at wrong revision:"
- echo "($(git describe --tags HEAD) instead of master^)"
- false
- } &&
+ test_cmp_rev master^ HEAD &&
git reset --hard &&
git rebase --continue
'
git checkout -b branch4 HEAD &&
GIT_EDITOR=: git commit --amend \
- --author="Somebody else <somebody@else.com>"
+ --author="Somebody else <somebody@else.com>" &&
test $(git rev-parse branch3) != $(git rev-parse branch4) &&
git rebase -i branch3 &&
test $(git rev-parse branch3) = $(git rev-parse branch4)
git add elif && git commit -m "submodule initial"
) &&
echo 1 >file1 &&
- git add file1 sub
+ git add file1 sub &&
test_tick &&
git commit -m "One" &&
echo 2 >file1 &&
'
test_expect_success 'rebase --stat' '
- git reset --hard start
+ git reset --hard start &&
git rebase --stat master >diffstat.txt &&
grep "^ fileX | *1 +$" diffstat.txt
'
test_expect_success 'rebase w/config rebase.stat' '
- git reset --hard start
+ git reset --hard start &&
git config rebase.stat true &&
git rebase master >diffstat.txt &&
grep "^ fileX | *1 +$" diffstat.txt
'
test_expect_success 'rebase -n overrides config rebase.stat config' '
- git reset --hard start
+ git reset --hard start &&
git config rebase.stat true &&
git rebase -n master >diffstat.txt &&
! grep "^ fileX | *1 +$" diffstat.txt
git commit -a -m "A sample commit log message that has a long
summary that spills over multiple lines.
-But otherwise with a sane description."
+But otherwise with a sane description." &&
git branch side &&
test_expect_success 'pre-rebase hook stops rebase' '
git checkout -b stops1 other &&
test_must_fail git rebase --root --onto master &&
- test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1 &&
test 0 = $(git rev-list other...stops1 | wc -l)
'
test_expect_success 'pre-rebase hook stops rebase -i' '
git checkout -b stops2 other &&
test_must_fail git rebase --root --onto master &&
- test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops2
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops2 &&
test 0 = $(git rev-list other...stops2 | wc -l)
'
git config core.whitespace "-blank-at-eol" &&
git reset --hard HEAD^ &&
cp third file && git add file && git commit -m third &&
- git rebase --whitespace=fix HEAD^^
+ git rebase --whitespace=fix HEAD^^ &&
git diff --exit-code HEAD^:file expect-second &&
test_cmp file third
'
--- /dev/null
+#!/bin/bash
+
+test_description='git rebase - test patch id computation'
+
+. ./test-lib.sh
+
+test_set_prereq NOT_EXPENSIVE
+test -n "$GIT_PATCHID_TIMING_TESTS" && test_set_prereq EXPENSIVE
+test -x /usr/bin/time && test_set_prereq USR_BIN_TIME
+
+count()
+{
+ i=0
+ while test $i -lt $1
+ do
+ echo "$i"
+ i=$(($i+1))
+ done
+}
+
+scramble()
+{
+ i=0
+ while read x
+ do
+ if test $i -ne 0
+ then
+ echo "$x"
+ fi
+ i=$(((i+1) % 10))
+ done < "$1" > "$1.new"
+ mv -f "$1.new" "$1"
+}
+
+run()
+{
+ echo \$ "$@"
+ /usr/bin/time "$@" >/dev/null
+}
+
+test_expect_success 'setup' '
+ git commit --allow-empty -m initial
+ git tag root
+'
+
+do_tests()
+{
+ pr=$1
+ nlines=$2
+
+ test_expect_success $pr "setup: $nlines lines" "
+ rm -f .gitattributes &&
+ git checkout -q -f master &&
+ git reset --hard root &&
+ count $nlines >file &&
+ git add file &&
+ git commit -q -m initial &&
+ git branch -f other &&
+
+ scramble file &&
+ git add file &&
+ git commit -q -m 'change big file' &&
+
+ git checkout -q other &&
+ : >newfile &&
+ git add newfile &&
+ git commit -q -m 'add small file' &&
+
+ git cherry-pick master >/dev/null 2>&1
+ "
+
+ test_debug "
+ run git diff master^\!
+ "
+
+ test_expect_success $pr 'setup attributes' "
+ echo 'file binary' >.gitattributes
+ "
+
+ test_debug "
+ run git format-patch --stdout master &&
+ run git format-patch --stdout --ignore-if-in-upstream master
+ "
+
+ test_expect_success $pr 'detect upstream patch' "
+ git checkout -q master &&
+ scramble file &&
+ git add file &&
+ git commit -q -m 'change big file again' &&
+ git checkout -q other^{} &&
+ git rebase master &&
+ test_must_fail test -n \"\$(git rev-list master...HEAD~)\"
+ "
+
+ test_expect_success $pr 'do not drop patch' "
+ git branch -f squashed master &&
+ git checkout -q -f squashed &&
+ git reset -q --soft HEAD~2 &&
+ git commit -q -m squashed &&
+ git checkout -q other^{} &&
+ test_must_fail git rebase squashed &&
+ rm -rf .git/rebase-apply
+ "
+}
+
+do_tests NOT_EXPENSIVE 500
+do_tests EXPENSIVE 50000
+
+test_done
test_expect_success 'fixup' '
echo foo-dev >foo &&
git add foo && test_tick && git commit -q -m 4 &&
- git reset --hard HEAD^
+ git reset --hard HEAD^ &&
echo foo-dev >expect
'
'
test_expect_success 'reconfigure' '
- git config rerere.enabled false
+ git config rerere.enabled false &&
git reset --hard
'
test_expect_success TABS_IN_FILENAMES 'setup' '
mkdir "$FN" &&
- for_each_name "echo initial >\"\$name\""
+ for_each_name "echo initial >\"\$name\"" &&
git add . &&
git commit -q -m Initial &&
for_each_name "echo second >\"\$name\"" &&
- git commit -a -m Second
+ git commit -a -m Second &&
for_each_name "echo modified >\"\$name\""
'
test_expect_success TABS_IN_FILENAMES 'setup expected files' '
-cat >expect.quoted <<\EOF
+cat >expect.quoted <<\EOF &&
Name
"Name and a\nLF"
"Name and an\tHT"
test_expect_success 'stash branch' '
echo foo > file &&
- git commit file -m first
+ git commit file -m first &&
echo bar > file &&
echo bar2 > file2 &&
git add file2 &&
echo file >.gitignore &&
git stash save "rm and ignore" &&
test bar = "$(cat file)" &&
- test file = "$(cat .gitignore)"
+ test file = "$(cat .gitignore)" &&
git stash apply &&
! test -r file &&
test file = "$(cat .gitignore)"
git add .gitignore &&
git stash save "rm and ignore (stage .gitignore)" &&
test bar = "$(cat file)" &&
- ! test -r .gitignore
+ ! test -r .gitignore &&
git stash apply &&
! test -r file &&
test file = "$(cat .gitignore)"
# note: bar sorts before dir, so the first 'n' is always to skip 'bar'
test_expect_success PERL 'saying "n" does nothing' '
- set_state dir/foo work index
+ set_state dir/foo work index &&
(echo n; echo n) | test_must_fail git stash save -p &&
verify_state dir/foo work index &&
verify_saved_state bar
'rm -fr Z [A-Z][A-Z] &&
git read-tree $tree_A &&
git checkout-index -f -a &&
- git read-tree --reset $tree_O || return 1
- git update-index --refresh >/dev/null ;# this can exit non-zero
+ git read-tree --reset $tree_O &&
+ test_must_fail git update-index --refresh -q &&
git diff-files >.test-a &&
cmp_diff_files_output .test-a .test-recursive-OA'
'rm -fr Z [A-Z][A-Z] &&
git read-tree $tree_B &&
git checkout-index -f -a &&
- git read-tree --reset $tree_O || return 1
- git update-index --refresh >/dev/null ;# this can exit non-zero
+ git read-tree --reset $tree_O &&
+ test_must_fail git update-index --refresh -q &&
git diff-files >.test-a &&
cmp_diff_files_output .test-a .test-recursive-OB'
'rm -fr Z [A-Z][A-Z] &&
git read-tree $tree_B &&
git checkout-index -f -a &&
- git read-tree --reset $tree_A || return 1
- git update-index --refresh >/dev/null ;# this can exit non-zero
+ git read-tree --reset $tree_A &&
+ test_must_fail git update-index --refresh -q &&
git diff-files >.test-a &&
cmp_diff_files_output .test-a .test-recursive-AB'
git checkout-index -f -u -a &&
sed -e "s/git/GIT/" file0 >file1 &&
sed -e "s/git/GET/" file0 >file2 &&
- rm -f file0
+ rm -f file0 &&
git update-index --add --remove file0 file1 file2'
test_expect_success \
test_must_fail git diff --no-index pinky brain > output 2> output.err &&
grep narf output &&
! grep error output.err'
+
+test_expect_success SYMLINKS 'setup symlinks with attributes' '
+ echo "*.bin diff=bin" >>.gitattributes &&
+ echo content >file.bin &&
+ ln -s file.bin link.bin &&
+ git add -N file.bin link.bin
+'
+
+cat >expect <<'EOF'
+diff --git a/file.bin b/file.bin
+index e69de29..d95f3ad 100644
+Binary files a/file.bin and b/file.bin differ
+diff --git a/link.bin b/link.bin
+index e69de29..dce41ec 120000
+--- a/link.bin
++++ b/link.bin
+@@ -0,0 +1 @@
++file.bin
+\ No newline at end of file
+EOF
+test_expect_success SYMLINKS 'symlinks do not respect userdiff config by path' '
+ git config diff.bin.binary true &&
+ git diff file.bin link.bin >actual &&
+ test_cmp expect actual
+'
+
test_done
tree1=`git write-tree` &&
test "$tree1" = "$tree0"'
-nul_to_q() {
- perl -pe 'y/\000/Q/'
-}
-
test_expect_success 'diff --no-index with binary creation' '
echo Q | q_to_nul >binary &&
(: hide error code from diff, which just indicates differences
test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' '
- git config core.whitespace "-indent-with-non-tab"
+ git config core.whitespace "-indent-with-non-tab" &&
echo " foo ();" > x &&
git diff --check
'
+# Start testing the colored format for whitespace checks
+
+test_expect_success 'setup diff colors' '
+ git config color.diff always &&
+ git config color.diff.plain normal &&
+ git config color.diff.meta bold &&
+ git config color.diff.frag cyan &&
+ git config color.diff.func normal &&
+ git config color.diff.old red &&
+ git config color.diff.new green &&
+ git config color.diff.commit yellow &&
+ git config color.diff.whitespace "normal red" &&
+
+ git config core.autocrlf false
+'
+cat >expected <<\EOF
+<BOLD>diff --git a/x b/x<RESET>
+<BOLD>index 9daeafb..2874b91 100644<RESET>
+<BOLD>--- a/x<RESET>
+<BOLD>+++ b/x<RESET>
+<CYAN>@@ -1 +1,4 @@<RESET>
+ test<RESET>
+<GREEN>+<RESET><GREEN>{<RESET>
+<GREEN>+<RESET><BRED> <RESET>
+<GREEN>+<RESET><GREEN>}<RESET>
+EOF
+
+test_expect_success 'diff that introduces a line with only tabs' '
+ git config core.whitespace blank-at-eol &&
+ git reset --hard &&
+ echo "test" > x &&
+ git commit -m "initial" x &&
+ echo "{NTN}" | tr "NT" "\n\t" >> x &&
+ git -c color.diff=always diff | test_decode_color >current &&
+ test_cmp expected current
+'
+
test_done
'
test_expect_success 'git diff-tree HEAD^ HEAD' '
- git diff-tree --exit-code HEAD^ HEAD
- test $? = 1
+ test_expect_code 1 git diff-tree --exit-code HEAD^ HEAD
'
test_expect_success 'git diff-tree HEAD^ HEAD -- a' '
git diff-tree --exit-code HEAD^ HEAD -- a
- test $? = 0
'
test_expect_success 'git diff-tree HEAD^ HEAD -- b' '
- git diff-tree --exit-code HEAD^ HEAD -- b
- test $? = 1
+ test_expect_code 1 git diff-tree --exit-code HEAD^ HEAD -- b
'
test_expect_success 'echo HEAD | git diff-tree --stdin' '
- echo $(git rev-parse HEAD) | git diff-tree --exit-code --stdin
- test $? = 1
+ echo $(git rev-parse HEAD) | test_expect_code 1 git diff-tree --exit-code --stdin
'
test_expect_success 'git diff-tree HEAD HEAD' '
git diff-tree --exit-code HEAD HEAD
- test $? = 0
'
test_expect_success 'git diff-files' '
git diff-files --exit-code
- test $? = 0
'
test_expect_success 'git diff-index --cached HEAD' '
git diff-index --exit-code --cached HEAD
- test $? = 0
'
test_expect_success 'git diff-index --cached HEAD^' '
- git diff-index --exit-code --cached HEAD^
- test $? = 1
+ test_expect_code 1 git diff-index --exit-code --cached HEAD^
'
test_expect_success 'git diff-index --cached HEAD^' '
echo text >>b &&
echo 3 >c &&
- git add . && {
- git diff-index --exit-code --cached HEAD^
- test $? = 1
- }
+ git add . &&
+ test_expect_code 1 git diff-index --exit-code --cached HEAD^
'
test_expect_success 'git diff-tree -Stext HEAD^ HEAD -- b' '
- git commit -m "text in b" && {
- git diff-tree -p --exit-code -Stext HEAD^ HEAD -- b
- test $? = 1
- }
+ git commit -m "text in b" &&
+ test_expect_code 1 git diff-tree -p --exit-code -Stext HEAD^ HEAD -- b
'
test_expect_success 'git diff-tree -Snot-found HEAD^ HEAD -- b' '
git diff-tree -p --exit-code -Snot-found HEAD^ HEAD -- b
- test $? = 0
'
test_expect_success 'git diff-files' '
- echo 3 >>c && {
- git diff-files --exit-code
- test $? = 1
- }
+ echo 3 >>c &&
+ test_expect_code 1 git diff-files --exit-code
'
test_expect_success 'git diff-index --cached HEAD' '
- git update-index c && {
- git diff-index --exit-code --cached HEAD
- test $? = 1
- }
+ git update-index c &&
+ test_expect_code 1 git diff-index --exit-code --cached HEAD
'
test_expect_success '--check --exit-code returns 0 for no difference' '
test_expect_success '--check --exit-code returns 1 for a clean difference' '
echo "good" > a &&
- git diff --check --exit-code
- test $? = 1
+ test_expect_code 1 git diff --check --exit-code
'
test_expect_success '--check --exit-code returns 3 for a dirty difference' '
echo "bad " >> a &&
- git diff --check --exit-code
- test $? = 3
+ test_expect_code 3 git diff --check --exit-code
'
test_expect_success '--check with --no-pager returns 2 for dirty difference' '
- git --no-pager diff --check
- test $? = 2
+ test_expect_code 2 git --no-pager diff --check
'
test_expect_success 'check should test not just the last line' '
echo "" >>a &&
- git --no-pager diff --check
- test $? = 2
+ test_expect_code 2 git --no-pager diff --check
'
echo binary >>b &&
git commit -m "side" b &&
test_must_fail git merge master &&
- git add b && (
- git --no-pager diff --cached --check >test.out
- test $? = 2
- ) &&
+ git add b &&
+ test_expect_code 2 git --no-pager diff --cached --check >test.out &&
test 3 = $(grep "conflict marker" test.out | wc -l) &&
git reset --hard
'
echo ">>>>>>> boo" >>b &&
echo "======" >>a &&
git diff --check a &&
- (
- git diff --check b
- test $? = 2
- ) &&
+ test_expect_code 2 git diff --check b &&
git reset --hard &&
echo ">>>>>>>> boo" >>b &&
echo "========" >>a &&
git diff --check &&
echo "b conflict-marker-size=8" >.gitattributes &&
- (
- git diff --check b
- test $? = 2
- ) &&
+ test_expect_code 2 git diff --check b &&
git diff --check a &&
git reset --hard
'
git diff --color >output
$grep_a "$blue_grep" output >error
$grep_a -v "$blue_grep" output >normal
+ return 0
}
test_expect_success default '
- prepare_output
+ prepare_output &&
grep Eight normal >/dev/null &&
grep HT error >/dev/null &&
test_expect_success 'without -trail' '
- git config core.whitespace -trail
- prepare_output
+ git config core.whitespace -trail &&
+ prepare_output &&
grep Eight normal >/dev/null &&
grep HT error >/dev/null &&
test_expect_success 'without -trail (attribute)' '
- git config --unset core.whitespace
- echo "F whitespace=-trail" >.gitattributes
- prepare_output
+ test_might_fail git config --unset core.whitespace &&
+ echo "F whitespace=-trail" >.gitattributes &&
+ prepare_output &&
grep Eight normal >/dev/null &&
grep HT error >/dev/null &&
test_expect_success 'without -space' '
- rm -f .gitattributes
- git config core.whitespace -space
- prepare_output
+ rm -f .gitattributes &&
+ git config core.whitespace -space &&
+ prepare_output &&
grep Eight normal >/dev/null &&
grep HT normal >/dev/null &&
test_expect_success 'without -space (attribute)' '
- git config --unset core.whitespace
- echo "F whitespace=-space" >.gitattributes
- prepare_output
+ test_might_fail git config --unset core.whitespace &&
+ echo "F whitespace=-space" >.gitattributes &&
+ prepare_output &&
grep Eight normal >/dev/null &&
grep HT normal >/dev/null &&
test_expect_success 'with indent-non-tab only' '
- rm -f .gitattributes
- git config core.whitespace indent,-trailing,-space
- prepare_output
+ rm -f .gitattributes &&
+ git config core.whitespace indent,-trailing,-space &&
+ prepare_output &&
grep Eight error >/dev/null &&
grep HT normal >/dev/null &&
test_expect_success 'with indent-non-tab only (attribute)' '
- git config --unset core.whitespace
- echo "F whitespace=indent,-trailing,-space" >.gitattributes
- prepare_output
+ test_might_fail git config --unset core.whitespace &&
+ echo "F whitespace=indent,-trailing,-space" >.gitattributes &&
+ prepare_output &&
grep Eight error >/dev/null &&
grep HT normal >/dev/null &&
test_expect_success 'with cr-at-eol' '
- rm -f .gitattributes
- git config core.whitespace cr-at-eol
- prepare_output
+ rm -f .gitattributes &&
+ git config core.whitespace cr-at-eol &&
+ prepare_output &&
grep Eight normal >/dev/null &&
grep HT error >/dev/null &&
test_expect_success 'with cr-at-eol (attribute)' '
- git config --unset core.whitespace
- echo "F whitespace=trailing,cr-at-eol" >.gitattributes
- prepare_output
+ test_might_fail git config --unset core.whitespace &&
+ echo "F whitespace=trailing,cr-at-eol" >.gitattributes &&
+ prepare_output &&
grep Eight normal >/dev/null &&
grep HT error >/dev/null &&
'
test_expect_success 'do not color trailing cr in context' '
- git config --unset core.whitespace
+ test_might_fail git config --unset core.whitespace &&
rm -f .gitattributes &&
echo AAAQ | tr Q "\015" >G &&
git add G &&
- echo BBBQ | tr Q "\015" >>G
+ echo BBBQ | tr Q "\015" >>G &&
git diff --color G | tr "\015" Q >output &&
grep "BBB.*${blue_grep}Q" output &&
grep "AAA.*\[mQ" output
test_expect_success 'format.numbered = auto' '
- git config format.numbered auto
+ git config format.numbered auto &&
git format-patch --stdout HEAD~2 > patch5 &&
test_numbered patch5
'
test_expect_success 'unknown color slots are ignored (diff)' '
- git config --unset diff.color.new
git config color.diff.nosuchslotwilleverbedefined white &&
git diff --color
'
test_expect_success 'conflicted submodule setup' '
# 39 efs
- c=fffffffffffffffffffffffffffffffffffffff
+ c=fffffffffffffffffffffffffffffffffffffff &&
(
- echo "000000 $_z40 0 sub"
- echo "160000 1$c 1 sub"
- echo "160000 2$c 2 sub"
+ echo "000000 $_z40 0 sub" &&
+ echo "160000 1$c 1 sub" &&
+ echo "160000 2$c 2 sub" &&
echo "160000 3$c 3 sub"
) | git update-index --index-info &&
echo >expect.nosub '\''diff --cc sub
test_expect_success setup '
- git config diff.color.old red
- git config diff.color.new green
+ git config diff.color.old red &&
+ git config diff.color.new green &&
git config diff.color.func magenta
'
EOF
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 330b04f..5ed8eff 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 330b04f..5ed8eff 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,3 +1,7 @@<RESET>
<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
'
cat > expect <<EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 330b04f..5ed8eff 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 330b04f..5ed8eff 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,3 +1,7 @@<RESET>
<RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET>
'
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 330b04f..5ed8eff 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 330b04f..5ed8eff 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1 +1 @@<RESET>
<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
<CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
'
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 330b04f..5ed8eff 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 330b04f..5ed8eff 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,3 +1,7 @@<RESET>
h(4),<GREEN>hh<RESET>[44]
'
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 330b04f..5ed8eff 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 330b04f..5ed8eff 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,3 +1,7 @@<RESET>
h(4)<GREEN>,hh[44]<RESET>
'
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 330b04f..5ed8eff 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 330b04f..5ed8eff 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,3 +1,7 @@<RESET>
h(4),<GREEN>{+hh+}<RESET>[44]
'
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 330b04f..5ed8eff 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 330b04f..5ed8eff 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1,3 +1,7 @@<RESET>
h(4),<GREEN>hh[44<RESET>]
echo 'aaa (aaa) aaa' > post
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index c29453b..be22f37 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index c29453b..be22f37 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1 +1 @@<RESET>
aaa (aaa) <GREEN>aaa<RESET>
EOF
echo '(' > post
cat > expect <<\EOF
-<WHITE>diff --git a/pre b/post<RESET>
-<WHITE>index 289cb9d..2d06f37 100644<RESET>
-<WHITE>--- a/pre<RESET>
-<WHITE>+++ b/post<RESET>
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 289cb9d..2d06f37 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
<CYAN>@@ -1 +1 @@<RESET>
(<RED>:<RESET>
EOF
test_expect_success 'added submodule' "
git add sm1 &&
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 0000000...$head1 (new submodule)
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
test_expect_success 'modified submodule(forward)' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head1..$head2:
> Add foo3
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule(forward)' "
git diff --submodule=log >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head1..$head2:
> Add foo3
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule(forward) --submodule' "
git diff --submodule >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head1..$head2:
> Add foo3
EOF
+ test_cmp expected actual
"
fullhead1=$(cd sm1; git rev-list --max-count=1 $head1)
fullhead2=$(cd sm1; git rev-list --max-count=1 $head2)
test_expect_success 'modified submodule(forward) --submodule=short' "
git diff --submodule=short >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
diff --git a/sm1 b/sm1
index $head1..$head2 160000
--- a/sm1
-Subproject commit $fullhead1
+Subproject commit $fullhead2
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
test_expect_success 'modified submodule(backward)' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head2..$head3 (rewind):
< Add foo3
< Add foo2
EOF
+ test_cmp expected actual
"
head4=$(add_file sm1 foo4 foo5) &&
head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
test_expect_success 'modified submodule(backward and forward)' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head2...$head4:
> Add foo5
> Add foo4
< Add foo3
< Add foo2
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
test_expect_success 'typechanged submodule(submodule->blob), --cached' "
git diff --submodule=log --cached >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 41fbea9...0000000 (submodule deleted)
diff --git a/sm1 b/sm1
new file mode 100644
@@ -0,0 +1 @@
+sm1
EOF
+ test_cmp expected actual
"
test_expect_success 'typechanged submodule(submodule->blob)' "
git diff --submodule=log >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
diff --git a/sm1 b/sm1
deleted file mode 100644
index 9da5fb8..0000000
-sm1
Submodule sm1 0000000...$head4 (new submodule)
EOF
+ test_cmp expected actual
"
rm -rf sm1 &&
git checkout-index sm1
test_expect_success 'typechanged submodule(submodule->blob)' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head4...0000000 (submodule deleted)
diff --git a/sm1 b/sm1
new file mode 100644
@@ -0,0 +1 @@
+sm1
EOF
+ test_cmp expected actual
"
rm -f sm1 &&
fullhead6=$(cd sm1; git rev-list --max-count=1 $head6)
test_expect_success 'nonexistent commit' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head4...$head6 (commits not present)
EOF
+ test_cmp expected actual
"
commit_file
test_expect_success 'typechanged submodule(blob->submodule)' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
diff --git a/sm1 b/sm1
deleted file mode 100644
index $head5..0000000
-sm1
Submodule sm1 0000000...$head6 (new submodule)
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
test_expect_success 'submodule is up to date' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
EOF
+ test_cmp expected actual
"
test_expect_success 'submodule contains untracked content' "
echo new > sm1/new-file &&
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains untracked content
EOF
+ test_cmp expected actual
"
test_expect_success 'submodule contains untracked content (untracked ignored)' "
test_expect_success 'submodule contains untracked and modifed content' "
echo new > sm1/foo6 &&
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains untracked content
Submodule sm1 contains modified content
EOF
+ test_cmp expected actual
"
test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' "
echo new > sm1/foo6 &&
git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains modified content
EOF
+ test_cmp expected actual
"
test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' "
test_expect_success 'submodule contains modifed content' "
rm -f sm1/new-file &&
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains modified content
EOF
+ test_cmp expected actual
"
(cd sm1; git commit -mchange foo6 >/dev/null) &&
head8=$(cd sm1; git rev-parse --verify HEAD | cut -c1-7) &&
test_expect_success 'submodule is modified' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule contains untracked content' "
echo new > sm1/new-file &&
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains untracked content
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule contains untracked content (untracked ignored)' "
git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule contains untracked content (dirty ignored)' "
git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule contains untracked content (all ignored)' "
test_expect_success 'modified submodule contains untracked and modifed content' "
echo modification >> sm1/foo6 &&
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains untracked content
Submodule sm1 contains modified content
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' "
echo modification >> sm1/foo6 &&
git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains modified content
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' "
echo modification >> sm1/foo6 &&
git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' "
test_expect_success 'modified submodule contains modifed content' "
rm -f sm1/new-file &&
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 contains modified content
Submodule sm1 $head6..$head8:
> change
EOF
+ test_cmp expected actual
"
rm -rf sm1
test_expect_success 'deleted submodule' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6...0000000 (submodule deleted)
EOF
+ test_cmp expected actual
"
test_create_repo sm2 &&
test_expect_success 'multiple submodules' "
git diff-index -p --submodule=log HEAD >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6...0000000 (submodule deleted)
Submodule sm2 0000000...$head7 (new submodule)
EOF
+ test_cmp expected actual
"
test_expect_success 'path filter' "
git diff-index -p --submodule=log HEAD sm2 >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm2 0000000...$head7 (new submodule)
EOF
+ test_cmp expected actual
"
commit_file sm2
test_expect_success 'given commit' "
git diff-index -p --submodule=log HEAD^ >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6...0000000 (submodule deleted)
Submodule sm2 0000000...$head7 (new submodule)
EOF
+ test_cmp expected actual
"
test_expect_success 'given commit --submodule' "
git diff-index -p --submodule HEAD^ >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6...0000000 (submodule deleted)
Submodule sm2 0000000...$head7 (new submodule)
EOF
+ test_cmp expected actual
"
fullhead7=$(cd sm2; git rev-list --max-count=1 $head7)
test_expect_success 'given commit --submodule=short' "
git diff-index -p --submodule=short HEAD^ >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
diff --git a/sm1 b/sm1
deleted file mode 160000
index $head6..0000000
@@ -0,0 +1 @@
+Subproject commit $fullhead7
EOF
+ test_cmp expected actual
"
test_expect_success 'setup .git file for sm2' '
test_expect_success 'diff --submodule with .git file' '
git diff --submodule HEAD^ >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
Submodule sm1 $head6...0000000 (submodule deleted)
Submodule sm2 0000000...$head7 (new submodule)
EOF
+ test_cmp expected actual
'
test_done
git diff-tree -p -C master binary >C.diff &&
git diff-tree -p --binary master binary >BF.diff &&
- git diff-tree -p --binary -C master binary >CF.diff
+ git diff-tree -p --binary -C master binary >CF.diff &&
+
+ git diff-tree -p --full-index master binary >B-index.diff &&
+ git diff-tree -p -C --full-index master binary >C-index.diff &&
+
+ git init other-repo &&
+ (cd other-repo &&
+ git fetch .. master &&
+ git reset --hard FETCH_HEAD
+ )
"
test_expect_success 'stat binary diff -- should not fail.' \
- 'git checkout master
+ 'git checkout master &&
git apply --stat --summary B.diff'
test_expect_success 'stat binary diff (copy) -- should not fail.' \
- 'git checkout master
+ 'git checkout master &&
git apply --stat --summary C.diff'
test_expect_success 'check binary diff -- should fail.' \
'
test_expect_success 'check binary diff with replacement.' \
- 'git checkout master
+ 'git checkout master &&
git apply --check --allow-binary-replacement BF.diff'
test_expect_success 'check binary diff with replacement (copy).' \
- 'git checkout master
+ 'git checkout master &&
git apply --check --allow-binary-replacement CF.diff'
# Now we start applying them.
'do_reset &&
test_must_fail git apply --index C.diff'
+test_expect_success 'apply binary diff with full-index' '
+ do_reset &&
+ git apply B-index.diff
+'
+
+test_expect_success 'apply binary diff with full-index (copy)' '
+ do_reset &&
+ git apply C-index.diff
+'
+
+test_expect_success 'apply full-index binary diff in new repo' '
+ (cd other-repo &&
+ do_reset &&
+ test_must_fail git apply ../B-index.diff)
+'
+
test_expect_success 'apply binary diff without replacement.' \
'do_reset &&
git apply BF.diff'
test_expect_success 'apply from .git dir' '
cp postimage expected &&
cp preimage .git/file &&
- cp preimage .git/objects/file
+ cp preimage .git/objects/file &&
(
cd .git &&
git apply "$patch"
test_expect_success 'apply from subdir of .git dir' '
cp postimage expected &&
cp preimage .git/file &&
- cp preimage .git/objects/file
+ cp preimage .git/objects/file &&
(
cd .git/objects &&
git apply "$patch"
test_expect_success 'apply --whitespace=strip in subdir' '
cd "$D" &&
- git config --unset-all apply.whitespace
+ git config --unset-all apply.whitespace &&
rm -f sub/file1 &&
cp saved sub/file1 &&
git update-index --refresh &&
'
test_expect_success 'blank at EOF with --whitespace=fix (1)' '
- : these can fail depending on what we did before
- git config --unset core.whitespace
- rm -f .gitattributes
+ test_might_fail git config --unset core.whitespace &&
+ rm -f .gitattributes &&
{ echo a; echo b; echo c; } >one &&
git add one &&
git diff -- one >patch &&
echo a >one &&
- test_must_fail git apply patch
+ test_must_fail git apply patch &&
test_must_fail git apply --whitespace=fix patch &&
test_must_fail git apply --ignore-space-change --whitespace=fix patch
'
printf "b\r\n" >>one &&
printf "c\r\n" >>one &&
cp one save-one &&
- printf " \r\n" >>one
+ printf " \r\n" >>one &&
git add one &&
printf "d\r\n" >>one &&
cp one expect &&
printf "b\r\n" >>one &&
printf "c\r\n" >>one &&
cp one save-one &&
- printf " \r\n" >>one
+ printf " \r\n" >>one &&
git add one &&
cp one expect &&
printf "d\r\n" >>one &&
'
test_expect_success 'apply same filename with overlapping changes' '
- git reset --hard
+ git reset --hard &&
modify "s/^d/z/" same_fn &&
git diff > patch0 &&
git add same_fn &&
'
test_expect_success 'apply same new filename after rename' '
- git reset --hard
- git mv same_fn new_fn
+ git reset --hard &&
+ git mv same_fn new_fn &&
modify "s/^d/z/" new_fn &&
git add new_fn &&
git diff -M --cached > patch1 &&
'
test_expect_success 'apply same old filename after rename -- should fail.' '
- git reset --hard
- git mv same_fn new_fn
+ git reset --hard &&
+ git mv same_fn new_fn &&
modify "s/^d/z/" new_fn &&
git add new_fn &&
git diff -M --cached > patch1 &&
- git mv new_fn same_fn
+ git mv new_fn same_fn &&
modify "s/^e/y/" same_fn &&
git diff >> patch1 &&
git reset --hard &&
'
test_expect_success 'apply A->B (rename), C->A (rename), A->A -- should pass.' '
- git reset --hard
- git mv same_fn new_fn
+ git reset --hard &&
+ git mv same_fn new_fn &&
modify "s/^d/z/" new_fn &&
git add new_fn &&
git diff -M --cached > patch1 &&
git commit -m "a rename" &&
- git mv other_fn same_fn
+ git mv other_fn same_fn &&
modify "s/^e/y/" same_fn &&
git add same_fn &&
git diff -M --cached >> patch1 &&
git reset --hard &&
mv file1 tmp &&
mv file2 file1 &&
- mv file3 file2
+ mv file3 file2 &&
mv tmp file3 &&
cp file1 file1-swapped &&
cp file2 file2-swapped &&
. ./test-lib.sh
test_expect_success setup '
- cat > bad1.patch <<EOF
+ cat > bad1.patch <<EOF &&
diff --git a/f b/f
new file mode 100644
index 0000000..d00491f
'
test_expect_success 'apply diff with inconsistent filenames in headers' '
- test_must_fail git apply bad1.patch 2>err
- grep "inconsistent new filename" err
- test_must_fail git apply bad2.patch 2>err
+ test_must_fail git apply bad1.patch 2>err &&
+ grep "inconsistent new filename" err &&
+ test_must_fail git apply bad2.patch 2>err &&
grep "inconsistent old filename" err
'
. ./test-lib.sh
test_expect_success setup '
- cat > create-sm.patch <<EOF
+ cat > create-sm.patch <<EOF &&
diff --git a/dir/sm b/dir/sm
new file mode 160000
index 0000000..0123456
test_expect_success 'am --signoff does not add Signed-off-by: line if already there' '
git format-patch --stdout HEAD^ >patch3 &&
- sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2," patch3 >patch4
+ sed -e "/^Subject/ s,\[PATCH,Re: Re: Re: & 1/5 v2," patch3 >patch4 &&
rm -fr .git/rebase-apply &&
git reset --hard &&
git checkout HEAD^ &&
tr 1234 "\370\235\204\236")" a1 &&
echo 5 >a1 &&
- git commit --quiet -m "a 12 34 56 78" a1
+ git commit --quiet -m "a 12 34 56 78" a1 &&
echo 6 >a1 &&
git commit --quiet -m "Commit by someone else" \
test_expect_success 'setup case sensitivity tests' '
echo case >one &&
test_tick &&
- git add one
+ git add one &&
git commit -a -m Second
'
test_commit octopus-b &&
git checkout master &&
test_commit seventh &&
- git merge octopus-a octopus-b
+ git merge octopus-a octopus-b &&
git merge reach
'
'
test_expect_success 'log.decorate configuration' '
- git config --unset-all log.decorate || :
+ test_might_fail git config --unset-all log.decorate &&
git log --oneline >expect.none &&
git log --oneline --decorate >expect.short &&
. ./test-lib.sh
+fuzz_blame () {
+ sed "
+ s/$_x05[0-9a-f][0-9a-f][0-9a-f]/OBJID/g
+ s/$_x05[0-9a-f][0-9a-f]/OBJI/g
+ s/[-0-9]\{10\} [:0-9]\{8\} [-+][0-9]\{4\}/DATE/g
+ " "$@"
+}
+
test_expect_success setup '
echo one >one &&
git add one &&
git commit -m initial &&
echo two >>one &&
git add one &&
+ test_tick &&
git commit --author "nick1 <bugs@company.xx>" -m second
'
EOF
test_expect_success 'mailmap.file set' '
- mkdir internal_mailmap &&
+ mkdir -p internal_mailmap &&
echo "Internal Guy <bugs@company.xx>" > internal_mailmap/.mailmap &&
git config mailmap.file internal_mailmap/.mailmap &&
git shortlog HEAD >actual &&
test_cmp expect actual
'
+cat >expect <<\EOF
+Internal Guy (1):
+ second
+
+Repo Guy (1):
+ initial
+
+EOF
+
+test_expect_success 'name entry after email entry' '
+ mkdir -p internal_mailmap &&
+ echo "<bugs@company.xy> <bugs@company.xx>" >internal_mailmap/.mailmap &&
+ echo "Internal Guy <bugs@company.xx>" >>internal_mailmap/.mailmap &&
+ git shortlog HEAD >actual &&
+ test_cmp expect actual
+'
+
+cat >expect <<\EOF
+Internal Guy (1):
+ second
+
+Repo Guy (1):
+ initial
+
+EOF
+
+test_expect_success 'name entry after email entry, case-insensitive' '
+ mkdir -p internal_mailmap &&
+ echo "<bugs@company.xy> <bugs@company.xx>" >internal_mailmap/.mailmap &&
+ echo "Internal Guy <BUGS@Company.xx>" >>internal_mailmap/.mailmap &&
+ git shortlog HEAD >actual &&
+ test_cmp expect actual
+'
+
cat >expect <<\EOF
A U Thor (1):
initial
EOF
test_expect_success 'No mailmap files, but configured' '
- rm .mailmap &&
+ rm -f .mailmap internal_mailmap/.mailmap &&
git shortlog HEAD >actual &&
test_cmp expect actual
'
test_tick &&
git commit --author "CTO <cto@coompany.xx>" -m seventh &&
- mkdir internal_mailmap &&
+ mkdir -p internal_mailmap &&
echo "Committed <committer@example.com>" > internal_mailmap/.mailmap &&
echo "<cto@company.xx> <cto@coompany.xx>" >> internal_mailmap/.mailmap &&
echo "Some Dude <some@dude.xx> nick1 <bugs@company.xx>" >> internal_mailmap/.mailmap &&
# git blame
cat >expect <<\EOF
-^3a2fdcb (A U Thor 2005-04-07 15:13:13 -0700 1) one
-7de6f99b (Some Dude 2005-04-07 15:13:13 -0700 2) two
-5815879d (Other Author 2005-04-07 15:14:13 -0700 3) three
-ff859d96 (Other Author 2005-04-07 15:15:13 -0700 4) four
-5ab6d4fa (Santa Claus 2005-04-07 15:16:13 -0700 5) five
-38a42d8b (Santa Claus 2005-04-07 15:17:13 -0700 6) six
-8ddc0386 (CTO 2005-04-07 15:18:13 -0700 7) seven
+^OBJI (A U Thor DATE 1) one
+OBJID (Some Dude DATE 2) two
+OBJID (Other Author DATE 3) three
+OBJID (Other Author DATE 4) four
+OBJID (Santa Claus DATE 5) five
+OBJID (Santa Claus DATE 6) six
+OBJID (CTO DATE 7) seven
EOF
-
test_expect_success 'Blame output (complex mapping)' '
git blame one >actual &&
- test_cmp expect actual
+ fuzz_blame actual >actual.fuzz &&
+ test_cmp expect actual.fuzz
'
test_done
'
test_expect_success 'apply to a funny path' '
- with_sq="with'\''sq"
+ with_sq="with'\''sq" &&
rm -fr .git/rebase-apply &&
git reset --hard initial &&
git am --directory="$with_sq" "$tm"/am-test-5-2 &&
test_expect_success \
'setup' \
- 'rm -f .git/index*
+ 'rm -f .git/index* &&
perl -e "print \"a\" x 4096;" > a &&
perl -e "print \"b\" x 4096;" > b &&
perl -e "print \"c\" x 4096;" > c &&
test_expect_success \
'setup' \
- 'rm -f .git/index*
+ 'rm -f .git/index* &&
for i in a b c
do
echo $i >$i &&
git repack -a -d &&
test "`git count-objects`" = "0 objects, 0 kilobytes" &&
pack2=`ls .git/objects/pack/*.pack` &&
- test -f "$pack2"
+ test -f "$pack2" &&
test "$pack1" \!= "$pack2"'
test_expect_success \
test_expect_success \
'setup' \
- 'rm -rf .git
+ 'rm -rf .git &&
git init &&
git config pack.threads 1 &&
i=1 &&
prev=$cur &&
cur=$(($cur+1))
done &&
- add B1 $A1
+ add B1 $A1 &&
echo $ATIP > .git/refs/heads/A &&
echo $BTIP > .git/refs/heads/B &&
git symbolic-ref HEAD refs/heads/B
cd cloned &&
git count-objects | sed -e "s/ *objects,.*//"
) ) &&
- test $cnt -eq 6
+ test $cnt -eq 6 &&
blob=$(git rev-parse HEAD:file | sed -e "s|..|&/|") &&
test -f "cloned/.git/objects/$blob" &&
'
test_expect_success NOT_MINGW 'fetch A (new commit : 1 connection)' '
- rm -f $U
+ rm -f $U &&
(
cd cloned &&
GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
'
test_expect_success NOT_MINGW 'fetch C, T (new branch, tag : 1 connection)' '
- rm -f $U
+ rm -f $U &&
(
cd cloned &&
GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
'
test_expect_success NOT_MINGW 'fetch B, S (commit and tag : 1 connection)' '
- rm -f $U
+ rm -f $U &&
(
cd cloned &&
GIT_DEBUG_SEND_PACK=3 git fetch 3>../$U &&
test_expect_success 'fetch must not resolve short remote name' '
cd "$D" &&
- git update-ref refs/remotes/six/HEAD HEAD
+ git update-ref refs/remotes/six/HEAD HEAD &&
mkdir six &&
cd six &&
(
cd two && git branch another
) &&
- git clone --mirror two three
+ git clone --mirror two three &&
git clone one test
'
'
test_expect_success 'warn on push to HEAD of non-bare repository' '
- mk_test heads/master
+ mk_test heads/master &&
(
cd testrepo &&
git checkout master &&
'
test_expect_success 'deny push to HEAD of non-bare repository' '
- mk_test heads/master
+ mk_test heads/master &&
(
cd testrepo &&
git checkout master &&
'
test_expect_success 'allow push to HEAD of bare repository (bare)' '
- mk_test heads/master
+ mk_test heads/master &&
(
cd testrepo &&
git checkout master &&
'
test_expect_success 'allow push to HEAD of non-bare repository (config)' '
- mk_test heads/master
+ mk_test heads/master &&
(
cd testrepo &&
git checkout master &&
(
cd alice-pub &&
git cat-file commit master >../bob-work/commit
- )
+ ) &&
(
# This time Bob does not pull from Alice, and
# the master branch at her public repository points
test_description='push with --set-upstream'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+ensure_fresh_upstream() {
+ rm -rf parent && git init --bare parent
+}
test_expect_success 'setup bare parent' '
- git init --bare parent &&
+ ensure_fresh_upstream &&
git remote add upstream parent
'
check_config headbranch upstream refs/heads/headbranch
'
+test_expect_success TTY 'progress messages go to tty' '
+ ensure_fresh_upstream &&
+
+ test_terminal git push -u upstream master >out 2>err &&
+ grep "Writing objects" err
+'
+
+test_expect_success 'progress messages do not go to non-tty' '
+ ensure_fresh_upstream &&
+
+ # skip progress messages, since stderr is non-tty
+ git push -u upstream master >out 2>err &&
+ ! grep "Writing objects" err
+'
+
+test_expect_success 'progress messages go to non-tty (forced)' '
+ ensure_fresh_upstream &&
+
+ # force progress messages to stderr, even though it is non-tty
+ git push -u --progress upstream master >out 2>err &&
+ grep "Writing objects" err
+'
+
+test_expect_success TTY 'push -q suppresses progress' '
+ ensure_fresh_upstream &&
+
+ test_terminal git push -u -q upstream master >out 2>err &&
+ ! grep "Writing objects" err
+'
+
+test_expect_failure TTY 'push --no-progress suppresses progress' '
+ ensure_fresh_upstream &&
+
+ test_terminal git push -u --no-progress upstream master >out 2>err &&
+ ! grep "Writing objects" err
+'
+
test_done
test_expect_success setup '
mkdir pub.git &&
- GIT_DIR=pub.git git init --bare
+ GIT_DIR=pub.git git init --bare &&
GIT_DIR=pub.git git config receive.fsckobjects true &&
mkdir work &&
(
SMART=smart
GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL
test_expect_success 'direct refs/heads/master not found' '
- log_div "refs/heads/master"
+ log_div "refs/heads/master" &&
GET refs/heads/master "404 Not Found"
'
test_expect_success 'static file is ok' '
- log_div "getanyfile default"
+ log_div "getanyfile default" &&
get_static_files "200 OK"
'
SMART=smart_noexport
unset GIT_HTTP_EXPORT_ALL
test_expect_success 'no export by default' '
- log_div "no git-daemon-export-ok"
+ log_div "no git-daemon-export-ok" &&
get_static_files "404 Not Found"
'
test_expect_success 'export if git-daemon-export-ok' '
- log_div "git-daemon-export-ok"
+ log_div "git-daemon-export-ok" &&
(cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
touch git-daemon-export-ok
) &&
SMART=smart
GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL
test_expect_success 'static file if http.getanyfile true is ok' '
- log_div "getanyfile true"
+ log_div "getanyfile true" &&
config http.getanyfile true &&
get_static_files "200 OK"
'
test_expect_success 'static file if http.getanyfile false fails' '
- log_div "getanyfile false"
+ log_div "getanyfile false" &&
config http.getanyfile false &&
get_static_files "403 Forbidden"
'
test_expect_success 'http.uploadpack default enabled' '
- log_div "uploadpack default"
+ log_div "uploadpack default" &&
GET info/refs?service=git-upload-pack "200 OK" &&
POST git-upload-pack 0000 "200 OK"
'
test_expect_success 'http.uploadpack true' '
- log_div "uploadpack true"
+ log_div "uploadpack true" &&
config http.uploadpack true &&
GET info/refs?service=git-upload-pack "200 OK" &&
POST git-upload-pack 0000 "200 OK"
'
test_expect_success 'http.uploadpack false' '
- log_div "uploadpack false"
+ log_div "uploadpack false" &&
config http.uploadpack false &&
GET info/refs?service=git-upload-pack "403 Forbidden" &&
POST git-upload-pack 0000 "403 Forbidden"
'
test_expect_success 'http.receivepack default disabled' '
- log_div "receivepack default"
+ log_div "receivepack default" &&
GET info/refs?service=git-receive-pack "403 Forbidden" &&
POST git-receive-pack 0000 "403 Forbidden"
'
test_expect_success 'http.receivepack true' '
- log_div "receivepack true"
+ log_div "receivepack true" &&
config http.receivepack true &&
GET info/refs?service=git-receive-pack "200 OK" &&
POST git-receive-pack 0000 "200 OK"
'
test_expect_success 'http.receivepack false' '
- log_div "receivepack false"
+ log_div "receivepack false" &&
config http.receivepack false &&
GET info/refs?service=git-receive-pack "403 Forbidden" &&
POST git-receive-pack 0000 "403 Forbidden"
. ./test-lib.sh
test_expect_success setup '
- echo "#!/bin/sh" > not_ssh
- echo "echo \"\$*\" > not_ssh_output" >> not_ssh
- echo "exit 1" >> not_ssh
+ echo "#!/bin/sh" > not_ssh &&
+ echo "echo \"\$*\" > not_ssh_output" >> not_ssh &&
+ echo "exit 1" >> not_ssh &&
chmod +x not_ssh
'
test_expect_success 'clone calls git upload-pack unqualified with no -u option' '
- GIT_SSH=./not_ssh git clone localhost:/path/to/repo junk
- echo "localhost git-upload-pack '\''/path/to/repo'\''" >expected
+ (
+ GIT_SSH=./not_ssh &&
+ export GIT_SSH &&
+ test_must_fail git clone localhost:/path/to/repo junk
+ ) &&
+ echo "localhost git-upload-pack '\''/path/to/repo'\''" >expected &&
test_cmp expected not_ssh_output
'
test_expect_success 'clone calls specified git upload-pack with -u option' '
- GIT_SSH=./not_ssh git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk
- echo "localhost ./something/bin/git-upload-pack '\''/path/to/repo'\''" >expected
+ (
+ GIT_SSH=./not_ssh &&
+ export GIT_SSH &&
+ test_must_fail git clone -u ./something/bin/git-upload-pack localhost:/path/to/repo junk
+ ) &&
+ echo "localhost ./something/bin/git-upload-pack '\''/path/to/repo'\''" >expected &&
test_cmp expected not_ssh_output
'
git clone --bare . a.git &&
git clone --bare . x &&
test "$(GIT_CONFIG=a.git/config git config --bool core.bare)" = true &&
- test "$(GIT_CONFIG=x/config git config --bool core.bare)" = true
+ test "$(GIT_CONFIG=x/config git config --bool core.bare)" = true &&
git bundle create b1.bundle --all &&
git bundle create b2.bundle master &&
mkdir dir &&
- cp b1.bundle dir/b3
+ cp b1.bundle dir/b3 &&
cp b1.bundle b4
'
cd "$D" &&
git clone b2.bundle b2 &&
cd b2 &&
- git fetch
+ git fetch &&
test ! -e .git/refs/heads/master
'
for type in basic parents parents-raw
do
test_expect_success 'without grafts' "
- rm -f .git/info/grafts
+ rm -f .git/info/grafts &&
check $type $B2 -- $B2 $B1 $B0
"
test_expect_success 'with grafts' "
- echo '$B0 $A2' >.git/info/grafts
+ echo '$B0 $A2' >.git/info/grafts &&
check $type $B2 -- $B2 $B1 $B0 $A2 $A1 $A0
"
test_expect_success 'without grafts, with pathlimit' "
- rm -f .git/info/grafts
+ rm -f .git/info/grafts &&
check $type $B2 subdir -- $B2 $B0
"
test_expect_success 'with grafts, with pathlimit' "
- echo '$B0 $A2' >.git/info/grafts
+ echo '$B0 $A2' >.git/info/grafts &&
check $type $B2 subdir -- $B2 $B0 $A2 $A0
"
commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
EOF
+test_expect_success '%x00 shows NUL' '
+ echo >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+ echo >>expect fooQbar &&
+ git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
+ nul_to_q <actual.nul >actual &&
+ test_cmp expect actual
+'
+
test_expect_success '%ad respects --date=' '
echo 2005-04-07 >expect.ad-short &&
git log -1 --date=short --pretty=tformat:%ad >output.ad-short master &&
commit one &&
- test_tick=$(($test_tick - 2400))
+ test_tick=$(($test_tick - 2400)) &&
commit two &&
commit three &&
R2=$(doit 3 R2 $R1) &&
PL=$(doit 4 PL $L2 $C2) &&
- PR=$(doit 4 PR $C2 $R2)
+ PR=$(doit 4 PR $C2 $R2) &&
git name-rev $C2 >expected &&
# Octopus merge B and C into branch A
git checkout A &&
git merge B C &&
- git tag A4
+ git tag A4 &&
test_commit A5 bar.txt &&
test_commit C4 bar.txt &&
git checkout A &&
git merge -s ours C &&
- git tag A6
+ git tag A6 &&
test_commit A7 bar.txt &&
# that undecorated merges are interesting, even with --simplify-by-decoration
test_expect_success '--graph --simplify-by-decoration' '
rm -f expected &&
- git tag -d A4
+ git tag -d A4 &&
echo "* $A7" >> expected &&
echo "* $A6" >> expected &&
echo "|\\ " >> expected &&
test_cmp expected actual
'
-# Get rid of all decorations on branch B, and graph with it simplified away
+test_expect_success 'setup: get rid of decorations on B' '
+ git tag -d B2 &&
+ git tag -d B1 &&
+ git branch -d B
+'
+
+# Graph with branch B 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 &&
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 &&
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 &&
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 &&
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 &&
git add dir &&
git commit -m "File: dir"'
-test_expect_code 1 'Merge with d/f conflicts' 'git merge "merge msg" B master'
+test_expect_success 'Merge with d/f conflicts' '
+ test_expect_code 1 git merge "merge msg" B master
+'
test_expect_success 'F/D conflict' '
git reset --hard &&
test_expect_success 'pull renaming branch into unrenaming one' \
'
- git show-branch
- git pull . white && {
- echo "BAD: should have conflicted"
- return 1
- }
- git ls-files -s
- test "$(git ls-files -u B | wc -l)" -eq 3 || {
- echo "BAD: should have left stages for B"
- return 1
- }
- test "$(git ls-files -s N | wc -l)" -eq 1 || {
- echo "BAD: should have merged N"
- return 1
- }
+ git show-branch &&
+ test_expect_code 1 git pull . white &&
+ git ls-files -s &&
+ git ls-files -u B >b.stages &&
+ test_line_count = 3 b.stages &&
+ git ls-files -s N >n.stages &&
+ test_line_count = 1 n.stages &&
sed -ne "/^g/{
p
q
- }" B | grep master || {
- echo "BAD: should have listed our change first"
- return 1
- }
- test "$(git diff white N | wc -l)" -eq 0 || {
- echo "BAD: should have taken colored branch"
- return 1
- }
+ }" B | grep master &&
+ git diff --exit-code white N
'
test_expect_success 'pull renaming branch into another renaming one' \
'
- rm -f B
- git reset --hard
- git checkout red
- git pull . white && {
- echo "BAD: should have conflicted"
- return 1
- }
- test "$(git ls-files -u B | wc -l)" -eq 3 || {
- echo "BAD: should have left stages"
- return 1
- }
- test "$(git ls-files -s N | wc -l)" -eq 1 || {
- echo "BAD: should have merged N"
- return 1
- }
+ rm -f B &&
+ git reset --hard &&
+ git checkout red &&
+ test_expect_code 1 git pull . white &&
+ git ls-files -u B >b.stages &&
+ test_line_count = 3 b.stages &&
+ git ls-files -s N >n.stages &&
+ test_line_count = 1 n.stages &&
sed -ne "/^g/{
p
q
- }" B | grep red || {
- echo "BAD: should have listed our change first"
- return 1
- }
- test "$(git diff white N | wc -l)" -eq 0 || {
- echo "BAD: should have taken colored branch"
- return 1
- }
+ }" B | grep red &&
+ git diff --exit-code white N
'
test_expect_success 'pull unrenaming branch into renaming one' \
'
- git reset --hard
- git show-branch
- git pull . master && {
- echo "BAD: should have conflicted"
- return 1
- }
- test "$(git ls-files -u B | wc -l)" -eq 3 || {
- echo "BAD: should have left stages"
- return 1
- }
- test "$(git ls-files -s N | wc -l)" -eq 1 || {
- echo "BAD: should have merged N"
- return 1
- }
+ git reset --hard &&
+ git show-branch &&
+ test_expect_code 1 git pull . master &&
+ git ls-files -u B >b.stages &&
+ test_line_count = 3 b.stages &&
+ git ls-files -s N >n.stages &&
+ test_line_count = 1 n.stages &&
sed -ne "/^g/{
p
q
- }" B | grep red || {
- echo "BAD: should have listed our change first"
- return 1
- }
- test "$(git diff white N | wc -l)" -eq 0 || {
- echo "BAD: should have taken colored branch"
- return 1
- }
+ }" B | grep red &&
+ git diff --exit-code white N
'
test_expect_success 'pull conflicting renames' \
'
- git reset --hard
- git show-branch
- git pull . blue && {
- echo "BAD: should have conflicted"
- return 1
- }
- test "$(git ls-files -u A | wc -l)" -eq 1 || {
- echo "BAD: should have left a stage"
- return 1
- }
- test "$(git ls-files -u B | wc -l)" -eq 1 || {
- echo "BAD: should have left a stage"
- return 1
- }
- test "$(git ls-files -u C | wc -l)" -eq 1 || {
- echo "BAD: should have left a stage"
- return 1
- }
- test "$(git ls-files -s N | wc -l)" -eq 1 || {
- echo "BAD: should have merged N"
- return 1
- }
+ git reset --hard &&
+ git show-branch &&
+ test_expect_code 1 git pull . blue &&
+ git ls-files -u A >a.stages &&
+ test_line_count = 1 a.stages &&
+ git ls-files -u B >b.stages &&
+ test_line_count = 1 b.stages &&
+ git ls-files -u C >c.stages &&
+ test_line_count = 1 c.stages &&
+ git ls-files -s N >n.stages &&
+ test_line_count = 1 n.stages &&
sed -ne "/^g/{
p
q
- }" B | grep red || {
- echo "BAD: should have listed our change first"
- return 1
- }
- test "$(git diff white N | wc -l)" -eq 0 || {
- echo "BAD: should have taken colored branch"
- return 1
- }
+ }" B | grep red &&
+ git diff --exit-code white N
'
test_expect_success 'interference with untracked working tree file' '
-
- git reset --hard
- git show-branch
- echo >A this file should not matter
- git pull . white && {
- echo "BAD: should have conflicted"
- return 1
- }
- test -f A || {
- echo "BAD: should have left A intact"
- return 1
- }
+ git reset --hard &&
+ git show-branch &&
+ echo >A this file should not matter &&
+ test_expect_code 1 git pull . white &&
+ test_path_is_file A
'
test_expect_success 'interference with untracked working tree file' '
-
- git reset --hard
- git checkout white
- git show-branch
- rm -f A
- echo >A this file should not matter
- git pull . red && {
- echo "BAD: should have conflicted"
- return 1
- }
- test -f A || {
- echo "BAD: should have left A intact"
- return 1
- }
+ git reset --hard &&
+ git checkout white &&
+ git show-branch &&
+ rm -f A &&
+ echo >A this file should not matter &&
+ test_expect_code 1 git pull . red &&
+ test_path_is_file A
'
test_expect_success 'interference with untracked working tree file' '
-
- git reset --hard
- rm -f A M
- git checkout -f master
- git tag -f anchor
- git show-branch
- git pull . yellow || {
- echo "BAD: should have cleanly merged"
- return 1
- }
- test -f M && {
- echo "BAD: should have removed M"
- return 1
- }
+ git reset --hard &&
+ rm -f A M &&
+ git checkout -f master &&
+ git tag -f anchor &&
+ git show-branch &&
+ git pull . yellow &&
+ test_path_is_missing M &&
git reset --hard anchor
'
test_expect_success 'updated working tree file should prevent the merge' '
-
- git reset --hard
- rm -f A M
- git checkout -f master
- git tag -f anchor
- git show-branch
- echo >>M one line addition
- cat M >M.saved
- git pull . yellow && {
- echo "BAD: should have complained"
- return 1
- }
- test_cmp M M.saved || {
- echo "BAD: should have left M intact"
- return 1
- }
+ git reset --hard &&
+ rm -f A M &&
+ git checkout -f master &&
+ git tag -f anchor &&
+ git show-branch &&
+ echo >>M one line addition &&
+ cat M >M.saved &&
+ test_expect_code 128 git pull . yellow &&
+ test_cmp M M.saved &&
rm -f M.saved
'
test_expect_success 'updated working tree file should prevent the merge' '
-
- git reset --hard
- rm -f A M
- git checkout -f master
- git tag -f anchor
- git show-branch
- echo >>M one line addition
- cat M >M.saved
- git update-index M
- git pull . yellow && {
- echo "BAD: should have complained"
- return 1
- }
- test_cmp M M.saved || {
- echo "BAD: should have left M intact"
- return 1
- }
+ git reset --hard &&
+ rm -f A M &&
+ git checkout -f master &&
+ git tag -f anchor &&
+ git show-branch &&
+ echo >>M one line addition &&
+ cat M >M.saved &&
+ git update-index M &&
+ test_expect_code 128 git pull . yellow &&
+ test_cmp M M.saved &&
rm -f M.saved
'
test_expect_success 'interference with untracked working tree file' '
-
- git reset --hard
- rm -f A M
- git checkout -f yellow
- git tag -f anchor
- git show-branch
- echo >M this file should not matter
- git pull . master || {
- echo "BAD: should have cleanly merged"
- return 1
- }
- test -f M || {
- echo "BAD: should have left M intact"
- return 1
- }
- git ls-files -s | grep M && {
- echo "BAD: M must be untracked in the result"
- return 1
- }
+ git reset --hard &&
+ rm -f A M &&
+ git checkout -f yellow &&
+ git tag -f anchor &&
+ git show-branch &&
+ echo >M this file should not matter &&
+ git pull . master &&
+ test_path_is_file M &&
+ ! {
+ git ls-files -s |
+ grep M
+ } &&
git reset --hard anchor
'
test_expect_success 'merge of identical changes in a renamed file' '
- rm -f A M N
+ rm -f A M N &&
git reset --hard &&
git checkout change+rename &&
GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
test_expect_success "merge without conflict" \
"git merge-file test.txt orig.txt new2.txt"
+test_expect_success 'works in subdirectory' '
+ mkdir dir &&
+ cp new1.txt dir/a.txt &&
+ cp orig.txt dir/o.txt &&
+ cp new2.txt dir/b.txt &&
+ ( cd dir && git merge-file a.txt o.txt b.txt )
+'
+
cp new1.txt test.txt
test_expect_success "merge without conflict (--quiet)" \
"git merge-file --quiet test.txt orig.txt new2.txt"
test_tick &&
git commit -m delete &&
git checkout -b rename HEAD^ &&
- git mv a1 a2
+ git mv a1 a2 &&
test_tick &&
git commit -m rename &&
test_must_fail git merge delete &&
test_expect_success setup '
- s="1 2 3 4 5 6 7 8"
+ s="1 2 3 4 5 6 7 8" &&
for i in $s; do echo $i; done >hello &&
git add hello &&
git commit -m initial &&
add_line_into_file "2(para): line 2 on parallel branch" dir2/file2 &&
PARA_HASH2=$(git rev-parse --verify HEAD) &&
add_line_into_file "3(para): line 3 on parallel branch" dir2/file3 &&
- PARA_HASH3=$(git rev-parse --verify HEAD)
+ PARA_HASH3=$(git rev-parse --verify HEAD) &&
git merge -m "merge HASH4 and PARA_HASH3" "$HASH4" &&
- PARA_HASH4=$(git rev-parse --verify HEAD)
+ PARA_HASH4=$(git rev-parse --verify HEAD) &&
add_line_into_file "5(para): add line on parallel branch" dir1/file1 &&
- PARA_HASH5=$(git rev-parse --verify HEAD)
+ PARA_HASH5=$(git rev-parse --verify HEAD) &&
add_line_into_file "6(para): add line on parallel branch" dir2/file2 &&
- PARA_HASH6=$(git rev-parse --verify HEAD)
+ PARA_HASH6=$(git rev-parse --verify HEAD) &&
git merge -m "merge HASH7 and PARA_HASH6" "$HASH7" &&
PARA_HASH7=$(git rev-parse --verify HEAD)
'
#
test_expect_success setup '
- ten="0 1 2 3 4 5 6 7 8 9"
+ ten="0 1 2 3 4 5 6 7 8 9" &&
for i in $ten
do
echo line $i in a sample file
test_expect_success 'checkout with local tracked branch' '
git checkout master &&
- git checkout follower >actual
+ git checkout follower >actual &&
grep "is ahead of" actual
'
echo "line 12" >> hello &&
echo "line 13" >> hello &&
add_and_commit_file hello "2 more lines" &&
- HASH6=$(git rev-parse --verify HEAD)
+ HASH6=$(git rev-parse --verify HEAD) &&
echo "line 14" >> hello &&
echo "line 15" >> hello &&
echo "line 16" >> hello &&
test_expect_success \
'checking -f on untracked file with existing target' \
'touch path0/untracked1 &&
- git mv -f untracked1 path0
+ test_must_fail git mv -f untracked1 path0 &&
test ! -f .git/index.lock &&
test -f untracked1 &&
test -f path0/untracked1'
git init &&
echo 1 >dirty &&
git add dirty &&
- entry="$(git ls-files --stage dirty | cut -f 1)"
+ entry="$(git ls-files --stage dirty | cut -f 1)" &&
git mv dirty dirty2 &&
[ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
echo 2 >dirty2 &&
test_expect_success \
'message in editor has initial comment' '
- GIT_EDITOR=cat git tag -a initial-comment > actual
+ ! (GIT_EDITOR=cat git tag -a initial-comment > actual)
+'
+
+test_expect_success \
+ 'message in editor has initial comment: first line' '
# check the first line --- should be empty
- first=$(sed -e 1q <actual) &&
- test -z "$first" &&
+ echo >first.expect &&
+ sed -e 1q <actual >first.actual &&
+ test_cmp first.expect first.actual
+'
+
+test_expect_success \
+ 'message in editor has initial comment: remainder' '
# remove commented lines from the remainder -- should be empty
- rest=$(sed -e 1d -e '/^#/d' <actual) &&
- test -z "$rest"
+ >rest.expect
+ sed -e 1d -e '/^#/d' <actual >rest.actual &&
+ test_cmp rest.expect rest.actual
'
get_tag_header reuse $commit commit $time >expect
test_expect_success 'creating second commit and tag' '
echo foo-2.0 >foo &&
git add foo &&
- git commit -m second
+ git commit -m second &&
git tag v2.0
'
EOF
test_expect_success 'checking that first commit is in all tags (hash)' "
- git tag -l --contains $hash1 v* >actual
+ git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
"
# other ways of specifying the commit
test_expect_success 'checking that first commit is in all tags (tag)' "
- git tag -l --contains v1.0 v* >actual
+ git tag -l --contains v1.0 v* >actual &&
test_cmp expected actual
"
test_expect_success 'checking that first commit is in all tags (relative)' "
- git tag -l --contains HEAD~2 v* >actual
+ git tag -l --contains HEAD~2 v* >actual &&
test_cmp expected actual
"
EOF
test_expect_success 'checking that second commit only has one tag' "
- git tag -l --contains $hash2 v* >actual
+ git tag -l --contains $hash2 v* >actual &&
test_cmp expected actual
"
EOF
test_expect_success 'checking that third commit has no tags' "
- git tag -l --contains $hash3 v* >actual
+ git tag -l --contains $hash3 v* >actual &&
test_cmp expected actual
"
git branch stable v2.0 &&
git checkout stable &&
echo foo-3.0 > foo &&
- git commit foo -m fourth
+ git commit foo -m fourth &&
git tag v3.0
'
EOF
test_expect_success 'checking that branch head only has one tag' "
- git tag -l --contains $hash4 v* >actual
+ git tag -l --contains $hash4 v* >actual &&
test_cmp expected actual
"
EOF
test_expect_success 'checking that original branch head has one tag now' "
- git tag -l --contains $hash3 v* >actual
+ git tag -l --contains $hash3 v* >actual &&
test_cmp expected actual
"
EOF
test_expect_success 'checking that initial commit is in all tags' "
- git tag -l --contains $hash1 v* >actual
+ git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
"
# mixing modes and options:
test_expect_success 'mixing incompatibles modes and options is forbidden' '
- test_must_fail git tag -a
- test_must_fail git tag -l -v
- test_must_fail git tag -n 100
- test_must_fail git tag -l -m msg
- test_must_fail git tag -l -F some file
+ test_must_fail git tag -a &&
+ test_must_fail git tag -l -v &&
+ test_must_fail git tag -n 100 &&
+ test_must_fail git tag -l -m msg &&
+ test_must_fail git tag -l -F some file &&
test_must_fail git tag -v -s
'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-pager.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
cleanup_fail() {
echo >&2 cleanup failed
(exit 1)
}
-test_expect_success 'set up terminal for tests' '
- rm -f stdout_is_tty ||
- cleanup_fail &&
-
- if test -t 1
- then
- >stdout_is_tty
- elif
- test_have_prereq PERL &&
- "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl \
- sh -c "test -t 1"
- then
- >test_terminal_works
- fi
-'
-
-if test -e stdout_is_tty
-then
- test_terminal() { "$@"; }
- test_set_prereq TTY
-elif test -e test_terminal_works
-then
- test_terminal() {
- "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl "$@"
- }
- test_set_prereq TTY
-else
- say "# no usable terminal, so skipping some tests"
-fi
-
test_expect_success 'setup' '
- unset GIT_PAGER GIT_PAGER_IN_USE;
+ sane_unset GIT_PAGER GIT_PAGER_IN_USE &&
test_might_fail git config --unset core.pager &&
PAGER="cat >paginated.out" &&
colorful colorful.log
'
-if test_have_prereq SIMPLEPAGER && test_have_prereq TTY
-then
- test_set_prereq SIMPLEPAGERTTY
-fi
-
# Use this helper to make it easy for the caller of your
# terminal-using function to specify whether it should fail.
# If you write
test_default_pager() {
parse_args "$@"
- $test_expectation SIMPLEPAGERTTY "$cmd - default pager is used by default" "
- unset PAGER GIT_PAGER;
+ $test_expectation SIMPLEPAGER,TTY "$cmd - default pager is used by default" "
+ sane_unset PAGER GIT_PAGER &&
test_might_fail git config --unset core.pager &&
rm -f default_pager_used ||
cleanup_fail &&
parse_args "$@"
$test_expectation TTY "$cmd - PAGER overrides default pager" "
- unset GIT_PAGER;
+ sane_unset GIT_PAGER &&
test_might_fail git config --unset core.pager &&
rm -f PAGER_used ||
cleanup_fail &&
parse_args "$@"
$test_expectation TTY "$cmd - repository-local core.pager setting $used_if_wanted" "
- unset GIT_PAGER;
+ sane_unset GIT_PAGER &&
rm -f core.pager_used ||
cleanup_fail &&
parse_args "$@"
$test_expectation TTY "$cmd - core.pager $used_if_wanted from subdirectory" "
- unset GIT_PAGER;
+ sane_unset GIT_PAGER &&
rm -f core.pager_used &&
rm -fr sub ||
cleanup_fail &&
# note: bar sorts before foo, so the first 'n' is always to skip 'bar'
test_expect_success PERL 'saying "n" does nothing' '
- set_and_save_state dir/foo work work
+ set_and_save_state dir/foo work work &&
(echo n; echo n) | git reset -p &&
verify_saved_state dir/foo &&
verify_saved_state bar
# the failure case (and thus get out of the loop).
test_expect_success PERL 'git reset -p dir' '
- set_state dir/foo work work
+ set_state dir/foo work work &&
(echo y; echo n) | git reset -p dir &&
verify_state dir/foo work head &&
verify_saved_state bar
'
test_expect_success PERL 'git reset -p -- foo (inside dir)' '
- set_state dir/foo work work
+ set_state dir/foo work work &&
(echo y; echo n) | (cd dir && git reset -p -- foo) &&
verify_state dir/foo work head &&
verify_saved_state bar
mkdir -p build docs &&
touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
- ln -s docs/manual.txt src/part4.c
+ ln -s docs/manual.txt src/part4.c &&
git clean &&
test -f Makefile &&
test -f README &&
test_expect_success 'added submodule' "
git add sm1 &&
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 0000000...$head1 (2):
> Add foo2
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
test_expect_success 'modified submodule(forward)' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head1...$head2 (1):
> Add foo3
EOF
+ test_cmp expected actual
"
test_expect_success 'modified submodule(forward), --files' "
git submodule summary --files >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head1...$head2 (1):
> Add foo3
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
test_expect_success 'modified submodule(backward)' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head2...$head3 (2):
< Add foo3
< Add foo2
EOF
+ test_cmp expected actual
"
head4=$(add_file sm1 foo4 foo5) &&
head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
test_expect_success 'modified submodule(backward and forward)' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head2...$head4 (4):
> Add foo5
> Add foo4
< Add foo2
EOF
+ test_cmp expected actual
"
test_expect_success '--summary-limit' "
git submodule summary -n 3 >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head2...$head4 (4):
> Add foo5
> Add foo4
< Add foo3
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
test_expect_success 'typechanged submodule(submodule->blob), --cached' "
git submodule summary --cached >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head4(submodule)->$head5(blob) (3):
< Add foo5
EOF
+ test_cmp actual expected
"
test_expect_success 'typechanged submodule(submodule->blob), --files' "
git submodule summary --files >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head5(blob)->$head4(submodule) (3):
> Add foo5
EOF
+ test_cmp actual expected
"
rm -rf sm1 &&
git checkout-index sm1
test_expect_success 'typechanged submodule(submodule->blob)' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head4(submodule)->$head5(blob):
EOF
+ test_cmp actual expected
"
rm -f sm1 &&
head6=$(add_file sm1 foo6 foo7)
test_expect_success 'nonexistent commit' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head4...$head6:
Warn: sm1 doesn't contain commit $head4_full
EOF
+ test_cmp actual expected
"
commit_file
test_expect_success 'typechanged submodule(blob->submodule)' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head5(blob)->$head6(submodule) (2):
> Add foo7
EOF
+ test_cmp expected actual
"
commit_file sm1 &&
rm -rf sm1
test_expect_success 'deleted submodule' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head6...0000000:
EOF
+ test_cmp expected actual
"
test_create_repo sm2 &&
test_expect_success 'multiple submodules' "
git submodule summary >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head6...0000000:
* sm2 0000000...$head7 (2):
> Add foo9
EOF
+ test_cmp expected actual
"
test_expect_success 'path filter' "
git submodule summary sm2 >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm2 0000000...$head7 (2):
> Add foo9
EOF
+ test_cmp expected actual
"
commit_file sm2
test_expect_success 'given commit' "
git submodule summary HEAD^ >actual &&
- diff actual - <<-EOF
+ cat >expected <<-EOF &&
* sm1 $head6...0000000:
* sm2 0000000...$head7 (2):
> Add foo9
EOF
+ test_cmp expected actual
"
test_expect_success '--for-status' "
git commit -m "submodule"
) &&
git clone super super-clone &&
- (cd super-clone && git submodule update --init)
+ (cd super-clone && git submodule update --init) &&
+ git clone super empty-clone &&
+ (cd empty-clone && git submodule init)
'
test_expect_success 'change submodule' '
)
'
+test_expect_success '"git submodule sync" should update submodule URLs if not yet cloned' '
+ (cd empty-clone &&
+ git pull &&
+ git submodule sync &&
+ test -d "$(git config submodule.submodule.url)"
+ )
+'
+
test_done
test_cmp expect actual
'
+sed -e "/nested1 /s/.*/+$nested1sha1 nested1 (file2~1)/;/sub[1-3]/d" < expect > expect2
+mv -f expect2 expect
+
+test_expect_success 'ensure "status --cached --recursive" preserves the --cached flag' '
+ (
+ cd clone3 &&
+ (
+ cd nested1 &&
+ test_commit file2
+ ) &&
+ git submodule status --cached --recursive -- nested1 > ../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/nested1/nested2/nested3/submodule/.git
'
+test_expect_success 'test "update --recursive" with a flag with spaces' '
+ git clone super "common objects" &&
+ git clone super clone5 &&
+ (
+ cd clone5 &&
+ test ! -d nested1/.git &&
+ git submodule update --init --recursive --reference="$(dirname "$PWD")/common objects" &&
+ test -d nested1/.git &&
+ test -d nested1/nested2/.git &&
+ test -d nested1/nested2/nested3/.git &&
+ test -f nested1/.git/objects/info/alternates &&
+ test -f nested1/nested2/.git/objects/info/alternates &&
+ test -f nested1/nested2/nested3/.git/objects/info/alternates
+ )
+'
+
+test_expect_success 'use "update --recursive nested1" to checkout all submodules rooted in nested1' '
+ git clone super clone6 &&
+ (
+ cd clone6 &&
+ test ! -d sub1/.git &&
+ test ! -d sub2/.git &&
+ test ! -d sub3/.git &&
+ test ! -d nested1/.git &&
+ git submodule update --init --recursive -- nested1 &&
+ 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
+ )
+'
+
test_done
echo >>negative &&
(
- unset GIT_COMMITTER_EMAIL
- unset GIT_COMMITTER_NAME
+ sane_unset GIT_COMMITTER_EMAIL &&
+ sane_unset GIT_COMMITTER_NAME &&
# must fail because there is no change
test_must_fail git commit -e -m "sample"
) &&
test_expect_success 'commit --no-status' '
clear_config commit.status &&
- try_commit --no-status
+ try_commit --no-status &&
! grep "^# Changes to be committed:" .git/COMMIT_EDITMSG
'
test_tick &&
git commit -a -C Initial --reset-author &&
echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
- author_header HEAD >actual
+ author_header HEAD >actual &&
test_cmp expect actual &&
message_body Initial >expect &&
test_expect_success 'merge picks up the best result' '
git config --unset-all pull.twohead &&
git reset --hard c5 &&
- git merge -s resolve c6
+ test_must_fail git merge -s resolve c6 &&
resolve_count=$(conflict_count) &&
git reset --hard c5 &&
- git merge -s recursive c6
+ test_must_fail git merge -s recursive c6 &&
recursive_count=$(conflict_count) &&
git reset --hard c5 &&
- git merge -s recursive -s resolve c6
+ test_must_fail git merge -s recursive -s resolve c6 &&
auto_count=$(conflict_count) &&
test $auto_count = $recursive_count &&
test $auto_count != $resolve_count
test_expect_success 'merge picks up the best result (from config)' '
git config pull.twohead "recursive resolve" &&
git reset --hard c5 &&
- git merge -s resolve c6
+ test_must_fail git merge -s resolve c6 &&
resolve_count=$(conflict_count) &&
git reset --hard c5 &&
- git merge -s recursive c6
+ test_must_fail git merge -s recursive c6 &&
recursive_count=$(conflict_count) &&
git reset --hard c5 &&
- git merge c6
+ test_must_fail git merge c6 &&
auto_count=$(conflict_count) &&
test $auto_count = $recursive_count &&
test $auto_count != $resolve_count
do
refs="$refs c$i"
i=`expr $i + 1`
- done
+ done &&
git merge $refs &&
test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" &&
i=1 &&
test_expect_success 'mergetool crlf' '
git config core.autocrlf true &&
- git checkout -b test2 branch1
+ git checkout -b test2 branch1 &&
test_must_fail git merge master >/dev/null 2>&1 &&
( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
'
test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
- mkdir alt_objects/pack
+ mkdir alt_objects/pack &&
mv .git/objects/pack/* alt_objects/pack &&
git repack -a &&
myidx=$(ls -1 .git/objects/pack/*.idx) &&
# swap the .keep so the commit object is in the pack with .keep
for p in alt_objects/pack/*.pack
do
- base_name=$(basename $p .pack)
+ base_name=$(basename $p .pack) &&
if test -f alt_objects/pack/$base_name.keep
then
rm alt_objects/pack/$base_name.keep
else
touch alt_objects/pack/$base_name.keep
fi
- done
+ done &&
git repack -a -d &&
myidx=$(ls -1 .git/objects/pack/*.idx) &&
test -f "$myidx" &&
# Specify the diff tool using $GIT_DIFF_TOOL
test_expect_success PERL 'GIT_DIFF_TOOL variable' '
- git config --unset diff.tool
+ test_might_fail git config --unset diff.tool &&
GIT_DIFF_TOOL=test-tool &&
export GIT_DIFF_TOOL &&
# Test that we don't have to pass --no-prompt when mergetool.prompt is false
test_expect_success PERL 'difftool merge.prompt = false' '
- git config --unset difftool.prompt
+ test_might_fail git config --unset difftool.prompt &&
git config mergetool.prompt false &&
diff=$(git difftool branch) &&
# git-difftool falls back to git-mergetool config variables
# so test that behavior here
test_expect_success PERL 'difftool + mergetool config variables' '
- remove_config_vars
+ remove_config_vars &&
git config merge.tool test-tool &&
git config mergetool.test-tool.cmd "cat \$LOCAL" &&
'
test_expect_success PERL 'difftool --extcmd echo arg1' '
- diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"echo\ \$1\" branch)
+ diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"echo\ \$1\" branch) &&
test "$diff" = file
'
test_expect_success PERL 'difftool --extcmd cat arg1' '
- diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$1\" branch)
+ diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$1\" branch) &&
test "$diff" = master
'
test_expect_success PERL 'difftool --extcmd cat arg2' '
- diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$2\" branch)
+ diff=$(git difftool --no-prompt --extcmd sh\ -c\ \"cat\ \$2\" branch) &&
test "$diff" = branch
'
echo file1:hello &&
echo sub/file2:world
} >non/expect.full &&
- echo file2:world >non/expect.sub
+ echo file2:world >non/expect.sub &&
(
GIT_CEILING_DIRECTORIES="$(pwd)/non/git" &&
export GIT_CEILING_DIRECTORIES &&
echo sub/file2:world
} >is/expect.full &&
: >is/expect.empty &&
- echo file2:world >is/expect.sub
+ echo file2:world >is/expect.sub &&
(
cd is/git &&
git init &&
cat >helper <<'EOF'
#!/bin/sh
-sed 's/^/converted: /' "$@"
+grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
+sed 's/^bin: /converted: /' "$1"
EOF
chmod +x helper
test_expect_success 'setup ' '
- echo test 1 >one.bin &&
- echo test number 2 >two.bin &&
+ echo "bin: test 1" >one.bin &&
+ echo "bin: test number 2" >two.bin &&
+ if test_have_prereq SYMLINKS; then
+ ln -s one.bin symlink.bin
+ fi &&
git add . &&
GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
- echo test 1 version 2 >one.bin &&
- echo test number 2 version 2 >>two.bin &&
+ echo "bin: test 1 version 2" >one.bin &&
+ echo "bin: test number 2 version 2" >>two.bin &&
+ if test_have_prereq SYMLINKS; then
+ ln -sf two.bin symlink.bin
+ fi &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
cat >expected <<EOF
-(Number2 2010-01-01 20:00:00 +0000 1) test 1 version 2
+(Number2 2010-01-01 20:00:00 +0000 1) bin: test 1 version 2
EOF
test_expect_success 'no filter specified' '
'
test_expect_success 'make a new commit' '
- echo "test number 2 version 3" >>two.bin &&
+ echo "bin: test number 2 version 3" >>two.bin &&
GIT_AUTHOR_NAME=Number3 git commit -a -m Third --date="2010-01-01 22:00:00"
'
test_cmp expected result
'
+cat >expected <<EOF
+(Number2 2010-01-01 20:00:00 +0000 1) two.bin
+EOF
+
+test_expect_success SYMLINKS 'blame with --no-textconv (on symlink)' '
+ git blame --no-textconv symlink.bin >blame &&
+ find_blame <blame >result &&
+ test_cmp expected result
+'
+
+test_expect_success SYMLINKS 'blame --textconv (on symlink)' '
+ git blame --textconv symlink.bin >blame &&
+ find_blame <blame >result &&
+ test_cmp expected result
+'
+
+# cp two.bin three.bin and make small tweak
+# (this will direct blame -C -C three.bin to consider two.bin and symlink.bin)
+test_expect_success SYMLINKS 'make another new commit' '
+ cat >three.bin <<\EOF &&
+bin: test number 2
+bin: test number 2 version 2
+bin: test number 2 version 3
+bin: test number 3
+EOF
+ git add three.bin &&
+ GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00"
+'
+
+test_expect_success SYMLINKS 'blame on last commit (-C -C, symlink)' '
+ git blame -C -C three.bin >blame &&
+ find_blame <blame >result &&
+ cat >expected <<\EOF &&
+(Number1 2010-01-01 18:00:00 +0000 1) converted: test number 2
+(Number2 2010-01-01 20:00:00 +0000 2) converted: test number 2 version 2
+(Number3 2010-01-01 22:00:00 +0000 3) converted: test number 2 version 3
+(Number4 2010-01-01 23:00:00 +0000 4) converted: test number 3
+EOF
+ test_cmp expected result
+'
+
test_done
cat >helper <<'EOF'
#!/bin/sh
-sed 's/^/converted: /' "$@"
+grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
+sed 's/^bin: /converted: /' "$1"
EOF
chmod +x helper
test_expect_success 'setup ' '
- echo test >one.bin &&
+ echo "bin: test" >one.bin &&
+ if test_have_prereq SYMLINKS; then
+ ln -s one.bin symlink.bin
+ fi &&
git add . &&
GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
- echo test version 2 >one.bin &&
+ echo "bin: test version 2" >one.bin &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
'
cat >expected <<EOF
-test version 2
+bin: test version 2
EOF
test_expect_success 'cat-file without --textconv' '
'
cat >expected <<EOF
-test
+bin: test
EOF
test_expect_success 'cat-file without --textconv on previous commit' '
git cat-file --textconv HEAD^:one.bin >result &&
test_cmp expected result
'
+
+test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
+ git cat-file blob :symlink.bin >result &&
+ printf "%s" "one.bin" >expected
+ test_cmp expected result
+'
+
+
+test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' '
+ ! git cat-file --textconv :symlink.bin 2>result &&
+ cat >expected <<\EOF &&
+fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
+EOF
+ test_cmp expected result
+'
+
+test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
+ ! git cat-file --textconv HEAD:symlink.bin 2>result &&
+ cat >expected <<EOF &&
+fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin
+EOF
+ test_cmp expected result
+'
+
test_done
git svn init --minimize-url -i stunk "$svnrepo"/stunk &&
git svn fetch -i stunk &&
git svn init --minimize-url -i flunked "$svnrepo"/flunked &&
- git svn fetch -i flunked
+ git svn fetch -i flunked &&
test "`git rev-parse --verify refs/remotes/flunk@18`" \
= "`git rev-parse --verify refs/remotes/stunk`" &&
test "`git rev-parse --verify refs/remotes/flunk~1`" \
test_expect_success 'init, fetch and checkout repository' '
git svn init --rewrite-root=http://invalid.invalid/ "$svnrepo" &&
- git svn fetch
+ git svn fetch &&
git checkout -b mybranch ${remotes_git_svn}
'
svn_cmd import -m "import for git svn" . "$svnrepo"
) &&
rm -rf import &&
- git svn init "$svnrepo"
+ git svn init "$svnrepo" &&
git svn fetch
'
'
test_expect_success 'git svn rebase creates empty directory' '
- ( cd cloned && git svn rebase )
+ ( cd cloned && git svn rebase ) &&
test -d cloned/"! !"
'
test_expect_success 'all svn merges became git merge commits' '
unmarked=$(git rev-list --parents --all --grep=Merge |
- grep -v " .* " | cut -f1 -d" ")
+ grep -v " .* " | cut -f1 -d" ") &&
[ -z "$unmarked" ]
'
test_expect_success 'cherry picks did not become git merge commits' '
bad_cherries=$(git rev-list --parents --all --grep=Cherry |
- grep " .* " | cut -f1 -d" ")
+ grep " .* " | cut -f1 -d" ") &&
[ -z "$bad_cherries" ]
'
test_expect_success 'svn non-merge merge commits did not become git merge commits' '
bad_non_merges=$(git rev-list --parents --all --grep=non-merge |
- grep " .* " | cut -f1 -d" ")
+ grep " .* " | cut -f1 -d" ") &&
[ -z "$bad_non_merges" ]
'
test_expect_success 'commit made to merged branch is reachable from the merge' '
- before_commit=$(git rev-list --all --grep="trunk commit before merging trunk to b2")
- merge_commit=$(git rev-list --all --grep="Merge trunk to b2")
- not_reachable=$(git rev-list -1 $before_commit --not $merge_commit)
+ before_commit=$(git rev-list --all --grep="trunk commit before merging trunk to b2") &&
+ merge_commit=$(git rev-list --all --grep="Merge trunk to b2") &&
+ not_reachable=$(git rev-list -1 $before_commit --not $merge_commit) &&
[ -z "$not_reachable" ]
'
test_expect_success 'merging two branches in one commit is detected correctly' '
- f1_commit=$(git rev-list --all --grep="make f1 branch from trunk")
- f2_commit=$(git rev-list --all --grep="make f2 branch from trunk")
- merge_commit=$(git rev-list --all --grep="Merge f1 and f2 to trunk")
- not_reachable=$(git rev-list -1 $f1_commit $f2_commit --not $merge_commit)
+ f1_commit=$(git rev-list --all --grep="make f1 branch from trunk") &&
+ f2_commit=$(git rev-list --all --grep="make f2 branch from trunk") &&
+ merge_commit=$(git rev-list --all --grep="Merge f1 and f2 to trunk") &&
+ not_reachable=$(git rev-list -1 $f1_commit $f2_commit --not $merge_commit) &&
[ -z "$not_reachable" ]
'
test_expect_failure 'everything got merged in the end' '
- unmerged=$(git rev-list --all --not master)
+ unmerged=$(git rev-list --all --not master) &&
[ -z "$unmerged" ]
'
'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
test_expect_success \
'C: validate reuse existing blob' \
- 'test $newf = `git rev-parse --verify branch:file2/newf`
+ 'test $newf = `git rev-parse --verify branch:file2/newf` &&
test $oldf = `git rev-parse --verify branch:file2/oldf`'
cat >expect <<EOF
test_tick &&
git tag rein &&
git checkout -b wer HEAD^ &&
- echo lange > file2
+ echo lange > file2 &&
test_tick &&
git commit -m sitzt file2 &&
test_tick &&
# as argument to co -d
test_expect_success 'basic checkout' \
'GIT_CONFIG="$git_config" cvs -Q co -d cvswork master &&
- test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | head -n 1))" = "empty/1.1/"
+ test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | head -n 1))" = "empty/1.1/" &&
test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5 | sed -ne \$p))" = "secondrootfile/1.1/"'
#------------------------
mkdir subdir &&
echo "Another text file" > subdir/file.h &&
echo "Another binary: Q (this time CR)" | q_to_cr > subdir/withCr.bin &&
- echo "Mixed up NUL, but marked text: Q <- there" | q_to_nul > mixedUp.c
+ echo "Mixed up NUL, but marked text: Q <- there" | q_to_nul > mixedUp.c &&
echo "Unspecified" > subdir/unspecified.other &&
echo "/*.bin -crlf" > .gitattributes &&
echo "/*.c crlf" >> .gitattributes &&
}
test_decode_color () {
- sed -e 's/.\[1m/<WHITE>/g' \
- -e 's/.\[31m/<RED>/g' \
- -e 's/.\[32m/<GREEN>/g' \
- -e 's/.\[33m/<YELLOW>/g' \
- -e 's/.\[34m/<BLUE>/g' \
- -e 's/.\[35m/<MAGENTA>/g' \
- -e 's/.\[36m/<CYAN>/g' \
- -e 's/.\[m/<RESET>/g'
+ awk '
+ function name(n) {
+ if (n == 0) return "RESET";
+ if (n == 1) return "BOLD";
+ if (n == 30) return "BLACK";
+ if (n == 31) return "RED";
+ if (n == 32) return "GREEN";
+ if (n == 33) return "YELLOW";
+ if (n == 34) return "BLUE";
+ if (n == 35) return "MAGENTA";
+ if (n == 36) return "CYAN";
+ if (n == 37) return "WHITE";
+ if (n == 40) return "BLACK";
+ if (n == 41) return "BRED";
+ if (n == 42) return "BGREEN";
+ if (n == 43) return "BYELLOW";
+ if (n == 44) return "BBLUE";
+ if (n == 45) return "BMAGENTA";
+ if (n == 46) return "BCYAN";
+ if (n == 47) return "BWHITE";
+ }
+ {
+ while (match($0, /\x1b\[[0-9;]*m/) != 0) {
+ printf "%s<", substr($0, 1, RSTART-1);
+ codes = substr($0, RSTART+2, RLENGTH-3);
+ if (length(codes) == 0)
+ printf "%s", name(0)
+ else {
+ n = split(codes, ary, ";");
+ sep = "";
+ for (i = 1; i <= n; i++) {
+ printf "%s%s", sep, name(ary[i]);
+ sep = ";"
+ }
+ }
+ printf ">";
+ $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1);
+ }
+ print
+ }
+ '
+}
+
+nul_to_q () {
+ perl -pe 'y/\000/Q/'
}
q_to_nul () {
tr '\015' Q | sed -e 's/Q$//'
}
+# In some bourne shell implementations, the "unset" builtin returns
+# nonzero status when a variable to be unset was not set in the first
+# place.
+#
+# Use sane_unset when that should not be considered an error.
+
+sane_unset () {
+ unset "$@"
+ return 0
+}
+
test_tick () {
if test -z "${test_tick+set}"
then
test $total_prereq = $ok_prereq
}
+test_declared_prereq () {
+ case ",$test_prereq," in
+ *,$1,*)
+ return 0
+ ;;
+ esac
+ return 1
+}
+
# You are not expected to call test_ok_ and test_failure_ directly, use
# the text_expect_* functions instead.
break
esac
done
- if test -z "$to_skip" && test -n "$prereq" &&
- ! test_have_prereq "$prereq"
+ if test -z "$to_skip" && test -n "$test_prereq" &&
+ ! test_have_prereq "$test_prereq"
then
to_skip=t
fi
case "$to_skip" in
t)
of_prereq=
- if test "$missing_prereq" != "$prereq"
+ if test "$missing_prereq" != "$test_prereq"
then
- of_prereq=" of $prereq"
+ of_prereq=" of $test_prereq"
fi
say_color skip >&3 "skipping test: $@"
}
test_expect_failure () {
- test "$#" = 3 && { prereq=$1; shift; } || prereq=
+ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 ||
error "bug in the test script: not 2 or 3 parameters to test-expect-failure"
+ export test_prereq
if ! test_skip "$@"
then
say >&3 "checking known breakage: $2"
}
test_expect_success () {
- test "$#" = 3 && { prereq=$1; shift; } || prereq=
+ test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 ||
error "bug in the test script: not 2 or 3 parameters to test-expect-success"
+ export test_prereq
if ! test_skip "$@"
then
say >&3 "expecting success: $2"
echo >&3 ""
}
-test_expect_code () {
- test "$#" = 4 && { prereq=$1; shift; } || prereq=
- test "$#" = 3 ||
- error "bug in the test script: not 3 or 4 parameters to test-expect-code"
- if ! test_skip "$@"
- then
- say >&3 "expecting exit code $1: $3"
- test_run_ "$3"
- if [ "$?" = 0 -a "$eval_ret" = "$1" ]
- then
- test_ok_ "$2"
- else
- test_failure_ "$@"
- fi
- fi
- echo >&3 ""
-}
-
# test_external runs external test scripts that provide continuous
# test output about their progress, and succeeds/fails on
# zero/non-zero exit code. It outputs the test output on stdout even
# Usage: test_external description command arguments...
# Example: test_external 'Perl API' perl ../path/to/test.pl
test_external () {
- test "$#" = 4 && { prereq=$1; shift; } || prereq=
+ test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 3 ||
error >&5 "bug in the test script: not 3 or 4 parameters to test_external"
descr="$1"
shift
+ export test_prereq
if ! test_skip "$descr" "$@"
then
# Announce the script to reduce confusion about the
fi
}
+# test_line_count checks that a file has the number of lines it
+# ought to. For example:
+#
+# test_expect_success 'produce exactly one line of output' '
+# do something >output &&
+# test_line_count = 1 output
+# '
+#
+# is like "test $(wc -l <output) = 1" except that it passes the
+# output through when the number of lines is wrong.
+
+test_line_count () {
+ if test $# != 3
+ then
+ error "bug in the test script: not 3 parameters to test_line_count"
+ elif ! test $(wc -l <"$3") "$1" "$2"
+ then
+ echo "test_line_count: line count for $3 !$1 $2"
+ cat "$3"
+ return 1
+ fi
+}
# This is not among top-level (test_expect_success | test_expect_failure)
# but is a prefix that can be used in the test script, like:
return 0
}
+# Similar to test_must_fail and test_might_fail, but check that a
+# given command exited with a given exit code. Meant to be used as:
+#
+# test_expect_success 'Merge with d/f conflicts' '
+# test_expect_code 1 git merge "merge msg" B master
+# '
+
+test_expect_code () {
+ want_code=$1
+ shift
+ "$@"
+ exit_code=$?
+ if test $exit_code = $want_code
+ then
+ echo >&2 "test_expect_code: command exited with $exit_code: $*"
+ return 0
+ else
+ echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*"
+ return 1
+ fi
+}
+
# test_cmp is a helper function to compare actual and expected output.
# You can use it like:
#
use IO::Pty;
use File::Copy;
-# Run @$argv in the background with stdout redirected to $out.
+# Run @$argv in the background with stdio redirected to $out and $err.
sub start_child {
- my ($argv, $out) = @_;
+ my ($argv, $out, $err) = @_;
my $pid = fork;
if (not defined $pid) {
die "fork failed: $!"
} elsif ($pid == 0) {
open STDOUT, ">&", $out;
+ open STDERR, ">&", $err;
close $out;
exec(@$argv) or die "cannot exec '$argv->[0]': $!"
}
copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!";
}
+sub copy_stdio {
+ my ($out, $err) = @_;
+ my $pid = fork;
+ defined $pid or die "fork failed: $!";
+ if (!$pid) {
+ close($out);
+ xsendfile(\*STDERR, $err);
+ exit 0;
+ }
+ close($err);
+ xsendfile(\*STDOUT, $out);
+ finish_child($pid) == 0
+ or exit 1;
+}
+
if ($#ARGV < 1) {
die "usage: test-terminal program args";
}
-my $master = new IO::Pty;
-my $slave = $master->slave;
-my $pid = start_child(\@ARGV, $slave);
-close $slave;
-xsendfile(\*STDOUT, $master);
+my $master_out = new IO::Pty;
+my $master_err = new IO::Pty;
+my $pid = start_child(\@ARGV, $master_out->slave, $master_err->slave);
+close $master_out->slave;
+close $master_err->slave;
+copy_stdio($master_out, $master_err);
exit(finish_child($pid));
args.use_thin_pack = data->options.thin;
args.verbose = (transport->verbose > 0);
args.quiet = (transport->verbose < 0);
+ args.progress = transport->progress;
args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN);
}
}
+ if (trailing_whitespace == -1)
+ trailing_whitespace = len;
+
/* Check indentation */
- for (i = 0; i < len; i++) {
+ for (i = 0; i < trailing_whitespace; i++) {
if (line[i] == ' ')
continue;
if (line[i] != '\t')
* Now the rest of the line starts at "written".
* The non-highlighted part ends at "trailing_whitespace".
*/
- if (trailing_whitespace == -1)
- trailing_whitespace = len;
/* Emit non-highlighted (middle) segment. */
if (trailing_whitespace - written > 0) {
return -1;
}
-static void xdl_find_func(xdfile_t *xf, long i, char *buf, long sz, long *ll,
- find_func_t ff, void *ff_priv) {
-
- /*
- * Be quite stupid about this for now. Find a line in the old file
- * before the start of the hunk (and context) which starts with a
- * plausible character.
- */
-
- const char *rec;
- long len;
-
- while (i-- > 0) {
- len = xdl_get_rec(xf, i, &rec);
- if ((*ll = ff(rec, len, buf, sz, ff_priv)) >= 0)
- return;
- }
- *ll = 0;
-}
-
-
static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
xdemitconf_t const *xecfg) {
xdfile_t *xdf = &xe->xdf1;
xdchange_t *xch, *xche;
char funcbuf[80];
long funclen = 0;
+ long funclineprev = -1;
find_func_t ff = xecfg->find_func ? xecfg->find_func : def_ff;
if (xecfg->flags & XDL_EMIT_COMMON)
*/
if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
- xdl_find_func(&xe->xdf1, s1, funcbuf,
- sizeof(funcbuf), &funclen,
- ff, xecfg->find_func_priv);
+ long l;
+ for (l = s1 - 1; l >= 0 && l > funclineprev; l--) {
+ const char *rec;
+ long reclen = xdl_get_rec(&xe->xdf1, l, &rec);
+ long newfunclen = ff(rec, reclen, funcbuf,
+ sizeof(funcbuf),
+ xecfg->find_func_priv);
+ if (newfunclen >= 0) {
+ funclen = newfunclen;
+ break;
+ }
+ }
+ funclineprev = s1 - 1;
}
if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
funcbuf, funclen, ecb) < 0)