diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Documentation/Makefile | 21 | ||||
-rw-r--r-- | Documentation/asciidoc.conf | 19 | ||||
-rw-r--r-- | Documentation/git-fsck.txt | 8 | ||||
-rw-r--r-- | Documentation/git-rev-list.txt | 13 | ||||
-rw-r--r-- | Makefile | 82 | ||||
-rw-r--r-- | builtin-add.c | 4 | ||||
-rw-r--r-- | builtin-apply.c | 12 | ||||
-rw-r--r-- | builtin-fsck.c | 17 | ||||
-rw-r--r-- | builtin-ls-files.c | 2 | ||||
-rw-r--r-- | builtin-mv.c | 2 | ||||
-rw-r--r-- | builtin-pack-objects.c | 2 | ||||
-rw-r--r-- | builtin-rev-list.c | 309 | ||||
-rw-r--r-- | builtin-update-index.c | 4 | ||||
-rw-r--r-- | cache.h | 5 | ||||
-rw-r--r-- | config.mak.in | 1 | ||||
-rw-r--r-- | configure.ac | 24 | ||||
-rw-r--r-- | contrib/emacs/git-blame.el | 138 | ||||
-rw-r--r-- | diff.c | 13 | ||||
-rw-r--r-- | dir.c | 96 | ||||
-rw-r--r-- | dir.h | 2 | ||||
-rwxr-xr-x | git-lost-found.sh | 2 | ||||
-rwxr-xr-x | git-svn.perl | 5 | ||||
-rw-r--r-- | git.spec.in | 36 | ||||
-rwxr-xr-x | gitweb/gitweb.perl | 64 | ||||
-rw-r--r-- | merge-recursive.c | 2 | ||||
-rw-r--r-- | pack-check.c | 11 | ||||
-rw-r--r-- | read-cache.c | 21 | ||||
-rw-r--r-- | sha1_file.c | 9 | ||||
-rw-r--r-- | sha1_name.c | 16 | ||||
-rwxr-xr-x | t/t6002-rev-list-bisect.sh | 2 | ||||
-rwxr-xr-x | t/t6004-rev-list-path-optim.sh | 34 | ||||
-rw-r--r-- | wt-status.c | 2 |
33 files changed, 805 insertions, 175 deletions
diff --git a/.gitignore b/.gitignore index e8d2731ee5..b39f78fcdf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ GIT-CFLAGS +GIT-GUI-VARS GIT-VERSION-FILE git git-add @@ -141,6 +142,7 @@ git-verify-tag git-whatchanged git-write-tree git-core-*/?* +gitk-wish gitweb/gitweb.cgi test-chmtime test-date diff --git a/Documentation/Makefile b/Documentation/Makefile index ad87736b0c..a637d8d559 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -65,6 +65,11 @@ install: man $(INSTALL) -m644 $(DOC_MAN7) $(DESTDIR)$(man7dir) +../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE + $(MAKE) -C ../ GIT-VERSION-FILE + +-include ../GIT-VERSION-FILE + # # Determine "include::" file references in asciidoc files. # @@ -94,17 +99,25 @@ cmd-list.made: cmd-list.perl $(MAN1_TXT) git.7 git.html: git.txt core-intro.txt clean: - rm -f *.xml *.html *.1 *.7 howto-index.txt howto/*.html doc.dep + rm -f *.xml *.xml+ *.html *.html+ *.1 *.7 howto-index.txt howto/*.html doc.dep rm -f $(cmds_txt) *.made %.html : %.txt - $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf $(ASCIIDOC_EXTRA) $< + rm -f $@+ $@ + $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \ + $(ASCIIDOC_EXTRA) -o - $< | \ + sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' >$@+ + mv $@+ $@ %.1 %.7 : %.xml xmlto -m callouts.xsl man $< %.xml : %.txt - $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf $< + rm -f $@+ $@ + $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ + $(ASCIIDOC_EXTRA) -o - $< | \ + sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' >$@+ + mv $@+ $@ user-manual.xml: user-manual.txt user-manual.conf $(ASCIIDOC) -b docbook -d book $< @@ -135,3 +148,5 @@ install-webdoc : html quick-install: sh ./install-doc-quick.sh $(DOC_REF) $(mandir) + +.PHONY: .FORCE-GIT-VERSION-FILE diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index 44b1ce4c6b..fa7dc94845 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -31,6 +31,25 @@ ifdef::backend-docbook[] {title#}</example> endif::backend-docbook[] +ifdef::doctype-manpage[] +ifdef::backend-docbook[] +[header] +template::[header-declarations] +<refentry> +<refmeta> +<refentrytitle>{mantitle}</refentrytitle> +<manvolnum>{manvolnum}</manvolnum> +<refmiscinfo class="source">Git</refmiscinfo> +<refmiscinfo class="version">@@GIT_VERSION@@</refmiscinfo> +<refmiscinfo class="manual">Git Manual</refmiscinfo> +</refmeta> +<refnamediv> + <refname>{manname}</refname> + <refpurpose>{manpurpose}</refpurpose> +</refnamediv> +endif::backend-docbook[] +endif::doctype-manpage[] + ifdef::backend-xhtml11[] [gitlink-inlinemacro] <a href="{target}.html">{target}{0?({0})}</a> diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt index 058009d2fa..8c68cf0372 100644 --- a/Documentation/git-fsck.txt +++ b/Documentation/git-fsck.txt @@ -9,7 +9,7 @@ git-fsck - Verifies the connectivity and validity of the objects in the database SYNOPSIS -------- [verse] -'git-fsck' [--tags] [--root] [--unreachable] [--cache] +'git-fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs] [--full] [--strict] [<object>*] DESCRIPTION @@ -38,6 +38,12 @@ index file and all SHA1 references in .git/refs/* as heads. Consider any object recorded in the index also as a head node for an unreachability trace. +--no-reflogs:: + Do not consider commits that are referenced only by an + entry in a reflog to be reachable. This option is meant + only to search for commits that used to be in a ref, but + now aren't, but are still in that corresponding reflog. + --full:: Check not just objects in GIT_OBJECT_DIRECTORY ($GIT_DIR/objects), but also the ones found in alternate diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt index 11ce395c98..12b71ed0bb 100644 --- a/Documentation/git-rev-list.txt +++ b/Documentation/git-rev-list.txt @@ -27,6 +27,7 @@ SYNOPSIS [ [\--objects | \--objects-edge] [ \--unpacked ] ] [ \--pretty | \--header ] [ \--bisect ] + [ \--bisect-vars ] [ \--merge ] [ \--reverse ] [ \--walk-reflogs ] @@ -280,6 +281,18 @@ introduces a regression is thus reduced to a binary search: repeatedly generate and test new 'midpoint's until the commit chain is of length one. +--bisect-vars:: + +This calculates the same as `--bisect`, but outputs text ready +to be eval'ed by the shell. These lines will assign the name of +the midpoint revision to the variable `bisect_rev`, and the +expected number of commits to be tested after `bisect_rev` is +tested to `bisect_nr`, the expected number of commits to be +tested if `bisect_rev` turns out to be good to `bisect_good`, +the expected number of commits to be tested if `bisect_rev` +turns out to be bad to `bisect_bad`, and the number of commits +we are bisecting right now to `bisect_all`. + -- Commit Ordering @@ -110,6 +110,14 @@ all:: # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's # MakeMaker (e.g. using ActiveState under Cygwin). # +# Define WITH_P4IMPORT to build and install Python git-p4import script. +# +# Define NO_TCLTK if you do not want Tcl/Tk GUI. +# +# The TCLTK_PATH variable governs the location of the Tck/Tk interpreter. +# If not set it defaults to the bare 'wish'. If it is set to the empty +# string then NO_TCLTK will be forced (this is used by configure script). +# GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -159,6 +167,7 @@ AR = ar TAR = tar INSTALL = install RPMBUILD = rpmbuild +TCLTK_PATH = wish # sparse is architecture-neutral, which means that we need to tell it # explicitly what architecture to check for. Fix this up for yours.. @@ -196,9 +205,20 @@ SCRIPT_PERL = \ git-svnimport.perl git-cvsexportcommit.perl \ git-send-email.perl git-svn.perl +SCRIPT_PYTHON = \ + git-p4import.py + +ifdef WITH_P4IMPORT +SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ + $(patsubst %.perl,%,$(SCRIPT_PERL)) \ + $(patsubst %.py,%,$(SCRIPT_PYTHON)) \ + git-status git-instaweb +else SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ $(patsubst %.perl,%,$(SCRIPT_PERL)) \ git-status git-instaweb +endif + # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS = \ @@ -231,6 +251,12 @@ BUILT_INS = \ # what 'all' will build and 'install' will install, in gitexecdir ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) +# what 'all' will build but not install in gitexecdir +OTHER_PROGRAMS = git$X gitweb/gitweb.cgi +ifndef NO_TCLTK +OTHER_PROGRAMS += gitk-wish +endif + # Backward compatibility -- to be removed after 1.0 PROGRAMS += git-ssh-pull$X git-ssh-push$X @@ -241,6 +267,9 @@ endif ifndef PERL_PATH PERL_PATH = /usr/bin/perl endif +ifndef PYTHON_PATH + PYTHON_PATH = /usr/local/bin/python +endif export PERL_PATH @@ -609,6 +638,10 @@ ifdef NO_PERL_MAKEMAKER export NO_PERL_MAKEMAKER endif +ifeq ($(TCLTK_PATH),) +NO_TCLTK=NoThanks +endif + QUIET_SUBDIR0 = $(MAKE) -C # space to separate -C and subdir QUIET_SUBDIR1 = @@ -647,6 +680,8 @@ prefix_SQ = $(subst ','\'',$(prefix)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) +PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH)) +TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) LIBS = $(GITLIBS) $(EXTLIBS) @@ -662,19 +697,27 @@ export prefix gitexecdir TAR INSTALL DESTDIR SHELL_PATH template_dir ### Build rules -all:: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi +all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) ifneq (,$X) $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$p';) endif all:: - $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all +ifndef NO_TCLTK + $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) TCLTK_PATH='$(TCLTK_PATH_SQ)' all +endif $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X +gitk-wish: gitk GIT-GUI-VARS + $(QUIET_GEN)rm -f $@ $@+ && \ + sed -e '1,3s|^exec .* "$$0"|exec $(subst |,'\|',$(TCLTK_PATH_SQ)) "$$0"|' <gitk >$@+ && \ + chmod +x $@+ && \ + mv -f $@+ $@ + git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS $(QUIET_LINK)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \ $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \ @@ -700,6 +743,15 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak +$(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py + rm -f $@ $@+ + sed -e '1s|#!.*/python|#!$(PYTHON_PATH_SQ)|' \ + -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ + -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ + $@.py >$@+ + chmod +x $@+ + mv $@+ $@ + perl/perl.mak: GIT-CFLAGS $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F) @@ -853,6 +905,20 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS echo "$$FLAGS" >GIT-CFLAGS; \ fi +### Detect Tck/Tk interpreter path changes +ifndef NO_TCLTK +TRACK_VARS = $(subst ','\'',-DTCLTK_PATH='$(TCLTK_PATH_SQ)') + +GIT-GUI-VARS: .FORCE-GIT-GUI-VARS + @VARS='$(TRACK_VARS)'; \ + if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \ + echo 1>&2 " * new Tcl/Tk interpreter location"; \ + echo "$$VARS" >$@; \ + fi + +.PHONY: .FORCE-GIT-GUI-VARS +endif + ### Testing rules # GNU make supports exporting all variables by "export" without parameters. @@ -893,10 +959,13 @@ install: all $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' - $(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' install +ifndef NO_TCLTK + $(INSTALL) gitk-wish '$(DESTDIR_SQ)$(bindir_SQ)'/gitk $(MAKE) -C git-gui install +endif if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \ then \ ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \ @@ -975,10 +1044,13 @@ clean: rm -f gitweb/gitweb.cgi $(MAKE) -C Documentation/ clean $(MAKE) -C perl clean - $(MAKE) -C git-gui clean $(MAKE) -C templates/ clean $(MAKE) -C t/ clean - rm -f GIT-VERSION-FILE GIT-CFLAGS +ifndef NO_TCLTK + rm -f gitk-wish + $(MAKE) -C git-gui clean +endif + rm -f GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS .PHONY: all install clean strip .PHONY: .FORCE-GIT-VERSION-FILE TAGS tags .FORCE-GIT-CFLAGS diff --git a/builtin-add.c b/builtin-add.c index 9fcf514dbc..7d1d5dc244 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -87,7 +87,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec) } /* Read the directory and prune it */ - read_directory(dir, path, base, baselen); + read_directory(dir, path, base, baselen, pathspec); if (pathspec) prune_directory(dir, pathspec, baselen); } @@ -205,7 +205,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) } for (i = 0; i < dir.nr; i++) - add_file_to_index(dir.entries[i]->name, verbose); + add_file_to_cache(dir.entries[i]->name, verbose); if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || diff --git a/builtin-apply.c b/builtin-apply.c index a5d612655f..4b8311b4de 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -30,7 +30,7 @@ static int unidiff_zero; static int p_value = 1; static int p_value_known; static int check_index; -static int write_index; +static int update_index; static int cached; static int diffstat; static int numstat; @@ -2308,7 +2308,7 @@ static void patch_stats(struct patch *patch) static void remove_file(struct patch *patch, int rmdir_empty) { - if (write_index) { + if (update_index) { if (remove_file_from_cache(patch->old_name) < 0) die("unable to remove %s from index", patch->old_name); cache_tree_invalidate_path(active_cache_tree, patch->old_name); @@ -2335,7 +2335,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned int namelen = strlen(path); unsigned ce_size = cache_entry_size(namelen); - if (!write_index) + if (!update_index) return; ce = xcalloc(1, ce_size); @@ -2662,8 +2662,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) if (whitespace_error && (new_whitespace == error_on_whitespace)) apply = 0; - write_index = check_index && apply; - if (write_index && newfd < 0) + update_index = check_index && apply; + if (update_index && newfd < 0) newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1); if (check_index) { @@ -2870,7 +2870,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) whitespace_error == 1 ? "s" : ""); } - if (write_index) { + if (update_index) { if (write_cache(newfd, active_cache, active_nr) || close(newfd) || commit_lock_file(&lock_file)) die("Unable to write new index file"); diff --git a/builtin-fsck.c b/builtin-fsck.c index 21f1f9e91d..4d8b66c344 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -14,6 +14,7 @@ static int show_root; static int show_tags; static int show_unreachable; +static int include_reflogs = 1; static int check_full; static int check_strict; static int keep_cache_objects; @@ -348,7 +349,7 @@ static int fsck_tag(struct tag *tag) return 0; } -static int fsck_sha1(unsigned char *sha1) +static int fsck_sha1(const unsigned char *sha1) { struct object *obj = parse_object(sha1); if (!obj) { @@ -517,7 +518,8 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f static void get_default_heads(void) { for_each_ref(fsck_handle_ref, NULL); - for_each_reflog(fsck_handle_reflog, NULL); + if (include_reflogs) + for_each_reflog(fsck_handle_reflog, NULL); /* * Not having any default heads isn't really fatal, but @@ -616,6 +618,10 @@ int cmd_fsck(int argc, char **argv, const char *prefix) keep_cache_objects = 1; continue; } + if (!strcmp(arg, "--no-reflogs")) { + include_reflogs = 0; + continue; + } if (!strcmp(arg, "--full")) { check_full = 1; continue; @@ -648,11 +654,8 @@ int cmd_fsck(int argc, char **argv, const char *prefix) for (p = packed_git; p; p = p->next) { uint32_t i, num = num_packed_objects(p); - for (i = 0; i < num; i++) { - unsigned char sha1[20]; - nth_packed_object_sha1(p, i, sha1); - fsck_sha1(sha1); - } + for (i = 0; i < num; i++) + fsck_sha1(nth_packed_object_sha1(p, i)); } } diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 4e1d5af634..74a6acacc1 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -216,7 +216,7 @@ static void show_files(struct dir_struct *dir, const char *prefix) if (baselen) path = base = prefix; - read_directory(dir, path, base, baselen); + read_directory(dir, path, base, baselen, pathspec); if (show_others) show_other_files(dir); if (show_killed) diff --git a/builtin-mv.c b/builtin-mv.c index 737af350b8..c4ab4784ce 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -273,7 +273,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) for (i = 0; i < added.nr; i++) { const char *path = added.items[i].path; - add_file_to_index(path, verbose); + add_file_to_cache(path, verbose); } for (i = 0; i < deleted.nr; i++) { diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index b5f9648e80..45ac3e482a 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -222,7 +222,7 @@ static const unsigned char *find_packed_object_name(struct packed_git *p, off_t ofs) { struct revindex_entry *entry = find_packed_object(p, ofs); - return ((unsigned char *)p->index_data) + 4 * 256 + 24 * entry->nr + 4; + return nth_packed_object_sha1(p, entry->nr); } static void *delta_against(void *buf, unsigned long size, struct object_entry *entry) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index b86e7ca8b1..09774f9559 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -37,7 +37,8 @@ static const char rev_list_usage[] = " --abbrev-commit\n" " --left-right\n" " special purpose:\n" -" --bisect" +" --bisect\n" +" --bisect-vars" ; static struct rev_info revs; @@ -169,38 +170,273 @@ static void clear_distance(struct commit_list *list) } } -static struct commit_list *find_bisection(struct commit_list *list) +#define DEBUG_BISECT 0 + +static inline int weight(struct commit_list *elem) { - int nr, closest; - struct commit_list *p, *best; + return *((int*)(elem->item->util)); +} - nr = 0; - p = list; - while (p) { - if (!revs.prune_fn || (p->item->object.flags & TREECHANGE)) - nr++; - p = p->next; +static inline void weight_set(struct commit_list *elem, int weight) +{ + *((int*)(elem->item->util)) = weight; +} + +static int count_interesting_parents(struct commit *commit) +{ + struct commit_list *p; + int count; + + for (count = 0, p = commit->parents; p; p = p->next) { + if (p->item->object.flags & UNINTERESTING) + continue; + count++; } - closest = -1; - best = list; + return count; +} + +static inline int halfway(struct commit_list *p, int distance, int nr) +{ + /* + * Don't short-cut something we are not going to return! + */ + if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) + return 0; + if (DEBUG_BISECT) + return 0; + /* + * 2 and 3 are halfway of 5. + * 3 is halfway of 6 but 2 and 4 are not. + */ + distance *= 2; + switch (distance - nr) { + case -1: case 0: case 1: + return 1; + default: + return 0; + } +} + +#if !DEBUG_BISECT +#define show_list(a,b,c,d) do { ; } while (0) +#else +static void show_list(const char *debug, int counted, int nr, + struct commit_list *list) +{ + struct commit_list *p; + + fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr); for (p = list; p; p = p->next) { - int distance; + struct commit_list *pp; + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + enum object_type type; + unsigned long size; + char *buf = read_sha1_file(commit->object.sha1, &type, &size); + char *ep, *sp; + + fprintf(stderr, "%c%c%c ", + (flags & TREECHANGE) ? 'T' : ' ', + (flags & UNINTERESTING) ? 'U' : ' ', + (flags & COUNTED) ? 'C' : ' '); + if (commit->util) + fprintf(stderr, "%3d", weight(p)); + else + fprintf(stderr, "---"); + fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1)); + for (pp = commit->parents; pp; pp = pp->next) + fprintf(stderr, " %.*s", 8, + sha1_to_hex(pp->item->object.sha1)); + + sp = strstr(buf, "\n\n"); + if (sp) { + sp += 2; + for (ep = sp; *ep && *ep != '\n'; ep++) + ; + fprintf(stderr, " %.*s", (int)(ep - sp), sp); + } + fprintf(stderr, "\n"); + } +} +#endif /* DEBUG_BISECT */ + +/* + * zero or positive weight is the number of interesting commits it can + * reach, including itself. Especially, weight = 0 means it does not + * reach any tree-changing commits (e.g. just above uninteresting one + * but traversal is with pathspec). + * + * weight = -1 means it has one parent and its distance is yet to + * be computed. + * + * weight = -2 means it has more than one parent and its distance is + * unknown. After running count_distance() first, they will get zero + * or positive distance. + */ + +static struct commit_list *find_bisection(struct commit_list *list, + int *reaches, int *all) +{ + int n, nr, on_list, counted, distance; + struct commit_list *p, *best, *next, *last; + int *weights; + + show_list("bisection 2 entry", 0, 0, list); - if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) + /* + * Count the number of total and tree-changing items on the + * list, while reversing the list. + */ + for (nr = on_list = 0, last = NULL, p = list; + p; + p = next) { + unsigned flags = p->item->object.flags; + + next = p->next; + if (flags & UNINTERESTING) continue; + p->next = last; + last = p; + if (!revs.prune_fn || (flags & TREECHANGE)) + nr++; + on_list++; + } + list = last; + show_list("bisection 2 sorted", 0, nr, list); + + *all = nr; + weights = xcalloc(on_list, sizeof(int*)); + counted = 0; + + for (n = 0, p = list; p; p = p->next) { + struct commit *commit = p->item; + unsigned flags = commit->object.flags; + + p->item->util = &weights[n++]; + switch (count_interesting_parents(commit)) { + case 0: + if (!revs.prune_fn || (flags & TREECHANGE)) { + weight_set(p, 1); + counted++; + show_list("bisection 2 count one", + counted, nr, list); + } + /* + * otherwise, it is known not to reach any + * tree-changing commit and gets weight 0. + */ + break; + case 1: + weight_set(p, -1); + break; + default: + weight_set(p, -2); + break; + } + } + show_list("bisection 2 initialize", counted, nr, list); + + /* + * If you have only one parent in the resulting set + * then you can reach one commit more than that parent + * can reach. So we do not have to run the expensive + * count_distance() for single strand of pearls. + * + * However, if you have more than one parents, you cannot + * just add their distance and one for yourself, since + * they usually reach the same ancestor and you would + * end up counting them twice that way. + * + * So we will first count distance of merges the usual + * way, and then fill the blanks using cheaper algorithm. + */ + for (p = list; p; p = p->next) { + if (p->item->object.flags & UNINTERESTING) + continue; + n = weight(p); + if (n != -2) + continue; distance = count_distance(p); clear_distance(list); + weight_set(p, distance); + + /* Does it happen to be at exactly half-way? */ + if (halfway(p, distance, nr)) { + p->next = NULL; + *reaches = distance; + free(weights); + return p; + } + counted++; + } + + show_list("bisection 2 count_distance", counted, nr, list); + + while (counted < nr) { + for (p = list; p; p = p->next) { + struct commit_list *q; + unsigned flags = p->item->object.flags; + + if (0 <= weight(p)) + continue; + for (q = p->item->parents; q; q = q->next) { + if (q->item->object.flags & UNINTERESTING) + continue; + if (0 <= weight(q)) + break; + } + if (!q) + continue; + + /* + * weight for p is unknown but q is known. + * add one for p itself if p is to be counted, + * otherwise inherit it from q directly. + */ + if (!revs.prune_fn || (flags & TREECHANGE)) { + weight_set(p, weight(q)+1); + counted++; + show_list("bisection 2 count one", + counted, nr, list); + } + else + weight_set(p, weight(q)); + + /* Does it happen to be at exactly half-way? */ + distance = weight(p); + if (halfway(p, distance, nr)) { + p->next = NULL; + *reaches = distance; + free(weights); + return p; + } + } + } + + show_list("bisection 2 counted all", counted, nr, list); + + /* Then find the best one */ + counted = -1; + best = list; + for (p = list; p; p = p->next) { + unsigned flags = p->item->object.flags; + + if (revs.prune_fn && !(flags & TREECHANGE)) + continue; + distance = weight(p); if (nr - distance < distance) distance = nr - distance; - if (distance > closest) { + if (distance > counted) { best = p; - closest = distance; + counted = distance; + *reaches = weight(p); } } if (best) best->next = NULL; + free(weights); return best; } @@ -226,6 +462,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) struct commit_list *list; int i; int read_from_stdin = 0; + int bisect_show_vars = 0; git_config(git_default_config); init_revisions(&revs, prefix); @@ -248,6 +485,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) bisect_list = 1; continue; } + if (!strcmp(arg, "--bisect-vars")) { + bisect_list = 1; + bisect_show_vars = 1; + continue; + } if (!strcmp(arg, "--stdin")) { if (read_from_stdin++) die("--stdin given twice?"); @@ -286,8 +528,39 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (revs.tree_objects) mark_edges_uninteresting(revs.commits, &revs, show_edge); - if (bisect_list) - revs.commits = find_bisection(revs.commits); + if (bisect_list) { + int reaches = reaches, all = all; + + revs.commits = find_bisection(revs.commits, &reaches, &all); + if (bisect_show_vars) { + int cnt; + if (!revs.commits) + return 1; + /* + * revs.commits can reach "reaches" commits among + * "all" commits. If it is good, then there are + * (all-reaches) commits left to be bisected. + * On the other hand, if it is bad, then the set + * to bisect is "reaches". + * A bisect set of size N has (N-1) commits further + * to test, as we already know one bad one. + */ + cnt = all-reaches; + if (cnt < reaches) + cnt = reaches; + printf("bisect_rev=%s\n" + "bisect_nr=%d\n" + "bisect_good=%d\n" + "bisect_bad=%d\n" + "bisect_all=%d\n", + sha1_to_hex(revs.commits->item->object.sha1), + cnt - 1, + all - reaches - 1, + reaches - 1, + all); + return 0; + } + } traverse_commit_list(&revs, show_commit, show_object); diff --git a/builtin-update-index.c b/builtin-update-index.c index 71cef633c0..d1e5cf7539 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -60,7 +60,7 @@ static int mark_valid(const char *path) return -1; } -static int add_file_to_cache(const char *path) +static int process_file(const char *path) { int size, namelen, option, status; struct cache_entry *ce; @@ -210,7 +210,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length) report("remove '%s'", path); goto free_return; } - if (add_file_to_cache(p)) + if (process_file(p)) die("Unable to process file %s", path); report("add '%s'", path); free_return: @@ -128,7 +128,6 @@ static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned in extern struct cache_entry **active_cache; extern unsigned int active_nr, active_alloc, active_cache_changed; extern struct cache_tree *active_cache_tree; -extern int cache_errno; enum object_type { OBJ_BAD = -1, @@ -188,7 +187,7 @@ extern int add_cache_entry(struct cache_entry *ce, int option); extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); extern int remove_cache_entry_at(int pos); extern int remove_file_from_cache(const char *path); -extern int add_file_to_index(const char *path, int verbose); +extern int add_file_to_cache(const char *path, int verbose); extern int ce_same_name(struct cache_entry *a, struct cache_entry *b); extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int); extern int ce_modified(struct cache_entry *ce, struct stat *st, int); @@ -428,7 +427,7 @@ extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t extern void unuse_pack(struct pack_window **); extern struct packed_git *add_packed_git(const char *, int, int); extern uint32_t num_packed_objects(const struct packed_git *p); -extern int nth_packed_object_sha1(const struct packed_git *, uint32_t, unsigned char*); +extern const unsigned char *nth_packed_object_sha1(const struct packed_git *, uint32_t); extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *); extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *); extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); diff --git a/config.mak.in b/config.mak.in index 9a578405d8..eb9d7a5549 100644 --- a/config.mak.in +++ b/config.mak.in @@ -6,6 +6,7 @@ CFLAGS = @CFLAGS@ AR = @AR@ TAR = @TAR@ #INSTALL = @INSTALL@ # needs install-sh or install.sh in sources +TCLTK_PATH = @TCLTK_PATH@ prefix = @prefix@ exec_prefix = @exec_prefix@ diff --git a/configure.ac b/configure.ac index 3a8e778def..50d2b85ace 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,14 @@ GIT_ARG_SET_PATH(shell) # Define PERL_PATH to provide path to Perl. GIT_ARG_SET_PATH(perl) # +# Declare the with-tcltk/without-tcltk options. +AC_ARG_WITH(tcltk, +AS_HELP_STRING([--with-tcltk],[use Tcl/Tk GUI (default is YES)]) +AS_HELP_STRING([],[ARG is the full path to the Tcl/Tk interpreter.]) +AS_HELP_STRING([],[Bare --with-tcltk will make the GUI part only if]) +AS_HELP_STRING([],[Tcl/Tk interpreter will be found in a system.]),\ +GIT_PARSE_WITH(tcltk)) +# ## Checks for programs. @@ -84,6 +92,22 @@ AC_PROG_CC([cc gcc]) #AC_PROG_INSTALL # needs install-sh or install.sh in sources AC_CHECK_TOOL(AR, ar, :) AC_CHECK_PROGS(TAR, [gtar tar]) +# TCLTK_PATH will be set to some value if we want Tcl/Tk +# or will be empty otherwise. +if test -z "$NO_TCLTK"; then + if test "$with_tcltk" = ""; then + # No Tcl/Tk switches given. Do not check for Tcl/Tk, use bare 'wish'. + TCLTK_PATH=wish + AC_SUBST(TCLTK_PATH) + elif test "$with_tcltk" = "yes"; then + # Tcl/Tk check requested. + AC_CHECK_PROGS(TCLTK_PATH, [wish], ) + else + AC_MSG_RESULT([Using Tcl/Tk interpreter $with_tcltk]) + TCLTK_PATH="$with_tcltk" + AC_SUBST(TCLTK_PATH) + fi +fi ## Checks for libraries. AC_MSG_NOTICE([CHECKS for libraries]) diff --git a/contrib/emacs/git-blame.el b/contrib/emacs/git-blame.el index 64ad50b327..bb671d561e 100644 --- a/contrib/emacs/git-blame.el +++ b/contrib/emacs/git-blame.el @@ -8,8 +8,8 @@ ;; License: GPL ;; Keywords: git, version control, release management ;; -;; Compatibility: Emacs21 - +;; Compatibility: Emacs21, Emacs22 and EmacsCVS +;; Git 1.5 and up ;; This file is *NOT* part of GNU Emacs. ;; This file is distributed under the same terms as GNU Emacs. @@ -61,8 +61,9 @@ ;;; Compatibility: ;; -;; It requires GNU Emacs 21. If you'are using Emacs 20, try -;; changing this: +;; It requires GNU Emacs 21 or later and Git 1.5.0 and up +;; +;; If you'are using Emacs 20, try changing this: ;; ;; (overlay-put ovl 'face (list :background ;; (cdr (assq 'color (cddddr info))))) @@ -77,30 +78,51 @@ ;; ;;; Code: -(require 'cl) ; to use `push', `pop' - -(defun color-scale (l) - (let* ((colors ()) - r g b) - (setq r l) - (while r - (setq g l) - (while g - (setq b l) - (while b - (push (concat "#" (car r) (car g) (car b)) colors) - (pop b)) - (pop g)) - (pop r)) - colors)) +(eval-when-compile (require 'cl)) ; to use `push', `pop' + + +(defun git-blame-color-scale (&rest elements) + "Given a list, returns a list of triples formed with each +elements of the list. + +a b => bbb bba bab baa abb aba aaa aab" + (let (result) + (dolist (a elements) + (dolist (b elements) + (dolist (c elements) + (setq result (cons (format "#%s%s%s" a b c) result))))) + result)) + +;; (git-blame-color-scale "0c" "04" "24" "1c" "2c" "34" "14" "3c") => +;; ("#3c3c3c" "#3c3c14" "#3c3c34" "#3c3c2c" "#3c3c1c" "#3c3c24" +;; "#3c3c04" "#3c3c0c" "#3c143c" "#3c1414" "#3c1434" "#3c142c" ...) + +(defmacro git-blame-random-pop (l) + "Select a random element from L and returns it. Also remove +selected element from l." + ;; only works on lists with unique elements + `(let ((e (elt ,l (random (length ,l))))) + (setq ,l (remove e ,l)) + e)) (defvar git-blame-dark-colors - (color-scale '("0c" "04" "24" "1c" "2c" "34" "14" "3c"))) + (git-blame-color-scale "0c" "04" "24" "1c" "2c" "34" "14" "3c") + "*List of colors (format #RGB) to use in a dark environment. + +To check out the list, evaluate (list-colors-display git-blame-dark-colors).") (defvar git-blame-light-colors - (color-scale '("c4" "d4" "cc" "dc" "f4" "e4" "fc" "ec"))) + (git-blame-color-scale "c4" "d4" "cc" "dc" "f4" "e4" "fc" "ec") + "*List of colors (format #RGB) to use in a light environment. + +To check out the list, evaluate (list-colors-display git-blame-light-colors).") -(defvar git-blame-ancient-color "dark green") +(defvar git-blame-colors '() + "Colors used by git-blame. The list is built once when activating git-blame +minor mode.") + +(defvar git-blame-ancient-color "dark green" + "*Color to be used for ancient commit.") (defvar git-blame-autoupdate t "*Automatically update the blame display while editing") @@ -125,41 +147,64 @@ "A queue of update requests") (make-variable-buffer-local 'git-blame-update-queue) +;; FIXME: docstrings +(defvar git-blame-file nil) +(defvar git-blame-current nil) + (defvar git-blame-mode nil) (make-variable-buffer-local 'git-blame-mode) -(unless (assq 'git-blame-mode minor-mode-alist) - (setq minor-mode-alist - (cons (list 'git-blame-mode " blame") - minor-mode-alist))) + +(defvar git-blame-mode-line-string " blame" + "String to display on the mode line when git-blame is active.") + +(or (assq 'git-blame-mode minor-mode-alist) + (setq minor-mode-alist + (cons '(git-blame-mode git-blame-mode-line-string) minor-mode-alist))) ;;;###autoload (defun git-blame-mode (&optional arg) - "Minor mode for displaying Git blame" + "Toggle minor mode for displaying Git blame + +With prefix ARG, turn the mode on if ARG is positive." (interactive "P") - (if arg - (setq git-blame-mode (eq arg 1)) - (setq git-blame-mode (not git-blame-mode))) + (cond + ((null arg) + (if git-blame-mode (git-blame-mode-off) (git-blame-mode-on))) + ((> (prefix-numeric-value arg) 0) (git-blame-mode-on)) + (t (git-blame-mode-off)))) + +(defun git-blame-mode-on () + "Turn on git-blame mode. + +See also function `git-blame-mode'." (make-local-variable 'git-blame-colors) (if git-blame-autoupdate (add-hook 'after-change-functions 'git-blame-after-change nil t) (remove-hook 'after-change-functions 'git-blame-after-change t)) (git-blame-cleanup) - (if git-blame-mode - (progn - (let ((bgmode (cdr (assoc 'background-mode (frame-parameters))))) - (if (eq bgmode 'dark) - (setq git-blame-colors git-blame-dark-colors) - (setq git-blame-colors git-blame-light-colors))) - (setq git-blame-cache (make-hash-table :test 'equal)) - (git-blame-run)) - (cancel-timer git-blame-idle-timer))) + (let ((bgmode (cdr (assoc 'background-mode (frame-parameters))))) + (if (eq bgmode 'dark) + (setq git-blame-colors git-blame-dark-colors) + (setq git-blame-colors git-blame-light-colors))) + (setq git-blame-cache (make-hash-table :test 'equal)) + (setq git-blame-mode t) + (git-blame-run)) + +(defun git-blame-mode-off () + "Turn off git-blame mode. + +See also function `git-blame-mode'." + (git-blame-cleanup) + (if git-blame-idle-timer (cancel-timer git-blame-idle-timer)) + (setq git-blame-mode nil)) ;;;###autoload (defun git-reblame () "Recalculate all blame information in the current buffer" - (unless git-blame-mode - (error "git-blame is not active")) (interactive) + (unless git-blame-mode + (error "Git-blame is not active")) + (git-blame-cleanup) (git-blame-run)) @@ -275,7 +320,6 @@ (t nil))) - (defun git-blame-new-commit (hash src-line res-line num-lines) (save-excursion (set-buffer git-blame-file) @@ -283,9 +327,11 @@ (inhibit-point-motion-hooks t) (inhibit-modification-hooks t)) (when (not info) - (let ((color (pop git-blame-colors))) - (unless color - (setq color git-blame-ancient-color)) + ;; Assign a random color to each new commit info + ;; Take care not to select the same color multiple times + (let ((color (if git-blame-colors + (git-blame-random-pop git-blame-colors) + git-blame-ancient-color))) (setq info (list hash src-line res-line num-lines (git-describe-commit hash) (cons 'color color)))) @@ -811,7 +811,12 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) if (data->files[i]->is_binary) { show_name(prefix, name, len, reset, set); - printf(" Bin\n"); + printf(" Bin "); + printf("%s%d%s", del_c, deleted, reset); + printf(" -> "); + printf("%s%d%s", add_c, added, reset); + printf(" bytes"); + printf("\n"); goto free_diffstat_file; } else if (data->files[i]->is_unmerged) { @@ -1185,9 +1190,11 @@ static void builtin_diffstat(const char *name_a, const char *name_b, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); - if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) + if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) { data->is_binary = 1; - else { + data->added = mf2.size; + data->deleted = mf1.size; + } else { /* Crazy xdl interfaces.. */ xpparam_t xpp; xdemitconf_t xecfg; @@ -8,6 +8,11 @@ #include "cache.h" #include "dir.h" +struct path_simplify { + int len; + const char *path; +}; + int common_prefix(const char **pathspec) { const char *path, *slash, *next; @@ -293,6 +298,31 @@ static int dir_exists(const char *dirname, int len) } /* + * This is an inexact early pruning of any recursive directory + * reading - if the path cannot possibly be in the pathspec, + * return true, and we'll skip it early. + */ +static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify) +{ + if (simplify) { + for (;;) { + const char *match = simplify->path; + int len = simplify->len; + + if (!match) + break; + if (len > pathlen) + len = pathlen; + if (!memcmp(path, match, len)) + return 0; + simplify++; + } + return 1; + } + return 0; +} + +/* * Read a directory tree. We currently ignore anything but * directories, regular files and symlinks. That's because git * doesn't handle them at all yet. Maybe that will change some @@ -301,7 +331,7 @@ static int dir_exists(const char *dirname, int len) * Also, we ignore the name ".git" (even if it is not a directory). * That likely will not change. */ -static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only) +static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify) { DIR *fdir = opendir(path); int contents = 0; @@ -324,6 +354,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co continue; len = strlen(de->d_name); memcpy(fullname + baselen, de->d_name, len+1); + if (simplify_away(fullname, baselen + len, simplify)) + continue; if (excluded(dir, fullname) != dir->show_ignored) { if (!dir->show_ignored || DTYPE(de) != DT_DIR) { continue; @@ -350,13 +382,13 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co if (dir->hide_empty_directories && !read_directory_recursive(dir, fullname, fullname, - baselen + len, 1)) + baselen + len, 1, simplify)) continue; break; } contents += read_directory_recursive(dir, - fullname, fullname, baselen + len, 0); + fullname, fullname, baselen + len, 0, simplify); continue; case DT_REG: case DT_LNK: @@ -386,8 +418,61 @@ static int cmp_name(const void *p1, const void *p2) e2->name, e2->len); } -int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen) +/* + * Return the length of the "simple" part of a path match limiter. + */ +static int simple_length(const char *match) { + const char special[256] = { + [0] = 1, ['?'] = 1, + ['\\'] = 1, ['*'] = 1, + ['['] = 1 + }; + int len = -1; + + for (;;) { + unsigned char c = *match++; + len++; + if (special[c]) + return len; + } +} + +static struct path_simplify *create_simplify(const char **pathspec) +{ + int nr, alloc = 0; + struct path_simplify *simplify = NULL; + + if (!pathspec) + return NULL; + + for (nr = 0 ; ; nr++) { + const char *match; + if (nr >= alloc) { + alloc = alloc_nr(alloc); + simplify = xrealloc(simplify, alloc * sizeof(*simplify)); + } + match = *pathspec++; + if (!match) + break; + simplify[nr].path = match; + simplify[nr].len = simple_length(match); + } + simplify[nr].path = NULL; + simplify[nr].len = 0; + return simplify; +} + +static void free_simplify(struct path_simplify *simplify) +{ + if (simplify) + free(simplify); +} + +int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec) +{ + struct path_simplify *simplify = create_simplify(pathspec); + /* * Make sure to do the per-directory exclude for all the * directories leading up to our base. @@ -414,7 +499,8 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i } } - read_directory_recursive(dir, path, base, baselen, 0); + read_directory_recursive(dir, path, base, baselen, 0, simplify); + free_simplify(simplify); qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name); return dir->nr; } @@ -48,7 +48,7 @@ extern int common_prefix(const char **pathspec); #define MATCHED_EXACTLY 3 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen); -extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen); +extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen, const char **pathspec); extern int push_exclude_per_directory(struct dir_struct *, const char *, int); extern void pop_exclude_per_directory(struct dir_struct *, int); diff --git a/git-lost-found.sh b/git-lost-found.sh index 9360804711..58570dff13 100755 --- a/git-lost-found.sh +++ b/git-lost-found.sh @@ -12,7 +12,7 @@ fi laf="$GIT_DIR/lost-found" rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit -git fsck --full | +git fsck --full --no-reflogs | while read dangling type sha1 do case "$dangling" in diff --git a/git-svn.perl b/git-svn.perl index d307d430f3..6216cade0f 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -33,7 +33,7 @@ use Carp qw/croak/; use IO::File qw//; use File::Basename qw/dirname basename/; use File::Path qw/mkpath/; -use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev pass_through/; +use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; use IPC::Open3; use Git; @@ -168,6 +168,7 @@ for (my $i = 0; $i < @ARGV; $i++) { my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd); read_repo_config(\%opts); +Getopt::Long::Configure('pass_through') if $cmd eq 'log'; my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version, 'minimize-connections' => \$Git::SVN::Migration::_minimize, 'id|i=s' => \$Git::SVN::default_ref_id, @@ -229,6 +230,8 @@ Usage: $0 <command> [options] [arguments]\n next if /^multi-/; # don't show deprecated commands print $fd ' ',pack('A17',$_),$cmd{$_}->[1],"\n"; foreach (keys %{$cmd{$_}->[2]}) { + # mixed-case options are for .git/config only + next if /[A-Z]/ && /^[a-z]+$/i; # prints out arguments as they should be passed: my $x = s#[:=]s$## ? '<arg>' : s#[:=]i$## ? '<num>' : ''; print $fd ' ' x 21, join(', ', map { length $_ > 1 ? diff --git a/git.spec.in b/git.spec.in index 46aee88fd1..f0746ed78c 100644 --- a/git.spec.in +++ b/git.spec.in @@ -1,4 +1,7 @@ # Pass --without docs to rpmbuild if you don't want the documentation + +%define python_path /usr/bin/python + Name: git Version: @@VERSION@@ Release: 1%{?dist} @@ -9,7 +12,7 @@ URL: http://kernel.org/pub/software/scm/git/ Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3} BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -Requires: git-core, git-svn, git-cvs, git-arch, git-email, gitk, git-gui, perl-Git +Requires: git-core, git-svn, git-cvs, git-arch, git-email, gitk, git-gui, git-p4, perl-Git %description Git is a fast, scalable, distributed revision control system with an @@ -50,6 +53,13 @@ Requires: git-core = %{version}-%{release}, tla %description arch Git tools for importing Arch repositories. +%package p4 +Summary: Git tools for importing Perforce repositories +Group: Development/Tools +Requires: git-core = %{version}-%{release}, python +%description p4 +Git tools for importing Perforce repositories. + %package email Summary: Git tools for sending email Group: Development/Tools @@ -85,23 +95,23 @@ Perl interface to Git %setup -q %build -make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" WITH_OWN_SUBPROCESS_PY=YesPlease \ - prefix=%{_prefix} all %{!?_without_docs: doc} +make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" WITH_P4IMPORT=YesPlease \ + prefix=%{_prefix} PYTHON_PATH=%{python_path} all %{!?_without_docs: doc} %install rm -rf $RPM_BUILD_ROOT make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" DESTDIR=$RPM_BUILD_ROOT \ - WITH_OWN_SUBPROCESS_PY=YesPlease \ - prefix=%{_prefix} mandir=%{_mandir} INSTALLDIRS=vendor \ - install %{!?_without_docs: install-doc} + WITH_P4IMPORT=YesPlease prefix=%{_prefix} mandir=%{_mandir} \ + PYTHON_PATH=%{python_path} \ + INSTALLDIRS=vendor install %{!?_without_docs: install-doc} find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';' find $RPM_BUILD_ROOT -type f -name '*.bs' -empty -exec rm -f {} ';' find $RPM_BUILD_ROOT -type f -name perllocal.pod -exec rm -f {} ';' -(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "archimport|svn|cvs|email|gitk|git-gui|git-citool" | sed -e s@^$RPM_BUILD_ROOT@@) > bin-man-doc-files +(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "p4import|archimport|svn|cvs|email|gitk|git-gui|git-citool" | sed -e s@^$RPM_BUILD_ROOT@@) > bin-man-doc-files (find $RPM_BUILD_ROOT%{perl_vendorlib} -type f | sed -e s@^$RPM_BUILD_ROOT@@) >> perl-files %if %{!?_without_docs:1}0 -(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "archimport|svn|git-cvs|email|gitk|git-gui|git-citool" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files +(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "p4import|archimport|svn|git-cvs|email|gitk|git-gui|git-citool" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files %else rm -rf $RPM_BUILD_ROOT%{_mandir} %endif @@ -133,6 +143,13 @@ rm -rf $RPM_BUILD_ROOT %{!?_without_docs: %{_mandir}/man1/git-archimport.1*} %{!?_without_docs: %doc Documentation/git-archimport.html } +%files p4 +%defattr(-,root,root) +%doc Documentation/git-p4import.txt +%{_bindir}/git-p4import +%{!?_without_docs: %{_mandir}/man1/git-p4import.1*} +%{!?_without_docs: %doc Documentation/git-p4import.html } + %files email %defattr(-,root,root) %doc Documentation/*email*.txt @@ -167,6 +184,9 @@ rm -rf $RPM_BUILD_ROOT %{!?_without_docs: %doc Documentation/*.html } %changelog +* Tue Mar 27 2007 Eygene Ryabinkin <rea-git@codelabs.ru> +- Added the git-p4 package: Perforce import stuff. + * Mon Feb 13 2007 Nicolas Pitre <nico@cam.org> - Update core package description (Git isn't as stupid as it used to be) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 45ac9d7121..e49eb91d69 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -19,7 +19,7 @@ use File::Basename qw(basename); binmode STDOUT, ':utf8'; BEGIN { - CGI->compile() if $ENV{MOD_PERL}; + CGI->compile() if $ENV{'MOD_PERL'}; } our $cgi = new CGI; @@ -1800,7 +1800,7 @@ EOF $cgi->hidden(-name => "a") . "\n" . $cgi->hidden(-name => "h") . "\n" . $cgi->popup_menu(-name => 'st', -default => 'commit', - -values => ['commit', 'author', 'committer', 'pickaxe']) . + -values => ['commit', 'author', 'committer', 'pickaxe']) . $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . " search:\n", $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . @@ -1870,16 +1870,16 @@ sub git_print_page_nav { my %arg = map { $_ => {action=>$_} } @navs; if (defined $head) { for (qw(commit commitdiff)) { - $arg{$_}{hash} = $head; + $arg{$_}{'hash'} = $head; } if ($current =~ m/^(tree | log | shortlog | commit | commitdiff | search)$/x) { for (qw(shortlog log)) { - $arg{$_}{hash} = $head; + $arg{$_}{'hash'} = $head; } } } - $arg{tree}{hash} = $treehead if defined $treehead; - $arg{tree}{hash_base} = $treebase if defined $treebase; + $arg{'tree'}{'hash'} = $treehead if defined $treehead; + $arg{'tree'}{'hash_base'} = $treebase if defined $treebase; print "<div class=\"page_nav\">\n" . (join " | ", @@ -1927,9 +1927,9 @@ sub git_print_header_div { my ($action, $title, $hash, $hash_base) = @_; my %args = (); - $args{action} = $action; - $args{hash} = $hash if $hash; - $args{hash_base} = $hash_base if $hash_base; + $args{'action'} = $action; + $args{'hash'} = $hash if $hash; + $args{'hash_base'} = $hash_base if $hash_base; print "<div class=\"header\">\n" . $cgi->a({-href => href(%args), -class => "title"}, @@ -3095,7 +3095,7 @@ sub git_summary { git_project_list_body(\@forklist, undef, 0, 15, $#forklist <= 15 ? undef : $cgi->a({-href => href(action=>"forks")}, "..."), - 'noheader'); + 'noheader'); } git_footer_html(); @@ -3202,7 +3202,7 @@ HTML my $rev = substr($full_rev, 0, 8); my $author = $meta->{'author'}; my %date = parse_date($meta->{'author-time'}, - $meta->{'author-tz'}); + $meta->{'author-tz'}); my $date = $date{'iso-tz'}; if ($group_size) { $current_color = ++$current_color % $num_colors; @@ -3214,9 +3214,9 @@ HTML print " rowspan=\"$group_size\"" if ($group_size > 1); print ">"; print $cgi->a({-href => href(action=>"commit", - hash=>$full_rev, - file_name=>$file_name)}, - esc_html($rev)); + hash=>$full_rev, + file_name=>$file_name)}, + esc_html($rev)); print "</td>\n"; } open (my $dd, "-|", git_cmd(), "rev-parse", "$full_rev^") @@ -3225,13 +3225,13 @@ HTML close $dd; chomp($parent_commit); my $blamed = href(action => 'blame', - file_name => $meta->{'filename'}, - hash_base => $parent_commit); + file_name => $meta->{'filename'}, + hash_base => $parent_commit); print "<td class=\"linenr\">"; print $cgi->a({ -href => "$blamed#l$orig_lineno", - -id => "l$lineno", - -class => "linenr" }, - esc_html($lineno)); + -id => "l$lineno", + -class => "linenr" }, + esc_html($lineno)); print "</td>"; print "<td class=\"pre\">" . esc_html($data) . "</td>\n"; print "</tr>\n"; @@ -3621,7 +3621,7 @@ sub git_snapshot { my $name = $project; $name =~ s/\047/\047\\\047\047/g; open my $fd, "-|", - "$git archive --format=tar --prefix=\'$name\'/ $hash | $command" + "$git archive --format=tar --prefix=\'$name\'/ $hash | $command" or die_error(undef, "Execute git-tar-tree failed"); binmode STDOUT, ':raw'; print <$fd>; @@ -3734,7 +3734,7 @@ sub git_commit { # difftree output is not printed for merges open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id", @diff_opts, $parent, $hash, "--" - or die_error(undef, "Open git-diff-tree failed"); + or die_error(undef, "Open git-diff-tree failed"); @difftree = map { chomp; $_ } <$fd>; close $fd or die_error(undef, "Reading git-diff-tree failed"); } @@ -4306,13 +4306,13 @@ sub git_search { if ($page > 0) { $paging_nav .= $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype)}, - "first"); + searchtext=>$searchtext, searchtype=>$searchtype)}, + "first"); $paging_nav .= " ⋅ " . $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page-1), - -accesskey => "p", -title => "Alt-p"}, "prev"); + searchtext=>$searchtext, searchtype=>$searchtype, + page=>$page-1), + -accesskey => "p", -title => "Alt-p"}, "prev"); } else { $paging_nav .= "first"; $paging_nav .= " ⋅ prev"; @@ -4320,9 +4320,9 @@ sub git_search { if ($#commitlist >= 100) { $paging_nav .= " ⋅ " . $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page+1), - -accesskey => "n", -title => "Alt-n"}, "next"); + searchtext=>$searchtext, searchtype=>$searchtype, + page=>$page+1), + -accesskey => "n", -title => "Alt-n"}, "next"); } else { $paging_nav .= " ⋅ next"; } @@ -4330,9 +4330,9 @@ sub git_search { if ($#commitlist >= 100) { $next_link = $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype, - page=>$page+1), - -accesskey => "n", -title => "Alt-n"}, "next"); + searchtext=>$searchtext, searchtype=>$searchtype, + page=>$page+1), + -accesskey => "n", -title => "Alt-n"}, "next"); } git_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav); diff --git a/merge-recursive.c b/merge-recursive.c index e1aebd7727..3611a2bdb7 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -221,7 +221,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, struct cache_entry *ce; ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh); if (!ce) - return error("cache_addinfo failed: %s", strerror(cache_errno)); + return error("addinfo_cache failed for path '%s'", path); return add_cache_entry(ce, options); } diff --git a/pack-check.c b/pack-check.c index d9883225ea..f58083d11e 100644 --- a/pack-check.c +++ b/pack-check.c @@ -42,13 +42,14 @@ static int verify_packfile(struct packed_git *p, */ nr_objects = num_packed_objects(p); for (i = 0, err = 0; i < nr_objects; i++) { - unsigned char sha1[20]; + const unsigned char *sha1; void *data; enum object_type type; unsigned long size; off_t offset; - if (nth_packed_object_sha1(p, i, sha1)) + sha1 = nth_packed_object_sha1(p, i); + if (!sha1) die("internal error pack-check nth-packed-object"); offset = find_pack_entry_one(sha1, p); if (!offset) @@ -82,14 +83,16 @@ static void show_pack_info(struct packed_git *p) memset(chain_histogram, 0, sizeof(chain_histogram)); for (i = 0; i < nr_objects; i++) { - unsigned char sha1[20], base_sha1[20]; + const unsigned char *sha1; + unsigned char base_sha1[20]; const char *type; unsigned long size; unsigned long store_size; off_t offset; unsigned int delta_chain_length; - if (nth_packed_object_sha1(p, i, sha1)) + sha1 = nth_packed_object_sha1(p, i); + if (!sha1) die("internal error pack-check nth-packed-object"); offset = find_pack_entry_one(sha1, p); if (!offset) diff --git a/read-cache.c b/read-cache.c index 6339a278da..a8f8a6b2b2 100644 --- a/read-cache.c +++ b/read-cache.c @@ -24,8 +24,6 @@ unsigned int active_nr, active_alloc, active_cache_changed; struct cache_tree *active_cache_tree; -int cache_errno; - static void *cache_mmap; static size_t cache_mmap_size; @@ -327,7 +325,7 @@ int remove_file_from_cache(const char *path) return 0; } -int add_file_to_index(const char *path, int verbose) +int add_file_to_cache(const char *path, int verbose) { int size, namelen; struct stat st; @@ -643,14 +641,15 @@ int add_cache_entry(struct cache_entry *ce, int option) * For example, you'd want to do this after doing a "git-read-tree", * to link up the stat cache details with the proper files. */ -struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) +static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, int *err) { struct stat st; struct cache_entry *updated; int changed, size; if (lstat(ce->name, &st) < 0) { - cache_errno = errno; + if (err) + *err = errno; return NULL; } @@ -664,7 +663,8 @@ struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) } if (ce_modified(ce, &st, really)) { - cache_errno = EINVAL; + if (err) + *err = EINVAL; return NULL; } @@ -696,6 +696,8 @@ int refresh_cache(unsigned int flags) for (i = 0; i < active_nr; i++) { struct cache_entry *ce, *new; + int cache_errno = 0; + ce = active_cache[i]; if (ce_stage(ce)) { while ((i < active_nr) && @@ -709,7 +711,7 @@ int refresh_cache(unsigned int flags) continue; } - new = refresh_cache_entry(ce, really); + new = refresh_cache_ent(ce, really, &cache_errno); if (new == ce) continue; if (!new) { @@ -737,6 +739,11 @@ int refresh_cache(unsigned int flags) return has_errors; } +struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) +{ + return refresh_cache_ent(ce, really, NULL); +} + static int verify_hdr(struct cache_header *hdr, unsigned long size) { SHA_CTX c; diff --git a/sha1_file.c b/sha1_file.c index 9c26038420..4304fe9bbc 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1532,15 +1532,14 @@ uint32_t num_packed_objects(const struct packed_git *p) return (uint32_t)((p->index_size - 20 - 20 - 4*256) / 24); } -int nth_packed_object_sha1(const struct packed_git *p, uint32_t n, - unsigned char* sha1) +const unsigned char *nth_packed_object_sha1(const struct packed_git *p, + uint32_t n) { const unsigned char *index = p->index_data; index += 4 * 256; if (num_packed_objects(p) <= n) - return -1; - hashcpy(sha1, index + 24 * n + 4); - return 0; + return NULL; + return index + 24 * n + 4; } off_t find_pack_entry_one(const unsigned char *sha1, diff --git a/sha1_name.c b/sha1_name.c index bede0e5b06..267ea3f3ed 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -71,7 +71,7 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char * static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) { struct packed_git *p; - unsigned char found_sha1[20]; + const unsigned char *found_sha1 = NULL; int found = 0; prepare_packed_git(); @@ -80,10 +80,10 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne uint32_t first = 0, last = num; while (first < last) { uint32_t mid = (first + last) / 2; - unsigned char now[20]; + const unsigned char *now; int cmp; - nth_packed_object_sha1(p, mid, now); + now = nth_packed_object_sha1(p, mid); cmp = hashcmp(match, now); if (!cmp) { first = mid; @@ -96,14 +96,14 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne last = mid; } if (first < num) { - unsigned char now[20], next[20]; - nth_packed_object_sha1(p, first, now); + const unsigned char *now, *next; + now = nth_packed_object_sha1(p, first); if (match_sha(len, match, now)) { - if (nth_packed_object_sha1(p, first+1, next) || - !match_sha(len, match, next)) { + next = nth_packed_object_sha1(p, first+1); + if (!next|| !match_sha(len, match, next)) { /* unique within this pack */ if (!found) { - hashcpy(found_sha1, now); + found_sha1 = now; found++; } else if (hashcmp(found_sha1, now)) { diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh index 7831e3461c..fcb3302764 100755 --- a/t/t6002-rev-list-bisect.sh +++ b/t/t6002-rev-list-bisect.sh @@ -163,7 +163,7 @@ test_sequence() # the bisection point is the head - this is the bad point. # -test_output_expect_success "--bisect l5 ^root" 'git-rev-list $_bisect_option l5 ^root' <<EOF +test_output_expect_success "$_bisect_option l5 ^root" 'git-rev-list $_bisect_option l5 ^root' <<EOF c3 EOF diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh index 5182dbb158..761f09b1e5 100755 --- a/t/t6004-rev-list-path-optim.sh +++ b/t/t6004-rev-list-path-optim.sh @@ -7,7 +7,8 @@ test_description='git-rev-list trivial path optimization test' test_expect_success setup ' echo Hello > a && git add a && -git commit -m "Initial commit" a +git commit -m "Initial commit" a && +initial=$(git rev-parse --verify HEAD) ' test_expect_success path-optimization ' @@ -16,4 +17,35 @@ test_expect_success path-optimization ' test $(git-rev-list $commit -- . | wc -l) = 1 ' +test_expect_success 'further setup' ' + git checkout -b side && + echo Irrelevant >c && + git add c && + git commit -m "Side makes an irrelevant commit" && + echo "More Irrelevancy" >c && + git add c && + git commit -m "Side makes another irrelevant commit" && + echo Bye >a && + git add a && + git commit -m "Side touches a" && + side=$(git rev-parse --verify HEAD) && + echo "Yet more Irrelevancy" >c && + git add c && + git commit -m "Side makes yet another irrelevant commit" && + git checkout master && + echo Another >b && + git add b && + git commit -m "Master touches b" && + git merge side && + echo Touched >b && + git add b && + git commit -m "Master touches b again" +' + +test_expect_success 'path optimization 2' ' + ( echo "$side"; echo "$initial" ) >expected && + git rev-list HEAD -- a >actual && + diff -u expected actual +' + test_done diff --git a/wt-status.c b/wt-status.c index a25632bc87..a0559905a0 100644 --- a/wt-status.c +++ b/wt-status.c @@ -260,7 +260,7 @@ static void wt_status_print_untracked(struct wt_status *s) if (file_exists(x)) add_excludes_from_file(&dir, x); - read_directory(&dir, ".", "", 0); + read_directory(&dir, ".", "", 0, NULL); for(i = 0; i < dir.nr; i++) { /* check for matching entry, which is unmerged; lifted from * builtin-ls-files:show_other_files */ |