Code

Merge branch 'rs/strbuf-setlen-assert'
authorJunio C Hamano <gitster@pobox.com>
Sun, 1 May 2011 23:25:04 +0000 (16:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 1 May 2011 23:25:04 +0000 (16:25 -0700)
* rs/strbuf-setlen-assert:
  strbuf: clarify assertion in strbuf_setlen()

78 files changed:
.gitignore
Documentation/RelNotes/1.7.5.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.6.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/diff-config.txt [new file with mode: 0644]
Documentation/diff-options.txt
Documentation/git-blame.txt
Documentation/git-format-patch.txt
Documentation/git-rebase.txt
Documentation/git-svn.txt
GIT-VERSION-GEN
Makefile
RelNotes
attr.c
builtin/blame.c
builtin/diff-tree.c
builtin/diff.c
builtin/index-pack.c
builtin/log.c
builtin/merge-tree.c
builtin/merge.c
builtin/pack-objects.c
builtin/shortlog.c
builtin/show-branch.c
cache.h
color.c
color.h
commit.h
config.c
contrib/completion/git-completion.bash
date.c
diff.c
diff.h
diffcore-rename.c
dir.c
environment.c
fast-import.c
git-parse-remote.sh
git-pull.sh
git-rebase--am.sh [new file with mode: 0644]
git-rebase--interactive.sh [changed mode: 0755->0644]
git-rebase--merge.sh [new file with mode: 0644]
git-rebase.sh
git-send-email.perl
git-stash.sh
git-svn.perl
graph.c
http.c
imap-send.c
merge-file.c
merge-file.h [new file with mode: 0644]
merge-recursive.c
sha1_name.c
strbuf.c
t/t0006-date.sh
t/t1303-wacky-config.sh
t/t1411-reflog-show.sh
t/t1506-rev-parse-diagnosis.sh
t/t3400-rebase.sh
t/t3403-rebase-skip.sh
t/t3407-rebase-abort.sh
t/t3418-rebase-continue.sh
t/t3903-stash.sh
t/t3904-stash-patch.sh
t/t4001-diff-rename.sh
t/t4013-diff-various.sh
t/t4013/diff.diff_--dirstat-by-file_initial_rearrange [new file with mode: 0644]
t/t4013/diff.diff_--dirstat_initial_rearrange [new file with mode: 0644]
t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
t/t4013/diff.log_--decorate=full_--all
t/t4013/diff.log_--decorate_--all
t/t4022-diff-rewrite.sh
t/t6022-merge-rename.sh
t/t7300-clean.sh
t/t9146-git-svn-empty-dirs.sh
t/test-lib.sh
upload-pack.c
vcs-svn/svndump.c

index 2cf3ca5808b51be3921a0f25b5871f806ce447e1..711fce7e08beea95d1870047452131e3bf5278dd 100644 (file)
 /git-quiltimport
 /git-read-tree
 /git-rebase
+/git-rebase--am
 /git-rebase--interactive
+/git-rebase--merge
 /git-receive-pack
 /git-reflog
 /git-relink
diff --git a/Documentation/RelNotes/1.7.5.1.txt b/Documentation/RelNotes/1.7.5.1.txt
new file mode 100644 (file)
index 0000000..cfd9b2a
--- /dev/null
@@ -0,0 +1,14 @@
+Git v1.7.5.1 Release Notes
+==========================
+
+Fixes since v1.7.5
+------------------
+
+ * The "--date=relative" output format used to say "X years, 12 months"
+   when it should have said "X+1 years".
+
+ * An error message from "git send-email" to diagnose a broken SMTP
+   connection configuration lacked a space between "hello=<smtp-domain>"
+   and "port=<smtp-server-port>".
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.6.txt b/Documentation/RelNotes/1.7.6.txt
new file mode 100644 (file)
index 0000000..3e08bd9
--- /dev/null
@@ -0,0 +1,79 @@
+Git v1.7.5 Release Notes (draft)
+========================
+
+Updates since v1.7.5
+--------------------
+
+ * Various git-svn updates.
+
+ * When an object "$tree:$path" does not exist, if $path does exist in the
+   subtree of $tree that corresponds to the subdirectory the user is in,
+   git now suggests using "$tree:./$path" in addition to the advice to use
+   the full path from the root of the working tree.
+
+ * "git blame" learned "--abbrev[=<n>]" option to control the minimum
+   number of hexdigits shown for commit object names.
+
+ * "git clean" used to fail on an empty directory that is not readable,
+   even though rmdir(2) could remove such a directory.  Now we attempt it
+   as the last resort.
+
+ * "git format-patch" learned "--quiet" option to suppress the output of
+   the names of generated files.
+
+ * "git merge" learned "-" as a short-hand for "the previous branch", just
+   like the way "git checkout -" works.
+
+ * "git pack-object" now takes core.bigfilethreashold into account, just
+   like fast-imoprt does.
+
+ * "git reflog" allows options like "--format=.." to be given.
+
+ * "git stash apply" can now apply to a working tree with changes as long
+   as there is no overlapping change as the stash being applied.
+
+ * "git stash apply @{99999}" now is diagnosed as an error, unless you
+   really have that many stash entries.
+
+Also contains various documentation updates.
+
+
+Fixes since v1.7.5
+------------------
+
+Unless otherwise noted, all the fixes in 1.7.5.X maintenance track are
+included in this release.
+
+ * The "--date=relative" output format used to say "X years, 12 months"
+   when it should have said "X+1 years".
+   (merge mg/x-years-12-months later)
+
+ * "git config" used to choke with an insanely long line.
+   (merge ef/maint-strbuf-init later)
+
+ * The "--dirstat" option of "diff" family of commands used to totally
+   ignore a change that only rearranged lines within a file.  Such a
+   change now counts as at least a minimum but non zero change.
+
+ * The "--dirstat" option of "diff" family of commands used to use the
+   pathname in the original, instead of the pathname in the result,
+   when renames are involved.
+   (merge jh/dirstat for the above two later)
+
+ * "git format-patch" when run with "--quiet" option used to produce a
+   nonsense result that consists of alternating empty output.
+   (merge early part of cn/format-patch-quiet later)
+
+ * "git stash -p --no-keep-index" and "git stash --no-keep-index -p" now
+   mean the same thing.
+   (merge dm/stash-k-i-p later)
+
+ * "git upload-pack" (hence "git push" over git native protocol) had a
+   subtle race condition that could lead to a deadlock.
+   (merge jk/maint-upload-pack-shallow later)
+
+---
+exec >/var/tmp/1
+echo O=$(git describe master)
+O=v1.7.5
+git shortlog --no-merges ^maint ^$O master
index 750c86d4f51b256faac1b1b5eb26275384d87886..480dd0a8617ced1f7bf24cda0bf23b7fc2c6c4f3 100644 (file)
@@ -442,8 +442,6 @@ for most projects as source code and other text files can still
 be delta compressed, but larger binary media files won't be.
 +
 Common unit suffixes of 'k', 'm', or 'g' are supported.
-+
-Currently only linkgit:git-fast-import[1] honors this setting.
 
 core.excludesfile::
        In addition to '.gitignore' (per-directory) and
@@ -643,7 +641,7 @@ branch.<name>.remote::
 
 branch.<name>.merge::
        Defines, together with branch.<name>.remote, the upstream branch
-       for the given branch. It tells 'git fetch'/'git pull' which
+       for the given branch. It tells 'git fetch'/'git pull'/'git rebase' which
        branch to merge and can also affect 'git push' (see push.default).
        When in branch <name>, it tells 'git fetch' the default
        refspec to be marked for merging in FETCH_HEAD. The value is
@@ -812,68 +810,7 @@ commit.template::
        "{tilde}/" is expanded to the value of `$HOME` and "{tilde}user/" to the
        specified user's home directory.
 
-diff.autorefreshindex::
-       When using 'git diff' to compare with work tree
-       files, do not consider stat-only change as changed.
-       Instead, silently run `git update-index --refresh` to
-       update the cached stat information for paths whose
-       contents in the work tree match the contents in the
-       index.  This option defaults to true.  Note that this
-       affects only 'git diff' Porcelain, and not lower level
-       'diff' commands such as 'git diff-files'.
-
-diff.external::
-       If this config variable is set, diff generation is not
-       performed using the internal diff machinery, but using the
-       given command.  Can be overridden with the `GIT_EXTERNAL_DIFF'
-       environment variable.  The command is called with parameters
-       as described under "git Diffs" in linkgit:git[1].  Note: if
-       you want to use an external diff program only on a subset of
-       your files, you might want to use linkgit:gitattributes[5] instead.
-
-diff.mnemonicprefix::
-       If set, 'git diff' uses a prefix pair that is different from the
-       standard "a/" and "b/" depending on what is being compared.  When
-       this configuration is in effect, reverse diff output also swaps
-       the order of the prefixes:
-`git diff`;;
-       compares the (i)ndex and the (w)ork tree;
-`git diff HEAD`;;
-        compares a (c)ommit and the (w)ork tree;
-`git diff --cached`;;
-       compares a (c)ommit and the (i)ndex;
-`git diff HEAD:file1 file2`;;
-       compares an (o)bject and a (w)ork tree entity;
-`git diff --no-index a b`;;
-       compares two non-git things (1) and (2).
-
-diff.noprefix::
-       If set, 'git diff' does not show any source or destination prefix.
-
-diff.renameLimit::
-       The number of files to consider when performing the copy/rename
-       detection; equivalent to the 'git diff' option '-l'.
-
-diff.renames::
-       Tells git to detect renames.  If set to any boolean value, it
-       will enable basic rename detection.  If set to "copies" or
-       "copy", it will detect copies, as well.
-
-diff.ignoreSubmodules::
-       Sets the default value of --ignore-submodules. Note that this
-       affects only 'git diff' Porcelain, and not lower level 'diff'
-       commands such as 'git diff-files'. 'git checkout' also honors
-       this setting when reporting uncommitted changes.
-
-diff.suppressBlankEmpty::
-       A boolean to inhibit the standard behavior of printing a space
-       before each empty output line. Defaults to false.
-
-diff.tool::
-       Controls which diff tool is used.  `diff.tool` overrides
-       `merge.tool` when used by linkgit:git-difftool[1] and has
-       the same valid values as `merge.tool` minus "tortoisemerge"
-       and plus "kompare".
+include::diff-config.txt[]
 
 difftool.<tool>.path::
        Override the path for the given tool.  This is useful in case
@@ -977,6 +914,16 @@ format.signoff::
     the rights to submit this work under the same open source license.
     Please see the 'SubmittingPatches' document for further discussion.
 
+filter.<driver>.clean::
+       The command which is used to convert the content of a worktree
+       file to a blob upon checkin.  See linkgit:gitattributes[5] for
+       details.
+
+filter.<driver>.smudge::
+       The command which is used to convert the content of a blob
+       object to a worktree file upon checkout.  See
+       linkgit:gitattributes[5] for details.
+
 gc.aggressiveWindow::
        The window size parameter used in the delta compression
        algorithm used by 'git gc --aggressive'.  This defaults
diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt
new file mode 100644 (file)
index 0000000..2b1605f
--- /dev/null
@@ -0,0 +1,92 @@
+diff.autorefreshindex::
+       When using 'git diff' to compare with work tree
+       files, do not consider stat-only change as changed.
+       Instead, silently run `git update-index --refresh` to
+       update the cached stat information for paths whose
+       contents in the work tree match the contents in the
+       index.  This option defaults to true.  Note that this
+       affects only 'git diff' Porcelain, and not lower level
+       'diff' commands such as 'git diff-files'.
+
+diff.external::
+       If this config variable is set, diff generation is not
+       performed using the internal diff machinery, but using the
+       given command.  Can be overridden with the `GIT_EXTERNAL_DIFF'
+       environment variable.  The command is called with parameters
+       as described under "git Diffs" in linkgit:git[1].  Note: if
+       you want to use an external diff program only on a subset of
+       your files, you might want to use linkgit:gitattributes[5] instead.
+
+diff.ignoreSubmodules::
+       Sets the default value of --ignore-submodules. Note that this
+       affects only 'git diff' Porcelain, and not lower level 'diff'
+       commands such as 'git diff-files'. 'git checkout' also honors
+       this setting when reporting uncommitted changes.
+
+diff.mnemonicprefix::
+       If set, 'git diff' uses a prefix pair that is different from the
+       standard "a/" and "b/" depending on what is being compared.  When
+       this configuration is in effect, reverse diff output also swaps
+       the order of the prefixes:
+`git diff`;;
+       compares the (i)ndex and the (w)ork tree;
+`git diff HEAD`;;
+        compares a (c)ommit and the (w)ork tree;
+`git diff --cached`;;
+       compares a (c)ommit and the (i)ndex;
+`git diff HEAD:file1 file2`;;
+       compares an (o)bject and a (w)ork tree entity;
+`git diff --no-index a b`;;
+       compares two non-git things (1) and (2).
+
+diff.noprefix::
+       If set, 'git diff' does not show any source or destination prefix.
+
+diff.renameLimit::
+       The number of files to consider when performing the copy/rename
+       detection; equivalent to the 'git diff' option '-l'.
+
+diff.renames::
+       Tells git to detect renames.  If set to any boolean value, it
+       will enable basic rename detection.  If set to "copies" or
+       "copy", it will detect copies, as well.
+
+diff.suppressBlankEmpty::
+       A boolean to inhibit the standard behavior of printing a space
+       before each empty output line. Defaults to false.
+
+diff.<driver>.command::
+       The custom diff driver command.  See linkgit:gitattributes[5]
+       for details.
+
+diff.<driver>.xfuncname::
+       The regular expression that the diff driver should use to
+       recognize the hunk header.  A built-in pattern may also be used.
+       See linkgit:gitattributes[5] for details.
+
+diff.<driver>.binary::
+       Set this option to true to make the diff driver treat files as
+       binary.  See linkgit:gitattributes[5] for details.
+
+diff.<driver>.textconv::
+       The command that the diff driver should call to generate the
+       text-converted version of a file.  The result of the
+       conversion is used to generate a human-readable diff.  See
+       linkgit:gitattributes[5] for details.
+
+diff.<driver>.wordregex::
+       The regular expression that the diff driver should use to
+       split words in a line.  See linkgit:gitattributes[5] for
+       details.
+
+diff.<driver>.cachetextconv::
+       Set this option to true to make the diff driver cache the text
+       conversion outputs.  See linkgit:gitattributes[5] for details.
+
+diff.tool::
+       The diff tool to be used by linkgit:git-difftool[1].  This
+       option overrides `merge.tool`, and has the same valid built-in
+       values as `merge.tool` minus "tortoisemerge" and plus
+       "kompare".  Any other value is treated as a custom diff tool,
+       and there must be a corresponding `difftool.<tool>.cmd`
+       option.
index c93124be79809e36d9a29fd69ce77cd7f22413e1..34f01458c296ce68bcba4c08177aba127fc2333b 100644 (file)
@@ -72,6 +72,10 @@ endif::git-format-patch[]
        a cut-off percent (3% by default) are not shown. The cut-off percent
        can be set with `--dirstat=<limit>`. Changes in a child directory are not
        counted for the parent directory, unless `--cumulative` is used.
++
+Note that the `--dirstat` option computes the changes while ignoring
+the amount of pure code movements within a file.  In other words,
+rearranging lines in a file is not counted as much as other changes.
 
 --dirstat-by-file[=<limit>]::
        Same as `--dirstat`, but counts changed files instead of lines.
@@ -259,6 +263,19 @@ endif::git-log[]
        projects, so use it with caution.  Giving more than one
        `-C` option has the same effect.
 
+-D::
+--irreversible-delete::
+       Omit the preimage for deletes, i.e. print only the header but not
+       the diff between the preimage and `/dev/null`. The resulting patch
+       is not meant to be applied with `patch` nor `git apply`; this is
+       solely for people who want to just concentrate on reviewing the
+       text after the change. In addition, the output obviously lack
+       enough information to apply such a patch in reverse, even manually,
+       hence the name of the option.
++
+When used together with `-B`, omit also the preimage in the deletion part
+of a delete/create pair.
+
 -l<num>::
        The `-M` and `-C` options require O(n^2) processing time where n
        is the number of potential rename/copy targets.  This
index c4d1ff86c90d22ffea3fff173ee6b76d88013dab..bb8edb4abc5adc8a7b9d46d839415997919871af 100644 (file)
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental] [-L n,m]
-           [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
+           [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>] [--abbrev=<n>]
            [<rev> | --contents <file> | --reverse <rev>] [--] <file>
 
 DESCRIPTION
@@ -73,6 +73,11 @@ include::blame-options.txt[]
        Ignore whitespace when comparing the parent's version and
        the child's to find where the lines came from.
 
+--abbrev=<n>::
+       Instead of using the default 7+1 hexadecimal digits as the
+       abbreviated object name, use <n>+1 digits. Note that 1 column
+       is used for a caret to mark the boundary commit.
+
 
 THE PORCELAIN FORMAT
 --------------------
index a5525e9aa87e8c2c724542bc9e54dfa7e34548fd..f4e959d662fab9ca36753be59d547cf206129da0 100644 (file)
@@ -20,7 +20,7 @@ SYNOPSIS
                   [--ignore-if-in-upstream]
                   [--subject-prefix=Subject-Prefix]
                   [--to=<email>] [--cc=<email>]
-                  [--cover-letter]
+                  [--cover-letter] [--quiet]
                   [<common diff options>]
                   [ <since> | <revision range> ]
 
@@ -196,6 +196,9 @@ will want to ensure that threading is disabled for `git send-email`.
 Note that the leading character does not have to be a dot; for example,
 you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
 
+--quiet::
+       Do not print the names of the generated files to standard output.
+
 --no-binary::
        Do not output contents of changes in binary files, instead
        display a notice that those files changed.  Patches generated
index 620d50e71f1a04f587079180ff2d987521d38786..9a075bc4d24d59c7b585e204e6feb50326c762f3 100644 (file)
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git rebase' [-i | --interactive] [options] [--onto <newbase>]
-       <upstream> [<branch>]
+       [<upstream>] [<branch>]
 'git rebase' [-i | --interactive] [options] --onto <newbase>
        --root [<branch>]
 
@@ -21,6 +21,12 @@ If <branch> is specified, 'git rebase' will perform an automatic
 `git checkout <branch>` before doing anything else.  Otherwise
 it remains on the current branch.
 
+If <upstream> is not specified, the upstream configured in
+branch.<name>.remote and branch.<name>.merge options will be used; see
+linkgit:git-config[1] for details.  If you are currently not on any
+branch or if the current branch does not have a configured upstream,
+the rebase will abort.
+
 All changes made by commits in the current branch but that are not
 in <upstream> are saved to a temporary area.  This is the same set
 of commits that would be shown by `git log <upstream>..HEAD` (or
@@ -217,7 +223,8 @@ leave out at most one of A and B, in which case it defaults to HEAD.
 
 <upstream>::
        Upstream branch to compare against.  May be any valid commit,
-       not just an existing branch name.
+       not just an existing branch name. Defaults to the configured
+       upstream for the current branch.
 
 <branch>::
        Working branch; defaults to HEAD.
index 30a67486d2dc9eb4169a9ba5ebd5db513a3a84f8..d07f5131aa5213c0d83afbd285446b964447f0bc 100644 (file)
@@ -145,17 +145,6 @@ Skip "branches" and "tags" of first level directories;;
 ------------------------------------------------------------------------
 --
 
---use-log-author;;
-       When retrieving svn commits into git (as part of fetch, rebase, or
-       dcommit operations), look for the first From: or Signed-off-by: line
-       in the log message and use that as the author string.
---add-author-from;;
-       When committing to svn from git (as part of commit or dcommit
-       operations), if the existing log message doesn't already have a
-       From: or Signed-off-by: line, append a From: line based on the
-       git commit's author string.  If you use this, then --use-log-author
-       will retrieve a valid author string for all commits.
-
 'clone'::
        Runs 'init' and 'fetch'.  It will automatically create a
        directory based on the basename of the URL passed to it;
@@ -350,6 +339,8 @@ Any other arguments are passed directly to 'git log'
        Empty directories are automatically recreated when using
        "git svn clone" and "git svn rebase", so "mkdirs" is intended
        for use after commands like "git checkout" or "git reset".
+       (See the svn-remote.<name>.automkdirs config file option for
+       more information.)
 
 'commit-diff'::
        Commits the diff of two tree-ish arguments from the
@@ -572,6 +563,17 @@ repository that will be fetched from.
 For 'branch' and 'tag', display the urls that will be used for copying when
 creating the branch or tag.
 
+--use-log-author::
+       When retrieving svn commits into git (as part of 'fetch', 'rebase', or
+       'dcommit' operations), look for the first `From:` or `Signed-off-by:` line
+       in the log message and use that as the author string.
+--add-author-from::
+       When committing to svn from git (as part of 'commit-diff', 'set-tree' or 'dcommit'
+       operations), if the existing log message doesn't already have a
+       `From:` or `Signed-off-by:` line, append a `From:` line based on the
+       git commit's author string.  If you use this, then `--use-log-author`
+       will retrieve a valid author string for all commits.
+
 
 ADVANCED OPTIONS
 ----------------
@@ -680,6 +682,14 @@ svn.pathnameencoding::
        locales to avoid corrupted file names with non-ASCII characters.
        Valid encodings are the ones supported by Perl's Encode module.
 
+svn-remote.<name>.automkdirs::
+       Normally, the "git svn clone" and "git svn rebase" commands
+       attempt to recreate empty directories that are in the
+       Subversion repository.  If this option is set to "false", then
+       empty directories will only be created if the "git svn mkdirs"
+       command is run explicitly.  If unset, 'git svn' assumes this
+       option to be "true".
+
 Since the noMetadata, rewriteRoot, rewriteUUID, useSvnsyncProps and useSvmProps
 options all affect the metadata generated and used by 'git svn'; they
 *must* be set in the configuration file before any history is imported
index 68691b3c124d27c74401fa736a318dda2494aede..7f48227494da7fe1bd57883d41e10b487c3f2fbf 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.5
+DEF_VER=v1.7.5.GIT
 
 LF='
 '
index cbc3fce2d573ac313ee1b8f19749432cff3b31b5..3a1fe20ff2219efc778d1d7c415c2ca9e8263ccd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -323,9 +323,7 @@ GCOV = gcov
 
 export TCL_PATH TCLTK_PATH
 
-# sparse is architecture-neutral, which means that we need to tell it
-# explicitly what architecture to check for. Fix this up for yours..
-SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
+SPARSE_FLAGS =
 
 
 
@@ -370,7 +368,6 @@ SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-pull.sh
 SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-rebase--interactive.sh
 SCRIPT_SH += git-rebase.sh
 SCRIPT_SH += git-repack.sh
 SCRIPT_SH += git-request-pull.sh
@@ -380,6 +377,9 @@ SCRIPT_SH += git-web--browse.sh
 
 SCRIPT_LIB += git-mergetool--lib
 SCRIPT_LIB += git-parse-remote
+SCRIPT_LIB += git-rebase--am
+SCRIPT_LIB += git-rebase--interactive
+SCRIPT_LIB += git-rebase--merge
 SCRIPT_LIB += git-sh-setup
 
 SCRIPT_PERL += git-add--interactive.perl
@@ -527,6 +527,7 @@ LIB_H += list-objects.h
 LIB_H += ll-merge.h
 LIB_H += log-tree.h
 LIB_H += mailmap.h
+LIB_H += merge-file.h
 LIB_H += merge-recursive.h
 LIB_H += notes.h
 LIB_H += notes-cache.h
@@ -924,6 +925,7 @@ ifeq ($(uname_O),Cygwin)
        X = .exe
        COMPAT_OBJS += compat/cygwin.o
        UNRELIABLE_FSTAT = UnfortunatelyYes
+       SPARSE_FLAGS = -isystem /usr/include/w32api -Wno-one-bit-signed-bitfield
 endif
 ifeq ($(uname_S),FreeBSD)
        NEEDS_LIBICONV = YesPlease
@@ -1177,6 +1179,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        EXTLIBS += -lws2_32
        PTHREAD_LIBS =
        X = .exe
+       SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
 ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
        htmldir=doc/git/html/
        prefix =
@@ -1580,6 +1583,7 @@ ifndef V
        QUIET_LNCP     = @echo '   ' LN/CP $@;
        QUIET_XGETTEXT = @echo '   ' XGETTEXT $@;
        QUIET_GCOV     = @echo '   ' GCOV $@;
+       QUIET_SP       = @echo '   ' SP $<;
        QUIET_SUBDIR0  = +@subdir=
        QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
                         $(MAKE) $(PRINT_DIR) -C $$subdir
@@ -1675,17 +1679,17 @@ strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
 
 git.o: common-cmds.h
-git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \
+git.sp git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \
        '-DGIT_HTML_PATH="$(htmldir_SQ)"'
 
 git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
 
-help.o: common-cmds.h
+help.sp help.o: common-cmds.h
 
-builtin/help.o: common-cmds.h
-builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
+builtin/help.sp builtin/help.o: common-cmds.h
+builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
        '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
@@ -1971,30 +1975,34 @@ $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) \
 test-svn-fe.o: vcs-svn/svndump.h
 endif
 
-exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
+exec_cmd.sp exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \
        '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
        '-DBINDIR="$(bindir_relative_SQ)"' \
        '-DPREFIX="$(prefix_SQ)"'
 
-builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
+builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
        -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
 
-config.s config.o: EXTRA_CPPFLAGS = -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
+config.sp config.s config.o: EXTRA_CPPFLAGS = \
+       -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
 
-attr.s attr.o: EXTRA_CPPFLAGS = -DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
+attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
+       -DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
 
-http.s http.o: EXTRA_CPPFLAGS = -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
+http.sp http.s http.o: EXTRA_CPPFLAGS = \
+       -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
 
 ifdef NO_EXPAT
-http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
+http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
 endif
 
 ifdef NO_REGEX
-compat/regex/regex.o: EXTRA_CPPFLAGS = -DGAWK -DNO_MBSUPPORT
+compat/regex/regex.sp compat/regex/regex.o: EXTRA_CPPFLAGS = \
+       -DGAWK -DNO_MBSUPPORT
 endif
 
 ifdef USE_NED_ALLOCATOR
-compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
+compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
        -DNDEBUG -DOVERRIDE_STRDUP -DREPLACE_SYSTEM_ALLOCATOR
 endif
 
@@ -2160,13 +2168,20 @@ test-%$X: test-%.o $(GITLIBS)
 check-sha1:: test-sha1$X
        ./test-sha1.sh
 
+SP_OBJ = $(patsubst %.o,%.sp,$(C_OBJ))
+
+$(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
+       $(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \
+               $(SPARSE_FLAGS) $<
+
+.PHONY: sparse $(SP_OBJ)
+sparse: $(SP_OBJ)
+
 check: common-cmds.h
-       if sparse; \
+       @if sparse; \
        then \
-               for i in $(patsubst %.o, %.c, $(GIT_OBJS)); \
-               do \
-                       sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
-               done; \
+               echo 2>&1 "Use 'make sparse' instead"; \
+               $(MAKE) --no-print-directory sparse; \
        else \
                echo 2>&1 "Did you mean 'make test'?"; \
                exit 1; \
index 540b756d2f64d8c8ebf927a707b9b2cc0a4c6151..5fcc4ef74770e8587a1469fff5e3f5610dabf0e1 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.5.txt
\ No newline at end of file
+Documentation/RelNotes/1.7.6.txt
\ No newline at end of file
diff --git a/attr.c b/attr.c
index 0e28ba871f9ba0da129610019cd0d0246f3a15f0..f6b3f7e850f9fcf5672031049ef1d6f43e619f63 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -465,7 +465,7 @@ static void drop_attr_stack(void)
        }
 }
 
-const char *git_etc_gitattributes(void)
+static const char *git_etc_gitattributes(void)
 {
        static const char *system_wide;
        if (!system_wide)
@@ -473,7 +473,7 @@ const char *git_etc_gitattributes(void)
        return system_wide;
 }
 
-int git_attr_system(void)
+static int git_attr_system(void)
 {
        return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
 }
index f6b03f750a0b69ef835caa0a2e4988f9a08abb85..463978817871b534dcdfb3c5c630ccd731d9733a 100644 (file)
@@ -41,6 +41,7 @@ static int reverse;
 static int blank_boundary;
 static int incremental;
 static int xdl_opts;
+static int abbrev = -1;
 
 static enum date_mode blame_date_mode = DATE_ISO8601;
 static size_t blame_date_width;
@@ -1670,7 +1671,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
        cp = nth_line(sb, ent->lno);
        for (cnt = 0; cnt < ent->num_lines; cnt++) {
                char ch;
-               int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8;
+               int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : abbrev;
 
                if (suspect->commit->object.flags & UNINTERESTING) {
                        if (blank_boundary)
@@ -2310,6 +2311,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                { OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
                { OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback },
                OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback),
+               OPT__ABBREV(&abbrev),
                OPT_END()
        };
 
@@ -2345,6 +2347,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 parse_done:
        argc = parse_options_end(&ctx);
 
+       if (abbrev == -1)
+               abbrev = default_abbrev;
+       /* one more abbrev length is needed for the boundary commit */
+       abbrev++;
+
        if (revs_file && read_ancestry(revs_file))
                die_errno("reading graft file '%s' failed", revs_file);
 
index 0d2a3e9fa2023cc673f1f6d9e17d3deeca1c7e9d..be6417d166abf428d379a70b9d67f894da4641d1 100644 (file)
@@ -163,6 +163,9 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
        }
 
        if (read_stdin) {
+               int saved_nrl = 0;
+               int saved_dcctc = 0;
+
                if (opt->diffopt.detect_rename)
                        opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
                                               DIFF_SETUP_USE_CACHE);
@@ -173,9 +176,16 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
                                fputs(line, stdout);
                                fflush(stdout);
                        }
