Merge branch 'maint'
authorJunio C Hamano <junkio@cox.net>
Thu, 5 Apr 2007 23:34:51 +0000 (16:34 -0700)
committerJunio C Hamano <junkio@cox.net>
Thu, 5 Apr 2007 23:34:51 +0000 (16:34 -0700)
* maint:
Fix lseek(2) calls with args 2 and 3 swapped
Honor -p<n> when applying git diffs
Fix dependency of common-cmds.h
Fix renaming branch without config file
DESTDIR support for git/contrib/emacs
gitweb: Fix bug in "blobdiff" view for split (e.g. file to symlink) patches
Document --left-right option to rev-list.
Revert "builtin-archive: use RUN_SETUP"
rename contrib/hooks/post-receieve-email to contrib/hooks/post-receive-email.
rerere: make sorting really stable.
Fix t4200-rerere for white-space from "wc -l"

1  2 
Documentation/git-rev-list.txt
Makefile
builtin-apply.c
builtin-rev-list.c
gitweb/gitweb.perl
index 3fa45b81cc6de7b5104d343538c9ad040c208ce1,11ce395c982d5eb217d13441c2668884cc371d22..12b71ed0bbae2516cb67c98c96a56e6278a6f5c2
@@@ -21,12 -21,12 +21,13 @@@ SYNOPSI
             [ \--stdin ]
             [ \--topo-order ]
             [ \--parents ]
+            [ \--left-right ]
             [ \--encoding[=<encoding>] ]
             [ \--(author|committer|grep)=<pattern> ]
             [ [\--objects | \--objects-edge] [ \--unpacked ] ]
             [ \--pretty | \--header ]
             [ \--bisect ]
 +           [ \--bisect-vars ]
             [ \--merge ]
             [ \--reverse ]
             [ \--walk-reflogs ]
@@@ -101,6 -101,36 +102,36 @@@ include::pretty-formats.txt[
  
        Print the parents of the commit.
  
+ --left-right::
+       Mark which side of a symmetric diff a commit is reachable from.
+       Commits from the left side are prefixed with `<` and those from
+       the right with `>`.  If combined with `--boundary`, those
+       commits are prefixed with `-`.
+ +
+ For example, if you have this topology:
+ +
+ -----------------------------------------------------------------------
+              y---b---b  branch B
+             / \ /
+            /   .
+           /   / \
+          o---x---a---a  branch A
+ -----------------------------------------------------------------------
+ +
+ you would get an output line this:
+ +
+ -----------------------------------------------------------------------
+       $ git rev-list --left-right --boundary --pretty=oneline A...B
+       >bbbbbbb... 3rd on b
+       >bbbbbbb... 2nd on b
+       <aaaaaaa... 3rd on a
+       <aaaaaaa... 2nd on a
+       -yyyyyyy... 1st on b
+       -xxxxxxx... 1st on a
+ -----------------------------------------------------------------------
  Diff Formatting
  ~~~~~~~~~~~~~~~
  
@@@ -250,18 -280,6 +281,18 @@@ introduces a regression is thus reduce
  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
diff --combined Makefile
index 507ad9103e73b275ed00f3e9099d9699affa868f,81dafe5ee3308cb3e75986740d6d67f1364f6995..45dbcf6edff9d907836aa2208dd59c12c4b6ec03
+++ b/Makefile
@@@ -110,14 -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
@@@ -167,7 -159,6 +167,7 @@@ AR = a
  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..
@@@ -205,20 -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 = \
@@@ -251,12 -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
  
@@@ -267,9 -241,6 +267,9 @@@ endi
  ifndef PERL_PATH
        PERL_PATH = /usr/bin/perl
  endif
 +ifndef PYTHON_PATH
 +      PYTHON_PATH = /usr/local/bin/python
 +endif
  
  export PERL_PATH
  
@@@ -637,10 -608,6 +637,10 @@@ ifdef NO_PERL_MAKEMAKE
        export NO_PERL_MAKEMAKER
  endif
  
 +ifeq ($(TCLTK_PATH),)
 +NO_TCLTK=NoThanks
 +endif
 +
  QUIET_SUBDIR0  = $(MAKE) -C # space to separate -C and subdir
  QUIET_SUBDIR1  =
  
@@@ -679,8 -646,6 +679,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)
  
