aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/CodingGuidelines12
-rw-r--r--Documentation/RelNotes-1.5.4.4.txt22
-rw-r--r--Documentation/RelNotes-1.5.5.txt115
-rw-r--r--Documentation/config.txt36
-rw-r--r--Documentation/git-cherry-pick.txt2
-rw-r--r--Documentation/git-cvsimport.txt6
-rw-r--r--Documentation/git-describe.txt9
-rw-r--r--Documentation/git-gc.txt5
-rw-r--r--Documentation/git-grep.txt2
-rw-r--r--Documentation/git-index-pack.txt3
-rw-r--r--Documentation/git-merge.txt3
-rw-r--r--Documentation/git-rebase.txt1
-rw-r--r--Documentation/git-rev-list.txt3
-rw-r--r--Documentation/git-verify-pack.txt4
-rw-r--r--Documentation/git-whatchanged.txt9
-rw-r--r--Documentation/pretty-options.txt3
-rw-r--r--Documentation/rev-list-options.txt2
-rw-r--r--Documentation/technical/api-run-command.txt13
-rw-r--r--Makefile19
-rw-r--r--builtin-checkout.c37
-rw-r--r--builtin-describe.c54
-rw-r--r--builtin-fetch-pack.c18
-rw-r--r--builtin-fsck.c341
-rw-r--r--builtin-gc.c4
-rw-r--r--builtin-http-fetch.c2
-rw-r--r--builtin-log.c34
-rw-r--r--builtin-ls-remote.c5
-rw-r--r--builtin-pack-objects.c161
-rw-r--r--builtin-reset.c8
-rw-r--r--builtin-rev-list.c4
-rw-r--r--builtin-revert.c20
-rw-r--r--builtin-send-pack.c4
-rw-r--r--builtin-unpack-objects.c23
-rw-r--r--builtin-verify-pack.c2
-rw-r--r--cache.h1
-rw-r--r--commit.c13
-rw-r--r--commit.h1
-rwxr-xr-xcontrib/completion/git-completion.bash28
-rw-r--r--contrib/emacs/git.el4
-rwxr-xr-xcontrib/fast-import/git-p445
-rw-r--r--contrib/hooks/post-receive-email2
-rwxr-xr-xcontrib/stats/packinfo.pl2
-rw-r--r--daemon.c18
-rw-r--r--diff-lib.c13
-rw-r--r--diff.c9
-rw-r--r--diffcore-rename.c7
-rw-r--r--fast-import.c1
-rw-r--r--fsck.c333
-rw-r--r--fsck.h32
-rwxr-xr-xgit-am.sh2
-rwxr-xr-xgit-clone.sh37
-rw-r--r--git-compat-util.h6
-rwxr-xr-xgit-cvsimport.perl17
-rwxr-xr-xgit-cvsserver.perl2
-rw-r--r--git-gui/lib/about.tcl3
-rw-r--r--git-gui/lib/error.tcl2
-rw-r--r--git-gui/lib/spellcheck.tcl75
-rw-r--r--git-gui/po/de.po70
-rw-r--r--git-gui/po/git-gui.pot32
-rw-r--r--git-gui/po/glossary/de.po4
-rwxr-xr-xgit-merge.sh19
-rwxr-xr-xgit-mergetool.sh161
-rwxr-xr-xgit-rebase.sh5
-rwxr-xr-xgit-remote.perl6
-rwxr-xr-xgit-submodule.sh2
-rwxr-xr-xgitweb/gitweb.perl60
-rw-r--r--http-push.c19
-rw-r--r--http-walker.c4
-rw-r--r--http.c24
-rw-r--r--http.h3
-rw-r--r--index-pack.c88
-rw-r--r--object-refs.c87
-rw-r--r--object.h8
-rw-r--r--pack-check.c11
-rw-r--r--pack-revindex.c142
-rw-r--r--pack-revindex.h12
-rw-r--r--path.c6
-rw-r--r--receive-pack.c2
-rw-r--r--revision.c31
-rw-r--r--run-command.c14
-rw-r--r--sha1_file.c10
-rw-r--r--sha1_name.c13
-rw-r--r--t/lib-httpd.sh96
-rw-r--r--t/lib-httpd/apache.conf34
-rw-r--r--t/lib-httpd/ssl.cnf8
-rwxr-xr-xt/t0000-basic.sh2
-rwxr-xr-xt/t2009-checkout-statinfo.sh52
-rwxr-xr-xt/t3404-rebase-interactive.sh2
-rwxr-xr-xt/t3407-rebase-abort.sh71
-rwxr-xr-xt/t3501-revert-cherry-pick.sh9
-rw-r--r--t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^4
-rwxr-xr-xt/t4014-format-patch.sh37
-rwxr-xr-xt/t4027-diff-submodule.sh53
-rwxr-xr-xt/t5540-http-push.sh73
-rwxr-xr-xt/t5701-clone-local.sh45
-rwxr-xr-xt/t6024-recursive-merge.sh2
-rwxr-xr-xt/t6029-merge-subtree.sh47
-rwxr-xr-xt/t6120-describe.sh25
-rwxr-xr-xt/t7300-clean.sh3
-rwxr-xr-xt/t7600-merge.sh6
-rw-r--r--t/t7610-mergetool.sh46
-rw-r--r--t/test-lib.sh11
-rw-r--r--tag.c6
-rw-r--r--transport.c18
-rw-r--r--tree.c48
-rw-r--r--upload-pack.c1
-rw-r--r--walker.c1
-rw-r--r--walker.h4
109 files changed, 2226 insertions, 951 deletions
diff --git a/.gitignore b/.gitignore
index 165b256e2..4ff2fec27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+GIT-BUILD-OPTIONS
GIT-CFLAGS
GIT-GUI-VARS
GIT-VERSION-FILE
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index 3b042db62..994eb9159 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -53,6 +53,18 @@ For shell scripts specifically (not exhaustive):
- We do not write the noiseword "function" in front of shell
functions.
+ - As to use of grep, stick to a subset of BRE (namely, no \{m,n\},
+ [::], [==], nor [..]) for portability.
+
+ - We do not use \{m,n\};
+
+ - We do not use -E;
+
+ - We do not use ? nor + (which are \{0,1\} and \{1,\}
+ respectively in BRE) but that goes without saying as these
+ are ERE elements not BRE (note that \? and \+ are not even part
+ of BRE -- making them accessible from BRE is a GNU extension).
+
For C programs:
- We use tabs to indent, and interpret tabs as taking up to
diff --git a/Documentation/RelNotes-1.5.4.4.txt b/Documentation/RelNotes-1.5.4.4.txt
index 5bfdb3537..5635977c9 100644
--- a/Documentation/RelNotes-1.5.4.4.txt
+++ b/Documentation/RelNotes-1.5.4.4.txt
@@ -4,6 +4,10 @@ GIT v1.5.4.4 Release Notes
Fixes since v1.5.4.3
--------------------
+ * Building and installing with an overtight umask such as 077 made
+ installed templates unreadable by others, while the rest of the install
+ are done in a way that is friendly to umask 022.
+
* "git cvsexportcommit -w $cvsdir" misbehaved when GIT_DIR is set to a
relative directory.
@@ -17,10 +21,26 @@ Fixes since v1.5.4.3
* "git send-email" in 1.5.4.3 issued a bogus empty In-Reply-To: header.
+ * "git bisect" showed mysterious "won't bisect on seeked tree" error message.
+ This was leftover from Cogito days to prevent "bisect" starting from a
+ cg-seeked state. We still keep the Cogito safety, but running "git bisect
+ start" when another bisect was in effect will clean up and start over.
+
+ * "git push" with an explicit PATH to receive-pack did not quite work if
+ receive-pack was not on usual PATH. We earlier fixed the same issue
+ with "git fetch" and upload-pack, but somehow forgot to do so in the
+ other direction.
+
+ * git-gui's info dialog was not displayed correctly when the user tries
+ to commit nothing (i.e. without staging anything).
+
+ * "git revert" did not properly fail when attempting to run with a
+ dirty index.
+
Also included are a handful documentation updates.
---
exec >/var/tmp/1
echo O=$(git describe maint)
-O=v1.5.4.3
+O=v1.5.4.3-32-g0f2d447
git shortlog --no-merges $O..maint
diff --git a/Documentation/RelNotes-1.5.5.txt b/Documentation/RelNotes-1.5.5.txt
index c8b4f72c2..b57fa1eb1 100644
--- a/Documentation/RelNotes-1.5.5.txt
+++ b/Documentation/RelNotes-1.5.5.txt
@@ -4,6 +4,10 @@ GIT v1.5.5 Release Notes
Updates since v1.5.4
--------------------
+(subsystems)
+
+ * Comes with git-gui 0.9.3
+
(performance)
* On platforms with suboptimal qsort(3) implementation, there
@@ -26,21 +30,97 @@ Updates since v1.5.4
* You can be warned when core.autocrlf conversion is applied in
such a way that results in an irreversible conversion.
+ * A catch-all "color.ui" configuration variable can be used to
+ enable coloring of all color-capable commands, instead of
+ individual ones such as "color.status" and "color.branch".
+
+ * The commands refused to take absolute pathnames where they
+ require pathnames relative to the work tree or the current
+ subdirectory. They now can take absolute pathnames in such a
+ case as long as the pathnames do not refer outside of the
+ work tree. E.g. "git add $(pwd)/foo" now works.
+
+ * Error messages used to be sent to stderr, only to get hidden,
+ when $PAGER was in use. They now are sent to stdout along
+ with the command output to be shown in the $PAGER.
+
* A pattern "foo/" in .gitignore file now matches a directory
"foo". Pattern "foo" also matches as before.
+ * bash completion's prompt helper function can talk about
+ operation in-progress (e.g. merge, rebase, etc.).
+
+ * Configuration variables "url.<usethis>.insteadof = <otherurl>" can be
+ used to tell "git-fetch" and "git-push" to use different URL than what
+ is given from the command line.
+
+ * "git push <somewhere> HEAD" and "git push <somewhere> +HEAD" works as
+ expected; they push the current branch (and only the current branch).
+ In addition, HEAD can be written as the value of "remote.<there>.push"
+ configuration variable.
+
+ * "git add -i" behaves better even before you make an initial commit.
+
+ * "git am" refused to run from a subdirectory without a good reason.
+
+ * After "git apply --whitespace=fix" fixes whitespace errors in a patch,
+ a line before the fix can appear as a context or preimage line in a
+ later patch, causing the patch not to apply. The command now knows to
+ see through whitespace fixes done to context lines to successfully
+ apply such a patch series.
+
+ * "git branch" (and "git checkout -b") to branch from a local branch can
+ optionally set "branch.<name>.merge" to mark the new branch to build on
+ the other local branch, when "branch.autosetupmerge" is set to
+ "always". By default, this does not happen when branching from a local
+ branch.
+
+ * "git checkout" to switch to a branch that has "branch.<name>.merge" set
+ (i.e. marked to build on another branch) reports how much the branch
+ and the other branch diverged.
+
+ * When "git checkout" has to update a lot of paths, it used to be silent
+ for 4 seconds before it showed any progress report. It is now a bit
+ more impatient and starts showing progress report early.
+
+ * "git commit" learned a new hook "prepare-commit-msg" that can
+ inspect what is going to be committed and prepare the commit
+ log message template to be edited.
+
+ * "git cvsimport" can now take more than one -M options.
+
* "git describe" learned to limit the tags to be used for
naming with --match option.
* "git describe --contains" now barfs when the named commit
cannot be described.
- * bash completion's prompt helper function can talk about
- operation in-progress (e.g. merge, rebase, etc.).
+ * "git describe --exact-match" describes only commits that are tagged.
- * "git commit" learned a new hook "prepare-commit-msg" that can
- inspect what is going to be committed and prepare the commit
- log message template to be edited.
+ * "git describe --long" describes a tagged commit as $tag-0-$sha1,
+ instead of just showing the exact tagname.
+
+ * "git describe" warns when using a tag whose name and path contradict
+ with each other.
+
+ * "git diff" learned "--relative" option to limit and output paths
+ relative to the current directory when working in a subdirectory.
+
+ * "git diff" learned "--dirstat" option to show birds-eye-summary of
+ changes more concisely than "--diffstat".
+
+ * "git format-patch" learned --cover-letter option to generate a cover
+ letter template.
+
+ * "git gc" learned --quiet option.
+
+ * "git grep" now knows "--name-only" is a synonym for the "-l" option.
+
+ * "git help <alias>" now reports "'git <alias>' is alias to <what>",
+ instead of saying "No manual entry for git-<alias>".
+
+ * "git log --grep=<what>" learned "--fixed-strings" option to look for
+ <what> without treating it as a regular expression.
* "git gui" learned an auto-spell checking.
@@ -50,6 +130,9 @@ Updates since v1.5.4
* "git send-email" learned an easier way to suppress CC
recipients.
+ * When the configuration variable "pack.threads" is set to 0, "git
+ repack" auto detects the number of CPUs and uses that many threads.
+
* Various "git cvsimport", "git cvsexportcommit", "git svn" and
"git p4" improvements.
@@ -61,6 +144,15 @@ Updates since v1.5.4
* It is now easier to write test scripts that records known
breakages.
+ * "git checkout" is rewritten in C.
+
+ * Two conflict hunks that are separated by a very short span of common
+ lines are now coalesced into one larger hunk, to make the result easier
+ to read.
+
+ * Run-command API's use of file descriptors is documented clearer and
+ is more consistent now.
+
Fixes since v1.5.4
------------------
@@ -68,11 +160,18 @@ Fixes since v1.5.4
All of the fixes in v1.5.4 maintenance series are included in
this release, unless otherwise noted.
+ * "git-daemon" did not send early errors to syslog.
+
+ * "git-http-push" did not allow deletion of remote ref with the usual
+ "push <remote> :<branch>" syntax.
+
+ * "git-log --merge" did not well work with --left-right option.
+
+ * "git-rebase --abort" did not go back to the right location if
+ "git-reset" was run during the "git-rebase" session.
---
exec >/var/tmp/1
-O=v1.5.4
-O=v1.5.4.2-122-g7cb97da
+O=v1.5.4.3-428-g6b48990
echo O=`git describe refs/heads/master`
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
-
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4027726f2..683a53a0b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -556,6 +556,11 @@ format.suffix::
`.patch`. Use this variable to change that suffix (make sure to
include the dot if you want it).
+format.pretty::
+ The default pretty format for log/show/whatchanged command,
+ See linkgit:git-log[1], linkgit:git-show[1],
+ linkgit:git-whatchanged[1].
+
gc.aggressiveWindow::
The window size parameter used in the delta compression
algorithm used by 'git gc --aggressive'. This defaults
@@ -749,8 +754,10 @@ merge.summary::
merge.tool::
Controls which merge resolution program is used by
- linkgit:git-mergetool[1]. Valid values are: "kdiff3", "tkdiff",
- "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and "opendiff".
+ linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3",
+ "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
+ "opendiff". Any other value is treated is custom merge tool
+ and there must be a corresponing mergetool.<tool>.cmd option.
merge.verbosity::
Controls the amount of output shown by the recursive merge
@@ -777,6 +784,31 @@ mergetool.<tool>.path::
Override the path for the given tool. This is useful in case
your tool is not in the PATH.
+mergetool.<tool>.cmd::
+ Specify the command to invoke the specified merge tool. The
+ specified command is evaluated in shell with the following
+ variables available: 'BASE' is the name of a temporary file
+ containing the common base of the files to be merged, if available;
+ 'LOCAL' is the name of a temporary file containing the contents of
+ the file on the current branch; 'REMOTE' is the name of a temporary
+ file containing the contents of the file from the branch being
+ merged; 'MERGED' contains the name of the file to which the merge
+ tool should write the results of a successful merge.
+
+mergetool.<tool>.trustExitCode::
+ For a custom merge command, specify whether the exit code of
+ the merge command can be used to determine whether the merge was
+ successful. If this is not set to true then the merge target file
+ timestamp is checked and the merge assumed to have been successful
+ if the file has been updated, otherwise the user is prompted to
+ indicate the success of the merge.
+
+mergetool.keepBackup::
+ After performing a merge, the original file with conflict markers
+ can be saved as a file with a `.orig` extension. If this variable
+ is set to `false` then this file is not preserved. Defaults to
+ `true` (i.e. keep the backup files).
+
pack.window::
The size of the window used by linkgit:git-pack-objects[1] when no
window size is given on the command line. Defaults to 10.
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 877ab66ef..f0beb412e 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -45,7 +45,7 @@ OPTIONS
default is not to do `-x` so this option is a no-op.
-m parent-number|--mainline parent-number::
- Usually you cannot revert a merge because you do not know which
+ Usually you cannot cherry-pick a merge because you do not know which
side of the merge should be considered the mainline. This
option specifies the parent number (starting from 1) of
the mainline and allows cherry-pick to replay the change
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index 6f91b9ea2..58eefd42e 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -102,13 +102,17 @@ If you need to pass multiple options, separate them with a comma.
-m::
Attempt to detect merges based on the commit message. This option
- will enable default regexes that try to capture the name source
+ will enable default regexes that try to capture the source
branch name from the commit message.
-M <regex>::
Attempt to detect merges based on the commit message with a custom
regex. It can be used with '-m' to enable the default regexes
as well. You must escape forward slashes.
++
+The regex must capture the source branch name in $1.
++
+This option can be used several times to provide several detection regexes.
-S <regex>::
Skip paths matching the regex.
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index fbb40a291..d9aa2f298 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -56,6 +56,15 @@ OPTIONS
being employed to standard error. The tag name will still
be printed to standard out.
+--long::
+ Always output the long format (the tag, the number of commits
+ and the abbreviated commit name) even when it matches a tag.
+ This is useful when you want to see parts of the commit object name
+ in "describe" output, even when the commit in question happens to be
+ a tagged version. Instead of just emitting the tag name, it will
+ describe such a commit as v1.2-0-deadbeef (0th commit since tag v1.2
+ that points at object deadbeef....).
+
--match <pattern>::
Only consider tags matching the given pattern (can be used to avoid
leaking private tags made from the repository).
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 4b2dfefa6..2e7be916a 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
SYNOPSIS
--------
-'git-gc' [--prune] [--aggressive] [--auto]
+'git-gc' [--prune] [--aggressive] [--auto] [--quiet]
DESCRIPTION
-----------
@@ -63,6 +63,9 @@ are consolidated into a single pack by using the `-A` option of
`git-repack`. Setting `gc.autopacklimit` to 0 disables
automatic consolidation of packs.
+--quiet::
+ Suppress all progress reports.
+
Configuration
-------------
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index 71a73354f..a97f0557f 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -78,7 +78,7 @@ OPTIONS
-l | --files-with-matches | --name-only | -L | --files-without-match::
Instead of showing every matched line, show only the
names of files that contain (or do not contain) matches.
- For better compatability with git-diff, --name-only is a
+ For better compatibility with git-diff, --name-only is a
synonym for --files-with-matches.
-c | --count::
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 72b5d0011..a7825b614 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -75,6 +75,9 @@ OPTIONS
to force the version for the generated pack index, and to force
64-bit index entries on objects located above the given offset.
+--strict::
+ Die, if the pack contains broken objects or links.
+
Note
----
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 0c9ad7f2b..c136b1069 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -68,7 +68,8 @@ HOW MERGE WORKS
---------------
A merge is always between the current `HEAD` and one or more
-remote branch heads, and the index file must exactly match the
+commits (usually, branch head or tag), and the index file must
+exactly match the
tree of `HEAD` commit (i.e. the contents of the last commit) when
it happens. In other words, `git-diff --cached HEAD` must
report no changes.
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index c11c6453e..4b1030474 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -9,6 +9,7 @@ SYNOPSIS
--------
[verse]
'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]
+ [-s <strategy> | --strategy=<strategy>]
[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]
[--onto <newbase>] <upstream> [<branch>]
'git-rebase' --continue | --skip | --abort
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index a8d489f9f..d80cdf550 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -20,6 +20,9 @@ SYNOPSIS
[ \--full-history ]
[ \--not ]
[ \--all ]
+ [ \--branches ]
+ [ \--tags ]
+ [ \--remotes ]
[ \--stdin ]
[ \--quiet ]
[ \--topo-order ]
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
index db019a2b8..ba2a15729 100644
--- a/Documentation/git-verify-pack.txt
+++ b/Documentation/git-verify-pack.txt
@@ -32,11 +32,11 @@ OUTPUT FORMAT
-------------
When specifying the -v option the format used is:
- SHA1 type size offset-in-packfile
+ SHA1 type size size-in-pack-file offset-in-packfile
for objects that are not deltified in the pack, and
- SHA1 type size offset-in-packfile depth base-SHA1
+ SHA1 type size size-in-packfile offset-in-packfile depth base-SHA1
for objects that are deltified.
diff --git a/Documentation/git-whatchanged.txt b/Documentation/git-whatchanged.txt
index 54947b676..a6e7bd4c8 100644
--- a/Documentation/git-whatchanged.txt
+++ b/Documentation/git-whatchanged.txt
@@ -38,11 +38,6 @@ OPTIONS
Show git internal diff output, but for the whole tree,
not just the top level.
---pretty=<format>::
- Controls the output format for the commit logs.
- <format> can be one of 'raw', 'medium', 'short', 'full',
- and 'oneline'.
-
-m::
By default, differences for merge commits are not shown.
With this flag, show differences to that commit from all
@@ -51,6 +46,10 @@ OPTIONS
However, it is not very useful in general, although it
*is* useful on a file-by-file basis.
+include::pretty-options.txt[]
+
+include::pretty-formats.txt[]
+
Examples
--------
git-whatchanged -p v2.6.12.. include/scsi drivers/scsi::
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 973d8dd73..6d66c74cc 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -4,6 +4,9 @@
where '<format>' can be one of 'oneline', 'short', 'medium',
'full', 'fuller', 'email', 'raw' and 'format:<string>'.
When omitted, the format defaults to 'medium'.
++
+Note: you can specify the default pretty format in the repository
+configuration (see linkgit:git-config[1]).
--abbrev-commit::
Instead of showing the full 40-byte hexadecimal commit object
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 259072c07..2648a5508 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -130,9 +130,11 @@ limiting may be applied.
Show commits older than a specific date.
+ifdef::git-rev-list[]
--max-age='timestamp', --min-age='timestamp'::
Limit the commits output to specified time range.
+endif::git-rev-list[]
--author='pattern', --committer='pattern'::
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
index dfbf9ac5d..c364a22c8 100644
--- a/Documentation/technical/api-run-command.txt
+++ b/Documentation/technical/api-run-command.txt
@@ -49,7 +49,7 @@ Functions
`finish_async`::
- Wait for the completeion of an asynchronous function that was
+ Wait for the completion of an asynchronous function that was
started with start_async().
@@ -111,9 +111,10 @@ stderr as follows:
.no_stdin, .no_stdout, .no_stderr: The respective channel is
redirected to /dev/null.
- .stdout_to_stderr: stdout of the child is redirected to the
- parent's stderr (i.e. *not* to what .err or
- .no_stderr specify).
+ .stdout_to_stderr: stdout of the child is redirected to its
+ stderr. This happens after stderr is itself redirected.
+ So stdout will follow stderr to wherever it is
+ redirected.
To modify the environment of the sub-process, specify an array of
string pointers (NULL terminated) in .env:
@@ -121,8 +122,8 @@ string pointers (NULL terminated) in .env:
. If the string is of the form "VAR=value", i.e. it contains '='
the variable is added to the child process's environment.
-. If the string does not contain '=', it names an environement
- variable that will be removed from the child process's envionment.
+. If the string does not contain '=', it names an environment
+ variable that will be removed from the child process's environment.
To specify a new initial working directory for the sub-process,
specify it in the .dir member.
diff --git a/Makefile b/Makefile
index a5b6eebf1..6e857e62c 100644
--- a/Makefile
+++ b/Makefile
@@ -304,7 +304,8 @@ LIB_H = \
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
- mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h
+ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h fsck.h \
+ pack-revindex.h
DIFF_OBJS = \
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -319,7 +320,7 @@ LIB_OBJS = \
patch-ids.o \
object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \
sideband.o reachable.o reflog-walk.o \
- quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
+ quote.o read-cache.o refs.o run-command.o dir.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
revision.o pager.o tree-walk.o xdiff-interface.o \
@@ -328,7 +329,7 @@ LIB_OBJS = \
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \
transport.o bundle.o walker.o parse-options.o ws.o archive.o branch.o \
- alias.o
+ alias.o fsck.o pack-revindex.o
BUILTIN_OBJS = \
builtin-add.o \
@@ -477,6 +478,7 @@ ifeq ($(uname_S),FreeBSD)
NO_MEMMEM = YesPlease
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
+ DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease
@@ -746,6 +748,9 @@ ifdef THREADED_DELTA_SEARCH
EXTLIBS += -lpthread
LIB_OBJS += thread-utils.o
endif
+ifdef DIR_HAS_BSD_GROUP_SEMANTICS
+ COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
+endif
ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
@@ -812,7 +817,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
### Build rules
-all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS)
+all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
ifneq (,$X)
$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';)
endif
@@ -1011,6 +1016,9 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
echo "$$FLAGS" >GIT-CFLAGS; \
fi
+GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
+ @echo SHELL_PATH=\''$(SHELL_PATH_SQ)'\' >$@
+
### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK
TRACK_VARS = $(subst ','\'',-DTCLTK_PATH='$(TCLTK_PATH_SQ)')
@@ -1166,10 +1174,11 @@ ifndef NO_TCLTK
$(MAKE) -C gitk-git clean
$(MAKE) -C git-gui clean
endif
- $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS
+ $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
.PHONY: all install clean strip
.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
+.PHONY: .FORCE-GIT-BUILD-OPTIONS
### Check documentation
#
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 9579ff4ab..6b0801622 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -67,17 +67,8 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
static int read_tree_some(struct tree *tree, const char **pathspec)
{
- int newfd;
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
- newfd = hold_locked_index(lock_file, 1);
- read_cache();
-
read_tree_recursive(tree, "", 0, 0, pathspec, update_some);
- if (write_cache(newfd, active_cache, active_nr) ||
- commit_locked_index(lock_file))
- die("unable to write new index file");
-
/* update the index with the given tree's info
* for all args, expanding wildcards, and exit
* with any non-zero return code.
@@ -85,7 +76,7 @@ static int read_tree_some(struct tree *tree, const char **pathspec)
return 0;
}
-static int checkout_paths(const char **pathspec)
+static int checkout_paths(struct tree *source_tree, const char **pathspec)
{
int pos;
struct checkout state;
@@ -94,6 +85,15 @@ static int checkout_paths(const char **pathspec)
int flag;
struct commit *head;
+ int newfd;
+ struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+
+ newfd = hold_locked_index(lock_file, 1);
+ read_cache();
+
+ if (source_tree)
+ read_tree_some(source_tree, pathspec);
+
for (pos = 0; pathspec[pos]; pos++)
;
ps_matched = xcalloc(1, pos);
@@ -116,6 +116,10 @@ static int checkout_paths(const char **pathspec)
}
}
+ if (write_cache(newfd, active_cache, active_nr) ||
+ commit_locked_index(lock_file))
+ die("unable to write new index file");
+
resolve_ref("HEAD", rev, 0, &flag);
head = lookup_commit_reference_gently(rev, 1);
@@ -480,11 +484,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
return post_checkout_hook(old.commit, new->commit, 1);
}
-static int git_checkout_config(const char *var, const char *value)
-{
- return git_default_config(var, value);
-}
-
int cmd_checkout(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
@@ -506,7 +505,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
memset(&opts, 0, sizeof(opts));
memset(&new, 0, sizeof(new));
- git_config(git_checkout_config);
+ git_config(git_default_config);
opts.track = git_branch_track;
@@ -558,11 +557,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
}
}
- if (source_tree)
- read_tree_some(source_tree, pathspec);
- else
- read_cache();
- return checkout_paths(pathspec);
+ return checkout_paths(source_tree, pathspec);
}
if (new.name && !new.commit) {
diff --git a/builtin-describe.c b/builtin-describe.c
index 05e309f5a..7a5ab012b 100644
--- a/builtin-describe.c
+++ b/builtin-describe.c
@@ -17,12 +17,15 @@ static const char * const describe_usage[] = {
static int debug; /* Display lots of verbose info */
static int all; /* Default to annotated tags only */
static int tags; /* But allow any tags if --tags is specified */
+static int longformat;
static int abbrev = DEFAULT_ABBREV;
static int max_candidates = 10;
const char *pattern = NULL;
struct commit_name {
+ struct tag *tag;
int prio; /* annotated tag = 2, tag = 1, head = 0 */
+ unsigned char sha1[20];
char path[FLEX_ARRAY]; /* more */
};
static const char *prio_names[] = {
@@ -31,14 +34,17 @@ static const char *prio_names[] = {
static void add_to_known_names(const char *path,
struct commit *commit,
- int prio)
+ int prio,
+ const unsigned char *sha1)
{
struct commit_name *e = commit->util;
if (!e || e->prio < prio) {
size_t len = strlen(path)+1;
free(e);
e = xmalloc(sizeof(struct commit_name) + len);
+ e->tag = NULL;
e->prio = prio;
+ hashcpy(e->sha1, sha1);
memcpy(e->path, path, len);
commit->util = e;
}
@@ -89,7 +95,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
if (!tags && prio < 2)
return 0;
}
- add_to_known_names(all ? path + 5 : path + 10, commit, prio);
+ add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1);
return 0;
}
@@ -146,6 +152,27 @@ static unsigned long finish_depth_computation(
return seen_commits;
}
+static void display_name(struct commit_name *n)
+{
+ if (n->prio == 2 && !n->tag) {
+ n->tag = lookup_tag(n->sha1);
+ if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
+ die("annotated tag %s not available", n->path);
+ if (strcmp(n->tag->tag, n->path))
+ warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
+ }
+
+ if (n->tag)
+ printf("%s", n->tag->tag);
+ else
+ printf("%s", n->path);
+}
+
+static void show_suffix(int depth, const unsigned char *sha1)
+{
+ printf("-%d-g%s", depth, find_unique_abbrev(sha1, abbrev));
+}
+
static void describe(const char *arg, int last_one)
{
unsigned char sha1[20];
@@ -170,7 +197,13 @@ static void describe(const char *arg, int last_one)
n = cmit->util;
if (n) {
- printf("%s\n", n->path);
+ /*
+ * Exact match to an existing ref.
+ */
+ display_name(n);
+ if (longformat)
+ show_suffix(0, n->tag->tagged->sha1);
+ printf("\n");
return;
}
@@ -252,12 +285,11 @@ static void describe(const char *arg, int last_one)
sha1_to_hex(gave_up_on->object.sha1));
}
}
- if (abbrev == 0)
- printf("%s\n", all_matches[0].name->path );
- else
- printf("%s-%d-g%s\n", all_matches[0].name->path,
- all_matches[0].depth,
- find_unique_abbrev(cmit->object.sha1, abbrev));
+
+ display_name(all_matches[0].name);
+ if (abbrev)
+ show_suffix(all_matches[0].depth, cmit->object.sha1);
+ printf("\n");
if (!last_one)
clear_commit_marks(cmit, -1);
@@ -271,6 +303,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN(0, "debug", &debug, "debug search strategy on stderr"),
OPT_BOOLEAN(0, "all", &all, "use any ref in .git/refs"),
OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"),
+ OPT_BOOLEAN(0, "long", &longformat, "always use long format"),
OPT__ABBREV(&abbrev),
OPT_SET_INT(0, "exact-match", &max_candidates,
"only output exact matches", 0),
@@ -289,6 +322,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
save_commit_buffer = 0;
+ if (longformat && abbrev == 0)
+ die("--long is incompatible with --abbrev=0");
+
if (contains) {
const char **args = xmalloc((6 + argc) * sizeof(char*));
int i = 0;
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 5ea48ca7d..29b38e465 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -41,7 +41,8 @@ static void rev_list_push(struct commit *commit, int mark)
commit->object.flags |= mark;
if (!(commit->object.parsed))
- parse_commit(commit);
+ if (parse_commit(commit))
+ return;
insert_by_date(commit, &rev_list);
@@ -83,7 +84,8 @@ static void mark_common(struct commit *commit,
if (!ancestors_only && !(o->flags & POPPED))
non_common_revs--;
if (!o->parsed && !dont_parse)
- parse_commit(commit);
+ if (parse_commit(commit))
+ return;
for (parents = commit->parents;
parents;
@@ -103,20 +105,20 @@ static const unsigned char* get_rev(void)
while (commit == NULL) {
unsigned int mark;
- struct commit_list* parents;
+ struct commit_list *parents = NULL;
if (rev_list == NULL || non_common_revs == 0)
return NULL;
commit = rev_list->item;
if (!(commit->object.parsed))
- parse_commit(commit);
+ if (!parse_commit(commit))
+ parents = commit->parents;
+
commit->object.flags |= POPPED;
if (!(commit->object.flags & COMMON))
non_common_revs--;
- parents = commit->parents;
-
if (commit->object.flags & COMMON) {
/* do not send "have", and ignore ancestors */
commit = NULL;
@@ -212,7 +214,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
if (!lookup_object(sha1))
die("object not found: %s", line);
/* make sure that it is parsed as shallow */
- parse_object(sha1);
+ if (!parse_object(sha1))
+ die("error in object: %s", line);
if (unregister_shallow(sha1))
die("no shallow found: %s", line);
continue;
@@ -386,7 +389,6 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
int retval;
unsigned long cutoff = 0;
- track_object_refs = 0;
save_commit_buffer = 0;
for (ref = *refs; ref; ref = ref->next) {
diff --git a/builtin-fsck.c b/builtin-fsck.c
index cc7524be8..78a6e1ff7 100644
--- a/builtin-fsck.c
+++ b/builtin-fsck.c
@@ -8,6 +8,7 @@
#include "pack.h"
#include "cache-tree.h"
#include "tree-walk.h"
+#include "fsck.h"
#include "parse-options.h"
#define REACHABLE 0x0001
@@ -54,13 +55,75 @@ static int objerror(struct object *obj, const char *err, ...)
return -1;
}
-static int objwarning(struct object *obj, const char *err, ...)
+static int fsck_error_func(struct object *obj, int type, const char *err, ...)
{
va_list params;
va_start(params, err);
- objreport(obj, "warning", err, params);
+ objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params);
va_end(params);
- return -1;
+ return (type == FSCK_WARN) ? 0 : 1;
+}
+
+static int mark_object(struct object *obj, int type, void *data)
+{
+ struct tree *tree = NULL;
+ struct object *parent = data;
+ int result;
+
+ if (!obj) {
+ printf("broken link from %7s %s\n",
+ typename(parent->type), sha1_to_hex(parent->sha1));
+ printf("broken link from %7s %s\n",
+ (type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
+ errors_found |= ERROR_REACHABLE;
+ return 1;
+ }
+
+ if (type != OBJ_ANY && obj->type != type)
+ objerror(parent, "wrong object type in link");
+
+ if (obj->flags & REACHABLE)
+ return 0;
+ obj->flags |= REACHABLE;
+ if (!obj->parsed) {
+ if (parent && !has_sha1_file(obj->sha1)) {
+ printf("broken link from %7s %s\n",
+ typename(parent->type), sha1_to_hex(parent->sha1));
+ printf(" to %7s %s\n",
+ typename(obj->type), sha1_to_hex(obj->sha1));
+ errors_found |= ERROR_REACHABLE;
+ }
+ return 1;
+ }
+
+ if (obj->type == OBJ_TREE) {
+ obj->parsed = 0;
+ tree = (struct tree *)obj;
+ if (parse_tree(tree) < 0)
+ return 1; /* error already displayed */
+ }
+ result = fsck_walk(obj, mark_object, obj);
+ if (tree) {
+ free(tree->buffer);
+ tree->buffer = NULL;
+ }
+ if (result < 0)
+ result = 1;
+
+ return result;
+}
+
+static void mark_object_reachable(struct object *obj)
+{
+ mark_object(obj, OBJ_ANY, 0);
+}
+
+static int mark_used(struct object *obj, int type, void *data)
+{
+ if (!obj)
+ return 1;
+ obj->used = 1;
+ return 0;
}
/*
@@ -68,8 +131,6 @@ static int objwarning(struct object *obj, const char *err, ...)
*/
static void check_reachable_object(struct object *obj)
{
- const struct object_refs *refs;
-
/*
* We obviously want the object to be parsed,
* except if it was in a pack-file and we didn't
@@ -82,25 +143,6 @@ static void check_reachable_object(struct object *obj)
errors_found |= ERROR_REACHABLE;
return;
}
-
- /*
- * Check that everything that we try to reference is also good.
- */
- refs = lookup_object_refs(obj);
- if (refs) {
- unsigned j;
- for (j = 0; j < refs->count; j++) {
- struct object *ref = refs->ref[j];
- if (ref->parsed ||
- (has_sha1_file(ref->sha1)))
- continue;
- printf("broken link from %7s %s\n",
- typename(obj->type), sha1_to_hex(obj->sha1));
- printf(" to %7s %s\n",
- typename(ref->type), sha1_to_hex(ref->sha1));
- errors_found |= ERROR_REACHABLE;
- }
- }
}
/*
@@ -204,230 +246,56 @@ static void check_connectivity(void)
}
}
-/*
- * The entries in a tree are ordered in the _path_ order,
- * which means that a directory entry is ordered by adding
- * a slash to the end of it.
- *
- * So a directory called "a" is ordered _after_ a file
- * called "a.c", because "a/" sorts after "a.c".
- */
-#define TREE_UNORDERED (-1)
-#define TREE_HAS_DUPS (-2)
-
-static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
+static int fsck_sha1(const unsigned char *sha1)
{
- int len1 = strlen(name1);
- int len2 = strlen(name2);
- int len = len1 < len2 ? len1 : len2;
- unsigned char c1, c2;
- int cmp;
-
- cmp = memcmp(name1, name2, len);
- if (cmp < 0)
+ struct object *obj = parse_object(sha1);
+ if (!obj) {
+ errors_found |= ERROR_OBJECT;
+ return error("%s: object corrupt or missing",
+ sha1_to_hex(sha1));
+ }
+ if (obj->flags & SEEN)
return 0;
- if (cmp > 0)
- return TREE_UNORDERED;
-
- /*
- * Ok, the first <len> characters are the same.
- * Now we need to order the next one, but turn
- * a '\0' into a '/' for a directory entry.
- */
- c1 = name1[len];
- c2 = name2[len];
- if (!c1 && !c2)
- /*
- * git-write-tree used to write out a nonsense tree that has
- * entries with the same name, one blob and one tree. Make
- * sure we do not have duplicate entries.
- */
- return TREE_HAS_DUPS;
- if (!c1 && S_ISDIR(mode1))
- c1 = '/';
- if (!c2 && S_ISDIR(mode2))
- c2 = '/';
- return c1 < c2 ? 0 : TREE_UNORDERED;
-}
-
-static int fsck_tree(struct tree *item)
-{
- int retval;
- int has_full_path = 0;
- int has_empty_name = 0;
- int has_zero_pad = 0;
- int has_bad_modes = 0;
- int has_dup_entries = 0;
- int not_properly_sorted = 0;
- struct tree_desc desc;
- unsigned o_mode;
- const char *o_name;
- const unsigned char *o_sha1;
+ obj->flags |= SEEN;
if (verbose)
- fprintf(stderr, "Checking tree %s\n",
- sha1_to_hex(item->object.sha1));
-
- init_tree_desc(&desc, item->buffer, item->size);
-
- o_mode = 0;
- o_name = NULL;
- o_sha1 = NULL;
- while (desc.size) {
- unsigned mode;
- const char *name;
- const unsigned char *sha1;
-
- sha1 = tree_entry_extract(&desc, &name, &mode);
-
- if (strchr(name, '/'))
- has_full_path = 1;
- if (!*name)
- has_empty_name = 1;
- has_zero_pad |= *(char *)desc.buffer == '0';
- update_tree_entry(&desc);
-
- switch (mode) {
- /*
- * Standard modes..
- */
- case S_IFREG | 0755:
- case S_IFREG | 0644:
- case S_IFLNK:
- case S_IFDIR:
- case S_IFGITLINK:
- break;
- /*
- * This is nonstandard, but we had a few of these
- * early on when we honored the full set of mode
- * bits..
- */
- case S_IFREG | 0664:
- if (!check_strict)
- break;
- default:
- has_bad_modes = 1;
- }
+ fprintf(stderr, "Checking %s %s\n",
+ typename(obj->type), sha1_to_hex(obj->sha1));
- if (o_name) {
- switch (verify_ordered(o_mode, o_name, mode, name)) {
- case TREE_UNORDERED:
- not_properly_sorted = 1;
- break;
- case TREE_HAS_DUPS:
- has_dup_entries = 1;
- break;
- default:
- break;
- }
- }
+ if (fsck_walk(obj, mark_used, 0))
+ objerror(obj, "broken links");
+ if (fsck_object(obj, check_strict, fsck_error_func))
+ return -1;
- o_mode = mode;
- o_name = name;
- o_sha1 = sha1;
- }
- free(item->buffer);
- item->buffer = NULL;
+ if (obj->type == OBJ_TREE) {
+ struct tree *item = (struct tree *) obj;
- retval = 0;
- if (has_full_path) {
- objwarning(&item->object, "contains full pathnames");
+ free(item->buffer);
+ item->buffer = NULL;
}
- if (has_empty_name) {
- objwarning(&item->object, "contains empty pathname");
- }
- if (has_zero_pad) {
- objwarning(&item->object, "contains zero-padded file modes");
- }
- if (has_bad_modes) {
- objwarning(&item->object, "contains bad file modes");
- }
- if (has_dup_entries) {
- retval = objerror(&item->object, "contains duplicate file entries");
- }
- if (not_properly_sorted) {
- retval = objerror(&item->object, "not properly sorted");
- }
- return retval;
-}
-static int fsck_commit(struct commit *commit)
-{
- char *buffer = commit->buffer;
- unsigned char tree_sha1[20], sha1[20];
+ if (obj->type == OBJ_COMMIT) {
+ struct commit *commit = (struct commit *) obj;
- if (verbose)
- fprintf(stderr, "Checking commit %s\n",
- sha1_to_hex(commit->object.sha1));
-
- if (!commit->date)
- return objerror(&commit->object, "invalid author/committer line");
-
- if (memcmp(buffer, "tree ", 5))
- return objerror(&commit->object, "invalid format - expected 'tree' line");
- if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
- return objerror(&commit->object, "invalid 'tree' line format - bad sha1");
- buffer += 46;
- while (!memcmp(buffer, "parent ", 7)) {
- if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
- return objerror(&commit->object, "invalid 'parent' line format - bad sha1");
- buffer += 48;
- }
- if (memcmp(buffer, "author ", 7))
- return objerror(&commit->object, "invalid format - expected 'author' line");
- free(commit->buffer);
- commit->buffer = NULL;
- if (!commit->tree)
- return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
- if (!commit->parents && show_root)
- printf("root %s\n", sha1_to_hex(commit->object.sha1));
- return 0;
-}
+ free(commit->buffer);
+ commit->buffer = NULL;
-static int fsck_tag(struct tag *tag)
-{
- struct object *tagged = tag->tagged;
+ if (!commit->parents && show_root)
+ printf("root %s\n", sha1_to_hex(commit->object.sha1));
+ }
- if (verbose)
- fprintf(stderr, "Checking tag %s\n",
- sha1_to_hex(tag->object.sha1));
+ if (obj->type == OBJ_TAG) {
+ struct tag *tag = (struct tag *) obj;
- if (!tagged) {
- return objerror(&tag->object, "could not load tagged object");
+ if (show_tags && tag->tagged) {
+ printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1));
+ printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
+ }
}
- if (!show_tags)
- return 0;
- printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
- printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
return 0;
}
-static int fsck_sha1(const unsigned char *sha1)
-{
- struct object *obj = parse_object(sha1);
- if (!obj) {
- errors_found |= ERROR_OBJECT;
- return error("%s: object corrupt or missing",
- sha1_to_hex(sha1));
- }
- if (obj->flags & SEEN)
- return 0;
- obj->flags |= SEEN;
- if (obj->type == OBJ_BLOB)
- return 0;
- if (obj->type == OBJ_TREE)
- return fsck_tree((struct tree *) obj);
- if (obj->type == OBJ_COMMIT)
- return fsck_commit((struct commit *) obj);
- if (obj->type == OBJ_TAG)
- return fsck_tag((struct tag *) obj);
-
- /* By now, parse_object() would've returned NULL instead. */
- return objerror(obj, "unknown type '%d' (internal fsck error)",
- obj->type);
-}
-
/*
* This is the sorting chunk size: make it reasonably
* big so that we can sort well..
@@ -538,13 +406,13 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
obj = lookup_object(osha1);
if (obj) {
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
}
}
obj = lookup_object(nsha1);
if (obj) {
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
}
return 0;
}
@@ -574,7 +442,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
error("%s: not a commit", refname);
default_refs++;
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
return 0;
}
@@ -660,7 +528,7 @@ static int fsck_cache_tree(struct cache_tree *it)
sha1_to_hex(it->sha1));
return 1;
}
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
obj->used = 1;
if (obj->type != OBJ_TREE)
err |= objerror(obj, "non-tree in cache-tree");
@@ -693,7 +561,6 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
{
int i, heads;
- track_object_refs = 1;
errors_found = 0;
argc = parse_options(argc, argv, fsck_opts, fsck_usage, 0);
@@ -741,7 +608,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
continue;
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
heads++;
continue;
}
@@ -773,7 +640,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
continue;
obj = &blob->object;
obj->used = 1;
- mark_reachable(obj, REACHABLE);
+ mark_object_reachable(obj);
}
if (active_cache_tree)
fsck_cache_tree(active_cache_tree);
diff --git a/builtin-gc.c b/builtin-gc.c
index ad4a75eed..045bf0e48 100644
--- a/builtin-gc.c
+++ b/builtin-gc.c
@@ -172,12 +172,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
int prune = 0;
int aggressive = 0;
int auto_gc = 0;
+ int quiet = 0;
char buf[80];
struct option builtin_gc_options[] = {
OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects"),
OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
+ OPT_BOOLEAN('q', "quiet", &quiet, "suppress progress reports"),
OPT_END()
};
@@ -197,6 +199,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
append_option(argv_repack, buf, MAX_ADD);
}
}
+ if (quiet)
+ append_option(argv_repack, "-q", MAX_ADD);
if (auto_gc) {
/*
diff --git a/builtin-http-fetch.c b/builtin-http-fetch.c
index 299093ff9..b1f33891c 100644
--- a/builtin-http-fetch.c
+++ b/builtin-http-fetch.c
@@ -59,7 +59,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
url = rewritten_url;
}
- walker = get_http_walker(url);
+ walker = get_http_walker(url, NULL);
walker->get_tree = get_tree;
walker->get_history = get_history;
walker->get_all = get_all;
diff --git a/builtin-log.c b/builtin-log.c
index 836b61ec5..d983cbc7b 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -20,6 +20,7 @@
static int default_show_root = 1;
static const char *fmt_patch_subject_prefix = "PATCH";
+static const char *fmt_pretty;
static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
{
@@ -54,6 +55,8 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
rev->abbrev = DEFAULT_ABBREV;
rev->commit_format = CMIT_FMT_DEFAULT;
+ if (fmt_pretty)
+ rev->commit_format = get_commit_format(fmt_pretty);
rev->verbose_header = 1;
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
rev->show_root_diff = default_show_root;
@@ -221,6 +224,8 @@ static int cmd_log_walk(struct rev_info *rev)
static int git_log_config(const char *var, const char *value)
{
+ if (!strcmp(var, "format.pretty"))
+ return git_config_string(&fmt_pretty, var, value);
if (!strcmp(var, "format.subjectprefix")) {
if (!value)
config_error_nonbool(var);
@@ -647,8 +652,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
int nr, struct commit **list, struct commit *head)
{
const char *committer;
- const char *origin_sha1, *head_sha1;
- const char *argv[7];
+ char *head_sha1;
const char *subject_start = NULL;
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
const char *msg;
@@ -657,6 +661,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct strbuf sb;
int i;
const char *encoding = "utf-8";
+ struct diff_options opts;
if (rev->commit_format != CMIT_FMT_EMAIL)
die("Cover letter needs email format");
@@ -683,6 +688,10 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
strbuf_release(&sb);
shortlog_init(&log);
+ log.wrap_lines = 1;
+ log.wrap = 72;
+ log.in1 = 2;
+ log.in2 = 4;
for (i = 0; i < nr; i++)
shortlog_add_commit(&log, list[i]);
@@ -694,20 +703,17 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
if (!origin)
return;
- origin_sha1 = sha1_to_hex(origin->object.sha1);
+ memcpy(&opts, &rev->diffopt, sizeof(opts));
+ opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
- argv[0] = "diff";
- argv[1] = "--stat";
- argv[2] = "--summary";
- argv[3] = head_sha1;
- argv[4] = "--not";
- argv[5] = origin_sha1;
- argv[6] = "--";
- argv[7] = NULL;
- fflush(stdout);
- run_command_v_opt(argv, RUN_GIT_CMD);
+ diff_setup_done(&opts);
+
+ diff_tree_sha1(origin->tree->object.sha1,
+ head->tree->object.sha1,
+ "", &opts);
+ diffcore_std(&opts);
+ diff_flush(&opts);
- fflush(stdout);
printf("\n");
}
diff --git a/builtin-ls-remote.c b/builtin-ls-remote.c
index 023754986..8907a89d6 100644
--- a/builtin-ls-remote.c
+++ b/builtin-ls-remote.c
@@ -94,11 +94,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
ref = transport_get_remote_refs(transport);
- transport_disconnect(transport);
-
- if (!ref)
+ if (transport_disconnect(transport))
return 1;
-
for ( ; ref; ref = ref->next) {
if (!check_ref_type(ref, flags))
continue;
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 1bba6e6a6..2799e6833 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -8,6 +8,7 @@
#include "tree.h"
#include "delta.h"
#include "pack.h"
+#include "pack-revindex.h"
#include "csum-file.h"
#include "tree-walk.h"
#include "diff.h"
@@ -93,157 +94,11 @@ static int *object_ix;
static int object_ix_hashsz;
/*
- * Pack index for existing packs give us easy access to the offsets into
- * corresponding pack file where each object's data starts, but the entries
- * do not store the size of the compressed representation (uncompressed
- * size is easily available by examining the pack entry header). It is
- * also rather expensive to find the sha1 for an object given its offset.
- *
- * We build a hashtable of existing packs (pack_revindex), and keep reverse
- * index here -- pack index file is sorted by object name mapping to offset;
- * this pack_revindex[].revindex array is a list of offset/index_nr pairs
- * ordered by offset, so if you know the offset of an object, next offset
- * is where its packed representation ends and the index_nr can be used to
- * get the object sha1 from the main index.
- */
-struct revindex_entry {
- off_t offset;
- unsigned int nr;
-};
-struct pack_revindex {
- struct packed_git *p;
- struct revindex_entry *revindex;
-};
-static struct pack_revindex *pack_revindex;
-static int pack_revindex_hashsz;
-
-/*
* stats
*/
static uint32_t written, written_delta;
static uint32_t reused, reused_delta;
-static int pack_revindex_ix(struct packed_git *p)
-{
- unsigned long ui = (unsigned long)p;
- int i;
-
- ui = ui ^ (ui >> 16); /* defeat structure alignment */
- i = (int)(ui % pack_revindex_hashsz);
- while (pack_revindex[i].p) {
- if (pack_revindex[i].p == p)
- return i;
- if (++i == pack_revindex_hashsz)
- i = 0;
- }
- return -1 - i;
-}
-
-static void prepare_pack_ix(void)
-{
- int num;
- struct packed_git *p;
- for (num = 0, p = packed_git; p; p = p->next)
- num++;
- if (!num)
- return;
- pack_revindex_hashsz = num * 11;
- pack_revindex = xcalloc(sizeof(*pack_revindex), pack_revindex_hashsz);
- for (p = packed_git; p; p = p->next) {
- num = pack_revindex_ix(p);
- num = - 1 - num;
- pack_revindex[num].p = p;
- }
- /* revindex elements are lazily initialized */
-}
-
-static int cmp_offset(const void *a_, const void *b_)
-{
- const struct revindex_entry *a = a_;
- const struct revindex_entry *b = b_;
- return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0;
-}
-
-/*
- * Ordered list of offsets of objects in the pack.
- */
-static void prepare_pack_revindex(struct pack_revindex *rix)
-{
- struct packed_git *p = rix->p;
- int num_ent = p->num_objects;
- int i;
- const char *index = p->index_data;
-
- rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
- index += 4 * 256;
-
- if (p->index_version > 1) {
- const uint32_t *off_32 =
- (uint32_t *)(index + 8 + p->num_objects * (20 + 4));
- const uint32_t *off_64 = off_32 + p->num_objects;
- for (i = 0; i < num_ent; i++) {
- uint32_t off = ntohl(*off_32++);
- if (!(off & 0x80000000)) {
- rix->revindex[i].offset = off;
- } else {
- rix->revindex[i].offset =
- ((uint64_t)ntohl(*off_64++)) << 32;
- rix->revindex[i].offset |=
- ntohl(*off_64++);
- }
- rix->revindex[i].nr = i;
- }
- } else {
- for (i = 0; i < num_ent; i++) {
- uint32_t hl = *((uint32_t *)(index + 24 * i));
- rix->revindex[i].offset = ntohl(hl);
- rix->revindex[i].nr = i;
- }
- }
-
- /* This knows the pack format -- the 20-byte trailer
- * follows immediately after the last object data.
- */
- rix->revindex[num_ent].offset = p->pack_size - 20;
- rix->revindex[num_ent].nr = -1;
- qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset);
-}
-
-static struct revindex_entry * find_packed_object(struct packed_git *p,
- off_t ofs)
-{
- int num;
- int lo, hi;
- struct pack_revindex *rix;
- struct revindex_entry *revindex;
- num = pack_revindex_ix(p);
- if (num < 0)
- die("internal error: pack revindex uninitialized");
- rix = &pack_revindex[num];
- if (!rix->revindex)
- prepare_pack_revindex(rix);
- revindex = rix->revindex;
- lo = 0;
- hi = p->num_objects + 1;
- do {
- int mi = (lo + hi) / 2;
- if (revindex[mi].offset == ofs) {
- return revindex + mi;
- }
- else if (ofs < revindex[mi].offset)
- hi = mi;
- else
- lo = mi + 1;
- } while (lo < hi);
- die("internal error: pack revindex corrupt");
-}
-
-static const unsigned char *find_packed_object_name(struct packed_git *p,
- off_t ofs)
-{
- struct revindex_entry *entry = find_packed_object(p, ofs);
- return nth_packed_object_sha1(p, entry->nr);
-}
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
{
@@ -510,7 +365,7 @@ static unsigned long write_object(struct sha1file *f,
}
hdrlen = encode_header(obj_type, entry->size, header);
offset = entry->in_pack_offset;
- revidx = find_packed_object(p, offset);
+ revidx = find_pack_revindex(p, offset);
datalen = revidx[1].offset - offset;
if (!pack_to_stdout && p->index_version > 1 &&
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
@@ -1162,8 +1017,11 @@ static void check_object(struct object_entry *entry)
die("delta base offset out of bound for %s",
sha1_to_hex(entry->idx.sha1));
ofs = entry->in_pack_offset - ofs;
- if (!no_reuse_delta && !entry->preferred_base)
- base_ref = find_packed_object_name(p, ofs);
+ if (!no_reuse_delta && !entry->preferred_base) {
+ struct revindex_entry *revidx;
+ revidx = find_pack_revindex(p, ofs);
+ base_ref = nth_packed_object_sha1(p, revidx->nr);
+ }
entry->in_pack_header_size = used + used_0;
break;
}
@@ -1240,9 +1098,11 @@ static void get_object_details(void)
sorted_by_offset[i] = objects + i;
qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
- prepare_pack_ix();
+ init_pack_revindex();
+
for (i = 0; i < nr_objects; i++)
check_object(sorted_by_offset[i]);
+
free(sorted_by_offset);
}
@@ -2013,7 +1873,6 @@ static void get_object_list(int ac, const char **av)
init_revisions(&revs, NULL);
save_commit_buffer = 0;
- track_object_refs = 0;
setup_revisions(ac, av, &revs, NULL);
while (fgets(line, sizeof(line), stdin) != NULL) {
diff --git a/builtin-reset.c b/builtin-reset.c
index af0037ec6..bb3e19240 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -63,14 +63,10 @@ static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
static void print_new_head_line(struct commit *commit)
{
- const char *hex, *dots = "...", *body;
+ const char *hex, *body;
hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
- if (!hex) {
- hex = sha1_to_hex(commit->object.sha1);
- dots = "";
- }
- printf("HEAD is now at %s%s", hex, dots);
+ printf("HEAD is now at %s", hex);
body = strstr(commit->buffer, "\n\n");
if (body) {
const char *eol;
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 6f7d5f821..d0a141692 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -25,6 +25,9 @@ static const char rev_list_usage[] =
" --no-merges\n"
" --remove-empty\n"
" --all\n"
+" --branches\n"
+" --tags\n"
+" --remotes\n"
" --stdin\n"
" --quiet\n"
" ordering output:\n"
@@ -607,7 +610,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
usage(rev_list_usage);
save_commit_buffer = revs.verbose_header || revs.grep_filter;
- track_object_refs = 0;
if (bisect_list)
revs.limited = 1;
diff --git a/builtin-revert.c b/builtin-revert.c
index b6dee6a56..607a2f033 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -9,6 +9,8 @@
#include "utf8.h"
#include "parse-options.h"
#include "cache-tree.h"
+#include "diff.h"
+#include "revision.h"
/*
* This implements the builtins revert and cherry-pick.
@@ -246,6 +248,17 @@ static char *help_msg(const unsigned char *sha1)
return helpbuf;
}
+static int index_is_dirty(void)
+{
+ struct rev_info rev;
+ init_revisions(&rev, NULL);
+ setup_revisions(0, NULL, &rev, "HEAD");
+ DIFF_OPT_SET(&rev.diffopt, QUIET);
+ DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
+ run_diff_index(&rev, 1);
+ return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
+}
+
static int revert_or_cherry_pick(int argc, const char **argv)
{
unsigned char head[20];
@@ -274,12 +287,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)
if (write_cache_as_tree(head, 0, NULL))
die ("Your index file is unmerged.");
} else {
- struct wt_status s;
-
if (get_sha1("HEAD", head))
die ("You do not have a valid HEAD");
- wt_status_prepare(&s);
- if (s.commitable)
+ if (read_cache() < 0)
+ die("could not read the index");
+ if (index_is_dirty())
die ("Dirty index: cannot %s", me);
discard_cache();
}
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index b0cfae83f..930e0fb3f 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -264,9 +264,7 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str
static const char *status_abbrev(unsigned char sha1[20])
{
- const char *abbrev;
- abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
- return abbrev ? abbrev : sha1_to_hex(sha1);
+ return find_unique_abbrev(sha1, DEFAULT_ABBREV);
}
static void print_ok_ref_status(struct ref *ref)
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index 1e51865c5..50e07faa1 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -8,6 +8,7 @@
#include "tag.h"
#include "tree.h"
#include "progress.h"
+#include "decorate.h"
static int dry_run, quiet, recover, has_errors;
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
@@ -18,6 +19,18 @@ static unsigned int offset, len;
static off_t consumed_bytes;
static SHA_CTX ctx;
+struct obj_buffer {
+ char *buffer;
+ unsigned long size;
+};
+
+static struct decoration obj_decorate;
+
+static struct obj_buffer *lookup_object_buffer(struct object *base)
+{
+ return lookup_decoration(&obj_decorate, base);
+}
+
/*
* Make sure at least "min" bytes are available in the buffer, and
* return the pointer to the buffer.
@@ -189,6 +202,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
void *delta_data, *base;
unsigned long base_size;
unsigned char base_sha1[20];
+ struct object *obj;
if (type == OBJ_REF_DELTA) {
hashcpy(base_sha1, fill(20));
@@ -252,6 +266,15 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
}
}
+ obj = lookup_object(base_sha1);
+ if (obj) {
+ struct obj_buffer *obj_buf = lookup_object_buffer(obj);
+ if (obj_buf) {
+ resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
+ return;
+ }
+ }
+
base = read_sha1_file(base_sha1, &type, &base_size);
if (!base) {
error("failed to read delta-pack base object %s",
diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c
index 4e31c273f..4958bbbf1 100644
--- a/builtin-verify-pack.c
+++ b/builtin-verify-pack.c
@@ -40,8 +40,8 @@ static int verify_one_pack(const char *path, int verbose)
if (!pack)
return error("packfile %s not found.", arg);
+ install_packed_git(pack);
err = verify_pack(pack, verbose);
- free(pack);
return err;
}
diff --git a/cache.h b/cache.h
index f16d341f5..e23030262 100644
--- a/cache.h
+++ b/cache.h
@@ -274,6 +274,7 @@ enum object_type {
/* 5 for future expansion */
OBJ_OFS_DELTA = 6,
OBJ_REF_DELTA = 7,
+ OBJ_ANY,
OBJ_MAX,
};
diff --git a/commit.c b/commit.c
index 22ce77686..94d5b3d26 100644
--- a/commit.c
+++ b/commit.c
@@ -193,7 +193,7 @@ static void prepare_commit_graft(void)
commit_graft_prepared = 1;
}
-static struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
+struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
{
int pos;
prepare_commit_graft();
@@ -290,17 +290,6 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
}
item->date = parse_commit_date(bufptr, tail);
- if (track_object_refs) {
- unsigned i = 0;
- struct commit_list *p;
- struct object_refs *refs = alloc_object_refs(n_refs);
- if (item->tree)
- refs->ref[i++] = &item->tree->object;
- for (p = item->parents; p; p = p->next)
- refs->ref[i++] = &p->item->object;
- set_object_refs(&item->object, refs);
- }
-
return 0;
}
diff --git a/commit.h b/commit.h
index 80d65b96d..a1e959142 100644
--- a/commit.h
+++ b/commit.h
@@ -116,6 +116,7 @@ struct commit_graft {
struct commit_graft *read_graft_line(char *buf, int len);
int register_commit_graft(struct commit_graft *, int);
int read_graft_file(const char *graft_file);
+struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 8f70e1efc..49e6df096 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -506,7 +506,33 @@ _git_bisect ()
_git_branch ()
{
- __gitcomp "$(__git_refs)"
+ local i c=1 only_local_ref="n" has_r="n"
+
+ while [ $c -lt $COMP_CWORD ]; do
+ i="${COMP_WORDS[c]}"
+ case "$i" in
+ -d|-m) only_local_ref="y" ;;
+ -r) has_r="y" ;;
+ esac
+ c=$((++c))
+ done
+
+ case "${COMP_WORDS[COMP_CWORD]}" in
+ --*=*) COMPREPLY=() ;;
+ --*)
+ __gitcomp "
+ --color --no-color --verbose --abbrev= --no-abbrev
+ --track --no-track
+ "
+ ;;
+ *)
+ if [ $only_local_ref = "y" -a $has_r = "n" ]; then
+ __gitcomp "$(__git_heads)"
+ else
+ __gitcomp "$(__git_refs)"
+ fi
+ ;;
+ esac
}
_git_bundle ()
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index cc21e9c68..4fa853fae 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -1299,7 +1299,7 @@ Return the list of files that haven't been handled."
(let (author-name author-email subject date msg)
(with-temp-buffer
(let ((coding-system (git-get-logoutput-coding-system)))
- (git-call-process-env t nil "log" "-1" commit)
+ (git-call-process-env t nil "log" "-1" "--pretty=medium" commit)
(goto-char (point-min))
(when (re-search-forward "^Author: *\\(.*\\) <\\(.*\\)>$" nil t)
(setq author-name (match-string 1))
@@ -1545,7 +1545,7 @@ Commands:
(with-current-buffer buffer
(when (and list-buffers-directory
(string-equal fulldir (expand-file-name list-buffers-directory))
- (string-match "\\*git-status\\*$" (buffer-name buffer)))
+ (eq major-mode 'git-status-mode))
(setq found buffer))))
(setq list (cdr list)))
found))
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index be9660075..650ea3417 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -850,29 +850,32 @@ class P4Sync(Command):
## Should move this out, doesn't use SELF.
def readP4Files(self, files):
+ filesForCommit = []
+ filesToRead = []
+
for f in files:
+ includeFile = True
for val in self.clientSpecDirs:
if f['path'].startswith(val[0]):
- if val[1] > 0:
- f['include'] = True
- else:
- f['include'] = False
+ if val[1] <= 0:
+ includeFile = False
break
- files = [f for f in files
- if f['action'] != 'delete' and
- (f.has_key('include') == False or f['include'] == True)]
+ if includeFile:
+ filesForCommit.append(f)
+ if f['action'] != 'delete':
+ filesToRead.append(f)
- if not files:
- return []
+ filedata = []
+ if len(filesToRead) > 0:
+ filedata = p4CmdList('-x - print',
+ stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
+ for f in filesToRead]),
+ stdin_mode='w+')
- filedata = p4CmdList('-x - print',
- stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
- for f in files]),
- stdin_mode='w+')
- if "p4ExitCode" in filedata[0]:
- die("Problems executing p4. Error: [%d]."
- % (filedata[0]['p4ExitCode']));
+ if "p4ExitCode" in filedata[0]:
+ die("Problems executing p4. Error: [%d]."
+ % (filedata[0]['p4ExitCode']));
j = 0;
contents = {}
@@ -896,10 +899,12 @@ class P4Sync(Command):
contents[stat['depotFile']] = text
- for f in files:
- assert not f.has_key('data')
- f['data'] = contents[f['path']]
- return files
+ for f in filesForCommit:
+ path = f['path']
+ if contents.has_key(path):
+ f['data'] = contents[path]
+
+ return filesForCommit
def commit(self, details, files, branch, branchPrefixes, parent = ""):
epoch = details["time"]
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 77c88ebf1..62a740c48 100644
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -567,7 +567,7 @@ generate_general_email()
echo ""
if [ "$newrev_type" = "commit" ]; then
echo $LOGBEGIN
- git show --no-color --root -s $newrev
+ git show --no-color --root -s --pretty=medium $newrev
echo $LOGEND
else
# What can we do here? The tag marks an object that is not
diff --git a/contrib/stats/packinfo.pl b/contrib/stats/packinfo.pl
index aab501ea0..f4a7b62cd 100755
--- a/contrib/stats/packinfo.pl
+++ b/contrib/stats/packinfo.pl
@@ -93,7 +93,7 @@ my %depths;
my @depths;
while (<STDIN>) {
- my ($sha1, $type, $size, $offset, $depth, $parent) = split(/\s+/, $_);
+ my ($sha1, $type, $size, $space, $offset, $depth, $parent) = split(/\s+/, $_);
next unless ($sha1 =~ /^[0-9a-f]{40}$/);
$depths{$sha1} = $depth || 0;
push(@depths, $depth || 0);
diff --git a/daemon.c b/daemon.c
index 41a60af62..2b4a6f145 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1149,6 +1149,11 @@ int main(int argc, char **argv)
usage(daemon_usage);
}
+ if (log_syslog) {
+ openlog("git-daemon", 0, LOG_DAEMON);
+ set_die_routine(daemon_die);
+ }
+
if (inetd_mode && (group_name || user_name))
die("--user and --group are incompatible with --inetd");
@@ -1176,14 +1181,17 @@ int main(int argc, char **argv)
}
}
- if (log_syslog) {
- openlog("git-daemon", 0, LOG_DAEMON);
- set_die_routine(daemon_die);
- }
-
if (strict_paths && (!ok_paths || !*ok_paths))
die("option --strict-paths requires a whitelist");
+ if (base_path) {
+ struct stat st;
+
+ if (stat(base_path, &st) || !S_ISDIR(st.st_mode))
+ die("base-path '%s' does not exist or "
+ "is not a directory", base_path);
+ }
+
if (inetd_mode) {
struct sockaddr_storage ss;
struct sockaddr *peer = (struct sockaddr *)&ss;
diff --git a/diff-lib.c b/diff-lib.c
index 94b150e83..4581b594d 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -472,22 +472,21 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
static void diff_index_show_file(struct rev_info *revs,
const char *prefix,
struct cache_entry *ce,
- unsigned char *sha1, unsigned int mode)
+ const unsigned char *sha1, unsigned int mode)
{
diff_addremove(&revs->diffopt, prefix[0], mode,
sha1, ce->name, NULL);
}
static int get_stat_data(struct cache_entry *ce,
- unsigned char **sha1p,
+ const unsigned char **sha1p,
unsigned int *modep,
int cached, int match_missing)
{
- unsigned char *sha1 = ce->sha1;
+ const unsigned char *sha1 = ce->sha1;
unsigned int mode = ce->ce_mode;
if (!cached) {
- static unsigned char no_sha1[20];
int changed;
struct stat st;
if (lstat(ce->name, &st) < 0) {
@@ -501,7 +500,7 @@ static int get_stat_data(struct cache_entry *ce,
changed = ce_match_stat(ce, &st, 0);
if (changed) {
mode = ce_mode_from_stat(ce, st.st_mode);
- sha1 = no_sha1;
+ sha1 = null_sha1;
}
}
@@ -514,7 +513,7 @@ static void show_new_file(struct rev_info *revs,
struct cache_entry *new,
int cached, int match_missing)
{
- unsigned char *sha1;
+ const unsigned char *sha1;
unsigned int mode;
/* New file in the index: it might actually be different in
@@ -533,7 +532,7 @@ static int show_modified(struct rev_info *revs,
int cached, int match_missing)
{
unsigned int mode, oldmode;
- unsigned char *sha1;
+ const unsigned char *sha1;
if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
if (report_missing)
diff --git a/diff.c b/diff.c
index ad1616423..00e1590c6 100644
--- a/diff.c
+++ b/diff.c
@@ -2581,8 +2581,6 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len)
return sha1_to_hex(sha1);
abbrev = find_unique_abbrev(sha1, len);
- if (!abbrev)
- return sha1_to_hex(sha1);
abblen = strlen(abbrev);
if (abblen < 37) {
static char hex[41];
@@ -3189,11 +3187,8 @@ static void diffcore_apply_filter(const char *filter)
static int diff_filespec_is_identical(struct diff_filespec *one,
struct diff_filespec *two)
{
- if (S_ISGITLINK(one->mode)) {
- diff_fill_sha1_info(one);
- diff_fill_sha1_info(two);
- return !hashcmp(one->sha1, two->sha1);
- }
+ if (S_ISGITLINK(one->mode))
+ return 0;
if (diff_populate_filespec(one, 0))
return 0;
if (diff_populate_filespec(two, 0))
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 3d377251b..31941bcbb 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -468,10 +468,11 @@ void diffcore_rename(struct diff_options *options)
*/
if (rename_limit <= 0 || rename_limit > 32767)
rename_limit = 32767;
- if (num_create > rename_limit && num_src > rename_limit)
- goto cleanup;
- if (num_create * num_src > rename_limit * rename_limit)
+ if ((num_create > rename_limit && num_src > rename_limit) ||
+ (num_create * num_src > rename_limit * rename_limit)) {
+ warning("too many files, skipping inexact rename detection");
goto cleanup;
+ }
mx = xmalloc(sizeof(*mx) * num_create * num_src);
for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
diff --git a/fast-import.c b/fast-import.c
index 0d3449f2c..7f197d5e3 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -2377,6 +2377,7 @@ int main(int argc, const char **argv)
{
unsigned int i, show_stats = 1;
+ setup_git_directory();
git_config(git_pack_config);
if (!pack_compression_seen && core_compression_seen)
pack_compression_level = core_compression_level;
diff --git a/fsck.c b/fsck.c
new file mode 100644
index 000000000..797e3178a
--- /dev/null
+++ b/fsck.c
@@ -0,0 +1,333 @@
+#include "cache.h"
+#include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "commit.h"
+#include "tag.h"
+#include "fsck.h"
+
+static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
+{
+ struct tree_desc desc;
+ struct name_entry entry;
+ int res = 0;
+
+ if (parse_tree(tree))
+ return -1;
+
+ init_tree_desc(&desc, tree->buffer, tree->size);
+ while (tree_entry(&desc, &entry)) {
+ int result;
+
+ if (S_ISGITLINK(entry.mode))
+ continue;
+ if (S_ISDIR(entry.mode))
+ result = walk(&lookup_tree(entry.sha1)->object, OBJ_TREE, data);
+ else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode))
+ result = walk(&lookup_blob(entry.sha1)->object, OBJ_BLOB, data);
+ else {
+ result = error("in tree %s: entry %s has bad mode %.6o\n",
+ sha1_to_hex(tree->object.sha1), entry.path, entry.mode);
+ }
+ if (result < 0)
+ return result;
+ if (!res)
+ res = result;
+ }
+ return res;
+}
+
+static int fsck_walk_commit(struct commit *commit, fsck_walk_func walk, void *data)
+{
+ struct commit_list *parents;
+ int res;
+ int result;
+
+ if (parse_commit(commit))
+ return -1;
+
+ result = walk((struct object *)commit->tree, OBJ_TREE, data);
+ if (result < 0)
+ return result;
+ res = result;
+
+ parents = commit->parents;
+ while (parents) {
+ result = walk((struct object *)parents->item, OBJ_COMMIT, data);
+ if (result < 0)
+ return result;
+ if (!res)
+ res = result;
+ parents = parents->next;
+ }
+ return res;
+}
+
+static int fsck_walk_tag(struct tag *tag, fsck_walk_func walk, void *data)
+{
+ if (parse_tag(tag))
+ return -1;
+ return walk(tag->tagged, OBJ_ANY, data);
+}
+
+int fsck_walk(struct object *obj, fsck_walk_func walk, void *data)
+{
+ if (!obj)
+ return -1;
+ switch (obj->type) {
+ case OBJ_BLOB:
+ return 0;
+ case OBJ_TREE:
+ return fsck_walk_tree((struct tree *)obj, walk, data);
+ case OBJ_COMMIT:
+ return fsck_walk_commit((struct commit *)obj, walk, data);
+ case OBJ_TAG:
+ return fsck_walk_tag((struct tag *)obj, walk, data);
+ default:
+ error("Unknown object type for %s", sha1_to_hex(obj->sha1));
+ return -1;
+ }
+}
+
+/*
+ * The entries in a tree are ordered in the _path_ order,
+ * which means that a directory entry is ordered by adding
+ * a slash to the end of it.
+ *
+ * So a directory called "a" is ordered _after_ a file
+ * called "a.c", because "a/" sorts after "a.c".
+ */
+#define TREE_UNORDERED (-1)
+#define TREE_HAS_DUPS (-2)
+
+static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
+{
+ int len1 = strlen(name1);
+ int len2 = strlen(name2);
+ int len = len1 < len2 ? len1 : len2;
+ unsigned char c1, c2;
+ int cmp;
+
+ cmp = memcmp(name1, name2, len);
+ if (cmp < 0)
+ return 0;
+ if (cmp > 0)
+ return TREE_UNORDERED;
+
+ /*
+ * Ok, the first <len> characters are the same.
+ * Now we need to order the next one, but turn
+ * a '\0' into a '/' for a directory entry.
+ */
+ c1 = name1[len];
+ c2 = name2[len];
+ if (!c1 && !c2)
+ /*
+ * git-write-tree used to write out a nonsense tree that has
+ * entries with the same name, one blob and one tree. Make
+ * sure we do not have duplicate entries.
+ */
+ return TREE_HAS_DUPS;
+ if (!c1 && S_ISDIR(mode1))
+ c1 = '/';
+ if (!c2 && S_ISDIR(mode2))
+ c2 = '/';
+ return c1 < c2 ? 0 : TREE_UNORDERED;
+}
+
+static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
+{
+ int retval;
+ int has_full_path = 0;
+ int has_empty_name = 0;
+ int has_zero_pad = 0;
+ int has_bad_modes = 0;
+ int has_dup_entries = 0;
+ int not_properly_sorted = 0;
+ struct tree_desc desc;
+ unsigned o_mode;
+ const char *o_name;
+ const unsigned char *o_sha1;
+
+ init_tree_desc(&desc, item->buffer, item->size);
+
+ o_mode = 0;
+ o_name = NULL;
+ o_sha1 = NULL;
+
+ while (desc.size) {
+ unsigned mode;
+ const char *name;
+ const unsigned char *sha1;
+
+ sha1 = tree_entry_extract(&desc, &name, &mode);
+
+ if (strchr(name, '/'))
+ has_full_path = 1;
+ if (!*name)
+ has_empty_name = 1;
+ has_zero_pad |= *(char *)desc.buffer == '0';
+ update_tree_entry(&desc);
+
+ switch (mode) {
+ /*
+ * Standard modes..
+ */
+ case S_IFREG | 0755:
+ case S_IFREG | 0644:
+ case S_IFLNK:
+ case S_IFDIR:
+ case S_IFGITLINK:
+ break;
+ /*
+ * This is nonstandard, but we had a few of these
+ * early on when we honored the full set of mode
+ * bits..
+ */
+ case S_IFREG | 0664:
+ if (!strict)
+ break;
+ default:
+ has_bad_modes = 1;
+ }
+
+ if (o_name) {
+ switch (verify_ordered(o_mode, o_name, mode, name)) {
+ case TREE_UNORDERED:
+ not_properly_sorted = 1;
+ break;
+ case TREE_HAS_DUPS:
+ has_dup_entries = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ o_mode = mode;
+ o_name = name;
+ o_sha1 = sha1;
+ }
+
+ retval = 0;
+ if (has_full_path)
+ retval += error_func(&item->object, FSCK_WARN, "contains full pathnames");
+ if (has_empty_name)
+ retval += error_func(&item->object, FSCK_WARN, "contains empty pathname");
+ if (has_zero_pad)
+ retval += error_func(&item->object, FSCK_WARN, "contains zero-padded file modes");
+ if (has_bad_modes)
+ retval += error_func(&item->object, FSCK_WARN, "contains bad file modes");
+ if (has_dup_entries)
+ retval += error_func(&item->object, FSCK_ERROR, "contains duplicate file entries");
+ if (not_properly_sorted)
+ retval += error_func(&item->object, FSCK_ERROR, "not properly sorted");
+ return retval;
+}
+
+static int fsck_commit(struct commit *commit, fsck_error error_func)
+{
+ char *buffer = commit->buffer;
+ unsigned char tree_sha1[20], sha1[20];
+ struct commit_graft *graft;
+ int parents = 0;
+
+ if (!commit->date)
+ return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line");
+
+ if (memcmp(buffer, "tree ", 5))
+ return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line");
+ if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
+ return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1");
+ buffer += 46;
+ while (!memcmp(buffer, "parent ", 7)) {
+ if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
+ return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1");
+ buffer += 48;
+ parents++;
+ }
+ graft = lookup_commit_graft(commit->object.sha1);
+ if (graft) {
+ struct commit_list *p = commit->parents;
+ parents = 0;
+ while (p) {
+ p = p->next;
+ parents++;
+ }
+ if (graft->nr_parent == -1 && !parents)
+ ; /* shallow commit */
+ else if (graft->nr_parent != parents)
+ return error_func(&commit->object, FSCK_ERROR, "graft objects missing");
+ } else {
+ struct commit_list *p = commit->parents;
+ while (p && parents) {
+ p = p->next;
+ parents--;
+ }
+ if (p || parents)
+ return error_func(&commit->object, FSCK_ERROR, "parent objects missing");
+ }
+ if (memcmp(buffer, "author ", 7))
+ return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line");
+ if (!commit->tree)
+ return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
+
+ return 0;
+}
+
+static int fsck_tag(struct tag *tag, fsck_error error_func)
+{
+ struct object *tagged = tag->tagged;
+
+ if (!tagged)
+ return error_func(&tag->object, FSCK_ERROR, "could not load tagged object");
+ return 0;
+}
+
+int fsck_object(struct object *obj, int strict, fsck_error error_func)
+{
+ if (!obj)
+ return error_func(obj, FSCK_ERROR, "no valid object to fsck");
+
+ if (obj->type == OBJ_BLOB)
+ return 0;
+ if (obj->type == OBJ_TREE)
+ return fsck_tree((struct tree *) obj, strict, error_func);
+ if (obj->type == OBJ_COMMIT)
+ return fsck_commit((struct commit *) obj, error_func);
+ if (obj->type == OBJ_TAG)
+ return fsck_tag((struct tag *) obj, error_func);
+
+ return error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)",
+ obj->type);
+}
+
+int fsck_error_function(struct object *obj, int type, const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+ struct strbuf sb;
+
+ strbuf_init(&sb, 0);
+ strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)");
+
+ va_start(ap, fmt);
+ len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
+ va_end(ap);
+
+ if (len < 0)
+ len = 0;
+ if (len >= strbuf_avail(&sb)) {
+ strbuf_grow(&sb, len + 2);
+ va_start(ap, fmt);
+ len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
+ va_end(ap);
+ if (len >= strbuf_avail(&sb))
+ die("this should not happen, your snprintf is broken");
+ }
+
+ error(sb.buf);
+ strbuf_release(&sb);
+ return 1;
+}
diff --git a/fsck.h b/fsck.h
new file mode 100644
index 000000000..990ee0233
--- /dev/null
+++ b/fsck.h
@@ -0,0 +1,32 @@
+#ifndef GIT_FSCK_H
+#define GIT_FSCK_H
+
+#define FSCK_ERROR 1
+#define FSCK_WARN 2
+
+/*
+ * callback function for fsck_walk
+ * type is the expected type of the object or OBJ_ANY
+ * the return value is:
+ * 0 everything OK
+ * <0 error signaled and abort
+ * >0 error signaled and do not abort
+ */
+typedef int (*fsck_walk_func)(struct object *obj, int type, void *data);
+
+/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
+typedef int (*fsck_error)(struct object *obj, int type, const char *err, ...);
+
+int fsck_error_function(struct object *obj, int type, const char *fmt, ...);
+
+/* descend in all linked child objects
+ * the return value is:
+ * -1 error in processing the object
+ * <0 return value of the callback, which lead to an abort
+ * >0 return value of the first sigaled error >0 (in the case of no other errors)
+ * 0 everything OK
+ */
+int fsck_walk(struct object *obj, fsck_walk_func walk, void *data);
+int fsck_object(struct object *obj, int strict, fsck_error error_func);
+
+#endif
diff --git a/git-am.sh b/git-am.sh
index 2ecebc45a..a2c6fea47 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -2,6 +2,7 @@
#
# Copyright (c) 2005, 2006 Junio C Hamano
+SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
OPTIONS_SPEC="\
git-am [options] <mbox>|<Maildir>...
@@ -25,6 +26,7 @@ skip skip the current patch"
. git-sh-setup
set_reflog_action am
require_work_tree
+cd_to_toplevel
git var GIT_COMMITTER_IDENT >/dev/null || exit
diff --git a/git-clone.sh b/git-clone.sh
index 0d686c3a0..e98112277 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -210,11 +210,28 @@ if base=$(get_repo_base "$repo"); then
then
local=yes
fi
+elif test -f "$repo"
+then
+ case "$repo" in /*) ;; *) repo="$PWD/$repo" ;; esac
+fi
+
+# Decide the directory name of the new repository
+if test -n "$2"
+then
+ dir="$2"
+else
+ # Derive one from the repository name
+ # Try using "humanish" part of source repo if user didn't specify one
+ if test -f "$repo"
+ then
+ # Cloning from a bundle
+ dir=$(echo "$repo" | sed -e 's|/*\.bundle$||' -e 's|.*/||g')
+ else
+ dir=$(echo "$repo" |
+ sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
+ fi
fi
-dir="$2"
-# Try using "humanish" part of source repo if user didn't specify one
-[ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
[ -e "$dir" ] && die "destination directory '$dir' already exists."
[ yes = "$bare" ] && unset GIT_WORK_TREE
[ -n "$GIT_WORK_TREE" ] && [ -e "$GIT_WORK_TREE" ] &&
@@ -364,11 +381,17 @@ yes)
fi
;;
*)
- case "$upload_pack" in
- '') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";;
- *) git-fetch-pack --all -k $quiet "$upload_pack" $depth $no_progress "$repo" ;;
- esac >"$GIT_DIR/CLONE_HEAD" ||
+ if [ -f "$repo" ] ; then
+ git bundle unbundle "$repo" > "$GIT_DIR/CLONE_HEAD" ||
+ die "unbundle from '$repo' failed."
+ else
+ case "$upload_pack" in
+ '') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";;
+ *) git-fetch-pack --all -k \
+ $quiet "$upload_pack" $depth $no_progress "$repo" ;;
+ esac >"$GIT_DIR/CLONE_HEAD" ||
die "fetch-pack from '$repo' failed."
+ fi
;;
esac
;;
diff --git a/git-compat-util.h b/git-compat-util.h
index 2a40703c8..591244351 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -437,4 +437,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
#define qsort git_qsort
#endif
+#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
+# define FORCE_DIR_SET_GID S_ISGID
+#else
+# define FORCE_DIR_SET_GID 0
+#endif
+
#endif
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 951624233..47f116f37 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -15,7 +15,7 @@
use strict;
use warnings;
-use Getopt::Std;
+use Getopt::Long;
use File::Spec;
use File::Temp qw(tempfile tmpnam);
use File::Path qw(mkpath);
@@ -29,7 +29,7 @@ use IPC::Open2;
$SIG{'PIPE'}="IGNORE";
$ENV{'TZ'}="UTC";
-our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r);
+our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r);
my (%conv_author_name, %conv_author_email);
sub usage(;$) {
@@ -112,7 +112,12 @@ sub read_repo_config {
my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:";
read_repo_config($opts);
-getopts($opts) or usage();
+Getopt::Long::Configure( 'no_ignore_case', 'bundling' );
+
+# turn the Getopt::Std specification in a Getopt::Long one,
+# with support for multiple -M options
+GetOptions( map { s/:/=s/; /M/ ? "$_\@" : $_ } split( /(?!:)/, $opts ) )
+ or usage();
usage if $opt_h;
if (@ARGV == 0) {
@@ -164,10 +169,10 @@ if ($#ARGV == 0) {
our @mergerx = ();
if ($opt_m) {
- @mergerx = ( qr/\b(?:from|of|merge|merging|merged) (\w+)/i );
+ @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i );
}
-if ($opt_M) {
- push (@mergerx, qr/$opt_M/);
+if (@opt_M) {
+ push (@mergerx, map { qr/$_/ } @opt_M);
}
# Remember UTC of our starting time
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index afe3d0b7f..7f632af20 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -2556,7 +2556,7 @@ sub update
if ($base) {
my @merged;
# print "want to log between $base $parent \n";
- open(GITLOG, '-|', 'git-log', "$base..$parent")
+ open(GITLOG, '-|', 'git-log', '--pretty=medium', "$base..$parent")
or die "Cannot call git-log: $!";
my $mergedhash;
while (<GITLOG>) {
diff --git a/git-gui/lib/about.tcl b/git-gui/lib/about.tcl
index 47be8eb97..241ab892c 100644
--- a/git-gui/lib/about.tcl
+++ b/git-gui/lib/about.tcl
@@ -41,7 +41,8 @@ proc do_about {} {
append v "Tcl version $tcl_patchLevel"
append v ", Tk version $tk_patchLevel"
}
- if {[info exists ui_comm_spell]} {
+ if {[info exists ui_comm_spell]
+ && [$ui_comm_spell version] ne {}} {
append v "\n"
append v [$ui_comm_spell version]
}
diff --git a/git-gui/lib/error.tcl b/git-gui/lib/error.tcl
index 08a24622c..8c27678e3 100644
--- a/git-gui/lib/error.tcl
+++ b/git-gui/lib/error.tcl
@@ -47,7 +47,7 @@ proc info_popup {msg} {
append title " ([reponame])"
}
tk_messageBox \
- -parent $parent \
+ -parent [_error_parent] \
-icon info \
-type ok \
-title $title \
diff --git a/git-gui/lib/spellcheck.tcl b/git-gui/lib/spellcheck.tcl
index 7f018e400..9be748683 100644
--- a/git-gui/lib/spellcheck.tcl
+++ b/git-gui/lib/spellcheck.tcl
@@ -1,27 +1,31 @@
-# git-gui spellchecking support through aspell
+# git-gui spellchecking support through ispell/aspell
# Copyright (C) 2008 Shawn Pearce
class spellcheck {
-field s_fd {} ; # pipe to aspell
-field s_version ; # aspell version string
-field s_lang ; # current language code
+field s_fd {} ; # pipe to ispell/aspell
+field s_version {} ; # ispell/aspell version string
+field s_lang {} ; # current language code
+field s_prog aspell; # are we actually old ispell?
+field s_failed 0 ; # is $s_prog bogus and not working?
field w_text ; # text widget we are spelling
field w_menu ; # context menu for the widget
field s_menuidx 0 ; # last index of insertion into $w_menu
-field s_i ; # timer registration for _run callbacks
+field s_i {} ; # timer registration for _run callbacks
field s_clear 0 ; # did we erase mispelled tags yet?
field s_seen [list] ; # lines last seen from $w_text in _run
field s_checked [list] ; # lines already checked
-field s_pending [list] ; # [$line $data] sent to aspell
+field s_pending [list] ; # [$line $data] sent to ispell/aspell
field s_suggest ; # array, list of suggestions, keyed by misspelling
constructor init {pipe_fd ui_text ui_menu} {
set w_text $ui_text
set w_menu $ui_menu
+ array unset s_suggest
+ bind_button3 $w_text [cb _popup_suggest %X %Y @%x,%y]
_connect $this $pipe_fd
return $this
}
@@ -33,14 +37,53 @@ method _connect {pipe_fd} {
-translation lf
if {[gets $pipe_fd s_version] <= 0} {
- close $pipe_fd
- error [mc "Not connected to aspell"]
+ if {[catch {close $pipe_fd} err]} {
+
+ # Eh? Is this actually ispell choking on aspell options?
+ #
+ if {$s_prog eq {aspell}
+ && [regexp -nocase {^Usage: } $err]
+ && ![catch {
+ set pipe_fd [open [list | $s_prog -v] r]
+ gets $pipe_fd s_version
+ close $pipe_fd
+ }]
+ && $s_version ne {}} {
+ if {{@(#) } eq [string range $s_version 0 4]} {
+ set s_version [string range $s_version 5 end]
+ }
+ set s_failed 1
+ error_popup [strcat \
+ [mc "Unsupported spell checker"] \
+ ":\n\n$s_version"]
+ set s_version {}
+ return
+ }
+
+ regsub -nocase {^Error: } $err {} err
+ if {$s_fd eq {}} {
+ error_popup [strcat [mc "Spell checking is unavailable"] ":\n\n$err"]
+ } else {
+ error_popup [strcat \
+ [mc "Invalid spell checking configuration"] \
+ ":\n\n$err\n\n" \
+ [mc "Reverting dictionary to %s." $s_lang]]
+ }
+ } else {
+ error_popup [mc "Spell checker silently failed on startup"]
+ }
+ return
}
+
if {{@(#) } ne [string range $s_version 0 4]} {
- close $pipe_fd
- error [strcat [mc "Unrecognized aspell version"] ": $s_version"]
+ catch {close $pipe_fd}
+ error_popup [strcat [mc "Unrecognized spell checker"] ":\n\n$s_version"]
+ return
}
set s_version [string range $s_version 5 end]
+ regexp \
+ {International Ispell Version .* \(but really (Aspell .*?)\)$} \
+ $s_version _junk s_version
puts $pipe_fd ! ; # enable terse mode
puts $pipe_fd {$$cr master} ; # fetch the language
@@ -65,7 +108,6 @@ method _connect {pipe_fd} {
$w_text tag conf misspelled \
-foreground red \
-underline 1
- bind_button3 $w_text [cb _popup_suggest %X %Y @%x,%y]
array unset s_suggest
set s_seen [list]
@@ -75,7 +117,7 @@ method _connect {pipe_fd} {
}
method lang {{n {}}} {
- if {$n ne {} && $s_lang ne $n} {
+ if {$n ne {} && $s_lang ne $n && !$s_failed} {
set spell_cmd [list |]
lappend spell_cmd aspell
lappend spell_cmd --master=$n
@@ -88,7 +130,10 @@ method lang {{n {}}} {
}
method version {} {
- return "$s_version, $s_lang"
+ if {$s_version ne {}} {
+ return "$s_version, $s_lang"
+ }
+ return {}
}
method stop {} {
@@ -333,11 +378,11 @@ method _read {} {
fconfigure $s_fd -block 1
if {[eof $s_fd]} {
if {![catch {close $s_fd} err]} {
- set err [mc "unexpected eof from aspell"]
+ set err [mc "Unexpected EOF from spell checker"]
}
catch {after cancel $s_i}
$w_text tag remove misspelled 1.0 end
- error_popup [strcat "Spell Checker Failed" "\n\n" $err]
+ error_popup [strcat [mc "Spell Checker Failed"] "\n\n" $err]
return
}
fconfigure $s_fd -block 0
diff --git a/git-gui/po/de.po b/git-gui/po/de.po
index d7c38f9c7..e84e1c7e0 100644
--- a/git-gui/po/de.po
+++ b/git-gui/po/de.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git-gui\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-02 10:14+0100\n"
-"PO-Revision-Date: 2008-02-02 10:18+0100\n"
+"POT-Creation-Date: 2008-02-16 21:24+0100\n"
+"PO-Revision-Date: 2008-02-16 21:52+0100\n"
"Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
@@ -653,7 +653,7 @@ msgstr "Lokale Zweige"
#: lib/branch_delete.tcl:52
msgid "Delete Only If Merged Into"
-msgstr "Nur löschen, wenn darin zusammengeführt"
+msgstr "Nur löschen, wenn zusammengeführt nach"
#: lib/branch_delete.tcl:54
msgid "Always (Do not perform merge test.)"
@@ -1292,19 +1292,19 @@ msgstr "Warning: Tcl/Tk unterstützt die Zeichencodierung »%s« nicht."
#: lib/commit.tcl:221
msgid "Calling pre-commit hook..."
-msgstr ""
+msgstr "Aufrufen der Vor-Eintragen-Kontrolle..."
#: lib/commit.tcl:236
msgid "Commit declined by pre-commit hook."
-msgstr ""
+msgstr "Eintragen abgelehnt durch Vor-Eintragen-Kontrolle (»pre-commit hook«)."
#: lib/commit.tcl:259
msgid "Calling commit-msg hook..."
-msgstr ""
+msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle..."
#: lib/commit.tcl:274
msgid "Commit declined by commit-msg hook."
-msgstr ""
+msgstr "Eintragen abgelehnt durch Versionsbeschreibungs-Kontrolle (»commit-message hook«)."
#: lib/commit.tcl:287
msgid "Committing changes..."
@@ -1389,7 +1389,7 @@ msgstr "Festplattenplatz von komprimierten Objekten"
#: lib/database.tcl:48
msgid "Packed objects waiting for pruning"
-msgstr "Komprimierte Objekte, die zum Entfernen vorgesehen sind"
+msgstr "Komprimierte Objekte, die zum Aufräumen vorgesehen sind"
#: lib/database.tcl:49
msgid "Garbage files"
@@ -1622,10 +1622,10 @@ msgstr "%s von %s"
#: lib/merge.tcl:119
#, tcl-format
-msgid "Merging %s and %s"
-msgstr "Zusammenführen von %s und %s"
+msgid "Merging %s and %s..."
+msgstr "Zusammenführen von %s und %s..."
-#: lib/merge.tcl:131
+#: lib/merge.tcl:130
msgid "Merge completed successfully."
msgstr "Zusammenführen erfolgreich abgeschlossen."
@@ -1636,7 +1636,7 @@ msgstr "Zusammenführen fehlgeschlagen. Konfliktauflösung ist notwendig."
#: lib/merge.tcl:158
#, tcl-format
msgid "Merge Into %s"
-msgstr "Zusammenführen in %s"
+msgstr "Zusammenführen in »%s«"
#: lib/merge.tcl:177
msgid "Revision To Merge"
@@ -1741,7 +1741,7 @@ msgstr "Auf Dateiänderungsdatum verlassen"
#: lib/option.tcl:111
msgid "Prune Tracking Branches During Fetch"
-msgstr "Übernahmezweige entfernen während Anforderung"
+msgstr "Übernahmezweige aufräumen während Anforderung"
#: lib/option.tcl:112
msgid "Match Tracking Branches"
@@ -1755,7 +1755,11 @@ msgstr "Anzahl der Kontextzeilen beim Vergleich"
msgid "New Branch Name Template"
msgstr "Namensvorschlag für neue Zweige"
-#: lib/option.tcl:176
+#: lib/option.tcl:191
+msgid "Spelling Dictionary:"
+msgstr "Wörterbuch Rechtschreibprüfung:"
+
+#: lib/option.tcl:215
msgid "Change Font"
msgstr "Schriftart ändern"
@@ -1778,11 +1782,11 @@ msgstr "Optionen konnten nicht gespeichert werden:"
#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
msgid "Delete Remote Branch"
-msgstr "Zweig aus anderem Projektarchiv löschen"
+msgstr "Zweig in anderem Projektarchiv löschen"
#: lib/remote_branch_delete.tcl:47
msgid "From Repository"
-msgstr "Von Projektarchiv"
+msgstr "In Projektarchiv"
#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:123
msgid "Remote:"
@@ -1790,7 +1794,7 @@ msgstr "Anderes Archiv:"
#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:138
msgid "Arbitrary URL:"
-msgstr "Kommunikation mit URL:"
+msgstr "Archiv-URL:"
#: lib/remote_branch_delete.tcl:84
msgid "Branches"
@@ -1798,11 +1802,11 @@ msgstr "Zweige"
#: lib/remote_branch_delete.tcl:109
msgid "Delete Only If"
-msgstr "Löschen, falls"
+msgstr "Nur löschen, wenn"
#: lib/remote_branch_delete.tcl:111
msgid "Merged Into:"
-msgstr "Zusammenführen mit:"
+msgstr "Zusammengeführt mit:"
#: lib/remote_branch_delete.tcl:119
msgid "Always (Do not perform merge checks)"
@@ -1864,7 +1868,7 @@ msgstr "»%s« laden..."
#: lib/remote.tcl:165
msgid "Prune from"
-msgstr "Entfernen von"
+msgstr "Aufräumen von"
#: lib/remote.tcl:170
msgid "Fetch from"
@@ -1882,6 +1886,26 @@ msgstr "Fehler beim Schreiben der Verknüpfung:"
msgid "Cannot write icon:"
msgstr "Fehler beim Erstellen des Icons:"
+#: lib/spellcheck.tcl:37
+msgid "Not connected to aspell"
+msgstr "Keine Verbindung zu »aspell«"
+
+#: lib/spellcheck.tcl:41
+msgid "Unrecognized aspell version"
+msgstr "Unbekannte Version von »aspell«"
+
+#: lib/spellcheck.tcl:135
+msgid "No Suggestions"
+msgstr "Keine Vorschläge"
+
+#: lib/spellcheck.tcl:336
+msgid "Unexpected EOF from aspell"
+msgstr "Unerwartetes EOF von »aspell«"
+
+#: lib/spellcheck.tcl:340
+msgid "Spell Checker Failed"
+msgstr "Rechtschreibprüfung fehlgeschlagen"
+
#: lib/status_bar.tcl:83
#, tcl-format
msgid "%s ... %*i of %*i %s (%3i%%)"
@@ -1900,12 +1924,12 @@ msgstr "Neue Änderungen von »%s« holen"
#: lib/transport.tcl:18
#, tcl-format
msgid "remote prune %s"
-msgstr "Entfernen von »%s« aus anderem Archiv"
+msgstr "Aufräumen von »%s«"
#: lib/transport.tcl:19
#, tcl-format
msgid "Pruning tracking branches deleted from %s"
-msgstr "Übernahmezweige entfernen, die in »%s« gelöscht wurden"
+msgstr "Übernahmezweige aufräumen und entfernen, die in »%s« gelöscht wurden"
#: lib/transport.tcl:25 lib/transport.tcl:71
#, tcl-format
@@ -1928,7 +1952,7 @@ msgstr "Zweige versenden"
#: lib/transport.tcl:103
msgid "Source Branches"
-msgstr "Herkunftszweige"
+msgstr "Lokale Zweige"
#: lib/transport.tcl:120
msgid "Destination Repository"
diff --git a/git-gui/po/git-gui.pot b/git-gui/po/git-gui.pot
index 3f139da6c..2e332849f 100644
--- a/git-gui/po/git-gui.pot
+++ b/git-gui/po/git-gui.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-02-02 10:14+0100\n"
+"POT-Creation-Date: 2008-02-16 21:24+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -1474,10 +1474,10 @@ msgstr ""
#: lib/merge.tcl:119
#, tcl-format
-msgid "Merging %s and %s"
+msgid "Merging %s and %s..."
msgstr ""
-#: lib/merge.tcl:131
+#: lib/merge.tcl:130
msgid "Merge completed successfully."
msgstr ""
@@ -1592,7 +1592,11 @@ msgstr ""
msgid "New Branch Name Template"
msgstr ""
-#: lib/option.tcl:176
+#: lib/option.tcl:191
+msgid "Spelling Dictionary:"
+msgstr ""
+
+#: lib/option.tcl:215
msgid "Change Font"
msgstr ""
@@ -1709,6 +1713,26 @@ msgstr ""
msgid "Cannot write icon:"
msgstr ""
+#: lib/spellcheck.tcl:37
+msgid "Not connected to aspell"
+msgstr ""
+
+#: lib/spellcheck.tcl:41
+msgid "Unrecognized aspell version"
+msgstr ""
+
+#: lib/spellcheck.tcl:135
+msgid "No Suggestions"
+msgstr ""
+
+#: lib/spellcheck.tcl:336
+msgid "Unexpected EOF from aspell"
+msgstr ""
+
+#: lib/spellcheck.tcl:340
+msgid "Spell Checker Failed"
+msgstr ""
+
#: lib/status_bar.tcl:83
#, tcl-format
msgid "%s ... %*i of %*i %s (%3i%%)"
diff --git a/git-gui/po/glossary/de.po b/git-gui/po/glossary/de.po
index 0b33c572b..35764d1d2 100644
--- a/git-gui/po/glossary/de.po
+++ b/git-gui/po/glossary/de.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: git-gui glossary\n"
"POT-Creation-Date: 2008-01-07 21:20+0100\n"
-"PO-Revision-Date: 2008-01-15 20:32+0100\n"
+"PO-Revision-Date: 2008-02-16 21:48+0100\n"
"Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
"Language-Team: German \n"
"MIME-Version: 1.0\n"
@@ -114,7 +114,7 @@ msgstr "Beschreibung (Meldung?, Nachricht?; Source Safe: Kommentar)"
#. "Deletes all stale tracking branches under <name>. These stale branches have already been removed from the remote repository referenced by <name>, but are still locally available in 'remotes/<name>'."
msgid "prune"
-msgstr "entfernen"
+msgstr "aufräumen (entfernen?)"
#. "Pulling a branch means to fetch it and merge it."
msgid "pull"
diff --git a/git-merge.sh b/git-merge.sh
index 1c123a37e..7dbbb1d79 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -37,6 +37,7 @@ use_strategies=
allow_fast_forward=t
allow_trivial_merge=t
+squash= no_commit=
dropsave() {
rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
@@ -70,7 +71,7 @@ finish_up_to_date () {
squash_message () {
echo Squashed commit of the following:
echo
- git log --no-merges ^"$head" $remoteheads
+ git log --no-merges --pretty=medium ^"$head" $remoteheads
}
finish () {
@@ -152,17 +153,21 @@ parse_config () {
--summary)
show_diffstat=t ;;
--squash)
- allow_fast_forward=t squash=t no_commit=t ;;
+ test "$allow_fast_forward" = t ||
+ die "You cannot combine --squash with --no-ff."
+ squash=t no_commit=t ;;
--no-squash)
- allow_fast_forward=t squash= no_commit= ;;
+ squash= no_commit= ;;
--commit)
- allow_fast_forward=t squash= no_commit= ;;
+ no_commit= ;;
--no-commit)
- allow_fast_forward=t squash= no_commit=t ;;
+ no_commit=t ;;
--ff)
- allow_fast_forward=t squash= no_commit= ;;
+ allow_fast_forward=t ;;
--no-ff)
- allow_fast_forward=false squash= no_commit= ;;
+ test "$squash" != t ||
+ die "You cannot combine --squash with --no-ff."
+ allow_fast_forward=f ;;
-s|--strategy)
shift
case " $all_strategies " in
diff --git a/git-mergetool.sh b/git-mergetool.sh
index cbbb70795..5c86f6922 100755
--- a/git-mergetool.sh
+++ b/git-mergetool.sh
@@ -34,7 +34,7 @@ base_present () {
cleanup_temp_files () {
if test "$1" = --save-backup ; then
- mv -- "$BACKUP" "$path.orig"
+ mv -- "$BACKUP" "$MERGED.orig"
rm -f -- "$LOCAL" "$REMOTE" "$BASE"
else
rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
@@ -67,14 +67,14 @@ resolve_symlink_merge () {
read ans
case "$ans" in
[lL]*)
- git checkout-index -f --stage=2 -- "$path"
- git add -- "$path"
+ git checkout-index -f --stage=2 -- "$MERGED"
+ git add -- "$MERGED"
cleanup_temp_files --save-backup
return
;;
[rR]*)
- git checkout-index -f --stage=3 -- "$path"
- git add -- "$path"
+ git checkout-index -f --stage=3 -- "$MERGED"
+ git add -- "$MERGED"
cleanup_temp_files --save-backup
return
;;
@@ -95,12 +95,12 @@ resolve_deleted_merge () {
read ans
case "$ans" in
[mMcC]*)
- git add -- "$path"
+ git add -- "$MERGED"
cleanup_temp_files --save-backup
return
;;
[dD]*)
- git rm -- "$path" > /dev/null
+ git rm -- "$MERGED" > /dev/null
cleanup_temp_files
return
;;
@@ -112,11 +112,11 @@ resolve_deleted_merge () {
}
check_unchanged () {
- if test "$path" -nt "$BACKUP" ; then
+ if test "$MERGED" -nt "$BACKUP" ; then
status=0;
else
while true; do
- echo "$path seems unchanged."
+ echo "$MERGED seems unchanged."
printf "Was the merge successful? [y/n] "
read answer < /dev/tty
case "$answer" in
@@ -127,50 +127,38 @@ check_unchanged () {
fi
}
-save_backup () {
- if test "$status" -eq 0; then
- mv -- "$BACKUP" "$path.orig"
- fi
-}
-
-remove_backup () {
- if test "$status" -eq 0; then
- rm "$BACKUP"
- fi
-}
-
merge_file () {
- path="$1"
+ MERGED="$1"
- f=`git ls-files -u -- "$path"`
+ f=`git ls-files -u -- "$MERGED"`
if test -z "$f" ; then
- if test ! -f "$path" ; then
- echo "$path: file not found"
+ if test ! -f "$MERGED" ; then
+ echo "$MERGED: file not found"
else
- echo "$path: file does not need merging"
+ echo "$MERGED: file does not need merging"
fi
exit 1
fi
- ext="$$$(expr "$path" : '.*\(\.[^/]*\)$')"
- BACKUP="$path.BACKUP.$ext"
- LOCAL="$path.LOCAL.$ext"
- REMOTE="$path.REMOTE.$ext"
- BASE="$path.BASE.$ext"
+ ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
+ BACKUP="$MERGED.BACKUP.$ext"
+ LOCAL="$MERGED.LOCAL.$ext"
+ REMOTE="$MERGED.REMOTE.$ext"
+ BASE="$MERGED.BASE.$ext"
- mv -- "$path" "$BACKUP"
- cp -- "$BACKUP" "$path"
+ mv -- "$MERGED" "$BACKUP"
+ cp -- "$BACKUP" "$MERGED"
- base_mode=`git ls-files -u -- "$path" | awk '{if ($3==1) print $1;}'`
- local_mode=`git ls-files -u -- "$path" | awk '{if ($3==2) print $1;}'`
- remote_mode=`git ls-files -u -- "$path" | awk '{if ($3==3) print $1;}'`
+ base_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}'`
+ local_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}'`
+ remote_mode=`git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}'`
- base_present && git cat-file blob ":1:$prefix$path" >"$BASE" 2>/dev/null
- local_present && git cat-file blob ":2:$prefix$path" >"$LOCAL" 2>/dev/null
- remote_present && git cat-file blob ":3:$prefix$path" >"$REMOTE" 2>/dev/null
+ base_present && git cat-file blob ":1:$prefix$MERGED" >"$BASE" 2>/dev/null
+ local_present && git cat-file blob ":2:$prefix$MERGED" >"$LOCAL" 2>/dev/null
+ remote_present && git cat-file blob ":3:$prefix$MERGED" >"$REMOTE" 2>/dev/null
if test -z "$local_mode" -o -z "$remote_mode"; then
- echo "Deleted merge conflict for '$path':"
+ echo "Deleted merge conflict for '$MERGED':"
describe_file "$local_mode" "local" "$LOCAL"
describe_file "$remote_mode" "remote" "$REMOTE"
resolve_deleted_merge
@@ -178,14 +166,14 @@ merge_file () {
fi
if is_symlink "$local_mode" || is_symlink "$remote_mode"; then
- echo "Symbolic link merge conflict for '$path':"
+ echo "Symbolic link merge conflict for '$MERGED':"
describe_file "$local_mode" "local" "$LOCAL"
describe_file "$remote_mode" "remote" "$REMOTE"
resolve_symlink_merge
return
fi
- echo "Normal merge conflict for '$path':"
+ echo "Normal merge conflict for '$MERGED':"
describe_file "$local_mode" "local" "$LOCAL"
describe_file "$remote_mode" "remote" "$REMOTE"
printf "Hit return to start merge resolution tool (%s): " "$merge_tool"
@@ -194,36 +182,32 @@ merge_file () {
case "$merge_tool" in
kdiff3)
if base_present ; then
- ("$merge_tool_path" --auto --L1 "$path (Base)" --L2 "$path (Local)" --L3 "$path (Remote)" \
- -o "$path" -- "$BASE" "$LOCAL" "$REMOTE" > /dev/null 2>&1)
+ ("$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" --auto --L1 "$path (Local)" --L2 "$path (Remote)" \
- -o "$path" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1)
+ ("$merge_tool_path" --auto --L1 "$MERGED (Local)" --L2 "$MERGED (Remote)" \
+ -o "$MERGED" -- "$LOCAL" "$REMOTE" > /dev/null 2>&1)
fi
status=$?
- remove_backup
;;
tkdiff)
if base_present ; then
- "$merge_tool_path" -a "$BASE" -o "$path" -- "$LOCAL" "$REMOTE"
+ "$merge_tool_path" -a "$BASE" -o "$MERGED" -- "$LOCAL" "$REMOTE"
else
- "$merge_tool_path" -o "$path" -- "$LOCAL" "$REMOTE"
+ "$merge_tool_path" -o "$MERGED" -- "$LOCAL" "$REMOTE"
fi
status=$?
- save_backup
;;
meld|vimdiff)
touch "$BACKUP"
- "$merge_tool_path" -- "$LOCAL" "$path" "$REMOTE"
+ "$merge_tool_path" -- "$LOCAL" "$MERGED" "$REMOTE"
check_unchanged
- save_backup
;;
gvimdiff)
- touch "$BACKUP"
- "$merge_tool_path" -f -- "$LOCAL" "$path" "$REMOTE"
- check_unchanged
- save_backup
- ;;
+ touch "$BACKUP"
+ "$merge_tool_path" -f -- "$LOCAL" "$MERGED" "$REMOTE"
+ check_unchanged
+ ;;
xxdiff)
touch "$BACKUP"
if base_present ; then
@@ -231,53 +215,68 @@ merge_file () {
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
-R 'Accel.Search: "Ctrl+F"' \
-R 'Accel.SearchForward: "Ctrl-G"' \
- --merged-file "$path" -- "$LOCAL" "$BASE" "$REMOTE"
+ --merged-file "$MERGED" -- "$LOCAL" "$BASE" "$REMOTE"
else
"$merge_tool_path" -X --show-merged-pane \
-R 'Accel.SaveAsMerged: "Ctrl-S"' \
-R 'Accel.Search: "Ctrl+F"' \
-R 'Accel.SearchForward: "Ctrl-G"' \
- --merged-file "$path" -- "$LOCAL" "$REMOTE"
+ --merged-file "$MERGED" -- "$LOCAL" "$REMOTE"
fi
check_unchanged
- save_backup
;;
opendiff)
touch "$BACKUP"
if base_present; then
- "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$path" | cat
+ "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED" | cat
else
- "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$path" | cat
+ "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED" | cat
fi
check_unchanged
- save_backup
;;
ecmerge)
touch "$BACKUP"
if base_present; then
- "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --mode=merge3 --to="$path"
+ "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --mode=merge3 --to="$MERGED"
else
- "$merge_tool_path" "$LOCAL" "$REMOTE" --mode=merge2 --to="$path"
+ "$merge_tool_path" "$LOCAL" "$REMOTE" --mode=merge2 --to="$MERGED"
fi
check_unchanged
- save_backup
;;
emerge)
if base_present ; then
- "$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$path")"
+ "$merge_tool_path" -f emerge-files-with-ancestor-command "$LOCAL" "$REMOTE" "$BASE" "$(basename "$MERGED")"
else
- "$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$path")"
+ "$merge_tool_path" -f emerge-files-command "$LOCAL" "$REMOTE" "$(basename "$MERGED")"
fi
status=$?
- save_backup
+ ;;
+ *)
+ if test -n "$merge_tool_cmd"; then
+ if test "$merge_tool_trust_exit_code" = "false"; then
+ touch "$BACKUP"
+ ( eval $merge_tool_cmd )
+ check_unchanged
+ else
+ ( eval $merge_tool_cmd )
+ status=$?
+ fi
+ fi
;;
esac
if test "$status" -ne 0; then
- echo "merge of $path failed" 1>&2
- mv -- "$BACKUP" "$path"
+ echo "merge of $MERGED failed" 1>&2
+ mv -- "$BACKUP" "$MERGED"
exit 1
fi
- git add -- "$path"
+
+ if test "$merge_keep_backup" = "true"; then
+ mv -- "$BACKUP" "$MERGED.orig"
+ else
+ rm -- "$BACKUP"
+ fi
+
+ git add -- "$MERGED"
cleanup_temp_files
}
@@ -309,12 +308,20 @@ do
shift
done
+valid_custom_tool()
+{
+ merge_tool_cmd="$(git config mergetool.$1.cmd)"
+ test -n "$merge_tool_cmd"
+}
+
valid_tool() {
case "$1" in
kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | ecmerge)
;; # happy
*)
- return 1
+ if ! valid_custom_tool "$1"; then
+ return 1
+ fi
;;
esac
}
@@ -380,10 +387,16 @@ else
init_merge_tool_path "$merge_tool"
- if ! type "$merge_tool_path" > /dev/null 2>&1; then
+ merge_keep_backup="$(git config --bool merge.keepBackup || echo true)"
+
+ if test -z "$merge_tool_cmd" && ! type "$merge_tool_path" > /dev/null 2>&1; then
echo "The merge tool $merge_tool is not available as '$merge_tool_path'"
exit 1
fi
+
+ if ! test -z "$merge_tool_cmd"; then
+ merge_tool_trust_exit_code="$(git config --bool mergetool.$merge_tool.trustExitCode || echo false)"
+ fi
fi
diff --git a/git-rebase.sh b/git-rebase.sh
index bdcea0ed7..6b9af962a 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -208,16 +208,15 @@ do
if test -d "$dotest"
then
move_to_original_branch
- rm -r "$dotest"
elif test -d .dotest
then
dotest=.dotest
move_to_original_branch
- rm -r .dotest
else
die "No rebase in progress?"
fi
- git reset --hard ORIG_HEAD
+ git reset --hard $(cat $dotest/orig-head)
+ rm -r "$dotest"
exit
;;
--onto)
diff --git a/git-remote.perl b/git-remote.perl
index 5cd69513c..b30ed734e 100755
--- a/git-remote.perl
+++ b/git-remote.perl
@@ -7,10 +7,10 @@ my $git = Git->repository();
sub add_remote_config {
my ($hash, $name, $what, $value) = @_;
if ($what eq 'url') {
- if (exists $hash->{$name}{'URL'}) {
- print STDERR "Warning: more than one remote.$name.url\n";
+ # Having more than one is Ok -- it is used for push.
+ if (! exists $hash->{'URL'}) {
+ $hash->{$name}{'URL'} = $value;
}
- $hash->{$name}{'URL'} = $value;
}
elsif ($what eq 'fetch') {
$hash->{$name}{'FETCH'} ||= [];
diff --git a/git-submodule.sh b/git-submodule.sh
index a6aaf40b0..67d3224c8 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -362,7 +362,7 @@ cmd_status()
do
name=$(module_name "$path") || exit
url=$(git config submodule."$name".url)
- if test -z "url" || ! test -d "$path"/.git
+ if test -z "$url" || ! test -d "$path"/.git
then
say "-$sha1 $path"
continue;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index fc95e2ca8..922dee98b 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -472,13 +472,15 @@ if (defined $searchtype) {
}
}
+our $search_use_regexp = $cgi->param('sr');
+
our $searchtext = $cgi->param('s');
our $search_regexp;
if (defined $searchtext) {
if (length($searchtext) < 2) {
die_error(undef, "At least two characters are required for search parameter");
}
- $search_regexp = quotemeta $searchtext;
+ $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext;
}
# now read PATH_INFO and use it as alternative to parameters
@@ -608,6 +610,7 @@ sub href(%) {
searchtype => "st",
snapshot_format => "sf",
extra_options => "opt",
+ search_use_regexp => "sr",
);
my %mapping = @mapping;
@@ -2079,7 +2082,7 @@ sub parse_commit {
}
sub parse_commits {
- my ($commit_id, $maxcount, $skip, $arg, $filename) = @_;
+ my ($commit_id, $maxcount, $skip, $filename, @args) = @_;
my @cos;
$maxcount ||= 1;
@@ -2089,7 +2092,7 @@ sub parse_commits {
open my $fd, "-|", git_cmd(), "rev-list",
"--header",
- ($arg ? ($arg) : ()),
+ @args,
("--max-count=" . $maxcount),
("--skip=" . $skip),
@extra_options,
@@ -2584,6 +2587,10 @@ EOF
$cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
" search:\n",
$cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
+ "<span title=\"Extended regular expression\">" .
+ $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
+ -checked => $search_use_regexp) .
+ "</span>" .
"</div>" .
$cgi->end_form() . "\n";
}
@@ -3830,7 +3837,7 @@ sub git_search_grep_body {
chop_and_escape_str($co{'title'}, 50) . "<br/>");
my $comment = $co{'comment'};
foreach my $line (@$comment) {
- if ($line =~ m/^(.*)($search_regexp)(.*)$/i) {
+ if ($line =~ m/^(.*?)($search_regexp)(.*)$/i) {
my ($lead, $match, $trail) = ($1, $2, $3);
$match = chop_str($match, 70, 5, 'center');
my $contextlen = int((80 - length($match))/2);
@@ -5172,7 +5179,7 @@ sub git_history {
$ftype = git_get_type($hash);
}
- my @commitlist = parse_commits($hash_base, 101, (100 * $page), "--full-history", $file_name);
+ my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history");
my $paging_nav = '';
if ($page > 0) {
@@ -5254,14 +5261,17 @@ sub git_search {
} elsif ($searchtype eq 'committer') {
$greptype = "--committer=";
}
- $greptype .= $search_regexp;
- my @commitlist = parse_commits($hash, 101, (100 * $page), $greptype);
+ $greptype .= $searchtext;
+ my @commitlist = parse_commits($hash, 101, (100 * $page), undef,
+ $greptype, '--regexp-ignore-case',
+ $search_use_regexp ? '--extended-regexp' : '--fixed-strings');
my $paging_nav = '';
if ($page > 0) {
$paging_nav .=
$cgi->a({-href => href(action=>"search", hash=>$hash,
- searchtext=>$searchtext, searchtype=>$searchtype)},
+ searchtext=>$searchtext,
+ searchtype=>$searchtype)},
"first");
$paging_nav .= " &sdot; " .
$cgi->a({-href => href(-replay=>1, page=>$page-1),
@@ -5298,8 +5308,9 @@ sub git_search {
my $git_command = git_cmd_str();
my $searchqtext = $searchtext;
$searchqtext =~ s/'/'\\''/;
+ my $pickaxe_flags = $search_use_regexp ? '--pickaxe-regex' : '';
open my $fd, "-|", "$git_command rev-list $hash | " .
- "$git_command diff-tree -r --stdin -S\'$searchqtext\'";
+ "$git_command diff-tree -r --stdin -S\'$searchqtext\' $pickaxe_flags";
undef %co;
my @files;
while (my $line = <$fd>) {
@@ -5363,7 +5374,9 @@ sub git_search {
my $alternate = 1;
my $matches = 0;
$/ = "\n";
- open my $fd, "-|", git_cmd(), 'grep', '-n', '-i', '-E', $searchtext, $co{'tree'};
+ open my $fd, "-|", git_cmd(), 'grep', '-n',
+ $search_use_regexp ? ('-E', '-i') : '-F',
+ $searchtext, $co{'tree'};
my $lastfile = '';
while (my $line = <$fd>) {
chomp $line;
@@ -5393,7 +5406,7 @@ sub git_search {
print "<div class=\"binary\">Binary file</div>\n";
} else {
$ltext = untabify($ltext);
- if ($ltext =~ m/^(.*)($searchtext)(.*)$/i) {
+ if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) {
$ltext = esc_html($1, -nbsp=>1);
$ltext .= '<span class="match">';
$ltext .= esc_html($2, -nbsp=>1);
@@ -5428,27 +5441,31 @@ sub git_search_help {
git_header_html();
git_print_page_nav('','', $hash,$hash,$hash);
print <<EOT;
+<p><strong>Pattern</strong> is by default a normal string that is matched precisely (but without
+regard to case, except in the case of pickaxe). However, when you check the <em>re</em> checkbox,
+the pattern entered is recognized as the POSIX extended
+<a href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a> (also case
+insensitive).</p>
<dl>
<dt><b>commit</b></dt>
-<dd>The commit messages and authorship information will be scanned for the given string.</dd>
+<dd>The commit messages and authorship information will be scanned for the given pattern.</dd>
EOT
my ($have_grep) = gitweb_check_feature('grep');
if ($have_grep) {
print <<EOT;
<dt><b>grep</b></dt>
<dd>All files in the currently selected tree (HEAD unless you are explicitly browsing
- a different one) are searched for the given
-<a href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a>
-(POSIX extended) and the matches are listed. On large
-trees, this search can take a while and put some strain on the server, so please use it with
-some consideration.</dd>
+ a different one) are searched for the given pattern. On large trees, this search can take
+a while and put some strain on the server, so please use it with some consideration. Note that
+due to git-grep peculiarity, currently if regexp mode is turned off, the matches are
+case-sensitive.</dd>
EOT
}
print <<EOT;
<dt><b>author</b></dt>
-<dd>Name and e-mail of the change author and date of birth of the patch will be scanned for the given string.</dd>
+<dd>Name and e-mail of the change author and date of birth of the patch will be scanned for the given pattern.</dd>
<dt><b>committer</b></dt>
-<dd>Name and e-mail of the committer and date of commit will be scanned for the given string.</dd>
+<dd>Name and e-mail of the committer and date of commit will be scanned for the given pattern.</dd>
EOT
my ($have_pickaxe) = gitweb_check_feature('pickaxe');
if ($have_pickaxe) {
@@ -5456,7 +5473,8 @@ EOT
<dt><b>pickaxe</b></dt>
<dd>All commits that caused the string to appear or disappear from any file (changes that
added, removed or "modified" the string) will be listed. This search can take a while and
-takes a lot of strain on the server, so please use it wisely.</dd>
+takes a lot of strain on the server, so please use it wisely. Note that since you may be
+interested even in changes just changing the case as well, this search is case sensitive.</dd>
EOT
}
print "</dl>\n";
@@ -5507,7 +5525,7 @@ sub git_feed {
# log/feed of current (HEAD) branch, log of given branch, history of file/directory
my $head = $hash || 'HEAD';
- my @commitlist = parse_commits($head, 150, 0, undef, $file_name);
+ my @commitlist = parse_commits($head, 150, 0, $file_name);
my %latest_commit;
my %latest_date;
diff --git a/http-push.c b/http-push.c
index 406270f6f..5b230380c 100644
--- a/http-push.c
+++ b/http-push.c
@@ -2133,6 +2133,8 @@ static int delete_remote_branch(char *pattern, int force)
/* Send delete request */
fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
+ if (dry_run)
+ return 0;
url = xmalloc(strlen(remote->url) + strlen(remote_ref->name) + 1);
sprintf(url, "%s%s", remote->url, remote_ref->name);
slot = get_active_slot();
@@ -2235,7 +2237,7 @@ int main(int argc, char **argv)
memset(remote_dir_exists, -1, 256);
- http_init();
+ http_init(NULL);
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
@@ -2306,6 +2308,16 @@ int main(int argc, char **argv)
if (!ref->peer_ref)
continue;
+
+ if (is_zero_sha1(ref->peer_ref->new_sha1)) {
+ if (delete_remote_branch(ref->name, 1) == -1) {
+ error("Could not remove %s", ref->name);
+ rc = -4;
+ }
+ new_refs++;
+ continue;
+ }
+
if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
if (push_verbosely || 1)
fprintf(stderr, "'%s': up-to-date\n", ref->name);
@@ -2337,11 +2349,6 @@ int main(int argc, char **argv)
}
}
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
- if (is_zero_sha1(ref->new_sha1)) {
- error("cannot happen anymore");
- rc = -3;
- continue;
- }
new_refs++;
strcpy(old_hex, sha1_to_hex(ref->old_sha1));
new_hex = sha1_to_hex(ref->new_sha1);
diff --git a/http-walker.c b/http-walker.c
index 2c3786870..7bda34d91 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -902,13 +902,13 @@ static void cleanup(struct walker *walker)
curl_slist_free_all(data->no_pragma_header);
}
-struct walker *get_http_walker(const char *url)
+struct walker *get_http_walker(const char *url, struct remote *remote)
{
char *s;
struct walker_data *data = xmalloc(sizeof(struct walker_data));
struct walker *walker = xmalloc(sizeof(struct walker));
- http_init();
+ http_init(remote);
data->no_pragma_header = curl_slist_append(NULL, "Pragma:");
diff --git a/http.c b/http.c
index 5925d0747..256a5f15f 100644
--- a/http.c
+++ b/http.c
@@ -218,13 +218,16 @@ static CURL* get_curl_handle(void)
return result;
}
-void http_init(void)
+void http_init(struct remote *remote)
{
char *low_speed_limit;
char *low_speed_time;
curl_global_init(CURL_GLOBAL_ALL);
+ if (remote && remote->http_proxy)
+ curl_http_proxy = xstrdup(remote->http_proxy);
+
pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
#ifdef USE_CURL_MULTI
@@ -281,23 +284,15 @@ void http_init(void)
void http_cleanup(void)
{
struct active_request_slot *slot = active_queue_head;
-#ifdef USE_CURL_MULTI
- char *wait_url;
-#endif
while (slot != NULL) {
struct active_request_slot *next = slot->next;
+ if (slot->curl != NULL) {
#ifdef USE_CURL_MULTI
- if (slot->in_use) {
- curl_easy_getinfo(slot->curl,
- CURLINFO_EFFECTIVE_URL,
- &wait_url);
- fprintf(stderr, "Waiting for %s\n", wait_url);
- run_active_slot(slot);
- }
+ curl_multi_remove_handle(curlm, slot->curl);
#endif
- if (slot->curl != NULL)
curl_easy_cleanup(slot->curl);
+ }
free(slot);
slot = next;
}
@@ -314,6 +309,11 @@ void http_cleanup(void)
curl_slist_free_all(pragma_header);
pragma_header = NULL;
+
+ if (curl_http_proxy) {
+ free(curl_http_proxy);
+ curl_http_proxy = NULL;
+ }
}
struct active_request_slot *get_active_slot(void)
diff --git a/http.h b/http.h
index 9bab2c882..04169d5f9 100644
--- a/http.h
+++ b/http.h
@@ -7,6 +7,7 @@
#include <curl/easy.h>
#include "strbuf.h"
+#include "remote.h"
/*
* We detect based on the cURL version if multi-transfer is
@@ -83,7 +84,7 @@ extern void add_fill_function(void *data, int (*fill)(void *));
extern void step_active_slots(void);
#endif
-extern void http_init(void);
+extern void http_init(struct remote *remote);
extern void http_cleanup(void);
extern int data_received;
diff --git a/index-pack.c b/index-pack.c
index 9fd6982a9..9c0c27813 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -7,9 +7,10 @@
#include "tag.h"
#include "tree.h"
#include "progress.h"
+#include "fsck.h"
static const char index_pack_usage[] =
-"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
+"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
struct object_entry
{
@@ -31,6 +32,9 @@ union delta_base {
*/
#define UNION_BASE_SZ 20
+#define FLAG_LINK (1u<<20)
+#define FLAG_CHECKED (1u<<21)
+
struct delta_entry
{
union delta_base base;
@@ -44,6 +48,7 @@ static int nr_deltas;
static int nr_resolved_deltas;
static int from_stdin;
+static int strict;
static int verbose;
static struct progress *progress;
@@ -56,6 +61,48 @@ static SHA_CTX input_ctx;
static uint32_t input_crc32;
static int input_fd, output_fd, pack_fd;
+static int mark_link(struct object *obj, int type, void *data)
+{
+ if (!obj)
+ return -1;
+
+ if (type != OBJ_ANY && obj->type != type)
+ die("object type mismatch at %s", sha1_to_hex(obj->sha1));
+
+ obj->flags |= FLAG_LINK;
+ return 0;
+}
+
+/* The content of each linked object must have been checked
+ or it must be already present in the object database */
+static void check_object(struct object *obj)
+{
+ if (!obj)
+ return;
+
+ if (!(obj->flags & FLAG_LINK))
+ return;
+
+ if (!(obj->flags & FLAG_CHECKED)) {
+ unsigned long size;
+ int type = sha1_object_info(obj->sha1, &size);
+ if (type != obj->type || type <= 0)
+ die("object of unexpected type");
+ obj->flags |= FLAG_CHECKED;
+ return;
+ }
+}
+
+static void check_objects(void)
+{
+ unsigned i, max;
+
+ max = get_max_object_index();
+ for (i = 0; i < max; i++)
+ check_object(get_indexed_object(i));
+}
+
+
/* Discard current buffer used content. */
static void flush(void)
{
@@ -341,6 +388,41 @@ static void sha1_object(const void *data, unsigned long size,
die("SHA1 COLLISION FOUND WITH %s !", sha1_to_hex(sha1));
free(has_data);
}
+ if (strict) {
+ if (type == OBJ_BLOB) {
+ struct blob *blob = lookup_blob(sha1);
+ if (blob)
+ blob->object.flags |= FLAG_CHECKED;
+ else
+ die("invalid blob object %s", sha1_to_hex(sha1));
+ } else {
+ struct object *obj;
+ int eaten;
+ void *buf = (void *) data;
+
+ /*
+ * we do not need to free the memory here, as the
+ * buf is deleted by the caller.
+ */
+ obj = parse_object_buffer(sha1, type, size, buf, &eaten);
+ if (!obj)
+ die("invalid %s", typename(type));
+ if (fsck_object(obj, 1, fsck_error_function))
+ die("Error in object");
+ if (fsck_walk(obj, mark_link, 0))
+ die("Not all child objects of %s are reachable", sha1_to_hex(obj->sha1));
+
+ if (obj->type == OBJ_TREE) {
+ struct tree *item = (struct tree *) obj;
+ item->buffer = NULL;
+ }
+ if (obj->type == OBJ_COMMIT) {
+ struct commit *commit = (struct commit *) obj;
+ commit->buffer = NULL;
+ }
+ obj->flags |= FLAG_CHECKED;
+ }
+ }
}
static void resolve_delta(struct object_entry *delta_obj, void *base_data,
@@ -714,6 +796,8 @@ int main(int argc, char **argv)
from_stdin = 1;
} else if (!strcmp(arg, "--fix-thin")) {
fix_thin_pack = 1;
+ } else if (!strcmp(arg, "--strict")) {
+ strict = 1;
} else if (!strcmp(arg, "--keep")) {
keep_msg = "";
} else if (!prefixcmp(arg, "--keep=")) {
@@ -812,6 +896,8 @@ int main(int argc, char **argv)
nr_deltas - nr_resolved_deltas);
}
free(deltas);
+ if (strict)
+ check_objects();
idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
for (i = 0; i < nr_objects; i++)
diff --git a/object-refs.c b/object-refs.c
deleted file mode 100644
index 534567156..000000000
--- a/object-refs.c
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "cache.h"
-#include "object.h"
-#include "decorate.h"
-
-int track_object_refs = 0;
-
-static struct decoration ref_decorate;
-
-struct object_refs *lookup_object_refs(struct object *base)
-{
- return lookup_decoration(&ref_decorate, base);
-}
-
-static void add_object_refs(struct object *obj, struct object_refs *refs)
-{
- if (add_decoration(&ref_decorate, obj, refs))
- die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1));
-}
-
-struct object_refs *alloc_object_refs(unsigned count)
-{
- struct object_refs *refs;
- size_t size = sizeof(*refs) + count*sizeof(struct object *);
-
- refs = xcalloc(1, size);
- refs->count = count;
- return refs;
-}
-
-static int compare_object_pointers(const void *a, const void *b)
-{
- const struct object * const *pa = a;
- const struct object * const *pb = b;
- if (*pa == *pb)
- return 0;
- else if (*pa < *pb)
- return -1;
- else
- return 1;
-}
-
-void set_object_refs(struct object *obj, struct object_refs *refs)
-{
- unsigned int i, j;
-
- /* Do not install empty list of references */
- if (refs->count < 1) {
- free(refs);
- return;
- }
-
- /* Sort the list and filter out duplicates */
- qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
- compare_object_pointers);
- for (i = j = 1; i < refs->count; i++) {
- if (refs->ref[i] != refs->ref[i - 1])
- refs->ref[j++] = refs->ref[i];
- }
- if (j < refs->count) {
- /* Duplicates were found - reallocate list */
- size_t size = sizeof(*refs) + j*sizeof(struct object *);
- refs->count = j;
- refs = xrealloc(refs, size);
- }
-
- for (i = 0; i < refs->count; i++)
- refs->ref[i]->used = 1;
- add_object_refs(obj, refs);
-}
-
-void mark_reachable(struct object *obj, unsigned int mask)
-{
- const struct object_refs *refs;
-
- if (!track_object_refs)
- die("cannot do reachability with object refs turned off");
- /* If we've been here already, don't bother */
- if (obj->flags & mask)
- return;
- obj->flags |= mask;
- refs = lookup_object_refs(obj);
- if (refs) {
- unsigned i;
- for (i = 0; i < refs->count; i++)
- mark_reachable(refs->ref[i], mask);
- }
-}
diff --git a/object.h b/object.h
index 397bbfa09..036bd66fe 100644
--- a/object.h
+++ b/object.h
@@ -35,14 +35,11 @@ struct object {
unsigned char sha1[20];
};
-extern int track_object_refs;
-
extern const char *typename(unsigned int type);
extern int type_from_string(const char *str);
extern unsigned int get_max_object_index(void);
extern struct object *get_indexed_object(unsigned int);
-extern struct object_refs *lookup_object_refs(struct object *);
/** Internal only **/
struct object *lookup_object(const unsigned char *sha1);
@@ -61,11 +58,6 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
/** Returns the object, with potentially excess memory allocated. **/
struct object *lookup_unknown_object(const unsigned char *sha1);
-struct object_refs *alloc_object_refs(unsigned count);
-void set_object_refs(struct object *obj, struct object_refs *refs);
-
-void mark_reachable(struct object *obj, unsigned int mask);
-
struct object_list *object_list_insert(struct object *item,
struct object_list **list_p);
diff --git a/pack-check.c b/pack-check.c
index d7dd62bb8..0f8ad2c00 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -1,5 +1,6 @@
#include "cache.h"
#include "pack.h"
+#include "pack-revindex.h"
struct idx_entry
{
@@ -101,8 +102,10 @@ static int verify_packfile(struct packed_git *p,
static void show_pack_info(struct packed_git *p)
{
uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1];
+
nr_objects = p->num_objects;
memset(chain_histogram, 0, sizeof(chain_histogram));
+ init_pack_revindex();
for (i = 0; i < nr_objects; i++) {
const unsigned char *sha1;
@@ -125,11 +128,11 @@ static void show_pack_info(struct packed_git *p)
base_sha1);
printf("%s ", sha1_to_hex(sha1));
if (!delta_chain_length)
- printf("%-6s %lu %"PRIuMAX"\n",
- type, size, (uintmax_t)offset);
+ printf("%-6s %lu %lu %"PRIuMAX"\n",
+ type, size, store_size, (uintmax_t)offset);
else {
- printf("%-6s %lu %"PRIuMAX" %u %s\n",
- type, size, (uintmax_t)offset,
+ printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
+ type, size, store_size, (uintmax_t)offset,
delta_chain_length, sha1_to_hex(base_sha1));
if (delta_chain_length <= MAX_CHAIN)
chain_histogram[delta_chain_length]++;
diff --git a/pack-revindex.c b/pack-revindex.c
new file mode 100644
index 000000000..a8aa2cd6c
--- /dev/null
+++ b/pack-revindex.c
@@ -0,0 +1,142 @@
+#include "cache.h"
+#include "pack-revindex.h"
+
+/*
+ * Pack index for existing packs give us easy access to the offsets into
+ * corresponding pack file where each object's data starts, but the entries
+ * do not store the size of the compressed representation (uncompressed
+ * size is easily available by examining the pack entry header). It is
+ * also rather expensive to find the sha1 for an object given its offset.
+ *
+ * We build a hashtable of existing packs (pack_revindex), and keep reverse
+ * index here -- pack index file is sorted by object name mapping to offset;
+ * this pack_revindex[].revindex array is a list of offset/index_nr pairs
+ * ordered by offset, so if you know the offset of an object, next offset
+ * is where its packed representation ends and the index_nr can be used to
+ * get the object sha1 from the main index.
+ */
+
+struct pack_revindex {
+ struct packed_git *p;
+ struct revindex_entry *revindex;
+};
+
+static struct pack_revindex *pack_revindex;
+static int pack_revindex_hashsz;
+
+static int pack_revindex_ix(struct packed_git *p)
+{
+ unsigned long ui = (unsigned long)p;
+ int i;
+
+ ui = ui ^ (ui >> 16); /* defeat structure alignment */
+ i = (int)(ui % pack_revindex_hashsz);
+ while (pack_revindex[i].p) {
+ if (pack_revindex[i].p == p)
+ return i;
+ if (++i == pack_revindex_hashsz)
+ i = 0;
+ }
+ return -1 - i;
+}
+
+void init_pack_revindex(void)
+{
+ int num;
+ struct packed_git *p;
+
+ for (num = 0, p = packed_git; p; p = p->next)
+ num++;
+ if (!num)
+ return;
+ pack_revindex_hashsz = num * 11;
+ pack_revindex = xcalloc(sizeof(*pack_revindex), pack_revindex_hashsz);
+ for (p = packed_git; p; p = p->next) {
+ num = pack_revindex_ix(p);
+ num = - 1 - num;
+ pack_revindex[num].p = p;
+ }
+ /* revindex elements are lazily initialized */
+}
+
+static int cmp_offset(const void *a_, const void *b_)
+{
+ const struct revindex_entry *a = a_;
+ const struct revindex_entry *b = b_;
+ return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0;
+}
+
+/*
+ * Ordered list of offsets of objects in the pack.
+ */
+static void create_pack_revindex(struct pack_revindex *rix)
+{
+ struct packed_git *p = rix->p;
+ int num_ent = p->num_objects;
+ int i;
+ const char *index = p->index_data;
+
+ rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
+ index += 4 * 256;
+
+ if (p->index_version > 1) {
+ const uint32_t *off_32 =
+ (uint32_t *)(index + 8 + p->num_objects * (20 + 4));
+ const uint32_t *off_64 = off_32 + p->num_objects;
+ for (i = 0; i < num_ent; i++) {
+ uint32_t off = ntohl(*off_32++);
+ if (!(off & 0x80000000)) {
+ rix->revindex[i].offset = off;
+ } else {
+ rix->revindex[i].offset =
+ ((uint64_t)ntohl(*off_64++)) << 32;
+ rix->revindex[i].offset |=
+ ntohl(*off_64++);
+ }
+ rix->revindex[i].nr = i;
+ }
+ } else {
+ for (i = 0; i < num_ent; i++) {
+ uint32_t hl = *((uint32_t *)(index + 24 * i));
+ rix->revindex[i].offset = ntohl(hl);
+ rix->revindex[i].nr = i;
+ }
+ }
+
+ /* This knows the pack format -- the 20-byte trailer
+ * follows immediately after the last object data.
+ */
+ rix->revindex[num_ent].offset = p->pack_size - 20;
+ rix->revindex[num_ent].nr = -1;
+ qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset);
+}
+
+struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
+{
+ int num;
+ int lo, hi;
+ struct pack_revindex *rix;
+ struct revindex_entry *revindex;
+
+ num = pack_revindex_ix(p);
+ if (num < 0)
+ die("internal error: pack revindex uninitialized");
+
+ rix = &pack_revindex[num];
+ if (!rix->revindex)
+ create_pack_revindex(rix);
+ revindex = rix->revindex;
+
+ lo = 0;
+ hi = p->num_objects + 1;
+ do {
+ int mi = (lo + hi) / 2;
+ if (revindex[mi].offset == ofs) {
+ return revindex + mi;
+ } else if (ofs < revindex[mi].offset)
+ hi = mi;
+ else
+ lo = mi + 1;
+ } while (lo < hi);
+ die("internal error: pack revindex corrupt");
+}
diff --git a/pack-revindex.h b/pack-revindex.h
new file mode 100644
index 000000000..c3527a756
--- /dev/null
+++ b/pack-revindex.h
@@ -0,0 +1,12 @@
+#ifndef PACK_REVINDEX_H
+#define PACK_REVINDEX_H
+
+struct revindex_entry {
+ off_t offset;
+ unsigned int nr;
+};
+
+void init_pack_revindex(void);
+struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs);
+
+#endif
diff --git a/path.c b/path.c
index 42609524a..f4ed97999 100644
--- a/path.c
+++ b/path.c
@@ -283,7 +283,7 @@ int adjust_shared_perm(const char *path)
? (S_IXGRP|S_IXOTH)
: 0));
if (S_ISDIR(mode))
- mode |= S_ISGID;
+ mode |= FORCE_DIR_SET_GID;
if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
return -2;
return 0;
@@ -311,8 +311,10 @@ const char *make_absolute_path(const char *path)
if (last_slash) {
*last_slash = '\0';
last_elem = xstrdup(last_slash + 1);
- } else
+ } else {
last_elem = xstrdup(buf);
+ *buf = '\0';
+ }
}
if (*buf) {
diff --git a/receive-pack.c b/receive-pack.c
index a971433db..f83ae87e1 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -471,6 +471,8 @@ int main(int argc, char **argv)
if (!dir)
usage(receive_pack_usage);
+ setup_path(NULL);
+
if (!enter_repo(dir, 0))
die("'%s': unable to chdir or not a git archive", dir);
diff --git a/revision.c b/revision.c
index 84fbdd3af..63bf2c5c2 100644
--- a/revision.c
+++ b/revision.c
@@ -633,12 +633,13 @@ static int handle_one_ref(const char *path, const unsigned char *sha1, int flag,
return 0;
}
-static void handle_all(struct rev_info *revs, unsigned flags)
+static void handle_refs(struct rev_info *revs, unsigned flags,
+ int (*for_each)(each_ref_fn, void *))
{
struct all_refs_cb cb;
cb.all_revs = revs;
cb.all_flags = flags;
- for_each_ref(handle_one_ref, &cb);
+ for_each(handle_one_ref, &cb);
}
static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)
@@ -771,14 +772,9 @@ static void prepare_show_merge(struct rev_info *revs)
add_pending_object(revs, &head->object, "HEAD");
add_pending_object(revs, &other->object, "MERGE_HEAD");
bases = get_merge_bases(head, other, 1);
- while (bases) {
- struct commit *it = bases->item;
- struct commit_list *n = bases->next;
- free(bases);
- bases = n;
- it->object.flags |= UNINTERESTING;
- add_pending_object(revs, &it->object, "(merge-base)");
- }
+ add_pending_commit_list(revs, bases, UNINTERESTING);
+ free_commit_list(bases);
+ head->object.flags |= SYMMETRIC_LEFT;
if (!active_nr)
read_cache();
@@ -797,6 +793,7 @@ static void prepare_show_merge(struct rev_info *revs)
i++;
}
revs->prune_data = prune;
+ revs->limited = 1;
}
int handle_revision_arg(const char *arg, struct rev_info *revs,
@@ -1015,7 +1012,19 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
continue;
}
if (!strcmp(arg, "--all")) {
- handle_all(revs, flags);
+ handle_refs(revs, flags, for_each_ref);
+ continue;
+ }
+ if (!strcmp(arg, "--branches")) {
+ handle_refs(revs, flags, for_each_branch_ref);
+ continue;
+ }
+ if (!strcmp(arg, "--tags")) {
+ handle_refs(revs, flags, for_each_tag_ref);
+ continue;
+ }
+ if (!strcmp(arg, "--remotes")) {
+ handle_refs(revs, flags, for_each_remote_ref);
continue;
}
if (!strcmp(arg, "--first-parent")) {
diff --git a/run-command.c b/run-command.c
index 743757c36..44100a749 100644
--- a/run-command.c
+++ b/run-command.c
@@ -91,6 +91,13 @@ int start_command(struct child_process *cmd)
close(cmd->in);
}
+ if (cmd->no_stderr)
+ dup_devnull(2);
+ else if (need_err) {
+ dup2(fderr[1], 2);
+ close_pair(fderr);
+ }
+
if (cmd->no_stdout)
dup_devnull(1);
else if (cmd->stdout_to_stderr)
@@ -103,13 +110,6 @@ int start_command(struct child_process *cmd)
close(cmd->out);
}
- if (cmd->no_stderr)
- dup_devnull(2);
- else if (need_err) {
- dup2(fderr[1], 2);
- close_pair(fderr);
- }
-
if (cmd->dir && chdir(cmd->dir))
die("exec %s: cd to %s failed (%s)", cmd->argv[0],
cmd->dir, strerror(errno));
diff --git a/sha1_file.c b/sha1_file.c
index 1ddb96bb8..445a871db 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -14,6 +14,7 @@
#include "tag.h"
#include "tree.h"
#include "refs.h"
+#include "pack-revindex.h"
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -1367,11 +1368,15 @@ const char *packed_object_info_detail(struct packed_git *p,
unsigned long dummy;
unsigned char *next_sha1;
enum object_type type;
+ struct revindex_entry *revidx;
*delta_chain_length = 0;
curpos = obj_offset;
type = unpack_object_header(p, &w_curs, &curpos, size);
+ revidx = find_pack_revindex(p, obj_offset);
+ *store_size = revidx[1].offset - obj_offset;
+
for (;;) {
switch (type) {
default:
@@ -1381,14 +1386,13 @@ const char *packed_object_info_detail(struct packed_git *p,
case OBJ_TREE:
case OBJ_BLOB:
case OBJ_TAG:
- *store_size = 0; /* notyet */
unuse_pack(&w_curs);
return typename(type);
case OBJ_OFS_DELTA:
obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
if (*delta_chain_length == 0) {
- /* TODO: find base_sha1 as pointed by curpos */
- hashclr(base_sha1);
+ revidx = find_pack_revindex(p, obj_offset);
+ hashcpy(base_sha1, nth_packed_object_sha1(p, revidx->nr));
}
break;
case OBJ_REF_DELTA:
diff --git a/sha1_name.c b/sha1_name.c
index 9d088cc2c..8358ba206 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -192,26 +192,25 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
const char *find_unique_abbrev(const unsigned char *sha1, int len)
{
- int status, is_null;
+ int status, exists;
static char hex[41];
- is_null = is_null_sha1(sha1);
+ exists = has_sha1_file(sha1);
memcpy(hex, sha1_to_hex(sha1), 40);
if (len == 40 || !len)
return hex;
while (len < 40) {
unsigned char sha1_ret[20];
status = get_short_sha1(hex, len, sha1_ret, 1);
- if (!status ||
- (is_null && status != SHORT_NAME_AMBIGUOUS)) {
+ if (exists
+ ? !status
+ : status == SHORT_NAME_NOT_FOUND) {
hex[len] = 0;
return hex;
}
- if (status != SHORT_NAME_AMBIGUOUS)
- return NULL;
len++;
}
- return NULL;
+ return hex;
}
static int ambiguous_path(const char *path, int len)
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
new file mode 100644
index 000000000..7f206c56c
--- /dev/null
+++ b/t/lib-httpd.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at>
+#
+
+if test -z "$GIT_TEST_HTTPD"
+then
+ say "skipping test, network testing disabled by default"
+ say "(define GIT_TEST_HTTPD to enable)"
+ test_done
+ exit
+fi
+
+LIB_HTTPD_PATH=${LIB_HTTPD_PATH-'/usr/sbin/apache2'}
+LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'8111'}
+
+TEST_PATH="$PWD"/../lib-httpd
+HTTPD_ROOT_PATH="$PWD"/httpd
+HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www
+
+if ! test -x "$LIB_HTTPD_PATH"
+then
+ say "skipping test, no web server found at '$LIB_HTTPD_PATH'"
+ test_done
+ exit
+fi
+
+HTTPD_VERSION=`$LIB_HTTPD_PATH -v | \
+ sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q'`
+
+if test -n "$HTTPD_VERSION"
+then
+ if test -z "$LIB_HTTPD_MODULE_PATH"
+ then
+ if ! test $HTTPD_VERSION -ge 2
+ then
+ say "skipping test, at least Apache version 2 is required"
+ test_done
+ exit
+ fi
+
+ LIB_HTTPD_MODULE_PATH='/usr/lib/apache2/modules'
+ fi
+else
+ error "Could not identify web server at '$LIB_HTTPD_PATH'"
+fi
+
+HTTPD_PARA="-d $HTTPD_ROOT_PATH -f $TEST_PATH/apache.conf"
+
+prepare_httpd() {
+ mkdir -p $HTTPD_DOCUMENT_ROOT_PATH
+
+ ln -s $LIB_HTTPD_MODULE_PATH $HTTPD_ROOT_PATH/modules
+
+ if test -n "$LIB_HTTPD_SSL"
+ then
+ HTTPD_URL=https://127.0.0.1:$LIB_HTTPD_PORT
+
+ RANDFILE_PATH="$HTTPD_ROOT_PATH"/.rnd openssl req \
+ -config $TEST_PATH/ssl.cnf \
+ -new -x509 -nodes \
+ -out $HTTPD_ROOT_PATH/httpd.pem \
+ -keyout $HTTPD_ROOT_PATH/httpd.pem
+ export GIT_SSL_NO_VERIFY=t
+ HTTPD_PARA="$HTTPD_PARA -DSSL"
+ else
+ HTTPD_URL=http://127.0.0.1:$LIB_HTTPD_PORT
+ fi
+
+ if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN"
+ then
+ HTTPD_PARA="$HTTPD_PARA -DDAV"
+
+ if test -n "$LIB_HTTPD_SVN"
+ then
+ HTTPD_PARA="$HTTPD_PARA -DSVN"
+ rawsvnrepo="$HTTPD_ROOT_PATH/svnrepo"
+ svnrepo="http://127.0.0.1:$LIB_HTTPD_PORT/svn"
+ fi
+ fi
+}
+
+start_httpd() {
+ prepare_httpd
+
+ trap 'stop_httpd; die' exit
+
+ "$LIB_HTTPD_PATH" $HTTPD_PARA \
+ -c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start
+}
+
+stop_httpd() {
+ trap 'die' exit
+
+ "$LIB_HTTPD_PATH" $HTTPD_PARA -k stop
+}
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
new file mode 100644
index 000000000..a4473462d
--- /dev/null
+++ b/t/lib-httpd/apache.conf
@@ -0,0 +1,34 @@
+PidFile httpd.pid
+DocumentRoot www
+ErrorLog error.log
+
+<IfDefine SSL>
+LoadModule ssl_module modules/mod_ssl.so
+
+SSLCertificateFile httpd.pem
+SSLCertificateKeyFile httpd.pem
+SSLRandomSeed startup file:/dev/urandom 512
+SSLRandomSeed connect file:/dev/urandom 512
+SSLSessionCache none
+SSLMutex file:ssl_mutex
+SSLEngine On
+</IfDefine>
+
+<IfDefine DAV>
+ LoadModule dav_module modules/mod_dav.so
+ LoadModule dav_fs_module modules/mod_dav_fs.so
+
+ DAVLockDB DAVLock
+ <Location />
+ Dav on
+ </Location>
+</IfDefine>
+
+<IfDefine SVN>
+ LoadModule dav_svn_module modules/mod_dav_svn.so
+
+ <Location /svn>
+ DAV svn
+ SVNPath svnrepo
+ </Location>
+</IfDefine>
diff --git a/t/lib-httpd/ssl.cnf b/t/lib-httpd/ssl.cnf
new file mode 100644
index 000000000..6dab2579c
--- /dev/null
+++ b/t/lib-httpd/ssl.cnf
@@ -0,0 +1,8 @@
+RANDFILE = $ENV::RANDFILE_PATH
+
+[ req ]
+default_bits = 1024
+distinguished_name = req_distinguished_name
+prompt = no
+[ req_distinguished_name ]
+commonName = 127.0.0.1
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 92de08822..27b54cbb1 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -304,6 +304,8 @@ test_expect_success 'absolute path works as expected' '
test "$dir" = "$(test-absolute-path $dir2)" &&
file="$dir"/index &&
test "$file" = "$(test-absolute-path $dir2/index)" &&
+ basename=blub &&
+ test "$dir/$basename" = $(cd .git && test-absolute-path $basename) &&
ln -s ../first/file .git/syml &&
sym="$(cd first; pwd -P)"/file &&
test "$sym" = "$(test-absolute-path $dir2/syml)"
diff --git a/t/t2009-checkout-statinfo.sh b/t/t2009-checkout-statinfo.sh
new file mode 100755
index 000000000..f3c215208
--- /dev/null
+++ b/t/t2009-checkout-statinfo.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='checkout should leave clean stat info'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+ echo hello >world &&
+ git update-index --add world &&
+ git commit -m initial &&
+ git branch side &&
+ echo goodbye >world &&
+ git update-index --add world &&
+ git commit -m second
+
+'
+
+test_expect_success 'branch switching' '
+
+ git reset --hard &&
+ test "$(git diff-files --raw)" = "" &&
+
+ git checkout master &&
+ test "$(git diff-files --raw)" = "" &&
+
+ git checkout side &&
+ test "$(git diff-files --raw)" = "" &&
+
+ git checkout master &&
+ test "$(git diff-files --raw)" = ""
+
+'
+
+test_expect_success 'path checkout' '
+
+ git reset --hard &&
+ test "$(git diff-files --raw)" = "" &&
+
+ git checkout master world &&
+ test "$(git diff-files --raw)" = "" &&
+
+ git checkout side world &&
+ test "$(git diff-files --raw)" = "" &&
+
+ git checkout master world &&
+ test "$(git diff-files --raw)" = ""
+
+'
+
+test_done
+
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 62e65d704..049aa3753 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -61,7 +61,7 @@ test_expect_success 'setup' '
git tag I
'
-echo "#!$SHELL" >fake-editor
+echo "#!$SHELL_PATH" >fake-editor.sh
cat >> fake-editor.sh <<\EOF
case "$1" in
*/COMMIT_EDITMSG)
diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh
new file mode 100755
index 000000000..37944c39a
--- /dev/null
+++ b/t/t3407-rebase-abort.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+test_description='git rebase --abort tests'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ echo a > a &&
+ git add a &&
+ git commit -m a &&
+ git branch to-rebase &&
+
+ echo b > a &&
+ git commit -a -m b &&
+ echo c > a &&
+ git commit -a -m c &&
+
+ git checkout to-rebase &&
+ echo d > a &&
+ git commit -a -m "merge should fail on this" &&
+ echo e > a &&
+ git commit -a -m "merge should fail on this, too" &&
+ git branch pre-rebase
+'
+
+testrebase() {
+ type=$1
+ dotest=$2
+
+ test_expect_success "rebase$type --abort" '
+ # Clean up the state from the previous one
+ git reset --hard pre-rebase
+ test_must_fail git rebase'"$type"' master &&
+ test -d '$dotest' &&
+ git rebase --abort &&
+ test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
+ test ! -d '$dotest'
+ '
+
+ test_expect_success "rebase$type --abort after --skip" '
+ # Clean up the state from the previous one
+ git reset --hard pre-rebase
+ test_must_fail git rebase'"$type"' master &&
+ test -d '$dotest' &&
+ test_must_fail git rebase --skip &&
+ test $(git rev-parse HEAD) = $(git rev-parse master) &&
+ git-rebase --abort &&
+ test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
+ test ! -d '$dotest'
+ '
+
+ test_expect_success "rebase$type --abort after --continue" '
+ # Clean up the state from the previous one
+ git reset --hard pre-rebase
+ test_must_fail git rebase'"$type"' master &&
+ test -d '$dotest' &&
+ echo c > a &&
+ echo d >> a &&
+ git add a &&
+ test_must_fail git rebase --continue &&
+ test $(git rev-parse HEAD) != $(git rev-parse master) &&
+ git rebase --abort &&
+ test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) &&
+ test ! -d '$dotest'
+ '
+}
+
+testrebase "" .dotest
+testrebase " --merge" .git/.dotest-merge
+
+test_done
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 2dbe04fb2..6da212825 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -59,4 +59,13 @@ test_expect_success 'revert after renaming branch' '
'
+test_expect_success 'revert forbidden on dirty working tree' '
+
+ echo content >extra_file &&
+ git add extra_file &&
+ test_must_fail git revert HEAD 2>errors &&
+ grep "Dirty index" errors
+
+'
+
test_done
diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
index 0151453b7..8dab4bf93 100644
--- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
+++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
@@ -7,8 +7,8 @@ Subject: [DIFFERENT_PREFIX 0/2] *** SUBJECT HERE ***
*** BLURB HERE ***
A U Thor (2):
- Second
- Third
+ Second
+ Third
dir/sub | 4 ++++
file0 | 3 +++
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 16aa99dc0..b2b7a8db8 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -147,7 +147,7 @@ test_expect_success 'thread' '
for i in patches/0002-* patches/0003-*
do
grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i
+ grep "In-Reply-To: $FIRST_MID" $i || break
done
'
@@ -160,7 +160,7 @@ test_expect_success 'thread in-reply-to' '
for i in patches/*
do
grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i
+ grep "In-Reply-To: $FIRST_MID" $i || break
done
'
@@ -173,7 +173,7 @@ test_expect_success 'thread cover-letter' '
for i in patches/0001-* patches/0002-* patches/0003-*
do
grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i
+ grep "In-Reply-To: $FIRST_MID" $i || break
done
'
@@ -186,7 +186,7 @@ test_expect_success 'thread cover-letter in-reply-to' '
for i in patches/*
do
grep "References: $FIRST_MID" $i &&
- grep "In-Reply-To: $FIRST_MID" $i
+ grep "In-Reply-To: $FIRST_MID" $i || break
done
'
@@ -201,4 +201,33 @@ test_expect_success 'excessive subject' '
ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
'
+test_expect_success 'cover-letter inherits diff options' '
+
+ git mv file foo &&
+ git commit -m foo &&
+ git format-patch --cover-letter -1 &&
+ ! grep "file => foo .* 0 *$" 0000-cover-letter.patch &&
+ git format-patch --cover-letter -1 -M &&
+ grep "file => foo .* 0 *$" 0000-cover-letter.patch
+
+'
+
+cat > expect << EOF
+ This is an excessively long subject line for a message due to the
+ habit some projects have of not having a short, one-line subject at
+ the start of the commit message, but rather sticking a whole
+ paragraph right at the start as the only thing in the commit
+ message. It had better not become the filename for the patch.
+ foo
+
+EOF
+
+test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
+
+ git format-patch --cover-letter -2 &&
+ sed -e "1,/A U Thor/d" -e "/^$/q" < 0000-cover-letter.patch > output &&
+ git diff expect output
+
+'
+
test_done
diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh
new file mode 100755
index 000000000..3d2d0816a
--- /dev/null
+++ b/t/t4027-diff-submodule.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+test_description='difference in submodules'
+
+. ./test-lib.sh
+. ../diff-lib.sh
+
+_z40=0000000000000000000000000000000000000000
+test_expect_success setup '
+ test_tick &&
+ test_create_repo sub &&
+ (
+ cd sub &&
+ echo hello >world &&
+ git add world &&
+ git commit -m submodule
+ ) &&
+
+ test_tick &&
+ echo frotz >nitfol &&
+ git add nitfol sub &&
+ git commit -m superproject &&
+
+ (
+ cd sub &&
+ echo goodbye >world &&
+ git add world &&
+ git commit -m "submodule #2"
+ ) &&
+
+ set x $(
+ cd sub &&
+ git rev-list HEAD
+ ) &&
+ echo ":160000 160000 $3 $_z40 M sub" >expect
+'
+
+test_expect_success 'git diff --raw HEAD' '
+ git diff --raw --abbrev=40 HEAD >actual &&
+ diff -u expect actual
+'
+
+test_expect_success 'git diff-index --raw HEAD' '
+ git diff-index --raw HEAD >actual.index &&
+ diff -u expect actual.index
+'
+
+test_expect_success 'git diff-files --raw' '
+ git diff-files --raw >actual.files &&
+ diff -u expect actual.files
+'
+
+test_done
diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh
new file mode 100755
index 000000000..737243916
--- /dev/null
+++ b/t/t5540-http-push.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at>
+#
+
+test_description='test http-push
+
+This test runs various sanity checks on http-push.'
+
+. ./test-lib.sh
+
+ROOT_PATH="$PWD"
+LIB_HTTPD_DAV=t
+
+. ../lib-httpd.sh
+
+if ! start_httpd >&3 2>&4
+then
+ say "skipping test, web server setup failed"
+ test_done
+ exit
+fi
+
+test_expect_success 'setup remote repository' '
+ cd "$ROOT_PATH" &&
+ mkdir test_repo &&
+ cd test_repo &&
+ git init &&
+ : >path1 &&
+ git add path1 &&
+ test_tick &&
+ git commit -m initial &&
+ cd - &&
+ git clone --bare test_repo test_repo.git &&
+ cd test_repo.git &&
+ git --bare update-server-info &&
+ chmod +x hooks/post-update &&
+ cd - &&
+ mv test_repo.git $HTTPD_DOCUMENT_ROOT_PATH
+'
+
+test_expect_success 'clone remote repository' '
+ cd "$ROOT_PATH" &&
+ git clone $HTTPD_URL/test_repo.git test_repo_clone
+'
+
+test_expect_success 'push to remote repository' '
+ cd "$ROOT_PATH"/test_repo_clone &&
+ : >path2 &&
+ git add path2 &&
+ test_tick &&
+ git commit -m path2 &&
+ git push
+'
+
+test_expect_success 'create and delete remote branch' '
+ cd "$ROOT_PATH"/test_repo_clone &&
+ git checkout -b dev &&
+ : >path3 &&
+ git add path3 &&
+ test_tick &&
+ git commit -m dev &&
+ git push origin dev &&
+ git fetch &&
+ git push origin :dev &&
+ git branch -d -r origin/dev &&
+ git fetch &&
+ ! git show-ref --verify refs/remotes/origin/dev
+'
+
+stop_httpd
+
+test_done
diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh
index 59a165a6d..8dfaaa456 100755
--- a/t/t5701-clone-local.sh
+++ b/t/t5701-clone-local.sh
@@ -11,6 +11,11 @@ test_expect_success 'preparing origin repository' '
git clone --bare . x &&
test "$(GIT_CONFIG=a.git/config git config --bool core.bare)" = true &&
test "$(GIT_CONFIG=x/config git config --bool core.bare)" = true
+ git bundle create b1.bundle --all HEAD &&
+ git bundle create b2.bundle --all &&
+ mkdir dir &&
+ cp b1.bundle dir/b3
+ cp b1.bundle b4
'
test_expect_success 'local clone without .git suffix' '
@@ -71,4 +76,44 @@ test_expect_success 'local clone of repo with nonexistent ref in HEAD' '
git fetch &&
test ! -e .git/refs/remotes/origin/HEAD'
+test_expect_success 'bundle clone without .bundle suffix' '
+ cd "$D" &&
+ git clone dir/b3 &&
+ cd b3 &&
+ git fetch
+'
+
+test_expect_success 'bundle clone with .bundle suffix' '
+ cd "$D" &&
+ git clone b1.bundle &&
+ cd b1 &&
+ git fetch
+'
+
+test_expect_success 'bundle clone from b4' '
+ cd "$D" &&
+ git clone b4 bdl &&
+ cd bdl &&
+ git fetch
+'
+
+test_expect_success 'bundle clone from b4.bundle that does not exist' '
+ cd "$D" &&
+ if git clone b4.bundle bb
+ then
+ echo "Oops, should have failed"
+ false
+ else
+ echo happy
+ fi
+'
+
+test_expect_success 'bundle clone with nonexistent HEAD' '
+ cd "$D" &&
+ git clone b2.bundle b2 &&
+ cd b2 &&
+ git fetch
+ test ! -e .git/refs/heads/master
+'
+
test_done
diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 149ea8543..23d24d3fe 100755
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -81,8 +81,8 @@ EOF
test_expect_success "virtual trees were processed" "git diff expect out"
-git reset --hard
test_expect_success 'refuse to merge binary files' '
+ git reset --hard &&
printf "\0" > binary-file &&
git add binary-file &&
git commit -m binary &&
diff --git a/t/t6029-merge-subtree.sh b/t/t6029-merge-subtree.sh
index 3900a0508..35d66e804 100755
--- a/t/t6029-merge-subtree.sh
+++ b/t/t6029-merge-subtree.sh
@@ -29,4 +29,51 @@ test_expect_success 'subtree available and works like recursive' '
'
+test_expect_success 'setup' '
+ mkdir git-gui &&
+ cd git-gui &&
+ git init &&
+ echo git-gui > git-gui.sh &&
+ o1=$(git hash-object git-gui.sh) &&
+ git add git-gui.sh &&
+ git commit -m "initial git-gui" &&
+ cd .. &&
+ mkdir git &&
+ cd git &&
+ git init &&
+ echo git >git.c &&
+ o2=$(git hash-object git.c) &&
+ git add git.c &&
+ git commit -m "initial git"
+'
+
+test_expect_success 'initial merge' '
+ git remote add -f gui ../git-gui &&
+ git merge -s ours --no-commit gui/master &&
+ git read-tree --prefix=git-gui/ -u gui/master &&
+ git commit -m "Merge git-gui as our subdirectory" &&
+ git ls-files -s >actual &&
+ (
+ echo "100644 $o1 0 git-gui/git-gui.sh"
+ echo "100644 $o2 0 git.c"
+ ) >expected &&
+ git diff -u expected actual
+'
+
+test_expect_success 'merge update' '
+ cd ../git-gui &&
+ echo git-gui2 > git-gui.sh &&
+ o3=$(git hash-object git-gui.sh) &&
+ git add git-gui.sh &&
+ git commit -m "update git-gui" &&
+ cd ../git &&
+ git pull -s subtree gui master &&
+ git ls-files -s >actual &&
+ (
+ echo "100644 $o3 0 git-gui/git-gui.sh"
+ echo "100644 $o2 0 git.c"
+ ) >expected &&
+ git diff -u expected actual
+'
+
test_done
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index ae8ee1118..56bbd8519 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -15,8 +15,11 @@ test_description='test describe
check_describe () {
expect="$1"
shift
- R=$(git describe "$@") &&
+ R=$(git describe "$@" 2>err.actual)
+ S=$?
+ cat err.actual >&3
test_expect_success "describe $*" '
+ test $S = 0 &&
case "$R" in
$expect) echo happy ;;
*) echo "Oops - $R is not $expect";
@@ -94,4 +97,24 @@ check_describe D-* --tags HEAD^^
check_describe A-* --tags HEAD^^2
check_describe B --tags HEAD^^2^
+check_describe B-0-* --long HEAD^^2^
+check_describe A-3-* --long HEAD^^2
+
+test_expect_success 'rename tag A to Q locally' '
+ mv .git/refs/tags/A .git/refs/tags/Q
+'
+cat - >err.expect <<EOF
+warning: tag 'A' is really 'Q' here
+EOF
+check_describe A-* HEAD
+test_expect_success 'warning was displayed for Q' '
+ git diff err.expect err.actual
+'
+test_expect_success 'rename tag Q back to A' '
+ mv .git/refs/tags/Q .git/refs/tags/A
+'
+
+test_expect_success 'pack tag refs' 'git pack-refs'
+check_describe A-* HEAD
+
test_done
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index 38403643a..403714292 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -320,8 +320,9 @@ test_expect_success 'removal failure' '
mkdir foo &&
touch foo/bar &&
+ exec <foo/bar &&
chmod 0 foo &&
- ! git clean -f -d
+ test_must_fail git clean -f -d
'
chmod 755 foo
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 50c51c82f..5d166280c 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -419,6 +419,7 @@ test_debug 'gitk --all'
test_expect_success 'merge c0 with c1 (no-ff)' '
git reset --hard c0 &&
+ git config branch.master.mergeoptions "" &&
test_tick &&
git merge --no-ff c1 &&
verify_merge file result.1 &&
@@ -427,6 +428,11 @@ test_expect_success 'merge c0 with c1 (no-ff)' '
test_debug 'gitk --all'
+test_expect_success 'combining --squash and --no-ff is refused' '
+ test_must_fail git merge --squash --no-ff c1 &&
+ test_must_fail git merge --no-ff --squash c1
+'
+
test_expect_success 'merge c0 with c1 (ff overrides no-ff)' '
git reset --hard c0 &&
git config branch.master.mergeoptions "--no-ff" &&
diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh
new file mode 100644
index 000000000..6b0483f3e
--- /dev/null
+++ b/t/t7610-mergetool.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Charles Bailey
+#
+
+test_description='git-mergetool
+
+Testing basic merge tool invocation'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ echo master >file1 &&
+ git add file1 &&
+ git commit -m "added file1" &&
+ git checkout -b branch1 master &&
+ echo branch1 change >file1 &&
+ echo branch1 newfile >file2 &&
+ git add file1 file2 &&
+ git commit -m "branch1 changes" &&
+ git checkout -b branch2 master &&
+ echo branch2 change >file1 &&
+ echo branch2 newfile >file2 &&
+ git add file1 file2 &&
+ git commit -m "branch2 changes" &&
+ git checkout master &&
+ echo master updated >file1 &&
+ echo master new >file2 &&
+ git add file1 file2 &&
+ git commit -m "master updates"
+'
+
+test_expect_success 'custom mergetool' '
+ git config merge.tool mytool &&
+ git config mergetool.mytool.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" &&
+ git config mergetool.mytool.trustExitCode true &&
+ git checkout branch1 &&
+ ! git merge master >/dev/null 2>&1 &&
+ ( yes "" | git mergetool file1>/dev/null 2>&1 ) &&
+ ( yes "" | git mergetool file2>/dev/null 2>&1 ) &&
+ test "$(cat file1)" = "master updated" &&
+ test "$(cat file2)" = "master new" &&
+ git commit -m "branch1 resolved with mergetool"
+'
+
+test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 90df619b9..87a5ea4a6 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -80,7 +80,7 @@ do
-q|--q|--qu|--qui|--quie|--quiet)
quiet=t; shift ;;
--no-color)
- color=; shift ;;
+ color=; shift ;;
--no-python)
# noop now...
shift ;;
@@ -142,7 +142,12 @@ test_count=0
test_fixed=0
test_broken=0
-trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit
+die () {
+ echo >&5 "FATAL: Unexpected exit with code $?"
+ exit 1
+}
+
+trap 'die' exit
test_tick () {
if test -z "${test_tick+set}"
@@ -359,6 +364,8 @@ if ! test -x ../test-chmtime; then
exit 1
fi
+. ../GIT-BUILD-OPTIONS
+
# Test repository
test=trash
rm -fr "$test"
diff --git a/tag.c b/tag.c
index 990134fe7..4470d2bf7 100644
--- a/tag.c
+++ b/tag.c
@@ -87,12 +87,6 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
item->tagged = NULL;
}
- if (item->tagged && track_object_refs) {
- struct object_refs *refs = alloc_object_refs(1);
- refs->ref[0] = item->tagged;
- set_object_refs(&item->object, refs);
- }
-
return 0;
}
diff --git a/transport.c b/transport.c
index 397983d11..166c1d1d4 100644
--- a/transport.c
+++ b/transport.c
@@ -442,7 +442,8 @@ static struct ref *get_refs_via_curl(struct transport *transport)
struct ref *last_ref = NULL;
if (!transport->data)
- transport->data = get_http_walker(transport->url);
+ transport->data = get_http_walker(transport->url,
+ transport->remote);
refs_url = xmalloc(strlen(transport->url) + 11);
sprintf(refs_url, "%s/info/refs", transport->url);
@@ -453,9 +454,6 @@ static struct ref *get_refs_via_curl(struct transport *transport)
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
- if (transport->remote->http_proxy)
- curl_easy_setopt(slot->curl, CURLOPT_PROXY,
- transport->remote->http_proxy);
if (start_active_slot(slot)) {
run_active_slot(slot);
@@ -509,7 +507,8 @@ static int fetch_objs_via_curl(struct transport *transport,
int nr_objs, struct ref **to_fetch)
{
if (!transport->data)
- transport->data = get_http_walker(transport->url);
+ transport->data = get_http_walker(transport->url,
+ transport->remote);
return fetch_objs_via_walker(transport, nr_objs, to_fetch);
}
@@ -622,6 +621,7 @@ static int fetch_refs_via_pack(struct transport *transport,
char *dest = xstrdup(transport->url);
struct fetch_pack_args args;
int i;
+ struct ref *refs_tmp = NULL;
memset(&args, 0, sizeof(args));
args.uploadpack = data->uploadpack;
@@ -634,15 +634,13 @@ static int fetch_refs_via_pack(struct transport *transport,
for (i = 0; i < nr_heads; i++)
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
- refs = transport_get_remote_refs(transport);
if (!data->conn) {
- struct ref *refs_tmp;
connect_setup(transport);
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0);
- free_refs(refs_tmp);
}
- refs = fetch_pack(&args, data->fd, data->conn, transport->remote_refs,
+ refs = fetch_pack(&args, data->fd, data->conn,
+ refs_tmp ? refs_tmp : transport->remote_refs,
dest, nr_heads, heads, &transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);
@@ -650,6 +648,8 @@ static int fetch_refs_via_pack(struct transport *transport,
refs = NULL;
data->conn = NULL;
+ free_refs(refs_tmp);
+
for (i = 0; i < nr_heads; i++)
free(origh[i]);
free(origh);
diff --git a/tree.c b/tree.c
index 87708ef42..4b1825c2a 100644
--- a/tree.c
+++ b/tree.c
@@ -202,52 +202,6 @@ struct tree *lookup_tree(const unsigned char *sha1)
return (struct tree *) obj;
}
-/*
- * NOTE! Tree refs to external git repositories
- * (ie gitlinks) do not count as real references.
- *
- * You don't have to have those repositories
- * available at all, much less have the objects
- * accessible from the current repository.
- */
-static void track_tree_refs(struct tree *item)
-{
- int n_refs = 0, i;
- struct object_refs *refs;
- struct tree_desc desc;
- struct name_entry entry;
-
- /* Count how many entries there are.. */
- init_tree_desc(&desc, item->buffer, item->size);
- while (tree_entry(&desc, &entry)) {
- if (S_ISGITLINK(entry.mode))
- continue;
- n_refs++;
- }
-
- /* Allocate object refs and walk it again.. */
- i = 0;
- refs = alloc_object_refs(n_refs);
- init_tree_desc(&desc, item->buffer, item->size);
- while (tree_entry(&desc, &entry)) {
- struct object *obj;
-
- if (S_ISGITLINK(entry.mode))
- continue;
- if (S_ISDIR(entry.mode))
- obj = &lookup_tree(entry.sha1)->object;
- else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode))
- obj = &lookup_blob(entry.sha1)->object;
- else {
- warning("in tree %s: entry %s has bad mode %.6o\n",
- sha1_to_hex(item->object.sha1), entry.path, entry.mode);
- obj = lookup_unknown_object(entry.sha1);
- }
- refs->ref[i++] = obj;
- }
- set_object_refs(&item->object, refs);
-}
-
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
{
if (item->object.parsed)
@@ -256,8 +210,6 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
item->buffer = buffer;
item->size = size;
- if (track_object_refs)
- track_tree_refs(item);
return 0;
}
diff --git a/upload-pack.c b/upload-pack.c
index b26d05331..e5421db9c 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -393,7 +393,6 @@ static int get_common_commits(void)
char hex[41], last_hex[41];
int len;
- track_object_refs = 0;
save_commit_buffer = 0;
for(;;) {
diff --git a/walker.c b/walker.c
index adc3e80ce..c10eca882 100644
--- a/walker.c
+++ b/walker.c
@@ -256,7 +256,6 @@ int walker_fetch(struct walker *walker, int targets, char **target,
int i;
save_commit_buffer = 0;
- track_object_refs = 0;
for (i = 0; i < targets; i++) {
if (!write_ref || !write_ref[i])
diff --git a/walker.h b/walker.h
index ea2c363f4..e1d40deaf 100644
--- a/walker.h
+++ b/walker.h
@@ -1,6 +1,8 @@
#ifndef WALKER_H
#define WALKER_H
+#include "remote.h"
+
struct walker {
void *data;
int (*fetch_ref)(struct walker *, char *ref, unsigned char *sha1);
@@ -32,6 +34,6 @@ int walker_fetch(struct walker *impl, int targets, char **target,
void walker_free(struct walker *walker);
-struct walker *get_http_walker(const char *url);
+struct walker *get_http_walker(const char *url, struct remote *remote);
#endif /* WALKER_H */