-                       else
+                       else {
                                diff_tree_stdin(line);
+                               if (saved_nrl < opt->diffopt.needed_rename_limit)
+                                       saved_nrl = opt->diffopt.needed_rename_limit;
+                               if (opt->diffopt.degraded_cc_to_c)
+                                       saved_dcctc = 1;
+                       }
                }
+               opt->diffopt.degraded_cc_to_c = saved_dcctc;
+               opt->diffopt.needed_rename_limit = saved_nrl;
        }
 
        return diff_result_code(&opt->diffopt, 0);
index 717fa1a3414e18cbdd4c6eb1e0785761687688d7..14bd14fce0fa6b9c9b047142d23d4a2237b57a36 100644 (file)
@@ -202,7 +202,6 @@ static void refresh_index_quietly(void)
 
 static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
 {
-       int result;
        unsigned int options = 0;
 
        while (1 < argc && argv[1][0] == '-') {
@@ -236,8 +235,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
                perror("read_cache_preload");
                return -1;
        }
-       result = run_diff_files(revs, options);
-       return diff_result_code(&revs->diffopt, result);
+       return run_diff_files(revs, options);
 }
 
 int cmd_diff(int argc, const char **argv, const char *prefix)
index 31f001f1059ec533ee62d6bd951b068d7f924f50..e40451ffb4ecd31107bfe51817cdce18e1dfe859 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "delta.h"
 #include "pack.h"
 #include "csum-file.h"
index 9db43edb063bbcb4da3b213d92d14b5c92aa4cfb..55abe07610bce0a959b1878be128e09906f8fea4 100644 (file)
@@ -49,13 +49,8 @@ static int parse_decoration_style(const char *var, const char *value)
        return -1;
 }
 
-static void cmd_log_init(int argc, const char **argv, const char *prefix,
-                        struct rev_info *rev, struct setup_revision_opt *opt)
+static void cmd_log_init_defaults(struct rev_info *rev)
 {
-       int i;
-       int decoration_given = 0;
-       struct userformat_want w;
-
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
        if (fmt_pretty)
@@ -68,7 +63,14 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
 
        if (default_date_mode)
                rev->date_mode = parse_date_format(default_date_mode);
+}
 
+static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
+                        struct rev_info *rev, struct setup_revision_opt *opt)
+{
+       int i;
+       int decoration_given = 0;
+       struct userformat_want w;
        /*
         * Check for -h before setup_revisions(), or "git log -h" will
         * fail when run without a git directory.
@@ -128,6 +130,13 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        setup_pager();
 }
 
+static void cmd_log_init(int argc, const char **argv, const char *prefix,
+                        struct rev_info *rev, struct setup_revision_opt *opt)
+{
+       cmd_log_init_defaults(rev);
+       cmd_log_init_finish(argc, argv, prefix, rev, opt);
+}
+
 /*
  * This gives a rough estimate for how many commits we
  * will print out in the list.
@@ -247,6 +256,8 @@ static void finish_early_output(struct rev_info *rev)
 static int cmd_log_walk(struct rev_info *rev)
 {
        struct commit *commit;
+       int saved_nrl = 0;
+       int saved_dcctc = 0;
 
        if (rev->early_output)
                setup_early_output(rev);
@@ -277,7 +288,14 @@ static int cmd_log_walk(struct rev_info *rev)
                }
                free_commit_list(commit->parents);
                commit->parents = NULL;
+               if (saved_nrl < rev->diffopt.needed_rename_limit)
+                       saved_nrl = rev->diffopt.needed_rename_limit;
+               if (rev->diffopt.degraded_cc_to_c)
+                       saved_dcctc = 1;
        }
+       rev->diffopt.degraded_cc_to_c = saved_dcctc;
+       rev->diffopt.needed_rename_limit = saved_nrl;
+
        if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
            DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
                return 02;
@@ -486,16 +504,11 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
        rev.verbose_header = 1;
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
-       cmd_log_init(argc, argv, prefix, &rev, &opt);
-
-       /*
-        * This means that we override whatever commit format the user gave
-        * on the cmd line.  Sad, but cmd_log_init() currently doesn't
-        * allow us to set a different default.
-        */
+       cmd_log_init_defaults(&rev);
        rev.commit_format = CMIT_FMT_ONELINE;
        rev.use_terminator = 1;
        rev.always_show_header = 1;
+       cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
 
        return cmd_log_walk(&rev);
 }
@@ -623,7 +636,7 @@ static FILE *realstdout = NULL;
 static const char *output_directory = NULL;
 static int outdir_offset;
 
-static int reopen_stdout(struct commit *commit, struct rev_info *rev)
+static int reopen_stdout(struct commit *commit, struct rev_info *rev, int quiet)
 {
        struct strbuf filename = STRBUF_INIT;
        int suffix_len = strlen(fmt_patch_suffix) + 1;
@@ -639,7 +652,7 @@ static int reopen_stdout(struct commit *commit, struct rev_info *rev)
 
        get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);
 
-       if (!DIFF_OPT_TST(&rev->diffopt, QUICK))
+       if (!quiet)
                fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
 
        if (freopen(filename.buf, "w", stdout) == NULL)
@@ -718,7 +731,8 @@ static void print_signature(void)
 static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              int numbered, int numbered_files,
                              struct commit *origin,
-                             int nr, struct commit **list, struct commit *head)
+                             int nr, struct commit **list, struct commit *head,
+                             int quiet)
 {
        const char *committer;
        const char *subject_start = NULL;
@@ -754,7 +768,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
                        sha1_to_hex(head->object.sha1), committer, committer);
        }
 
-       if (!use_stdout && reopen_stdout(commit, rev))
+       if (!use_stdout && reopen_stdout(commit, rev, quiet))
                return;
 
        if (commit) {
@@ -995,6 +1009,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        char *add_signoff = NULL;
        struct strbuf buf = STRBUF_INIT;
        int use_patch_format = 0;
+       int quiet = 0;
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
                            "use [PATCH n/m] even with a single patch",
@@ -1050,6 +1065,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                            PARSE_OPT_OPTARG, thread_callback },
                OPT_STRING(0, "signature", &signature, "signature",
                            "add a signature"),
+               OPT_BOOLEAN(0, "quiet", &quiet,
+                           "don't print the patch filenames"),
                OPT_END()
        };
 
@@ -1259,7 +1276,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                if (thread)
                        gen_message_id(&rev, "cover");
                make_cover_letter(&rev, use_stdout, numbered, numbered_files,
-                                 origin, nr, list, head);
+                                 origin, nr, list, head, quiet);
                total++;
                start_number--;
        }
@@ -1305,7 +1322,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                }
 
                if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
-                                                &rev))
+                                                &rev, quiet))
                        die(_("Failed to create output files"));
                shown = log_tree_commit(&rev, commit);
                free(commit->buffer);
index 19917426fba19cf60b838ff9b07d20b5e44259a5..897a563bc6662e108c29656d633b7400384154f9 100644 (file)
@@ -3,6 +3,7 @@
 #include "xdiff-interface.h"
 #include "blob.h"
 #include "exec_cmd.h"
+#include "merge-file.h"
 
 static const char merge_tree_usage[] = "git merge-tree <base-tree> <branch1> <branch2>";
 static int resolve_directories = 1;
@@ -54,8 +55,6 @@ static const char *explanation(struct merge_list *entry)
        return "removed in remote";
 }
 
-extern void *merge_file(const char *, struct blob *, struct blob *, struct blob *, unsigned long *);
-
 static void *result(struct merge_list *entry, unsigned long *size)
 {
        enum object_type type;
index d54e7ddbb12286beb4f9622864f2eeaa79453d32..0bdd19a13784590c107108443f449d37fd7509d8 100644 (file)
@@ -1062,9 +1062,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (!allow_fast_forward && fast_forward_only)
                die(_("You cannot combine --no-ff with --ff-only."));
 
-       if (!argc && !abort_current_merge && default_to_upstream)
-               argc = setup_with_upstream(&argv);
-
+       if (!abort_current_merge) {
+               if (!argc && default_to_upstream)
+                       argc = setup_with_upstream(&argv);
+               else if (argc == 1 && !strcmp(argv[0], "-"))
+                       argv[0] = "@{-1}";
+       }
        if (!argc)
                usage_with_options(builtin_merge_usage,
                        builtin_merge_options);
index b0503b202afb4356caaca794518fb4e21082a48f..f402a843bb5ee23360d29bdbbc6cc9c5b9c72008 100644 (file)
@@ -1142,8 +1142,12 @@ static void get_object_details(void)
                sorted_by_offset[i] = objects + i;
        qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
 
-       for (i = 0; i < nr_objects; i++)
-               check_object(sorted_by_offset[i]);
+       for (i = 0; i < nr_objects; i++) {
+               struct object_entry *entry = sorted_by_offset[i];
+               check_object(entry);
+               if (big_file_threshold <= entry->size)
+                       entry->no_try_delta = 1;
+       }
 
        free(sorted_by_offset);
 }
index f5efc67c9cad24fe54d5c6ab7257d38a4b1727ac..b6f4b0eb03b66dda2f691ff5c80b78321c1b701d 100644 (file)
@@ -29,9 +29,6 @@ static int compare_by_number(const void *a1, const void *a2)
                return -1;
 }
 
-const char *format_subject(struct strbuf *sb, const char *msg,
-                          const char *line_separator);
-
 static void insert_one_record(struct shortlog *log,
                              const char *author,
                              const char *oneline)
index da695815e26c281cbacfbf865dfa72da44df9f19..1abcd9e02e64022e2619db3de40c7b3a731d4479 100644 (file)
@@ -12,16 +12,6 @@ static const char* show_branch_usage[] = {
 };
 
 static int showbranch_use_color = -1;
-static char column_colors[][COLOR_MAXLEN] = {
-       GIT_COLOR_RED,
-       GIT_COLOR_GREEN,
-       GIT_COLOR_YELLOW,
-       GIT_COLOR_BLUE,
-       GIT_COLOR_MAGENTA,
-       GIT_COLOR_CYAN,
-};
-
-#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))
 
 static int default_num;
 static int default_alloc;
@@ -37,7 +27,7 @@ static const char **default_arg;
 static const char *get_color_code(int idx)
 {
        if (showbranch_use_color)
-               return column_colors[idx];
+               return column_colors_ansi[idx % column_colors_ansi_max];
        return "";
 }
 
@@ -892,7 +882,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                                for (j = 0; j < i; j++)
                                        putchar(' ');
                                printf("%s%c%s [%s] ",
-                                      get_color_code(i % COLUMN_COLORS_MAX),
+                                      get_color_code(i),
                                       is_head ? '*' : '!',
                                       get_color_reset_code(), ref_name[i]);
                        }
@@ -954,7 +944,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                                else
                                        mark = '+';
                                printf("%s%c%s",
-                                      get_color_code(i % COLUMN_COLORS_MAX),
+                                      get_color_code(i),
                                       mark, get_color_reset_code());
                        }
                        putchar(' ');
diff --git a/cache.h b/cache.h
index 2674f4cf5a74aaa8e6137985d552d7b6123a432c..28899b7b7881474eed4a6f3b6fda8db79d5cbc9c 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -573,6 +573,7 @@ extern int core_compression_seen;
 extern size_t packed_git_window_size;
 extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
+extern unsigned long big_file_threshold;
 extern int read_replace_refs;
 extern int fsync_object_files;
 extern int core_preload_index;
diff --git a/color.c b/color.c
index 417cf8fb2812b09ad4f5bfa2674b35d7e11f32b9..3db214c24720496f13481b718e46810c21f53b8d 100644 (file)
--- a/color.c
+++ b/color.c
@@ -3,6 +3,28 @@
 
 int git_use_color_default = 0;
 
