summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/1.7.4.2.txt9
-rw-r--r--Documentation/RelNotes/1.7.5.txt48
-rw-r--r--Documentation/config.txt6
-rw-r--r--Documentation/git-am.txt6
-rw-r--r--Documentation/git-bisect.txt68
-rw-r--r--Documentation/git-difftool.txt4
-rw-r--r--Documentation/git-log.txt11
-rw-r--r--Documentation/git-mergetool.txt4
-rw-r--r--Documentation/git-rerere.txt4
-rw-r--r--Documentation/git-rev-list.txt3
-rw-r--r--Documentation/gitattributes.txt10
-rw-r--r--Documentation/merge-config.txt8
-rw-r--r--Documentation/merge-options.txt10
-rw-r--r--Documentation/rev-list-options.txt339
-rw-r--r--Makefile42
-rw-r--r--alloc.c11
-rw-r--r--attr.c7
-rw-r--r--builtin/clone.c3
-rw-r--r--builtin/commit.c60
-rw-r--r--builtin/config.c2
-rw-r--r--builtin/describe.c6
-rw-r--r--builtin/fetch-pack.c34
-rw-r--r--builtin/fetch.c2
-rw-r--r--builtin/fmt-merge-msg.c2
-rw-r--r--builtin/grep.c6
-rw-r--r--builtin/hash-object.c2
-rw-r--r--builtin/index-pack.c2
-rw-r--r--builtin/log.c8
-rw-r--r--builtin/ls-remote.c11
-rw-r--r--builtin/merge-index.c3
-rw-r--r--builtin/merge-recursive.c2
-rw-r--r--builtin/merge-tree.c2
-rw-r--r--builtin/merge.c7
-rw-r--r--builtin/mktag.c51
-rw-r--r--builtin/notes.c4
-rw-r--r--builtin/pack-redundant.c3
-rw-r--r--builtin/pack-refs.c2
-rw-r--r--builtin/patch-id.c5
-rw-r--r--builtin/push.c1
-rw-r--r--builtin/receive-pack.c37
-rw-r--r--builtin/remote-ext.c2
-rw-r--r--builtin/remote-fd.c2
-rw-r--r--builtin/remote.c2
-rw-r--r--builtin/rerere.c7
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/rev-list.c14
-rw-r--r--builtin/send-pack.c2
-rw-r--r--builtin/unpack-file.c4
-rw-r--r--builtin/var.c3
-rw-r--r--cache.h12
-rw-r--r--color.c9
-rw-r--r--color.h3
-rw-r--r--config.c15
-rw-r--r--config.mak.in1
-rw-r--r--configure.ac24
-rwxr-xr-xcontrib/completion/git-completion.bash33
-rwxr-xr-xcontrib/fast-import/git-p441
-rw-r--r--daemon.c2
-rw-r--r--diff-lib.c3
-rw-r--r--diff.c4
-rw-r--r--diff.h3
-rw-r--r--diffcore-rename.c15
-rw-r--r--environment.c1
-rw-r--r--fast-import.c2
-rw-r--r--gettext.c14
-rw-r--r--gettext.h40
-rwxr-xr-xgit-bisect.sh10
-rw-r--r--git-mergetool--lib.sh225
-rw-r--r--git-parse-remote.sh50
-rwxr-xr-xgit-pull.sh6
-rwxr-xr-xgit-request-pull.sh3
-rwxr-xr-xgit-stash.sh14
-rwxr-xr-xgit-svn.perl2
-rwxr-xr-xgitweb/gitweb.perl5
-rw-r--r--graph.c17
-rw-r--r--imap-send.c2
-rw-r--r--list-objects.c7
-rw-r--r--log-tree.c28
-rw-r--r--merge-recursive.c13
-rw-r--r--merge-recursive.h2
-rw-r--r--notes-merge.c2
-rw-r--r--parse-options.c4
-rw-r--r--pkt-line.c55
-rw-r--r--po/.gitignore1
-rw-r--r--pretty.c42
-rw-r--r--replace_object.c1
-rw-r--r--revision.c82
-rw-r--r--revision.h8
-rw-r--r--run-command.c17
-rw-r--r--sha1_file.c9
-rw-r--r--submodule.c6
-rw-r--r--t/README7
-rwxr-xr-xt/t0001-init.sh5
-rwxr-xr-xt/t1510-repo-setup.sh2
-rwxr-xr-xt/t3903-stash.sh19
-rwxr-xr-xt/t4013-diff-various.sh3
-rw-r--r--t/t4013/diff.log_-SF_master_--max-count=02
-rw-r--r--t/t4013/diff.log_-SF_master_--max-count=17
-rw-r--r--t/t4013/diff.log_-SF_master_--max-count=27
-rwxr-xr-xt/t4014-format-patch.sh84
-rwxr-xr-xt/t4040-whitespace-status.sh7
-rwxr-xr-xt/t5501-fetch-push-alternates.sh66
-rwxr-xr-xt/t5601-clone.sh1
-rwxr-xr-xt/t6007-rev-list-cherry-pick-file.sh113
-rwxr-xr-xt/t6110-rev-list-sparse.sh20
-rwxr-xr-xt/t7810-grep.sh5
-rwxr-xr-xt/t8006-blame-textconv.sh3
-rwxr-xr-xt/t9130-git-svn-authors-file.sh1
-rwxr-xr-xt/t9800-git-p4.sh23
-rw-r--r--t/test-lib.sh43
-rw-r--r--thread-utils.c2
-rw-r--r--trace.c74
-rw-r--r--transport-helper.c2
-rw-r--r--transport.c36
-rw-r--r--transport.h3
-rw-r--r--unpack-trees.c2
-rw-r--r--upload-pack.c28
-rw-r--r--url.c1
-rw-r--r--usage.c8
-rw-r--r--utf8.c9
-rw-r--r--utf8.h2
-rw-r--r--vcs-svn/fast_export.c27
-rw-r--r--vcs-svn/fast_export.h5
-rw-r--r--vcs-svn/line_buffer.c36
-rw-r--r--vcs-svn/line_buffer.h6
-rw-r--r--vcs-svn/line_buffer.txt3
-rw-r--r--vcs-svn/repo_tree.c43
-rw-r--r--vcs-svn/repo_tree.h10
-rw-r--r--vcs-svn/svndump.c307
-rw-r--r--wt-status.c160
-rw-r--r--wt-status.h7
131 files changed, 1911 insertions, 994 deletions
diff --git a/Documentation/RelNotes/1.7.4.2.txt b/Documentation/RelNotes/1.7.4.2.txt
index afb387161b..991dae4811 100644
--- a/Documentation/RelNotes/1.7.4.2.txt
+++ b/Documentation/RelNotes/1.7.4.2.txt
@@ -7,6 +7,11 @@ Fixes since v1.7.4.1
* Many documentation updates to match "git cmd -h" output and the
git-cmd manual page.
+ * We used to keep one file descriptor open for each and every packfile
+ that we have a mmap window on it (read: "in use"), even when for very
+ tiny packfiles. We now close the file descriptor early when the entire
+ packfile fits inside one mmap window.
+
* "git clone /no/such/path" did not fail correctly.
* "git commit" did not correctly error out when the user asked to use a
@@ -34,6 +39,10 @@ Fixes since v1.7.4.1
to update the upstream branch it forked from is now called "upstream".
The old name "tracking" is and will be supported.
+ * "git submodule update" used to honor the --merge/--rebase option (or
+ corresponding configuration variables) even for a newly cloned
+ subproject, which made no sense (so/submodule-no-update-first-time).
+
* gitweb's "highlight" interface mishandled tabs.
* gitweb had a few forward-incompatible syntactic constructs and
diff --git a/Documentation/RelNotes/1.7.5.txt b/Documentation/RelNotes/1.7.5.txt
index bb0eb40af4..24f5d8c4a4 100644
--- a/Documentation/RelNotes/1.7.5.txt
+++ b/Documentation/RelNotes/1.7.5.txt
@@ -12,6 +12,12 @@ Updates since v1.7.4
* Update to more modern HP-UX port.
+ * The codebase is getting prepared for i18n/l10n; no translated/translatable
+ strings in the code yet.
+
+ * The bash completion script can now complete symmetric difference
+ for "git diff" command, e.g. "git diff ...bra<TAB>".
+
* "git apply -v" reports offset lines when the patch does not apply at
the exact location recorded in the diff output.
@@ -40,12 +46,31 @@ Updates since v1.7.4
reached, without spewing unnecessary error messages that complain about
the server response it never got.
+ * "git fetch" vs "git upload-pack" transfer learned 'no-done'
+ protocol extension to save one round-trip after the content
+ negotiation is done. This saves one HTTP RPC, reducing the overall
+ latency for a trivial fetch.
+
+ * "git grep -f <filename>" learned to treat "-" as "read from the
+ standard input stream".
+
* "git grep --no-index" did not honor pathspecs correctly, returning
paths outside the specified area.
* "git log" type commands now understand globbing pathspecs. You
can say "git log -- '*.txt'" for example.
+ * "git log" family of commands learned --cherry and --cherry-mark
+ options that can be used to view two diverged branches while omitting
+ or highlighting equivalent changes that appear on both sides of a
+ symmetric difference (e.g. "log --cherry A...B").
+
+ * "git mergetool" learned how to drive "beyond compare 3" as well.
+
+ * "git rerere forget" without pathspec used to forget all the saved
+ conflicts that relate to the current merge; it now requires you to
+ give it pathspecs.
+
* "git rev-list --objects $revs -- $pathspec" now limits the objects listed
in its output properly with the pathspec, in preparation for narrow
clones.
@@ -73,11 +98,6 @@ Fixes since v1.7.4
All of the fixes in the v1.7.4.X maintenance series are included in this
release, unless otherwise noted.
- * We used to keep one file descriptor open for each and every packfile
- that we have a mmap window on it (read: "in use"), even when for very
- tiny packfiles. We now close the file descriptor early when the entire
- packfile fits inside one mmap window.
-
* "git apply" used to confuse lines updated by previous hunks as lines
that existed before when applying a hunk, contributing misapplication
of patches with offsets.
@@ -86,12 +106,22 @@ release, unless otherwise noted.
in the working tree that are in the way in order to check out paths
under it from the named branch (js/checkout-untracked-symlink).
- * "git submodule update" used to honor the --merge/--rebase option (or
- corresponding configuration variables) even for a newly cloned
- subproject, which made no sense (so/submodule-no-update-first-time).
+ * "git fetch" from a client that is mostly following the remote
+ needlessly told all of its refs to the server for both sides to
+ compute the set of objects that need to be transferred efficiently,
+ instead of stopping when the server heard enough. In a project with
+ many tags, this turns out to be extremely wasteful, especially over
+ the smart HTTP transport (sp/maint-{upload,fetch}-pack-stop-early~1).
+
+ * "git fetch" run from a repository that uses the same repository as
+ its alternate object store as the repository it is fetching from
+ did not tell the server that it already has access to objects
+ reachable from the refs in their common alternate object store,
+ causing it to fetch unnecessary objects (jc/maint-fetch-alt).
---
exec >/var/tmp/1
-O=v1.7.4.1-291-g01de349
+O=v1.7.4.1-352-gcdc3466
+O=v1.7.4.1-414-gaeb2aaa
echo O=$(git describe 'master')
git shortlog --no-merges ^maint ^$O master
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 701fba92dc..8ea55d46ad 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -558,6 +558,12 @@ core.sparseCheckout::
Enable "sparse checkout" feature. See section "Sparse checkout" in
linkgit:git-read-tree[1] for more information.
+core.abbrev::
+ Set the length object names are abbreviated to. If unspecified,
+ many commands abbreviate to 7 hexdigits, which may not be enough
+ for abbreviated object names to stay unique for sufficiently long
+ time.
+
add.ignore-errors::
add.ignoreErrors::
Tells 'git add' to continue adding files when some files cannot be
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 621b720091..6b1b5af64e 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -173,9 +173,9 @@ aborts in the middle. You can recover from this in one of two ways:
the index file to bring it into a state that the patch should
have produced. Then run the command with the '--resolved' option.
-The command refuses to process new mailboxes while the `.git/rebase-apply`
-directory exists, so if you decide to start over from scratch,
-run `rm -f -r .git/rebase-apply` before running the command with mailbox
+The command refuses to process new mailboxes until the current
+operation is finished, so if you decide to start over from scratch,
+run `git am --abort` before running the command with mailbox
names.
Before any patches are applied, ORIG_HEAD is set to the tip of the
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index a1e47d6798..7b7bafba0c 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -241,7 +241,12 @@ exit(3) manual page), as the value is chopped with "& 0377".
The special exit code 125 should be used when the current source code
cannot be tested. If the script exits with this code, the current
-revision will be skipped (see `git bisect skip` above).
+revision will be skipped (see `git bisect skip` above). 125 was chosen
+as the highest sensible value to use for this purpose, because 126 and 127
+are used by POSIX shells to signal specific error status (127 is for
+command not found, 126 is for command found but not executable---these
+details do not matter, as they are normal errors in the script, as far as
+"bisect run" is concerned).
You may often find that during a bisect session you want to have
temporary modifications (e.g. s/#define DEBUG 0/#define DEBUG 1/ in a
@@ -274,53 +279,68 @@ $ git bisect start HEAD origin -- # HEAD is bad, origin is good
$ git bisect run make test # "make test" builds and tests
------------
-* Automatically bisect a broken test suite:
+* Automatically bisect a broken test case:
+
------------
$ cat ~/test.sh
#!/bin/sh
-make || exit 125 # this skips broken builds
-make test # "make test" runs the test suite
-$ git bisect start v1.3 v1.1 -- # v1.3 is bad, v1.1 is good
+make || exit 125 # this skips broken builds
+~/check_test_case.sh # does the test case pass?
+$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run ~/test.sh
------------
+
Here we use a "test.sh" custom script. In this script, if "make"
fails, we skip the current commit.
+"check_test_case.sh" should "exit 0" if the test case passes,
+and "exit 1" otherwise.
+
-It is safer to use a custom script outside the repository to prevent
-interactions between the bisect, make and test processes and the
-script.
-+
-"make test" should "exit 0", if the test suite passes, and
-"exit 1" otherwise.
+It is safer if both "test.sh" and "check_test_case.sh" are
+outside the repository to prevent interactions between the bisect,
+make and test processes and the scripts.
-* Automatically bisect a broken test case:
+* Automatically bisect with temporary modifications (hot-fix):
+
------------
$ cat ~/test.sh
#!/bin/sh
-make || exit 125 # this skips broken builds
-~/check_test_case.sh # does the test case passes ?
-$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
-$ git bisect run ~/test.sh
+
+# tweak the working tree by merging the hot-fix branch
+# and then attempt a build
+if git merge --no-commit hot-fix &&
+ make
+then
+ # run project specific test and report its status
+ ~/check_test_case.sh
+ status=$?
+else
+ # tell the caller this is untestable
+ status=125
+fi
+
+# undo the tweak to allow clean flipping to the next commit
+git reset --hard
+
+# return control
+exit $status
------------
+
-Here "check_test_case.sh" should "exit 0" if the test case passes,
-and "exit 1" otherwise.
-+
-It is safer if both "test.sh" and "check_test_case.sh" scripts are
-outside the repository to prevent interactions between the bisect,
-make and test processes and the scripts.
+This applies modifications from a hot-fix branch before each test run,
+e.g. in case your build or test environment changed so that older
+revisions may need a fix which newer ones have already. (Make sure the
+hot-fix branch is based off a commit which is contained in all revisions
+which you are bisecting, so that the merge does not pull in too much, or
+use `git cherry-pick` instead of `git merge`.)
-* Automatically bisect a broken test suite:
+* Automatically bisect a broken test case:
+
------------
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
------------
+
-Does the same as the previous example, but on a single line.
+This shows that you can do without a run script if you write the test
+on a single line.
SEE ALSO
--------
diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt
index a5d9c121f1..590f410abf 100644
--- a/Documentation/git-difftool.txt
+++ b/Documentation/git-difftool.txt
@@ -31,8 +31,8 @@ OPTIONS
--tool=<tool>::
Use the diff tool specified by <tool>.
Valid merge tools are:
- kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
- ecmerge, diffuse, opendiff, p4merge and araxis.
+ araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3,
+ kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff.
+
If a diff tool is not specified, 'git difftool'
will use the configuration variable `diff.tool`. If the
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index 7fb842334f..2c84028838 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -25,6 +25,7 @@ OPTIONS
-<n>::
Limits the number of commits to show.
+ Note that this is a commit limiting option, see below.
<since>..<until>::
Show only commits between the named two commits. When
@@ -72,16 +73,16 @@ produced by --stat etc.
to be prefixed with "\-- " to separate them from options or
refnames.
+include::rev-list-options.txt[]
+
+include::pretty-formats.txt[]
+
Common diff options
-~~~~~~~~~~~~~~~~~~~
+-------------------
:git-log: 1
include::diff-options.txt[]
-include::rev-list-options.txt[]
-
-include::pretty-formats.txt[]
-
include::diff-generate-patch.txt[]
Examples
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index 1834adba75..8c79ae8d2a 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -26,8 +26,8 @@ OPTIONS
--tool=<tool>::
Use the merge resolution program specified by <tool>.
Valid merge tools are:
- kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge,
- diffuse, tortoisemerge, opendiff, p4merge and araxis.
+ araxis, bc3, diffuse, ecmerge, emerge, gvimdiff, kdiff3,
+ meld, opendiff, p4merge, tkdiff, tortoisemerge, vimdiff and xxdiff.
+
If a merge resolution program is not specified, 'git mergetool'
will use the configuration variable `merge.tool`. If the
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt
index 161ecad2a9..52db1d80cf 100644
--- a/Documentation/git-rerere.txt
+++ b/Documentation/git-rerere.txt
@@ -7,7 +7,7 @@ git-rerere - Reuse recorded resolution of conflicted merges
SYNOPSIS
--------
-'git rerere' ['clear'|'forget' [<pathspec>]|'diff'|'status'|'gc']
+'git rerere' ['clear'|'forget' <pathspec>|'diff'|'status'|'gc']
DESCRIPTION
-----------
@@ -43,7 +43,7 @@ will automatically invoke this command.
'forget' <pathspec>::
This resets the conflict resolutions which rerere has recorded for the current
-conflict in <pathspec>. The <pathspec> is optional.
+conflict in <pathspec>.
'diff'::
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 5ce4d7fd0b..b08dfbc3c4 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -31,6 +31,9 @@ SYNOPSIS
[ \--parents ]
[ \--timestamp ]
[ \--left-right ]
+ [ \--left-only ]
+ [ \--right-only ]
+ [ \--cherry-mark ]
[ \--cherry-pick ]
[ \--encoding[=<encoding>] ]
[ \--(author|committer|grep)=<pattern> ]
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 7e7e12168e..15aebc6062 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -632,7 +632,7 @@ Performing a three-way merge
`merge`
^^^^^^^
-The attribute `merge` affects how three versions of a file is
+The attribute `merge` affects how three versions of a file are
merged when a file-level merge is necessary during `git merge`,
and other commands such as `git revert` and `git cherry-pick`.
@@ -646,15 +646,15 @@ Unset::
Take the version from the current branch as the
tentative merge result, and declare that the merge has
- conflicts. This is suitable for binary files that does
+ conflicts. This is suitable for binary files that do
not have a well-defined merge semantics.
Unspecified::
By default, this uses the same built-in 3-way merge
- driver as is the case the `merge` attribute is set.
- However, `merge.default` configuration variable can name
- different merge driver to be used for paths to which the
+ driver as is the case when the `merge` attribute is set.
+ However, the `merge.default` configuration variable can name
+ different merge driver to be used with paths for which the
`merge` attribute is unspecified.
String::
diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt
index 1e5c22c5e5..33bf74c334 100644
--- a/Documentation/merge-config.txt
+++ b/Documentation/merge-config.txt
@@ -33,10 +33,10 @@ merge.stat::
merge.tool::
Controls which merge resolution program is used by
- linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3",
- "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff",
- "diffuse", "ecmerge", "tortoisemerge", "p4merge", "araxis" and
- "opendiff". Any other value is treated is custom merge tool
+ linkgit:git-mergetool[1]. Valid built-in values are: "araxis",
+ "bc3", "diffuse", "ecmerge", "emerge", "gvimdiff", "kdiff3", "meld",
+ "opendiff", "p4merge", "tkdiff", "tortoisemerge", "vimdiff"
+ and "xxdiff". Any other value is treated is custom merge tool
and there must be a corresponding mergetool.<tool>.cmd option.
merge.verbosity::
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index e33e0f8e11..b613d4ed08 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -75,9 +75,17 @@ option can be used to override --squash.
ifndef::git-pull[]
-q::
--quiet::
- Operate quietly.
+ Operate quietly. Implies --no-progress.
-v::
--verbose::
Be verbose.
+
+--progress::
+--no-progress::
+ Turn progress on/off explicitly. If neither is specified,
+ progress is shown if standard error is connected to a terminal.
+ Note that not all merge strategies may support progress
+ reporting.
+
endif::git-pull[]
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 9c47ad885b..5c6850f048 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -1,164 +1,10 @@
-Commit Formatting
-~~~~~~~~~~~~~~~~~
-
-ifdef::git-rev-list[]
-Using these options, linkgit:git-rev-list[1] will act similar to the
-more specialized family of commit log tools: linkgit:git-log[1],
-linkgit:git-show[1], and linkgit:git-whatchanged[1]
-endif::git-rev-list[]
-
-include::pretty-options.txt[]
-
---relative-date::
-
- Synonym for `--date=relative`.
-
---date=(relative|local|default|iso|rfc|short|raw)::
-
- Only takes effect for dates shown in human-readable format, such
- as when using "--pretty". `log.date` config variable sets a default
- value for log command's --date option.
-+
-`--date=relative` shows dates relative to the current time,
-e.g. "2 hours ago".
-+
-`--date=local` shows timestamps in user's local timezone.
-+
-`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
-+
-`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
-format, often found in E-mail messages.
-+
-`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
-+
-`--date=raw` shows the date in the internal raw git format `%s %z` format.
-+
-`--date=default` shows timestamps in the original timezone
-(either committer's or author's).
-
-ifdef::git-rev-list[]
---header::
-
- Print the contents of the commit in raw-format; each record is
- separated with a NUL character.
-endif::git-rev-list[]
-
---parents::
-
- Print also the parents of the commit (in the form "commit parent...").
- Also enables parent rewriting, see 'History Simplification' below.
-
---children::
-
- Print also the children of the commit (in the form "commit child...").
- Also enables parent rewriting, see 'History Simplification' below.
-
-ifdef::git-rev-list[]
---timestamp::
- Print the raw commit timestamp.
-endif::git-rev-list[]
-
---left-right::
-
- Mark which side of a symmetric diff a commit is reachable from.
- Commits from the left side are prefixed with `<` and those from
- the right with `>`. If combined with `--boundary`, those
- commits are prefixed with `-`.
-+
-For example, if you have this topology:
-+
------------------------------------------------------------------------
- y---b---b branch B
- / \ /
- / .
- / / \
- o---x---a---a branch A
------------------------------------------------------------------------
-+
-you would get an output like this:
-+
------------------------------------------------------------------------
- $ git rev-list --left-right --boundary --pretty=oneline A...B
-
- >bbbbbbb... 3rd on b
- >bbbbbbb... 2nd on b
- <aaaaaaa... 3rd on a
- <aaaaaaa... 2nd on a
- -yyyyyyy... 1st on b
- -xxxxxxx... 1st on a
------------------------------------------------------------------------
-
---graph::
-
- Draw a text-based graphical representation of the commit history
- on the left hand side of the output. This may cause extra lines
- to be printed in between commits, in order for the graph history
- to be drawn properly.
-+
-This enables parent rewriting, see 'History Simplification' below.
-+
-This implies the '--topo-order' option by default, but the
-'--date-order' option may also be specified.
-
-ifdef::git-rev-list[]
---count::
- Print a number stating how many commits would have been
- listed, and suppress all other output. When used together
- with '--left-right', instead print the counts for left and
- right commits, separated by a tab.
-endif::git-rev-list[]
-
-
-ifndef::git-rev-list[]
-Diff Formatting
-~~~~~~~~~~~~~~~
-
-Below are listed options that control the formatting of diff output.
-Some of them are specific to linkgit:git-rev-list[1], however other diff
-options may be given. See linkgit:git-diff-files[1] for more options.
-
--c::
-
- With this option, diff output for a merge commit
- shows the differences from each of the parents to the merge result
- simultaneously instead of showing pairwise diff between a parent
- and the result one at a time. Furthermore, it lists only files
- which were modified from all parents.
-
---cc::
-
- This flag implies the '-c' options and further compresses the
- patch output by omitting uninteresting hunks whose contents in
- the parents have only two variants and the merge result picks
- one of them without modification.
-
--m::
-
- This flag makes the merge commits show the full diff like
- regular commits; for each merge parent, a separate log entry
- and diff is generated. An exception is that only diff against
- the first parent is shown when '--first-parent' option is given;
- in that case, the output represents the changes the merge
- brought _into_ the then-current branch.
-
--r::
-
- Show recursive diffs.
-
--t::
-
- Show the tree objects in the diff output. This implies '-r'.
-
--s::
- Suppress diff output.
-endif::git-rev-list[]
-
Commit Limiting
~~~~~~~~~~~~~~~
Besides specifying a range of commits that should be listed using the
special notations explained in the description, additional commit
-limiting may be applied.
+limiting may be applied. Note that they are applied before commit
+ordering and formatting options, such as '--reverse'.
--
@@ -305,6 +151,11 @@ ifdef::git-rev-list[]
to /dev/null as the output does not have to be formatted.
endif::git-rev-list[]
+--cherry-mark::
+
+ Like `--cherry-pick` (see below) but mark equivalent commits
+ with `=` rather than omitting them, and inequivalent ones with `+`.
+
--cherry-pick::
Omit any commit that introduces the same change as
@@ -319,6 +170,27 @@ from the other branch (for example, "3rd on b" may be cherry-picked
from branch A). With this option, such pairs of commits are
excluded from the output.
+--left-only::
+--right-only::
+
+ List only commits on the respective side of a symmetric range,
+ i.e. only those which would be marked `<` resp. `>` by
+ `--left-right`.
++
+For example, `--cherry-pick --right-only A...B` omits those
+commits from `B` which are in `A` or are patch-equivalent to a commit in
+`A`. In other words, this lists the `{plus}` commits from `git cherry A B`.
+More precisely, `--cherry-pick --right-only --no-merges` gives the exact
+list.
+
+--cherry::
+
+ A synonym for `--right-only --cherry-mark --no-merges`; useful to
+ limit the output to the commits on our side and mark those that
+ have been applied to the other side of a forked history with
+ `git log --cherry upstream...mybranch`, similar to
+ `git cherry upstream mybranch`.
+
-g::
--walk-reflogs::
@@ -735,3 +607,158 @@ These options are mostly targeted for packing of git repositories.
--do-walk::
Overrides a previous --no-walk.
+
+Commit Formatting
+~~~~~~~~~~~~~~~~~
+
+ifdef::git-rev-list[]
+Using these options, linkgit:git-rev-list[1] will act similar to the
+more specialized family of commit log tools: linkgit:git-log[1],
+linkgit:git-show[1], and linkgit:git-whatchanged[1]
+endif::git-rev-list[]
+
+include::pretty-options.txt[]
+
+--relative-date::
+
+ Synonym for `--date=relative`.
+
+--date=(relative|local|default|iso|rfc|short|raw)::
+
+ Only takes effect for dates shown in human-readable format, such
+ as when using "--pretty". `log.date` config variable sets a default
+ value for log command's --date option.
++
+`--date=relative` shows dates relative to the current time,
+e.g. "2 hours ago".
++
+`--date=local` shows timestamps in user's local timezone.
++
+`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
++
+`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
+format, often found in E-mail messages.
++
+`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
++
+`--date=raw` shows the date in the internal raw git format `%s %z` format.
++
+`--date=default` shows timestamps in the original timezone
+(either committer's or author's).
+
+ifdef::git-rev-list[]
+--header::
+
+ Print the contents of the commit in raw-format; each record is
+ separated with a NUL character.
+endif::git-rev-list[]
+
+--parents::
+
+ Print also the parents of the commit (in the form "commit parent...").
+ Also enables parent rewriting, see 'History Simplification' below.
+
+--children::
+
+ Print also the children of the commit (in the form "commit child...").
+ Also enables parent rewriting, see 'History Simplification' below.
+
+ifdef::git-rev-list[]
+--timestamp::
+ Print the raw commit timestamp.
+endif::git-rev-list[]
+
+--left-right::
+
+ Mark which side of a symmetric diff a commit is reachable from.
+ Commits from the left side are prefixed with `<` and those from
+ the right with `>`. If combined with `--boundary`, those
+ commits are prefixed with `-`.
++
+For example, if you have this topology:
++
+-----------------------------------------------------------------------
+ y---b---b branch B
+ / \ /
+ / .
+ / / \
+ o---x---a---a branch A
+-----------------------------------------------------------------------
++
+you would get an output like this:
++
+-----------------------------------------------------------------------
+ $ git rev-list --left-right --boundary --pretty=oneline A...B
+
+ >bbbbbbb... 3rd on b
+ >bbbbbbb... 2nd on b
+ <aaaaaaa... 3rd on a
+ <aaaaaaa... 2nd on a
+ -yyyyyyy... 1st on b
+ -xxxxxxx... 1st on a
+-----------------------------------------------------------------------
+
+--graph::
+
+ Draw a text-based graphical representation of the commit history
+ on the left hand side of the output. This may cause extra lines
+ to be printed in between commits, in order for the graph history
+ to be drawn properly.
++
+This enables parent rewriting, see 'History Simplification' below.
++
+This implies the '--topo-order' option by default, but the
+'--date-order' option may also be specified.
+
+ifdef::git-rev-list[]
+--count::
+ Print a number stating how many commits would have been
+ listed, and suppress all other output. When used together
+ with '--left-right', instead print the counts for left and
+ right commits, separated by a tab.
+endif::git-rev-list[]
+
+
+ifndef::git-rev-list[]
+Diff Formatting
+~~~~~~~~~~~~~~~
+
+Below are listed options that control the formatting of diff output.
+Some of them are specific to linkgit:git-rev-list[1], however other diff
+options may be given. See linkgit:git-diff-files[1] for more options.
+
+-c::
+
+ With this option, diff output for a merge commit
+ shows the differences from each of the parents to the merge result
+ simultaneously instead of showing pairwise diff between a parent
+ and the result one at a time. Furthermore, it lists only files
+ which were modified from all parents.
+
+--cc::
+
+ This flag implies the '-c' options and further compresses the
+ patch output by omitting uninteresting hunks whose contents in
+ the parents have only two variants and the merge result picks
+ one of them without modification.
+
+-m::
+
+ This flag makes the merge commits show the full diff like
+ regular commits; for each merge parent, a separate log entry
+ and diff is generated. An exception is that only diff against
+ the first parent is shown when '--first-parent' option is given;
+ in that case, the output represents the changes the merge
+ brought _into_ the then-current branch.
+
+-r::
+
+ Show recursive diffs.
+
+-t::
+
+ Show the tree objects in the diff output. This implies '-r'.
+
+-s::
+ Suppress diff output.
+endif::git-rev-list[]
diff --git a/Makefile b/Makefile
index 5c2b797554..b0f155ab30 100644
--- a/Makefile
+++ b/Makefile
@@ -45,11 +45,6 @@ all::
# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
# d_type in struct dirent (Cygwin 1.5, fixed in Cygwin 1.7).
#
-# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
-# do not support the 'size specifiers' introduced by C99, namely ll, hh,
-# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
-# some C compilers supported these specifiers prior to C99 as an extension.
-#
# Define NO_STRCASESTR if you don't have strcasestr.
#
# Define NO_MEMMEM if you don't have memmem.
@@ -216,6 +211,11 @@ all::
#
# Define NO_REGEX if you have no or inferior regex support in your C library.
#
+# Define GETTEXT_POISON if you are debugging the choice of strings marked
+# for translation. In a GETTEXT_POISON build, you can turn all strings marked
+# for translation into gibberish by setting the GIT_GETTEXT_POISON variable
+# (to any value) in your environment.
+#
# Define JSMIN to point to JavaScript minifier that functions as
# a filter to have gitweb.js minified.
#
@@ -316,6 +316,7 @@ INSTALL = install
RPMBUILD = rpmbuild
TCL_PATH = tclsh
TCLTK_PATH = wish
+XGETTEXT = xgettext
PTHREAD_LIBS = -lpthread
PTHREAD_CFLAGS =
GCOV = gcov
@@ -515,6 +516,7 @@ LIB_H += diff.h
LIB_H += dir.h
LIB_H += exec_cmd.h
LIB_H += fsck.h
+LIB_H += gettext.h
LIB_H += git-compat-util.h
LIB_H += graph.h
LIB_H += grep.h
@@ -871,7 +873,6 @@ ifeq ($(uname_S),SunOS)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
NO_STRLCPY = YesPlease
- NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
endif
@@ -882,21 +883,18 @@ ifeq ($(uname_S),SunOS)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
NO_STRLCPY = YesPlease
- NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
endif
ifeq ($(uname_R),5.8)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
- NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
endif
ifeq ($(uname_R),5.9)
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
- NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
GIT_TEST_CMP = cmp
endif
@@ -1076,7 +1074,6 @@ ifeq ($(uname_S),Windows)
NO_MEMMEM = YesPlease
# NEEDS_LIBICONV = YesPlease
NO_ICONV = YesPlease
- NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
NO_STRTOULL = YesPlease
NO_MKDTEMP = YesPlease
@@ -1153,7 +1150,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_MEMMEM = YesPlease
NEEDS_LIBICONV = YesPlease
OLD_ICONV = YesPlease
- NO_C99_FORMAT = YesPlease
NO_STRTOUMAX = YesPlease
NO_MKDTEMP = YesPlease
NO_MKSTEMPS = YesPlease
@@ -1356,9 +1352,6 @@ endif
ifdef NO_NSEC
BASIC_CFLAGS += -DNO_NSEC
endif
-ifdef NO_C99_FORMAT
- BASIC_CFLAGS += -DNO_C99_FORMAT
-endif
ifdef SNPRINTF_RETURNS_BOGUS
COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
COMPAT_OBJS += compat/snprintf.o
@@ -1370,6 +1363,10 @@ endif
ifdef NO_SYMLINK_HEAD
BASIC_CFLAGS += -DNO_SYMLINK_HEAD
endif
+ifdef GETTEXT_POISON
+ LIB_OBJS += gettext.o
+ BASIC_CFLAGS += -DGETTEXT_POISON
+endif
ifdef NO_STRCASESTR
COMPAT_CFLAGS += -DNO_STRCASESTR
COMPAT_OBJS += compat/strcasestr.o
@@ -1581,6 +1578,7 @@ ifndef V
QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
QUIET_GEN = @echo ' ' GEN $@;
QUIET_LNCP = @echo ' ' LN/CP $@;
+ QUIET_XGETTEXT = @echo ' ' XGETTEXT $@;
QUIET_GCOV = @echo ' ' GCOV $@;
QUIET_SUBDIR0 = +@subdir=
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
@@ -2048,6 +2046,20 @@ info:
pdf:
$(MAKE) -C Documentation pdf
+XGETTEXT_FLAGS = \
+ --force-po \
+ --add-comments \
+ --msgid-bugs-address="Git Mailing List <git@vger.kernel.org>" \
+ --from-code=UTF-8
+XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --keyword=_ --keyword=N_ --language=C
+LOCALIZED_C := $(C_OBJ:o=c)
+
+po/git.pot: $(LOCALIZED_C)
+ $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C) && \
+ mv $@+ $@
+
+pot: po/git.pot
+
$(ETAGS_TARGET): FORCE
$(RM) $(ETAGS_TARGET)
$(FIND) . -name '*.[hcS]' -print | xargs etags -a -o $(ETAGS_TARGET)
@@ -2089,6 +2101,7 @@ endif
ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
@echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@
endif
+ @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@
### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK
@@ -2314,6 +2327,7 @@ dist-doc:
distclean: clean
$(RM) configure
+ $(RM) po/git.pot
clean:
$(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
diff --git a/alloc.c b/alloc.c
index 6ef6753d18..aeae55c976 100644
--- a/alloc.c
+++ b/alloc.c
@@ -51,19 +51,12 @@ DEFINE_ALLOCATOR(commit, struct commit)
DEFINE_ALLOCATOR(tag, struct tag)
DEFINE_ALLOCATOR(object, union any_object)
-#ifdef NO_C99_FORMAT
-#define SZ_FMT "%u"
-#else
-#define SZ_FMT "%zu"
-#endif
-
static void report(const char *name, unsigned int count, size_t size)
{
- fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size);
+ fprintf(stderr, "%10s: %8u (%"PRIuMAX" kB)\n",
+ name, count, (uintmax_t) size);
}
-#undef SZ_FMT
-
#define REPORT(name) \
report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
diff --git a/attr.c b/attr.c
index 6aff6951d3..0e28ba871f 100644
--- a/attr.c
+++ b/attr.c
@@ -478,11 +478,6 @@ int git_attr_system(void)
return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
}
-int git_attr_global(void)
-{
- return !git_env_bool("GIT_ATTR_NOGLOBAL", 0);
-}
-
static int git_attr_config(const char *var, const char *value, void *dummy)
{
if (!strcmp(var, "core.attributesfile"))
@@ -511,7 +506,7 @@ static void bootstrap_attr_stack(void)
}
git_config(git_attr_config, NULL);
- if (git_attr_global() && attributes_file) {
+ if (attributes_file) {
elem = read_attr_from_file(attributes_file, 1);
if (elem) {
elem->origin = NULL;
diff --git a/builtin/clone.c b/builtin/clone.c
index 404f589680..c6e10bb9e9 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -8,7 +8,7 @@
* Clone a repository into a different directory that does not yet exist.
*/
-#include "cache.h"
+#include "builtin.h"
#include "parse-options.h"
#include "fetch-pack.h"
#include "refs.h"
@@ -383,6 +383,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
junk_pid = getpid();
+ packet_trace_identity("clone");
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
diff --git a/builtin/commit.c b/builtin/commit.c
index 82092e5c82..3979b823ef 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -612,7 +612,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
int commitable, saved_color_setting;
struct strbuf sb = STRBUF_INIT;
char *buffer;
- FILE *fp;
const char *hook_arg1 = NULL;
const char *hook_arg2 = NULL;
int ident_shown = 0;
@@ -705,8 +704,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
hook_arg2 = "";
}
- fp = fopen(git_path(commit_editmsg), "w");
- if (fp == NULL)
+ s->fp = fopen(git_path(commit_editmsg), "w");
+ if (s->fp == NULL)
die_errno("could not open '%s'", git_path(commit_editmsg));
if (cleanup_mode != CLEANUP_NONE)
@@ -730,7 +729,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
strbuf_release(&sob);
}
- if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+ if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
die_errno("could not write commit template");
strbuf_release(&sb);
@@ -743,56 +742,58 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
if (use_editor && include_status) {
char *ai_tmp, *ci_tmp;
if (whence != FROM_COMMIT)
- fprintf(fp,
- "#\n"
- "# It looks like you may be committing a %s.\n"
- "# If this is not correct, please remove the file\n"
- "# %s\n"
- "# and try again.\n"
- "#\n",
+ status_printf_ln(s, GIT_COLOR_NORMAL,
+ "\n"
+ "It looks like you may be committing a %s.\n"
+ "If this is not correct, please remove the file\n"
+ " %s\n"
+ "and try again.\n"
+ "",
whence_s(),
git_path(whence == FROM_MERGE
? "MERGE_HEAD"
: "CHERRY_PICK_HEAD"));
- fprintf(fp,
- "\n"
- "# Please enter the commit message for your changes.");
+
+ fprintf(s->fp, "\n");
+ status_printf(s, GIT_COLOR_NORMAL,
+ "Please enter the commit message for your changes.");
if (cleanup_mode == CLEANUP_ALL)
- fprintf(fp,
+ status_printf_more(s, GIT_COLOR_NORMAL,
" Lines starting\n"
- "# with '#' will be ignored, and an empty"
+ "with '#' will be ignored, and an empty"
" message aborts the commit.\n");
else /* CLEANUP_SPACE, that is. */
- fprintf(fp,
+ status_printf_more(s, GIT_COLOR_NORMAL,
" Lines starting\n"
- "# with '#' will be kept; you may remove them"
+ "with '#' will be kept; you may remove them"
" yourself if you want to.\n"
- "# An empty message aborts the commit.\n");
+ "An empty message aborts the commit.\n");
if (only_include_assumed)
- fprintf(fp, "# %s\n", only_include_assumed);
+ status_printf_ln(s, GIT_COLOR_NORMAL,
+ "%s", only_include_assumed);
ai_tmp = cut_ident_timestamp_part(author_ident->buf);
ci_tmp = cut_ident_timestamp_part(committer_ident.buf);
if (strcmp(author_ident->buf, committer_ident.buf))
- fprintf(fp,
+ status_printf_ln(s, GIT_COLOR_NORMAL,
"%s"
- "# Author: %s\n",
- ident_shown++ ? "" : "#\n",
+ "Author: %s",
+ ident_shown++ ? "" : "\n",
author_ident->buf);
if (!user_ident_sufficiently_given())
- fprintf(fp,
+ status_printf_ln(s, GIT_COLOR_NORMAL,
"%s"
- "# Committer: %s\n",
- ident_shown++ ? "" : "#\n",
+ "Committer: %s",
+ ident_shown++ ? "" : "\n",
committer_ident.buf);
if (ident_shown)
- fprintf(fp, "#\n");
+ status_printf_ln(s, GIT_COLOR_NORMAL, "");
saved_color_setting = s->use_color;
s->use_color = 0;
- commitable = run_status(fp, index_file, prefix, 1, s);
+ commitable = run_status(s->fp, index_file, prefix, 1, s);
s->use_color = saved_color_setting;
*ai_tmp = ' ';
@@ -814,7 +815,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
}
strbuf_release(&committer_ident);
- fclose(fp);
+ fclose(s->fp);
/*
* Reject an attempt to record a non-merge empty commit without
@@ -1285,7 +1286,6 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
get_commit_format(format.buf, &rev);
rev.always_show_header = 0;
rev.diffopt.detect_rename = 1;
- rev.diffopt.rename_limit = 100;
rev.diffopt.break_opt = 0;
diff_setup_done(&rev.diffopt);
diff --git a/builtin/config.c b/builtin/config.c
index 76be0b786f..3e3c528497 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -160,7 +160,7 @@ static int get_value(const char *key_, const char *regex_)
if (!local) {
const char *home = getenv("HOME");
local = repo_config = git_pathdup("config");
- if (git_config_global() && home)
+ if (home)
global = xstrdup(mkpath("%s/.gitconfig", home));
if (git_config_system())
system_wide = git_etc_gitconfig();
diff --git a/builtin/describe.c b/builtin/describe.c
index 3ba26dc819..4afd1504a6 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -21,7 +21,7 @@ static int debug; /* Display lots of verbose info */
static int all; /* Any valid ref can be used */
static int tags; /* Allow lightweight tags */
static int longformat;
-static int abbrev = DEFAULT_ABBREV;
+static int abbrev = -1; /* unspecified */
static int max_candidates = 10;
static struct hash_table names;
static int have_util;
@@ -420,7 +420,11 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
+ if (abbrev < 0)
+ abbrev = DEFAULT_ABBREV;
+
if (max_candidates < 0)
max_candidates = 0;
else if (max_candidates > MAX_TAGS)
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index b999413934..0ef9a11940 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "refs.h"
#include "pkt-line.h"
#include "commit.h"
@@ -9,11 +9,13 @@
#include "fetch-pack.h"
#include "remote.h"
#include "run-command.h"
+#include "transport.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
static int unpack_limit = 100;
static int prefer_ofs_delta = 1;
+static int no_done = 0;
static struct fetch_pack_args args = {
/* .uploadpack = */ "git-upload-pack",
};
@@ -217,6 +219,16 @@ static void send_request(int fd, struct strbuf *buf)
safe_write(fd, buf->buf, buf->len);
}
+static void insert_one_alternate_ref(const struct ref *ref, void *unused)
+{
+ rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
+}
+
+static void insert_alternate_refs(void)
+{
+ foreach_alt_odb(refs_from_alternate_cb, insert_one_alternate_ref);
+}
+
static int find_common(int fd[2], unsigned char *result_sha1,
struct ref *refs)
{
@@ -225,6 +237,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
const unsigned char *sha1;
unsigned in_vain = 0;
int got_continue = 0;
+ int got_ready = 0;
struct strbuf req_buf = STRBUF_INIT;
size_t state_len = 0;
@@ -235,6 +248,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
marked = 1;
for_each_ref(rev_list_insert_ref, NULL);
+ insert_alternate_refs();
fetching = 0;
for ( ; refs ; refs = refs->next) {
@@ -262,6 +276,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
struct strbuf c = STRBUF_INIT;
if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed");
if (multi_ack == 1) strbuf_addstr(&c, " multi_ack");
+ if (no_done) strbuf_addstr(&c, " no-done");
if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k");
if (use_sideband == 1) strbuf_addstr(&c, " side-band");
if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack");
@@ -379,6 +394,10 @@ static int find_common(int fd[2], unsigned char *result_sha1,
retval = 0;
in_vain = 0;
got_continue = 1;
+ if (ack == ACK_ready) {
+ rev_list = NULL;
+ got_ready = 1;
+ }
break;
}
}
@@ -392,8 +411,10 @@ static int find_common(int fd[2], unsigned char *result_sha1,
}
}
done:
- packet_buf_write(&req_buf, "done\n");
- send_request(fd[1], &req_buf);
+ if (!got_ready || !no_done) {
+ packet_buf_write(&req_buf, "done\n");
+ send_request(fd[1], &req_buf);
+ }
if (args.verbose)
fprintf(stderr, "done\n");
if (retval != 0) {
@@ -696,6 +717,11 @@ static struct ref *do_fetch_pack(int fd[2],
if (args.verbose)
fprintf(stderr, "Server supports multi_ack_detailed\n");
multi_ack = 2;
+ if (server_supports("no-done")) {
+ if (args.verbose)
+ fprintf(stderr, "Server supports no-done\n");
+ no_done = 1;
+ }
}
else if (server_supports("multi_ack")) {
if (args.verbose)
@@ -804,6 +830,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
char **pack_lockfile_ptr = NULL;
struct child_process *conn;
+ packet_trace_identity("fetch-pack");
+
nr_heads = 0;
heads = NULL;
for (i = 1; i < argc; i++) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7efecfe1cf..1b6d4be002 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -906,6 +906,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct remote *remote;
int result = 0;
+ packet_trace_identity("fetch");
+
/* Record the command line for the reflog */
strbuf_addstr(&default_rla, "fetch");
for (i = 1; i < argc; i++)
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 5189b16c9e..75816329d6 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -31,7 +31,7 @@ struct src_data {
int head_status;
};
-void init_src_data(struct src_data *data)
+static void init_src_data(struct src_data *data)
{
data->branch.strdup_strings = 1;
data->tag.strdup_strings = 1;
diff --git a/builtin/grep.c b/builtin/grep.c
index eaf8560a52..0bf8c0116a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -659,11 +659,12 @@ static int context_callback(const struct option *opt, const char *arg,
static int file_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
+ int from_stdin = !strcmp(arg, "-");
FILE *patterns;
int lno = 0;
struct strbuf sb = STRBUF_INIT;
- patterns = fopen(arg, "r");
+ patterns = from_stdin ? stdin : fopen(arg, "r");
if (!patterns)
die_errno("cannot open '%s'", arg);
while (strbuf_getline(&sb, patterns, '\n') == 0) {
@@ -677,7 +678,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
s = strbuf_detach(&sb, &len);
append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
}
- fclose(patterns);
+ if (!from_stdin)
+ fclose(patterns);
strbuf_release(&sb);
return 0;
}
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index c90acddcb2..b96f46acf5 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -4,7 +4,7 @@
* Copyright (C) Linus Torvalds, 2005
* Copyright (C) Junio C Hamano, 2005
*/
-#include "cache.h"
+#include "builtin.h"
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index c7e600db47..5a67c8181e 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -207,7 +207,7 @@ static void parse_pack_header(void)
static NORETURN void bad_object(unsigned long offset, const char *format,
...) __attribute__((format (printf, 2, 3)));
-static void bad_object(unsigned long offset, const char *format, ...)
+static NORETURN void bad_object(unsigned long offset, const char *format, ...)
{
va_list params;
char buf[1024];
diff --git a/builtin/log.c b/builtin/log.c
index 99e33b3651..796e9e5746 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -263,7 +263,13 @@ static int cmd_log_walk(struct rev_info *rev)
* retain that state information if replacing rev->diffopt in this loop
*/
while ((commit = get_revision(rev)) != NULL) {
- log_tree_commit(rev, commit);
+ if (!log_tree_commit(rev, commit) &&
+ rev->max_count >= 0)
+ /*
+ * We decremented max_count in get_revision,
+ * but we didn't actually show the commit.
+ */
+ rev->max_count++;
if (!rev->reflog_info) {
/* we allow cycles in reflog ancestry */
free(commit->buffer);
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 97eed4012b..1a1ff87e8f 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -33,6 +33,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
int i;
const char *dest = NULL;
unsigned flags = 0;
+ int get_url = 0;
int quiet = 0;
const char *uploadpack = NULL;
const char **pattern = NULL;
@@ -69,6 +70,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
quiet = 1;
continue;
}
+ if (!strcmp("--get-url", arg)) {
+ get_url = 1;
+ continue;
+ }
usage(ls_remote_usage);
}
dest = arg;
@@ -94,6 +99,12 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
}
if (!remote->url_nr)
die("remote %s has no configured URL", dest);
+
+ if (get_url) {
+ printf("%s\n", *remote->url);
+ return 0;
+ }
+
transport = transport_get(remote, NULL);
if (uploadpack != NULL)
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index 2c4cf5e559..2338832587 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -1,6 +1,5 @@
-#include "cache.h"
+#include "builtin.h"
#include "run-command.h"
-#include "exec_cmd.h"
static const char *pgm;
static int one_shot, quiet;
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index c33091b3ed..3a64f5d0bd 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "commit.h"
#include "tag.h"
#include "merge-recursive.h"
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 9b25ddc979..19917426fb 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "tree-walk.h"
#include "xdiff-interface.h"
#include "blob.h"
diff --git a/builtin/merge.c b/builtin/merge.c
index b4746ee55b..aa3453c5e1 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -58,6 +58,7 @@ static int option_renormalize;
static int verbosity;
static int allow_rerere_auto;
static int abort_current_merge;
+static int show_progress = -1;
static struct strategy all_strategy[] = {
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
@@ -200,6 +201,7 @@ static struct option builtin_merge_options[] = {
OPT__VERBOSITY(&verbosity),
OPT_BOOLEAN(0, "abort", &abort_current_merge,
"abort the current in-progress merge"),
+ OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
OPT_END()
};
@@ -660,6 +662,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
o.subtree_shift = "";
o.renormalize = option_renormalize;
+ o.show_rename_progress =
+ show_progress == -1 ? isatty(2) : show_progress;
for (x = 0; x < xopts_nr; x++)
if (parse_merge_opt(&o, xopts[x]))
@@ -974,6 +978,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, builtin_merge_options,
builtin_merge_usage, 0);
+ if (verbosity < 0 && show_progress == -1)
+ show_progress = 0;
+
if (abort_current_merge) {
int nargc = 2;
const char *nargv[] = {"reset", "--merge", NULL};
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 1cb0f3f2a7..324a267163 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -1,6 +1,5 @@
-#include "cache.h"
+#include "builtin.h"
#include "tag.h"
-#include "exec_cmd.h"
/*
* A signature file has a very simple fixed format: four lines
@@ -35,12 +34,6 @@ static int verify_object(const unsigned char *sha1, const char *expected_type)
return ret;
}
-#ifdef NO_C99_FORMAT
-#define PD_FMT "%d"
-#else
-#define PD_FMT "%td"
-#endif
-
static int verify_tag(char *buffer, unsigned long size)
{
int typelen;
@@ -70,15 +63,18 @@ static int verify_tag(char *buffer, unsigned long size)
/* Verify tag-line */
tag_line = strchr(type_line, '\n');
if (!tag_line)
- return error("char" PD_FMT ": could not find next \"\\n\"", type_line - buffer);
+ return error("char%"PRIuMAX": could not find next \"\\n\"",
+ (uintmax_t) (type_line - buffer));
tag_line++;
if (memcmp(tag_line, "tag ", 4) || tag_line[4] == '\n')
- return error("char" PD_FMT ": no \"tag \" found", tag_line - buffer);
+ return error("char%"PRIuMAX": no \"tag \" found",
+ (uintmax_t) (tag_line - buffer));
/* Get the actual type */
typelen = tag_line - type_line - strlen("type \n");
if (typelen >= sizeof(type))
- return error("char" PD_FMT ": type too long", type_line+5 - buffer);
+ return error("char%"PRIuMAX": type too long",
+ (uintmax_t) (type_line+5 - buffer));
memcpy(type, type_line+5, typelen);
type[typelen] = 0;
@@ -95,15 +91,16 @@ static int verify_tag(char *buffer, unsigned long size)
break;
if (c > ' ')
continue;
- return error("char" PD_FMT ": could not verify tag name", tag_line - buffer);
+ return error("char%"PRIuMAX": could not verify tag name",
+ (uintmax_t) (tag_line - buffer));
}
/* Verify the tagger line */
tagger_line = tag_line;
if (memcmp(tagger_line, "tagger ", 7))
- return error("char" PD_FMT ": could not find \"tagger \"",
- tagger_line - buffer);
+ return error("char%"PRIuMAX": could not find \"tagger \"",
+ (uintmax_t) (tagger_line - buffer));
/*
* Check for correct form for name and email
@@ -115,44 +112,42 @@ static int verify_tag(char *buffer, unsigned long size)
if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) ||
strpbrk(tagger_line, "<>\n") != lb+1 ||
strpbrk(lb+2, "><\n ") != rb)
- return error("char" PD_FMT ": malformed tagger field",
- tagger_line - buffer);
+ return error("char%"PRIuMAX": malformed tagger field",
+ (uintmax_t) (tagger_line - buffer));
/* Check for author name, at least one character, space is acceptable */
if (lb == tagger_line)
- return error("char" PD_FMT ": missing tagger name",
- tagger_line - buffer);
+ return error("char%"PRIuMAX": missing tagger name",
+ (uintmax_t) (tagger_line - buffer));
/* timestamp, 1 or more digits followed by space */
tagger_line = rb + 2;
if (!(len = strspn(tagger_line, "0123456789")))
- return error("char" PD_FMT ": missing tag timestamp",
- tagger_line - buffer);
+ return error("char%"PRIuMAX": missing tag timestamp",
+ (uintmax_t) (tagger_line - buffer));
tagger_line += len;
if (*tagger_line != ' ')
- return error("char" PD_FMT ": malformed tag timestamp",
- tagger_line - buffer);
+ return error("char%"PRIuMAX": malformed tag timestamp",
+ (uintmax_t) (tagger_line - buffer));
tagger_line++;
/* timezone, 5 digits [+-]hhmm, max. 1400 */
if (!((tagger_line[0] == '+' || tagger_line[0] == '-') &&
strspn(tagger_line+1, "0123456789") == 4 &&
tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400))
- return error("char" PD_FMT ": malformed tag timezone",
- tagger_line - buffer);
+ return error("char%"PRIuMAX": malformed tag timezone",
+ (uintmax_t) (tagger_line - buffer));
tagger_line += 6;
/* Verify the blank line separating the header from the body */
if (*tagger_line != '\n')
- return error("char" PD_FMT ": trailing garbage in tag header",
- tagger_line - buffer);
+ return error("char%"PRIuMAX": trailing garbage in tag header",
+ (uintmax_t) (tagger_line - buffer));
/* The actual stuff afterwards we don't care about.. */
return 0;
}
-#undef PD_FMT
-
int cmd_mktag(int argc, const char **argv, const char *prefix)
{
struct strbuf buf = STRBUF_INIT;
diff --git a/builtin/notes.c b/builtin/notes.c
index 0aab150c52..a0f310b729 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -423,7 +423,7 @@ void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c)
free(c);
}
-int notes_copy_from_stdin(int force, const char *rewrite_cmd)
+static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
{
struct strbuf buf = STRBUF_INIT;
struct notes_rewrite_cfg *c = NULL;
@@ -819,7 +819,7 @@ static int merge_commit(struct notes_merge_options *o)
t = xcalloc(1, sizeof(struct notes_tree));
init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
- o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, 0);
+ o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
if (!o->local_ref)
die("Failed to resolve NOTES_MERGE_REF");
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 41e1615a28..f5c6afc5dd 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -6,8 +6,7 @@
*
*/
-#include "cache.h"
-#include "exec_cmd.h"
+#include "builtin.h"
#define BLKSIZE 512
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index 091860b2e3..39a9d89fbd 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "parse-options.h"
#include "pack-refs.h"
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 49a0472a9b..f821eb3f0b 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,5 +1,4 @@
-#include "cache.h"
-#include "exec_cmd.h"
+#include "builtin.h"
static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c)
{
@@ -57,7 +56,7 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
return 1;
}
-int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
+static int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
{
static char line[1000];
int patchlen = 0, found_next = 0;
diff --git a/builtin/push.c b/builtin/push.c
index c3c2feb944..6f6a66f986 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -245,6 +245,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_END()
};
+ packet_trace_identity("push");
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d883585804..27050e7c16 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -731,43 +731,14 @@ static int delete_only(struct command *commands)
return 1;
}
-static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
+static void add_one_alternate_ref(const struct ref *ref, void *unused)
{
- char *other;
- size_t len;
- struct remote *remote;
- struct transport *transport;
- const struct ref *extra;
-
- e->name[-1] = '\0';
- other = xstrdup(real_path(e->base));
- e->name[-1] = '/';
- len = strlen(other);
-
- while (other[len-1] == '/')
- other[--len] = '\0';
- if (len < 8 || memcmp(other + len - 8, "/objects", 8))
- return 0;
- /* Is this a git repository with refs? */
- memcpy(other + len - 8, "/refs", 6);
- if (!is_directory(other))
- return 0;
- other[len - 8] = '\0';
- remote = remote_get(other);
- transport = transport_get(remote, other);
- for (extra = transport_get_remote_refs(transport);
- extra;
- extra = extra->next) {
- add_extra_ref(".have", extra->old_sha1, 0);
- }
- transport_disconnect(transport);
- free(other);
- return 0;
+ add_extra_ref(".have", ref->old_sha1, 0);
}
static void add_alternate_refs(void)
{
- foreach_alt_odb(add_refs_from_alternate, NULL);
+ foreach_alt_odb(refs_from_alternate_cb, add_one_alternate_ref);
}
int cmd_receive_pack(int argc, const char **argv, const char *prefix)
@@ -778,6 +749,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
char *dir = NULL;
struct command *commands;
+ packet_trace_identity("receive-pack");
+
argv++;
for (i = 1; i < argc; i++) {
const char *arg = *argv++;
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index ea71977c83..155e609d68 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -1,4 +1,4 @@
-#include "git-compat-util.h"
+#include "builtin.h"
#include "transport.h"
#include "run-command.h"
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index 1f2467bdb7..08d7121b6d 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -1,4 +1,4 @@
-#include "git-compat-util.h"
+#include "builtin.h"
#include "transport.h"
/*
diff --git a/builtin/remote.c b/builtin/remote.c
index cb26080956..b71ecd228f 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "parse-options.h"
#include "transport.h"
#include "remote.h"
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 67cbfeb152..82358855d1 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -8,7 +8,7 @@
#include "xdiff-interface.h"
static const char * const rerere_usage[] = {
- "git rerere [clear | status | remaining | diff | gc]",
+ "git rerere [clear | forget path... | status | remaining | diff | gc]",
NULL,
};
@@ -136,7 +136,10 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
return rerere(flags);
if (!strcmp(argv[0], "forget")) {
- const char **pathspec = get_pathspec(prefix, argv + 1);
+ const char **pathspec;
+ if (argc < 2)
+ warning("'git rerere forget' without paths is deprecated");
+ pathspec = get_pathspec(prefix, argv + 1);
return rerere_forget(pathspec);
}
diff --git a/builtin/reset.c b/builtin/reset.c
index 5de2bceeec..eb5f98c163 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -7,7 +7,7 @@
*
* Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
*/
-#include "cache.h"
+#include "builtin.h"
#include "tag.h"
#include "object.h"
#include "commit.h"
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index ba27d39f97..f458cb7587 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -64,18 +64,8 @@ static void show_commit(struct commit *commit, void *data)
if (info->header_prefix)
fputs(info->header_prefix, stdout);
- if (!revs->graph) {
- if (commit->object.flags & BOUNDARY)
- putchar('-');
- else if (commit->object.flags & UNINTERESTING)
- putchar('^');
- else if (revs->left_right) {
- if (commit->object.flags & SYMMETRIC_LEFT)
- putchar('<');
- else
- putchar('>');
- }
- }
+ if (!revs->graph)
+ fputs(get_revision_mark(revs, commit), stdout);
if (revs->abbrev_commit && revs->abbrev)
fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev),
stdout);
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 2cd1c40b70..8b0911c0d2 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
#include "commit.h"
#include "refs.h"
#include "pkt-line.h"
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 608590ada8..19200291a2 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -1,6 +1,4 @@
-#include "cache.h"
-#include "blob.h"
-#include "exec_cmd.h"
+#include "builtin.h"
static char *create_temp_file(unsigned char *sha1)
{
diff --git a/builtin/var.c b/builtin/var.c
index 0744bb8318..99d068a532 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -3,8 +3,7 @@
*
* Copyright (C) Eric Biederman, 2005
*/
-#include "cache.h"
-#include "exec_cmd.h"
+#include "builtin.h"
static const char var_usage[] = "git var (-l | <variable>)";
diff --git a/cache.h b/cache.h
index a99fd560e9..f765cf5da2 100644
--- a/cache.h
+++ b/cache.h
@@ -5,6 +5,7 @@
#include "strbuf.h"
#include "hash.h"
#include "advice.h"
+#include "gettext.h"
#include SHA1_HEADER
#ifndef git_SHA_CTX
@@ -555,6 +556,7 @@ extern int trust_executable_bit;
extern int trust_ctime;
extern int quote_path_fully;
extern int has_symlinks;
+extern int minimum_abbrev, default_abbrev;
extern int ignore_case;
extern int assume_unchanged;
extern int prefer_symlink_refs;
@@ -774,8 +776,8 @@ static inline unsigned int hexval(unsigned char c)
}
/* Convert to/from hex/sha1 representation */
-#define MINIMUM_ABBREV 4
-#define DEFAULT_ABBREV 7
+#define MINIMUM_ABBREV minimum_abbrev
+#define DEFAULT_ABBREV default_abbrev
struct object_context {
unsigned char tree[20];
@@ -1021,7 +1023,6 @@ extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value, void *cb);
extern int git_env_bool(const char *, int);
extern int git_config_system(void);
-extern int git_config_global(void);
extern int config_error_nonbool(const char *);
extern const char *get_log_output_encoding(void);
extern const char *get_commit_output_encoding(void);
@@ -1083,9 +1084,14 @@ extern void alloc_report(void);
/* trace.c */
__attribute__((format (printf, 1, 2)))
extern void trace_printf(const char *format, ...);
+extern void trace_vprintf(const char *key, const char *format, va_list ap);
__attribute__((format (printf, 2, 3)))
extern void trace_argv_printf(const char **argv, const char *format, ...);
extern void trace_repo_setup(const char *prefix);
+extern int trace_want(const char *key);
+extern void trace_strbuf(const char *key, const struct strbuf *buf);
+
+void packet_trace_identity(const char *prog);
/* convert.c */
/* returns 1 if *dst was used */
diff --git a/color.c b/color.c
index 6a5a54ec66..417cf8fb28 100644
--- a/color.c
+++ b/color.c
@@ -175,6 +175,15 @@ int git_color_default_config(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
+void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
+{
+ if (*color)
+ fprintf(fp, "%s", color);
+ fprintf(fp, "%s", sb->buf);
+ if (*color)
+ fprintf(fp, "%s", GIT_COLOR_RESET);
+}
+
static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
va_list args, const char *trail)
{
diff --git a/color.h b/color.h
index 170ff4074d..c0528cf087 100644
--- a/color.h
+++ b/color.h
@@ -1,6 +1,8 @@
#ifndef COLOR_H
#define COLOR_H
+struct strbuf;
+
/* 2 + (2 * num_attrs) + 8 + 1 + 8 + 'm' + NUL */
/* "\033[1;2;4;5;7;38;5;2xx;48;5;2xxm\0" */
/*
@@ -64,6 +66,7 @@ __attribute__((format (printf, 3, 4)))
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
__attribute__((format (printf, 3, 4)))
int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
+void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
int color_is_nil(const char *color);
diff --git a/config.c b/config.c
index fa740a6a60..0abcada938 100644
--- a/config.c
+++ b/config.c
@@ -523,6 +523,14 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.abbrev")) {
+ int abbrev = git_config_int(var, value);
+ if (abbrev < minimum_abbrev || abbrev > 40)
+ return -1;
+ default_abbrev = abbrev;
+ return 0;
+ }
+
if (!strcmp(var, "core.loosecompression")) {
int level = git_config_int(var, value);
if (level == -1)
@@ -825,11 +833,6 @@ int git_config_system(void)
return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
}
-int git_config_global(void)
-{
- return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
-}
-
int git_config_from_parameters(config_fn_t fn, void *data)
{
static int loaded_environment;
@@ -861,7 +864,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
}
home = getenv("HOME");
- if (git_config_global() && home) {
+ if (home) {
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
if (!access(user_config, R_OK)) {
ret += git_config_from_file(fn, user_config, data);
diff --git a/config.mak.in b/config.mak.in
index 9614973057..e378534cbd 100644
--- a/config.mak.in
+++ b/config.mak.in
@@ -43,7 +43,6 @@ NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@
NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@
NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@
NO_IPV6=@NO_IPV6@
-NO_C99_FORMAT=@NO_C99_FORMAT@
NO_HSTRERROR=@NO_HSTRERROR@
NO_STRCASESTR=@NO_STRCASESTR@
NO_STRTOK_R=@NO_STRTOK_R@
diff --git a/configure.ac b/configure.ac
index 20039c546f..dd0790725b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -686,30 +686,6 @@ AC_CHECK_TYPE([struct addrinfo],[
])
AC_SUBST(NO_IPV6)
#
-# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
-# do not support the 'size specifiers' introduced by C99, namely ll, hh,
-# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
-# some C compilers supported these specifiers prior to C99 as an extension.
-AC_CACHE_CHECK([whether formatted IO functions support C99 size specifiers],
- [ac_cv_c_c99_format],
-[# Actually git uses only %z (%zu) in alloc.c, and %t (%td) in mktag.c
-AC_RUN_IFELSE(
- [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
- [[char buf[64];
- if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
- return 1;
- else if (strcmp(buf, "12345"))
- return 2;]])],
- [ac_cv_c_c99_format=yes],
- [ac_cv_c_c99_format=no])
-])
-if test $ac_cv_c_c99_format = no; then
- NO_C99_FORMAT=YesPlease
-else
- NO_C99_FORMAT=
-fi
-AC_SUBST(NO_C99_FORMAT)
-#
# Define NO_REGEX if you have no or inferior regex support in your C library.
AC_CACHE_CHECK([whether the platform regex can handle null bytes],
[ac_cv_c_excellent_regex], [
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 0b0b913d28..3b1cc83e2d 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -664,11 +664,14 @@ __git_compute_merge_strategies ()
: ${__git_merge_strategies:=$(__git_list_merge_strategies)}
}
-__git_complete_file ()
+__git_complete_revlist_file ()
{
local pfx ls ref cur
_get_comp_words_by_ref -n =: cur
case "$cur" in
+ *..?*:*)
+ return
+ ;;
?*:*)
ref="${cur%%:*}"
cur="${cur#*:}"
@@ -682,7 +685,7 @@ __git_complete_file ()
*)
ls="$ref"
;;
- esac
+ esac
case "$COMP_WORDBREAKS" in
*:*) : great ;;
@@ -707,17 +710,6 @@ __git_complete_file ()
s/^.* //')" \
-- "$cur"))
;;
- *)
- __gitcomp "$(__git_refs)"
- ;;
- esac
-}
-
-__git_complete_revlist ()
-{
- local pfx cur
- _get_comp_words_by_ref -n =: cur
- case "$cur" in
*...*)
pfx="${cur%...*}..."
cur="${cur#*...}"
@@ -734,6 +726,17 @@ __git_complete_revlist ()
esac
}
+
+__git_complete_file ()
+{
+ __git_complete_revlist_file
+}
+
+__git_complete_revlist ()
+{
+ __git_complete_revlist_file
+}
+
__git_complete_remote_or_refspec ()
{
local cur words cword
@@ -1356,11 +1359,11 @@ _git_diff ()
return
;;
esac
- __git_complete_file
+ __git_complete_revlist_file
}
__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
- tkdiff vimdiff gvimdiff xxdiff araxis p4merge
+ tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
"
_git_difftool ()
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 7cb479c5e1..3881515034 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -333,9 +333,13 @@ def gitBranchExists(branch):
return proc.wait() == 0;
_gitConfig = {}
-def gitConfig(key):
+def gitConfig(key, args = None): # set args to "--bool", for instance
if not _gitConfig.has_key(key):
- _gitConfig[key] = read_pipe("git config %s" % key, ignore_error=True).strip()
+ argsFilter = ""
+ if args != None:
+ argsFilter = "%s " % args
+ cmd = "git config %s%s" % (argsFilter, key)
+ _gitConfig[key] = read_pipe(cmd, ignore_error=True).strip()
return _gitConfig[key]
def p4BranchesInGit(branchesAreInRemotes = True):
@@ -452,6 +456,19 @@ def p4ChangesForPaths(depotPaths, changeRange):
changelist.sort()
return changelist
+def p4PathStartsWith(path, prefix):
+ # This method tries to remedy a potential mixed-case issue:
+ #
+ # If UserA adds //depot/DirA/file1
+ # and UserB adds //depot/dira/file2
+ #
+ # we may or may not have a problem. If you have core.ignorecase=true,
+ # we treat DirA and dira as the same directory
+ ignorecase = gitConfig("core.ignorecase", "--bool") == "true"
+ if ignorecase:
+ return path.lower().startswith(prefix.lower())
+ return path.startswith(prefix)
+
class Command:
def __init__(self):
self.usage = "usage: %prog [options]"
@@ -599,7 +616,7 @@ class P4Submit(Command):
lastTab = path.rfind("\t")
if lastTab != -1:
path = path[:lastTab]
- if not path.startswith(self.depotPath):
+ if not p4PathStartsWith(path, self.depotPath):
continue
else:
inFilesSection = False
@@ -937,11 +954,11 @@ class P4Sync(Command):
path = commit["depotFile%s" % fnum]
if [p for p in self.cloneExclude
- if path.startswith (p)]:
+ if p4PathStartsWith(path, p)]:
found = False
else:
found = [p for p in self.depotPaths
- if path.startswith (p)]
+ if p4PathStartsWith(path, p)]
if not found:
fnum = fnum + 1
continue
@@ -976,7 +993,7 @@ class P4Sync(Command):
prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
for p in prefixes:
- if path.startswith(p):
+ if p4PathStartsWith(path, p):
path = path[len(p):]
return path
@@ -987,7 +1004,7 @@ class P4Sync(Command):
while commit.has_key("depotFile%s" % fnum):
path = commit["depotFile%s" % fnum]
found = [p for p in self.depotPaths
- if path.startswith (p)]
+ if p4PathStartsWith(path, p)]
if not found:
fnum = fnum + 1
continue
@@ -1140,10 +1157,10 @@ class P4Sync(Command):
# create a commit.
new_files = []
for f in files:
- if [p for p in branchPrefixes if f['path'].startswith(p)]:
+ if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
new_files.append (f)
else:
- sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
+ sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
self.gitStream.write("commit %s\n" % branch)
# gitStream.write("mark :%s\n" % details["change"])
@@ -1304,7 +1321,7 @@ class P4Sync(Command):
source = paths[0]
destination = paths[1]
## HACK
- if source.startswith(self.depotPaths[0]) and destination.startswith(self.depotPaths[0]):
+ if p4PathStartsWith(source, self.depotPaths[0]) and p4PathStartsWith(destination, self.depotPaths[0]):
source = source[len(self.depotPaths[0]):-4]
destination = destination[len(self.depotPaths[0]):-4]
@@ -1763,7 +1780,9 @@ class P4Sync(Command):
changes.sort()
else:
- if not isinstance(self, P4Clone) and not self.p4BranchesInGit:
+ # catch "git-p4 sync" with no new branches, in a repo that
+ # does not have any existing git-p4 branches
+ if len(args) == 0 and not self.p4BranchesInGit:
die("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here.");
if self.verbose:
print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
diff --git a/daemon.c b/daemon.c
index 347fd0c52b..4c8346d5a1 100644
--- a/daemon.c
+++ b/daemon.c
@@ -660,7 +660,7 @@ static void check_dead_children(void)
static char **cld_argv;
static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
{
- struct child_process cld = { 0 };
+ struct child_process cld = { NULL };
char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
char *env[] = { addrbuf, portbuf, NULL };
diff --git a/diff-lib.c b/diff-lib.c
index 1e22992cb1..2870de400e 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -103,7 +103,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
unsigned dirty_submodule = 0;
if (DIFF_OPT_TST(&revs->diffopt, QUICK) &&
- DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
+ !revs->diffopt.filter &&
+ DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
break;
if (!ce_path_match(ce, &revs->prune_data))
diff --git a/diff.c b/diff.c
index 3fd9e0c703..9b3eb9938f 100644
--- a/diff.c
+++ b/diff.c
@@ -23,7 +23,7 @@
#endif
static int diff_detect_rename_default;
-static int diff_rename_limit_default = 200;
+static int diff_rename_limit_default = 400;
static int diff_suppress_blank_empty;
int diff_use_color_default = -1;
static const char *diff_word_regex_cfg;
@@ -628,7 +628,7 @@ struct diff_words_style {
const char *newline;
};
-struct diff_words_style diff_words_styles[] = {
+static struct diff_words_style diff_words_styles[] = {
{ DIFF_WORDS_PORCELAIN, {"+", "\n"}, {"-", "\n"}, {" ", "\n"}, "~\n" },
{ DIFF_WORDS_PLAIN, {"{+", "+}"}, {"[-", "-]"}, {"", ""}, "\n" },
{ DIFF_WORDS_COLOR, {"", ""}, {"", ""}, {"", ""}, "\n" }
diff --git a/diff.h b/diff.h
index 310bd6b283..007a0554d4 100644
--- a/diff.h
+++ b/diff.h
@@ -110,7 +110,8 @@ struct diff_options {
int pickaxe_opts;
int rename_score;
int rename_limit;
- int warn_on_too_large_rename;
+ int needed_rename_limit;
+ int show_rename_progress;
int dirstat_percent;
int setup;
int abbrev;
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 0cd4c1305b..d40e40a3ac 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -5,6 +5,7 @@
#include "diff.h"
#include "diffcore.h"
#include "hash.h"
+#include "progress.h"
/* Table of rename/copy destinations */
@@ -449,6 +450,7 @@ void diffcore_rename(struct diff_options *options)
struct diff_score *mx;
int i, j, rename_count;
int num_create, num_src, dst_cnt;
+ struct progress *progress = NULL;
if (!minimum_score)
minimum_score = DEFAULT_RENAME_SCORE;
@@ -518,15 +520,22 @@ void diffcore_rename(struct diff_options *options)
* 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)) {
- if (options->warn_on_too_large_rename)
- warning("too many files (created: %d deleted: %d), skipping inexact rename detection", num_create, num_src);
+ options->needed_rename_limit =
+ num_src > num_create ? num_src : num_create;
goto cleanup;
}
+ if (options->show_rename_progress) {
+ progress = start_progress_delay(
+ "Performing inexact rename detection",
+ rename_dst_nr * rename_src_nr, 50, 1);
+ }
+
mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
struct diff_filespec *two = rename_dst[i].two;
@@ -556,7 +565,9 @@ void diffcore_rename(struct diff_options *options)
diff_free_filespec_blob(two);
}
dst_cnt++;
+ display_progress(progress, (i+1)*rename_src_nr);
}
+ stop_progress(&progress);
/* cost matrix sorted by most to least similar pair */
qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);
diff --git a/environment.c b/environment.c
index cc670b1562..f4549d3f7b 100644
--- a/environment.c
+++ b/environment.c
@@ -15,6 +15,7 @@ int user_ident_explicitly_given;
int trust_executable_bit = 1;
int trust_ctime = 1;
int has_symlinks = 1;
+int minimum_abbrev = 4, default_abbrev = 7;
int ignore_case;
int assume_unchanged;
int prefer_symlink_refs;
diff --git a/fast-import.c b/fast-import.c
index d9f9a3f524..65d65bf8f9 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -2939,7 +2939,7 @@ static void parse_ls(struct branch *b)
{
const char *p;
struct tree_entry *root = NULL;
- struct tree_entry leaf = {0};
+ struct tree_entry leaf = {NULL};
/* ls SP (<treeish> SP)? <path> */
p = command_buf.buf + strlen("ls ");
diff --git a/gettext.c b/gettext.c
new file mode 100644
index 0000000000..ae5394a496
--- /dev/null
+++ b/gettext.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2010 Ævar Arnfjörð Bjarmason
+ */
+
+#include "git-compat-util.h"
+#include "gettext.h"
+
+int use_gettext_poison(void)
+{
+ static int poison_requested = -1;
+ if (poison_requested == -1)
+ poison_requested = getenv("GIT_GETTEXT_POISON") ? 1 : 0;
+ return poison_requested;
+}
diff --git a/gettext.h b/gettext.h
new file mode 100644
index 0000000000..1b253b7e76
--- /dev/null
+++ b/gettext.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010-2011 Ævar Arnfjörð Bjarmason
+ *
+ * This is a skeleton no-op implementation of gettext for Git.
+ * You can replace it with something that uses libintl.h and wraps
+ * gettext() to try out the translations.
+ */
+
+#ifndef GETTEXT_H
+#define GETTEXT_H
+
+#if defined(_) || defined(Q_)
+#error "namespace conflict: '_' or 'Q_' is pre-defined?"
+#endif
+
+#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
+
+#ifdef GETTEXT_POISON
+extern int use_gettext_poison(void);
+#else
+#define use_gettext_poison() 0
+#endif
+
+static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
+{
+ return use_gettext_poison() ? "# GETTEXT POISON #" : msgid;
+}
+
+static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
+const char *Q_(const char *msgid, const char *plu, unsigned long n)
+{
+ if (use_gettext_poison())
+ return "# GETTEXT POISON #";
+ return n == 1 ? msgid : plu;
+}
+
+/* Mark msgid for translation but do not translate it. */
+#define N_(msgid) (msgid)
+
+#endif
diff --git a/git-bisect.sh b/git-bisect.sh
index c21e33c8d1..415a8d04cc 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -288,10 +288,12 @@ bisect_visualize() {
if test $# = 0
then
- case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
- '') set git log ;;
- set*) set gitk ;;
- esac
+ if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
+ type gitk >/dev/null 2>&1; then
+ set gitk
+ else
+ set git log
+ fi
else
case "$1" in
git*|tig) ;;
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index 78ce49e984..fb3f52ba25 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -10,17 +10,20 @@ merge_mode() {
translate_merge_tool_path () {
case "$1" in
- vimdiff|vimdiff2)
- echo vim
+ araxis)
+ echo compare
;;
- gvimdiff|gvimdiff2)
- echo gvim
+ bc3)
+ echo bcompare
;;
emerge)
echo emacs
;;
- araxis)
- echo compare
+ gvimdiff|gvimdiff2)
+ echo gvim
+ ;;
+ vimdiff|vimdiff2)
+ echo vim
;;
*)
echo "$1"
@@ -46,17 +49,16 @@ check_unchanged () {
valid_tool () {
case "$1" in
- kdiff3 | tkdiff | xxdiff | meld | opendiff | \
- vimdiff | gvimdiff | vimdiff2 | gvimdiff2 | \
- emerge | ecmerge | diffuse | araxis | p4merge)
+ araxis | bc3 | diffuse | ecmerge | emerge | gvimdiff | gvimdiff2 | \
+ kdiff3 | meld | opendiff | p4merge | tkdiff | vimdiff | vimdiff2 | xxdiff)
;; # happy
- tortoisemerge)
- if ! merge_mode; then
+ kompare)
+ if ! diff_mode; then
return 1
fi
;;
- kompare)
- if ! diff_mode; then
+ tortoisemerge)
+ if ! merge_mode; then
return 1
fi
;;
@@ -89,88 +91,91 @@ run_merge_tool () {
status=0
case "$1" in
- kdiff3)
+ araxis)
if merge_mode; then
+ touch "$BACKUP"
if $base_present; then
- ("$merge_tool_path" --auto \
- --L1 "$MERGED (Base)" \
- --L2 "$MERGED (Local)" \
- --L3 "$MERGED (Remote)" \
- -o "$MERGED" \
- "$BASE" "$LOCAL" "$REMOTE" \
- > /dev/null 2>&1)
+ "$merge_tool_path" -wait -merge -3 -a1 \
+ "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
+ >/dev/null 2>&1
else
- ("$merge_tool_path" --auto \
- --L1 "$MERGED (Local)" \
- --L2 "$MERGED (Remote)" \
- -o "$MERGED" \
- "$LOCAL" "$REMOTE" \
- > /dev/null 2>&1)
+ "$merge_tool_path" -wait -2 \
+ "$LOCAL" "$REMOTE" "$MERGED" \
+ >/dev/null 2>&1
fi
- status=$?
+ check_unchanged
else
- ("$merge_tool_path" --auto \
- --L1 "$MERGED (A)" \
- --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
- > /dev/null 2>&1)
+ "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
+ >/dev/null 2>&1
fi
;;
- kompare)
- "$merge_tool_path" "$LOCAL" "$REMOTE"
- ;;
- tkdiff)
+ bc3)
if merge_mode; then
+ touch "$BACKUP"
if $base_present; then
- "$merge_tool_path" -a "$BASE" \
- -o "$MERGED" "$LOCAL" "$REMOTE"
+ "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" \
+ -mergeoutput="$MERGED"
else
- "$merge_tool_path" \
- -o "$MERGED" "$LOCAL" "$REMOTE"
+ "$merge_tool_path" "$LOCAL" "$REMOTE" \
+ -mergeoutput="$MERGED"
fi
- status=$?
+ check_unchanged
else
"$merge_tool_path" "$LOCAL" "$REMOTE"
fi
;;
- p4merge)
+ diffuse)
if merge_mode; then
- touch "$BACKUP"
+ touch "$BACKUP"
if $base_present; then
- "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
+ "$merge_tool_path" \
+ "$LOCAL" "$MERGED" "$REMOTE" \
+ "$BASE" | cat
else
- "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
+ "$merge_tool_path" \
+ "$LOCAL" "$MERGED" "$REMOTE" | cat
fi
check_unchanged
else
- "$merge_tool_path" "$LOCAL" "$REMOTE"
+ "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
fi
;;
- meld)
+ ecmerge)
if merge_mode; then
touch "$BACKUP"
- "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
+ if $base_present; then
+ "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
+ --default --mode=merge3 --to="$MERGED"
+ else
+ "$merge_tool_path" "$LOCAL" "$REMOTE" \
+ --default --mode=merge2 --to="$MERGED"
+ fi
check_unchanged
else
- "$merge_tool_path" "$LOCAL" "$REMOTE"
+ "$merge_tool_path" --default --mode=diff2 \
+ "$LOCAL" "$REMOTE"
fi
;;
- diffuse)
+ emerge)
if merge_mode; then
- touch "$BACKUP"
if $base_present; then
"$merge_tool_path" \
- "$LOCAL" "$MERGED" "$REMOTE" \
- "$BASE" | cat
+ -f emerge-files-with-ancestor-command \
+ "$LOCAL" "$REMOTE" "$BASE" \
+ "$(basename "$MERGED")"
else
"$merge_tool_path" \
- "$LOCAL" "$MERGED" "$REMOTE" | cat
+ -f emerge-files-command \
+ "$LOCAL" "$REMOTE" \
+ "$(basename "$MERGED")"
fi
- check_unchanged
+ status=$?
else
- "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+ "$merge_tool_path" -f emerge-files-command \
+ "$LOCAL" "$REMOTE"
fi
;;
- vimdiff|gvimdiff)
+ gvimdiff|vimdiff)
if merge_mode; then
touch "$BACKUP"
if $base_present; then
@@ -186,7 +191,7 @@ run_merge_tool () {
"$LOCAL" "$REMOTE"
fi
;;
- vimdiff2|gvimdiff2)
+ gvimdiff2|vimdiff2)
if merge_mode; then
touch "$BACKUP"
"$merge_tool_path" -f -d -c "wincmd l" \
@@ -197,30 +202,42 @@ run_merge_tool () {
"$LOCAL" "$REMOTE"
fi
;;
- xxdiff)
+ kdiff3)
if merge_mode; then
- touch "$BACKUP"
if $base_present; then
- "$merge_tool_path" -X --show-merged-pane \
- -R 'Accel.SaveAsMerged: "Ctrl-S"' \
- -R 'Accel.Search: "Ctrl+F"' \
- -R 'Accel.SearchForward: "Ctrl-G"' \
- --merged-file "$MERGED" \
- "$LOCAL" "$BASE" "$REMOTE"
+ ("$merge_tool_path" --auto \
+ --L1 "$MERGED (Base)" \
+ --L2 "$MERGED (Local)" \
+ --L3 "$MERGED (Remote)" \
+ -o "$MERGED" \
+ "$BASE" "$LOCAL" "$REMOTE" \
+ > /dev/null 2>&1)
else
- "$merge_tool_path" -X $extra \
- -R 'Accel.SaveAsMerged: "Ctrl-S"' \
- -R 'Accel.Search: "Ctrl+F"' \
- -R 'Accel.SearchForward: "Ctrl-G"' \
- --merged-file "$MERGED" \
- "$LOCAL" "$REMOTE"
+ ("$merge_tool_path" --auto \
+ --L1 "$MERGED (Local)" \
+ --L2 "$MERGED (Remote)" \
+ -o "$MERGED" \
+ "$LOCAL" "$REMOTE" \
+ > /dev/null 2>&1)
fi
+ status=$?
+ else
+ ("$merge_tool_path" --auto \
+ --L1 "$MERGED (A)" \
+ --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
+ > /dev/null 2>&1)
+ fi
+ ;;
+ kompare)
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
+ ;;
+ meld)
+ if merge_mode; then
+ touch "$BACKUP"
+ "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
check_unchanged
else
- "$merge_tool_path" \
- -R 'Accel.Search: "Ctrl+F"' \
- -R 'Accel.SearchForward: "Ctrl-G"' \
- "$LOCAL" "$REMOTE"
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
fi
;;
opendiff)
@@ -239,39 +256,31 @@ run_merge_tool () {
"$merge_tool_path" "$LOCAL" "$REMOTE" | cat
fi
;;
- ecmerge)
+ p4merge)
if merge_mode; then
- touch "$BACKUP"
+ touch "$BACKUP"
if $base_present; then
- "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
- --default --mode=merge3 --to="$MERGED"
+ "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
else
- "$merge_tool_path" "$LOCAL" "$REMOTE" \
- --default --mode=merge2 --to="$MERGED"
+ "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
fi
check_unchanged
else
- "$merge_tool_path" --default --mode=diff2 \
- "$LOCAL" "$REMOTE"
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
fi
;;
- emerge)
+ tkdiff)
if merge_mode; then
if $base_present; then
- "$merge_tool_path" \
- -f emerge-files-with-ancestor-command \
- "$LOCAL" "$REMOTE" "$BASE" \
- "$(basename "$MERGED")"
+ "$merge_tool_path" -a "$BASE" \
+ -o "$MERGED" "$LOCAL" "$REMOTE"
else
"$merge_tool_path" \
- -f emerge-files-command \
- "$LOCAL" "$REMOTE" \
- "$(basename "$MERGED")"
+ -o "$MERGED" "$LOCAL" "$REMOTE"
fi
status=$?
else
- "$merge_tool_path" -f emerge-files-command \
- "$LOCAL" "$REMOTE"
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
fi
;;
tortoisemerge)
@@ -286,22 +295,30 @@ run_merge_tool () {
status=1
fi
;;
- araxis)
+ xxdiff)
if merge_mode; then
touch "$BACKUP"
if $base_present; then
- "$merge_tool_path" -wait -merge -3 -a1 \
- "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
- >/dev/null 2>&1
+ "$merge_tool_path" -X --show-merged-pane \
+ -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+ -R 'Accel.Search: "Ctrl+F"' \
+ -R 'Accel.SearchForward: "Ctrl-G"' \
+ --merged-file "$MERGED" \
+ "$LOCAL" "$BASE" "$REMOTE"
else
- "$merge_tool_path" -wait -2 \
- "$LOCAL" "$REMOTE" "$MERGED" \
- >/dev/null 2>&1
+ "$merge_tool_path" -X $extra \
+ -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+ -R 'Accel.Search: "Ctrl+F"' \
+ -R 'Accel.SearchForward: "Ctrl-G"' \
+ --merged-file "$MERGED" \
+ "$LOCAL" "$REMOTE"
fi
check_unchanged
else
- "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
- >/dev/null 2>&1
+ "$merge_tool_path" \
+ -R 'Accel.Search: "Ctrl+F"' \
+ -R 'Accel.SearchForward: "Ctrl-G"' \
+ "$LOCAL" "$REMOTE"
fi
;;
*)
@@ -343,7 +360,7 @@ guess_merge_tool () {
else
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
fi
- tools="$tools gvimdiff diffuse ecmerge p4merge araxis"
+ tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3"
fi
case "${VISUAL:-$EDITOR}" in
*vim*)
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 1cc2ba6e09..e7013f7ba7 100644
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -4,56 +4,6 @@
# this would fail in that case and would issue an error message.
GIT_DIR=$(git rev-parse -q --git-dir) || :;
-get_data_source () {
- case "$1" in
- */*)
- echo ''
- ;;
- .)
- echo self
- ;;
- *)
- if test "$(git config --get "remote.$1.url")"
- then
- echo config
- elif test -f "$GIT_DIR/remotes/$1"
- then
- echo remotes
- elif test -f "$GIT_DIR/branches/$1"
- then
- echo branches
- else
- echo ''
- fi ;;
- esac
-}
-
-get_remote_url () {
- data_source=$(get_data_source "$1")
- case "$data_source" in
- '')
- echo "$1"
- ;;
- self)
- echo "$1"
- ;;
- config)
- git config --get "remote.$1.url"
- ;;
- remotes)
- sed -ne '/^URL: */{
- s///p
- q
- }' "$GIT_DIR/remotes/$1"
- ;;
- branches)
- sed -e 's/#.*//' "$GIT_DIR/branches/$1"
- ;;
- *)
- die "internal error: get-remote-url $1" ;;
- esac
-}
-
get_default_remote () {
curr_branch=$(git symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
origin=$(git config --get "branch.$curr_branch.remote")
diff --git a/git-pull.sh b/git-pull.sh
index f6b7b84048..63b063a7b2 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -53,6 +53,8 @@ do
verbosity="$verbosity -v" ;;
--progress)
progress=--progress ;;
+ --no-progress)
+ progress=--no-progress ;;
-n|--no-stat|--no-summary)
diffstat=--no-stat ;;
--stat|--summary)
@@ -293,8 +295,8 @@ true)
;;
*)
eval="git-merge $diffstat $no_commit $squash $no_ff $ff_only"
- eval="$eval $log_arg $strategy_args $merge_args"
- eval="$eval \"\$merge_name\" HEAD $merge_head $verbosity"
+ eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress"
+ eval="$eval \"\$merge_name\" HEAD $merge_head"
;;
esac
eval "exec $eval"
diff --git a/git-request-pull.sh b/git-request-pull.sh
index 6fdea397dd..fc080cc5e4 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -15,7 +15,6 @@ p show patch text as well
'
. git-sh-setup
-. git-parse-remote
GIT_PAGER=
export GIT_PAGER
@@ -55,7 +54,7 @@ branch=$(git ls-remote "$url" \
p
q
}")
-url=$(get_remote_url "$url")
+url=$(git ls-remote --get-url "$url")
if [ -z "$branch" ]; then
echo "warn: No branch of $url is at:" >&2
git log --max-count=1 --pretty='tformat:warn: %h: %s' $headrev >&2
diff --git a/git-stash.sh b/git-stash.sh
index 7561b374d2..a305fb19f1 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -12,12 +12,14 @@ USAGE="list [<options>]
SUBDIRECTORY_OK=Yes
OPTIONS_SPEC=
+START_DIR=`pwd`
. git-sh-setup
require_work_tree
cd_to_toplevel
TMP="$GIT_DIR/.git-stash.$$"
-trap 'rm -f "$TMP-*"' 0
+TMPindex=${GIT_INDEX_FILE-"$GIT_DIR/index"}.stash.$$
+trap 'rm -f "$TMP-"* "$TMPindex"' 0
ref_stash=refs/stash
@@ -81,14 +83,12 @@ create_stash () {
# state of the working tree
w_tree=$( (
- rm -f "$TMP-index" &&
- cp -p ${GIT_INDEX_FILE-"$GIT_DIR/index"} "$TMP-index" &&
- GIT_INDEX_FILE="$TMP-index" &&
+ git read-tree --index-output="$TMPindex" -m $i_tree &&
+ GIT_INDEX_FILE="$TMPindex" &&
export GIT_INDEX_FILE &&
- git read-tree -m $i_tree &&
git diff --name-only -z HEAD | git update-index -z --add --remove --stdin &&
git write-tree &&
- rm -f "$TMP-index"
+ rm -f "$TMPindex"
) ) ||
die "Cannot save the current worktree state"
@@ -394,7 +394,7 @@ apply_stash () {
then
squelch='>/dev/null 2>&1'
fi
- eval "git status $squelch" || :
+ (cd "$START_DIR" && eval "git status $squelch") || :
else
# Merge conflict; keep the exit status from merge-recursive
status=$?
diff --git a/git-svn.perl b/git-svn.perl
index 177dd259cd..a5857c1ad4 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -5734,7 +5734,7 @@ sub cmd_show_log {
my (@k, $c, $d, $stat);
my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
while (<$log>) {
- if (/^${esc_color}commit -?($::sha1_short)/o) {
+ if (/^${esc_color}commit (- )?($::sha1_short)/o) {
my $cmt = $1;
if ($c && cmt_showable($c) && $c->{r} != $r_last) {
$r_last = $c->{r};
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index f275adbcf1..0178633b26 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -4919,7 +4919,6 @@ sub git_log_body {
next if !%co;
my $commit = $co{'id'};
my $ref = format_ref_marker($refs, $commit);
- my %ad = parse_date($co{'author_epoch'});
git_print_header_div('commit',
"<span class=\"age\">$co{'age_string'}</span>" .
esc_html($co{'title'}) . $ref,
@@ -7077,7 +7076,7 @@ sub git_feed {
if (defined($commitlist[0])) {
%latest_commit = %{$commitlist[0]};
my $latest_epoch = $latest_commit{'committer_epoch'};
- %latest_date = parse_date($latest_epoch);
+ %latest_date = parse_date($latest_epoch, $latest_commit{'comitter_tz'});
my $if_modified = $cgi->http('IF_MODIFIED_SINCE');
if (defined $if_modified) {
my $since;
@@ -7208,7 +7207,7 @@ XML
if (($i >= 20) && ((time - $co{'author_epoch'}) > 48*60*60)) {
last;
}
- my %cd = parse_date($co{'author_epoch'});
+ my %cd = parse_date($co{'author_epoch'}, $co{'author_tz'});
# get list of changed files
open my $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
diff --git a/graph.c b/graph.c
index f1a63c2241..ef2e24e85a 100644
--- a/graph.c
+++ b/graph.c
@@ -798,22 +798,9 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
}
/*
- * If revs->left_right is set, print '<' for commits that
- * come from the left side, and '>' for commits from the right
- * side.
+ * get_revision_mark() handles all other cases without assert()
*/
- if (graph->revs && graph->revs->left_right) {
- if (graph->commit->object.flags & SYMMETRIC_LEFT)
- strbuf_addch(sb, '<');
- else
- strbuf_addch(sb, '>');
- return;
- }
-
- /*
- * Print '*' in all other cases
- */
- strbuf_addch(sb, '*');
+ strbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit));
}
/*
diff --git a/imap-send.c b/imap-send.c
index 71506a8dd3..9adf4b9819 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1069,7 +1069,7 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
if (srvc->tunnel) {
const char *argv[] = { srvc->tunnel, NULL };
- struct child_process tunnel = {0};
+ struct child_process tunnel = {NULL};
imap_info("Starting tunnel '%s'... ", srvc->tunnel);
diff --git a/list-objects.c b/list-objects.c
index 61f6cc98d9..838b6a732e 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -173,7 +173,12 @@ void traverse_commit_list(struct rev_info *revs,
strbuf_init(&base, PATH_MAX);
while ((commit = get_revision(revs)) != NULL) {
- add_pending_tree(revs, commit->tree);
+ /*
+ * an uninteresting boundary commit may not have its tree
+ * parsed yet, but we are not going to show them anyway
+ */
+ if (commit->tree)
+ add_pending_tree(revs, commit->tree);
show_commit(commit, data);
}
for (i = 0; i < revs->pending.nr; i++) {
diff --git a/log-tree.c b/log-tree.c
index b46ed3baef..2a1e3a94c9 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -380,18 +380,8 @@ void show_log(struct rev_info *opt)
if (!opt->verbose_header) {
graph_show_commit(opt->graph);
- if (!opt->graph) {
- if (commit->object.flags & BOUNDARY)
- putchar('-');
- else if (commit->object.flags & UNINTERESTING)
- putchar('^');
- else if (opt->left_right) {
- if (commit->object.flags & SYMMETRIC_LEFT)
- putchar('<');
- else
- putchar('>');
- }
- }
+ if (!opt->graph)
+ put_revision_mark(opt, commit);
fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
if (opt->print_parents)
show_parents(commit, abbrev_commit);
@@ -448,18 +438,8 @@ void show_log(struct rev_info *opt)
if (opt->commit_format != CMIT_FMT_ONELINE)
fputs("commit ", stdout);
- if (!opt->graph) {
- if (commit->object.flags & BOUNDARY)
- putchar('-');
- else if (commit->object.flags & UNINTERESTING)
- putchar('^');
- else if (opt->left_right) {
- if (commit->object.flags & SYMMETRIC_LEFT)
- putchar('<');
- else
- putchar('>');
- }
- }
+ if (!opt->graph)
+ put_revision_mark(opt, commit);
fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),
stdout);
if (opt->print_parents)
diff --git a/merge-recursive.c b/merge-recursive.c
index 3debbc44a0..8e82a8b1a5 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -22,6 +22,11 @@
#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)
{
@@ -418,14 +423,16 @@ static struct string_list *get_renames(struct merge_options *o,
opts.detect_rename = DIFF_DETECT_RENAME;
opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
o->diff_rename_limit >= 0 ? o->diff_rename_limit :
- 500;
+ 1000;
opts.rename_score = o->rename_score;
- opts.warn_on_too_large_rename = 1;
+ opts.show_rename_progress = o->show_rename_progress;
opts.output_format = DIFF_FORMAT_NO_OUTPUT;
if (diff_setup_done(&opts) < 0)
die("diff setup failed");
diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
diffcore_std(&opts);
+ if (opts.needed_rename_limit > o->needed_rename_limit)
+ o->needed_rename_limit = opts.needed_rename_limit;
for (i = 0; i < diff_queued_diff.nr; ++i) {
struct string_list_item *item;
struct rename *re;
@@ -1649,6 +1656,8 @@ 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);
return clean;
}
diff --git a/merge-recursive.h b/merge-recursive.h
index 981ed6ac94..7e1e972b13 100644
--- a/merge-recursive.h
+++ b/merge-recursive.h
@@ -20,6 +20,8 @@ struct merge_options {
int diff_rename_limit;
int merge_rename_limit;
int rename_score;
+ int needed_rename_limit;
+ int show_rename_progress;
int call_depth;
struct strbuf obuf;
struct string_list current_file_set;
diff --git a/notes-merge.c b/notes-merge.c
index 1467ad3179..28046a9984 100644
--- a/notes-merge.c
+++ b/notes-merge.c
@@ -359,7 +359,7 @@ static int ll_merge_in_worktree(struct notes_merge_options *o,
read_mmblob(&remote, p->remote);
status = ll_merge(&result_buf, sha1_to_hex(p->obj), &base, NULL,
- &local, o->local_ref, &remote, o->remote_ref, 0);
+ &local, o->local_ref, &remote, o->remote_ref, NULL);
free(base.ptr);
free(local.ptr);
diff --git a/parse-options.c b/parse-options.c
index 42b51ef145..73bd28ad90 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -561,14 +561,14 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
return PARSE_OPT_HELP;
}
-void usage_with_options(const char * const *usagestr,
+void NORETURN usage_with_options(const char * const *usagestr,
const struct option *opts)
{
usage_with_options_internal(NULL, usagestr, opts, 0, 1);
exit(129);
}
-void usage_msg_opt(const char *msg,
+void NORETURN usage_msg_opt(const char *msg,
const char * const *usagestr,
const struct option *options)
{
diff --git a/pkt-line.c b/pkt-line.c
index 295ba2b16c..cd1bd26413 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -1,6 +1,51 @@
#include "cache.h"
#include "pkt-line.h"
+const char *packet_trace_prefix = "git";
+static const char trace_key[] = "GIT_TRACE_PACKET";
+
+void packet_trace_identity(const char *prog)
+{
+ packet_trace_prefix = xstrdup(prog);
+}
+
+static void packet_trace(const char *buf, unsigned int len, int write)
+{
+ int i;
+ struct strbuf out;
+
+ if (!trace_want(trace_key))
+ return;
+
+ /* +32 is just a guess for header + quoting */
+ strbuf_init(&out, len+32);
+
+ strbuf_addf(&out, "packet: %12s%c ",
+ packet_trace_prefix, write ? '>' : '<');
+
+ if ((len >= 4 && !prefixcmp(buf, "PACK")) ||
+ (len >= 5 && !prefixcmp(buf+1, "PACK"))) {
+ strbuf_addstr(&out, "PACK ...");
+ unsetenv(trace_key);
+ }
+ else {
+ /* XXX we should really handle printable utf8 */
+ for (i = 0; i < len; i++) {
+ /* suppress newlines */
+ if (buf[i] == '\n')
+ continue;
+ if (buf[i] >= 0x20 && buf[i] <= 0x7e)
+ strbuf_addch(&out, buf[i]);
+ else
+ strbuf_addf(&out, "\\%o", buf[i]);
+ }
+ }
+
+ strbuf_addch(&out, '\n');
+ trace_strbuf(trace_key, &out);
+ strbuf_release(&out);
+}
+
/*
* Write a packetized stream, where each line is preceded by
* its length (including the header) as a 4-byte hex number.
@@ -39,11 +84,13 @@ ssize_t safe_write(int fd, const void *buf, ssize_t n)
*/
void packet_flush(int fd)
{
+ packet_trace("0000", 4, 1);
safe_write(fd, "0000", 4);
}
void packet_buf_flush(struct strbuf *buf)
{
+ packet_trace("0000", 4, 1);
strbuf_add(buf, "0000", 4);
}
@@ -62,6 +109,7 @@ static unsigned format_packet(const char *fmt, va_list args)
buffer[1] = hex(n >> 8);
buffer[2] = hex(n >> 4);
buffer[3] = hex(n);
+ packet_trace(buffer+4, n-4, 1);
return n;
}
@@ -130,13 +178,16 @@ int packet_read_line(int fd, char *buffer, unsigned size)
len = packet_length(linelen);
if (len < 0)
die("protocol error: bad line length character: %.4s", linelen);
- if (!len)
+ if (!len) {
+ packet_trace("0000", 4, 0);
return 0;
+ }
len -= 4;
if (len >= size)
die("protocol error: bad line length %d", len);
safe_read(fd, buffer, len);
buffer[len] = 0;
+ packet_trace(buffer, len, 0);
return len;
}
@@ -153,6 +204,7 @@ int packet_get_line(struct strbuf *out,
if (!len) {
*src_buf += 4;
*src_len -= 4;
+ packet_trace("0000", 4, 0);
return 0;
}
if (*src_len < len)
@@ -165,5 +217,6 @@ int packet_get_line(struct strbuf *out,
strbuf_add(out, *src_buf, len);
*src_buf += len;
*src_len -= len;
+ packet_trace(out->buf, out->len, 0);
return len;
}
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644
index 0000000000..a242a86e93
--- /dev/null
+++ b/po/.gitignore
@@ -0,0 +1 @@
+/git.pot
diff --git a/pretty.c b/pretty.c
index 8549934751..e1d8a8f414 100644
--- a/pretty.c
+++ b/pretty.c
@@ -216,36 +216,53 @@ static int is_rfc2047_special(char ch)
static void add_rfc2047(struct strbuf *sb, const char *line, int len,
const char *encoding)
{
- int i, last;
+ static const int max_length = 78; /* per rfc2822 */
+ int i;
+ int line_len;
+
+ /* How many bytes are already used on the current line? */
+ for (i = sb->len - 1; i >= 0; i--)
+ if (sb->buf[i] == '\n')
+ break;
+ line_len = sb->len - (i+1);
for (i = 0; i < len; i++) {
int ch = line[i];
- if (non_ascii(ch))
+ if (non_ascii(ch) || ch == '\n')
goto needquote;
if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
goto needquote;
}
- strbuf_add(sb, line, len);
+ strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
return;
needquote:
strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
strbuf_addf(sb, "=?%s?q?", encoding);
- for (i = last = 0; i < len; i++) {
+ line_len += strlen(encoding) + 5; /* 5 for =??q? */
+ for (i = 0; i < len; i++) {
unsigned ch = line[i] & 0xFF;
+
+ if (line_len >= max_length - 2) {
+ strbuf_addf(sb, "?=\n =?%s?q?", encoding);
+ line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
+ }
+
/*
* We encode ' ' using '=20' even though rfc2047
* allows using '_' for readability. Unfortunately,
* many programs do not understand this and just
* leave the underscore in place.
*/
- if (is_rfc2047_special(ch) || ch == ' ') {
- strbuf_add(sb, line + last, i - last);
+ if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
strbuf_addf(sb, "=%02X", ch);
- last = i + 1;
+ line_len += 3;
+ }
+ else {
+ strbuf_addch(sb, ch);
+ line_len++;
}
}
- strbuf_add(sb, line + last, len - last);
strbuf_addstr(sb, "?=");
}
@@ -859,11 +876,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
c->abbrev_parent_hashes.off;
return 1;
case 'm': /* left/right/bottom */
- strbuf_addch(sb, (commit->object.flags & BOUNDARY)
- ? '-'
- : (commit->object.flags & SYMMETRIC_LEFT)
- ? '<'
- : '>');
+ strbuf_addstr(sb, get_revision_mark(NULL, commit));
return 1;
case 'd':
format_decoration(sb, commit);
@@ -1106,11 +1119,10 @@ void pp_title_line(enum cmit_fmt fmt,
const char *encoding,
int need_8bit_cte)
{
- const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
struct strbuf title;
strbuf_init(&title, 80);
- *msg_p = format_subject(&title, *msg_p, line_separator);
+ *msg_p = format_subject(&title, *msg_p, " ");
strbuf_grow(sb, title.len + 1024);
if (subject) {
diff --git a/replace_object.c b/replace_object.c
index eb59604fd3..7c6c7544ad 100644
--- a/replace_object.c
+++ b/replace_object.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "sha1-lookup.h"
#include "refs.h"
+#include "commit.h"
static struct replace_object {
unsigned char sha1[2][20];
diff --git a/revision.c b/revision.c
index 86d2470489..e96c281d1f 100644
--- a/revision.c
+++ b/revision.c
@@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
int left_count = 0, right_count = 0;
int left_first;
struct patch_ids ids;
+ unsigned cherry_flag;
/* First count the commits on the left and on the right */
for (p = list; p; p = p->next) {
@@ -572,6 +573,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
commit->util = add_commit_patch_id(commit, &ids);
}
+ /* either cherry_mark or cherry_pick are true */
+ cherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN;
+
/* Check the other side */
for (p = list; p; p = p->next) {
struct commit *commit = p->item;
@@ -594,7 +598,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
if (!id)
continue;
id->seen = 1;
- commit->object.flags |= SHOWN;
+ commit->object.flags |= cherry_flag;
}
/* Now check the original side for seen ones */
@@ -606,7 +610,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
if (!ent)
continue;
if (ent->seen)
- commit->object.flags |= SHOWN;
+ commit->object.flags |= cherry_flag;
commit->util = NULL;
}
@@ -729,6 +733,23 @@ static struct commit_list *collect_bottom_commits(struct commit_list *list)
return bottom;
}
+/* Assumes either left_only or right_only is set */
+static void limit_left_right(struct commit_list *list, struct rev_info *revs)
+{
+ struct commit_list *p;
+
+ for (p = list; p; p = p->next) {
+ struct commit *commit = p->item;
+
+ if (revs->right_only) {
+ if (commit->object.flags & SYMMETRIC_LEFT)
+ commit->object.flags |= SHOWN;
+ } else /* revs->left_only is set */
+ if (!(commit->object.flags & SYMMETRIC_LEFT))
+ commit->object.flags |= SHOWN;
+ }
+}
+
static int limit_list(struct rev_info *revs)
{
int slop = SLOP;
@@ -781,9 +802,12 @@ static int limit_list(struct rev_info *revs)
show(revs, newlist);
show_early_output = NULL;
}
- if (revs->cherry_pick)
+ if (revs->cherry_pick || revs->cherry_mark)
cherry_pick_list(newlist, revs);
+ if (revs->left_only || revs->right_only)
+ limit_left_right(newlist, revs);
+
if (bottom) {
limit_to_ancestry(bottom, newlist);
free_commit_list(bottom);
@@ -1260,9 +1284,32 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->boundary = 1;
} else if (!strcmp(arg, "--left-right")) {
revs->left_right = 1;
+ } else if (!strcmp(arg, "--left-only")) {
+ if (revs->right_only)
+ die("--left-only is incompatible with --right-only"
+ " or --cherry");
+ revs->left_only = 1;
+ } else if (!strcmp(arg, "--right-only")) {
+ if (revs->left_only)
+ die("--right-only is incompatible with --left-only");
+ revs->right_only = 1;
+ } else if (!strcmp(arg, "--cherry")) {
+ if (revs->left_only)
+ die("--cherry is incompatible with --left-only");
+ revs->cherry_mark = 1;
+ revs->right_only = 1;
+ revs->no_merges = 1;
+ revs->limited = 1;
} else if (!strcmp(arg, "--count")) {
revs->count = 1;
+ } else if (!strcmp(arg, "--cherry-mark")) {
+ if (revs->cherry_pick)
+ die("--cherry-mark is incompatible with --cherry-pick");
+ revs->cherry_mark = 1;
+ revs->limited = 1; /* needs limit_list() */
} else if (!strcmp(arg, "--cherry-pick")) {
+ if (revs->cherry_mark)
+ die("--cherry-pick is incompatible with --cherry-mark");
revs->cherry_pick = 1;
revs->limited = 1;
} else if (!strcmp(arg, "--objects")) {
@@ -2232,3 +2279,32 @@ struct commit *get_revision(struct rev_info *revs)
graph_update(revs->graph, c);
return c;
}
+
+char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)
+{
+ if (commit->object.flags & BOUNDARY)
+ return "-";
+ else if (commit->object.flags & UNINTERESTING)
+ return "^";
+ else if (commit->object.flags & PATCHSAME)
+ return "=";
+ else if (!revs || revs->left_right) {
+ if (commit->object.flags & SYMMETRIC_LEFT)
+ return "<";
+ else
+ return ">";
+ } else if (revs->graph)
+ return "*";
+ else if (revs->cherry_mark)
+ return "+";
+ return "";
+}
+
+void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
+{
+ char *mark = get_revision_mark(revs, commit);
+ if (!strlen(mark))
+ return;
+ fputs(mark, stdout);
+ putchar(' ');
+}
diff --git a/revision.h b/revision.h
index 82509dd1d9..ae948601f9 100644
--- a/revision.h
+++ b/revision.h
@@ -14,7 +14,8 @@
#define CHILD_SHOWN (1u<<6)
#define ADDED (1u<<7) /* Parents already parsed and added? */
#define SYMMETRIC_LEFT (1u<<8)
-#define ALL_REV_FLAGS ((1u<<9)-1)
+#define PATCHSAME (1u<<9)
+#define ALL_REV_FLAGS ((1u<<10)-1)
#define DECORATE_SHORT_REFS 1
#define DECORATE_FULL_REFS 2
@@ -59,6 +60,8 @@ struct rev_info {
boundary:2,
count:1,
left_right:1,
+ left_only:1,
+ right_only:1,
rewrite_parents:1,
print_parents:1,
show_source:1,
@@ -66,6 +69,7 @@ struct rev_info {
reverse:1,
reverse_output_stage:1,
cherry_pick:1,
+ cherry_mark:1,
bisect:1,
ancestry_path:1,
first_parent_only:1;
@@ -163,6 +167,8 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,
extern int prepare_revision_walk(struct rev_info *revs);
extern struct commit *get_revision(struct rev_info *revs);
+extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);
+extern void put_revision_mark(const struct rev_info *revs, const struct commit *commit);
extern void mark_parents_uninteresting(struct commit *commit);
extern void mark_tree_uninteresting(struct tree *tree);
diff --git a/run-command.c b/run-command.c
index f91e446c86..8619c769a9 100644
--- a/run-command.c
+++ b/run-command.c
@@ -67,21 +67,26 @@ static int child_notifier = -1;
static void notify_parent(void)
{
- ssize_t unused;
- unused = write(child_notifier, "", 1);
+ /*
+ * execvp failed. If possible, we'd like to let start_command
+ * know, so failures like ENOENT can be handled right away; but
+ * otherwise, finish_command will still report the error.
+ */
+ if (write(child_notifier, "", 1))
+ ; /* yes, dear gcc -D_FORTIFY_SOURCE, there was an error. */
}
static NORETURN void die_child(const char *err, va_list params)
{
char msg[4096];
- ssize_t unused;
int len = vsnprintf(msg, sizeof(msg), err, params);
if (len > sizeof(msg))
len = sizeof(msg);
- unused = write(child_err, "fatal: ", 7);
- unused = write(child_err, msg, len);
- unused = write(child_err, "\n", 1);
+ if (write(child_err, "fatal: ", 7) ||
+ write(child_err, msg, len) ||
+ write(child_err, "\n", 1))
+ ; /* yes, gcc -D_FORTIFY_SOURCE, we know there was an error. */
exit(128);
}
#endif
diff --git a/sha1_file.c b/sha1_file.c
index b4fcca8ffd..7829d615d4 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -26,13 +26,8 @@
#endif
#endif
-#ifdef NO_C99_FORMAT
-#define SZ_FMT "lu"
-static unsigned long sz_fmt(size_t s) { return (unsigned long)s; }
-#else
-#define SZ_FMT "zu"
-static size_t sz_fmt(size_t s) { return s; }
-#endif
+#define SZ_FMT PRIuMAX
+static inline uintmax_t sz_fmt(size_t s) { return s; }
const unsigned char null_sha1[20];
diff --git a/submodule.c b/submodule.c
index e9f2b19e1c..0cb6d18299 100644
--- a/submodule.c
+++ b/submodule.c
@@ -9,9 +9,9 @@
#include "refs.h"
#include "string-list.h"
-struct string_list config_name_for_path;
-struct string_list config_fetch_recurse_submodules_for_name;
-struct string_list config_ignore_for_name;
+static struct string_list config_name_for_path;
+static struct string_list config_fetch_recurse_submodules_for_name;
+static struct string_list config_ignore_for_name;
static int config_fetch_recurse_submodules;
static int add_submodule_odb(const char *path)
diff --git a/t/README b/t/README
index 165e7cf34d..ccf6a53377 100644
--- a/t/README
+++ b/t/README
@@ -102,6 +102,13 @@ appropriately before running "make".
not see any output, this option implies --verbose. For
convenience, it also implies --tee.
+ Note that valgrind is run with the option --leak-check=no,
+ as the git process is short-lived and some errors are not
+ interesting. In order to run a single command under the same
+ conditions manually, you should set GIT_VALGRIND to point to
+ the 't/valgrind/' directory and use the commands under
+ 't/valgrind/bin/'.
+
--tee::
In addition to printing the test output to the terminal,
write it to files named 't/test-results/$TEST_NAME.out'.
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index f684993211..ce4ba1379e 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -47,7 +47,7 @@ test_expect_success 'plain nested in bare' '
test_expect_success 'plain through aliased command, outside any git repo' '
(
- sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
+ sane_unset GIT_DIR GIT_WORK_TREE &&
HOME=$(pwd)/alias-config &&
export HOME &&
mkdir alias-config &&
@@ -231,7 +231,6 @@ test_expect_success 'init with init.templatedir set' '
git config -f "$test_config" init.templatedir "${HOME}/templatedir-source" &&
mkdir templatedir-set &&
cd templatedir-set &&
- sane_unset GIT_CONFIG_NOGLOBAL &&
sane_unset GIT_TEMPLATE_DIR &&
NO_SET_GIT_TEMPLATE_DIR=t &&
export NO_SET_GIT_TEMPLATE_DIR &&
@@ -243,7 +242,6 @@ test_expect_success 'init with init.templatedir set' '
test_expect_success 'init --bare/--shared overrides system/global config' '
(
test_config="$HOME"/.gitconfig &&
- sane_unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" core.bare false &&
git config -f "$test_config" core.sharedRepository 0640 &&
mkdir init-bare-shared-override &&
@@ -258,7 +256,6 @@ test_expect_success 'init --bare/--shared overrides system/global config' '
test_expect_success 'init honors global core.sharedRepository' '
(
test_config="$HOME"/.gitconfig &&
- sane_unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" core.sharedRepository 0666 &&
mkdir shared-honor-global &&
cd shared-honor-global &&
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
index 15101d5e03..ec50a9ad70 100755
--- a/t/t1510-repo-setup.sh
+++ b/t/t1510-repo-setup.sh
@@ -57,7 +57,7 @@ test_repo () {
export GIT_WORK_TREE
fi &&
rm -f trace &&
- GIT_TRACE="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
+ GIT_TRACE_SETUP="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
grep '^setup: ' trace >result &&
test_cmp expected result
)
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 6fd560ccf1..f62aaf5816 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -556,4 +556,23 @@ test_expect_success 'stash branch should not drop the stash if the branch exists
git rev-parse stash@{0} --
'
+test_expect_success 'stash apply shows status same as git status (relative to current directory)' '
+ git stash clear &&
+ echo 1 >subdir/subfile1 &&
+ echo 2 >subdir/subfile2 &&
+ git add subdir/subfile1 &&
+ git commit -m subdir &&
+ (
+ cd subdir &&
+ echo x >subfile1 &&
+ echo x >../file &&
+ git status >../expect &&
+ git stash &&
+ sane_unset GIT_MERGE_VERBOSITY &&
+ git stash apply
+ ) |
+ sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index b8f81d07c3..5daa0f2a0c 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -210,6 +210,9 @@ log -m -p master
log -SF master
log -S F master
log -SF -p master
+log -SF master --max-count=0
+log -SF master --max-count=1
+log -SF master --max-count=2
log -GF master
log -GF -p master
log -GF -p --pickaxe-all master
diff --git a/t/t4013/diff.log_-SF_master_--max-count=0 b/t/t4013/diff.log_-SF_master_--max-count=0
new file mode 100644
index 0000000000..c1fc6c8731
--- /dev/null
+++ b/t/t4013/diff.log_-SF_master_--max-count=0
@@ -0,0 +1,2 @@
+$ git log -SF master --max-count=0
+$
diff --git a/t/t4013/diff.log_-SF_master_--max-count=1 b/t/t4013/diff.log_-SF_master_--max-count=1
new file mode 100644
index 0000000000..c981a03814
--- /dev/null
+++ b/t/t4013/diff.log_-SF_master_--max-count=1
@@ -0,0 +1,7 @@
+$ git log -SF master --max-count=1
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+$
diff --git a/t/t4013/diff.log_-SF_master_--max-count=2 b/t/t4013/diff.log_-SF_master_--max-count=2
new file mode 100644
index 0000000000..a6c55fd482
--- /dev/null
+++ b/t/t4013/diff.log_-SF_master_--max-count=2
@@ -0,0 +1,7 @@
+$ git log -SF master --max-count=2
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date: Mon Jun 26 00:02:00 2006 +0000
+
+ Third
+$
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 027c13d52c..9c663677df 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -709,4 +709,88 @@ test_expect_success TTY 'format-patch --stdout paginates' '
test_path_is_missing .git/pager_used
'
+test_expect_success 'format-patch handles multi-line subjects' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ for i in one two three; do echo $i; done >msg &&
+ git add file &&
+ git commit -F msg &&
+ git format-patch -o patches -1 &&
+ grep ^Subject: patches/0001-one.patch >actual &&
+ echo "Subject: [PATCH] one two three" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'format-patch handles multi-line encoded subjects' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ for i in en två tre; do echo $i; done >msg &&
+ git add file &&
+ git commit -F msg &&
+ git format-patch -o patches -1 &&
+ grep ^Subject: patches/0001-en.patch >actual &&
+ echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
+ test_cmp expect actual
+'
+
+M8="foo bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar
+EOF
+test_expect_success 'format-patch wraps extremely long headers (ascii)' '
+ echo content >>file &&
+ git add file &&
+ git commit -m "$M512" &&
+ git format-patch --stdout -1 >patch &&
+ sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+ test_cmp expect subject
+'
+
+M8="föö bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+EOF
+test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
+ rm -rf patches/ &&
+ echo content >>file &&
+ git add file &&
+ git commit -m "$M512" &&
+ git format-patch --stdout -1 >patch &&
+ sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+ test_cmp expect subject
+'
+
test_done
diff --git a/t/t4040-whitespace-status.sh b/t/t4040-whitespace-status.sh
index a30b03bcf2..abc49348b1 100755
--- a/t/t4040-whitespace-status.sh
+++ b/t/t4040-whitespace-status.sh
@@ -60,4 +60,11 @@ test_expect_success 'diff-files -b -p --exit-code' '
git diff-files -b -p --exit-code
'
+test_expect_success 'diff-files --diff-filter --quiet' '
+ git reset --hard &&
+ rm a/d &&
+ echo x >>b/e &&
+ test_must_fail git diff-files --diff-filter=M --quiet
+'
+
test_done
diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh
new file mode 100755
index 0000000000..b5ced8483a
--- /dev/null
+++ b/t/t5501-fetch-push-alternates.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='fetch/push involving alternates'
+. ./test-lib.sh
+
+count_objects () {
+ loose=0 inpack=0
+ eval "$(
+ git count-objects -v |
+ sed -n -e 's/^count: \(.*\)/loose=\1/p' \
+ -e 's/^in-pack: \(.*\)/inpack=\1/p'
+ )" &&
+ echo $(( $loose + $inpack ))
+}
+
+
+test_expect_success setup '
+ (
+ git init original &&
+ cd original &&
+ i=0 &&
+ while test $i -le 100
+ do
+ echo "$i" >count &&
+ git add count &&
+ git commit -m "$i" || exit
+ i=$(($i + 1))
+ done
+ ) &&
+ (
+ git clone --reference=original "file:///$(pwd)/original" one &&
+ cd one &&
+ echo Z >count &&
+ git add count &&
+ git commit -m Z &&
+ count_objects >../one.count
+ ) &&
+ A=$(pwd)/original/.git/objects &&
+ git init receiver &&
+ echo "$A" >receiver/.git/objects/info/alternates &&
+ git init fetcher &&
+ echo "$A" >fetcher/.git/objects/info/alternates
+'
+
+test_expect_success 'pushing into a repository with the same alternate' '
+ (
+ cd one &&
+ git push ../receiver master:refs/heads/it
+ ) &&
+ (
+ cd receiver &&
+ count_objects >../receiver.count
+ ) &&
+ test_cmp one.count receiver.count
+'
+
+test_expect_success 'fetching from a repository with the same alternate' '
+ (
+ cd fetcher &&
+ git fetch ../one master:refs/heads/it &&
+ count_objects >../fetcher.count
+ ) &&
+ test_cmp one.count fetcher.count
+'
+
+test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 987e0c8463..3ca275cc67 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -164,7 +164,6 @@ test_expect_success 'clone a void' '
test_expect_success 'clone respects global branch.autosetuprebase' '
(
test_config="$HOME/.gitconfig" &&
- unset GIT_CONFIG_NOGLOBAL &&
git config -f "$test_config" branch.autosetuprebase remote &&
rm -fr dst &&
git clone src dst &&
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index b565638e92..cacf3de6c9 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -4,13 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'
. ./test-lib.sh
-# A---B
+# A---B---D---F
# \
# \
-# C
+# C---E
#
# B changes a file foo.c, adding a line of text. C changes foo.c as
# well as bar.c, but the change in foo.c was identical to change B.
+# D and C change bar in the same way, E and F differently.
test_expect_success setup '
echo Hallo > foo &&
@@ -25,11 +26,26 @@ test_expect_success setup '
test_tick &&
git commit -m "C" &&
git tag C &&
+ echo Dello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "E" &&
+ git tag E &&
git checkout master &&
git checkout branch foo &&
test_tick &&
git commit -m "B" &&
- git tag B
+ git tag B &&
+ echo Cello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "D" &&
+ git tag D &&
+ echo Nello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "F" &&
+ git tag F
'
cat >expect <<EOF
@@ -53,8 +69,92 @@ test_expect_success '--cherry-pick foo comes up empty' '
test -z "$(git rev-list --left-right --cherry-pick B...C -- foo)"
'
+cat >expect <<EOF
+>tags/C
+EOF
+
test_expect_success '--cherry-pick bar does not come up empty' '
- ! test -z "$(git rev-list --left-right --cherry-pick B...C -- bar)"
+ git rev-list --left-right --cherry-pick B...C -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+test_expect_success 'bar does not come up empty' '
+ git rev-list --left-right B...C -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+>tags/E
+EOF
+
+test_expect_success '--cherry-pick bar does not come up empty (II)' '
+ git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/F
+=tags/D
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark' '
+ git rev-list --cherry-mark F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+=tags/D
+>tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark --left-right' '
+ git rev-list --cherry-mark --left-right F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+tags/E
+EOF
+
+test_expect_success '--cherry-pick --right-only' '
+ git rev-list --cherry-pick --right-only F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+test_expect_success '--cherry-pick --left-only' '
+ git rev-list --cherry-pick --left-only E...F -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry' '
+ git rev-list --cherry F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
'
test_expect_success '--cherry-pick with independent, but identical branches' '
@@ -75,11 +175,8 @@ cat >expect <<EOF
1 2
EOF
-# Insert an extra commit to break the symmetry
test_expect_success '--count --left-right' '
- git checkout branch &&
- test_commit D &&
- git rev-list --count --left-right B...D > actual &&
+ git rev-list --count --left-right C...D > actual &&
test_cmp expect actual
'
diff --git a/t/t6110-rev-list-sparse.sh b/t/t6110-rev-list-sparse.sh
new file mode 100755
index 0000000000..656ac7fe9d
--- /dev/null
+++ b/t/t6110-rev-list-sparse.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+test_description='operations that cull histories in unusual ways'
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+ git checkout -b side HEAD^ &&
+ test_commit D &&
+ test_commit E &&
+ git merge master
+'
+
+test_expect_success 'rev-list --first-parent --boundary' '
+ git rev-list --first-parent --boundary HEAD^..
+'
+
+test_done
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 8a7788dc39..dbc6cd8a77 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -303,6 +303,11 @@ test_expect_success 'grep -f, ignore empty lines' '
test_cmp expected actual
'
+test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
+ git grep -f - <patterns >actual &&
+ test_cmp expected actual
+'
+
cat >expected <<EOF
y:y yy
--
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index ea64cd8d0f..32ec82ad67 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -25,7 +25,8 @@ test_expect_success 'setup ' '
echo "bin: test 1 version 2" >one.bin &&
echo "bin: test number 2 version 2" >>two.bin &&
if test_have_prereq SYMLINKS; then
- ln -sf two.bin symlink.bin
+ rm symlink.bin &&
+ ln -s two.bin symlink.bin
fi &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh
index ec0a106614..b324c491c5 100755
--- a/t/t9130-git-svn-authors-file.sh
+++ b/t/t9130-git-svn-authors-file.sh
@@ -96,7 +96,6 @@ test_expect_success 'fresh clone with svn.authors-file in config' '
rm -r "$GIT_DIR" &&
test x = x"$(git config svn.authorsfile)" &&
test_config="$HOME"/.gitconfig &&
- unset GIT_CONFIG_NOGLOBAL &&
unset GIT_DIR &&
unset GIT_CONFIG &&
git config --global \
diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh
index abe7c64ba9..a523473954 100755
--- a/t/t9800-git-p4.sh
+++ b/t/t9800-git-p4.sh
@@ -61,6 +61,29 @@ test_expect_success 'git-p4 clone @all' '
rm -rf "$git" && mkdir "$git"
'
+test_expect_success 'git-p4 sync uninitialized repo' '
+ test_create_repo "$git" &&
+ cd "$git" &&
+ test_must_fail "$GITP4" sync &&
+ rm -rf "$git" && mkdir "$git"
+'
+
+#
+# Create a git repo by hand. Add a commit so that HEAD is valid.
+# Test imports a new p4 repository into a new git branch.
+#
+test_expect_success 'git-p4 sync new branch' '
+ test_create_repo "$git" &&
+ cd "$git" &&
+ test_commit head &&
+ "$GITP4" sync --branch=refs/remotes/p4/depot //depot@all &&
+ git log --oneline p4/depot >lines &&
+ cat lines &&
+ test_line_count = 2 lines &&
+ cd .. &&
+ rm -rf "$git" && mkdir "$git"
+'
+
test_expect_success 'exit when p4 fails to produce marshaled output' '
badp4dir="$TRASH_DIRECTORY/badp4dir" &&
mkdir -p "$badp4dir" &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 0fdc541a7c..7cc9a52cbf 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -43,36 +43,16 @@ TERM=dumb
export LANG LC_ALL PAGER TERM TZ
EDITOR=:
unset VISUAL
-unset GIT_EDITOR
-unset AUTHOR_DATE
-unset AUTHOR_EMAIL
-unset AUTHOR_NAME
-unset COMMIT_AUTHOR_EMAIL
-unset COMMIT_AUTHOR_NAME
unset EMAIL
-unset GIT_ALTERNATE_OBJECT_DIRECTORIES
-unset GIT_AUTHOR_DATE
+unset $(perl -e '
+ my @env = keys %ENV;
+ my @vars = grep(/^GIT_/ && !/^GIT_(TRACE|DEBUG|USE_LOOKUP)/, @env);
+ print join("\n", @vars);
+')
GIT_AUTHOR_EMAIL=author@example.com
GIT_AUTHOR_NAME='A U Thor'
-unset GIT_COMMITTER_DATE
GIT_COMMITTER_EMAIL=committer@example.com
GIT_COMMITTER_NAME='C O Mitter'
-unset GIT_DIFF_OPTS
-unset GIT_DIR
-unset GIT_WORK_TREE
-unset GIT_EXTERNAL_DIFF
-unset GIT_INDEX_FILE
-unset GIT_OBJECT_DIRECTORY
-unset GIT_CEILING_DIRECTORIES
-unset SHA1_FILE_DIRECTORIES
-unset SHA1_FILE_DIRECTORY
-unset GIT_NOTES_REF
-unset GIT_NOTES_DISPLAY_REF
-unset GIT_NOTES_REWRITE_REF
-unset GIT_NOTES_REWRITE_MODE
-unset GIT_REFLOG_ACTION
-unset GIT_CHERRY_PICK_HELP
-unset GIT_QUIET
GIT_MERGE_VERBOSITY=5
export GIT_MERGE_VERBOSITY
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
@@ -954,8 +934,8 @@ fi
GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
unset GIT_CONFIG
GIT_CONFIG_NOSYSTEM=1
-GIT_CONFIG_NOGLOBAL=1
-export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
+GIT_ATTR_NOSYSTEM=1
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
@@ -1079,6 +1059,15 @@ esac
test -z "$NO_PERL" && test_set_prereq PERL
test -z "$NO_PYTHON" && test_set_prereq PYTHON
+# Can we rely on git's output in the C locale?
+if test -n "$GETTEXT_POISON"
+then
+ GIT_GETTEXT_POISON=YesPlease
+ export GIT_GETTEXT_POISON
+else
+ test_set_prereq C_LOCALE_OUTPUT
+fi
+
# test whether the filesystem supports symbolic links
ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS
rm -f y
diff --git a/thread-utils.c b/thread-utils.c
index 589f838f82..7f4b76a958 100644
--- a/thread-utils.c
+++ b/thread-utils.c
@@ -1,5 +1,5 @@
#include "cache.h"
-#include <pthread.h>
+#include "thread-utils.h"
#if defined(hpux) || defined(__hpux) || defined(_hpux)
# include <sys/pstat.h>
diff --git a/trace.c b/trace.c
index eda3f6d721..d95341693f 100644
--- a/trace.c
+++ b/trace.c
@@ -25,10 +25,10 @@
#include "cache.h"
#include "quote.h"
-/* Get a trace file descriptor from GIT_TRACE env variable. */
-static int get_trace_fd(int *need_close)
+/* Get a trace file descriptor from "key" env variable. */
+static int get_trace_fd(const char *key, int *need_close)
{
- char *trace = getenv("GIT_TRACE");
+ char *trace = getenv(key);
if (!trace || !strcmp(trace, "") ||
!strcmp(trace, "0") || !strcasecmp(trace, "false"))
@@ -50,10 +50,10 @@ static int get_trace_fd(int *need_close)
return fd;
}
- fprintf(stderr, "What does '%s' for GIT_TRACE mean?\n", trace);
+ fprintf(stderr, "What does '%s' for %s mean?\n", trace, key);
fprintf(stderr, "If you want to trace into a file, "
- "then please set GIT_TRACE to an absolute pathname "
- "(starting with /).\n");
+ "then please set %s to an absolute pathname "
+ "(starting with /).\n", key);
fprintf(stderr, "Defaulting to tracing on stderr...\n");
return STDERR_FILENO;
@@ -62,23 +62,44 @@ static int get_trace_fd(int *need_close)
static const char err_msg[] = "Could not trace into fd given by "
"GIT_TRACE environment variable";
-void trace_printf(const char *fmt, ...)
+void trace_vprintf(const char *key, const char *fmt, va_list ap)
{
struct strbuf buf = STRBUF_INIT;
- va_list ap;
- int fd, need_close = 0;
- fd = get_trace_fd(&need_close);
- if (!fd)
+ if (!trace_want(key))
return;
set_try_to_free_routine(NULL); /* is never reset */
- va_start(ap, fmt);
strbuf_vaddf(&buf, fmt, ap);
+ trace_strbuf(key, &buf);
+ strbuf_release(&buf);
+}
+
+static void trace_printf_key(const char *key, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ trace_vprintf(key, fmt, ap);
va_end(ap);
+}
- write_or_whine_pipe(fd, buf.buf, buf.len, err_msg);
- strbuf_release(&buf);
+void trace_printf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ trace_vprintf("GIT_TRACE", fmt, ap);
+ va_end(ap);
+}
+
+void trace_strbuf(const char *key, const struct strbuf *buf)
+{
+ int fd, need_close = 0;
+
+ fd = get_trace_fd(key, &need_close);
+ if (!fd)
+ return;
+
+ write_or_whine_pipe(fd, buf->buf, buf->len, err_msg);
if (need_close)
close(fd);
@@ -90,7 +111,7 @@ void trace_argv_printf(const char **argv, const char *fmt, ...)
va_list ap;
int fd, need_close = 0;
- fd = get_trace_fd(&need_close);
+ fd = get_trace_fd("GIT_TRACE", &need_close);
if (!fd)
return;
@@ -134,12 +155,11 @@ static const char *quote_crnl(const char *path)
/* FIXME: move prefix to startup_info struct and get rid of this arg */
void trace_repo_setup(const char *prefix)
{
+ static const char *key = "GIT_TRACE_SETUP";
const char *git_work_tree;
char cwd[PATH_MAX];
- char *trace = getenv("GIT_TRACE");
- if (!trace || !strcmp(trace, "") ||
- !strcmp(trace, "0") || !strcasecmp(trace, "false"))
+ if (!trace_want(key))
return;
if (!getcwd(cwd, PATH_MAX))
@@ -151,8 +171,18 @@ void trace_repo_setup(const char *prefix)
if (!prefix)
prefix = "(null)";
- trace_printf("setup: git_dir: %s\n", quote_crnl(get_git_dir()));
- trace_printf("setup: worktree: %s\n", quote_crnl(git_work_tree));
- trace_printf("setup: cwd: %s\n", quote_crnl(cwd));
- trace_printf("setup: prefix: %s\n", quote_crnl(prefix));
+ trace_printf_key(key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
+ trace_printf_key(key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
+ trace_printf_key(key, "setup: cwd: %s\n", quote_crnl(cwd));
+ trace_printf_key(key, "setup: prefix: %s\n", quote_crnl(prefix));
+}
+
+int trace_want(const char *key)
+{
+ const char *trace = getenv(key);
+
+ if (!trace || !strcmp(trace, "") ||
+ !strcmp(trace, "0") || !strcasecmp(trace, "false"))
+ return 0;
+ return 1;
}
diff --git a/transport-helper.c b/transport-helper.c
index 0c5b1bd994..5846b55875 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -76,7 +76,7 @@ static void write_constant(int fd, const char *str)
die_errno("Full write to remote helper failed");
}
-const char *remove_ext_force(const char *url)
+static const char *remove_ext_force(const char *url)
{
if (url) {
const char *colon = strchr(url, ':');
diff --git a/transport.c b/transport.c
index 0078660611..a02f79aae3 100644
--- a/transport.c
+++ b/transport.c
@@ -192,7 +192,7 @@ static const char *rsync_url(const char *url)
static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
{
struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
- struct ref dummy = {0}, *tail = &dummy;
+ struct ref dummy = {NULL}, *tail = &dummy;
struct child_process rsync;
const char *args[5];
int temp_dir_len;
@@ -1189,3 +1189,37 @@ char *transport_anonymize_url(const char *url)
literal_copy:
return xstrdup(url);
}
+
+int refs_from_alternate_cb(struct alternate_object_database *e, void *cb)
+{
+ char *other;
+ size_t len;
+ struct remote *remote;
+ struct transport *transport;
+ const struct ref *extra;
+ alternate_ref_fn *ref_fn = cb;
+
+ e->name[-1] = '\0';
+ other = xstrdup(real_path(e->base));
+ e->name[-1] = '/';
+ len = strlen(other);
+
+ while (other[len-1] == '/')
+ other[--len] = '\0';
+ if (len < 8 || memcmp(other + len - 8, "/objects", 8))
+ return 0;
+ /* Is this a git repository with refs? */
+ memcpy(other + len - 8, "/refs", 6);
+ if (!is_directory(other))
+ return 0;
+ other[len - 8] = '\0';
+ remote = remote_get(other);
+ transport = transport_get(remote, other);
+ for (extra = transport_get_remote_refs(transport);
+ extra;
+ extra = extra->next)
+ ref_fn(extra, NULL);
+ transport_disconnect(transport);
+ free(other);
+ return 0;
+}
diff --git a/transport.h b/transport.h
index e803c0e7ba..efb1968869 100644
--- a/transport.h
+++ b/transport.h
@@ -166,4 +166,7 @@ int transport_refs_pushed(struct ref *ref);
void transport_print_push_status(const char *dest, struct ref *refs,
int verbose, int porcelain, int *nonfastforward);
+typedef void alternate_ref_fn(const struct ref *, void *);
+extern int refs_from_alternate_cb(struct alternate_object_database *e, void *cb);
+
#endif
diff --git a/unpack-trees.c b/unpack-trees.c
index b68ec820dd..500ebcfd54 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -16,7 +16,7 @@
* situation better. See how "git checkout" and "git merge" replaces
* them using setup_unpack_trees_porcelain(), for example.
*/
-const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
+static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
/* ERROR_WOULD_OVERWRITE */
"Entry '%s' would be overwritten by merge. Cannot merge.",
diff --git a/upload-pack.c b/upload-pack.c
index b40a43f27d..72aa661f8d 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -27,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<
static unsigned long oldest_have;
static int multi_ack, nr_our_refs;
+static int no_done;
static int use_thin_pack, use_ofs_delta, use_include_tag;
static int no_progress, daemon_mode;
static int shallow_nr;
@@ -429,6 +430,9 @@ static int get_common_commits(void)
static char line[1000];
unsigned char sha1[20];
char last_hex[41];
+ int got_common = 0;
+ int got_other = 0;
+ int sent_ready = 0;
save_commit_buffer = 0;
@@ -437,25 +441,40 @@ static int get_common_commits(void)
reset_timeout();
if (!len) {
+ if (multi_ack == 2 && got_common
+ && !got_other && ok_to_give_up()) {
+ sent_ready = 1;
+ packet_write(1, "ACK %s ready\n", last_hex);
+ }
if (have_obj.nr == 0 || multi_ack)
packet_write(1, "NAK\n");
+
+ if (no_done && sent_ready) {
+ packet_write(1, "ACK %s\n", last_hex);
+ return 0;
+ }
if (stateless_rpc)
exit(0);
+ got_common = 0;
+ got_other = 0;
continue;
}
strip(line, len);
if (!prefixcmp(line, "have ")) {
switch (got_sha1(line+5, sha1)) {
case -1: /* they have what we do not */
+ got_other = 1;
if (multi_ack && ok_to_give_up()) {
const char *hex = sha1_to_hex(sha1);
- if (multi_ack == 2)
+ if (multi_ack == 2) {
+ sent_ready = 1;
packet_write(1, "ACK %s ready\n", hex);
- else
+ } else
packet_write(1, "ACK %s continue\n", hex);
}
break;
default:
+ got_common = 1;
memcpy(last_hex, sha1_to_hex(sha1), 41);
if (multi_ack == 2)
packet_write(1, "ACK %s common\n", last_hex);
@@ -526,6 +545,8 @@ static void receive_needs(void)
multi_ack = 2;
else if (strstr(line+45, "multi_ack"))
multi_ack = 1;
+ if (strstr(line+45, "no-done"))
+ no_done = 1;
if (strstr(line+45, "thin-pack"))
use_thin_pack = 1;
if (strstr(line+45, "ofs-delta"))
@@ -619,7 +640,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
{
static const char *capabilities = "multi_ack thin-pack side-band"
" side-band-64k ofs-delta shallow no-progress"
- " include-tag multi_ack_detailed";
+ " include-tag multi_ack_detailed no-done";
struct object *o = parse_object(sha1);
if (!o)
@@ -682,6 +703,7 @@ int main(int argc, char **argv)
int i;
int strict = 0;
+ packet_trace_identity("upload-pack");
git_extract_argv0_path(argv[0]);
read_replace_refs = 0;
diff --git a/url.c b/url.c
index 6a5495960f..3e06fd34c4 100644
--- a/url.c
+++ b/url.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "url.h"
int is_urlschemechar(int first_flag, int ch)
{
diff --git a/usage.c b/usage.c
index ec4cf53b6b..b5e67e3d0d 100644
--- a/usage.c
+++ b/usage.c
@@ -46,7 +46,7 @@ void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list param
die_routine = routine;
}
-void usagef(const char *err, ...)
+void NORETURN usagef(const char *err, ...)
{
va_list params;
@@ -55,12 +55,12 @@ void usagef(const char *err, ...)
va_end(params);
}
-void usage(const char *err)
+void NORETURN usage(const char *err)
{
usagef("%s", err);
}
-void die(const char *err, ...)
+void NORETURN die(const char *err, ...)
{
va_list params;
@@ -69,7 +69,7 @@ void die(const char *err, ...)
va_end(params);
}
-void die_errno(const char *fmt, ...)
+void NORETURN die_errno(const char *fmt, ...)
{
va_list params;
char fmt_with_err[1024];
diff --git a/utf8.c b/utf8.c
index 84cfc72e6d..8acbc660d3 100644
--- a/utf8.c
+++ b/utf8.c
@@ -405,6 +405,15 @@ new_line:
}
}
+int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+ int indent, int indent2, int width)
+{
+ char *tmp = xstrndup(data, len);
+ int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
+ free(tmp);
+ return r;
+}
+
int is_encoding_utf8(const char *name)
{
if (!name)
diff --git a/utf8.h b/utf8.h
index ebc4d2fa85..81f2c82fab 100644
--- a/utf8.h
+++ b/utf8.h
@@ -10,6 +10,8 @@ int is_encoding_utf8(const char *name);
int strbuf_add_wrapped_text(struct strbuf *buf,
const char *text, int indent, int indent2, int width);
+int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+ int indent, int indent2, int width);
#ifndef NO_ICONV
char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 260cf50e77..a4d4d9993d 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -31,24 +31,24 @@ void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
}
static char gitsvnline[MAX_GITSVN_LINE_LEN];
-void fast_export_commit(uint32_t revision, uint32_t author, char *log,
- uint32_t uuid, uint32_t url,
+void fast_export_commit(uint32_t revision, const char *author, char *log,
+ const char *uuid, const char *url,
unsigned long timestamp)
{
if (!log)
log = "";
- if (~uuid && ~url) {
+ if (*uuid && *url) {
snprintf(gitsvnline, MAX_GITSVN_LINE_LEN,
"\n\ngit-svn-id: %s@%"PRIu32" %s\n",
- pool_fetch(url), revision, pool_fetch(uuid));
+ url, revision, uuid);
} else {
*gitsvnline = '\0';
}
printf("commit refs/heads/master\n");
printf("committer %s <%s@%s> %ld +0000\n",
- ~author ? pool_fetch(author) : "nobody",
- ~author ? pool_fetch(author) : "nobody",
- ~uuid ? pool_fetch(uuid) : "local", timestamp);
+ *author ? author : "nobody",
+ *author ? author : "nobody",
+ *uuid ? uuid : "local", timestamp);
printf("data %"PRIu32"\n%s%s\n",
(uint32_t) (strlen(log) + strlen(gitsvnline)),
log, gitsvnline);
@@ -63,14 +63,23 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,
printf("progress Imported commit %"PRIu32".\n\n", revision);
}
+static void die_short_read(struct line_buffer *input)
+{
+ if (buffer_ferror(input))
+ die_errno("error reading dump file");
+ die("invalid dump: unexpected end of file");
+}
+
void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input)
{
if (mode == REPO_MODE_LNK) {
/* svn symlink blobs start with "link " */
- buffer_skip_bytes(input, 5);
len -= 5;
+ if (buffer_skip_bytes(input, 5) != 5)
+ die_short_read(input);
}
printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
- buffer_copy_bytes(input, len);
+ if (buffer_copy_bytes(input, len) != len)
+ die_short_read(input);
fputc('\n', stdout);
}
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 054e7d5eb1..05cf97f3a7 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -6,8 +6,9 @@
void fast_export_delete(uint32_t depth, uint32_t *path);
void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
uint32_t mark);
-void fast_export_commit(uint32_t revision, uint32_t author, char *log,
- uint32_t uuid, uint32_t url, unsigned long timestamp);
+void fast_export_commit(uint32_t revision, const char *author, char *log,
+ const char *uuid, const char *url,
+ unsigned long timestamp);
void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
struct line_buffer *input);
diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c
index aedf105b70..33e733a04c 100644
--- a/vcs-svn/line_buffer.c
+++ b/vcs-svn/line_buffer.c
@@ -59,6 +59,11 @@ long buffer_tmpfile_prepare_to_read(struct line_buffer *buf)
return pos;
}
+int buffer_ferror(struct line_buffer *buf)
+{
+ return ferror(buf->infile);
+}
+
int buffer_read_char(struct line_buffer *buf)
{
return fgetc(buf->infile);
@@ -99,31 +104,32 @@ void buffer_read_binary(struct line_buffer *buf,
strbuf_fread(sb, size, buf->infile);
}
-void buffer_copy_bytes(struct line_buffer *buf, uint32_t len)
+off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
{
char byte_buffer[COPY_BUFFER_LEN];
- uint32_t in;
- while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {
- in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
+ off_t done = 0;
+ while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
+ off_t len = nbytes - done;
+ size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
in = fread(byte_buffer, 1, in, buf->infile);
- len -= in;
+ done += in;
fwrite(byte_buffer, 1, in, stdout);
- if (ferror(stdout)) {
- buffer_skip_bytes(buf, len);
- return;
- }
+ if (ferror(stdout))
+ return done + buffer_skip_bytes(buf, nbytes - done);
}
+ return done;
}
-void buffer_skip_bytes(struct line_buffer *buf, uint32_t len)
+off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
{
char byte_buffer[COPY_BUFFER_LEN];
- uint32_t in;
- while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {
- in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
- in = fread(byte_buffer, 1, in, buf->infile);
- len -= in;
+ off_t done = 0;
+ while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
+ off_t len = nbytes - done;
+ size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
+ done += fread(byte_buffer, 1, in, buf->infile);
}
+ return done;
}
void buffer_reset(struct line_buffer *buf)
diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h
index 96ce966a22..f5c468afa4 100644
--- a/vcs-svn/line_buffer.h
+++ b/vcs-svn/line_buffer.h
@@ -21,11 +21,13 @@ int buffer_tmpfile_init(struct line_buffer *buf);
FILE *buffer_tmpfile_rewind(struct line_buffer *buf); /* prepare to write. */
long buffer_tmpfile_prepare_to_read(struct line_buffer *buf);
+int buffer_ferror(struct line_buffer *buf);
char *buffer_read_line(struct line_buffer *buf);
char *buffer_read_string(struct line_buffer *buf, uint32_t len);
int buffer_read_char(struct line_buffer *buf);
void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);
-void buffer_copy_bytes(struct line_buffer *buf, uint32_t len);
-void buffer_skip_bytes(struct line_buffer *buf, uint32_t len);
+/* Returns number of bytes read (not necessarily written). */
+off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);
+off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);
#endif
diff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt
index e89cc41d56..4ef0755cf5 100644
--- a/vcs-svn/line_buffer.txt
+++ b/vcs-svn/line_buffer.txt
@@ -76,7 +76,8 @@ Functions
`buffer_skip_bytes`::
Discards `len` bytes from the input stream (stopping early
- if necessary because of an error or eof).
+ if necessary because of an error or eof). Return value is
+ the number of bytes successfully read.
`buffer_reset`::
Deallocates non-static buffers.
diff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c
index 207ffc3a83..632dbd8736 100644
--- a/vcs-svn/repo_tree.c
+++ b/vcs-svn/repo_tree.c
@@ -87,7 +87,8 @@ static struct repo_dir *repo_clone_dir(struct repo_dir *orig_dir)
return dir_pointer(new_o);
}
-static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path)
+static struct repo_dirent *repo_read_dirent(uint32_t revision,
+ const uint32_t *path)
{
uint32_t name = 0;
struct repo_dirent *key = dent_pointer(dent_alloc(1));
@@ -105,7 +106,7 @@ static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path)
return dent;
}
-static void repo_write_dirent(uint32_t *path, uint32_t mode,
+static void repo_write_dirent(const uint32_t *path, uint32_t mode,
uint32_t content_offset, uint32_t del)
{
uint32_t name, revision, dir_o = ~0, parent_dir_o = ~0;
@@ -157,7 +158,24 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode,
dent_remove(&dir_pointer(parent_dir_o)->entries, dent);
}
-uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst)
+uint32_t repo_read_path(const uint32_t *path)
+{
+ uint32_t content_offset = 0;
+ struct repo_dirent *dent = repo_read_dirent(active_commit, path);
+ if (dent != NULL)
+ content_offset = dent->content_offset;
+ return content_offset;
+}
+
+uint32_t repo_read_mode(const uint32_t *path)
+{
+ struct repo_dirent *dent = repo_read_dirent(active_commit, path);
+ if (dent == NULL)
+ die("invalid dump: path to be modified is missing");
+ return dent->mode;
+}
+
+void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst)
{
uint32_t mode = 0, content_offset = 0;
struct repo_dirent *src_dent;
@@ -167,7 +185,6 @@ uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst)
content_offset = src_dent->content_offset;
repo_write_dirent(dst, mode, content_offset, 0);
}
- return mode;
}
void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
@@ -175,20 +192,6 @@ void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
repo_write_dirent(path, mode, blob_mark, 0);
}
-uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark)
-{
- struct repo_dirent *src_dent;
- src_dent = repo_read_dirent(active_commit, path);
- if (!src_dent)
- return 0;
- if (!blob_mark)
- blob_mark = src_dent->content_offset;
- if (!mode)
- mode = src_dent->mode;
- repo_write_dirent(path, mode, blob_mark, 0);
- return mode;
-}
-
void repo_delete(uint32_t *path)
{
repo_write_dirent(path, 0, 0, 1);
@@ -275,8 +278,8 @@ void repo_diff(uint32_t r1, uint32_t r2)
repo_commit_root_dir(commit_pointer(r2)));
}
-void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
- uint32_t url, unsigned long timestamp)
+void repo_commit(uint32_t revision, const char *author, char *log,
+ const char *uuid, const char *url, unsigned long timestamp)
{
fast_export_commit(revision, author, log, uuid, url, timestamp);
dent_commit();
diff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h
index 68baeb582f..a1b0e87651 100644
--- a/vcs-svn/repo_tree.h
+++ b/vcs-svn/repo_tree.h
@@ -12,12 +12,14 @@
#define REPO_MAX_PATH_DEPTH 1000
uint32_t next_blob_mark(void);
-uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst);
+void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst);
void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);
-uint32_t repo_modify_path(uint32_t *path, uint32_t mode, uint32_t blob_mark);
+uint32_t repo_read_path(const uint32_t *path);
+uint32_t repo_read_mode(const uint32_t *path);
void repo_delete(uint32_t *path);
-void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
- uint32_t url, long unsigned timestamp);
+void repo_commit(uint32_t revision, const char *author,
+ char *log, const char *uuid, const char *url,
+ long unsigned timestamp);
void repo_diff(uint32_t r1, uint32_t r2);
void repo_init(void);
void repo_reset(void);
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index ee7c0bb2ea..ea5b128e4f 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -11,8 +11,14 @@
#include "repo_tree.h"
#include "fast_export.h"
#include "line_buffer.h"
-#include "obj_pool.h"
#include "string_pool.h"
+#include "strbuf.h"
+
+/*
+ * Compare start of string to literal of equal length;
+ * must be guarded by length test.
+ */
+#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1)
#define NODEACT_REPLACE 4
#define NODEACT_DELETE 3
@@ -27,20 +33,8 @@
#define LENGTH_UNKNOWN (~0)
#define DATE_RFC2822_LEN 31
-/* Create memory pool for log messages */
-obj_pool_gen(log, char, 4096)
-
static struct line_buffer input = LINE_BUFFER_INIT;
-static char *log_copy(uint32_t length, const char *log)
-{
- char *buffer;
- log_free(log_pool.size);
- buffer = log_pointer(log_alloc(length));
- strncpy(buffer, log, length);
- return buffer;
-}
-
static struct {
uint32_t action, propLength, textLength, srcRev, type;
uint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH];
@@ -48,24 +42,16 @@ static struct {
} node_ctx;
static struct {
- uint32_t revision, author;
+ uint32_t revision;
unsigned long timestamp;
- char *log;
+ struct strbuf log, author;
} rev_ctx;
static struct {
- uint32_t version, uuid, url;
+ uint32_t version;
+ struct strbuf uuid, url;
} dump_ctx;
-static struct {
- uint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,
- revision_number, node_path, node_kind, node_action,
- node_copyfrom_path, node_copyfrom_rev, text_content_length,
- prop_content_length, content_length, svn_fs_dump_format_version,
- /* version 3 format */
- text_delta, prop_delta;
-} keys;
-
static void reset_node_ctx(char *fname)
{
node_ctx.type = 0;
@@ -83,56 +69,58 @@ static void reset_rev_ctx(uint32_t revision)
{
rev_ctx.revision = revision;
rev_ctx.timestamp = 0;
- rev_ctx.log = NULL;
- rev_ctx.author = ~0;
+ strbuf_reset(&rev_ctx.log);
+ strbuf_reset(&rev_ctx.author);
}
-static void reset_dump_ctx(uint32_t url)
+static void reset_dump_ctx(const char *url)
{
- dump_ctx.url = url;
+ strbuf_reset(&dump_ctx.url);
+ if (url)
+ strbuf_addstr(&dump_ctx.url, url);
dump_ctx.version = 1;
- dump_ctx.uuid = ~0;
+ strbuf_reset(&dump_ctx.uuid);
}
-static void init_keys(void)
-{
- keys.svn_log = pool_intern("svn:log");
- keys.svn_author = pool_intern("svn:author");
- keys.svn_date = pool_intern("svn:date");
- keys.svn_executable = pool_intern("svn:executable");
- keys.svn_special = pool_intern("svn:special");
- keys.uuid = pool_intern("UUID");
- keys.revision_number = pool_intern("Revision-number");
- keys.node_path = pool_intern("Node-path");
- keys.node_kind = pool_intern("Node-kind");
- keys.node_action = pool_intern("Node-action");
- keys.node_copyfrom_path = pool_intern("Node-copyfrom-path");
- keys.node_copyfrom_rev = pool_intern("Node-copyfrom-rev");
- keys.text_content_length = pool_intern("Text-content-length");
- keys.prop_content_length = pool_intern("Prop-content-length");
- keys.content_length = pool_intern("Content-length");
- keys.svn_fs_dump_format_version = pool_intern("SVN-fs-dump-format-version");
- /* version 3 format (Subversion 1.1.0) */
- keys.text_delta = pool_intern("Text-delta");
- keys.prop_delta = pool_intern("Prop-delta");
-}
-
-static void handle_property(uint32_t key, const char *val, uint32_t len,
+static void handle_property(const struct strbuf *key_buf,
+ const char *val, uint32_t len,
uint32_t *type_set)
{
- if (key == keys.svn_log) {
+ const char *key = key_buf->buf;
+ size_t keylen = key_buf->len;
+
+ switch (keylen + 1) {
+ case sizeof("svn:log"):
+ if (constcmp(key, "svn:log"))
+ break;
if (!val)
die("invalid dump: unsets svn:log");
- /* Value length excludes terminating nul. */
- rev_ctx.log = log_copy(len + 1, val);
- } else if (key == keys.svn_author) {
- rev_ctx.author = pool_intern(val);
- } else if (key == keys.svn_date) {
+ strbuf_reset(&rev_ctx.log);
+ strbuf_add(&rev_ctx.log, val, len);
+ break;
+ case sizeof("svn:author"):
+ if (constcmp(key, "svn:author"))
+ break;
+ strbuf_reset(&rev_ctx.author);
+ if (val)
+ strbuf_add(&rev_ctx.author, val, len);
+ break;
+ case sizeof("svn:date"):
+ if (constcmp(key, "svn:date"))
+ break;
if (!val)
die("invalid dump: unsets svn:date");
if (parse_date_basic(val, &rev_ctx.timestamp, NULL))
warning("invalid timestamp: %s", val);
- } else if (key == keys.svn_executable || key == keys.svn_special) {
+ break;
+ case sizeof("svn:executable"):
+ case sizeof("svn:special"):
+ if (keylen == strlen("svn:executable") &&
+ constcmp(key, "svn:executable"))
+ break;
+ if (keylen == strlen("svn:special") &&
+ constcmp(key, "svn:special"))
+ break;
if (*type_set) {
if (!val)
return;
@@ -143,15 +131,22 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,
return;
}
*type_set = 1;
- node_ctx.type = key == keys.svn_executable ?
+ node_ctx.type = keylen == strlen("svn:executable") ?
REPO_MODE_EXE :
REPO_MODE_LNK;
}
}
+static void die_short_read(void)
+{
+ if (buffer_ferror(&input))
+ die_errno("error reading dump file");
+ die("invalid dump: unexpected end of file");
+}
+
static void read_props(void)
{
- uint32_t key = ~0;
+ static struct strbuf key = STRBUF_INIT;
const char *t;
/*
* NEEDSWORK: to support simple mode changes like
@@ -170,25 +165,37 @@ static void read_props(void)
uint32_t len;
const char *val;
const char type = t[0];
+ int ch;
if (!type || t[1] != ' ')
die("invalid property line: %s\n", t);
len = atoi(&t[2]);
val = buffer_read_string(&input, len);
- buffer_skip_bytes(&input, 1); /* Discard trailing newline. */
+ if (!val || strlen(val) != len)
+ die_short_read();
+
+ /* Discard trailing newline. */
+ ch = buffer_read_char(&input);
+ if (ch == EOF)
+ die_short_read();
+ if (ch != '\n')
+ die("invalid dump: expected newline after %s", val);
switch (type) {
case 'K':
- key = pool_intern(val);
- continue;
case 'D':
- key = pool_intern(val);
+ strbuf_reset(&key);
+ if (val)
+ strbuf_add(&key, val, len);
+ if (type == 'K')
+ continue;
+ assert(type == 'D');
val = NULL;
len = 0;
/* fall through */
case 'V':
- handle_property(key, val, len, &type_set);
- key = ~0;
+ handle_property(&key, val, len, &type_set);
+ strbuf_reset(&key);
continue;
default:
die("invalid property line: %s\n", t);
@@ -201,13 +208,14 @@ static void handle_node(void)
uint32_t mark = 0;
const uint32_t type = node_ctx.type;
const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
+ const int have_text = node_ctx.textLength != LENGTH_UNKNOWN;
if (node_ctx.text_delta)
die("text deltas not supported");
- if (node_ctx.textLength != LENGTH_UNKNOWN)
+ if (have_text)
mark = next_blob_mark();
if (node_ctx.action == NODEACT_DELETE) {
- if (mark || have_props || node_ctx.srcRev)
+ if (have_text || have_props || node_ctx.srcRev)
die("invalid dump: deletion node has "
"copyfrom info, text, or properties");
return repo_delete(node_ctx.dst);
@@ -221,37 +229,47 @@ static void handle_node(void)
if (node_ctx.action == NODEACT_ADD)
node_ctx.action = NODEACT_CHANGE;
}
- if (mark && type == REPO_MODE_DIR)
+ if (have_text && type == REPO_MODE_DIR)
die("invalid dump: directories cannot have text attached");
+
+ /*
+ * Decide on the new content (mark) and mode (node_ctx.type).
+ */
if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {
if (type != REPO_MODE_DIR)
die("invalid dump: root of tree is not a regular file");
} else if (node_ctx.action == NODEACT_CHANGE) {
- uint32_t mode = repo_modify_path(node_ctx.dst, 0, mark);
- if (!mode)
- die("invalid dump: path to be modified is missing");
+ uint32_t mode;
+ if (!have_text)
+ mark = repo_read_path(node_ctx.dst);
+ mode = repo_read_mode(node_ctx.dst);
if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)
die("invalid dump: cannot modify a directory into a file");
if (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)
die("invalid dump: cannot modify a file into a directory");
node_ctx.type = mode;
} else if (node_ctx.action == NODEACT_ADD) {
- if (!mark && type != REPO_MODE_DIR)
+ if (!have_text && type != REPO_MODE_DIR)
die("invalid dump: adds node without text");
- repo_add(node_ctx.dst, type, mark);
} else {
die("invalid dump: Node-path block lacks Node-action");
}
+
+ /*
+ * Adjust mode to reflect properties.
+ */
if (have_props) {
- const uint32_t old_mode = node_ctx.type;
if (!node_ctx.prop_delta)
node_ctx.type = type;
if (node_ctx.propLength)
read_props();
- if (node_ctx.type != old_mode)
- repo_modify_path(node_ctx.dst, node_ctx.type, mark);
}
- if (mark)
+
+ /*
+ * Save the result.
+ */
+ repo_add(node_ctx.dst, node_ctx.type, mark);
+ if (have_text)
fast_export_blob(node_ctx.type, mark,
node_ctx.textLength, &input);
}
@@ -259,8 +277,9 @@ static void handle_node(void)
static void handle_revision(void)
{
if (rev_ctx.revision)
- repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,
- dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
+ repo_commit(rev_ctx.revision, rev_ctx.author.buf,
+ rev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf,
+ rev_ctx.timestamp);
}
void svndump_read(const char *url)
@@ -269,44 +288,65 @@ void svndump_read(const char *url)
char *t;
uint32_t active_ctx = DUMP_CTX;
uint32_t len;
- uint32_t key;
- reset_dump_ctx(pool_intern(url));
+ reset_dump_ctx(url);
while ((t = buffer_read_line(&input))) {
- val = strstr(t, ": ");
+ val = strchr(t, ':');
if (!val)
continue;
- *val++ = '\0';
- *val++ = '\0';
- key = pool_intern(t);
+ val++;
+ if (*val != ' ')
+ continue;
+ val++;
- if (key == keys.svn_fs_dump_format_version) {
+ /* strlen(key) + 1 */
+ switch (val - t - 1) {
+ case sizeof("SVN-fs-dump-format-version"):
+ if (constcmp(t, "SVN-fs-dump-format-version"))
+ continue;
dump_ctx.version = atoi(val);
if (dump_ctx.version > 3)
die("expected svn dump format version <= 3, found %"PRIu32,
dump_ctx.version);
- } else if (key == keys.uuid) {
- dump_ctx.uuid = pool_intern(val);
- } else if (key == keys.revision_number) {
+ break;
+ case sizeof("UUID"):
+ if (constcmp(t, "UUID"))
+ continue;
+ strbuf_reset(&dump_ctx.uuid);
+ strbuf_addstr(&dump_ctx.uuid, val);
+ break;
+ case sizeof("Revision-number"):
+ if (constcmp(t, "Revision-number"))
+ continue;
if (active_ctx == NODE_CTX)
handle_node();
if (active_ctx != DUMP_CTX)
handle_revision();
active_ctx = REV_CTX;
reset_rev_ctx(atoi(val));
- } else if (key == keys.node_path) {
- if (active_ctx == NODE_CTX)
- handle_node();
- active_ctx = NODE_CTX;
- reset_node_ctx(val);
- } else if (key == keys.node_kind) {
+ break;
+ case sizeof("Node-path"):
+ if (prefixcmp(t, "Node-"))
+ continue;
+ if (!constcmp(t + strlen("Node-"), "path")) {
+ if (active_ctx == NODE_CTX)
+ handle_node();
+ active_ctx = NODE_CTX;
+ reset_node_ctx(val);
+ break;
+ }
+ if (constcmp(t + strlen("Node-"), "kind"))
+ continue;
if (!strcmp(val, "dir"))
node_ctx.type = REPO_MODE_DIR;
else if (!strcmp(val, "file"))
node_ctx.type = REPO_MODE_BLB;
else
fprintf(stderr, "Unknown node-kind: %s\n", val);
- } else if (key == keys.node_action) {
+ break;
+ case sizeof("Node-action"):
+ if (constcmp(t, "Node-action"))
+ continue;
if (!strcmp(val, "delete")) {
node_ctx.action = NODEACT_DELETE;
} else if (!strcmp(val, "add")) {
@@ -319,21 +359,44 @@ void svndump_read(const char *url)
fprintf(stderr, "Unknown node-action: %s\n", val);
node_ctx.action = NODEACT_UNKNOWN;
}
- } else if (key == keys.node_copyfrom_path) {
+ break;
+ case sizeof("Node-copyfrom-path"):
+ if (constcmp(t, "Node-copyfrom-path"))
+ continue;
pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.src, "/", val);
- } else if (key == keys.node_copyfrom_rev) {
+ break;
+ case sizeof("Node-copyfrom-rev"):
+ if (constcmp(t, "Node-copyfrom-rev"))
+ continue;
node_ctx.srcRev = atoi(val);
- } else if (key == keys.text_content_length) {
- node_ctx.textLength = atoi(val);
- } else if (key == keys.prop_content_length) {
+ break;
+ case sizeof("Text-content-length"):
+ if (!constcmp(t, "Text-content-length")) {
+ node_ctx.textLength = atoi(val);
+ break;
+ }
+ if (constcmp(t, "Prop-content-length"))
+ continue;
node_ctx.propLength = atoi(val);
- } else if (key == keys.text_delta) {
- node_ctx.text_delta = !strcmp(val, "true");
- } else if (key == keys.prop_delta) {
+ break;
+ case sizeof("Text-delta"):
+ if (!constcmp(t, "Text-delta")) {
+ node_ctx.text_delta = !strcmp(val, "true");
+ break;
+ }
+ if (constcmp(t, "Prop-delta"))
+ continue;
node_ctx.prop_delta = !strcmp(val, "true");
- } else if (key == keys.content_length) {
+ break;
+ case sizeof("Content-length"):
+ if (constcmp(t, "Content-length"))
+ continue;
len = atoi(val);
- buffer_read_line(&input);
+ t = buffer_read_line(&input);
+ if (!t)
+ die_short_read();
+ if (*t)
+ die("invalid dump: expected blank line after content length header");
if (active_ctx == REV_CTX) {
read_props();
} else if (active_ctx == NODE_CTX) {
@@ -341,10 +404,13 @@ void svndump_read(const char *url)
active_ctx = REV_CTX;
} else {
fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
- buffer_skip_bytes(&input, len);
+ if (buffer_skip_bytes(&input, len) != len)
+ die_short_read();
}
}
}
+ if (buffer_ferror(&input))
+ die_short_read();
if (active_ctx == NODE_CTX)
handle_node();
if (active_ctx != DUMP_CTX)
@@ -356,20 +422,23 @@ int svndump_init(const char *filename)
if (buffer_init(&input, filename))
return error("cannot open %s: %s", filename, strerror(errno));
repo_init();
- reset_dump_ctx(~0);
+ strbuf_init(&dump_ctx.uuid, 4096);
+ strbuf_init(&dump_ctx.url, 4096);
+ strbuf_init(&rev_ctx.log, 4096);
+ strbuf_init(&rev_ctx.author, 4096);
+ reset_dump_ctx(NULL);
reset_rev_ctx(0);
reset_node_ctx(NULL);
- init_keys();
return 0;
}
void svndump_deinit(void)
{
- log_reset();
repo_reset();
- reset_dump_ctx(~0);
+ reset_dump_ctx(NULL);
reset_rev_ctx(0);
reset_node_ctx(NULL);
+ strbuf_release(&rev_ctx.log);
if (buffer_deinit(&input))
fprintf(stderr, "Input error\n");
if (ferror(stdout))
@@ -378,10 +447,10 @@ void svndump_deinit(void)
void svndump_reset(void)
{
- log_reset();
buffer_reset(&input);
repo_reset();
- reset_dump_ctx(~0);
- reset_rev_ctx(0);
- reset_node_ctx(NULL);
+ strbuf_release(&dump_ctx.uuid);
+ strbuf_release(&dump_ctx.url);
+ strbuf_release(&rev_ctx.log);
+ strbuf_release(&rev_ctx.author);
}
diff --git a/wt-status.c b/wt-status.c
index 4daa8bb524..53558d7e5f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -32,6 +32,80 @@ static const char *color(int slot, struct wt_status *s)
return c;
}
+static void status_vprintf(struct wt_status *s, int at_bol, const char *color,
+ const char *fmt, va_list ap, const char *trail)
+{
+ struct strbuf sb = STRBUF_INIT;
+ struct strbuf linebuf = STRBUF_INIT;
+ const char *line, *eol;
+
+ strbuf_vaddf(&sb, fmt, ap);
+ if (!sb.len) {
+ strbuf_addch(&sb, '#');
+ if (!trail)
+ strbuf_addch(&sb, ' ');
+ color_print_strbuf(s->fp, color, &sb);
+ if (trail)
+ fprintf(s->fp, "%s", trail);
+ strbuf_release(&sb);
+ return;
+ }
+ for (line = sb.buf; *line; line = eol + 1) {
+ eol = strchr(line, '\n');
+
+ strbuf_reset(&linebuf);
+ if (at_bol) {
+ strbuf_addch(&linebuf, '#');
+ if (*line != '\n' && *line != '\t')
+ strbuf_addch(&linebuf, ' ');
+ }
+ if (eol)
+ strbuf_add(&linebuf, line, eol - line);
+ else
+ strbuf_addstr(&linebuf, line);
+ color_print_strbuf(s->fp, color, &linebuf);
+ if (eol)
+ fprintf(s->fp, "\n");
+ else
+ break;
+ at_bol = 1;
+ }
+ if (trail)
+ fprintf(s->fp, "%s", trail);
+ strbuf_release(&linebuf);
+ strbuf_release(&sb);
+}
+
+void status_printf_ln(struct wt_status *s, const char *color,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ status_vprintf(s, 1, color, fmt, ap, "\n");
+ va_end(ap);
+}
+
+void status_printf(struct wt_status *s, const char *color,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ status_vprintf(s, 1, color, fmt, ap, NULL);
+ va_end(ap);
+}
+
+void status_printf_more(struct wt_status *s, const char *color,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ status_vprintf(s, 0, color, fmt, ap, NULL);
+ va_end(ap);
+}
+
void wt_status_prepare(struct wt_status *s)
{
unsigned char sha1[20];
@@ -57,33 +131,33 @@ static void wt_status_print_unmerged_header(struct wt_status *s)
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# Unmerged paths:");
+ status_printf_ln(s, c, "Unmerged paths:");
if (!advice_status_hints)
return;
if (s->whence != FROM_COMMIT)
;
else if (!s->is_initial)
- color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
+ status_printf_ln(s, c, " (use \"git reset %s <file>...\" to unstage)", s->reference);
else
- color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)");
- color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" as appropriate to mark resolution)");
- color_fprintf_ln(s->fp, c, "#");
+ status_printf_ln(s, c, " (use \"git rm --cached <file>...\" to unstage)");
+ status_printf_ln(s, c, " (use \"git add/rm <file>...\" as appropriate to mark resolution)");
+ status_printf_ln(s, c, "");
}
static void wt_status_print_cached_header(struct wt_status *s)
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# Changes to be committed:");
+ status_printf_ln(s, c, "Changes to be committed:");
if (!advice_status_hints)
return;
if (s->whence != FROM_COMMIT)
; /* NEEDSWORK: use "git reset --unresolve"??? */
else if (!s->is_initial)
- color_fprintf_ln(s->fp, c, "# (use \"git reset %s <file>...\" to unstage)", s->reference);
+ status_printf_ln(s, c, " (use \"git reset %s <file>...\" to unstage)", s->reference);
else
- color_fprintf_ln(s->fp, c, "# (use \"git rm --cached <file>...\" to unstage)");
- color_fprintf_ln(s->fp, c, "#");
+ status_printf_ln(s, c, " (use \"git rm --cached <file>...\" to unstage)");
+ status_printf_ln(s, c, "");
}
static void wt_status_print_dirty_header(struct wt_status *s,
@@ -92,17 +166,17 @@ static void wt_status_print_dirty_header(struct wt_status *s,
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# Changes not staged for commit:");
+ status_printf_ln(s, c, "Changes not staged for commit:");
if (!advice_status_hints)
return;
if (!has_deleted)
- color_fprintf_ln(s->fp, c, "# (use \"git add <file>...\" to update what will be committed)");
+ status_printf_ln(s, c, " (use \"git add <file>...\" to update what will be committed)");
else
- color_fprintf_ln(s->fp, c, "# (use \"git add/rm <file>...\" to update what will be committed)");
- color_fprintf_ln(s->fp, c, "# (use \"git checkout -- <file>...\" to discard changes in working directory)");
+ status_printf_ln(s, c, " (use \"git add/rm <file>...\" to update what will be committed)");
+ status_printf_ln(s, c, " (use \"git checkout -- <file>...\" to discard changes in working directory)");
if (has_dirty_submodules)
- color_fprintf_ln(s->fp, c, "# (commit or discard the untracked or modified content in submodules)");
- color_fprintf_ln(s->fp, c, "#");
+ status_printf_ln(s, c, " (commit or discard the untracked or modified content in submodules)");
+ status_printf_ln(s, c, "");
}
static void wt_status_print_other_header(struct wt_status *s,
@@ -110,16 +184,16 @@ static void wt_status_print_other_header(struct wt_status *s,
const char *how)
{
const char *c = color(WT_STATUS_HEADER, s);
- color_fprintf_ln(s->fp, c, "# %s files:", what);
+ status_printf_ln(s, c, "%s files:", what);
if (!advice_status_hints)
return;
- color_fprintf_ln(s->fp, c, "# (use \"git %s <file>...\" to include in what will be committed)", how);
- color_fprintf_ln(s->fp, c, "#");
+ status_printf_ln(s, c, " (use \"git %s <file>...\" to include in what will be committed)", how);
+ status_printf_ln(s, c, "");
}
static void wt_status_print_trailer(struct wt_status *s)
{
- color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
+ status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
}
#define quote_path quote_path_relative
@@ -133,7 +207,7 @@ static void wt_status_print_unmerged_data(struct wt_status *s,
const char *one, *how = "bug";
one = quote_path(it->string, -1, &onebuf, s->prefix);
- color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+ status_printf(s, color(WT_STATUS_HEADER, s), "\t");
switch (d->stagemask) {
case 1: how = "both deleted:"; break;
case 2: how = "added by us:"; break;
@@ -143,7 +217,7 @@ static void wt_status_print_unmerged_data(struct wt_status *s,
case 6: how = "both added:"; break;
case 7: how = "both modified:"; break;
}
- color_fprintf(s->fp, c, "%-20s%s\n", how, one);
+ status_printf_more(s, c, "%-20s%s\n", how, one);
strbuf_release(&onebuf);
}
@@ -186,40 +260,40 @@ static void wt_status_print_change_data(struct wt_status *s,
one = quote_path(one_name, -1, &onebuf, s->prefix);
two = quote_path(two_name, -1, &twobuf, s->prefix);
- color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+ status_printf(s, color(WT_STATUS_HEADER, s), "\t");
switch (status) {
case DIFF_STATUS_ADDED:
- color_fprintf(s->fp, c, "new file: %s", one);
+ status_printf_more(s, c, "new file: %s", one);
break;
case DIFF_STATUS_COPIED:
- color_fprintf(s->fp, c, "copied: %s -> %s", one, two);
+ status_printf_more(s, c, "copied: %s -> %s", one, two);
break;
case DIFF_STATUS_DELETED:
- color_fprintf(s->fp, c, "deleted: %s", one);
+ status_printf_more(s, c, "deleted: %s", one);
break;
case DIFF_STATUS_MODIFIED:
- color_fprintf(s->fp, c, "modified: %s", one);
+ status_printf_more(s, c, "modified: %s", one);
break;
case DIFF_STATUS_RENAMED:
- color_fprintf(s->fp, c, "renamed: %s -> %s", one, two);
+ status_printf_more(s, c, "renamed: %s -> %s", one, two);
break;
case DIFF_STATUS_TYPE_CHANGED:
- color_fprintf(s->fp, c, "typechange: %s", one);
+ status_printf_more(s, c, "typechange: %s", one);
break;
case DIFF_STATUS_UNKNOWN:
- color_fprintf(s->fp, c, "unknown: %s", one);
+ status_printf_more(s, c, "unknown: %s", one);
break;
case DIFF_STATUS_UNMERGED:
- color_fprintf(s->fp, c, "unmerged: %s", one);
+ status_printf_more(s, c, "unmerged: %s", one);
break;
default:
die("bug: unhandled diff status %c", status);
}
if (extra.len) {
- color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "%s", extra.buf);
+ status_printf_more(s, color(WT_STATUS_HEADER, s), "%s", extra.buf);
strbuf_release(&extra);
}
- fprintf(s->fp, "\n");
+ status_printf_more(s, GIT_COLOR_NORMAL, "\n");
strbuf_release(&onebuf);
strbuf_release(&twobuf);
}
@@ -576,9 +650,9 @@ static void wt_status_print_other(struct wt_status *s,
for (i = 0; i < l->nr; i++) {
struct string_list_item *it;
it = &(l->items[i]);
- color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
- color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s",
- quote_path(it->string, strlen(it->string),
+ status_printf(s, color(WT_STATUS_HEADER, s), "\t");
+ status_printf_more(s, color(WT_STATUS_UNTRACKED, s),
+ "%s\n", quote_path(it->string, strlen(it->string),
&buf, s->prefix));
}
strbuf_release(&buf);
@@ -645,17 +719,17 @@ void wt_status_print(struct wt_status *s)
branch_status_color = color(WT_STATUS_NOBRANCH, s);
on_what = "Not currently on any branch.";
}
- color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# ");
- color_fprintf(s->fp, branch_status_color, "%s", on_what);
- color_fprintf_ln(s->fp, branch_color, "%s", branch_name);
+ status_printf(s, color(WT_STATUS_HEADER, s), "");
+ status_printf_more(s, branch_status_color, "%s", on_what);
+ status_printf_more(s, branch_color, "%s\n", branch_name);
if (!s->is_initial)
wt_status_print_tracking(s);
}
if (s->is_initial) {
- color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
- color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit");
- color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
+ status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
+ status_printf_ln(s, color(WT_STATUS_HEADER, s), "Initial commit");
+ status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
}
wt_status_print_updated(s);
@@ -672,7 +746,7 @@ void wt_status_print(struct wt_status *s)
if (s->show_ignored_files)
wt_status_print_other(s, &s->ignored, "Ignored", "add -f");
} else if (s->commitable)
- fprintf(s->fp, "# Untracked files not listed%s\n",
+ status_printf_ln(s, GIT_COLOR_NORMAL, "Untracked files not listed%s",
advice_status_hints
? " (use -u option to show untracked files)" : "");
@@ -680,7 +754,7 @@ void wt_status_print(struct wt_status *s)
wt_status_print_verbose(s);
if (!s->commitable) {
if (s->amend)
- fprintf(s->fp, "# No changes\n");
+ status_printf_ln(s, GIT_COLOR_NORMAL, "No changes");
else if (s->nowarn)
; /* nothing */
else if (s->workdir_dirty)
diff --git a/wt-status.h b/wt-status.h
index cec482a56e..682b4c8f7d 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -75,4 +75,11 @@ void wt_status_collect(struct wt_status *s);
void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_branch);
void wt_porcelain_print(struct wt_status *s, int null_termination);
+void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...)
+ ;
+void status_printf(struct wt_status *s, const char *color, const char *fmt, ...)
+ ;
+void status_printf_more(struct wt_status *s, const char *color, const char *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
+
#endif /* STATUS_H */