@@@ -696,27 -661,19 +696,27 @@@ export prefix gitexecdir TAR INSTALL DE
  
  ### 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,$^) \
@@@ -727,7 -684,7 +727,7 @@@ help.o: common-cmds.
  $(BUILT_INS): git$X
        $(QUIET_BUILT_IN)rm -f $@ && ln git$X $@
  
- common-cmds.h: Documentation/git-*.txt
+ common-cmds.h: $(wildcard Documentation/git-*.txt)
        $(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
  
  $(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)
  
@@@ -904,20 -852,6 +904,20 @@@ GIT-CFLAGS: .FORCE-GIT-CFLAG
                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.
@@@ -958,13 -892,10 +958,13 @@@ install: al
        $(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' \
@@@ -1043,13 -974,10 +1043,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 --combined builtin-apply.c
index 6a8292e2a5448389fbe76d9d899cb1d066e2a996,a5d612655f82e071c8e7d961660a6f1d562f6f40..4b8311b4de3f5c5d93352dac62856d67acfb143f
@@@ -30,7 -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;
@@@ -417,7 -417,7 +417,7 @@@ static int gitdiff_hdrend(const char *l
  static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, const char *oldnew)
  {
        if (!orig_name && !isnull)
-               return find_name(line, NULL, 1, TERM_TAB);
+               return find_name(line, NULL, p_value, TERM_TAB);
  
        if (orig_name) {
                int len;
                len = strlen(name);
                if (isnull)
                        die("git-apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr);
-               another = find_name(line, NULL, 1, TERM_TAB);
+               another = find_name(line, NULL, p_value, TERM_TAB);
                if (!another || memcmp(another, name, len))
                        die("git-apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr);
                free(another);
@@@ -2308,7 -2308,7 +2308,7 @@@ static void patch_stats(struct patch *p
  
  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 +2335,7 @@@ static void add_index_file(const char *
        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 +2662,8 @@@ static int apply_patch(int fd, const ch
        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 +2870,7 @@@ int cmd_apply(int argc, const char **ar
                                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 --combined builtin-rev-list.c
index f91685a4067630b49e6d9235f29ab8f8060faf66,b86e7ca8b18c7d11886dd3a1b4ca0eba95af264a..09774f9559b81050d89bd6663b8b672438da4342
@@@ -35,9 -35,9 +35,10 @@@ static const char rev_list_usage[] 
  "    --header | --pretty\n"
  "    --abbrev=nr | --no-abbrev\n"
  "    --abbrev-commit\n"
+ "    --left-right\n"
  "  special purpose:\n"
 -"    --bisect"
 +"    --bisect\n"
 +"    --bisect-vars"
  ;
  
  static struct rev_info revs;
@@@ -169,273 -169,38 +170,273 @@@ static void clear_distance(struct commi
        }
  }
  
 -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;
  }
  
@@@ -461,7 -226,6 +462,7 @@@ int cmd_rev_list(int argc, const char *
        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);
                        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?");
        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 --combined gitweb/gitweb.perl
index ea491562c80fbb8147746bd0dd711529555780ee,45ac9d7121e30e85f19380b7a44c6f228dc73444..e49eb91d69c2344163ab9477883777476c789bc7
@@@ -19,7 -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 +1800,7 @@@ EO
                      $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 +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 +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 +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 +3202,7 @@@ HTM
                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;
                        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^")
                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 +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 +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");
        }
@@@ -3934,7 -3934,8 +3934,8 @@@ sub git_blobdiff 
  
                # open patch output
                open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
-                       '-p', $hash_parent_base, $hash_base,
+                       '-p', ($format eq 'html' ? "--full-index" : ()),
+                       $hash_parent_base, $hash_base,
                        "--", (defined $file_parent ? $file_parent : ()), $file_name
                        or die_error(undef, "Open git-diff-tree failed");
        }
                }
  
                # open patch output
-               open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts,
+               open $fd, "-|", git_cmd(), "diff", @diff_opts,
+                       '-p', ($format eq 'html' ? "--full-index" : ()),
                        $hash_parent, $hash, "--"
                        or die_error(undef, "Open git-diff failed");
        } else  {
@@@ -4304,13 -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 .= " &sdot; " .
                                $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 .= " &sdot; prev";
                if ($#commitlist >= 100) {
                        $paging_nav .= " &sdot; " .
                                $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 .= " &sdot; next";
                }
                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);