+/*
+ * The list of available column colors.
+ */
+const char *column_colors_ansi[] = {
+       GIT_COLOR_RED,
+       GIT_COLOR_GREEN,
+       GIT_COLOR_YELLOW,
+       GIT_COLOR_BLUE,
+       GIT_COLOR_MAGENTA,
+       GIT_COLOR_CYAN,
+       GIT_COLOR_BOLD_RED,
+       GIT_COLOR_BOLD_GREEN,
+       GIT_COLOR_BOLD_YELLOW,
+       GIT_COLOR_BOLD_BLUE,
+       GIT_COLOR_BOLD_MAGENTA,
+       GIT_COLOR_BOLD_CYAN,
+       GIT_COLOR_RESET,
+};
+
+/* Ignore the RESET at the end when giving the size */
+const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
+
 static int parse_color(const char *name, int len)
 {
        static const char * const color_names[] = {
diff --git a/color.h b/color.h
index c0528cf08713ac8e101cfdeac2b3de193a0c5094..68a926a2cdfb870ae0da0bfbc4c5b36681609911 100644 (file)
--- a/color.h
+++ b/color.h
@@ -53,6 +53,9 @@ struct strbuf;
  */
 extern int git_use_color_default;
 
+/* A default list of colors to use for commit graphs and show-branch output */
+extern const char *column_colors_ansi[];
+extern const int column_colors_ansi_max;
 
 /*
  * Use this instead of git_default_config if you need the value of color.ui.
index 41985130d1473573af2cfd4ca97a579e999b0c0b..b3c3bb70c5e737ed18df7ca665c85e339e1f3292 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -90,6 +90,8 @@ extern char *logmsg_reencode(const struct commit *commit,
 extern char *reencode_commit_message(const struct commit *commit,
                                     const char **encoding_p);
 extern void get_commit_format(const char *arg, struct rev_info *);
+extern const char *format_subject(struct strbuf *sb, const char *msg,
+                                 const char *line_separator);
 extern void userformat_find_requirements(const char *fmt, struct userformat_want *w);
 extern void format_commit_message(const struct commit *commit,
                                  const char *format, struct strbuf *sb,
index 0abcada9381a3e6638f94bcf41bf9ee7b96f4de8..5f9ec2894570d23f8b91327374a4d82dd46cbca3 100644 (file)
--- a/config.c
+++ b/config.c
@@ -133,23 +133,21 @@ static int get_next_char(void)
 
 static char *parse_value(void)
 {
-       static char value[1024];
-       int quote = 0, comment = 0, len = 0, space = 0;
+       static struct strbuf value = STRBUF_INIT;
+       int quote = 0, comment = 0, space = 0;
 
+       strbuf_reset(&value);
        for (;;) {
                int c = get_next_char();
-               if (len >= sizeof(value) - 1)
-                       return NULL;
                if (c == '\n') {
                        if (quote)
                                return NULL;
-                       value[len] = 0;
-                       return value;
+                       return value.buf;
                }
                if (comment)
                        continue;
                if (isspace(c) && !quote) {
-                       if (len)
+                       if (value.len)
                                space++;
                        continue;
                }
@@ -160,7 +158,7 @@ static char *parse_value(void)
                        }
                }
                for (; space; space--)
-                       value[len++] = ' ';
+                       strbuf_addch(&value, ' ');
                if (c == '\\') {
                        c = get_next_char();
                        switch (c) {
@@ -182,14 +180,14 @@ static char *parse_value(void)
                        default:
                                return NULL;
                        }
-                       value[len++] = c;
+                       strbuf_addch(&value, c);
                        continue;
                }
                if (c == '"') {
                        quote = 1-quote;
                        continue;
                }
-               value[len++] = c;
+               strbuf_addch(&value, c);
        }
 }
 
@@ -567,6 +565,12 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.bigfilethreshold")) {
+               long n = git_config_int(var, value);
+               big_file_threshold = 0 < n ? n : 0;
+               return 0;
+       }
+
        if (!strcmp(var, "core.packedgitlimit")) {
                packed_git_limit = git_config_int(var, value);
                return 0;
index 840ae38760a5de84b369b208a52cc579ce478378..9150ea60267913dd17e749afdf2bca348646a165 100755 (executable)
@@ -1,6 +1,6 @@
 #!bash
 #
-# bash completion support for core Git.
+# bash/zsh completion support for core Git.
 #
 # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
 # Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
 # To use these routines:
 #
 #    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
-#    2) Added the following line to your .bashrc:
-#        source ~/.git-completion.sh
-#
-#       Or, add the following lines to your .zshrc:
-#        autoload bashcompinit
-#        bashcompinit
+#    2) Add the following line to your .bashrc/.zshrc:
 #        source ~/.git-completion.sh
 #
 #    3) Consider changing your PS1 to also show the current branch:
-#        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
 #
 #       The argument to __git_ps1 will be displayed only if you
 #       are currently in a git repository.  The %s token will be
 #       git@vger.kernel.org
 #
 
+if [[ -n ${ZSH_VERSION-} ]]; then
+       autoload -U +X bashcompinit && bashcompinit
+fi
+
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
diff --git a/date.c b/date.c
index 00f9eb5d0b9730107a8e08e92eb04d4cc9233595..896fbb48060c673b8dc2f2aa6ea3de3c1042fbd2 100644 (file)
--- a/date.c
+++ b/date.c
@@ -129,8 +129,9 @@ const char *show_date_relative(unsigned long time, int tz,
        }
        /* Give years and months for 5 years or so */
        if (diff < 1825) {
-               unsigned long years = diff / 365;
-               unsigned long months = (diff % 365 + 15) / 30;
+               unsigned long totalmonths = (diff * 12 * 2 + 365) / (365 * 2);
+               unsigned long years = totalmonths / 12;
+               unsigned long months = totalmonths % 12;
                int n;
                n = snprintf(timebuf, timebuf_size, "%lu year%s",
                                years, (years > 1 ? "s" : ""));
diff --git a/diff.c b/diff.c
index 9fa841010cc21bebc464926b15232b2aace0f5ba..3b40e597d5793d13944f9604e5197ac216eb3a3e 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -581,11 +581,14 @@ static void emit_rewrite_diff(const char *name_a,
                line_prefix, metainfo, a_name.buf, name_a_tab, reset,
                line_prefix, metainfo, b_name.buf, name_b_tab, reset,
                line_prefix, fraginfo);
-       print_line_count(o->file, lc_a);
+       if (!o->irreversible_delete)
+               print_line_count(o->file, lc_a);
+       else
+               fprintf(o->file, "?,?");
        fprintf(o->file, " +");
        print_line_count(o->file, lc_b);
        fprintf(o->file, " @@%s\n", reset);
-       if (lc_a)
+       if (lc_a && !o->irreversible_delete)
                emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
        if (lc_b)
                emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
@@ -1538,8 +1541,36 @@ static void show_dirstat(struct diff_options *options)
                struct diff_filepair *p = q->queue[i];
                const char *name;
                unsigned long copied, added, damage;
+               int content_changed;
+
+               name = p->two->path ? p->two->path : p->one->path;
+
+               if (p->one->sha1_valid && p->two->sha1_valid)
+                       content_changed = hashcmp(p->one->sha1, p->two->sha1);
+               else
+                       content_changed = 1;
+
+               if (!content_changed) {
+                       /*
+                        * The SHA1 has not changed, so pre-/post-content is
+                        * identical. We can therefore skip looking at the
+                        * file contents altogether.
+                        */
+                       damage = 0;
+                       goto found_damage;
+               }
 
-               name = p->one->path ? p->one->path : p->two->path;
+               if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) {
+                       /*
+                        * In --dirstat-by-file mode, we don't really need to
+                        * look at the actual file contents at all.
+                        * The fact that the SHA1 changed is enough for us to
+                        * add this file to the list of results
+                        * (with each file contributing equal damage).
+                        */
+                       damage = 1;
+                       goto found_damage;
+               }
 
                if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
                        diff_populate_filespec(p->one, 0);
@@ -1563,14 +1594,18 @@ static void show_dirstat(struct diff_options *options)
                /*
                 * Original minus copied is the removed material,
                 * added is the new material.  They are both damages
-                * made to the preimage. In --dirstat-by-file mode, count
-                * damaged files, not damaged lines. This is done by
-                * counting only a single damaged line per file.
+                * made to the preimage.
+                * If the resulting damage is zero, we know that
+                * diffcore_count_changes() considers the two entries to
+                * be identical, but since content_changed is true, we
+                * know that there must have been _some_ kind of change,
+                * so we force all entries to have damage > 0.
                 */
                damage = (p->one->size - copied) + added;
-               if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0)
+               if (!damage)
                        damage = 1;
 
+found_damage:
                ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
                dir.files[dir.nr].name = name;
                dir.files[dir.nr].changed = damage;
@@ -1949,7 +1984,11 @@ static void builtin_diff(const char *name_a,
                }
        }
 
-       if (!DIFF_OPT_TST(o, TEXT) &&
+       if (o->irreversible_delete && lbl[1][0] == '/') {
+               fprintf(o->file, "%s", header.buf);
+               strbuf_reset(&header);
+               goto free_ab_and_return;
+       } else if (!DIFF_OPT_TST(o, TEXT) &&
            ( (!textconv_one && diff_filespec_is_binary(one)) ||
              (!textconv_two && diff_filespec_is_binary(two)) )) {
                if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
@@ -1969,8 +2008,7 @@ static void builtin_diff(const char *name_a,
                        fprintf(o->file, "%sBinary files %s and %s differ\n",
                                line_prefix, lbl[0], lbl[1]);
                o->found_changes = 1;
-       }
-       else {
+       } else {
                /* Crazy xdl interfaces.. */
                const char *diffopts = getenv("GIT_DIFF_OPTS");
                xpparam_t xpp;
@@ -3168,6 +3206,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                        return error("invalid argument to -M: %s", arg+2);
                options->detect_rename = DIFF_DETECT_RENAME;
        }
+       else if (!strcmp(arg, "-D") || !strcmp(arg, "--irreversible-delete")) {
+               options->irreversible_delete = 1;
+       }
        else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--find-copies=") ||
                 !strcmp(arg, "--find-copies")) {
                if (options->detect_rename == DIFF_DETECT_COPY)
@@ -3955,6 +3996,28 @@ static int is_summary_empty(const struct diff_queue_struct *q)
        return 1;
 }
 
+static const char rename_limit_warning[] =
+"inexact rename detection was skipped due to too many files.";
+
+static const char degrade_cc_to_c_warning[] =
+"only found copies from modified paths due to too many files.";
+
+static const char rename_limit_advice[] =
+"you may want to set your %s variable to at least "
+"%d and retry the command.";
+
+void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc)
+{
+       if (degraded_cc)
+               warning(degrade_cc_to_c_warning);
+       else if (needed)
+               warning(rename_limit_warning);
+       else
+               return;
+       if (0 < needed && needed < 32767)
+               warning(rename_limit_advice, varname, needed);
+}
+
 void diff_flush(struct diff_options *options)
 {
        struct diff_queue_struct *q = &diff_queued_diff;
@@ -4236,6 +4299,10 @@ void diffcore_std(struct diff_options *options)
 int diff_result_code(struct diff_options *opt, int status)
 {
        int result = 0;
+
+       diff_warn_rename_limit("diff.renamelimit",
+                              opt->needed_rename_limit,
+                              opt->degraded_cc_to_c);
        if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
            !(opt->output_format & DIFF_FORMAT_CHECKDIFF))
                return status;
diff --git a/diff.h b/diff.h
index 007a0554d4b252e83e98f5578758d51ec0c6e120..6fe1597785761b0e6961910214a129a2dde5197f 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -104,6 +104,7 @@ struct diff_options {
        int interhunkcontext;
        int break_opt;
        int detect_rename;
+       int irreversible_delete;
        int skip_stat_unmatch;
        int line_termination;
        int output_format;
@@ -111,6 +112,7 @@ struct diff_options {
        int rename_score;
        int rename_limit;
        int needed_rename_limit;
+       int degraded_cc_to_c;
        int show_rename_progress;
        int dirstat_percent;
        int setup;
@@ -273,6 +275,7 @@ extern void diffcore_fix_diff_index(struct diff_options *);
 
 extern int diff_queue_is_empty(void);
 extern void diff_flush(struct diff_options*);
+extern void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc);
 
 /* diff-raw status letters */
 #define DIFF_STATUS_ADDED              'A'
index d40e40a3ac9c919475d6157464fa906e37b0dd80..3d65bb370dbfd6d6581b6b3b454b5551d3e3fe22 100644 (file)
@@ -55,22 +55,23 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
 
 /* Table of rename/copy src files */
 static struct diff_rename_src {
-       struct diff_filespec *one;
+       struct diff_filepair *p;
        unsigned short score; /* to remember the break score */
 } *rename_src;
 static int rename_src_nr, rename_src_alloc;
 
-static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
-                                                  unsigned short score)
+static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
 {
        int first, last;
+       struct diff_filespec *one = p->one;
+       unsigned short score = p->score;
 
        first = 0;
        last = rename_src_nr;
        while (last > first) {
                int next = (last + first) >> 1;
                struct diff_rename_src *src = &(rename_src[next]);
-               int cmp = strcmp(one->path, src->one->path);
+               int cmp = strcmp(one->path, src->p->one->path);
                if (!cmp)
                        return src;
                if (cmp < 0) {
@@ -90,7 +91,7 @@ static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
        if (first < rename_src_nr)
                memmove(rename_src + first + 1, rename_src + first,
                        (rename_src_nr - first - 1) * sizeof(*rename_src));
-       rename_src[first].one = one;
+       rename_src[first].p = p;
        rename_src[first].score = score;
        return &(rename_src[first]);
 }
@@ -205,7 +206,7 @@ static void record_rename_pair(int dst_index, int src_index, int score)
        if (rename_dst[dst_index].pair)
                die("internal error: dst already matched.");
 
-       src = rename_src[src_index].one;
+       src = rename_src[src_index].p->one;
        src->rename_used++;
        src->count++;
 
@@ -389,7 +390,7 @@ static int find_exact_renames(struct diff_options *options)
 
        init_hash(&file_table);
        for (i = 0; i < rename_src_nr; i++)
-               insert_file_table(&file_table, -1, i, rename_src[i].one);
+               insert_file_table(&file_table, -1, i, rename_src[i].p->one);
 
        for (i = 0; i < rename_dst_nr; i++)
                insert_file_table(&file_table, 1, i, rename_dst[i].two);
@@ -419,6 +420,55 @@ static void record_if_better(struct diff_score m[], struct diff_score *o)
                m[worst] = *o;
 }
 
+/*
+ * Returns:
+ * 0 if we are under the limit;
+ * 1 if we need to disable inexact rename detection;
+ * 2 if we would be under the limit if we were given -C instead of -C -C.
+ */
+static int too_many_rename_candidates(int num_create,
+                                     struct diff_options *options)
+{
+       int rename_limit = options->rename_limit;
+       int num_src = rename_src_nr;
+       int i;
+
+       options->needed_rename_limit = 0;
+
+       /*
+        * This basically does a test for the rename matrix not
+        * growing larger than a "rename_limit" square matrix, ie:
+        *
+        *    num_create * num_src > rename_limit * rename_limit
+        *
+        * but handles the potential overflow case specially (and we
+        * assume at least 32-bit integers)
+        */
+       if (rename_limit <= 0 || rename_limit > 32767)
+               rename_limit = 32767;
+       if ((num_create <= rename_limit || num_src <= rename_limit) &&
+           (num_create * num_src <= rename_limit * rename_limit))
+               return 0;
+
+       options->needed_rename_limit =
+               num_src > num_create ? num_src : num_create;
+
+       /* Are we running under -C -C? */
+       if (!DIFF_OPT_TST(options, FIND_COPIES_HARDER))
+               return 1;
+
+       /* Would we bust the limit if we were running under -C? */
+       for (num_src = i = 0; i < rename_src_nr; i++) {
+               if (diff_unmodified_pair(rename_src[i].p))
+                       continue;
+               num_src++;
+       }
+       if ((num_create <= rename_limit || num_src <= rename_limit) &&
+           (num_create * num_src <= rename_limit * rename_limit))
+               return 2;
+       return 1;
+}
+
 static int find_renames(struct diff_score *mx, int dst_cnt, int minimum_score, int copies)
 {
        int count = 0, i;
@@ -432,7 +482,7 @@ static int find_renames(struct diff_score *mx, int dst_cnt, int minimum_score, i
                dst = &rename_dst[mx[i].dst];
                if (dst->pair)
                        continue; /* already done, either exact or fuzzy. */
-               if (!copies && rename_src[mx[i].src].one->rename_used)
+               if (!copies && rename_src[mx[i].src].p->one->rename_used)
                        continue;
                record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
                count++;
@@ -444,12 +494,11 @@ void diffcore_rename(struct diff_options *options)
 {
        int detect_rename = options->detect_rename;
        int minimum_score = options->rename_score;
-       int rename_limit = options->rename_limit;
        struct diff_queue_struct *q = &diff_queued_diff;
        struct diff_queue_struct outq;
        struct diff_score *mx;
-       int i, j, rename_count;
-       int num_create, num_src, dst_cnt;
+       int i, j, rename_count, skip_unmodified = 0;
+       int num_create, dst_cnt;
        struct progress *progress = NULL;
 
        if (!minimum_score)
@@ -476,7 +525,7 @@ void diffcore_rename(struct diff_options *options)
                         */
                        if (p->broken_pair && !p->score)
                                p->one->rename_used++;
-                       register_rename_src(p->one, p->score);
+                       register_rename_src(p);
                }
                else if (detect_rename == DIFF_DETECT_COPY) {
                        /*
@@ -484,7 +533,7 @@ void diffcore_rename(struct diff_options *options)
                         * one, to indicate ourselves as a user.
                         */
                        p->one->rename_used++;
-                       register_rename_src(p->one, p->score);
+                       register_rename_src(p);
                }
        }
        if (rename_dst_nr == 0 || rename_src_nr == 0)
@@ -505,29 +554,20 @@ void diffcore_rename(struct diff_options *options)
         * files still remain as options for rename/copies!)
         */
        num_create = (rename_dst_nr - rename_count);
-       num_src = rename_src_nr;
 
        /* All done? */
        if (!num_create)
                goto cleanup;
 
-       /*
-        * This basically does a test for the rename matrix not
-        * growing larger than a "rename_limit" square matrix, ie:
-        *
-        *    num_create * num_src > rename_limit * rename_limit
-        *
-        * but handles the potential overflow case specially (and we
-        * assume at least 32-bit integers)
-        */
-       options->needed_rename_limit = 0;
-       if (rename_limit <= 0 || rename_limit > 32767)
-               rename_limit = 32767;
-       if ((num_create > rename_limit && num_src > rename_limit) ||
-           (num_create * num_src > rename_limit * rename_limit)) {
-               options->needed_rename_limit =
-                       num_src > num_create ? num_src : num_create;
+       switch (too_many_rename_candidates(num_create, options)) {
+       case 1:
                goto cleanup;
+       case 2:
+               options->degraded_cc_to_c = 1;
+               skip_unmodified = 1;
+               break;
+       default:
+               break;
        }
 
        if (options->show_rename_progress) {
@@ -549,8 +589,13 @@ void diffcore_rename(struct diff_options *options)
                        m[j].dst = -1;
 
                for (j = 0; j < rename_src_nr; j++) {
-                       struct diff_filespec *one = rename_src[j].one;
+                       struct diff_filespec *one = rename_src[j].p->one;
                        struct diff_score this_src;
+
+                       if (skip_unmodified &&
+                           diff_unmodified_pair(rename_src[j].p))
+                               continue;
+
                        this_src.score = estimate_similarity(one, two,
                                                             minimum_score);
                        this_src.name_score = basename_same(one, two);
diff --git a/dir.c b/dir.c
index 325fb56ad395c9b47dcbdea47b2833a4287198bc..532bcb65b523223b66efd3f4e458f62fcbe0d6a5 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -1192,7 +1192,7 @@ int remove_dir_recursively(struct strbuf *path, int flag)
 
        dir = opendir(path->buf);
        if (!dir)
-               return -1;
+               return rmdir(path->buf);
        if (path->buf[original_len - 1] != '/')
                strbuf_addch(path, '/');
 
index f4549d3f7b0367b31b0fa0042fb12ff183beb081..40185bc854ea2c5b8d2e3deb800dd6f3f44482a9 100644 (file)
@@ -35,6 +35,7 @@ int fsync_object_files;
 size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 size_t delta_base_cache_limit = 16 * 1024 * 1024;
+unsigned long big_file_threshold = 512 * 1024 * 1024;
 const char *pager_program;
 int pager_use_color = 1;
 const char *editor_program;
index 65d65bf8f91b7a584c7dc77f84a5dec263c3d11c..3e4e655bb989076e4bb6311fa4fe41320c344194 100644 (file)
@@ -274,7 +274,6 @@ struct recent_command {
 /* Configured limits on output */
 static unsigned long max_depth = 10;
 static off_t max_packsize;
-static uintmax_t big_file_threshold = 512 * 1024 * 1024;
 static int force_update;
 static int pack_compression_level = Z_DEFAULT_COMPRESSION;
 static int pack_compression_seen;
@@ -3206,10 +3205,6 @@ static int git_pack_config(const char *k, const char *v, void *cb)
                max_packsize = git_config_ulong(k, v);
                return 0;
        }
-       if (!strcmp(k, "core.bigfilethreshold")) {
-               long n = git_config_int(k, v);
-               big_file_threshold = 0 < n ? n : 0;
-       }
        return git_default_config(k, v, cb);
 }
 
index ea093d251d98af6a3d4df19e900d56df34d51572..b24119d69c092e3bd345cff1b6bafd48f5fd1e1b 100644 (file)
@@ -50,3 +50,41 @@ get_remote_merge_branch () {
            esac
        esac
 }
+
+error_on_missing_default_upstream () {
+       cmd="$1"
+       op_type="$2"
+       op_prep="$3"
+       example="$4"
+       branch_name=$(git symbolic-ref -q HEAD)
+       if test -z "$branch_name"
+       then
+               echo "You are not currently on a branch, so I cannot use any
+'branch.<branchname>.merge' in your configuration file.
+Please specify which branch you want to $op_type $op_prep on the command
+line and try again (e.g. '$example').
+See git-${cmd}(1) for details."
+       else
+               echo "You asked me to $cmd without telling me which branch you
+want to $op_type $op_prep, and 'branch.${branch_name#refs/heads/}.merge' in
+your configuration file does not tell me, either. Please
+specify which branch you want to use on the command line and
+try again (e.g. '$example').
+See git-${cmd}(1) for details.
+
+If you often $op_type $op_prep the same branch, you may want to
+use something like the following in your configuration file:
+    [branch \"${branch_name#refs/heads/}\"]
+    remote = <nickname>
+    merge = <remote-ref>"
+               test rebase = "$op_type" &&
+               echo "    rebase = true"
+               echo "
+    [remote \"<nickname>\"]
+    url = <url>
+    fetch = <refspec>
+
+See git-config(1) for details."
+       fi
+       exit 1
+}
index 4e9e0e49ecf2532ac8af1bfd46033e68c6f1042d..fb9e2df9312e96ecf8ad5ab2bde4b74b979fe02e 100755 (executable)
@@ -168,34 +168,10 @@ error_on_no_merge_candidates () {
                echo "You asked to pull from the remote '$1', but did not specify"
                echo "a branch. Because this is not the default configured remote"
                echo "for your current branch, you must specify a branch on the command line."
-       elif [ -z "$curr_branch" ]; then
-               echo "You are not currently on a branch, so I cannot use any"
-               echo "'branch.<branchname>.merge' in your configuration file."
-               echo "Please specify which remote branch you want to use on the command"
-               echo "line and try again (e.g. 'git pull <repository> <refspec>')."
-               echo "See git-pull(1) for details."
-       elif [ -z "$upstream" ]; then
-               echo "You asked me to pull without telling me which branch you"
-               echo "want to $op_type $op_prep, and 'branch.${curr_branch}.merge' in"
-               echo "your configuration file does not tell me, either. Please"
-               echo "specify which branch you want to use on the command line and"
-               echo "try again (e.g. 'git pull <repository> <refspec>')."
-               echo "See git-pull(1) for details."
-               echo
-               echo "If you often $op_type $op_prep the same branch, you may want to"
-               echo "use something like the following in your configuration file:"
-               echo
-               echo "    [branch \"${curr_branch}\"]"
-               echo "    remote = <nickname>"
-               echo "    merge = <remote-ref>"
-               test rebase = "$op_type" &&
-                       echo "    rebase = true"
-               echo
-               echo "    [remote \"<nickname>\"]"
-               echo "    url = <url>"
-               echo "    fetch = <refspec>"
-               echo
-               echo "See git-config(1) for details."
+       elif [ -z "$curr_branch" -o -z "$upstream" ]; then
+               . git-parse-remote
+               error_on_missing_default_upstream "pull" $op_type $op_prep \
+                       "git pull <repository> <refspec>"
        else
                echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'"
                echo "from the remote, but no such ref was fetched."
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
new file mode 100644 (file)
index 0000000..c815a24
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Junio C Hamano.
+#
+
+. git-sh-setup
+
+case "$action" in
+continue)
+       git am --resolved --resolvemsg="$resolvemsg" &&
+       move_to_original_branch
+       exit
+       ;;
+skip)
+       git am --skip --resolvemsg="$resolvemsg" &&
+       move_to_original_branch
+       exit
+       ;;
+esac
+
+test -n "$rebase_root" && root_flag=--root
+
+git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+       --src-prefix=a/ --dst-prefix=b/ \
+       --no-renames $root_flag "$revisions" |
+git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" &&
+move_to_original_branch
+ret=$?
+test 0 != $ret -a -d "$state_dir" && write_basic_state
+exit $ret
old mode 100755 (executable)
new mode 100644 (file)
index 5873ba4..6566d31
 # The original idea comes from Eric W. Biederman, in
 # http://article.gmane.org/gmane.comp.version-control.git/22407
 
-OPTIONS_KEEPDASHDASH=
-OPTIONS_SPEC="\
-git-rebase [-i] [options] [--] <upstream> [<branch>]
-git-rebase [-i] (--continue | --abort | --skip)
---
- Available options are
-v,verbose          display a diffstat of what changed upstream
-onto=              rebase onto given branch instead of upstream
-p,preserve-merges  try to recreate merges instead of ignoring them
-s,strategy=        use the given merge strategy
-no-ff              cherry-pick all commits, even if unchanged
-m,merge            always used (no-op)
-i,interactive      always used (no-op)
- Actions:
-continue           continue rebasing process
-abort              abort rebasing process and restore original branch
-skip               skip current patch and continue rebasing process
-no-verify          override pre-rebase hook from stopping the operation
-verify             allow pre-rebase hook to run
-root               rebase all reachable commmits up to the root(s)
-autosquash         move commits that begin with squash!/fixup! under -i
-"
-
 . git-sh-setup
-require_work_tree
-
-DOTEST="$GIT_DIR/rebase-merge"
 
 # The file containing rebase commands, comments, and empty lines.
 # This file is created by "git rebase -i" then edited by the user.  As
 # the lines are processed, they are removed from the front of this
-# file and written to the tail of $DONE.
-TODO="$DOTEST"/git-rebase-todo
+# file and written to the tail of $done.
+todo="$state_dir"/git-rebase-todo
 
 # The rebase command lines that have already been processed.  A line
 # is moved here when it is first handled, before any associated user
 # actions.
-DONE="$DOTEST"/done
+done="$state_dir"/done
 
 # The commit message that is planned to be used for any changes that
 # need to be committed following a user interaction.
-MSG="$DOTEST"/message
+msg="$state_dir"/message
 
 # The file into which is accumulated the suggested commit message for
 # squash/fixup commands.  When the first of a series of squash/fixups
@@ -61,34 +35,34 @@ MSG="$DOTEST"/message
 # is appended to the file as it is processed.
 #
 # The first line of the file is of the form
-#     # This is a combination of $COUNT commits.
-# where $COUNT is the number of commits whose messages have been
+#     # This is a combination of $count commits.
+# where $count is the number of commits whose messages have been
 # written to the file so far (including the initial "pick" commit).
 # Each time that a commit message is processed, this line is read and
 # updated.  It is deleted just before the combined commit is made.
-SQUASH_MSG="$DOTEST"/message-squash
+squash_msg="$state_dir"/message-squash
 
 # If the current series of squash/fixups has not yet included a squash
 # command, then this file exists and holds the commit message of the
 # original "pick" commit.  (If the series ends without a "squash"
 # command, then this can be used as the commit message of the combined
 # commit without opening the editor.)
-FIXUP_MSG="$DOTEST"/message-fixup
+fixup_msg="$state_dir"/message-fixup
 
-# $REWRITTEN is the name of a directory containing files for each
-# commit that is reachable by at least one merge base of $HEAD and
-# $UPSTREAM. They are not necessarily rewritten, but their children
+# $rewritten is the name of a directory containing files for each
+# commit that is reachable by at least one merge base of $head and
+# $upstream. They are not necessarily rewritten, but their children
 # might be.  This ensures that commits on merged, but otherwise
 # unrelated side branches are left alone. (Think "X" in the man page's
 # example.)
-REWRITTEN="$DOTEST"/rewritten
+rewritten="$state_dir"/rewritten
 
-DROPPED="$DOTEST"/dropped
+dropped="$state_dir"/dropped
 
 # A script to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE that will be used for the commit that is currently
 # being rebased.
-AUTHOR_SCRIPT="$DOTEST"/author-script
+author_script="$state_dir"/author-script
 
 # When an "edit" rebase command is being processed, the SHA1 of the
 # commit to be edited is recorded in this file.  When "git rebase
@@ -96,69 +70,31 @@ AUTHOR_SCRIPT="$DOTEST"/author-script
 # will be amended to the HEAD commit, but only provided the HEAD
 # commit is still the commit to be edited.  When any other rebase
 # command is processed, this file is deleted.
-AMEND="$DOTEST"/amend
+amend="$state_dir"/amend
 
 # For the post-rewrite hook, we make a list of rewritten commits and
 # their new sha1s.  The rewritten-pending list keeps the sha1s of
 # commits that have been processed, but not committed yet,
 # e.g. because they are waiting for a 'squash' command.
-REWRITTEN_LIST="$DOTEST"/rewritten-list
-REWRITTEN_PENDING="$DOTEST"/rewritten-pending
-
-PRESERVE_MERGES=
-STRATEGY=
-ONTO=
-VERBOSE=
-OK_TO_SKIP_PRE_REBASE=
-REBASE_ROOT=
-AUTOSQUASH=
-test "$(git config --bool rebase.autosquash)" = "true" && AUTOSQUASH=t
-NEVER_FF=
-
-GIT_CHERRY_PICK_HELP="\
-hint: after resolving the conflicts, mark the corrected paths
-hint: with 'git add <paths>' and run 'git rebase --continue'"
+rewritten_list="$state_dir"/rewritten-list
+rewritten_pending="$state_dir"/rewritten-pending
+
+GIT_CHERRY_PICK_HELP="$resolvemsg"
 export GIT_CHERRY_PICK_HELP
 
 warn () {
        printf '%s\n' "$*" >&2
 }
 
-output () {
-       case "$VERBOSE" in
-       '')
-               output=$("$@" 2>&1 )
-               status=$?
-               test $status != 0 && printf "%s\n" "$output"
-               return $status
-               ;;
-       *)
-               "$@"
-               ;;
-       esac
-}
-
 # Output the commit message for the specified commit.
 commit_message () {
        git cat-file commit "$1" | sed "1,/^$/d"
 }
 
-run_pre_rebase_hook () {
-       if test -z "$OK_TO_SKIP_PRE_REBASE" &&
-          test -x "$GIT_DIR/hooks/pre-rebase"
-       then
-               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
-                       echo >&2 "The pre-rebase hook refused to rebase."
-                       exit 1
-               }
-       fi
-}
-
-
-ORIG_REFLOG_ACTION="$GIT_REFLOG_ACTION"
+orig_reflog_action="$GIT_REFLOG_ACTION"
 
 comment_for_reflog () {
-       case "$ORIG_REFLOG_ACTION" in
+       case "$orig_reflog_action" in
        ''|rebase*)
                GIT_REFLOG_ACTION="rebase -i ($1)"
                export GIT_REFLOG_ACTION
@@ -168,16 +104,16 @@ comment_for_reflog () {
 
 last_count=
 mark_action_done () {
-       sed -e 1q < "$TODO" >> "$DONE"
-       sed -e 1d < "$TODO" >> "$TODO".new
-       mv -f "$TODO".new "$TODO"
-       count=$(sane_grep -c '^[^#]' < "$DONE")
-       total=$(($count+$(sane_grep -c '^[^#]' < "$TODO")))
-       if test "$last_count" != "$count"
+       sed -e 1q < "$todo" >> "$done"
+       sed -e 1d < "$todo" >> "$todo".new
+       mv -f "$todo".new "$todo"
+       new_count=$(sane_grep -c '^[^#]' < "$done")
+       total=$(($new_count+$(sane_grep -c '^[^#]' < "$todo")))
+       if test "$last_count" != "$new_count"
        then
-               last_count=$count
-               printf "Rebasing (%d/%d)\r" $count $total
-               test -z "$VERBOSE" || echo
+               last_count=$new_count
+               printf "Rebasing (%d/%d)\r" $new_count $total
+               test -z "$verbose" || echo
        fi
 }
 
@@ -193,22 +129,22 @@ make_patch () {
        *)
                echo "Root commit"
                ;;
-       esac > "$DOTEST"/patch
-       test -f "$MSG" ||
-               commit_message "$1" > "$MSG"
-       test -f "$AUTHOR_SCRIPT" ||
-               get_author_ident_from_commit "$1" > "$AUTHOR_SCRIPT"
+       esac > "$state_dir"/patch
+       test -f "$msg" ||
+               commit_message "$1" > "$msg"
+       test -f "$author_script" ||
+               get_author_ident_from_commit "$1" > "$author_script"
 }
 
 die_with_patch () {
-       echo "$1" > "$DOTEST"/stopped-sha
+       echo "$1" > "$state_dir"/stopped-sha
        make_patch "$1"
        git rerere
        die "$2"
 }
 
 die_abort () {
-       rm -rf "$DOTEST"
+       rm -rf "$state_dir"
        die "$1"
 }
 
@@ -228,15 +164,10 @@ do_with_author () {
 pick_one () {
        ff=--ff
        case "$1" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac
-       case "$NEVER_FF" in '') ;; ?*) ff= ;; esac
+       case "$force_rebase" in '') ;; ?*) ff= ;; esac
        output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
