Merge branch 'js/patience-diff'
authorJunio C Hamano <gitster@pobox.com>
Sat, 24 Jan 2009 05:51:38 +0000 (21:51 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 24 Jan 2009 05:51:38 +0000 (21:51 -0800)
* js/patience-diff:
bash completions: Add the --patience option
Introduce the diff option '--patience'
Implement the patience diff algorithm

Conflicts:
contrib/completion/git-completion.bash

1  2 
Documentation/diff-options.txt
Makefile
contrib/completion/git-completion.bash
diff.c
xdiff/xdiff.h
index 43793d75005a7af875a055d377a8ab6a13510682,808bf87277b5645c758c84e8521624c60dea90ed..1f8ce979bbb73c7caf28bc6bca3283254470bb1c
@@@ -19,12 -19,16 +19,12 @@@ endif::git-format-patch[
  
  ifndef::git-format-patch[]
  -p::
 +-u::
        Generate patch (see section on generating patches).
        {git-diff? This is the default.}
  endif::git-format-patch[]
  
 --u::
 -      Synonym for "-p".
 -
  -U<n>::
 -      Shorthand for "--unified=<n>".
 -
  --unified=<n>::
        Generate diffs with <n> lines of context instead of
        the usual three. Implies "-p".
@@@ -36,6 -40,9 +36,9 @@@
  --patch-with-raw::
        Synonym for "-p --raw".
  
+ --patience:
+       Generate a diff using the "patience diff" algorithm.
  --stat[=width[,name-width]]::
        Generate a diffstat.  You can override the default
        output width for 80-column terminal by "--stat=width".
  --abbrev[=<n>]::
        Instead of showing the full 40-byte hexadecimal object
        name in diff-raw format output and diff-tree header
 -      lines, show only handful hexdigits prefix.  This is
 +      lines, show only a partial prefix.  This is
        independent of --full-index option above, which controls
        the diff-patch output format.  Non default number of
        digits can be specified with --abbrev=<n>.
        can name which subdirectory to make the output relative
        to by giving a <path> as an argument.
  
 +-a::
  --text::
        Treat all files as text.
  
 --a::
 -      Shorthand for "--text".
 -
  --ignore-space-at-eol::
        Ignore changes in whitespace at EOL.
  
 +-b::
  --ignore-space-change::
        Ignore changes in amount of whitespace.  This ignores whitespace
        at line end, and considers all other sequences of one or
        more whitespace characters to be equivalent.
  
 --b::
 -      Shorthand for "--ignore-space-change".
 -
 +-w::
  --ignore-all-space::
        Ignore whitespace when comparing lines.  This ignores
        differences even if one line has whitespace where the other
        line has none.
  
 --w::
 -      Shorthand for "--ignore-all-space".
 +--inter-hunk-context=<lines>::
 +      Show the context between diff hunks, up to the specified number
 +      of lines, thereby fusing hunks that are close to each other.
  
  --exit-code::
        Make the program exit with codes similar to diff(1).
diff --combined Makefile
index 270b223adb8704070997bf02dffff2c94a91de69,33e6fa403e61bab60979f509a85d4191a4ec1ea7..b4d9cb49497482a6a84d4afbadc63f85a56e4a73
+++ b/Makefile
@@@ -1287,7 -1287,7 +1287,7 @@@ $(LIB_FILE): $(LIB_OBJS
        $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
  
  XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
-       xdiff/xmerge.o
+       xdiff/xmerge.o xdiff/xpatience.o
  $(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
        xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
  
@@@ -1307,9 -1307,6 +1307,9 @@@ html
  info:
        $(MAKE) -C Documentation info
  
 +pdf:
 +      $(MAKE) -C Documentation pdf
 +
  TAGS:
        $(RM) TAGS
        $(FIND) . -name '*.[hcS]' -print | xargs etags -a
@@@ -1356,15 -1353,7 +1356,15 @@@ endi
  
  ### Testing rules
  
 -TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X
 +TEST_PROGRAMS += test-chmtime$X
 +TEST_PROGRAMS += test-ctype$X
 +TEST_PROGRAMS += test-date$X
 +TEST_PROGRAMS += test-delta$X
 +TEST_PROGRAMS += test-genrandom$X
 +TEST_PROGRAMS += test-match-trees$X
 +TEST_PROGRAMS += test-parse-options$X
 +TEST_PROGRAMS += test-path-utils$X
 +TEST_PROGRAMS += test-sha1$X
  
  all:: $(TEST_PROGRAMS)
  
@@@ -1377,8 -1366,6 +1377,8 @@@ export NO_SVN_TEST
  test: all
        $(MAKE) -C t/ all
  
 +test-ctype$X: ctype.o
 +
  test-date$X: date.o ctype.o
  
  test-delta$X: diff-delta.o patch-delta.o
@@@ -1444,12 -1431,10 +1444,12 @@@ endi
        { $(RM) "$$execdir/git-add$X" && \
                ln git-add$X "$$execdir/git-add$X" 2>/dev/null || \
                cp git-add$X "$$execdir/git-add$X"; } && \
 -      { $(foreach p,$(filter-out git-add$X,$(BUILT_INS)), $(RM) "$$execdir/$p" && \
 -              ln "$$execdir/git-add$X" "$$execdir/$p" 2>/dev/null || \
 -              ln -s "git-add$X" "$$execdir/$p" 2>/dev/null || \
 -              cp "$$execdir/git-add$X" "$$execdir/$p" || exit;) } && \
 +      { for p in $(filter-out git-add$X,$(BUILT_INS)); do \
 +              $(RM) "$$execdir/$$p" && \
 +              ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \
 +              ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \
 +              cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \
 +        done } && \
        ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
  
  install-doc:
@@@ -1464,9 -1449,6 +1464,9 @@@ install-html
  install-info:
        $(MAKE) -C Documentation install-info
  
 +install-pdf:
 +      $(MAKE) -C Documentation install-pdf
 +
  quick-install-doc:
        $(MAKE) -C Documentation quick-install
  
index 703f4c2e90b034a996d993632a81553de02ceda8,b98d765deb5294abddc24b1bc975c9d3b3c93a1d..81f70ec6449f3c15f26884040cdfe9e9cad489eb
@@@ -1,4 -1,3 +1,4 @@@
 +#!bash
  #
  # bash completion support for core Git.
  #
@@@ -51,11 -50,9 +51,11 @@@ case "$COMP_WORDBREAKS" i
  *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
  esac
  
 +# __gitdir accepts 0 or 1 arguments (i.e., location)
 +# returns location of .git repo
  __gitdir ()
  {
 -      if [ -z "$1" ]; then
 +      if [ -z "${1-}" ]; then
                if [ -n "$__git_dir" ]; then
                        echo "$__git_dir"
                elif [ -d .git ]; then
@@@ -70,8 -67,6 +70,8 @@@
        fi
  }
  
 +# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
 +# returns text to add to bash PS1 prompt (includes branch name)
  __git_ps1 ()
  {
        local g="$(git rev-parse --git-dir 2>/dev/null)"
                        fi
                fi
  
 -              if [ -n "$1" ]; then
 +              if [ -n "${1-}" ]; then
                        printf "$1" "${b##refs/heads/}$r"
                else
                        printf " (%s)" "${b##refs/heads/}$r"
        fi
  }
  
 +# __gitcomp_1 requires 2 arguments
  __gitcomp_1 ()
  {
        local c IFS=' '$'\t'$'\n'
        done
  }
  
 +# __gitcomp accepts 1, 2, 3, or 4 arguments
 +# generates completion reply with compgen
  __gitcomp ()
  {
        local cur="${COMP_WORDS[COMP_CWORD]}"
                ;;
        *)
                local IFS=$'\n'
 -              COMPREPLY=($(compgen -P "$2" \
 -                      -W "$(__gitcomp_1 "$1" "$4")" \
 +              COMPREPLY=($(compgen -P "${2-}" \
 +                      -W "$(__gitcomp_1 "${1-}" "${4-}")" \
                        -- "$cur"))
                ;;
        esac
  }
  
 +# __git_heads accepts 0 or 1 arguments (to pass to __gitdir)
  __git_heads ()
  {
 -      local cmd i is_hash=y dir="$(__gitdir "$1")"
 +      local cmd i is_hash=y dir="$(__gitdir "${1-}")"
        if [ -d "$dir" ]; then
                git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
                        refs/heads
                return
        fi
 -      for i in $(git ls-remote "$1" 2>/dev/null); do
 +      for i in $(git ls-remote "${1-}" 2>/dev/null); do
                case "$is_hash,$i" in
                y,*) is_hash=n ;;
                n,*^{}) is_hash=y ;;
        done
  }
  
 +# __git_tags accepts 0 or 1 arguments (to pass to __gitdir)
  __git_tags ()
  {
 -      local cmd i is_hash=y dir="$(__gitdir "$1")"
 +      local cmd i is_hash=y dir="$(__gitdir "${1-}")"
        if [ -d "$dir" ]; then
                git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
                        refs/tags
                return
        fi
 -      for i in $(git ls-remote "$1" 2>/dev/null); do
 +      for i in $(git ls-remote "${1-}" 2>/dev/null); do
                case "$is_hash,$i" in
                y,*) is_hash=n ;;
                n,*^{}) is_hash=y ;;
        done
  }
  
 +# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
  __git_refs ()
  {
 -      local i is_hash=y dir="$(__gitdir "$1")"
 +      local i is_hash=y dir="$(__gitdir "${1-}")"
        local cur="${COMP_WORDS[COMP_CWORD]}" format refs
        if [ -d "$dir" ]; then
                case "$cur" in
        done
  }
  
 +# __git_refs2 requires 1 argument (to pass to __git_refs)
  __git_refs2 ()
  {
        local i
        done
  }
  
 +# __git_refs_remotes requires 1 argument (to pass to ls-remote)
  __git_refs_remotes ()
  {
        local cmd i is_hash=y
@@@ -483,7 -470,6 +483,7 @@@ __git_aliases (
        done
  }
  
 +# __git_aliased_command requires 1 argument
  __git_aliased_command ()
  {
        local word cmdline=$(git --git-dir="$(__gitdir)" \
        done
  }
  
 +# __git_find_subcommand requires 1 argument
  __git_find_subcommand ()
  {
        local word subcommand c=1
@@@ -578,7 -563,7 +578,7 @@@ _git_add (
        --*)
                __gitcomp "
                        --interactive --refresh --patch --update --dry-run
 -                      --ignore-errors
 +                      --ignore-errors --intent-to-add
                        "
                return
        esac
@@@ -643,6 -628,7 +643,6 @@@ _git_branch (
        done
  
        case "${COMP_WORDS[COMP_CWORD]}" in
 -      --*=*)  COMPREPLY=() ;;
        --*)
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
@@@ -773,29 -759,24 +773,30 @@@ _git_describe (
        __gitcomp "$(__git_refs)"
  }
  
 -_git_diff ()
 -{
 -      __git_has_doubledash && return
 -
 -      local cur="${COMP_WORDS[COMP_CWORD]}"
 -      case "$cur" in
 -      --*)
 -              __gitcomp "--cached --stat --numstat --shortstat --summary
 +__git_diff_common_options="--stat --numstat --shortstat --summary
                        --patch-with-stat --name-only --name-status --color
                        --no-color --color-words --no-renames --check
                        --full-index --binary --abbrev --diff-filter=
 -                      --find-copies-harder --pickaxe-all --pickaxe-regex
 +                      --find-copies-harder
                        --text --ignore-space-at-eol --ignore-space-change
                        --ignore-all-space --exit-code --quiet --ext-diff
                        --no-ext-diff
                        --no-prefix --src-prefix= --dst-prefix=
 -                      --base --ours --theirs
 +                      --inter-hunk-context=
+                       --patience
 +                      --raw
 +"
 +
 +_git_diff ()
 +{
 +      __git_has_doubledash && return
 +
 +      local cur="${COMP_WORDS[COMP_CWORD]}"
 +      case "$cur" in
 +      --*)
 +              __gitcomp "--cached --pickaxe-all --pickaxe-regex
 +                      --base --ours --theirs
 +                      $__git_diff_common_options
                        "
                return
                ;;
@@@ -843,8 -824,6 +844,8 @@@ _git_format_patch (
                        --not --all
                        --cover-letter
                        --no-prefix --src-prefix= --dst-prefix=
 +                      --inline --suffix= --ignore-if-in-upstream
 +                      --subject-prefix=
                        "
                return
                ;;
@@@ -952,8 -931,6 +953,8 @@@ _git_ls_tree (
        __git_complete_file
  }
  
 +__git_log_pretty_formats="oneline short medium full fuller email raw format:"
 +
  _git_log ()
  {
        __git_has_doubledash && return
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --pretty=*)
 -              __gitcomp "
 -                      oneline short medium full fuller email raw
 +              __gitcomp "$__git_log_pretty_formats
                        " "" "${cur##--pretty=}"
                return
                ;;
                        --relative-date --date=
                        --author= --committer= --grep=
                        --all-match
 -                      --pretty= --name-status --name-only --raw
 +                      --pretty=
                        --not --all
                        --left-right --cherry-pick
                        --graph
 -                      --stat --numstat --shortstat
 -                      --decorate --diff-filter=
 -                      --color-words --walk-reflogs
 +                      --decorate
 +                      --walk-reflogs
                        --parents --children --full-history
                        --merge
 -                      --patience
 +                      $__git_diff_common_options
 +                      --pickaxe-all --pickaxe-regex
                        "
                return
                ;;
@@@ -1391,7 -1369,7 +1392,7 @@@ _git_config (
  
  _git_remote ()
  {
 -      local subcommands="add rm show prune update"
 +      local subcommands="add rename rm show prune update"
        local subcommand="$(__git_find_subcommand "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
        fi
  
        case "$subcommand" in
 -      rm|show|prune)
 +      rename|rm|show|prune)
                __gitcomp "$(__git_remotes)"
                ;;
        update)
@@@ -1427,7 -1405,7 +1428,7 @@@ _git_reset (
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --*)
 -              __gitcomp "--mixed --hard --soft"
 +              __gitcomp "--merge --mixed --hard --soft"
                return
                ;;
        esac
@@@ -1489,14 -1467,13 +1490,14 @@@ _git_show (
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --pretty=*)
 -              __gitcomp "
 -                      oneline short medium full fuller email raw
 +              __gitcomp "$__git_log_pretty_formats
                        " "" "${cur##--pretty=}"
                return
                ;;
        --*)
 -              __gitcomp "--pretty="
 +              __gitcomp "--pretty=
 +                      $__git_diff_common_options
 +                      "
                return
                ;;
        esac
@@@ -1583,7 -1560,7 +1584,7 @@@ _git_svn (
                        --follow-parent --authors-file= --repack=
                        --no-metadata --use-svm-props --use-svnsync-props
                        --log-window-size= --no-checkout --quiet
 -                      --repack-flags --user-log-author $remote_opts
 +                      --repack-flags --user-log-author --localtime $remote_opts
                        "
                local init_opts="
                        --template= --shared= --trunk= --tags=
@@@ -1697,6 -1674,7 +1698,6 @@@ _git (
  
        if [ -z "$command" ]; then
                case "${COMP_WORDS[COMP_CWORD]}" in
 -              --*=*) COMPREPLY=() ;;
                --*)   __gitcomp "
                        --paginate
                        --no-pager
        show)        _git_show ;;
        show-branch) _git_show_branch ;;
        stash)       _git_stash ;;
 +      stage)       _git_add ;;
        submodule)   _git_submodule ;;
        svn)         _git_svn ;;
        tag)         _git_tag ;;
@@@ -1788,16 -1765,13 +1789,16 @@@ _gitk (
        __git_complete_revlist
  }
  
 -complete -o default -o nospace -F _git git
 -complete -o default -o nospace -F _gitk gitk
 +complete -o bashdefault -o default -o nospace -F _git git 2>/dev/null \
 +      || complete -o default -o nospace -F _git git
 +complete -o bashdefault -o default -o nospace -F _gitk gitk 2>/dev/null \
 +      || complete -o default -o nospace -F _gitk gitk
  
  # The following are necessary only for Cygwin, and only are needed
  # when the user has tab-completed the executable name and consequently
  # included the '.exe' suffix.
  #
  if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
 -complete -o default -o nospace -F _git git.exe
 +complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
 +      || complete -o default -o nospace -F _git git.exe
  fi
diff --combined diff.c
index 073131316041fa25790c1da27c0a526d1c1b3d66,4aeab7746c253143b05b9b40627da29d4760153b..82cff975b3512b6b31d78a31cfab4cca3d575cc5
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -118,9 -118,7 +118,9 @@@ int git_diff_basic_config(const char *v
        }
  
        /* like GNU diff's --suppress-blank-empty option  */
 -      if (!strcmp(var, "diff.suppress-blank-empty")) {
 +      if (!strcmp(var, "diff.suppressblankempty") ||
 +                      /* for backwards compatibility */
 +                      !strcmp(var, "diff.suppress-blank-empty")) {
                diff_suppress_blank_empty = git_config_bool(var, value);
                return 0;
        }
@@@ -1471,7 -1469,6 +1471,7 @@@ static void builtin_diff(const char *na
                ecbdata.file = o->file;
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
 +              xecfg.interhunkctxlen = o->interhunkcontext;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
                if (pe)
                        xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
@@@ -2042,7 -2039,7 +2042,7 @@@ static void diff_fill_sha1_info(struct 
                        if (lstat(one->path, &st) < 0)
                                die("stat %s", one->path);
                        if (index_path(one->sha1, one->path, &st, 0))
 -                              die("cannot hash %s\n", one->path);
 +                              die("cannot hash %s", one->path);
                }
        }
        else
@@@ -2474,6 -2471,8 +2474,8 @@@ int diff_opt_parse(struct diff_options 
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else if (!strcmp(arg, "--ignore-space-at-eol"))
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
+       else if (!strcmp(arg, "--patience"))
+               options->xdl_opts |= XDF_PATIENCE_DIFF;
  
        /* flags options */
        else if (!strcmp(arg, "--binary")) {
                options->b_prefix = arg + 13;
        else if (!strcmp(arg, "--no-prefix"))
                options->a_prefix = options->b_prefix = "";
 +      else if (opt_arg(arg, '\0', "inter-hunk-context",
 +                       &options->interhunkcontext))
 +              ;
        else if (!prefixcmp(arg, "--output=")) {
                options->file = fopen(arg + strlen("--output="), "w");
                options->close_file = 1;
diff --combined xdiff/xdiff.h
index 361f80231905c66b642dcc764eeea32e7814ba07,d238c8263eebbbcb83d0d9f551560d86ec4866bb..4da052a3fff6768fca05b2f3399c5d87ec1daa2e
@@@ -32,6 -32,7 +32,7 @@@ extern "C" 
  #define XDF_IGNORE_WHITESPACE (1 << 2)
  #define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3)
  #define XDF_IGNORE_WHITESPACE_AT_EOL (1 << 4)
+ #define XDF_PATIENCE_DIFF (1 << 5)
  #define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE | XDF_IGNORE_WHITESPACE_AT_EOL)
  
  #define XDL_PATCH_NORMAL '-'
@@@ -84,7 -85,6 +85,7 @@@ typedef long (*find_func_t)(const char 
  
  typedef struct s_xdemitconf {
        long ctxlen;
 +      long interhunkctxlen;
        unsigned long flags;
        find_func_t find_func;
        void *find_func_priv;