-       test -d "$REWRITTEN" &&
+       test -d "$rewritten" &&
                pick_one_preserving_merges "$@" && return
-       if test -n "$REBASE_ROOT"
-       then
-               output git cherry-pick "$@"
-               return
-       fi
        output git cherry-pick $ff "$@"
 }
 
@@ -253,20 +184,20 @@ pick_one_preserving_merges () {
        esac
        sha1=$(git rev-parse $sha1)
 
-       if test -f "$DOTEST"/current-commit
+       if test -f "$state_dir"/current-commit
        then
                if test "$fast_forward" = t
                then
                        while read current_commit
                        do
-                               git rev-parse HEAD > "$REWRITTEN"/$current_commit
-                       done <"$DOTEST"/current-commit
-                       rm "$DOTEST"/current-commit ||
+                               git rev-parse HEAD > "$rewritten"/$current_commit
+                       done <"$state_dir"/current-commit
+                       rm "$state_dir"/current-commit ||
                        die "Cannot write current commit's replacement sha1"
                fi
        fi
 
-       echo $sha1 >> "$DOTEST"/current-commit
+       echo $sha1 >> "$state_dir"/current-commit
 
        # rewrite parents; if none were rewritten, we can fast-forward.
        new_parents=
@@ -280,9 +211,9 @@ pick_one_preserving_merges () {
                p=$(expr "$pend" : ' \([^ ]*\)')
                pend="${pend# $p}"
 
-               if test -f "$REWRITTEN"/$p
+               if test -f "$rewritten"/$p
                then
-                       new_p=$(cat "$REWRITTEN"/$p)
+                       new_p=$(cat "$rewritten"/$p)
 
                        # If the todo reordered commits, and our parent is marked for
                        # rewriting, but hasn't been gotten to yet, assume the user meant to
@@ -301,10 +232,10 @@ pick_one_preserving_merges () {
                                ;;
                        esac
                else
-                       if test -f "$DROPPED"/$p
+                       if test -f "$dropped"/$p
                        then
                                fast_forward=f
-                               replacement="$(cat "$DROPPED"/$p)"
+                               replacement="$(cat "$dropped"/$p)"
                                test -z "$replacement" && replacement=root
                                pend=" $replacement$pend"
                        else
@@ -333,18 +264,19 @@ pick_one_preserving_merges () {
                        test "a$1" = a-n && die "Refusing to squash a merge: $sha1"
 
                        # redo merge
-                       author_script=$(get_author_ident_from_commit $sha1)
-                       eval "$author_script"
-                       msg="$(commit_message $sha1)"
+                       author_script_content=$(get_author_ident_from_commit $sha1)
+                       eval "$author_script_content"
+                       msg_content="$(commit_message $sha1)"
                        # No point in merging the first parent, that's HEAD
                        new_parents=${new_parents# $first_parent}
                        if ! do_with_author output \
-                               git merge $STRATEGY -m "$msg" $new_parents
+                               git merge ${strategy:+-s $strategy} -m \
+                                       "$msg_content" $new_parents
                        then
-                               printf "%s\n" "$msg" > "$GIT_DIR"/MERGE_MSG
+                               printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
                                die_with_patch $sha1 "Error redoing merge $sha1"
                        fi
-                       echo "$sha1 $(git rev-parse HEAD^0)" >> "$REWRITTEN_LIST"
+                       echo "$sha1 $(git rev-parse HEAD^0)" >> "$rewritten_list"
                        ;;
                *)
                        output git cherry-pick "$@" ||
@@ -365,46 +297,46 @@ nth_string () {
 }
 
 update_squash_messages () {
-       if test -f "$SQUASH_MSG"; then
-               mv "$SQUASH_MSG" "$SQUASH_MSG".bak || exit
-               COUNT=$(($(sed -n \
+       if test -f "$squash_msg"; then
+               mv "$squash_msg" "$squash_msg".bak || exit
+               count=$(($(sed -n \
                        -e "1s/^# This is a combination of \(.*\) commits\./\1/p" \
-                       -e "q" < "$SQUASH_MSG".bak)+1))
+                       -e "q" < "$squash_msg".bak)+1))
                {
-                       echo "# This is a combination of $COUNT commits."
+                       echo "# This is a combination of $count commits."
                        sed -e 1d -e '2,/^./{
                                /^$/d
-                       }' <"$SQUASH_MSG".bak
-               } >"$SQUASH_MSG"
+                       }' <"$squash_msg".bak
+               } >"$squash_msg"
        else
-               commit_message HEAD > "$FIXUP_MSG" || die "Cannot write $FIXUP_MSG"
-               COUNT=2
+               commit_message HEAD > "$fixup_msg" || die "Cannot write $fixup_msg"
+               count=2
                {
                        echo "# This is a combination of 2 commits."
                        echo "# The first commit's message is:"
                        echo
-                       cat "$FIXUP_MSG"
-               } >"$SQUASH_MSG"
+                       cat "$fixup_msg"
+               } >"$squash_msg"
        fi
        case $1 in
        squash)
-               rm -f "$FIXUP_MSG"
+               rm -f "$fixup_msg"
                echo
-               echo "# This is the $(nth_string $COUNT) commit message:"
+               echo "# This is the $(nth_string $count) commit message:"
                echo
                commit_message $2
                ;;
        fixup)
                echo
-               echo "# The $(nth_string $COUNT) commit message will be skipped:"
+               echo "# The $(nth_string $count) commit message will be skipped:"
                echo
                commit_message $2 | sed -e 's/^/#       /'
                ;;
-       esac >>"$SQUASH_MSG"
+       esac >>"$squash_msg"
 }
 
 peek_next_command () {
-       sed -n -e "/^#/d" -e '/^$/d' -e "s/ .*//p" -e "q" < "$TODO"
+       sed -n -e "/^#/d" -e '/^$/d' -e "s/ .*//p" -e "q" < "$todo"
 }
 
 # A squash/fixup has failed.  Prepare the long version of the squash
@@ -414,24 +346,24 @@ peek_next_command () {
 # messages, effectively causing the combined commit to be used as the
 # new basis for any further squash/fixups.  Args: sha1 rest
 die_failed_squash() {
-       mv "$SQUASH_MSG" "$MSG" || exit
-       rm -f "$FIXUP_MSG"
-       cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
+       mv "$squash_msg" "$msg" || exit
+       rm -f "$fixup_msg"
+       cp "$msg" "$GIT_DIR"/MERGE_MSG || exit
        warn
        warn "Could not apply $1... $2"
        die_with_patch $1 ""
 }
 
 flush_rewritten_pending() {
-       test -s "$REWRITTEN_PENDING" || return
+       test -s "$rewritten_pending" || return
        newsha1="$(git rev-parse HEAD^0)"
-       sed "s/$/ $newsha1/" < "$REWRITTEN_PENDING" >> "$REWRITTEN_LIST"
-       rm -f "$REWRITTEN_PENDING"
+       sed "s/$/ $newsha1/" < "$rewritten_pending" >> "$rewritten_list"
+       rm -f "$rewritten_pending"
 }
 
 record_in_rewritten() {
        oldsha1="$(git rev-parse $1)"
-       echo "$oldsha1" >> "$REWRITTEN_PENDING"
+       echo "$oldsha1" >> "$rewritten_pending"
 
        case "$(peek_next_command)" in
        squash|s|fixup|f)
@@ -443,8 +375,8 @@ record_in_rewritten() {
 }
 
 do_next () {
-       rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
-       read -r command sha1 rest < "$TODO"
+       rm -f "$msg" "$author_script" "$amend" || exit
+       read -r command sha1 rest < "$todo"
        case "$command" in
        '#'*|''|noop)
                mark_action_done
@@ -472,9 +404,9 @@ do_next () {
                mark_action_done
                pick_one $sha1 ||
                        die_with_patch $sha1 "Could not apply $sha1... $rest"
-               echo "$sha1" > "$DOTEST"/stopped-sha
+               echo "$sha1" > "$state_dir"/stopped-sha
                make_patch $sha1
-               git rev-parse --verify HEAD > "$AMEND"
+               git rev-parse --verify HEAD > "$amend"
                warn "Stopped at $sha1... $rest"
                warn "You can amend the commit now, with"
                warn
@@ -497,47 +429,47 @@ do_next () {
                esac
                comment_for_reflog $squash_style
 
-               test -f "$DONE" && has_action "$DONE" ||
+               test -f "$done" && has_action "$done" ||
                        die "Cannot '$squash_style' without a previous commit"
 
                mark_action_done
                update_squash_messages $squash_style $sha1
-               author_script=$(get_author_ident_from_commit HEAD)
-               echo "$author_script" > "$AUTHOR_SCRIPT"
-               eval "$author_script"
+               author_script_content=$(get_author_ident_from_commit HEAD)
+               echo "$author_script_content" > "$author_script"
+               eval "$author_script_content"
                output git reset --soft HEAD^
                pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
                case "$(peek_next_command)" in
                squash|s|fixup|f)
                        # This is an intermediate commit; its message will only be
                        # used in case of trouble.  So use the long version:
-                       do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
+                       do_with_author output git commit --no-verify -F "$squash_msg" ||
                                die_failed_squash $sha1 "$rest"
                        ;;
                *)
                        # This is the final command of this squash/fixup group
-                       if test -f "$FIXUP_MSG"
+                       if test -f "$fixup_msg"
                        then
-                               do_with_author git commit --no-verify -F "$FIXUP_MSG" ||
+                               do_with_author git commit --no-verify -F "$fixup_msg" ||
                                        die_failed_squash $sha1 "$rest"
                        else
-                               cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit
+                               cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit
                                rm -f "$GIT_DIR"/MERGE_MSG
                                do_with_author git commit --no-verify -e ||
                                        die_failed_squash $sha1 "$rest"
                        fi
-                       rm -f "$SQUASH_MSG" "$FIXUP_MSG"
+                       rm -f "$squash_msg" "$fixup_msg"
                        ;;
                esac
                record_in_rewritten $sha1
                ;;
        x|"exec")
-               read -r command rest < "$TODO"
+               read -r command rest < "$todo"
                mark_action_done
                printf 'Executing: %s\n' "$rest"
                # "exec" command doesn't take a sha1 in the todo-list.
                # => can't just use $sha1 here.
-               git rev-parse --verify HEAD > "$DOTEST"/stopped-sha
+               git rev-parse --verify HEAD > "$state_dir"/stopped-sha
                ${SHELL:-@SHELL_PATH@} -c "$rest" # Actual execution
                status=$?
                if test "$status" -ne 0
@@ -563,42 +495,40 @@ do_next () {
                warn "Unknown command: $command $sha1 $rest"
                if git rev-parse --verify -q "$sha1" >/dev/null
                then
-                       die_with_patch $sha1 "Please fix this in the file $TODO."
+                       die_with_patch $sha1 "Please fix this in the file $todo."
                else
-                       die "Please fix this in the file $TODO."
+                       die "Please fix this in the file $todo."
                fi
                ;;
        esac
-       test -s "$TODO" && return
+       test -s "$todo" && return
 
        comment_for_reflog finish &&
-       HEADNAME=$(cat "$DOTEST"/head-name) &&
-       OLDHEAD=$(cat "$DOTEST"/head) &&
-       SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) &&
-       NEWHEAD=$(git rev-parse HEAD) &&
-       case $HEADNAME in
+       shortonto=$(git rev-parse --short $onto) &&
+       newhead=$(git rev-parse HEAD) &&
+       case $head_name in
        refs/*)
-               message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO" &&
-               git update-ref -m "$message" $HEADNAME $NEWHEAD $OLDHEAD &&
-               git symbolic-ref HEAD $HEADNAME
+               message="$GIT_REFLOG_ACTION: $head_name onto $shortonto" &&
+               git update-ref -m "$message" $head_name $newhead $orig_head &&
+               git symbolic-ref HEAD $head_name
                ;;
        esac && {
-               test ! -f "$DOTEST"/verbose ||
-                       git diff-tree --stat $(cat "$DOTEST"/head)..HEAD
+               test ! -f "$state_dir"/verbose ||
+                       git diff-tree --stat $orig_head..HEAD
        } &&
        {
-               test -s "$REWRITTEN_LIST" &&
-               git notes copy --for-rewrite=rebase < "$REWRITTEN_LIST" ||
+               test -s "$rewritten_list" &&
+               git notes copy --for-rewrite=rebase < "$rewritten_list" ||
                true # we don't care if this copying failed
        } &&
        if test -x "$GIT_DIR"/hooks/post-rewrite &&
-               test -s "$REWRITTEN_LIST"; then
-               "$GIT_DIR"/hooks/post-rewrite rebase < "$REWRITTEN_LIST"
+               test -s "$rewritten_list"; then
+               "$GIT_DIR"/hooks/post-rewrite rebase < "$rewritten_list"
                true # we don't care if this hook failed
        fi &&
-       rm -rf "$DOTEST" &&
+       rm -rf "$state_dir" &&
        git gc --auto &&
-       warn "Successfully rebased and updated $HEADNAME."
+       warn "Successfully rebased and updated $head_name."
 
        exit
 }
@@ -618,11 +548,11 @@ skip_unnecessary_picks () {
                # fd=3 means we skip the command
                case "$fd,$command" in
                3,pick|3,p)
-                       # pick a commit whose parent is current $ONTO -> skip
+                       # pick a commit whose parent is current $onto -> skip
                        sha1=${rest%% *}
                        case "$(git rev-parse --verify --quiet "$sha1"^)" in
-                       "$ONTO"*)
-                               ONTO=$sha1
+                       "$onto"*)
+                               onto=$sha1
                                ;;
                        *)
                                fd=1
@@ -637,32 +567,16 @@ skip_unnecessary_picks () {
                        ;;
                esac
                printf '%s\n' "$command${rest:+ }$rest" >&$fd
-       done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
-       mv -f "$TODO".new "$TODO" &&
+       done <"$todo" >"$todo.new" 3>>"$done" &&
+       mv -f "$todo".new "$todo" &&
        case "$(peek_next_command)" in
        squash|s|fixup|f)
-               record_in_rewritten "$ONTO"
+               record_in_rewritten "$onto"
                ;;
        esac ||
        die "Could not skip unnecessary pick commands"
 }
 
-# check if no other options are set
-is_standalone () {
-       test $# -eq 2 -a "$2" = '--' &&
-       test -z "$ONTO" &&
-       test -z "$PRESERVE_MERGES" &&
-       test -z "$STRATEGY" &&
-       test -z "$VERBOSE"
-}
-
-get_saved_options () {
-       test -d "$REWRITTEN" && PRESERVE_MERGES=t
-       test -f "$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)"
-       test -f "$DOTEST"/verbose && VERBOSE=t
-       test -f "$DOTEST"/rebase-root && REBASE_ROOT=t
-}
-
 # Rearrange the todo list that has both "pick sha1 msg" and
 # "pick sha1 fixup!/squash! msg" appears in it so that the latter
 # comes immediately after the former, and change "pick" to
@@ -699,7 +613,7 @@ rearrange_squash () {
                esac
                printf '%s\n' "$pick $sha1 $message"
                used="$used$sha1 "
-               while read -r squash action msg
+               while read -r squash action msg_content
                do
                        case " $used" in
                        *" $squash "*) continue ;;
@@ -709,13 +623,13 @@ rearrange_squash () {
                        +*)
                                action="${action#+}"
                                # full sha1 prefix test
-                               case "$msg" in "$sha1"*) emit=1;; esac ;;
+                               case "$msg_content" in "$sha1"*) emit=1;; esac ;;
                        *)
                                # message prefix test
-                               case "$message" in "$msg"*) emit=1;; esac ;;
+                               case "$message" in "$msg_content"*) emit=1;; esac ;;
                        esac
                        if test $emit = 1; then
-                               printf '%s\n' "$action $squash $action! $msg"
+                               printf '%s\n' "$action $squash $action! $msg_content"
                                used="$used$squash "
                        fi
                done <"$1.sq"
@@ -724,296 +638,159 @@ rearrange_squash () {
        rm -f "$1.sq" "$1.rearranged"
 }
 
-LF='
-'
-parse_onto () {
-       case "$1" in
-       *...*)
-               if      left=${1%...*} right=${1#*...} &&
-                       onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
-               then
-                       case "$onto" in
-                       ?*"$LF"?* | '')
-                               exit 1 ;;
-                       esac
-                       echo "$onto"
-                       exit 0
-               fi
-       esac
-       git rev-parse --verify "$1^0"
-}
-
-while test $# != 0
-do
-       case "$1" in
-       --no-verify)
-               OK_TO_SKIP_PRE_REBASE=yes
-               ;;
-       --verify)
-               OK_TO_SKIP_PRE_REBASE=
-               ;;
-       --continue)
-               is_standalone "$@" || usage
-               get_saved_options
-               comment_for_reflog continue
-
-               test -d "$DOTEST" || die "No interactive rebase running"
-
-               # Sanity check
-               git rev-parse --verify HEAD >/dev/null ||
-                       die "Cannot read HEAD"
-               git update-index --ignore-submodules --refresh &&
-                       git diff-files --quiet --ignore-submodules ||
-                       die "Working tree is dirty"
-
-               # do we have anything to commit?
-               if git diff-index --cached --quiet --ignore-submodules HEAD --
+case "$action" in
+continue)
+       # do we have anything to commit?
+       if git diff-index --cached --quiet --ignore-submodules HEAD --
+       then
+               : Nothing to commit -- skip this
+       else
+               . "$author_script" ||
+                       die "Cannot find the author identity"
+               current_head=
+               if test -f "$amend"
                then
-                       : Nothing to commit -- skip this
-               else
-                       . "$AUTHOR_SCRIPT" ||
-                               die "Cannot find the author identity"
-                       amend=
-                       if test -f "$AMEND"
-                       then
-                               amend=$(git rev-parse --verify HEAD)
-                               test "$amend" = $(cat "$AMEND") ||
-                               die "\
+                       current_head=$(git rev-parse --verify HEAD)
+                       test "$current_head" = $(cat "$amend") ||
+                       die "\
 You have uncommitted changes in your working tree. Please, commit them
 first and then run 'git rebase --continue' again."
-                               git reset --soft HEAD^ ||
-                               die "Cannot rewind the HEAD"
-                       fi
-                       do_with_author git commit --no-verify -F "$MSG" -e || {
-                               test -n "$amend" && git reset --soft $amend
-                               die "Could not commit staged changes."
-                       }
+                       git reset --soft HEAD^ ||
+                       die "Cannot rewind the HEAD"
                fi
+               do_with_author git commit --no-verify -F "$msg" -e || {
+                       test -n "$current_head" && git reset --soft $current_head
+                       die "Could not commit staged changes."
+               }
+       fi
 
-               record_in_rewritten "$(cat "$DOTEST"/stopped-sha)"
-
-               require_clean_work_tree "rebase"
-               do_rest
-               ;;
-       --abort)
-               is_standalone "$@" || usage
-               get_saved_options
-               comment_for_reflog abort
-
-               git rerere clear
-               test -d "$DOTEST" || die "No interactive rebase running"
-
-               HEADNAME=$(cat "$DOTEST"/head-name)
-               HEAD=$(cat "$DOTEST"/head)
-               case $HEADNAME in
-               refs/*)
-                       git symbolic-ref HEAD $HEADNAME
-                       ;;
-               esac &&
-               output git reset --hard $HEAD &&
-               rm -rf "$DOTEST"
-               exit
-               ;;
-       --skip)
-               is_standalone "$@" || usage
-               get_saved_options
-               comment_for_reflog skip
-
-               git rerere clear
-               test -d "$DOTEST" || die "No interactive rebase running"
-
-               output git reset --hard && do_rest
-               ;;
-       -s)
-               case "$#,$1" in
-               *,*=*)
-                       STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
-               1,*)
-                       usage ;;
-               *)
-                       STRATEGY="-s $2"
-                       shift ;;
-               esac
-               ;;
-       -m)
-               # we use merge anyway
-               ;;
-       -v)
-               VERBOSE=t
-               ;;
-       -p)
-               PRESERVE_MERGES=t
-               ;;
-       -i)
-               # yeah, we know
-               ;;
-       --no-ff)
-               NEVER_FF=t
-               ;;
-       --root)
-               REBASE_ROOT=t
-               ;;
-       --autosquash)
-               AUTOSQUASH=t
-               ;;
-       --no-autosquash)
-               AUTOSQUASH=
-               ;;
-       --onto)
-               shift
-               ONTO=$(parse_onto "$1") ||
-                       die "Does not point to a valid commit: $1"
-               ;;
-       --)
-               shift
-               test -z "$REBASE_ROOT" -a $# -ge 1 -a $# -le 2 ||
-               test ! -z "$REBASE_ROOT" -a $# -le 1 || usage
-               test -d "$DOTEST" &&
-                       die "Interactive rebase already started"
-
-               git var GIT_COMMITTER_IDENT >/dev/null ||
-                       die "You need to set your committer info first"
+       record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
 
-               if test -z "$REBASE_ROOT"
-               then
-                       UPSTREAM_ARG="$1"
-                       UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
-                       test -z "$ONTO" && ONTO=$UPSTREAM
-                       shift
-               else
-                       UPSTREAM=
-                       UPSTREAM_ARG=--root
-                       test -z "$ONTO" &&
-                               die "You must specify --onto when using --root"
-               fi
-               run_pre_rebase_hook "$UPSTREAM_ARG" "$@"
+       require_clean_work_tree "rebase"
+       do_rest
+       ;;
+skip)
+       git rerere clear
 
-               comment_for_reflog start
+       do_rest
+       ;;
+esac
 
-               require_clean_work_tree "rebase" "Please commit or stash them."
+git var GIT_COMMITTER_IDENT >/dev/null ||
+       die "You need to set your committer info first"
 
-               if test ! -z "$1"
-               then
-                       output git checkout "$1" -- ||
-                               die "Could not checkout $1"
-               fi
+comment_for_reflog start
 
-               HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
-               mkdir "$DOTEST" || die "Could not create temporary $DOTEST"
+if test ! -z "$switch_to"
+then
+       output git checkout "$switch_to" -- ||
+               die "Could not checkout $switch_to"
+fi
 
-               : > "$DOTEST"/interactive || die "Could not mark as interactive"
-               git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
-                       echo "detached HEAD" > "$DOTEST"/head-name
+orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
+mkdir "$state_dir" || die "Could not create temporary $state_dir"
 
-               echo $HEAD > "$DOTEST"/head
-               case "$REBASE_ROOT" in
-               '')
-                       rm -f "$DOTEST"/rebase-root ;;
-               *)
-                       : >"$DOTEST"/rebase-root ;;
-               esac
-               echo $ONTO > "$DOTEST"/onto
-               test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy
-               test t = "$VERBOSE" && : > "$DOTEST"/verbose
-               if test t = "$PRESERVE_MERGES"
-               then
-                       if test -z "$REBASE_ROOT"
-                       then
-                               mkdir "$REWRITTEN" &&
-                               for c in $(git merge-base --all $HEAD $UPSTREAM)
-                               do
-                                       echo $ONTO > "$REWRITTEN"/$c ||
-                                               die "Could not init rewritten commits"
-                               done
-                       else
-                               mkdir "$REWRITTEN" &&
-                               echo $ONTO > "$REWRITTEN"/root ||
-                                       die "Could not init rewritten commits"
-                       fi
-                       # No cherry-pick because our first pass is to determine
-                       # parents to rewrite and skipping dropped commits would
-                       # prematurely end our probe
-                       MERGES_OPTION=
-                       first_after_upstream="$(git rev-list --reverse --first-parent $UPSTREAM..$HEAD | head -n 1)"
-               else
-                       MERGES_OPTION="--no-merges --cherry-pick"
-               fi
-
-               SHORTHEAD=$(git rev-parse --short $HEAD)
-               SHORTONTO=$(git rev-parse --short $ONTO)
-               if test -z "$REBASE_ROOT"
-                       # this is now equivalent to ! -z "$UPSTREAM"
-               then
-                       SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
-                       REVISIONS=$UPSTREAM...$HEAD
-                       SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
-               else
-                       REVISIONS=$ONTO...$HEAD
-                       SHORTREVISIONS=$SHORTHEAD
-               fi
-               git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
-                       --abbrev=7 --reverse --left-right --topo-order \
-                       $REVISIONS | \
-                       sed -n "s/^>//p" |
-               while read -r shortsha1 rest
+: > "$state_dir"/interactive || die "Could not mark as interactive"
+write_basic_state
+if test t = "$preserve_merges"
+then
+       if test -z "$rebase_root"
+       then
+               mkdir "$rewritten" &&
+               for c in $(git merge-base --all $orig_head $upstream)
                do
-                       if test t != "$PRESERVE_MERGES"
-                       then
-                               printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
-                       else
-                               sha1=$(git rev-parse $shortsha1)
-                               if test -z "$REBASE_ROOT"
-                               then
-                                       preserve=t
-                                       for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
-                                       do
-                                               if test -f "$REWRITTEN"/$p -a \( $p != $ONTO -o $sha1 = $first_after_upstream \)
-                                               then
-                                                       preserve=f
-                                               fi
-                                       done
-                               else
-                                       preserve=f
-                               fi
-                               if test f = "$preserve"
-                               then
-                                       touch "$REWRITTEN"/$sha1
-                                       printf '%s\n' "pick $shortsha1 $rest" >> "$TODO"
-                               fi
-                       fi
+                       echo $onto > "$rewritten"/$c ||
+                               die "Could not init rewritten commits"
                done
-
-               # Watch for commits that been dropped by --cherry-pick
-               if test t = "$PRESERVE_MERGES"
+       else
+               mkdir "$rewritten" &&
+               echo $onto > "$rewritten"/root ||
+                       die "Could not init rewritten commits"
+       fi
+       # No cherry-pick because our first pass is to determine
+       # parents to rewrite and skipping dropped commits would
+       # prematurely end our probe
+       merges_option=
+       first_after_upstream="$(git rev-list --reverse --first-parent $upstream..$orig_head | head -n 1)"
+else
+       merges_option="--no-merges --cherry-pick"
+fi
+
+shorthead=$(git rev-parse --short $orig_head)
+shortonto=$(git rev-parse --short $onto)
+if test -z "$rebase_root"
+       # this is now equivalent to ! -z "$upstream"
+then
+       shortupstream=$(git rev-parse --short $upstream)
+       revisions=$upstream...$orig_head
+       shortrevisions=$shortupstream..$shorthead
+else
+       revisions=$onto...$orig_head
+       shortrevisions=$shorthead
+fi
+git rev-list $merges_option --pretty=oneline --abbrev-commit \
+       --abbrev=7 --reverse --left-right --topo-order \
+       $revisions | \
+       sed -n "s/^>//p" |
+while read -r shortsha1 rest
+do
+       if test t != "$preserve_merges"
+       then
+               printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
+       else
+               sha1=$(git rev-parse $shortsha1)
+               if test -z "$rebase_root"
                then
-                       mkdir "$DROPPED"
-                       # Save all non-cherry-picked changes
-                       git rev-list $REVISIONS --left-right --cherry-pick | \
-                               sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks
-                       # Now all commits and note which ones are missing in
-                       # not-cherry-picks and hence being dropped
-                       git rev-list $REVISIONS |
-                       while read rev
+                       preserve=t
+                       for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
                        do
-                               if test -f "$REWRITTEN"/$rev -a "$(sane_grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
+                               if test -f "$rewritten"/$p -a \( $p != $onto -o $sha1 = $first_after_upstream \)
                                then
-                                       # Use -f2 because if rev-list is telling us this commit is
-                                       # not worthwhile, we don't want to track its multiple heads,
-                                       # just the history of its first-parent for others that will
-                                       # be rebasing on top of it
-                                       git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
-                                       short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
-                                       sane_grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
-                                       rm "$REWRITTEN"/$rev
+                                       preserve=f
                                fi
                        done
+               else
+                       preserve=f
+               fi
+               if test f = "$preserve"
+               then
+                       touch "$rewritten"/$sha1
+                       printf '%s\n' "pick $shortsha1 $rest" >> "$todo"
                fi
+       fi
+done
 
-               test -s "$TODO" || echo noop >> "$TODO"
-               test -n "$AUTOSQUASH" && rearrange_squash "$TODO"
-               cat >> "$TODO" << EOF
+# Watch for commits that been dropped by --cherry-pick
+if test t = "$preserve_merges"
+then
+       mkdir "$dropped"
+       # Save all non-cherry-picked changes
+       git rev-list $revisions --left-right --cherry-pick | \
+               sed -n "s/^>//p" > "$state_dir"/not-cherry-picks
+       # Now all commits and note which ones are missing in
+       # not-cherry-picks and hence being dropped
+       git rev-list $revisions |
+       while read rev
+       do
+               if test -f "$rewritten"/$rev -a "$(sane_grep "$rev" "$state_dir"/not-cherry-picks)" = ""
+               then
+                       # Use -f2 because if rev-list is telling us this commit is
+                       # not worthwhile, we don't want to track its multiple heads,
+                       # just the history of its first-parent for others that will
+                       # be rebasing on top of it
+                       git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$dropped"/$rev
+                       short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
+                       sane_grep -v "^[a-z][a-z]* $short" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
+                       rm "$rewritten"/$rev
+               fi
+       done
+fi
+
+test -s "$todo" || echo noop >> "$todo"
+test -n "$autosquash" && rearrange_squash "$todo"
+cat >> "$todo" << EOF
 
-# Rebase $SHORTREVISIONS onto $SHORTONTO
+# Rebase $shortrevisions onto $shortonto
 #
 # Commands:
 #  p, pick = use commit
@@ -1028,22 +805,18 @@ first and then run 'git rebase --continue' again."
 #
 EOF
 
-               has_action "$TODO" ||
-                       die_abort "Nothing to do"
+has_action "$todo" ||
+       die_abort "Nothing to do"
 
-               cp "$TODO" "$TODO".backup
-               git_editor "$TODO" ||
-                       die_abort "Could not execute editor"
+cp "$todo" "$todo".backup
+git_editor "$todo" ||
+       die_abort "Could not execute editor"
 
-               has_action "$TODO" ||
-                       die_abort "Nothing to do"
+has_action "$todo" ||
+       die_abort "Nothing to do"
 
-               test -d "$REWRITTEN" || test -n "$NEVER_FF" || skip_unnecessary_picks
+test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
 
-               output git checkout $ONTO || die_abort "could not detach HEAD"
-               git update-ref ORIG_HEAD $HEAD
-               do_rest
-               ;;
-       esac
-       shift
-done
+output git checkout $onto || die_abort "could not detach HEAD"
+git update-ref ORIG_HEAD $orig_head
+do_rest
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
new file mode 100644 (file)
index 0000000..26afc75
--- /dev/null
@@ -0,0 +1,151 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Junio C Hamano.
+#
+
+. git-sh-setup
+
+prec=4
+
+read_state () {
+       onto_name=$(cat "$state_dir"/onto_name) &&
+       end=$(cat "$state_dir"/end) &&
+       msgnum=$(cat "$state_dir"/msgnum)
+}
+
+continue_merge () {
+       test -d "$state_dir" || die "$state_dir directory does not exist"
+
+       unmerged=$(git ls-files -u)
+       if test -n "$unmerged"
+       then
+               echo "You still have unmerged paths in your index"
+               echo "did you forget to use git add?"
+               die "$resolvemsg"
+       fi
+
+       cmt=`cat "$state_dir/current"`
+       if ! git diff-index --quiet --ignore-submodules HEAD --
+       then
+               if ! git commit --no-verify -C "$cmt"
+               then
+                       echo "Commit failed, please do not call \"git commit\""
+                       echo "directly, but instead do one of the following: "
+                       die "$resolvemsg"
+               fi
+               if test -z "$GIT_QUIET"
+               then
+                       printf "Committed: %0${prec}d " $msgnum
+               fi
+               echo "$cmt $(git rev-parse HEAD^0)" >> "$state_dir/rewritten"
+       else
+               if test -z "$GIT_QUIET"
+               then
+                       printf "Already applied: %0${prec}d " $msgnum
+               fi
+       fi
+       test -z "$GIT_QUIET" &&
+       GIT_PAGER='' git log --format=%s -1 "$cmt"
+
+       # onto the next patch:
+       msgnum=$(($msgnum + 1))
+       echo "$msgnum" >"$state_dir/msgnum"
+}
+
+call_merge () {
+       cmt="$(cat "$state_dir/cmt.$1")"
+       echo "$cmt" > "$state_dir/current"
+       hd=$(git rev-parse --verify HEAD)
+       cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
+       msgnum=$(cat "$state_dir/msgnum")
+       eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
+       eval GITHEAD_$hd='$onto_name'
+       export GITHEAD_$cmt GITHEAD_$hd
+       if test -n "$GIT_QUIET"
+       then
+               GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
+       fi
+       test -z "$strategy" && strategy=recursive
+       eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"'
+       rv=$?
+       case "$rv" in
+       0)
+               unset GITHEAD_$cmt GITHEAD_$hd
+               return
+               ;;
+       1)
+               git rerere $allow_rerere_autoupdate
+               die "$resolvemsg"
+               ;;
+       2)
+               echo "Strategy: $strategy failed, try another" 1>&2
+               die "$resolvemsg"
+               ;;
+       *)
+               die "Unknown exit code ($rv) from command:" \
+                       "git-merge-$strategy $cmt^ -- HEAD $cmt"
+               ;;
+       esac
+}
+
+finish_rb_merge () {
+       move_to_original_branch
+       git notes copy --for-rewrite=rebase < "$state_dir"/rewritten
+       if test -x "$GIT_DIR"/hooks/post-rewrite &&
+               test -s "$state_dir"/rewritten; then
+               "$GIT_DIR"/hooks/post-rewrite rebase < "$state_dir"/rewritten
+       fi
+       rm -r "$state_dir"
+       say All done.
+}
+
+case "$action" in
+continue)
+       read_state
+       continue_merge
+       while test "$msgnum" -le "$end"
+       do
+               call_merge "$msgnum"
+               continue_merge
+       done
+       finish_rb_merge
+       exit
+       ;;
+skip)
+       read_state
+       git rerere clear
+       msgnum=$(($msgnum + 1))
+       while test "$msgnum" -le "$end"
+       do
+               call_merge "$msgnum"
+               continue_merge
+       done
+       finish_rb_merge
+       exit
+       ;;
+esac
+
+mkdir -p "$state_dir"
+echo "$onto_name" > "$state_dir/onto_name"
+write_basic_state
+
+msgnum=0
+for cmt in `git rev-list --reverse --no-merges "$revisions"`
+do
+       msgnum=$(($msgnum + 1))
+       echo "$cmt" > "$state_dir/cmt.$msgnum"
+done
+
+echo 1 >"$state_dir/msgnum"
+echo $msgnum >"$state_dir/end"
+
+end=$msgnum
+msgnum=1
+
+while test "$msgnum" -le "$end"
+do
+       call_merge "$msgnum"
+       continue_merge
+done
+
+finish_rb_merge
index cbb0ea90ed410d5af68ce814b7fd93a90829f3ee..7a54bfc6182a567860af023cb7720680d1806c72 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] (<upstream>|--root) [<branch>] [--quiet | -q]'
+USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]'
 LONG_USAGE='git-rebase replaces <branch> with a new branch of the
 same name.  When the --onto option is provided the new branch starts
 out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -28,7 +28,39 @@ Example:       git-rebase master~1 topic
 '
 
 SUBDIRECTORY_OK=Yes
-OPTIONS_SPEC=
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>]
+git rebase [-i] [options] --onto <newbase> --root [<branch>]
+git-rebase [-i] --continue | --abort | --skip
+--
+ Available options are
+v,verbose!         display a diffstat of what changed upstream
+q,quiet!           be quiet. implies --no-stat
+onto=!             rebase onto given branch instead of upstream
+p,preserve-merges! try to recreate merges instead of ignoring them
+s,strategy=!       use the given merge strategy
+no-ff!             cherry-pick all commits, even if unchanged
+m,merge!           use merging strategies to rebase
+i,interactive!     let the user edit the list of commits to rebase
+f,force-rebase!    force rebase even if branch is up to date
+X,strategy-option=! pass the argument through to the merge strategy
+stat!              display a diffstat of what changed upstream
+n,no-stat!         do not show diffstat of what changed upstream
+verify             allow pre-rebase hook to run
+rerere-autoupdate  allow rerere to update index with resolved conflicts
+root!              rebase all reachable commits up to the root(s)
+autosquash         move commits that begin with squash!/fixup! under -i
+committer-date-is-author-date! passed to 'git am'
+ignore-date!       passed to 'git am'
+whitespace=!       passed to 'git apply'
+ignore-whitespace! passed to 'git apply'
+C=!                passed to 'git apply'
+ Actions:
+continue!          continue rebasing process
+abort!             abort rebasing process and restore original branch
+skip!              skip current patch and continue rebasing process
+"
 . git-sh-setup
 set_reflog_action rebase
 require_work_tree
@@ -36,18 +68,18 @@ cd_to_toplevel
 
 LF='
 '
-OK_TO_SKIP_PRE_REBASE=
-RESOLVEMSG="
+ok_to_skip_pre_rebase=
+resolvemsg="
 When you have resolved this problem run \"git rebase --continue\".
 If you would prefer to skip this patch, instead run \"git rebase --skip\".
 To restore the original branch and stop rebasing run \"git rebase --abort\".
 "
-unset newbase
-strategy=recursive
+unset onto
+strategy=
 strategy_opts=
 do_merge=
-dotest="$GIT_DIR"/rebase-merge
-prec=4
+merge_dir="$GIT_DIR"/rebase-merge
+apply_dir="$GIT_DIR"/rebase-apply
 verbose=
 diffstat=
 test "$(git config --bool rebase.stat)" = true && diffstat=t
@@ -55,92 +87,67 @@ git_am_opt=
 rebase_root=
 force_rebase=
 allow_rerere_autoupdate=
-
-continue_merge () {
-       test -n "$prev_head" || die "prev_head must be defined"
-       test -d "$dotest" || die "$dotest directory does not exist"
-
-       unmerged=$(git ls-files -u)
-       if test -n "$unmerged"
-       then
-               echo "You still have unmerged paths in your index"
-               echo "did you forget to use git add?"
-               die "$RESOLVEMSG"
-       fi
-
-       cmt=`cat "$dotest/current"`
-       if ! git diff-index --quiet --ignore-submodules HEAD --
+# Non-empty if a rebase was in progress when 'git rebase' was invoked
+in_progress=
+# One of {am, merge, interactive}
+type=
+# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
+state_dir=
+# One of {'', continue, skip, abort}, as parsed from command line
+action=
+preserve_merges=
+autosquash=
+test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
+
+read_basic_state () {
+       head_name=$(cat "$state_dir"/head-name) &&
+       onto=$(cat "$state_dir"/onto) &&
+       # We always write to orig-head, but interactive rebase used to write to
+       # head. Fall back to reading from head to cover for the case that the
+       # user upgraded git with an ongoing interactive rebase.
+       if test -f "$state_dir"/orig-head
        then
-               if ! git commit --no-verify -C "$cmt"
-               then
-                       echo "Commit failed, please do not call \"git commit\""
-                       echo "directly, but instead do one of the following: "
-                       die "$RESOLVEMSG"
-               fi
-               if test -z "$GIT_QUIET"
-               then
-                       printf "Committed: %0${prec}d " $msgnum
-               fi
-               echo "$cmt $(git rev-parse HEAD^0)" >> "$dotest/rewritten"
+               orig_head=$(cat "$state_dir"/orig-head)
        else
-               if test -z "$GIT_QUIET"
-               then
-                       printf "Already applied: %0${prec}d " $msgnum
-               fi
-       fi
-       test -z "$GIT_QUIET" &&
-       GIT_PAGER='' git log --format=%s -1 "$cmt"
-
-       prev_head=`git rev-parse HEAD^0`
-       # save the resulting commit so we can read-tree on it later
-       echo "$prev_head" > "$dotest/prev_head"
+               orig_head=$(cat "$state_dir"/head)
+       fi &&
+       GIT_QUIET=$(cat "$state_dir"/quiet) &&
+       test -f "$state_dir"/verbose && verbose=t
+       test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
+       test -f "$state_dir"/strategy_opts &&
+               strategy_opts="$(cat "$state_dir"/strategy_opts)"
+       test -f "$state_dir"/allow_rerere_autoupdate &&
+               allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
+}
 
-       # onto the next patch:
-       msgnum=$(($msgnum + 1))
-       echo "$msgnum" >"$dotest/msgnum"
+write_basic_state () {
+       echo "$head_name" > "$state_dir"/head-name &&
+       echo "$onto" > "$state_dir"/onto &&
+       echo "$orig_head" > "$state_dir"/orig-head &&
+       echo "$GIT_QUIET" > "$state_dir"/quiet &&
+       test t = "$verbose" && : > "$state_dir"/verbose
+       test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy
+       test -n "$strategy_opts" && echo "$strategy_opts" > \
+               "$state_dir"/strategy_opts
+       test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
+               "$state_dir"/allow_rerere_autoupdate
 }
 
-call_merge () {
-       cmt="$(cat "$dotest/cmt.$1")"
-       echo "$cmt" > "$dotest/current"
-       hd=$(git rev-parse --verify HEAD)
-       cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
-       msgnum=$(cat "$dotest/msgnum")
-       end=$(cat "$dotest/end")
-       eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
-       eval GITHEAD_$hd='$(cat "$dotest/onto_name")'
-       export GITHEAD_$cmt GITHEAD_$hd
-       if test -n "$GIT_QUIET"
-       then
-               GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
-       fi
-       eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"'
-       rv=$?
-       case "$rv" in
-       0)
-               unset GITHEAD_$cmt GITHEAD_$hd
-               return
-               ;;
-       1)
-               git rerere $allow_rerere_autoupdate
-               die "$RESOLVEMSG"
-               ;;
-       2)
-               echo "Strategy: $rv $strategy failed, try another" 1>&2
-               die "$RESOLVEMSG"
+output () {
+       case "$verbose" in
+       '')
+               output=$("$@" 2>&1 )
+               status=$?
+               test $status != 0 && printf "%s\n" "$output"
+               return $status
                ;;
        *)
-               die "Unknown exit code ($rv) from command:" \
-                       "git-merge-$strategy $cmt^ -- HEAD $cmt"
+               "$@"
                ;;
        esac
 }
 
 move_to_original_branch () {
-       test -z "$head_name" &&
-               head_name="$(cat "$dotest"/head-name)" &&
-               onto="$(cat "$dotest"/onto)" &&
-               orig_head="$(cat "$dotest"/orig-head)"
        case "$head_name" in
        refs/*)
                message="rebase finished: $head_name onto $onto"
@@ -152,42 +159,16 @@ move_to_original_branch () {
        esac
 }
 
-finish_rb_merge () {
-       move_to_original_branch
-       git notes copy --for-rewrite=rebase < "$dotest"/rewritten
-       if test -x "$GIT_DIR"/hooks/post-rewrite &&
-               test -s "$dotest"/rewritten; then
-               "$GIT_DIR"/hooks/post-rewrite rebase < "$dotest"/rewritten
-       fi
-       rm -r "$dotest"
-       say All done.
-}
-
-is_interactive () {
-       while test $# != 0
-       do
-               case "$1" in
-                       -i|--interactive)
-                               interactive_rebase=explicit
-                               break
-                       ;;
-                       -p|--preserve-merges)
-                               interactive_rebase=implied
-                       ;;
-               esac
-               shift
-       done
-
+run_specific_rebase () {
        if [ "$interactive_rebase" = implied ]; then
                GIT_EDITOR=:
                export GIT_EDITOR
        fi
-
-       test -n "$interactive_rebase" || test -f "$dotest"/interactive
+       . git-rebase--$type
 }
 
 run_pre_rebase_hook () {
-       if test -z "$OK_TO_SKIP_PRE_REBASE" &&
+       if test -z "$ok_to_skip_pre_rebase" &&
           test -x "$GIT_DIR/hooks/pre-rebase"
        then
                "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} ||
@@ -195,163 +176,94 @@ run_pre_rebase_hook () {
        fi
 }
 
-test -f "$GIT_DIR"/rebase-apply/applying &&
+test -f "$apply_dir"/applying &&
        die 'It looks like git-am is in progress. Cannot rebase.'
 
-is_interactive "$@" && exec git-rebase--interactive "$@"
+if test -d "$apply_dir"
+then
+       type=am
+       state_dir="$apply_dir"
+elif test -d "$merge_dir"
+then
+       if test -f "$merge_dir"/interactive
+       then
+               type=interactive
+               interactive_rebase=explicit
+       else
+               type=merge
+       fi
+       state_dir="$merge_dir"
+fi
+test -n "$type" && in_progress=t
 
+total_argc=$#
 while test $# != 0
 do
        case "$1" in
        --no-verify)
-               OK_TO_SKIP_PRE_REBASE=yes
+               ok_to_skip_pre_rebase=yes
                ;;
        --verify)
-               OK_TO_SKIP_PRE_REBASE=
-               ;;
-       --continue)
-               test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
-                       die "No rebase in progress?"
-
-               git update-index --ignore-submodules --refresh &&
-               git diff-files --quiet --ignore-submodules || {
-                       echo "You must edit all merge conflicts and then"
-                       echo "mark them as resolved using git add"
-                       exit 1
-               }
-               if test -d "$dotest"
-               then
-                       prev_head=$(cat "$dotest/prev_head")
-                       end=$(cat "$dotest/end")
-                       msgnum=$(cat "$dotest/msgnum")
-                       onto=$(cat "$dotest/onto")
-                       GIT_QUIET=$(cat "$dotest/quiet")
-                       continue_merge
-                       while test "$msgnum" -le "$end"
-                       do
-                               call_merge "$msgnum"
-                               continue_merge
-                       done
-                       finish_rb_merge
-                       exit
-               fi
-               head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
-               onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
-               orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
-               GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
-               git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
-               move_to_original_branch
-               exit
+               ok_to_skip_pre_rebase=
                ;;
-       --skip)
-               test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
-                       die "No rebase in progress?"
-
-               git reset --hard HEAD || exit $?
-               if test -d "$dotest"
-               then
-                       git rerere clear
-                       prev_head=$(cat "$dotest/prev_head")
-                       end=$(cat "$dotest/end")
-                       msgnum=$(cat "$dotest/msgnum")
-                       msgnum=$(($msgnum + 1))
-                       onto=$(cat "$dotest/onto")
-                       GIT_QUIET=$(cat "$dotest/quiet")
-                       while test "$msgnum" -le "$end"
-                       do
-                               call_merge "$msgnum"
-                               continue_merge
-                       done
-                       finish_rb_merge
-                       exit
-               fi
-               head_name=$(cat "$GIT_DIR"/rebase-apply/head-name) &&
-               onto=$(cat "$GIT_DIR"/rebase-apply/onto) &&
-               orig_head=$(cat "$GIT_DIR"/rebase-apply/orig-head) &&
-               GIT_QUIET=$(cat "$GIT_DIR"/rebase-apply/quiet)
-               git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
-               move_to_original_branch
-               exit
-               ;;
-       --abort)
-               test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply ||
-                       die "No rebase in progress?"
-
-               git rerere clear
-
-               test -d "$dotest" || dotest="$GIT_DIR"/rebase-apply
-
-               head_name="$(cat "$dotest"/head-name)" &&
-               case "$head_name" in
-               refs/*)
-                       git symbolic-ref HEAD $head_name ||
-                       die "Could not move back to $head_name"
-                       ;;
-               esac
-               git reset --hard $(cat "$dotest/orig-head")
-               rm -r "$dotest"
-               exit
+       --continue|--skip|--abort)
+               test $total_argc -eq 2 || usage
+               action=${1##--}
                ;;
        --onto)
                test 2 -le "$#" || usage
-               newbase="$2"
+               onto="$2"
                shift
                ;;
-       -M|-m|--m|--me|--mer|--merg|--merge)
+       -i)
+               interactive_rebase=explicit
+               ;;
+       -p)
+               preserve_merges=t
+               test -z "$interactive_rebase" && interactive_rebase=implied
+               ;;
+       --autosquash)
+               autosquash=t
+               ;;
+       --no-autosquash)
+               autosquash=
+               ;;
+       -M|-m)
                do_merge=t
                ;;
-       -X*|--strategy-option*)
-               case "$#,$1" in
-               1,-X|1,--strategy-option)
-                       usage ;;
-               *,-X|*,--strategy-option)
-                       newopt="$2"
-                       shift ;;
-               *,--strategy-option=*)
-                       newopt="$(expr " $1" : ' --strategy-option=\(.*\)')" ;;
-               *,-X*)
-                       newopt="$(expr " $1" : ' -X\(.*\)')" ;;
-               1,*)
-                       usage ;;
-               esac
-               strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")"
+       -X)
+               shift
+               strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$1")"
                do_merge=t
+               test -z "$strategy" && strategy=recursive
                ;;
-       -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
-               --strateg=*|--strategy=*|\
-       -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
-               case "$#,$1" in
-               *,*=*)
-                       strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       strategy="$2"
-                       shift ;;
-               esac
+       -s)
+               shift
+               strategy="$1"
                do_merge=t
                ;;
-       -n|--no-stat)
+       -n)
                diffstat=
                ;;
        --stat)
                diffstat=t
                ;;
-       -v|--verbose)
+       -v)
                verbose=t
                diffstat=t
                GIT_QUIET=
                ;;
-       -q|--quiet)
+       -q)
                GIT_QUIET=t
                git_am_opt="$git_am_opt -q"
                verbose=
                diffstat=
                ;;
-       --whitespace=*)
-               git_am_opt="$git_am_opt $1"
+       --whitespace)
+               shift
+               git_am_opt="$git_am_opt --whitespace=$1"
                case "$1" in
-               --whitespace=fix|--whitespace=strip)
+               fix|strip)
                        force_rebase=t
                        ;;
                esac
@@ -363,22 +275,21 @@ do
                git_am_opt="$git_am_opt $1"
                force_rebase=t
                ;;
-       -C*)
-               git_am_opt="$git_am_opt $1"
+       -C)
+               shift
+               git_am_opt="$git_am_opt -C$1"
                ;;
        --root)
                rebase_root=t
                ;;
-       -f|--f|--fo|--for|--forc|--force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase|--no-ff)
+       -f|--no-ff)
                force_rebase=t
                ;;
        --rerere-autoupdate|--no-rerere-autoupdate)
                allow_rerere_autoupdate="$1"
                ;;
-       -*)
-               usage
-               ;;
-       *)
+       --)
+               shift
                break
                ;;
        esac
@@ -386,58 +297,106 @@ do
 done
 test $# -gt 2 && usage
 
-if test $# -eq 0 && test -z "$rebase_root"
+if test -n "$action"
 then
-       test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || usage
-       test -d "$dotest" -o -f "$GIT_DIR"/rebase-apply/rebasing &&
-               die 'A rebase is in progress, try --continue, --skip or --abort.'
+       test -z "$in_progress" && die "No rebase in progress?"
+       # Only interactive rebase uses detailed reflog messages
+       if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase
+       then
+               GIT_REFLOG_ACTION="rebase -i ($action)"
+               export GIT_REFLOG_ACTION
+       fi
 fi
 
-# Make sure we do not have $GIT_DIR/rebase-apply
-if test -z "$do_merge"
+case "$action" in
+continue)
+       # Sanity check
+       git rev-parse --verify HEAD >/dev/null ||
+               die "Cannot read HEAD"
+       git update-index --ignore-submodules --refresh &&
+       git diff-files --quiet --ignore-submodules || {
+               echo "You must edit all merge conflicts and then"
+               echo "mark them as resolved using git add"
+               exit 1
+       }
+       read_basic_state
+       run_specific_rebase
+       ;;
+skip)
+       output git reset --hard HEAD || exit $?
+       read_basic_state
+       run_specific_rebase
+       ;;
+abort)
+       git rerere clear
+       read_basic_state
+       case "$head_name" in
+       refs/*)
+               git symbolic-ref HEAD $head_name ||
+               die "Could not move back to $head_name"
+               ;;
+       esac
+       output git reset --hard $orig_head
+       rm -r "$state_dir"
+       exit
+       ;;
+esac
+
+# Make sure no rebase is in progress
+if test -n "$in_progress"
 then
-       if mkdir "$GIT_DIR"/rebase-apply 2>/dev/null
-       then
-               rmdir "$GIT_DIR"/rebase-apply
-       else
-               echo >&2 '
-It seems that I cannot create a rebase-apply directory, and
-I wonder if you are in the middle of patch application or another
-rebase.  If that is not the case, please
-       rm -fr '"$GIT_DIR"'/rebase-apply
+       die '
+It seems that there is already a '"${state_dir##*/}"' directory, and
+I wonder if you are in the middle of another rebase.  If that is the
+case, please try
+       git rebase (--continue | --abort | --skip)
+If that is not the case, please
+       rm -fr '"$state_dir"'
 and run me again.  I am stopping in case you still have something
 valuable there.'
-               exit 1
-       fi
-else
-       if test -d "$dotest"
-       then
-               die "previous rebase directory $dotest still exists." \
-                       'Try git rebase (--continue | --abort | --skip)'
-       fi
 fi
 
-require_clean_work_tree "rebase" "Please commit or stash them."
+if test -n "$interactive_rebase"
+then
+       type=interactive
+       state_dir="$merge_dir"
+elif test -n "$do_merge"
+then
+       type=merge
+       state_dir="$merge_dir"
+else
+       type=am
+       state_dir="$apply_dir"
+fi
 
 if test -z "$rebase_root"
 then
-       # The upstream head must be given.  Make sure it is valid.
-       upstream_name="$1"
-       shift
+       case "$#" in
+       0)
+               if ! upstream_name=$(git rev-parse --symbolic-full-name \
+                       --verify -q @{upstream} 2>/dev/null)
+               then
+                       . git-parse-remote
+                       error_on_missing_default_upstream "rebase" "rebase" \
+                               "against" "git rebase <upstream branch>"
+               fi
+               ;;
+       *)      upstream_name="$1"
+               shift
+               ;;
+       esac
        upstream=`git rev-parse --verify "${upstream_name}^0"` ||
        die "invalid upstream $upstream_name"
-       unset root_flag
        upstream_arg="$upstream_name"
 else
-       test -z "$newbase" && die "--root must be used with --onto"
+       test -z "$onto" && die "You must specify --onto when using --root"
        unset upstream_name
        unset upstream
-       root_flag="--root"
-       upstream_arg="$root_flag"
+       upstream_arg=--root
 fi
 
 # Make sure the branch to rebase onto is valid.
-onto_name=${newbase-"$upstream_name"}
+onto_name=${onto-"$upstream_name"}
 case "$onto_name" in
 *...*)
        if      left=${onto_name%...*} right=${onto_name#*...} &&
@@ -456,13 +415,11 @@ case "$onto_name" in
        fi
        ;;
 *)
-       onto=$(git rev-parse --verify "${onto_name}^0") || exit
+       onto=$(git rev-parse --verify "${onto_name}^0") ||
+       die "Does not point to a valid commit: $1"
        ;;
 esac
 
-# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook "$upstream_arg" "$@"
-
 # If the branch to rebase is given, that is the branch we will rebase
 # $branch_name -- branch being rebased, or HEAD (already detached)
 # $orig_head -- commit object name of tip of the branch before rebasing
@@ -475,10 +432,10 @@ case "$#" in
        switch_to="$1"
 
        if git show-ref --verify --quiet -- "refs/heads/$1" &&
-          branch=$(git rev-parse -q --verify "refs/heads/$1")
+          orig_head=$(git rev-parse -q --verify "refs/heads/$1")
        then
                head_name="refs/heads/$1"
-       elif branch=$(git rev-parse -q --verify "$1")
+       elif orig_head=$(git rev-parse -q --verify "$1")
        then
                head_name="detached HEAD"
        else
@@ -496,20 +453,23 @@ case "$#" in
                head_name="detached HEAD"
                branch_name=HEAD ;# detached
        fi
-       branch=$(git rev-parse --verify "${branch_name}^0") || exit
+       orig_head=$(git rev-parse --verify "${branch_name}^0") || exit
        ;;
 esac
-orig_head=$branch
 
-# Now we are rebasing commits $upstream..$branch (or with --root,
-# everything leading up to $branch) on top of $onto
+require_clean_work_tree "rebase" "Please commit or stash them."
+
+# Now we are rebasing commits $upstream..$orig_head (or with --root,
+# everything leading up to $orig_head) on top of $onto
 
 # Check if we are already based on $onto with linear history,
-# but this should be done only when upstream and onto are the same.
-mb=$(git merge-base "$onto" "$branch")
-if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
+# but this should be done only when upstream and onto are the same
+# and if this is not an interactive rebase.
+mb=$(git merge-base "$onto" "$orig_head")
+if test "$type" != interactive && test "$upstream" = "$onto" &&
+       test "$mb" = "$onto" &&
        # linear history?
-       ! (git rev-list --parents "$onto".."$branch" | sane_grep " .* ") > /dev/null
+       ! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
 then
        if test -z "$force_rebase"
        then
@@ -522,10 +482,8 @@ then
        fi
 fi
 
-# Detach HEAD and reset the tree
-say "First, rewinding head to replay your work on top of it..."
-git checkout -q "$onto^0" || die "could not detach HEAD"
-git update-ref ORIG_HEAD $branch
+# If a hook exists, give it a chance to interrupt
+run_pre_rebase_hook "$upstream_arg" "$@"
 
 if test -n "$diffstat"
 then
@@ -537,9 +495,16 @@ then
        GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
 fi
 
+test "$type" = interactive && run_specific_rebase
+
+# Detach HEAD and reset the tree
+say "First, rewinding head to replay your work on top of it..."
+git checkout -q "$onto^0" || die "could not detach HEAD"
+git update-ref ORIG_HEAD $orig_head
+
 # If the $onto is a proper descendant of the tip of the branch, then
 # we just fast-forwarded.
-if test "$mb" = "$branch"
+if test "$mb" = "$orig_head"
 then
        say "Fast-forwarded $branch_name to $onto_name."
        move_to_original_branch
@@ -553,51 +518,4 @@ else
        revisions="$upstream..$orig_head"
 fi
 
-if test -z "$do_merge"
-then
-       git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-               --src-prefix=a/ --dst-prefix=b/ \
-               --no-renames $root_flag "$revisions" |
-       git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
-       move_to_original_branch
-       ret=$?
-       test 0 != $ret -a -d "$GIT_DIR"/rebase-apply &&
-               echo $head_name > "$GIT_DIR"/rebase-apply/head-name &&
-               echo $onto > "$GIT_DIR"/rebase-apply/onto &&
-               echo $orig_head > "$GIT_DIR"/rebase-apply/orig-head &&
-               echo "$GIT_QUIET" > "$GIT_DIR"/rebase-apply/quiet
-       exit $ret
-fi
-
-# start doing a rebase with git-merge
-# this is rename-aware if the recursive (default) strategy is used
-
-mkdir -p "$dotest"
-echo "$onto" > "$dotest/onto"
-echo "$onto_name" > "$dotest/onto_name"
-prev_head=$orig_head
-echo "$prev_head" > "$dotest/prev_head"
-echo "$orig_head" > "$dotest/orig-head"
-echo "$head_name" > "$dotest/head-name"
-echo "$GIT_QUIET" > "$dotest/quiet"
-
-msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$revisions"`
-do
-       msgnum=$(($msgnum + 1))
-       echo "$cmt" > "$dotest/cmt.$msgnum"
-done
-
-echo 1 >"$dotest/msgnum"
-echo $msgnum >"$dotest/end"
-
-end=$msgnum
-msgnum=1
-
-while test "$msgnum" -le "$end"
-do
-       call_merge "$msgnum"
-       continue_merge
-done
-
-finish_rb_merge
+run_specific_rebase
index 76565de2ee517f48001ffacca32e3c08320cfe38..98ab33aae7e35c2d288bc34ddb2bbc71f8a16cdd 100755 (executable)
@@ -1091,7 +1091,7 @@ X-Mailer: git-send-email $gitversion
                            "VALUES: server=$smtp_server ",
                            "encryption=$smtp_encryption ",
                            "hello=$smtp_domain",
-                           defined $smtp_server_port ? "port=$smtp_server_port" : "";
+                           defined $smtp_server_port ? " port=$smtp_server_port" : "";
                }
 
                if (defined $smtp_authuser) {
index a305fb19f11bc4ae80e585b102ecb5d982d1a0f5..0a9403653d7dbbb6927973dcfcc41bfd9a904e05 100755 (executable)
@@ -136,11 +136,12 @@ save_stash () {
                        keep_index=t
                        ;;
                --no-keep-index)
-                       keep_index=
+                       keep_index=n
                        ;;
                -p|--patch)
                        patch_mode=t
-                       keep_index=t
+                       # only default to keep if we don't already have an override
+                       test -z "$keep_index" && keep_index=t
                        ;;
                -q|--quiet)
                        GIT_QUIET=t
@@ -185,7 +186,7 @@ save_stash () {
        then
                git reset --hard ${GIT_QUIET:+-q}
 
-               if test -n "$keep_index" && test -n $i_tree
+               if test "$keep_index" = "t" && test -n $i_tree
                then
                        git read-tree --reset -u $i_tree
                fi
@@ -193,7 +194,7 @@ save_stash () {
                git apply -R < "$TMP-patch" ||
                die "Cannot remove worktree changes"
 
-               if test -z "$keep_index"
+               if test "$keep_index" != "t"
                then
                        git reset
                fi
@@ -264,7 +265,7 @@ parse_flags_and_rev()
        b_tree=
        i_tree=
 
-       REV=$(git rev-parse --no-flags --symbolic "$@" 2>/dev/null)
+       REV=$(git rev-parse --no-flags --symbolic "$@") || exit 1
 
        FLAGS=
        for opt
@@ -310,16 +311,6 @@ parse_flags_and_rev()
        IS_STASH_LIKE=t &&
        test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
        IS_STASH_REF=t
-
-       if test "${REV}" != "${REV%{*\}}"
-       then
-               # maintainers: it would be better if git rev-parse indicated
-               # this condition with a non-zero status code but as of 1.7.2.1 it
-               # it did not. So, we use non-empty stderr output as a proxy for the
-               # condition of interest.
-               test -z "$(git rev-parse "$REV" 2>&1 >/dev/null)" || die "$REV does not exist in the stash log"
-       fi
-
 }
 
 is_stash_like()
@@ -344,9 +335,7 @@ apply_stash () {
 
        assert_stash_like "$@"
 
-       git update-index -q --refresh &&
-       git diff-files --quiet --ignore-submodules ||
-               die 'Cannot apply to a dirty working tree, please stage your changes'
+       git update-index -q --refresh || die 'unable to refresh index'
 
        # current index state
        c_tree=$(git write-tree) ||
index bf0451b46835357af7811096538e9e7d75311166..0fd2fd2188b93fe15bda901f512bd55ad3a5034a 100755 (executable)
@@ -784,6 +784,15 @@ sub cmd_find_rev {
        print "$result\n" if $result;
 }
 
+sub auto_create_empty_directories {
+       my ($gs) = @_;
+       my $var = eval { command_oneline('config', '--get', '--bool',
+                                        "svn-remote.$gs->{repo_id}.automkdirs") };
+       # By default, create empty directories by consulting the unhandled log,
+       # but allow setting it to 'false' to skip it.
+       return !($var && $var eq 'false');
+}
+
 sub cmd_rebase {
        command_noisy(qw/update-index --refresh/);
        my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
@@ -807,7 +816,9 @@ sub cmd_rebase {
                $_fetch_all ? $gs->fetch_all : $gs->fetch;
        }
        command_noisy(rebase_cmd(), $gs->refname);
-       $gs->mkemptydirs;
+       if (auto_create_empty_directories($gs)) {
+               $gs->mkemptydirs;
+       }
 }
 
 sub cmd_show_ignore {
@@ -1245,7 +1256,9 @@ sub post_fetch_checkout {
        command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
        print STDERR "Checked out HEAD:\n  ",
                     $gs->full_url, " r", $gs->last_rev, "\n";
-       $gs->mkemptydirs($gs->last_rev);
+       if (auto_create_empty_directories($gs)) {
+               $gs->mkemptydirs($gs->last_rev);
+       }
 }
 
 sub complete_svn_url {
diff --git a/graph.c b/graph.c
index ef2e24e85a41dc97cf00bb7b19985ec01b8662bf..2f6893dc4f97dfbccad6f22f66861c24021a3c46 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -59,27 +59,6 @@ enum graph_state {
        GRAPH_COLLAPSING
 };
 
-/*
- * The list of available column colors.
- */
-static const char *column_colors_ansi[] = {
-       GIT_COLOR_RED,
-       GIT_COLOR_GREEN,
-       GIT_COLOR_YELLOW,
-       GIT_COLOR_BLUE,
-       GIT_COLOR_MAGENTA,
-       GIT_COLOR_CYAN,
-       GIT_COLOR_BOLD_RED,
-       GIT_COLOR_BOLD_GREEN,
-       GIT_COLOR_BOLD_YELLOW,
-       GIT_COLOR_BOLD_BLUE,
-       GIT_COLOR_BOLD_MAGENTA,
-       GIT_COLOR_BOLD_CYAN,
-       GIT_COLOR_RESET,
-};
-
-#define COLUMN_COLORS_ANSI_MAX (ARRAY_SIZE(column_colors_ansi) - 1)
-
 static const char **column_colors;
 static unsigned short column_colors_max;
 
@@ -228,7 +207,7 @@ struct git_graph *graph_init(struct rev_info *opt)
 
        if (!column_colors)
                graph_set_column_colors(column_colors_ansi,
-                                       COLUMN_COLORS_ANSI_MAX);
+                                       column_colors_ansi_max);
 
        graph->commit = NULL;
        graph->revs = opt;
diff --git a/http.c b/http.c
index 9e767723ed1045445e91e79489cb8ec8bb861965..b27bb57d627f19d725b1f24aa3f06d261e48f8e5 100644 (file)
--- a/http.c
+++ b/http.c
@@ -536,6 +536,7 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
+       curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 
index 9adf4b981953080676aa24907fead1038b920e60..e1ad1a48ce3b8bd8517568a67477d8d0e32dfaa8 100644 (file)
@@ -1193,13 +1193,13 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
        if (!preauth) {
 #ifndef NO_OPENSSL
                if (!srvc->use_ssl && CAP(STARTTLS)) {
-                       if (imap_exec(ctx, 0, "STARTTLS") != RESP_OK)
+                       if (imap_exec(ctx, NULL, "STARTTLS") != RESP_OK)
                                goto bail;
                        if (ssl_socket_connect(&imap->buf.sock, 1,
                                               srvc->ssl_verify))
                                goto bail;
                        /* capabilities may have changed, so get the new capabilities */
-                       if (imap_exec(ctx, 0, "CAPABILITY") != RESP_OK)
+                       if (imap_exec(ctx, NULL, "CAPABILITY") != RESP_OK)
                                goto bail;
                }
 #endif
index f7f4533926e35867725db00f0c89522c4b290898..7845528e88eea6a42f914b5bf596473eb33dea40 100644 (file)
@@ -3,6 +3,7 @@
 #include "xdiff-interface.h"
 #include "ll-merge.h"
 #include "blob.h"
+#include "merge-file.h"
 
 static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
 {
diff --git a/merge-file.h b/merge-file.h
new file mode 100644 (file)
index 0000000..9b3b83a
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef MERGE_FILE_H
+#define MERGE_FILE_H
+
+extern void *merge_file(const char *path, struct blob *base, struct blob *our,
+                       struct blob *their, unsigned long *size);
+
+#endif
index af131508ec7ffa3ac7b1b1b1cadfcda0040becf2..fb3c874ff47c949dc8df89edb320accf90bc8ac9 100644 (file)
 #include "dir.h"
 #include "submodule.h"
 
-static const char rename_limit_advice[] =
-"inexact rename detection was skipped because there were too many\n"
-"  files. You may want to set your merge.renamelimit variable to at least\n"
-"  %d and retry this merge.";
-
 static struct tree *shift_tree_object(struct tree *one, struct tree *two,
                                      const char *subtree_shift)
 {
@@ -344,10 +339,11 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o,
         * make room for the corresponding directory.  Such paths will
         * later be processed in process_df_entry() at the end.  If
         * the corresponding directory ends up being removed by the
-        * merge, then the file will be reinstated at that time;
-        * otherwise, if the file is not supposed to be removed by the
-        * merge, the contents of the file will be placed in another
-        * unique filename.
+        * merge, then the file will be reinstated at that time
+        * (albeit with a different timestamp!); otherwise, if the
+        * file is not supposed to be removed by the merge, the
+        * contents of the file will be placed in another unique
+        * filename.
         *
         * NOTE: This function relies on the fact that entries for a
         * D/F conflict will appear adjacent in the index, with the
@@ -358,6 +354,13 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o,
        int last_len = 0;
        int i;
 
+       /*
+        * Do not do any of this crazyness during the recursive; we don't
+        * even write anything to the working tree!
+        */
+       if (o->call_depth)
+               return;
+
        for (i = 0; i < entries->nr; i++) {
                const char *path = entries->items[i].string;
                int len = strlen(path);
@@ -1260,9 +1263,13 @@ static int merge_content(struct merge_options *o,
        }
 
        if (mfi.clean && !df_conflict_remains &&
-           sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode)
+           sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode &&
+           !o->call_depth && !lstat(path, &st)) {
                output(o, 3, "Skipped %s (merged same as existing)", path);
-       else
+               add_cacheinfo(mfi.mode, mfi.sha, path,
+                             0 /*stage*/, 1 /*refresh*/, 0 /*options*/);
+               return mfi.clean;
+       } else
                output(o, 2, "Auto-merging %s", path);
 
        if (!mfi.clean) {
@@ -1652,8 +1659,9 @@ int merge_recursive(struct merge_options *o,
                commit_list_insert(h2, &(*result)->parents->next);
        }
        flush_output(o);
-       if (o->needed_rename_limit)
-               warning(rename_limit_advice, o->needed_rename_limit);
+       if (show(o, 2))
+               diff_warn_rename_limit("merge.renamelimit",
+                                      o->needed_rename_limit, 0);
        return clean;
 }
 
index faea58dc8c27de23e8fbaff17b39cb9e57708510..69cd6c815d6bb43fdeda9c4b28fc138bed17c057 100644 (file)
@@ -1012,11 +1012,13 @@ static void diagnose_invalid_sha1_path(const char *prefix,
                if (!get_tree_entry(tree_sha1, fullname,
                                    sha1, &mode)) {
                        die("Path '%s' exists, but not '%s'.\n"
-                           "Did you mean '%s:%s'?",
+                           "Did you mean '%s:%s' aka '%s:./%s'?",
                            fullname,
                            filename,
                            object_name,
-                           fullname);
+                           fullname,
+                           object_name,
+                           filename);
                }
                die("Path '%s' does not exist in '%s'",
                    filename, object_name);
@@ -1065,9 +1067,10 @@ static void diagnose_invalid_index_path(int stage,
                if (ce_namelen(ce) == fullnamelen &&
                    !memcmp(ce->name, fullname, fullnamelen))
                        die("Path '%s' is in the index, but not '%s'.\n"
-                           "Did you mean ':%d:%s'?",
+                           "Did you mean ':%d:%s' aka ':%d:./%s'?",
                            fullname, filename,
-                           ce_stage(ce), fullname);
+                           ce_stage(ce), fullname,
+                           ce_stage(ce), filename);
        }
 
        if (!lstat(filename, &st))
index 77444a94df3d4a0cda6403957fd13ea262d3ab24..09c43ae59a7d4715c26f13d72ca37bc759d1c76d 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -30,8 +30,10 @@ void strbuf_init(struct strbuf *sb, size_t hint)
 {
        sb->alloc = sb->len = 0;
        sb->buf = strbuf_slopbuf;
-       if (hint)
+       if (hint) {
                strbuf_grow(sb, hint);
+               sb->buf[0] = '\0';
+       }
 }
 
 void strbuf_release(struct strbuf *sb)
index 1d4d0a5c7d2549c67334a8d5dd3f462962db81f2..f87abb5a0682d7a2fc7c3947789301c4157d331d 100755 (executable)
@@ -25,6 +25,7 @@ check_show 37500000 '1 year, 2 months ago'
 check_show 55188000 '1 year, 9 months ago'
 check_show 630000000 '20 years ago'
 check_show 31449600 '12 months ago'
+check_show 62985600 '2 years ago'
 
 check_parse() {
        echo "$1 -> $2" >expect
index 080117c6bcbb61078539f36011ecd62780bae305..46103a1591680c9803588d24a135abf79fe64ae9 100755 (executable)
@@ -44,7 +44,7 @@ LONG_VALUE=$(printf "x%01021dx a" 7)
 test_expect_success 'do not crash on special long config line' '
        setup &&
        git config section.key "$LONG_VALUE" &&
-       check section.key "fatal: bad config file line 2 in .git/config"
+       check section.key "$LONG_VALUE"
 '
 
 test_done
index ba25ff354d6fc4998237b1145737faf6c836966e..caa687b5b46cea65ed16c70c29cc11e9e8b771f1 100755 (executable)
@@ -28,6 +28,24 @@ test_expect_success 'oneline reflog format' '
        test_cmp expect actual
 '
 
+test_expect_success 'reflog default format' '
+       git reflog -1 >actual &&
+       test_cmp expect actual
+'
+
+cat >expect <<'EOF'
+commit e46513e
+Reflog: HEAD@{0} (C O Mitter <committer@example.com>)
+Reflog message: commit (initial): one
+Author: A U Thor <author@example.com>
+
+    one
+EOF
+test_expect_success 'override reflog default format' '
+       git reflog --format=short -1 >actual &&
+       test_cmp expect actual
+'
+
 cat >expect <<'EOF'
 Reflog: HEAD@{Thu Apr 7 15:13:13 2005 -0700} (C O Mitter <committer@example.com>)
 Reflog message: commit (initial): one
index 9f8adb1f824a5bafe8829e5ab613e2ab83065f4f..4a6396f9e3fb8006969916e12066fa6fc1527b3d 100755 (executable)
@@ -6,6 +6,13 @@ exec </dev/null
 
 . ./test-lib.sh
 
+test_did_you_mean ()
+{
+       printf "fatal: Path '$2$3' $4, but not ${5:-'$3'}.\n" >expected &&
+       printf "Did you mean '$1:$2$3'${2:+ aka '$1:./$3'}?\n" >>expected &&
+       test_cmp expected error
+}
+
 HASH_file=
 
 test_expect_success 'set up basic repo' '
@@ -106,7 +113,7 @@ test_expect_success 'incorrect file in sha1:path' '
        grep "fatal: Path '"'"'index-only.txt'"'"' exists on disk, but not in '"'"'HEAD'"'"'." error &&
        (cd subdir &&
         test_must_fail git rev-parse HEAD:file2.txt 2> error &&
-        grep "Did you mean '"'"'HEAD:subdir/file2.txt'"'"'?" error )
+        test_did_you_mean HEAD subdir/ file2.txt exists )
 '
 
 test_expect_success 'incorrect file in :path and :N:path' '
@@ -115,14 +122,14 @@ test_expect_success 'incorrect file in :path and :N:path' '
        test_must_fail git rev-parse :1:nothing.txt 2> error &&
        grep "Path '"'"'nothing.txt'"'"' does not exist (neither on disk nor in the index)." error &&
        test_must_fail git rev-parse :1:file.txt 2> error &&
-       grep "Did you mean '"'"':0:file.txt'"'"'?" error &&
+       test_did_you_mean ":0" "" file.txt "is in the index" "at stage 1" &&
        (cd subdir &&
         test_must_fail git rev-parse :1:file.txt 2> error &&
-        grep "Did you mean '"'"':0:file.txt'"'"'?" error &&
+        test_did_you_mean ":0" "" file.txt "is in the index" "at stage 1" &&
         test_must_fail git rev-parse :file2.txt 2> error &&
-        grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error &&
+        test_did_you_mean ":0" subdir/ file2.txt "is in the index" &&
         test_must_fail git rev-parse :2:file2.txt 2> error &&
-        grep "Did you mean '"'"':0:subdir/file2.txt'"'"'?" error) &&
+        test_did_you_mean :0 subdir/ file2.txt "is in the index") &&
        test_must_fail git rev-parse :disk-only.txt 2> error &&
        grep "fatal: Path '"'"'disk-only.txt'"'"' exists on disk, but not in the index." error
 '
index 349eebd54268c927249322dc22fc478869860f7c..6eaecec906c49749237b243f772f2e33eb0efedd 100755 (executable)
@@ -158,15 +158,24 @@ test_expect_success 'Show verbose error when HEAD could not be detached' '
 '
 rm -f B
 
-test_expect_success 'dump usage when upstream arg is missing' '
-       git checkout -b usage topic &&
-       test_must_fail git rebase 2>error1 &&
-       grep "[Uu]sage" error1 &&
-       test_must_fail git rebase --abort 2>error2 &&
-       grep "No rebase in progress" error2 &&
-       test_must_fail git rebase --onto master 2>error3 &&
-       grep "[Uu]sage" error3 &&
-       ! grep "can.t shift" error3
+test_expect_success 'fail when upstream arg is missing and not on branch' '
+       git checkout topic &&
+       test_must_fail git rebase >output.out &&
+       grep "You are not currently on a branch" output.out
+'
+
+test_expect_success 'fail when upstream arg is missing and not configured' '
+       git checkout -b no-config topic &&
+       test_must_fail git rebase >output.out &&
+       grep "branch.no-config.merge" output.out
+'
+
+test_expect_success 'default to @{upstream} when upstream arg is missing' '
+       git checkout -b default topic &&
+       git config branch.default.remote .
+       git config branch.default.merge refs/heads/master
+       git rebase &&
+       test "$(git rev-parse default~1)" = "$(git rev-parse master)"
 '
 
 test_expect_success 'rebase -q is quiet' '
index 64446e3db3afed68e970de6fc3c0780db25c85d1..826500bd18a520a37e3490b9deeca94fb9e14405 100755 (executable)
@@ -35,6 +35,11 @@ test_expect_success 'rebase with git am -3 (default)' '
        test_must_fail git rebase master
 '
 
+test_expect_success 'rebase --skip can not be used with other options' '
+       test_must_fail git rebase -v --skip &&
+       test_must_fail git rebase --skip -v
+'
+
 test_expect_success 'rebase --skip with am -3' '
        git rebase --skip
        '
index e573dc845b3d72004b2a96f344528c68977c52e1..a6a6c40a98512b190f8610391aa153a294e4b5cb 100755 (executable)
@@ -84,6 +84,16 @@ testrebase() {
                test_cmp reflog_before reflog_after &&
                rm reflog_before reflog_after
        '
+
+       test_expect_success 'rebase --abort can not be used with other options' '
+               cd "$work_dir" &&
+               # Clean up the state from the previous one
+               git reset --hard pre-rebase &&
+               test_must_fail git rebase$type master &&
+               test_must_fail git rebase -v --abort &&
+               test_must_fail git rebase --abort -v &&
+               git rebase --abort
+       '
 }
 
 testrebase "" .git/rebase-apply
index 3b0d27350e8a0fe43bb7735bc614462347aed3e0..1e855cdae55ff46cbb878b724328b57cdb8069ce 100755 (executable)
@@ -40,4 +40,59 @@ test_expect_success 'non-interactive rebase --continue works with touched file'
        git rebase --continue
 '
 
+test_expect_success 'rebase --continue can not be used with other options' '
+       test_must_fail git rebase -v --continue &&
+       test_must_fail git rebase --continue -v
+'
+
+test_expect_success 'rebase --continue remembers merge strategy and options' '
+       rm -fr .git/rebase-* &&
+       git reset --hard commit-new-file-F2-on-topic-branch &&
+       test_commit "commit-new-file-F3-on-topic-branch" F3 32 &&
+       test_when_finished "rm -fr test-bin funny.was.run" &&
+       mkdir test-bin &&
+       cat >test-bin/git-merge-funny <<-EOF
+       #!$SHELL_PATH
+       case "\$1" in --opt) ;; *) exit 2 ;; esac
+       shift &&
+       >funny.was.run &&
+       exec git merge-recursive "\$@"
+       EOF
+       chmod +x test-bin/git-merge-funny &&
+       (
+               PATH=./test-bin:$PATH
+               test_must_fail git rebase -s funny -Xopt master topic
+       ) &&
+       test -f funny.was.run &&
+       rm funny.was.run &&
+       echo "Resolved" >F2 &&
+       git add F2 &&
+       (
+               PATH=./test-bin:$PATH
+               git rebase --continue
+       ) &&
+       test -f funny.was.run
+'
+
+test_expect_success 'rebase --continue remembers --rerere-autoupdate' '
+       rm -fr .git/rebase-* &&
+       git reset --hard commit-new-file-F3-on-topic-branch &&
+       git checkout master
+       test_commit "commit-new-file-F3" F3 3 &&
+       git config rerere.enabled true &&
+       test_must_fail git rebase -m master topic &&
+       echo "Resolved" >F2 &&
+       git add F2 &&
+       test_must_fail git rebase --continue &&
+       echo "Resolved" >F3 &&
+       git add F3 &&
+       git rebase --continue &&
+       git reset --hard topic@{1} &&
+       test_must_fail git rebase -m --rerere-autoupdate master &&
+       test "$(cat F2)" = "Resolved" &&
+       test_must_fail git rebase --continue &&
+       test "$(cat F3)" = "Resolved" &&
+       git rebase --continue
+'
+
 test_done
index f62aaf5816f6ecf4e2c4e8fe5ae60925e61ccfcd..5c725406422dcedb6c6d5e5d61cfc80f87d3595c 100755 (executable)
@@ -37,14 +37,32 @@ test_expect_success 'parents of stash' '
        test_cmp output expect
 '
 
-test_expect_success 'apply needs clean working directory' '
-       echo 4 > other-file &&
+test_expect_success 'applying bogus stash does nothing' '
+       test_must_fail git stash apply stash@{1} &&
+       echo 1 >expect &&
+       test_cmp expect file
+'
+
+test_expect_success 'apply does not need clean working directory' '
+       echo 4 >other-file &&
        git add other-file &&
-       echo 5 > other-file &&
-       test_must_fail git stash apply
+       echo 5 >other-file &&
+       git stash apply &&
+       echo 3 >expect &&
+       test_cmp expect file
+'
+
+test_expect_success 'apply does not clobber working directory changes' '
+       git reset --hard &&
+       echo 4 >file &&
+       test_must_fail git stash apply &&
+       echo 4 >expect &&
+       test_cmp expect file
 '
 
 test_expect_success 'apply stashed changes' '
+       git reset --hard &&
+       echo 5 >other-file &&
        git add other-file &&
        test_tick &&
        git commit -m other-file &&
@@ -218,6 +236,14 @@ test_expect_success 'stash -k' '
        test bar,bar4 = $(cat file),$(cat file2)
 '
 
+test_expect_success 'stash --no-keep-index' '
+       echo bar33 > file &&
+       echo bar44 > file2 &&
+       git add file2 &&
+       git stash --no-keep-index &&
+       test bar,bar2 = $(cat file),$(cat file2)
+'
+
 test_expect_success 'stash --invalid-option' '
        echo bar5 > file &&
        echo bar6 > file2 &&
@@ -537,11 +563,11 @@ test_expect_success 'invalid ref of the form stash@{n}, n >= N' '
        echo bar6 > file2 &&
        git add file2 &&
        git stash &&
-       test_must_fail git drop stash@{1} &&
-       test_must_fail git pop stash@{1} &&
-       test_must_fail git apply stash@{1} &&
-       test_must_fail git show stash@{1} &&
-       test_must_fail git branch tmp stash@{1} &&
+       test_must_fail git stash drop stash@{1} &&
+       test_must_fail git stash pop stash@{1} &&
+       test_must_fail git stash apply stash@{1} &&
+       test_must_fail git stash show stash@{1} &&
+       test_must_fail git stash branch tmp stash@{1} &&
        git stash drop
 '
 
index 1e7193ac0bc650868f187d3103be32c3004a95b2..781fd716815d90956575b042d72601e67834231c 100755 (executable)
@@ -48,6 +48,18 @@ test_expect_success PERL 'git stash -p --no-keep-index' '
        verify_state bar dummy bar_index
 '
 
+test_expect_success PERL 'git stash --no-keep-index -p' '
+       set_state dir/foo work index &&
+       set_state bar bar_work bar_index &&
+       (echo n; echo y) | git stash save --no-keep-index -p &&
+       verify_state dir/foo head head &&
+       verify_state bar bar_work dummy &&
+       git reset --hard &&
+       git stash apply --index &&
+       verify_state dir/foo work index &&
+       verify_state bar dummy bar_index
+'
+
 test_expect_success PERL 'none of this moved HEAD' '
        verify_saved_head
 '
index cad85450b78891a98a0b60af1422c62c7288265c..3dadf9b31636b862b2ab7377ce7100ebebd397e2 100755 (executable)
@@ -77,4 +77,29 @@ test_expect_success C_LOCALE_OUTPUT  'favour same basenames even with minor diff
        git show HEAD:path1 | sed "s/15/16/" > subdir/path1 &&
        git status | grep "renamed: .*path1 -> subdir/path1"'
 
+test_expect_success 'setup for many rename source candidates' '
+       git reset --hard &&
+       for i in 0 1 2 3 4 5 6 7 8 9;
+       do
+               for j in 0 1 2 3 4 5 6 7 8 9;
+               do
+                       echo "$i$j" >"path$i$j"
+               done
+       done &&
+       git add "path??" &&
+       test_tick &&
+       git commit -m "hundred" &&
+       (cat path1; echo new) >new-path &&
+       echo old >>path1 &&
+       git add new-path path1 &&
+       git diff -l 4 -C -C --cached --name-status >actual 2>actual.err &&
+       sed -e "s/^\([CM]\)[0-9]*       /\1     /" actual >actual.munged &&
+       cat >expect <<-EOF &&
+       C       path1   new-path
+       M       path1
+       EOF
+       test_cmp expect actual.munged &&
+       grep warning actual.err
+'
+
 test_done
index 5daa0f2a0c9c8cd6ed2c06e12c8fd421c178d4f0..93a6f208710befc064b7b99bcd758bb8b6381918 100755 (executable)
@@ -80,18 +80,31 @@ test_expect_success setup '
 
        git config log.showroot false &&
        git commit --amend &&
+
+       GIT_AUTHOR_DATE="2006-06-26 00:06:00 +0000" &&
+       GIT_COMMITTER_DATE="2006-06-26 00:06:00 +0000" &&
+       export GIT_AUTHOR_DATE GIT_COMMITTER_DATE &&
+       git checkout -b rearrange initial &&
+       for i in B A; do echo $i; done >dir/sub &&
+       git add dir/sub &&
+       git commit -m "Rearranged lines in dir/sub" &&
+       git checkout master &&
+
        git show-branch
 '
 
 : <<\EOF
 ! [initial] Initial
  * [master] Merge branch 'side'
-  ! [side] Side
----
- -  [master] Merge branch 'side'
- *+ [side] Side
- *  [master^] Second
-+*+ [initial] Initial
+  ! [rearrange] Rearranged lines in dir/sub
+   ! [side] Side
+----
+  +  [rearrange] Rearranged lines in dir/sub
+ -   [master] Merge branch 'side'
+ * + [side] Side
+ *   [master^] Third
+ *   [master~2] Second
++*++ [initial] Initial
 EOF
 
 V=`git version | sed -e 's/^git version //' -e 's/\./\\./g'`
@@ -287,6 +300,8 @@ diff --no-index --name-status -- dir2 dir
 diff --no-index dir dir3
 diff master master^ side
 diff --dirstat master~1 master~2
+diff --dirstat initial rearrange
+diff --dirstat-by-file initial rearrange
 EOF
 
 test_expect_success 'log -S requires an argument' '
diff --git a/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange b/t/t4013/diff.diff_--dirstat-by-file_initial_rearrange
new file mode 100644 (file)
index 0000000..e48e33f
--- /dev/null
@@ -0,0 +1,3 @@
+$ git diff --dirstat-by-file initial rearrange
+ 100.0% dir/
+$
diff --git a/t/t4013/diff.diff_--dirstat_initial_rearrange b/t/t4013/diff.diff_--dirstat_initial_rearrange
new file mode 100644 (file)
index 0000000..5fb02c1
--- /dev/null
@@ -0,0 +1,3 @@
+$ git diff --dirstat initial rearrange
+ 100.0% dir/
+$
index 1f0f9ad44b241e57e867c0676b73f37a1dc93d60..3b4e113012568dc936bd230fe33c251ab8bff3dd 100644 (file)
@@ -1,7 +1,7 @@
 $ git format-patch --stdout --cover-letter -n initial..master^
 From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001
 From: C O Mitter <committer@example.com>
-Date: Mon, 26 Jun 2006 00:05:00 +0000
+Date: Mon, 26 Jun 2006 00:06:00 +0000
 Subject: [DIFFERENT_PREFIX 0/2] *** SUBJECT HERE ***
 
 *** BLURB HERE ***
index d155e0bab29000a99eb797681450be1174185846..44d45257da708f25bd0eb2c631bd7e68a38a7354 100644 (file)
@@ -1,4 +1,10 @@
 $ git log --decorate=full --all
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (refs/heads/rearrange)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Rearranged lines in dir/sub
+
 commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, refs/heads/master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
index fd7c3e64396b4ea57c3b03d2e120580205263462..27d3eabc26f35401581d64f0a933fb552e5f4d52 100644 (file)
@@ -1,4 +1,10 @@
 $ git log --decorate --all
+commit cd4e72fd96faed3f0ba949dc42967430374e2290 (rearrange)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:06:00 2006 +0000
+
+    Rearranged lines in dir/sub
+
 commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
 Merge: 9a6d494 c7a2ab9
 Author: A U Thor <author@example.com>
index 2a537a21e8e6793e6ffa2fe1522e30f877b209fe..c00a94b9ba4498e72a31856aac9cf653bbce8ba3 100755 (executable)
@@ -11,7 +11,9 @@ test_expect_success setup '
        tr \
          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \
          "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM" \
-         <"$TEST_DIRECTORY"/../COPYING >test
+         <"$TEST_DIRECTORY"/../COPYING >test &&
+       echo "to be deleted" >test2 &&
+       git add test2
 
 '
 
@@ -25,5 +27,44 @@ test_expect_success 'detect rewrite' '
 
 '
 
+cat >expect <<EOF
+diff --git a/test2 b/test2
+deleted file mode 100644
+index 4202011..0000000
+--- a/test2
++++ /dev/null
+@@ -1 +0,0 @@
+-to be deleted
+EOF
+test_expect_success 'show deletion diff without -D' '
+
+       rm test2 &&
+       git diff -- test2 >actual &&
+       test_cmp expect actual
+'
+
+cat >expect <<EOF
+diff --git a/test2 b/test2
+deleted file mode 100644
+index 4202011..0000000
+EOF
+test_expect_success 'suppress deletion diff with -D' '
+
+       git diff -D -- test2 >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'show deletion diff with -B' '
+
+       git diff -B -- test >actual &&
+       grep "Linus Torvalds" actual
+'
+
+test_expect_success 'suppress deletion diff with -B -D' '
+
+       git diff -B -D -- test >actual &&
+       grep -v "Linus Torvalds" actual
+'
+
 test_done
 
index 1ed259d864b4ef4c8c7060fa5f22634a25c8e032..5f3b604fd99b22c73cfdebf0f1cf13539e1af3e4 100755 (executable)
@@ -609,4 +609,67 @@ test_expect_success 'check handling of differently renamed file with D/F conflic
        ! test -f original
 '
 
+test_expect_success 'setup avoid unnecessary update, normal rename' '
+       git reset --hard &&
+       git checkout --orphan avoid-unnecessary-update-1 &&
+       git rm -rf . &&
+       git clean -fdqx &&
+
+       printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
+       git add -A &&
+       git commit -m "Common commmit" &&
+
+       git mv original rename &&
+       echo 11 >>rename &&
+       git add -u &&
+       git commit -m "Renamed and modified" &&
+
+       git checkout -b merge-branch-1 HEAD~1 &&
+       echo "random content" >random-file &&
+       git add -A &&
+       git commit -m "Random, unrelated changes"
+'
+
+test_expect_success 'avoid unnecessary update, normal rename' '
+       git checkout -q avoid-unnecessary-update-1^0 &&
+       test-chmtime =1000000000 rename &&
+       test-chmtime -v +0 rename >expect &&
+       git merge merge-branch-1 &&
+       test-chmtime -v +0 rename >actual &&
+       test_cmp expect actual # "rename" should have stayed intact
+'
+
+test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
+       git reset --hard &&
+       git checkout --orphan avoid-unnecessary-update-2 &&
+       git rm -rf . &&
+       git clean -fdqx &&
+
+       mkdir df &&
+       printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
+       git add -A &&
+       git commit -m "Common commmit" &&
+
+       git mv df/file temp &&
+       rm -rf df &&
+       git mv temp df &&
+       echo 11 >>df &&
+       git add -u &&
+       git commit -m "Renamed and modified" &&
+
+       git checkout -b merge-branch-2 HEAD~1 &&
+       >unrelated-change &&
+       git add unrelated-change &&
+       git commit -m "Only unrelated changes"
+'
+
+test_expect_failure 'avoid unnecessary update, with D/F conflict' '
+       git checkout -q avoid-unnecessary-update-2^0 &&
+       test-chmtime =1000000000 df &&
+       test-chmtime -v +0 df >expect &&
+       git merge merge-branch-2 &&
+       test-chmtime -v +0 df >actual &&
+       test_cmp expect actual # "df" should have stayed intact
+'
+
 test_done
index 7e1be444027621e1ea94b0b9ed0e129fce922b02..800b5368a5248835bb9817c0e0c8409131306b3c 100755 (executable)
@@ -453,4 +453,11 @@ test_expect_success 'git clean -e' '
        )
 '
 
+test_expect_success SANITY 'git clean -d with an unreadable empty directory' '
+       mkdir foo &&
+       chmod a= foo &&
+       git clean -dfx foo &&
+       ! test -d foo
+'
+
 test_done
index 158c8e33ef3381f3310ac39a99932d185290d685..6d3130e61856335dff7004903741a490ae94fc08 100755 (executable)
@@ -28,6 +28,23 @@ test_expect_success 'empty directories exist' '
        )
 '
 
+test_expect_success 'option automkdirs set to false' '
+       (
+               git svn init "$svnrepo" cloned-no-mkdirs &&
+               cd cloned-no-mkdirs &&
+               git config svn-remote.svn.automkdirs false &&
+               git svn fetch &&
+               for i in a b c d d/e d/e/f "weird file name"
+               do
+                       if test -d "$i"
+                       then
+                               echo >&2 "$i exists"
+                               exit 1
+                       fi
+               done
+       )
+'
+
 test_expect_success 'more emptiness' '
        svn_cmd mkdir -m "bang bang"  "$svnrepo"/"! !"
 '
index abc47f3abc5d925ed217d0d95f10bf078bc26034..aca03d2db0eaf2411c01f58554ec0075da491ea7 100644 (file)
@@ -575,7 +575,7 @@ test_external () {
 test_external_without_stderr () {
        # The temporary file has no (and must have no) security
        # implications.
-       tmp="$TMPDIR"; if [ -z "$tmp" ]; then tmp=/tmp; fi
+       tmp=${TMPDIR:-/tmp}
        stderr="$tmp/git-external-stderr.$$.tmp"
        test_external "$@" 4> "$stderr"
        [ -f "$stderr" ] || error "Internal error: $stderr disappeared."
@@ -801,12 +801,14 @@ test_done () {
                mkdir -p "$test_results_dir"
                test_results_path="$test_results_dir/${0%.sh}-$$.counts"
 
-               echo "total $test_count" >> $test_results_path
-               echo "success $test_success" >> $test_results_path
-               echo "fixed $test_fixed" >> $test_results_path
-               echo "broken $test_broken" >> $test_results_path
-               echo "failed $test_failure" >> $test_results_path
-               echo "" >> $test_results_path
+               cat >>"$test_results_path" <<-EOF
+               total $test_count
+               success $test_success
+               fixed $test_fixed
+               broken $test_broken
+               failed $test_failure
+
+               EOF
        fi
 
        if test "$test_fixed" != 0
index bba053f0aac8eef982d6779983dc6fd979d69d69..ce5cbbea6be45a6dfa79bcc8c8244ae0b99c7ca3 100644 (file)
@@ -157,15 +157,8 @@ static void create_pack_file(void)
        const char *argv[10];
        int arg = 0;
 
-       if (shallow_nr) {
-               memset(&rev_list, 0, sizeof(rev_list));
-               rev_list.proc = do_rev_list;
-               rev_list.out = -1;
-               if (start_async(&rev_list))
-                       die("git upload-pack: unable to fork git-rev-list");
-               argv[arg++] = "pack-objects";
-       } else {
-               argv[arg++] = "pack-objects";
+       argv[arg++] = "pack-objects";
+       if (!shallow_nr) {
                argv[arg++] = "--revs";
                if (create_full_pack)
                        argv[arg++] = "--all";
@@ -183,7 +176,7 @@ static void create_pack_file(void)
        argv[arg++] = NULL;
 
        memset(&pack_objects, 0, sizeof(pack_objects));
-       pack_objects.in = shallow_nr ? rev_list.out : -1;
+       pack_objects.in = -1;
        pack_objects.out = -1;
        pack_objects.err = -1;
        pack_objects.git_cmd = 1;
@@ -192,8 +185,14 @@ static void create_pack_file(void)
        if (start_command(&pack_objects))
                die("git upload-pack: unable to fork git-pack-objects");
 
-       /* pass on revisions we (don't) want */
-       if (!shallow_nr) {
+       if (shallow_nr) {
+               memset(&rev_list, 0, sizeof(rev_list));
+               rev_list.proc = do_rev_list;
+               rev_list.out = pack_objects.in;
+               if (start_async(&rev_list))
+                       die("git upload-pack: unable to fork git-rev-list");
+       }
+       else {
                FILE *pipe_fd = xfdopen(pack_objects.in, "w");
                if (!create_full_pack) {
                        int i;
index 572a99596657b85cbda372a9107a43c6c2fb44b2..bc792223b2638bce4196eb0dc6626beb32f48da4 100644 (file)
@@ -13,6 +13,7 @@
 #include "line_buffer.h"
 #include "string_pool.h"
 #include "strbuf.h"
+#include "svndump.h"
 
 /*
  * Compare start of string to literal of equal length;