mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit 'mingw/master' into work/merge-mingw
Conflicts: Makefile help.c moved msysgit specific code to show_html_page and call show_html_page per default.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,6 +12,7 @@ git-archive
|
||||
git-bisect
|
||||
git-blame
|
||||
git-branch
|
||||
git-browse-help
|
||||
git-bundle
|
||||
git-cat-file
|
||||
git-check-attr
|
||||
|
||||
@@ -5,7 +5,11 @@ MAN1_TXT= \
|
||||
MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt
|
||||
MAN7_TXT=git.txt
|
||||
|
||||
DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT))
|
||||
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
|
||||
MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
|
||||
MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
|
||||
|
||||
DOC_HTML=$(MAN_HTML)
|
||||
|
||||
ARTICLES = tutorial
|
||||
ARTICLES += tutorial-2
|
||||
@@ -29,6 +33,7 @@ DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
|
||||
|
||||
prefix?=$(HOME)
|
||||
bindir?=$(prefix)/bin
|
||||
htmldir?=$(prefix)/share/doc/git-doc
|
||||
mandir?=$(prefix)/share/man
|
||||
man1dir=$(mandir)/man1
|
||||
man5dir=$(mandir)/man5
|
||||
@@ -79,7 +84,7 @@ man1: $(DOC_MAN1)
|
||||
man5: $(DOC_MAN5)
|
||||
man7: $(DOC_MAN7)
|
||||
|
||||
info: git.info
|
||||
info: git.info gitman.info
|
||||
|
||||
install: man
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
|
||||
@@ -91,13 +96,17 @@ install: man
|
||||
|
||||
install-info: info
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
|
||||
$(INSTALL) -m 644 git.info $(DESTDIR)$(infodir)
|
||||
$(INSTALL) -m 644 git.info gitman.info $(DESTDIR)$(infodir)
|
||||
if test -r $(DESTDIR)$(infodir)/dir; then \
|
||||
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) git.info ;\
|
||||
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) gitman.info ;\
|
||||
else \
|
||||
echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
|
||||
fi
|
||||
|
||||
install-html: html
|
||||
sh ./install-webdoc.sh $(DESTDIR)$(htmldir)
|
||||
|
||||
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
$(MAKE) -C ../ GIT-VERSION-FILE
|
||||
|
||||
@@ -161,12 +170,27 @@ XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
|
||||
user-manual.html: user-manual.xml
|
||||
xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
|
||||
|
||||
git.info: user-manual.xml
|
||||
$(RM) $@ $*.texi $*.texi+
|
||||
$(DOCBOOK2X_TEXI) user-manual.xml --to-stdout >$*.texi+
|
||||
$(PERL_PATH) fix-texi.perl <$*.texi+ >$*.texi
|
||||
git.info: user-manual.texi
|
||||
$(MAKEINFO) --no-split -o $@ user-manual.texi
|
||||
|
||||
user-manual.texi: user-manual.xml
|
||||
$(RM) $@+ $@
|
||||
$(DOCBOOK2X_TEXI) user-manual.xml --to-stdout | $(PERL_PATH) fix-texi.perl >$@+
|
||||
mv $@+ $@
|
||||
|
||||
gitman.texi: $(MAN_XML) cat-texi.perl
|
||||
$(RM) $@+ $@
|
||||
($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --to-stdout $(xml);)) | \
|
||||
$(PERL_PATH) cat-texi.perl $@ >$@+
|
||||
mv $@+ $@
|
||||
|
||||
gitman.info: gitman.texi
|
||||
$(MAKEINFO) --no-split $*.texi
|
||||
$(RM) $*.texi $*.texi+
|
||||
|
||||
$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
|
||||
$(RM) $@+ $@
|
||||
$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+
|
||||
mv $@+ $@
|
||||
|
||||
howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
||||
$(RM) $@+ $@
|
||||
|
||||
@@ -132,6 +132,10 @@ Updates since v1.5.3
|
||||
variable used to mean "do not require -f option to lose untracked
|
||||
files", but we now use the safer default).
|
||||
|
||||
* The kinds of whitespace errors "git diff" and "git apply" notice (and
|
||||
fix) can be controlled via 'core.whitespace' configuration variable
|
||||
and 'whitespace' attribute in .gitattributes file.
|
||||
|
||||
* "git push" learned --dry-run option to show what would happen if a
|
||||
push is run.
|
||||
|
||||
@@ -200,6 +204,12 @@ Updates since v1.5.3
|
||||
|
||||
* "git bisect" learned "skip" action to mark untestable commits.
|
||||
|
||||
* "git bisect visualize" learned a shorter synonym "git bisect view".
|
||||
|
||||
* "git bisect visualize" runs "git log" in a non-windowed
|
||||
environments. It also can be told what command to run (e.g. "git
|
||||
bisect visualize tig").
|
||||
|
||||
* "git format-patch" learned "format.numbered" configuration variable
|
||||
to automatically turn --numbered option on when more than one commits
|
||||
are formatted.
|
||||
@@ -220,6 +230,9 @@ Updates since v1.5.3
|
||||
* "git checkout" from a subdirectory learned to use "../path" to allow
|
||||
checking out a path outside the current directory without cd'ing up.
|
||||
|
||||
* "git checkout" from and to detached HEAD leaves a bit more
|
||||
information in the reflog.
|
||||
|
||||
* "git send-email --dry-run" shows full headers for easier diagnosis.
|
||||
|
||||
* "git merge-ours" is now built-in.
|
||||
@@ -233,11 +246,26 @@ Updates since v1.5.3
|
||||
descriptive name from From: and Signed-off-by: lines in the commit
|
||||
message.
|
||||
|
||||
* "git status" from a subdirectory now shows relative paths which makes
|
||||
copy-and-pasting for git-checkout/git-add/git-rm easier.
|
||||
* "git svn" wasted way too much disk to record revision mappings
|
||||
between svn and git; a new representation that is much more compact
|
||||
for this information has been introduced to correct this.
|
||||
|
||||
* "git checkout" from and to detached HEAD leaves a bit more
|
||||
information in the reflog.
|
||||
* "git status" from a subdirectory now shows relative paths, which
|
||||
makes copy-and-pasting for git-checkout/git-add/git-rm easier. The
|
||||
traditional behaviour to show the full path relative to the top of
|
||||
the work tree can be had by setting status.relativepaths
|
||||
configuration variable to true.
|
||||
|
||||
* "git blame" kept text for each annotated revision in core needlessly;
|
||||
this has been corrected.
|
||||
|
||||
* "git shortlog" learned to default to HEAD when the standard input is
|
||||
a terminal and the user did not give any revision parameter.
|
||||
|
||||
* "git shortlog" learned "-e" option to show e-mail addresses as well as
|
||||
authors' names.
|
||||
|
||||
* "git help" learned "-w" option to show documentation in browsers.
|
||||
|
||||
* In addition there are quite a few internal clean-ups. Notably
|
||||
|
||||
@@ -266,6 +294,6 @@ series.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.3.7-1111-gd9f4059
|
||||
O=v1.5.4-rc0
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
38
Documentation/cat-texi.perl
Executable file
38
Documentation/cat-texi.perl
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
my @menu = ();
|
||||
my $output = $ARGV[0];
|
||||
|
||||
open TMP, '>', "$output.tmp";
|
||||
|
||||
while (<STDIN>) {
|
||||
next if (/^\\input texinfo/../\@node Top/);
|
||||
next if (/^\@bye/ || /^\.ft/);
|
||||
if (s/^\@top (.*)/\@node $1,,,Top/) {
|
||||
push @menu, $1;
|
||||
}
|
||||
s/\(\@pxref{\[URLS\]}\)//;
|
||||
print TMP;
|
||||
}
|
||||
close TMP;
|
||||
|
||||
printf '\input texinfo
|
||||
@setfilename gitman.info
|
||||
@documentencoding us-ascii
|
||||
@node Top,,%s
|
||||
@top Git Manual Pages
|
||||
@documentlanguage en
|
||||
@menu
|
||||
', $menu[0];
|
||||
|
||||
for (@menu) {
|
||||
print "* ${_}::\n";
|
||||
}
|
||||
print "\@end menu\n";
|
||||
open TMP, '<', "$output.tmp";
|
||||
while (<TMP>) {
|
||||
print;
|
||||
}
|
||||
close TMP;
|
||||
print "\@bye\n";
|
||||
unlink "$output.tmp";
|
||||
@@ -295,6 +295,20 @@ core.pager::
|
||||
The command that git will use to paginate output. Can be overridden
|
||||
with the `GIT_PAGER` environment variable.
|
||||
|
||||
core.whitespace::
|
||||
A comma separated list of common whitespace problems to
|
||||
notice. `git diff` will use `color.diff.whitespace` to
|
||||
highlight them, and `git apply --whitespace=error` will
|
||||
consider them as errors:
|
||||
+
|
||||
* `trailing-space` treats trailing whitespaces at the end of the line
|
||||
as an error (enabled by default).
|
||||
* `space-before-tab` treats a space character that appears immediately
|
||||
before a tab character in the initial indent part of the line as an
|
||||
error (enabled by default).
|
||||
* `indent-with-non-tab` treats a line that is indented with 8 or more
|
||||
space characters that can be replaced with tab characters.
|
||||
|
||||
alias.*::
|
||||
Command aliases for the gitlink:git[1] command wrapper - e.g.
|
||||
after defining "alias.last = cat-file commit HEAD", the invocation
|
||||
@@ -387,8 +401,8 @@ color.diff.<slot>::
|
||||
which part of the patch to use the specified color, and is one
|
||||
of `plain` (context text), `meta` (metainformation), `frag`
|
||||
(hunk header), `old` (removed lines), `new` (added lines),
|
||||
`commit` (commit headers), or `whitespace` (highlighting dubious
|
||||
whitespace). The values of these variables may be specified as
|
||||
`commit` (commit headers), or `whitespace` (highlighting
|
||||
whitespace errors). The values of these variables may be specified as
|
||||
in color.branch.<slot>.
|
||||
|
||||
color.interactive::
|
||||
@@ -762,6 +776,12 @@ showbranch.default::
|
||||
The default set of branches for gitlink:git-show-branch[1].
|
||||
See gitlink:git-show-branch[1].
|
||||
|
||||
status.relativePaths::
|
||||
By default, gitlink:git-status[1] shows paths relative to the
|
||||
current directory. Setting this variable to `false` shows paths
|
||||
relative to the repository root (this was the default for git
|
||||
prior to v1.5.4).
|
||||
|
||||
tar.umask::
|
||||
This variable can be used to restrict the permission bits of
|
||||
tar archive entries. The default is 0002, which turns off the
|
||||
|
||||
@@ -84,3 +84,64 @@ all parents.
|
||||
|
||||
|
||||
include::diff-generate-patch.txt[]
|
||||
|
||||
|
||||
other diff formats
|
||||
------------------
|
||||
|
||||
The `--summary` option describes newly added, deleted, renamed and
|
||||
copied files. The `--stat` option adds diffstat(1) graph to the
|
||||
output. These options can be combined with other options, such as
|
||||
`-p`, and are meant for human consumption.
|
||||
|
||||
When showing a change that involves a rename or a copy, `--stat` output
|
||||
formats the pathnames compactly by combining common prefix and suffix of
|
||||
the pathnames. For example, a change that moves `arch/i386/Makefile` to
|
||||
`arch/x86/Makefile` while modifying 4 lines will be shown like this:
|
||||
|
||||
------------------------------------
|
||||
arch/{i386 => x86}/Makefile | 4 +--
|
||||
------------------------------------
|
||||
|
||||
The `--numstat` option gives the diffstat(1) information but is designed
|
||||
for easier machine consumption. An entry in `--numstat` output looks
|
||||
like this:
|
||||
|
||||
----------------------------------------
|
||||
1 2 README
|
||||
3 1 arch/{i386 => x86}/Makefile
|
||||
----------------------------------------
|
||||
|
||||
That is, from left to right:
|
||||
|
||||
. the number of added lines;
|
||||
. a tab;
|
||||
. the number of deleted lines;
|
||||
. a tab;
|
||||
. pathname (possibly with rename/copy information);
|
||||
. a newline.
|
||||
|
||||
When `-z` output option is in effect, the output is formatted this way:
|
||||
|
||||
----------------------------------------
|
||||
1 2 README NUL
|
||||
3 1 NUL arch/i386/Makefile NUL arch/x86/Makefile NUL
|
||||
----------------------------------------
|
||||
|
||||
That is:
|
||||
|
||||
. the number of added lines;
|
||||
. a tab;
|
||||
. the number of deleted lines;
|
||||
. a tab;
|
||||
. a NUL (only exists if renamed/copied);
|
||||
. pathname in preimage;
|
||||
. a NUL (only exists if renamed/copied);
|
||||
. pathname in postimage (only exists if renamed/copied);
|
||||
. a NUL.
|
||||
|
||||
The extra `NUL` before the preimage path in renamed case is to allow
|
||||
scripts that read the output to tell if the current record being read is
|
||||
a single-path record or a rename/copy record without reading ahead.
|
||||
After reading added and deleted lines, reading up to `NUL` would yield
|
||||
the pathname, but if that is `NUL`, the record will show two paths.
|
||||
|
||||
@@ -175,19 +175,19 @@ endif::git-format-patch[]
|
||||
Shorthand for "--text".
|
||||
|
||||
--ignore-space-at-eol::
|
||||
Ignore changes in white spaces at EOL.
|
||||
Ignore changes in whitespace at EOL.
|
||||
|
||||
--ignore-space-change::
|
||||
Ignore changes in amount of white space. This ignores white
|
||||
space at line end, and consider all other sequences of one or
|
||||
more white space characters to be equivalent.
|
||||
Ignore changes in amount of whitespace. This ignores whitespace
|
||||
at line end, and considers all other sequences of one or
|
||||
more whitespace characters to be equivalent.
|
||||
|
||||
-b::
|
||||
Shorthand for "--ignore-space-change".
|
||||
|
||||
--ignore-all-space::
|
||||
Ignore white space when comparing lines. This ignores
|
||||
difference even if one line has white space where the other
|
||||
Ignore whitespace when comparing lines. This ignores
|
||||
differences even if one line has whitespace where the other
|
||||
line has none.
|
||||
|
||||
-w::
|
||||
|
||||
@@ -65,7 +65,7 @@ OPTIONS
|
||||
operation to a subset of the working tree. See ``Interactive
|
||||
mode'' for details.
|
||||
|
||||
-p, \--patch:
|
||||
-p, \--patch::
|
||||
Similar to Interactive mode but the initial command loop is
|
||||
bypassed and the 'patch' subcommand is invoked using each of
|
||||
the specified filepatterns before exiting.
|
||||
|
||||
@@ -13,7 +13,7 @@ SYNOPSIS
|
||||
[--apply] [--no-add] [--build-fake-ancestor <file>] [-R | --reverse]
|
||||
[--allow-binary-replacement | --binary] [--reject] [-z]
|
||||
[-pNUM] [-CNUM] [--inaccurate-eof] [--cached]
|
||||
[--whitespace=<nowarn|warn|error|error-all|strip>]
|
||||
[--whitespace=<nowarn|warn|fix|error|error-all>]
|
||||
[--exclude=PATH] [--verbose] [<patch>...]
|
||||
|
||||
DESCRIPTION
|
||||
@@ -119,7 +119,7 @@ discouraged.
|
||||
|
||||
--no-add::
|
||||
When applying a patch, ignore additions made by the
|
||||
patch. This can be used to extract common part between
|
||||
patch. This can be used to extract the common part between
|
||||
two files by first running `diff` on them and applying
|
||||
the result with this option, which would apply the
|
||||
deletion part but not addition part.
|
||||
@@ -135,25 +135,32 @@ discouraged.
|
||||
be useful when importing patchsets, where you want to exclude certain
|
||||
files or directories.
|
||||
|
||||
--whitespace=<option>::
|
||||
When applying a patch, detect a new or modified line
|
||||
that ends with trailing whitespaces (this includes a
|
||||
line that solely consists of whitespaces). By default,
|
||||
the command outputs warning messages and applies the
|
||||
patch.
|
||||
When gitlink:git-apply[1] is used for statistics and not applying a
|
||||
patch, it defaults to `nowarn`.
|
||||
You can use different `<option>` to control this
|
||||
behavior:
|
||||
--whitespace=<action>::
|
||||
When applying a patch, detect a new or modified line that has
|
||||
whitespace errors. What are considered whitespace errors is
|
||||
controlled by `core.whitespace` configuration. By default,
|
||||
trailing whitespaces (including lines that solely consist of
|
||||
whitespaces) and a space character that is immediately followed
|
||||
by a tab character inside the initial indent of the line are
|
||||
considered whitespace errors.
|
||||
+
|
||||
By default, the command outputs warning messages but applies the patch.
|
||||
When gitlink:git-apply[1] is used for statistics and not applying a
|
||||
patch, it defaults to `nowarn`.
|
||||
+
|
||||
You can use different `<action>` to control this
|
||||
behavior:
|
||||
+
|
||||
* `nowarn` turns off the trailing whitespace warning.
|
||||
* `warn` outputs warnings for a few such errors, but applies the
|
||||
patch (default).
|
||||
patch as-is (default).
|
||||
* `fix` outputs warnings for a few such errors, and applies the
|
||||
patch after fixing them (`strip` is a synonym --- the tool
|
||||
used to consider only trailing whitespaces as errors, and the
|
||||
fix involved 'stripping' them, but modern gits do more).
|
||||
* `error` outputs warnings for a few such errors, and refuses
|
||||
to apply the patch.
|
||||
* `error-all` is similar to `error` but shows all errors.
|
||||
* `strip` outputs warnings for a few such errors, strips out the
|
||||
trailing whitespaces and applies the patch.
|
||||
|
||||
--inaccurate-eof::
|
||||
Under certain circumstances, some versions of diff do not correctly
|
||||
|
||||
@@ -92,7 +92,16 @@ During the bisection process, you can say
|
||||
$ git bisect visualize
|
||||
------------
|
||||
|
||||
to see the currently remaining suspects in `gitk`.
|
||||
to see the currently remaining suspects in `gitk`. `visualize` is a bit
|
||||
too long to type and `view` is provided as a synonym.
|
||||
|
||||
If `DISPLAY` environment variable is not set, `git log` is used
|
||||
instead. You can even give command line options such as `-p` and
|
||||
`--stat`.
|
||||
|
||||
------------
|
||||
$ git bisect view --stat
|
||||
------------
|
||||
|
||||
Bisect log and bisect replay
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -86,7 +86,7 @@ OPTIONS
|
||||
Add Signed-off-by line at the end of the commit message.
|
||||
|
||||
--no-verify::
|
||||
This option bypasses the pre-commit hook.
|
||||
This option bypasses the pre-commit and commit-msg hooks.
|
||||
See also link:hooks.html[hooks].
|
||||
|
||||
--allow-empty::
|
||||
|
||||
@@ -7,7 +7,7 @@ git-help - display help information about git
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git help' [-a|--all] [COMMAND]
|
||||
'git help' [-a|--all|-i|--info|-w|--web] [COMMAND]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -20,7 +20,8 @@ If the option '--all' or '-a' is given, then all available commands are
|
||||
printed on the standard output.
|
||||
|
||||
If a git command is named, a manual page for that command is brought
|
||||
up. The 'man' program is used by default for this purpose.
|
||||
up. The 'man' program is used by default for this purpose, but this
|
||||
can be overriden by other options.
|
||||
|
||||
Note that 'git --help ...' is identical as 'git help ...' because the
|
||||
former is internally converted into the latter.
|
||||
@@ -28,10 +29,31 @@ former is internally converted into the latter.
|
||||
OPTIONS
|
||||
-------
|
||||
-a|--all::
|
||||
|
||||
Prints all the available commands on the standard output. This
|
||||
option superseeds any other option.
|
||||
|
||||
-i|--info::
|
||||
Use the 'info' program to display the manual page, instead of
|
||||
the 'man' program that is used by default.
|
||||
|
||||
-w|--web::
|
||||
Use a web browser to display the HTML manual page, instead of
|
||||
the 'man' program that is used by default.
|
||||
+
|
||||
The web browser can be specified using the configuration variable
|
||||
'help.browser', or 'web.browser' if the former is not set. If none of
|
||||
these config variables is set, the 'git-browse-help' script (called by
|
||||
'git-help') will pick a suitable default.
|
||||
+
|
||||
You can explicitly provide a full path to your prefered browser by
|
||||
setting the configuration variable 'browser.<tool>.path'. For example,
|
||||
you can configure the absolute path to firefox by setting
|
||||
'browser.firefox.path'. Otherwise, 'git-browse-help' assumes the tool
|
||||
is available in PATH.
|
||||
+
|
||||
Note that the script tries, as much as possible, to display the HTML
|
||||
page in a new tab on an already opened browser.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <gitster@pobox.com> and the git-list
|
||||
|
||||
@@ -71,6 +71,9 @@ You may specify configuration in your .git/config
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
If the configuration variable 'instaweb.browser' is not set,
|
||||
'web.browser' will be used instead if it is defined.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Eric Wong <normalperson@yhbt.net>
|
||||
|
||||
@@ -8,8 +8,8 @@ git-shortlog - Summarize 'git log' output
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s]
|
||||
git-shortlog [-n|--numbered] [-s|--summary] [<committish>...]
|
||||
git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e]
|
||||
git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [<committish>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -32,6 +32,9 @@ OPTIONS
|
||||
-s, \--summary::
|
||||
Suppress commit description and provide a commit count summary only.
|
||||
|
||||
-e, \--email::
|
||||
Show the email address of each author.
|
||||
|
||||
FILES
|
||||
-----
|
||||
|
||||
|
||||
@@ -12,37 +12,32 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Examines paths in the working tree that has changes unrecorded
|
||||
to the index file, and changes between the index file and the
|
||||
current HEAD commit. The former paths are what you _could_
|
||||
commit by running 'git add' before running 'git
|
||||
commit', and the latter paths are what you _would_ commit by
|
||||
running 'git commit'.
|
||||
|
||||
If there is no path that is different between the index file and
|
||||
the current HEAD commit, the command exits with non-zero
|
||||
status.
|
||||
Displays paths that have differences between the index file and the
|
||||
current HEAD commit, paths that have differences between the working
|
||||
tree and the index file, and paths in the working tree that are not
|
||||
tracked by git (and are not ignored by gitlink:gitignore[5]). The first
|
||||
are what you _would_ commit by running `git commit`; the second and
|
||||
third are what you _could_ commit by running `git add` before running
|
||||
`git commit`.
|
||||
|
||||
The command takes the same set of options as `git-commit`; it
|
||||
shows what would be committed if the same options are given to
|
||||
`git-commit`.
|
||||
|
||||
If any paths have been touched in the working tree (that is,
|
||||
their modification times have changed) but their contents and
|
||||
permissions are identical to those in the index file, the command
|
||||
updates the index file. Running `git-status` can thus speed up
|
||||
subsequent operations such as `git-diff` if the working tree
|
||||
contains many paths that have been touched but not modified.
|
||||
If there is no path that is different between the index file and
|
||||
the current HEAD commit (i.e., there is nothing to commit by running
|
||||
`git-commit`), the command exits with non-zero status.
|
||||
|
||||
|
||||
OUTPUT
|
||||
------
|
||||
The output from this command is designed to be used as a commit
|
||||
template comments, and all the output lines are prefixed with '#'.
|
||||
template comment, and all the output lines are prefixed with '#'.
|
||||
|
||||
The paths mentioned in the output, unlike many other git commands, are
|
||||
made relative to the current directory, if you are working in a
|
||||
subdirectory (this is on purpose, to help cutting and pasting).
|
||||
made relative to the current directory if you are working in a
|
||||
subdirectory (this is on purpose, to help cutting and pasting). See
|
||||
the status.relativePaths config option below.
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
@@ -53,6 +48,10 @@ mean the same thing and the latter is kept for backward
|
||||
compatibility) and `color.status.<slot>` configuration variables
|
||||
to colorize its output.
|
||||
|
||||
If the config variable `status.relativePaths` is set to false, then all
|
||||
paths shown are relative to the repository root, not to the current
|
||||
directory.
|
||||
|
||||
See Also
|
||||
--------
|
||||
gitlink:gitignore[5]
|
||||
|
||||
@@ -104,6 +104,11 @@ OPTIONS
|
||||
commands. If the option '--all' or '-a' is given then all
|
||||
available commands are printed. If a git command is named this
|
||||
option will bring up the manual page for that command.
|
||||
+
|
||||
Other options are available to control how the manual page is
|
||||
displayed. See gitlink:git-help[1] for more information,
|
||||
because 'git --help ...' is converted internally into 'git
|
||||
help ...'.
|
||||
|
||||
--exec-path::
|
||||
Path to wherever your core git programs are installed.
|
||||
|
||||
@@ -361,6 +361,37 @@ When left unspecified, the driver itself is used for both
|
||||
internal merge and the final merge.
|
||||
|
||||
|
||||
Checking whitespace errors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
`whitespace`
|
||||
^^^^^^^^^^^^
|
||||
|
||||
The `core.whitespace` configuration variable allows you to define what
|
||||
`diff` and `apply` should consider whitespace errors for all paths in
|
||||
the project (See gitlink:git-config[1]). This attribute gives you finer
|
||||
control per path.
|
||||
|
||||
Set::
|
||||
|
||||
Notice all types of potential whitespace errors known to git.
|
||||
|
||||
Unset::
|
||||
|
||||
Do not notice anything as error.
|
||||
|
||||
Unspecified::
|
||||
|
||||
Use the value of `core.whitespace` configuration variable to
|
||||
decide what to notice as error.
|
||||
|
||||
String::
|
||||
|
||||
Specify a comma separate list of common whitespace problems to
|
||||
notice in the same format as `core.whitespace` configuration
|
||||
variable.
|
||||
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
|
||||
|
||||
@@ -244,8 +244,7 @@ This commit is referred to as a "merge commit", or sometimes just a
|
||||
The unique identifier of an <<def_object,object>>. The <<def_hash,hash>>
|
||||
of the object's contents using the Secure Hash Algorithm
|
||||
1 and usually represented by the 40 character hexadecimal encoding of
|
||||
the <<def_hash,hash>> of the object (possibly followed by
|
||||
a white space).
|
||||
the <<def_hash,hash>> of the object.
|
||||
|
||||
[[def_object_type]]object type::
|
||||
One of the identifiers
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.3.GIT
|
||||
DEF_VER=v1.5.4-rc0.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
21
Makefile
21
Makefile
@@ -157,9 +157,12 @@ STRIP ?= strip
|
||||
|
||||
prefix =
|
||||
bindir = $(prefix)/bin
|
||||
mandir = $(prefix)/share/man
|
||||
infodir = $(prefix)/share/info
|
||||
gitexecdir = $(bindir)
|
||||
sharedir = $(prefix)/share
|
||||
template_dir = $(sharedir)/git-core/templates
|
||||
htmldir=$(sharedir)/doc/git-doc
|
||||
ifeq ($(prefix),/usr)
|
||||
sysconfdir = /etc
|
||||
else
|
||||
@@ -186,7 +189,7 @@ GITWEB_FAVICON = git-favicon.png
|
||||
GITWEB_SITE_HEADER =
|
||||
GITWEB_SITE_FOOTER =
|
||||
|
||||
export prefix bindir gitexecdir sharedir template_dir sysconfdir
|
||||
export prefix bindir gitexecdir sharedir template_dir htmldir sysconfdir
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
@@ -226,7 +229,8 @@ SCRIPT_SH = \
|
||||
git-merge-resolve.sh \
|
||||
git-lost-found.sh git-quiltimport.sh git-submodule.sh \
|
||||
git-filter-branch.sh \
|
||||
git-stash.sh
|
||||
git-stash.sh \
|
||||
git-browse-help.sh
|
||||
|
||||
SCRIPT_PERL = \
|
||||
git-add--interactive.perl \
|
||||
@@ -314,7 +318,7 @@ LIB_OBJS = \
|
||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_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
|
||||
transport.o bundle.o walker.o parse-options.o ws.o
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
@@ -787,8 +791,11 @@ ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG))
|
||||
|
||||
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
|
||||
bindir_SQ = $(subst ','\'',$(bindir))
|
||||
mandir_SQ = $(subst ','\'',$(mandir))
|
||||
infodir_SQ = $(subst ','\'',$(infodir))
|
||||
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
|
||||
template_dir_SQ = $(subst ','\'',$(template_dir))
|
||||
htmldir_SQ = $(subst ','\'',$(htmldir))
|
||||
prefix_SQ = $(subst ','\'',$(prefix))
|
||||
sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
|
||||
|
||||
@@ -834,7 +841,10 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
|
||||
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
|
||||
|
||||
help.o: common-cmds.h
|
||||
help.o: help.c common-cmds.h GIT-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
|
||||
'-DGIT_MAN_PATH="$(mandir_SQ)"' \
|
||||
'-DGIT_INFO_PATH="$(infodir_SQ)"' $<
|
||||
|
||||
git-merge-subtree$X: git-merge-recursive$X
|
||||
$(QUIET_BUILT_IN)$(RM) $@ && ln git-merge-recursive$X $@
|
||||
@@ -853,6 +863,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
-e 's|@@HTMLDIR@@|$(htmldir_SQ)|g' \
|
||||
-e 's/@@NO_HARDLINKS@@/$(NO_HARDLINKS)/g' \
|
||||
$@.sh >$@+ && \
|
||||
chmod +x $@+ && \
|
||||
@@ -1068,7 +1079,7 @@ install: all
|
||||
GIT_CONFIG='$(DESTDIR_SQ)$(sysconfdir_SQ)/gitconfig' \
|
||||
$(DESTDIR_SQ)$(bindir_SQ)/git$X config core.symlinks false
|
||||
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
|
||||
$(MAKE) -C perl prefix='$(prefix_SQ)' install
|
||||
$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
|
||||
ifndef NO_TCLTK
|
||||
$(MAKE) -C gitk-git install
|
||||
$(MAKE) -C git-gui install
|
||||
|
||||
234
builtin-apply.c
234
builtin-apply.c
@@ -45,14 +45,14 @@ static const char *fake_ancestor;
|
||||
static int line_termination = '\n';
|
||||
static unsigned long p_context = ULONG_MAX;
|
||||
static const char apply_usage[] =
|
||||
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
|
||||
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|fix|error|error-all>] <patch>...";
|
||||
|
||||
static enum whitespace_eol {
|
||||
nowarn_whitespace,
|
||||
warn_on_whitespace,
|
||||
error_on_whitespace,
|
||||
strip_whitespace,
|
||||
} new_whitespace = warn_on_whitespace;
|
||||
static enum ws_error_action {
|
||||
nowarn_ws_error,
|
||||
warn_on_ws_error,
|
||||
die_on_ws_error,
|
||||
correct_ws_error,
|
||||
} ws_error_action = warn_on_ws_error;
|
||||
static int whitespace_error;
|
||||
static int squelch_whitespace_errors = 5;
|
||||
static int applied_after_fixing_ws;
|
||||
@@ -61,28 +61,28 @@ static const char *patch_input_file;
|
||||
static void parse_whitespace_option(const char *option)
|
||||
{
|
||||
if (!option) {
|
||||
new_whitespace = warn_on_whitespace;
|
||||
ws_error_action = warn_on_ws_error;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(option, "warn")) {
|
||||
new_whitespace = warn_on_whitespace;
|
||||
ws_error_action = warn_on_ws_error;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(option, "nowarn")) {
|
||||
new_whitespace = nowarn_whitespace;
|
||||
ws_error_action = nowarn_ws_error;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(option, "error")) {
|
||||
new_whitespace = error_on_whitespace;
|
||||
ws_error_action = die_on_ws_error;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(option, "error-all")) {
|
||||
new_whitespace = error_on_whitespace;
|
||||
ws_error_action = die_on_ws_error;
|
||||
squelch_whitespace_errors = 0;
|
||||
return;
|
||||
}
|
||||
if (!strcmp(option, "strip")) {
|
||||
new_whitespace = strip_whitespace;
|
||||
if (!strcmp(option, "strip") || !strcmp(option, "fix")) {
|
||||
ws_error_action = correct_ws_error;
|
||||
return;
|
||||
}
|
||||
die("unrecognized whitespace option '%s'", option);
|
||||
@@ -90,11 +90,8 @@ static void parse_whitespace_option(const char *option)
|
||||
|
||||
static void set_default_whitespace_mode(const char *whitespace_option)
|
||||
{
|
||||
if (!whitespace_option && !apply_default_whitespace) {
|
||||
new_whitespace = (apply
|
||||
? warn_on_whitespace
|
||||
: nowarn_whitespace);
|
||||
}
|
||||
if (!whitespace_option && !apply_default_whitespace)
|
||||
ws_error_action = (apply ? warn_on_ws_error : nowarn_ws_error);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -137,11 +134,17 @@ struct fragment {
|
||||
#define BINARY_DELTA_DEFLATED 1
|
||||
#define BINARY_LITERAL_DEFLATED 2
|
||||
|
||||
/*
|
||||
* This represents a "patch" to a file, both metainfo changes
|
||||
* such as creation/deletion, filemode and content changes represented
|
||||
* as a series of fragments.
|
||||
*/
|
||||
struct patch {
|
||||
char *new_name, *old_name, *def_name;
|
||||
unsigned int old_mode, new_mode;
|
||||
int is_new, is_delete; /* -1 = unknown, 0 = false, 1 = true */
|
||||
int rejected;
|
||||
unsigned ws_rule;
|
||||
unsigned long deflate_origlen;
|
||||
int lines_added, lines_deleted;
|
||||
int score;
|
||||
@@ -158,7 +161,8 @@ struct patch {
|
||||
struct patch *next;
|
||||
};
|
||||
|
||||
static void say_patch_name(FILE *output, const char *pre, struct patch *patch, const char *post)
|
||||
static void say_patch_name(FILE *output, const char *pre,
|
||||
struct patch *patch, const char *post)
|
||||
{
|
||||
fputs(pre, output);
|
||||
if (patch->old_name && patch->new_name &&
|
||||
@@ -229,7 +233,8 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
|
||||
if (*line == '"') {
|
||||
struct strbuf name;
|
||||
|
||||
/* Proposed "new-style" GNU patch/diff format; see
|
||||
/*
|
||||
* Proposed "new-style" GNU patch/diff format; see
|
||||
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
|
||||
*/
|
||||
strbuf_init(&name, 0);
|
||||
@@ -499,7 +504,8 @@ static int gitdiff_dissimilarity(const char *line, struct patch *patch)
|
||||
|
||||
static int gitdiff_index(const char *line, struct patch *patch)
|
||||
{
|
||||
/* index line is N hexadecimal, "..", N hexadecimal,
|
||||
/*
|
||||
* index line is N hexadecimal, "..", N hexadecimal,
|
||||
* and optional space with octal mode.
|
||||
*/
|
||||
const char *ptr, *eol;
|
||||
@@ -550,7 +556,8 @@ static const char *stop_at_slash(const char *line, int llen)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is to extract the same name that appears on "diff --git"
|
||||
/*
|
||||
* This is to extract the same name that appears on "diff --git"
|
||||
* line. We do not find and return anything if it is a rename
|
||||
* patch, and it is OK because we will find the name elsewhere.
|
||||
* We need to reliably find name only when it is mode-change only,
|
||||
@@ -584,7 +591,8 @@ static char *git_header_name(char *line, int llen)
|
||||
goto free_and_fail1;
|
||||
strbuf_remove(&first, 0, cp + 1 - first.buf);
|
||||
|
||||
/* second points at one past closing dq of name.
|
||||
/*
|
||||
* second points at one past closing dq of name.
|
||||
* find the second name.
|
||||
*/
|
||||
while ((second < line + llen) && isspace(*second))
|
||||
@@ -627,7 +635,8 @@ static char *git_header_name(char *line, int llen)
|
||||
return NULL;
|
||||
name++;
|
||||
|
||||
/* since the first name is unquoted, a dq if exists must be
|
||||
/*
|
||||
* since the first name is unquoted, a dq if exists must be
|
||||
* the beginning of the second name.
|
||||
*/
|
||||
for (second = name; second < line + llen; second++) {
|
||||
@@ -758,7 +767,7 @@ static int parse_num(const char *line, unsigned long *p)
|
||||
}
|
||||
|
||||
static int parse_range(const char *line, int len, int offset, const char *expect,
|
||||
unsigned long *p1, unsigned long *p2)
|
||||
unsigned long *p1, unsigned long *p2)
|
||||
{
|
||||
int digits, ex;
|
||||
|
||||
@@ -867,14 +876,14 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
||||
return offset;
|
||||
}
|
||||
|
||||
/** --- followed by +++ ? */
|
||||
/* --- followed by +++ ? */
|
||||
if (memcmp("--- ", line, 4) || memcmp("+++ ", line + len, 4))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We only accept unified patches, so we want it to
|
||||
* at least have "@@ -a,b +c,d @@\n", which is 14 chars
|
||||
* minimum
|
||||
* minimum ("@@ -0,0 +1 @@\n" is the shortest).
|
||||
*/
|
||||
nextlen = linelen(line + len, size - len);
|
||||
if (size < nextlen + 14 || memcmp("@@ -", line + len + nextlen, 4))
|
||||
@@ -889,7 +898,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void check_whitespace(const char *line, int len)
|
||||
static void check_whitespace(const char *line, int len, unsigned ws_rule)
|
||||
{
|
||||
const char *err = "Adds trailing whitespace";
|
||||
int seen_space = 0;
|
||||
@@ -901,23 +910,35 @@ static void check_whitespace(const char *line, int len)
|
||||
* this function. That is, an addition of an empty line would
|
||||
* check the '+' here. Sneaky...
|
||||
*/
|
||||
if (isspace(line[len-2]))
|
||||
if ((ws_rule & WS_TRAILING_SPACE) && isspace(line[len-2]))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Make sure that there is no space followed by a tab in
|
||||
* indentation.
|
||||
*/
|
||||
err = "Space in indent is followed by a tab";
|
||||
for (i = 1; i < len; i++) {
|
||||
if (line[i] == '\t') {
|
||||
if (seen_space)
|
||||
goto error;
|
||||
if (ws_rule & WS_SPACE_BEFORE_TAB) {
|
||||
err = "Space in indent is followed by a tab";
|
||||
for (i = 1; i < len; i++) {
|
||||
if (line[i] == '\t') {
|
||||
if (seen_space)
|
||||
goto error;
|
||||
}
|
||||
else if (line[i] == ' ')
|
||||
seen_space = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (line[i] == ' ')
|
||||
seen_space = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the indentation does not contain more than
|
||||
* 8 spaces.
|
||||
*/
|
||||
if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
|
||||
(8 < len) && !strncmp("+ ", line, 9)) {
|
||||
err = "Indent more than 8 places with spaces";
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -931,14 +952,14 @@ static void check_whitespace(const char *line, int len)
|
||||
err, patch_input_file, linenr, len-2, line+1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse a unified diff. Note that this really needs to parse each
|
||||
* fragment separately, since the only way to know the difference
|
||||
* between a "---" that is part of a patch, and a "---" that starts
|
||||
* the next patch is to look at the line counts..
|
||||
*/
|
||||
static int parse_fragment(char *line, unsigned long size, struct patch *patch, struct fragment *fragment)
|
||||
static int parse_fragment(char *line, unsigned long size,
|
||||
struct patch *patch, struct fragment *fragment)
|
||||
{
|
||||
int added, deleted;
|
||||
int len = linelen(line, size), offset;
|
||||
@@ -979,22 +1000,23 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
|
||||
break;
|
||||
case '-':
|
||||
if (apply_in_reverse &&
|
||||
new_whitespace != nowarn_whitespace)
|
||||
check_whitespace(line, len);
|
||||
ws_error_action != nowarn_ws_error)
|
||||
check_whitespace(line, len, patch->ws_rule);
|
||||
deleted++;
|
||||
oldlines--;
|
||||
trailing = 0;
|
||||
break;
|
||||
case '+':
|
||||
if (!apply_in_reverse &&
|
||||
new_whitespace != nowarn_whitespace)
|
||||
check_whitespace(line, len);
|
||||
ws_error_action != nowarn_ws_error)
|
||||
check_whitespace(line, len, patch->ws_rule);
|
||||
added++;
|
||||
newlines--;
|
||||
trailing = 0;
|
||||
break;
|
||||
|
||||
/* We allow "\ No newline at end of file". Depending
|
||||
/*
|
||||
* We allow "\ No newline at end of file". Depending
|
||||
* on locale settings when the patch was produced we
|
||||
* don't know what this line looks like. The only
|
||||
* thing we do know is that it begins with "\ ".
|
||||
@@ -1012,7 +1034,8 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
|
||||
fragment->leading = leading;
|
||||
fragment->trailing = trailing;
|
||||
|
||||
/* If a fragment ends with an incomplete line, we failed to include
|
||||
/*
|
||||
* If a fragment ends with an incomplete line, we failed to include
|
||||
* it in the above loop because we hit oldlines == newlines == 0
|
||||
* before seeing it.
|
||||
*/
|
||||
@@ -1140,7 +1163,8 @@ static struct fragment *parse_binary_hunk(char **buf_p,
|
||||
int *status_p,
|
||||
int *used_p)
|
||||
{
|
||||
/* Expect a line that begins with binary patch method ("literal"
|
||||
/*
|
||||
* Expect a line that begins with binary patch method ("literal"
|
||||
* or "delta"), followed by the length of data before deflating.
|
||||
* a sequence of 'length-byte' followed by base-85 encoded data
|
||||
* should follow, terminated by a newline.
|
||||
@@ -1189,7 +1213,8 @@ static struct fragment *parse_binary_hunk(char **buf_p,
|
||||
size--;
|
||||
break;
|
||||
}
|
||||
/* Minimum line is "A00000\n" which is 7-byte long,
|
||||
/*
|
||||
* Minimum line is "A00000\n" which is 7-byte long,
|
||||
* and the line length must be multiple of 5 plus 2.
|
||||
*/
|
||||
if ((llen < 7) || (llen-2) % 5)
|
||||
@@ -1240,7 +1265,8 @@ static struct fragment *parse_binary_hunk(char **buf_p,
|
||||
|
||||
static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
|
||||
{
|
||||
/* We have read "GIT binary patch\n"; what follows is a line
|
||||
/*
|
||||
* We have read "GIT binary patch\n"; what follows is a line
|
||||
* that says the patch method (currently, either "literal" or
|
||||
* "delta") and the length of data before deflating; a
|
||||
* sequence of 'length-byte' followed by base-85 encoded data
|
||||
@@ -1270,7 +1296,8 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
|
||||
if (reverse)
|
||||
used += used_1;
|
||||
else if (status) {
|
||||
/* not having reverse hunk is not an error, but having
|
||||
/*
|
||||
* Not having reverse hunk is not an error, but having
|
||||
* a corrupt reverse hunk is.
|
||||
*/
|
||||
free((void*) forward->patch);
|
||||
@@ -1291,7 +1318,12 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
|
||||
patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
|
||||
patch->ws_rule = whitespace_rule(patch->new_name
|
||||
? patch->new_name
|
||||
: patch->old_name);
|
||||
|
||||
patchsize = parse_single_patch(buffer + offset + hdrsize,
|
||||
size - offset - hdrsize, patch);
|
||||
|
||||
if (!patchsize) {
|
||||
static const char *binhdr[] = {
|
||||
@@ -1367,8 +1399,10 @@ static void reverse_patches(struct patch *p)
|
||||
}
|
||||
}
|
||||
|
||||
static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
|
||||
static const char minuses[]= "----------------------------------------------------------------------";
|
||||
static const char pluses[] =
|
||||
"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
|
||||
static const char minuses[]=
|
||||
"----------------------------------------------------------------------";
|
||||
|
||||
static void show_stats(struct patch *patch)
|
||||
{
|
||||
@@ -1437,7 +1471,9 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
|
||||
}
|
||||
}
|
||||
|
||||
static int find_offset(const char *buf, unsigned long size, const char *fragment, unsigned long fragsize, int line, int *lines)
|
||||
static int find_offset(const char *buf, unsigned long size,
|
||||
const char *fragment, unsigned long fragsize,
|
||||
int line, int *lines)
|
||||
{
|
||||
int i;
|
||||
unsigned long start, backwards, forwards;
|
||||
@@ -1536,9 +1572,11 @@ static void remove_last_line(const char **rbuf, int *rsize)
|
||||
*rsize = offset + 1;
|
||||
}
|
||||
|
||||
static int apply_line(char *output, const char *patch, int plen)
|
||||
static int apply_line(char *output, const char *patch, int plen,
|
||||
unsigned ws_rule)
|
||||
{
|
||||
/* plen is number of bytes to be copied from patch,
|
||||
/*
|
||||
* plen is number of bytes to be copied from patch,
|
||||
* starting at patch+1 (patch[0] is '+'). Typically
|
||||
* patch[plen] is '\n', unless this is the incomplete
|
||||
* last line.
|
||||
@@ -1551,13 +1589,17 @@ static int apply_line(char *output, const char *patch, int plen)
|
||||
int need_fix_leading_space = 0;
|
||||
char *buf;
|
||||
|
||||
if ((new_whitespace != strip_whitespace) || !whitespace_error ||
|
||||
if ((ws_error_action != correct_ws_error) || !whitespace_error ||
|
||||
*patch != '+') {
|
||||
memcpy(output, patch + 1, plen);
|
||||
return plen;
|
||||
}
|
||||
|
||||
if (1 < plen && isspace(patch[plen-1])) {
|
||||
/*
|
||||
* Strip trailing whitespace
|
||||
*/
|
||||
if ((ws_rule & WS_TRAILING_SPACE) &&
|
||||
(1 < plen && isspace(patch[plen-1]))) {
|
||||
if (patch[plen] == '\n')
|
||||
add_nl_to_tail = 1;
|
||||
plen--;
|
||||
@@ -1566,15 +1608,23 @@ static int apply_line(char *output, const char *patch, int plen)
|
||||
fixed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check leading whitespaces (indent)
|
||||
*/
|
||||
for (i = 1; i < plen; i++) {
|
||||
char ch = patch[i];
|
||||
if (ch == '\t') {
|
||||
last_tab_in_indent = i;
|
||||
if (0 <= last_space_in_indent)
|
||||
if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
|
||||
0 <= last_space_in_indent)
|
||||
need_fix_leading_space = 1;
|
||||
} else if (ch == ' ') {
|
||||
last_space_in_indent = i;
|
||||
if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
|
||||
last_tab_in_indent < 0 &&
|
||||
8 <= i)
|
||||
need_fix_leading_space = 1;
|
||||
}
|
||||
else if (ch == ' ')
|
||||
last_space_in_indent = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
@@ -1582,10 +1632,21 @@ static int apply_line(char *output, const char *patch, int plen)
|
||||
buf = output;
|
||||
if (need_fix_leading_space) {
|
||||
int consecutive_spaces = 0;
|
||||
/* between patch[1..last_tab_in_indent] strip the
|
||||
* funny spaces, updating them to tab as needed.
|
||||
int last = last_tab_in_indent + 1;
|
||||
|
||||
if (ws_rule & WS_INDENT_WITH_NON_TAB) {
|
||||
/* have "last" point at one past the indent */
|
||||
if (last_tab_in_indent < last_space_in_indent)
|
||||
last = last_space_in_indent + 1;
|
||||
else
|
||||
last = last_tab_in_indent + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* between patch[1..last], strip the funny spaces,
|
||||
* updating them to tab as needed.
|
||||
*/
|
||||
for (i = 1; i < last_tab_in_indent; i++, plen--) {
|
||||
for (i = 1; i < last; i++, plen--) {
|
||||
char ch = patch[i];
|
||||
if (ch != ' ') {
|
||||
consecutive_spaces = 0;
|
||||
@@ -1598,8 +1659,10 @@ static int apply_line(char *output, const char *patch, int plen)
|
||||
}
|
||||
}
|
||||
}
|
||||
while (0 < consecutive_spaces--)
|
||||
*output++ = ' ';
|
||||
fixed = 1;
|
||||
i = last_tab_in_indent;
|
||||
i = last;
|
||||
}
|
||||
else
|
||||
i = 1;
|
||||
@@ -1612,7 +1675,8 @@ static int apply_line(char *output, const char *patch, int plen)
|
||||
return output + plen - buf;
|
||||
}
|
||||
|
||||
static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int inaccurate_eof)
|
||||
static int apply_one_fragment(struct strbuf *buf, struct fragment *frag,
|
||||
int inaccurate_eof, unsigned ws_rule)
|
||||
{
|
||||
int match_beginning, match_end;
|
||||
const char *patch = frag->patch;
|
||||
@@ -1671,7 +1735,7 @@ static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int ina
|
||||
case '+':
|
||||
if (first != '+' || !no_add) {
|
||||
int added = apply_line(new + newsize, patch,
|
||||
plen);
|
||||
plen, ws_rule);
|
||||
newsize += added;
|
||||
if (first == '+' &&
|
||||
added == 1 && new[newsize-1] == '\n')
|
||||
@@ -1694,8 +1758,9 @@ static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int ina
|
||||
size -= len;
|
||||
}
|
||||
|
||||
if (inaccurate_eof && oldsize > 0 && old[oldsize - 1] == '\n' &&
|
||||
newsize > 0 && new[newsize - 1] == '\n') {
|
||||
if (inaccurate_eof &&
|
||||
oldsize > 0 && old[oldsize - 1] == '\n' &&
|
||||
newsize > 0 && new[newsize - 1] == '\n') {
|
||||
oldsize--;
|
||||
newsize--;
|
||||
}
|
||||
@@ -1732,7 +1797,7 @@ static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int ina
|
||||
if (match_beginning && offset)
|
||||
offset = -1;
|
||||
if (offset >= 0) {
|
||||
if (new_whitespace == strip_whitespace &&
|
||||
if (ws_error_action == correct_ws_error &&
|
||||
(buf->len - oldsize - offset == 0)) /* end of file? */
|
||||
newsize -= new_blank_lines_at_end;
|
||||
|
||||
@@ -1757,9 +1822,10 @@ static int apply_one_fragment(struct strbuf *buf, struct fragment *frag, int ina
|
||||
match_beginning = match_end = 0;
|
||||
continue;
|
||||
}
|
||||
/* Reduce the number of context lines
|
||||
* Reduce both leading and trailing if they are equal
|
||||
* otherwise just reduce the larger context.
|
||||
/*
|
||||
* Reduce the number of context lines; reduce both
|
||||
* leading and trailing if they are equal otherwise
|
||||
* just reduce the larger context.
|
||||
*/
|
||||
if (leading >= trailing) {
|
||||
remove_first_line(&oldlines, &oldsize);
|
||||
@@ -1819,7 +1885,8 @@ static int apply_binary(struct strbuf *buf, struct patch *patch)
|
||||
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
||||
unsigned char sha1[20];
|
||||
|
||||
/* For safety, we require patch index line to contain
|
||||
/*
|
||||
* For safety, we require patch index line to contain
|
||||
* full 40-byte textual SHA1 for old and new, at least for now.
|
||||
*/
|
||||
if (strlen(patch->old_sha1_prefix) != 40 ||
|
||||
@@ -1830,7 +1897,8 @@ static int apply_binary(struct strbuf *buf, struct patch *patch)
|
||||
"without full index line", name);
|
||||
|
||||
if (patch->old_name) {
|
||||
/* See if the old one matches what the patch
|
||||
/*
|
||||
* See if the old one matches what the patch
|
||||
* applies to.
|
||||
*/
|
||||
hash_sha1_file(buf->buf, buf->len, blob_type, sha1);
|
||||
@@ -1867,7 +1935,8 @@ static int apply_binary(struct strbuf *buf, struct patch *patch)
|
||||
/* XXX read_sha1_file NUL-terminates */
|
||||
strbuf_attach(buf, result, size, size + 1);
|
||||
} else {
|
||||
/* We have verified buf matches the preimage;
|
||||
/*
|
||||
* We have verified buf matches the preimage;
|
||||
* apply the patch data to it, which is stored
|
||||
* in the patch->fragments->{patch,size}.
|
||||
*/
|
||||
@@ -1889,12 +1958,14 @@ static int apply_fragments(struct strbuf *buf, struct patch *patch)
|
||||
{
|
||||
struct fragment *frag = patch->fragments;
|
||||
const char *name = patch->old_name ? patch->old_name : patch->new_name;
|
||||
unsigned ws_rule = patch->ws_rule;
|
||||
unsigned inaccurate_eof = patch->inaccurate_eof;
|
||||
|
||||
if (patch->is_binary)
|
||||
return apply_binary(buf, patch);
|
||||
|
||||
while (frag) {
|
||||
if (apply_one_fragment(buf, frag, patch->inaccurate_eof)) {
|
||||
if (apply_one_fragment(buf, frag, inaccurate_eof, ws_rule)) {
|
||||
error("patch failed: %s:%ld", name, frag->oldpos);
|
||||
if (!apply_with_reject)
|
||||
return -1;
|
||||
@@ -2066,7 +2137,8 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
|
||||
|
||||
if (new_name && prev_patch && 0 < prev_patch->is_delete &&
|
||||
!strcmp(prev_patch->old_name, new_name))
|
||||
/* A type-change diff is always split into a patch to
|
||||
/*
|
||||
* A type-change diff is always split into a patch to
|
||||
* delete old, immediately followed by a patch to
|
||||
* create new (see diff.c::run_diff()); in such a case
|
||||
* it is Ok that the entry to be deleted by the
|
||||
@@ -2670,7 +2742,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||
offset += nr;
|
||||
}
|
||||
|
||||
if (whitespace_error && (new_whitespace == error_on_whitespace))
|
||||
if (whitespace_error && (ws_error_action == die_on_ws_error))
|
||||
apply = 0;
|
||||
|
||||
update_index = check_index && apply;
|
||||
@@ -2865,7 +2937,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
||||
squelched,
|
||||
squelched == 1 ? "" : "s");
|
||||
}
|
||||
if (new_whitespace == error_on_whitespace)
|
||||
if (ws_error_action == die_on_ws_error)
|
||||
die("%d line%s add%s whitespace errors.",
|
||||
whitespace_error,
|
||||
whitespace_error == 1 ? "" : "s",
|
||||
|
||||
@@ -130,6 +130,14 @@ static void origin_decref(struct origin *o)
|
||||
}
|
||||
}
|
||||
|
||||
static void drop_origin_blob(struct origin *o)
|
||||
{
|
||||
if (o->file.ptr) {
|
||||
free(o->file.ptr);
|
||||
o->file.ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Each group of lines is described by a blame_entry; it can be split
|
||||
* as we pass blame to the parents. They form a linked list in the
|
||||
@@ -380,6 +388,7 @@ static struct origin *find_origin(struct scoreboard *sb,
|
||||
}
|
||||
}
|
||||
diff_flush(&diff_opts);
|
||||
diff_tree_release_paths(&diff_opts);
|
||||
if (porigin) {
|
||||
/*
|
||||
* Create a freestanding copy that is not part of
|
||||
@@ -436,6 +445,7 @@ static struct origin *find_rename(struct scoreboard *sb,
|
||||
}
|
||||
}
|
||||
diff_flush(&diff_opts);
|
||||
diff_tree_release_paths(&diff_opts);
|
||||
return porigin;
|
||||
}
|
||||
|
||||
@@ -1157,7 +1167,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
|
||||
}
|
||||
}
|
||||
diff_flush(&diff_opts);
|
||||
|
||||
diff_tree_release_paths(&diff_opts);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1274,8 +1284,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
|
||||
}
|
||||
|
||||
finish:
|
||||
for (i = 0; i < MAXPARENT; i++)
|
||||
origin_decref(parent_origin[i]);
|
||||
for (i = 0; i < MAXPARENT; i++) {
|
||||
if (parent_origin[i]) {
|
||||
drop_origin_blob(parent_origin[i]);
|
||||
origin_decref(parent_origin[i]);
|
||||
}
|
||||
}
|
||||
drop_origin_blob(origin);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -98,8 +98,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
strbuf_addf(&buffer, "parent %s\n", sha1_to_hex(parent_sha1[i]));
|
||||
|
||||
/* Person/date information */
|
||||
strbuf_addf(&buffer, "author %s\n", git_author_info(1));
|
||||
strbuf_addf(&buffer, "committer %s\n", git_committer_info(1));
|
||||
strbuf_addf(&buffer, "author %s\n", git_author_info(IDENT_ERROR_ON_NO_NAME));
|
||||
strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
|
||||
if (!encoding_is_utf8)
|
||||
strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
|
||||
strbuf_addch(&buffer, '\n');
|
||||
|
||||
@@ -285,7 +285,8 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix)
|
||||
struct wt_status s;
|
||||
|
||||
wt_status_prepare(&s);
|
||||
s.prefix = prefix;
|
||||
if (wt_status_relative_paths)
|
||||
s.prefix = prefix;
|
||||
|
||||
if (amend) {
|
||||
s.amend = 1;
|
||||
@@ -496,7 +497,7 @@ static void determine_author_info(struct strbuf *sb)
|
||||
email = xstrndup(lb + 2, rb - (lb + 2));
|
||||
}
|
||||
|
||||
strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, 1));
|
||||
strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, IDENT_ERROR_ON_NO_NAME));
|
||||
}
|
||||
|
||||
static int parse_and_validate_options(int argc, const char *argv[],
|
||||
@@ -659,12 +660,16 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
|
||||
rev.verbose_header = 1;
|
||||
rev.show_root_diff = 1;
|
||||
rev.commit_format = get_commit_format("format:%h: %s");
|
||||
rev.always_show_header = 1;
|
||||
rev.always_show_header = 0;
|
||||
|
||||
printf("Created %scommit ", initial_commit ? "initial " : "");
|
||||
|
||||
log_tree_commit(&rev, commit);
|
||||
printf("\n");
|
||||
if (!log_tree_commit(&rev, commit)) {
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
format_commit_message(commit, "%h: %s", &buf);
|
||||
printf("%s\n", buf.buf);
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
int git_commit_config(const char *k, const char *v)
|
||||
@@ -775,7 +780,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
determine_author_info(&sb);
|
||||
strbuf_addf(&sb, "committer %s\n", git_committer_info(1));
|
||||
strbuf_addf(&sb, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
|
||||
if (!is_encoding_utf8(git_commit_encoding))
|
||||
strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
|
||||
strbuf_addch(&sb, '\n');
|
||||
@@ -786,15 +791,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
char index[PATH_MAX];
|
||||
const char *env[2] = { index, NULL };
|
||||
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
|
||||
launch_editor(git_path(commit_editmsg), &sb, env);
|
||||
} else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
|
||||
rollback_index_files();
|
||||
die("could not read commit message");
|
||||
launch_editor(git_path(commit_editmsg), NULL, env);
|
||||
}
|
||||
if (run_hook(index_file, "commit-msg", git_path(commit_editmsg))) {
|
||||
if (!no_verify &&
|
||||
run_hook(index_file, "commit-msg", git_path(commit_editmsg))) {
|
||||
rollback_index_files();
|
||||
exit(1);
|
||||
}
|
||||
if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
|
||||
rollback_index_files();
|
||||
die("could not read commit message");
|
||||
}
|
||||
|
||||
/* Truncate the message just before the diff, if any. */
|
||||
p = strstr(sb.buf, "\ndiff --git a/");
|
||||
|
||||
@@ -176,18 +176,6 @@ static int builtin_diff_combined(struct rev_info *revs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_head(struct rev_info *revs)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
struct object *obj;
|
||||
if (get_sha1("HEAD", sha1))
|
||||
return;
|
||||
obj = parse_object(sha1);
|
||||
if (!obj)
|
||||
return;
|
||||
add_pending_object(revs, obj, "HEAD");
|
||||
}
|
||||
|
||||
static void refresh_index_quietly(void)
|
||||
{
|
||||
struct lock_file *lock_file;
|
||||
@@ -272,7 +260,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
if (!strcmp(arg, "--"))
|
||||
break;
|
||||
else if (!strcmp(arg, "--cached")) {
|
||||
add_head(&rev);
|
||||
add_head_to_pending(&rev);
|
||||
if (!rev.pending.nr)
|
||||
die("No HEAD commit to compare with (yet)");
|
||||
break;
|
||||
|
||||
@@ -103,7 +103,7 @@ static void handle_object(const unsigned char *sha1)
|
||||
mark_object(object);
|
||||
|
||||
printf("blob\nmark :%d\ndata %lu\n", last_idnum, size);
|
||||
if (fwrite(buf, size, 1, stdout) != 1)
|
||||
if (size && fwrite(buf, size, 1, stdout) != 1)
|
||||
die ("Could not write blob %s", sha1_to_hex(sha1));
|
||||
printf("\n");
|
||||
|
||||
|
||||
@@ -18,9 +18,6 @@
|
||||
static int default_show_root = 1;
|
||||
static const char *fmt_patch_subject_prefix = "PATCH";
|
||||
|
||||
/* this is in builtin-diff.c */
|
||||
void add_head(struct rev_info *revs);
|
||||
|
||||
static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
|
||||
{
|
||||
int plen = strlen(prefix);
|
||||
@@ -557,7 +554,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
|
||||
|
||||
static void gen_message_id(char *dest, unsigned int length, char *base)
|
||||
{
|
||||
const char *committer = git_committer_info(-1);
|
||||
const char *committer = git_committer_info(IDENT_WARN_ON_NO_NAME);
|
||||
const char *email_start = strrchr(committer, '<');
|
||||
const char *email_end = strrchr(committer, '>');
|
||||
if(!email_start || !email_end || email_start > email_end - 1)
|
||||
@@ -665,7 +662,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||
!strcmp(argv[i], "-s")) {
|
||||
const char *committer;
|
||||
const char *endpos;
|
||||
committer = git_committer_info(1);
|
||||
committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
|
||||
endpos = strchr(committer, '>');
|
||||
if (!endpos)
|
||||
die("bogos committer info %s\n", committer);
|
||||
@@ -746,7 +743,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||
* does not have.
|
||||
*/
|
||||
rev.pending.objects[0].item->flags |= UNINTERESTING;
|
||||
add_head(&rev);
|
||||
add_head_to_pending(&rev);
|
||||
}
|
||||
/*
|
||||
* Otherwise, it is "format-patch -22 HEAD", and/or
|
||||
|
||||
@@ -6,6 +6,27 @@
|
||||
static const char ls_remote_usage[] =
|
||||
"git-ls-remote [--upload-pack=<git-upload-pack>] [<host>:]<directory>";
|
||||
|
||||
/*
|
||||
* Is there one among the list of patterns that match the tail part
|
||||
* of the path?
|
||||
*/
|
||||
static int tail_match(const char **pattern, const char *path)
|
||||
{
|
||||
const char *p;
|
||||
char pathbuf[PATH_MAX];
|
||||
|
||||
if (!pattern)
|
||||
return 1; /* no restriction */
|
||||
|
||||
if (snprintf(pathbuf, sizeof(pathbuf), "/%s", path) > sizeof(pathbuf))
|
||||
return error("insanely long ref %.*s...", 20, path);
|
||||
while ((p = *(pattern++)) != NULL) {
|
||||
if (!fnmatch(p, pathbuf, 0))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
@@ -13,6 +34,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
||||
int nongit = 0;
|
||||
unsigned flags = 0;
|
||||
const char *uploadpack = NULL;
|
||||
const char **pattern = NULL;
|
||||
|
||||
struct remote *remote;
|
||||
struct transport *transport;
|
||||
@@ -47,12 +69,23 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
||||
usage(ls_remote_usage);
|
||||
}
|
||||
dest = arg;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dest || i != argc - 1)
|
||||
if (!dest)
|
||||
usage(ls_remote_usage);
|
||||
|
||||
if (argv[i]) {
|
||||
int j;
|
||||
pattern = xcalloc(sizeof(const char *), argc - i + 1);
|
||||
for (j = i; j < argc; j++) {
|
||||
int len = strlen(argv[j]);
|
||||
char *p = xmalloc(len + 3);
|
||||
sprintf(p, "*/%s", argv[j]);
|
||||
pattern[j - i] = p;
|
||||
}
|
||||
}
|
||||
remote = nongit ? NULL : remote_get(dest);
|
||||
if (remote && !remote->url_nr)
|
||||
die("remote %s has no configured URL", dest);
|
||||
@@ -65,10 +98,12 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
|
||||
if (!ref)
|
||||
return 1;
|
||||
|
||||
while (ref) {
|
||||
if (check_ref_type(ref, flags))
|
||||
printf("%s %s\n", sha1_to_hex(ref->old_sha1), ref->name);
|
||||
ref = ref->next;
|
||||
for ( ; ref; ref = ref->next) {
|
||||
if (!check_ref_type(ref, flags))
|
||||
continue;
|
||||
if (!tail_match(pattern, ref->name))
|
||||
continue;
|
||||
printf("%s %s\n", sha1_to_hex(ref->old_sha1), ref->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1245,28 +1245,37 @@ static void get_object_details(void)
|
||||
free(sorted_by_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* We search for deltas in a list sorted by type, by filename hash, and then
|
||||
* by size, so that we see progressively smaller and smaller files.
|
||||
* That's because we prefer deltas to be from the bigger file
|
||||
* to the smaller -- deletes are potentially cheaper, but perhaps
|
||||
* more importantly, the bigger file is likely the more recent
|
||||
* one. The deepest deltas are therefore the oldest objects which are
|
||||
* less susceptible to be accessed often.
|
||||
*/
|
||||
static int type_size_sort(const void *_a, const void *_b)
|
||||
{
|
||||
const struct object_entry *a = *(struct object_entry **)_a;
|
||||
const struct object_entry *b = *(struct object_entry **)_b;
|
||||
|
||||
if (a->type < b->type)
|
||||
return -1;
|
||||
if (a->type > b->type)
|
||||
return 1;
|
||||
if (a->hash < b->hash)
|
||||
return -1;
|
||||
if (a->type < b->type)
|
||||
return 1;
|
||||
if (a->hash > b->hash)
|
||||
return 1;
|
||||
if (a->preferred_base < b->preferred_base)
|
||||
return -1;
|
||||
if (a->hash < b->hash)
|
||||
return 1;
|
||||
if (a->preferred_base > b->preferred_base)
|
||||
return 1;
|
||||
if (a->size < b->size)
|
||||
return -1;
|
||||
if (a->size > b->size)
|
||||
if (a->preferred_base < b->preferred_base)
|
||||
return 1;
|
||||
return a > b ? -1 : (a < b); /* newest last */
|
||||
if (a->size > b->size)
|
||||
return -1;
|
||||
if (a->size < b->size)
|
||||
return 1;
|
||||
return a < b ? -1 : (a > b); /* newest first */
|
||||
}
|
||||
|
||||
struct unpacked {
|
||||
@@ -1317,14 +1326,6 @@ static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We search for deltas _backwards_ in a list sorted by type and
|
||||
* by size, so that we see progressively smaller and smaller files.
|
||||
* That's because we prefer deltas to be from the bigger file
|
||||
* to the smaller - deletes are potentially cheaper, but perhaps
|
||||
* more importantly, the bigger file is likely the more recent
|
||||
* one.
|
||||
*/
|
||||
static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
unsigned max_depth, unsigned long *mem_usage)
|
||||
{
|
||||
@@ -1422,10 +1423,6 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
}
|
||||
}
|
||||
|
||||
trg_entry->delta = src_entry;
|
||||
trg_entry->delta_size = delta_size;
|
||||
trg->depth = src->depth + 1;
|
||||
|
||||
/*
|
||||
* Handle memory allocation outside of the cache
|
||||
* accounting lock. Compiler will optimize the strangeness
|
||||
@@ -1439,7 +1436,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
trg_entry->delta_data = NULL;
|
||||
}
|
||||
if (delta_cacheable(src_size, trg_size, delta_size)) {
|
||||
delta_cache_size += trg_entry->delta_size;
|
||||
delta_cache_size += delta_size;
|
||||
cache_unlock();
|
||||
trg_entry->delta_data = xrealloc(delta_buf, delta_size);
|
||||
} else {
|
||||
@@ -1447,6 +1444,10 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
free(delta_buf);
|
||||
}
|
||||
|
||||
trg_entry->delta = src_entry;
|
||||
trg_entry->delta_size = delta_size;
|
||||
trg->depth = src->depth + 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1478,10 +1479,10 @@ static unsigned long free_unpacked(struct unpacked *n)
|
||||
return freed_mem;
|
||||
}
|
||||
|
||||
static void find_deltas(struct object_entry **list, unsigned list_size,
|
||||
static void find_deltas(struct object_entry **list, unsigned *list_size,
|
||||
int window, int depth, unsigned *processed)
|
||||
{
|
||||
uint32_t i = list_size, idx = 0, count = 0;
|
||||
uint32_t i, idx = 0, count = 0;
|
||||
unsigned int array_size = window * sizeof(struct unpacked);
|
||||
struct unpacked *array;
|
||||
unsigned long mem_usage = 0;
|
||||
@@ -1489,11 +1490,23 @@ static void find_deltas(struct object_entry **list, unsigned list_size,
|
||||
array = xmalloc(array_size);
|
||||
memset(array, 0, array_size);
|
||||
|
||||
do {
|
||||
struct object_entry *entry = list[--i];
|
||||
for (;;) {
|
||||
struct object_entry *entry = *list++;
|
||||
struct unpacked *n = array + idx;
|
||||
int j, max_depth, best_base = -1;
|
||||
|
||||
progress_lock();
|
||||
if (!*list_size) {
|
||||
progress_unlock();
|
||||
break;
|
||||
}
|
||||
(*list_size)--;
|
||||
if (!entry->preferred_base) {
|
||||
(*processed)++;
|
||||
display_progress(progress_state, *processed);
|
||||
}
|
||||
progress_unlock();
|
||||
|
||||
mem_usage -= free_unpacked(n);
|
||||
n->entry = entry;
|
||||
|
||||
@@ -1511,11 +1524,6 @@ static void find_deltas(struct object_entry **list, unsigned list_size,
|
||||
if (entry->preferred_base)
|
||||
goto next;
|
||||
|
||||
progress_lock();
|
||||
(*processed)++;
|
||||
display_progress(progress_state, *processed);
|
||||
progress_unlock();
|
||||
|
||||
/*
|
||||
* If the current object is at pack edge, take the depth the
|
||||
* objects that depend on the current object into account
|
||||
@@ -1575,7 +1583,7 @@ static void find_deltas(struct object_entry **list, unsigned list_size,
|
||||
count++;
|
||||
if (idx >= window)
|
||||
idx = 0;
|
||||
} while (i > 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < window; ++i) {
|
||||
free_delta_index(array[i].index);
|
||||
@@ -1590,6 +1598,7 @@ struct thread_params {
|
||||
pthread_t thread;
|
||||
struct object_entry **list;
|
||||
unsigned list_size;
|
||||
unsigned remaining;
|
||||
int window;
|
||||
int depth;
|
||||
unsigned *processed;
|
||||
@@ -1611,10 +1620,10 @@ static void *threaded_find_deltas(void *arg)
|
||||
pthread_mutex_lock(&data_ready);
|
||||
pthread_mutex_unlock(&data_request);
|
||||
|
||||
if (!me->list_size)
|
||||
if (!me->remaining)
|
||||
return NULL;
|
||||
|
||||
find_deltas(me->list, me->list_size,
|
||||
find_deltas(me->list, &me->remaining,
|
||||
me->window, me->depth, me->processed);
|
||||
}
|
||||
}
|
||||
@@ -1623,57 +1632,112 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
|
||||
int window, int depth, unsigned *processed)
|
||||
{
|
||||
struct thread_params *target, p[delta_search_threads];
|
||||
int i, ret;
|
||||
unsigned chunk_size;
|
||||
int i, ret, active_threads = 0;
|
||||
|
||||
if (delta_search_threads <= 1) {
|
||||
find_deltas(list, list_size, window, depth, processed);
|
||||
find_deltas(list, &list_size, window, depth, processed);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&data_provider);
|
||||
pthread_mutex_lock(&data_ready);
|
||||
|
||||
/* Start work threads. */
|
||||
for (i = 0; i < delta_search_threads; i++) {
|
||||
p[i].window = window;
|
||||
p[i].depth = depth;
|
||||
p[i].processed = processed;
|
||||
p[i].remaining = 0;
|
||||
ret = pthread_create(&p[i].thread, NULL,
|
||||
threaded_find_deltas, &p[i]);
|
||||
if (ret)
|
||||
die("unable to create thread: %s", strerror(ret));
|
||||
active_threads++;
|
||||
}
|
||||
|
||||
/* this should be auto-tuned somehow */
|
||||
chunk_size = window * 1000;
|
||||
|
||||
do {
|
||||
unsigned sublist_size = chunk_size;
|
||||
if (sublist_size > list_size)
|
||||
sublist_size = list_size;
|
||||
|
||||
/* try to split chunks on "path" boundaries */
|
||||
while (sublist_size < list_size && list[sublist_size]->hash &&
|
||||
list[sublist_size]->hash == list[sublist_size-1]->hash)
|
||||
sublist_size++;
|
||||
/* Then partition the work amongst them. */
|
||||
for (i = 0; i < delta_search_threads; i++) {
|
||||
unsigned sub_size = list_size / (delta_search_threads - i);
|
||||
|
||||
pthread_mutex_lock(&data_provider);
|
||||
target = data_requester;
|
||||
if (!sub_size) {
|
||||
pthread_mutex_unlock(&data_ready);
|
||||
pthread_join(target->thread, NULL);
|
||||
active_threads--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* try to split chunks on "path" boundaries */
|
||||
while (sub_size < list_size && list[sub_size]->hash &&
|
||||
list[sub_size]->hash == list[sub_size-1]->hash)
|
||||
sub_size++;
|
||||
|
||||
target->list = list;
|
||||
target->list_size = sublist_size;
|
||||
target->list_size = sub_size;
|
||||
target->remaining = sub_size;
|
||||
pthread_mutex_unlock(&data_ready);
|
||||
|
||||
list += sublist_size;
|
||||
list_size -= sublist_size;
|
||||
if (!sublist_size) {
|
||||
pthread_join(target->thread, NULL);
|
||||
i--;
|
||||
list += sub_size;
|
||||
list_size -= sub_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now let's wait for work completion. Each time a thread is done
|
||||
* with its work, we steal half of the remaining work from the
|
||||
* thread with the largest number of unprocessed objects and give
|
||||
* it to that newly idle thread. This ensure good load balancing
|
||||
* until the remaining object list segments are simply too short
|
||||
* to be worth splitting anymore.
|
||||
*/
|
||||
do {
|
||||
struct thread_params *victim = NULL;
|
||||
unsigned sub_size = 0;
|
||||
pthread_mutex_lock(&data_provider);
|
||||
target = data_requester;
|
||||
|
||||
progress_lock();
|
||||
for (i = 0; i < delta_search_threads; i++)
|
||||
if (p[i].remaining > 2*window &&
|
||||
(!victim || victim->remaining < p[i].remaining))
|
||||
victim = &p[i];
|
||||
if (victim) {
|
||||
sub_size = victim->remaining / 2;
|
||||
list = victim->list + victim->list_size - sub_size;
|
||||
while (sub_size && list[0]->hash &&
|
||||
list[0]->hash == list[-1]->hash) {
|
||||
list++;
|
||||
sub_size--;
|
||||
}
|
||||
if (!sub_size) {
|
||||
/*
|
||||
* It is possible for some "paths" to have
|
||||
* so many objects that no hash boundary
|
||||
* might be found. Let's just steal the
|
||||
* exact half in that case.
|
||||
*/
|
||||
sub_size = victim->remaining / 2;
|
||||
list -= sub_size;
|
||||
}
|
||||
target->list = list;
|
||||
victim->list_size -= sub_size;
|
||||
victim->remaining -= sub_size;
|
||||
}
|
||||
} while (i);
|
||||
progress_unlock();
|
||||
|
||||
target->list_size = sub_size;
|
||||
target->remaining = sub_size;
|
||||
pthread_mutex_unlock(&data_ready);
|
||||
|
||||
if (!sub_size) {
|
||||
pthread_join(target->thread, NULL);
|
||||
active_threads--;
|
||||
}
|
||||
} while (active_threads);
|
||||
}
|
||||
|
||||
#else
|
||||
#define ll_find_deltas find_deltas
|
||||
#define ll_find_deltas(l, s, w, d, p) find_deltas(l, &s, w, d, p)
|
||||
#endif
|
||||
|
||||
static void prepare_pack(int window, int depth)
|
||||
|
||||
@@ -158,6 +158,7 @@ static int read_from_tree(const char *prefix, const char **argv,
|
||||
return 1;
|
||||
diffcore_std(&opt);
|
||||
diff_flush(&opt);
|
||||
diff_tree_release_paths(&opt);
|
||||
|
||||
if (!index_was_discarded)
|
||||
/* The index is still clobbered from do_diff_cache() */
|
||||
|
||||
@@ -11,6 +11,7 @@ static const char shortlog_usage[] =
|
||||
"git-shortlog [-n] [-s] [<commit-id>... ]";
|
||||
|
||||
static char *common_repo_prefix;
|
||||
static int email;
|
||||
|
||||
static int compare_by_number(const void *a1, const void *a2)
|
||||
{
|
||||
@@ -27,45 +28,68 @@ static int compare_by_number(const void *a1, const void *a2)
|
||||
|
||||
static struct path_list mailmap = {NULL, 0, 0, 0};
|
||||
|
||||
static void insert_author_oneline(struct path_list *list,
|
||||
const char *author, int authorlen,
|
||||
const char *oneline, int onelinelen)
|
||||
static void insert_one_record(struct path_list *list,
|
||||
const char *author,
|
||||
const char *oneline)
|
||||
{
|
||||
const char *dot3 = common_repo_prefix;
|
||||
char *buffer, *p;
|
||||
struct path_list_item *item;
|
||||
struct path_list *onelines;
|
||||
char namebuf[1024];
|
||||
size_t len;
|
||||
const char *eol;
|
||||
const char *boemail, *eoemail;
|
||||
|
||||
while (authorlen > 0 && isspace(author[authorlen - 1]))
|
||||
authorlen--;
|
||||
boemail = strchr(author, '<');
|
||||
if (!boemail)
|
||||
return;
|
||||
eoemail = strchr(boemail, '>');
|
||||
if (!eoemail)
|
||||
return;
|
||||
if (!map_email(&mailmap, boemail+1, namebuf, sizeof(namebuf))) {
|
||||
while (author < boemail && isspace(*author))
|
||||
author++;
|
||||
for (len = 0;
|
||||
len < sizeof(namebuf) - 1 && author + len < boemail;
|
||||
len++)
|
||||
namebuf[len] = author[len];
|
||||
while (0 < len && isspace(namebuf[len-1]))
|
||||
len--;
|
||||
namebuf[len] = '\0';
|
||||
}
|
||||
else
|
||||
len = strlen(namebuf);
|
||||
|
||||
buffer = xmemdupz(author, authorlen);
|
||||
if (email) {
|
||||
size_t room = sizeof(namebuf) - len - 1;
|
||||
int maillen = eoemail - boemail + 1;
|
||||
snprintf(namebuf + len, room, " %.*s", maillen, boemail);
|
||||
}
|
||||
|
||||
buffer = xstrdup(namebuf);
|
||||
item = path_list_insert(buffer, list);
|
||||
if (item->util == NULL)
|
||||
item->util = xcalloc(1, sizeof(struct path_list));
|
||||
else
|
||||
free(buffer);
|
||||
|
||||
eol = strchr(oneline, '\n');
|
||||
if (!eol)
|
||||
eol = oneline + strlen(oneline);
|
||||
while (*oneline && isspace(*oneline) && *oneline != '\n')
|
||||
oneline++;
|
||||
if (!prefixcmp(oneline, "[PATCH")) {
|
||||
char *eob = strchr(oneline, ']');
|
||||
|
||||
if (eob) {
|
||||
while (isspace(eob[1]) && eob[1] != '\n')
|
||||
eob++;
|
||||
if (eob - oneline < onelinelen) {
|
||||
onelinelen -= eob - oneline;
|
||||
oneline = eob;
|
||||
}
|
||||
}
|
||||
if (eob && (!eol || eob < eol))
|
||||
oneline = eob + 1;
|
||||
}
|
||||
|
||||
while (onelinelen > 0 && isspace(oneline[0])) {
|
||||
while (*oneline && isspace(*oneline) && *oneline != '\n')
|
||||
oneline++;
|
||||
onelinelen--;
|
||||
}
|
||||
while (onelinelen > 0 && isspace(oneline[onelinelen - 1]))
|
||||
onelinelen--;
|
||||
buffer = xmemdupz(oneline, onelinelen);
|
||||
len = eol - oneline;
|
||||
while (len && isspace(oneline[len-1]))
|
||||
len--;
|
||||
buffer = xmemdupz(oneline, len);
|
||||
|
||||
if (dot3) {
|
||||
int dot3len = strlen(dot3);
|
||||
@@ -92,55 +116,32 @@ static void insert_author_oneline(struct path_list *list,
|
||||
|
||||
static void read_from_stdin(struct path_list *list)
|
||||
{
|
||||
char buffer[1024];
|
||||
char author[1024], oneline[1024];
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
|
||||
char *bob;
|
||||
if ((buffer[0] == 'A' || buffer[0] == 'a') &&
|
||||
!prefixcmp(buffer + 1, "uthor: ") &&
|
||||
(bob = strchr(buffer + 7, '<')) != NULL) {
|
||||
char buffer2[1024], offset = 0;
|
||||
|
||||
if (map_email(&mailmap, bob + 1, buffer, sizeof(buffer)))
|
||||
bob = buffer + strlen(buffer);
|
||||
else {
|
||||
offset = 8;
|
||||
while (buffer + offset < bob &&
|
||||
isspace(bob[-1]))
|
||||
bob--;
|
||||
}
|
||||
|
||||
while (fgets(buffer2, sizeof(buffer2), stdin) &&
|
||||
buffer2[0] != '\n')
|
||||
; /* chomp input */
|
||||
if (fgets(buffer2, sizeof(buffer2), stdin)) {
|
||||
int l2 = strlen(buffer2);
|
||||
int i;
|
||||
for (i = 0; i < l2; i++)
|
||||
if (!isspace(buffer2[i]))
|
||||
break;
|
||||
insert_author_oneline(list,
|
||||
buffer + offset,
|
||||
bob - buffer - offset,
|
||||
buffer2 + i, l2 - i);
|
||||
}
|
||||
}
|
||||
while (fgets(author, sizeof(author), stdin) != NULL) {
|
||||
if (!(author[0] == 'A' || author[0] == 'a') ||
|
||||
prefixcmp(author + 1, "uthor: "))
|
||||
continue;
|
||||
while (fgets(oneline, sizeof(oneline), stdin) &&
|
||||
oneline[0] != '\n')
|
||||
; /* discard headers */
|
||||
while (fgets(oneline, sizeof(oneline), stdin) &&
|
||||
oneline[0] == '\n')
|
||||
; /* discard blanks */
|
||||
insert_one_record(list, author + 8, oneline);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_from_rev(struct rev_info *rev, struct path_list *list)
|
||||
{
|
||||
char scratch[1024];
|
||||
struct commit *commit;
|
||||
|
||||
prepare_revision_walk(rev);
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
const char *author = NULL, *oneline, *buffer;
|
||||
int authorlen = authorlen, onelinelen;
|
||||
const char *author = NULL, *buffer;
|
||||
|
||||
/* get author and oneline */
|
||||
for (buffer = commit->buffer; buffer && *buffer != '\0' &&
|
||||
*buffer != '\n'; ) {
|
||||
buffer = commit->buffer;
|
||||
while (*buffer && *buffer != '\n') {
|
||||
const char *eol = strchr(buffer, '\n');
|
||||
|
||||
if (eol == NULL)
|
||||
@@ -148,50 +149,17 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
|
||||
else
|
||||
eol++;
|
||||
|
||||
if (!prefixcmp(buffer, "author ")) {
|
||||
char *bracket = strchr(buffer, '<');
|
||||
|
||||
if (bracket == NULL || bracket > eol)
|
||||
die("Invalid commit buffer: %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (map_email(&mailmap, bracket + 1, scratch,
|
||||
sizeof(scratch))) {
|
||||
author = scratch;
|
||||
authorlen = strlen(scratch);
|
||||
} else {
|
||||
if (bracket[-1] == ' ')
|
||||
bracket--;
|
||||
|
||||
author = buffer + 7;
|
||||
authorlen = bracket - buffer - 7;
|
||||
}
|
||||
}
|
||||
if (!prefixcmp(buffer, "author "))
|
||||
author = buffer + 7;
|
||||
buffer = eol;
|
||||
}
|
||||
|
||||
if (author == NULL)
|
||||
die ("Missing author: %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (buffer == NULL || *buffer == '\0') {
|
||||
oneline = "<none>";
|
||||
onelinelen = sizeof(oneline) + 1;
|
||||
} else {
|
||||
char *eol;
|
||||
|
||||
oneline = buffer + 1;
|
||||
eol = strchr(oneline, '\n');
|
||||
if (eol == NULL)
|
||||
onelinelen = strlen(oneline);
|
||||
else
|
||||
onelinelen = eol - oneline;
|
||||
}
|
||||
|
||||
insert_author_oneline(list,
|
||||
author, authorlen, oneline, onelinelen);
|
||||
if (!author)
|
||||
die("Missing author: %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
if (*buffer)
|
||||
buffer++;
|
||||
insert_one_record(list, author, !*buffer ? "<none>" : buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int parse_uint(char const **arg, int comma)
|
||||
@@ -260,6 +228,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
else if (!strcmp(argv[1], "-s") ||
|
||||
!strcmp(argv[1], "--summary"))
|
||||
summary = 1;
|
||||
else if (!strcmp(argv[1], "-e") ||
|
||||
!strcmp(argv[1], "--email"))
|
||||
email = 1;
|
||||
else if (!prefixcmp(argv[1], "-w")) {
|
||||
wrap_lines = 1;
|
||||
parse_wrap_args(argv[1], &in1, &in2, &wrap);
|
||||
@@ -278,9 +249,10 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
|
||||
read_mailmap(&mailmap, ".mailmap", &common_repo_prefix);
|
||||
|
||||
/* assume HEAD if from a tty */
|
||||
if (!rev.pending.nr && isatty(0))
|
||||
add_head_to_pending(&rev);
|
||||
if (rev.pending.nr == 0) {
|
||||
if (isatty(0))
|
||||
fprintf(stderr, "(reading log to summarize from standard input)\n");
|
||||
read_from_stdin(&list);
|
||||
}
|
||||
else
|
||||
@@ -294,7 +266,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
struct path_list *onelines = list.items[i].util;
|
||||
|
||||
if (summary) {
|
||||
printf("%s: %d\n", list.items[i].path, onelines->nr);
|
||||
printf("%6d\t%s\n", onelines->nr, list.items[i].path);
|
||||
} else {
|
||||
printf("%s (%d):\n", list.items[i].path, onelines->nr);
|
||||
for (j = onelines->nr - 1; j >= 0; j--) {
|
||||
|
||||
@@ -53,6 +53,8 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e
|
||||
die("There was a problem with the editor %s.", editor);
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
if (strbuf_read_file(buffer, path, 0) < 0)
|
||||
die("could not read message file '%s': %s",
|
||||
path, strerror(errno));
|
||||
@@ -186,7 +188,7 @@ static int do_sign(struct strbuf *buffer)
|
||||
int len;
|
||||
|
||||
if (!*signingkey) {
|
||||
if (strlcpy(signingkey, git_committer_info(1),
|
||||
if (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME),
|
||||
sizeof(signingkey)) > sizeof(signingkey) - 1)
|
||||
return error("committer info too long.");
|
||||
bracket = strchr(signingkey, '>');
|
||||
@@ -248,14 +250,18 @@ static const char tag_template[] =
|
||||
"# Write a tag message\n"
|
||||
"#\n";
|
||||
|
||||
static void set_signingkey(const char *value)
|
||||
{
|
||||
if (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey))
|
||||
die("signing key value too long (%.10s...)", value);
|
||||
}
|
||||
|
||||
static int git_tag_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "user.signingkey")) {
|
||||
if (!value)
|
||||
die("user.signingkey without value");
|
||||
if (strlcpy(signingkey, value, sizeof(signingkey))
|
||||
>= sizeof(signingkey))
|
||||
die("user.signingkey value too long");
|
||||
set_signingkey(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -310,7 +316,7 @@ static void create_tag(const unsigned char *object, const char *tag,
|
||||
sha1_to_hex(object),
|
||||
typename(type),
|
||||
tag,
|
||||
git_committer_info(1));
|
||||
git_committer_info(IDENT_ERROR_ON_NO_NAME));
|
||||
|
||||
if (header_len > sizeof(header_buf) - 1)
|
||||
die("tag header too big.");
|
||||
@@ -408,6 +414,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
|
||||
argc = parse_options(argc, argv, options, git_tag_usage, 0);
|
||||
|
||||
if (keyid) {
|
||||
sign = 1;
|
||||
set_signingkey(keyid);
|
||||
}
|
||||
if (sign)
|
||||
annotate = 1;
|
||||
|
||||
|
||||
17
cache.h
17
cache.h
@@ -468,6 +468,9 @@ void datestamp(char *buf, int bufsize);
|
||||
unsigned long approxidate(const char *);
|
||||
enum date_mode parse_date_format(const char *format);
|
||||
|
||||
#define IDENT_WARN_ON_NO_NAME 1
|
||||
#define IDENT_ERROR_ON_NO_NAME 2
|
||||
#define IDENT_NO_DATE 4
|
||||
extern const char *git_author_info(int);
|
||||
extern const char *git_committer_info(int);
|
||||
extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
|
||||
@@ -620,7 +623,7 @@ extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char
|
||||
/* pager.c */
|
||||
extern void setup_pager(void);
|
||||
extern char *pager_program;
|
||||
extern int pager_in_use;
|
||||
extern int pager_in_use(void);
|
||||
extern int pager_use_color;
|
||||
|
||||
extern char *editor_program;
|
||||
@@ -656,6 +659,18 @@ extern int diff_auto_refresh_index;
|
||||
/* match-trees.c */
|
||||
void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
|
||||
|
||||
/*
|
||||
* whitespace rules.
|
||||
* used by both diff and apply
|
||||
*/
|
||||
#define WS_TRAILING_SPACE 01
|
||||
#define WS_SPACE_BEFORE_TAB 02
|
||||
#define WS_INDENT_WITH_NON_TAB 04
|
||||
#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
|
||||
extern unsigned whitespace_rule_cfg;
|
||||
extern unsigned whitespace_rule(const char *);
|
||||
extern unsigned parse_whitespace_rule(const char *);
|
||||
|
||||
/* ls-files */
|
||||
int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen);
|
||||
int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset);
|
||||
|
||||
2
color.c
2
color.c
@@ -135,7 +135,7 @@ int git_config_colorbool(const char *var, const char *value, int stdout_is_tty)
|
||||
auto_color:
|
||||
if (stdout_is_tty < 0)
|
||||
stdout_is_tty = isatty(1);
|
||||
if (stdout_is_tty || (pager_in_use && pager_use_color)) {
|
||||
if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
|
||||
char *term = getenv("TERM");
|
||||
if (term && strcmp(term, "dumb"))
|
||||
return 1;
|
||||
|
||||
15
config.c
15
config.c
@@ -439,6 +439,11 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.whitespace")) {
|
||||
whitespace_rule_cfg = parse_whitespace_rule(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return 0;
|
||||
}
|
||||
@@ -646,13 +651,19 @@ static int store_write_pair(int fd, const char* key, const char* value)
|
||||
int length = strlen(key+store.baselen+1);
|
||||
int quote = 0;
|
||||
|
||||
/* Check to see if the value needs to be quoted. */
|
||||
/*
|
||||
* Check to see if the value needs to be surrounded with a dq pair.
|
||||
* Note that problematic characters are always backslash-quoted; this
|
||||
* check is about not losing leading or trailing SP and strings that
|
||||
* follow beginning-of-comment characters (i.e. ';' and '#') by the
|
||||
* configuration parser.
|
||||
*/
|
||||
if (value[0] == ' ')
|
||||
quote = 1;
|
||||
for (i = 0; value[i]; i++)
|
||||
if (value[i] == ';' || value[i] == '#')
|
||||
quote = 1;
|
||||
if (value[i-1] == ' ')
|
||||
if (i && value[i-1] == ' ')
|
||||
quote = 1;
|
||||
|
||||
if (write_in_full(fd, "\t", 1) != 1 ||
|
||||
|
||||
@@ -23,6 +23,7 @@ VPATH = @srcdir@
|
||||
export exec_prefix mandir
|
||||
export srcdir VPATH
|
||||
|
||||
ASCIIDOC8=@ASCIIDOC8@
|
||||
NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@
|
||||
NO_OPENSSL=@NO_OPENSSL@
|
||||
NO_CURL=@NO_CURL@
|
||||
|
||||
21
configure.ac
21
configure.ac
@@ -122,6 +122,27 @@ if test -z "$NO_TCLTK"; then
|
||||
AC_SUBST(TCLTK_PATH)
|
||||
fi
|
||||
fi
|
||||
AC_CHECK_PROGS(ASCIIDOC, [asciidoc])
|
||||
if test -n "$ASCIIDOC"; then
|
||||
AC_MSG_CHECKING([for asciidoc version])
|
||||
asciidoc_version=`$ASCIIDOC --version 2>&1`
|
||||
case "${asciidoc_version}" in
|
||||
asciidoc' '8*)
|
||||
ASCIIDOC8=YesPlease
|
||||
AC_MSG_RESULT([${asciidoc_version} > 7])
|
||||
;;
|
||||
asciidoc' '7*)
|
||||
ASCIIDOC8=
|
||||
AC_MSG_RESULT([${asciidoc_version}])
|
||||
;;
|
||||
*)
|
||||
ASCIIDOC8=
|
||||
AC_MSG_RESULT([${asciidoc_version} (unknown)])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
AC_SUBST(ASCIIDOC8)
|
||||
|
||||
|
||||
## Checks for libraries.
|
||||
AC_MSG_NOTICE([CHECKS for libraries])
|
||||
|
||||
@@ -523,8 +523,13 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
||||
end = host;
|
||||
|
||||
path = strchr(end, c);
|
||||
#ifdef __MINGW32__
|
||||
/* host must have at least 2 chars to catch DOS C:/path */
|
||||
if (path && path - end > 1) {
|
||||
if (path && path - end > 1)
|
||||
#else
|
||||
if (path)
|
||||
#endif
|
||||
{
|
||||
if (c == ':') {
|
||||
protocol = PROTO_SSH;
|
||||
*path++ = '\0';
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
(eval-when-compile (require 'cl))
|
||||
(require 'ewoc)
|
||||
(require 'log-edit)
|
||||
(require 'easymenu)
|
||||
|
||||
|
||||
;;;; Customizations
|
||||
@@ -1297,7 +1298,47 @@ Return the list of files that haven't been handled."
|
||||
(define-key toggle-map "i" 'git-toggle-show-ignored)
|
||||
(define-key toggle-map "k" 'git-toggle-show-unknown)
|
||||
(define-key toggle-map "m" 'git-toggle-all-marks)
|
||||
(setq git-status-mode-map map)))
|
||||
(setq git-status-mode-map map))
|
||||
(easy-menu-define git-menu git-status-mode-map
|
||||
"Git Menu"
|
||||
`("Git"
|
||||
["Refresh" git-refresh-status t]
|
||||
["Commit" git-commit-file t]
|
||||
("Merge"
|
||||
["Next Unmerged File" git-next-unmerged-file t]
|
||||
["Prev Unmerged File" git-prev-unmerged-file t]
|
||||
["Mark as Resolved" git-resolve-file t]
|
||||
["Interactive Merge File" git-find-file-imerge t]
|
||||
["Diff Against Common Base File" git-diff-file-base t]
|
||||
["Diff Combined" git-diff-file-combined t]
|
||||
["Diff Against Merge Head" git-diff-file-merge-head t]
|
||||
["Diff Against Mine" git-diff-file-mine t]
|
||||
["Diff Against Other" git-diff-file-other t])
|
||||
"--------"
|
||||
["Add File" git-add-file t]
|
||||
["Revert File" git-revert-file t]
|
||||
["Ignore File" git-ignore-file t]
|
||||
["Remove File" git-remove-file t]
|
||||
"--------"
|
||||
["Find File" git-find-file t]
|
||||
["View File" git-view-file t]
|
||||
["Diff File" git-diff-file t]
|
||||
["Interactive Diff File" git-diff-file-idiff t]
|
||||
["Log" git-log-file t]
|
||||
"--------"
|
||||
["Mark" git-mark-file t]
|
||||
["Mark All" git-mark-all t]
|
||||
["Unmark" git-unmark-file t]
|
||||
["Unmark All" git-unmark-all t]
|
||||
["Toggle All Marks" git-toggle-all-marks t]
|
||||
["Hide Handled Files" git-remove-handled t]
|
||||
"--------"
|
||||
["Show Uptodate Files" git-toggle-show-uptodate :style toggle :selected git-show-uptodate]
|
||||
["Show Ignored Files" git-toggle-show-ignored :style toggle :selected git-show-ignored]
|
||||
["Show Unknown Files" git-toggle-show-unknown :style toggle :selected git-show-unknown]
|
||||
"--------"
|
||||
["Quit" git-status-quit t])))
|
||||
|
||||
|
||||
;; git mode should only run in the *git status* buffer
|
||||
(put 'git-status-mode 'mode-class 'special)
|
||||
|
||||
157
diff.c
157
diff.c
@@ -454,6 +454,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
||||
struct emit_callback {
|
||||
struct xdiff_emit_state xm;
|
||||
int nparents, color_diff;
|
||||
unsigned ws_rule;
|
||||
const char **label_path;
|
||||
struct diff_words_data *diff_words;
|
||||
int *found_changesp;
|
||||
@@ -493,8 +494,8 @@ static void emit_line(const char *set, const char *reset, const char *line, int
|
||||
}
|
||||
|
||||
static void emit_line_with_ws(int nparents,
|
||||
const char *set, const char *reset, const char *ws,
|
||||
const char *line, int len)
|
||||
const char *set, const char *reset, const char *ws,
|
||||
const char *line, int len, unsigned ws_rule)
|
||||
{
|
||||
int col0 = nparents;
|
||||
int last_tab_in_indent = -1;
|
||||
@@ -502,13 +503,17 @@ static void emit_line_with_ws(int nparents,
|
||||
int i;
|
||||
int tail = len;
|
||||
int need_highlight_leading_space = 0;
|
||||
/* The line is a newly added line. Does it have funny leading
|
||||
* whitespaces? In indent, SP should never precede a TAB.
|
||||
/*
|
||||
* The line is a newly added line. Does it have funny leading
|
||||
* whitespaces? In indent, SP should never precede a TAB. In
|
||||
* addition, under "indent with non tab" rule, there should not
|
||||
* be more than 8 consecutive spaces.
|
||||
*/
|
||||
for (i = col0; i < len; i++) {
|
||||
if (line[i] == '\t') {
|
||||
last_tab_in_indent = i;
|
||||
if (0 <= last_space_in_indent)
|
||||
if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
|
||||
0 <= last_space_in_indent)
|
||||
need_highlight_leading_space = 1;
|
||||
}
|
||||
else if (line[i] == ' ')
|
||||
@@ -516,6 +521,13 @@ static void emit_line_with_ws(int nparents,
|
||||
else
|
||||
break;
|
||||
}
|
||||
if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
|
||||
0 <= last_space_in_indent &&
|
||||
last_tab_in_indent < 0 &&
|
||||
8 <= (i - col0)) {
|
||||
last_tab_in_indent = i;
|
||||
need_highlight_leading_space = 1;
|
||||
}
|
||||
fputs(set, stdout);
|
||||
fwrite(line, col0, 1, stdout);
|
||||
fputs(reset, stdout);
|
||||
@@ -540,10 +552,12 @@ static void emit_line_with_ws(int nparents,
|
||||
tail = len - 1;
|
||||
if (line[tail] == '\n' && i < tail)
|
||||
tail--;
|
||||
while (i < tail) {
|
||||
if (!isspace(line[tail]))
|
||||
break;
|
||||
tail--;
|
||||
if (ws_rule & WS_TRAILING_SPACE) {
|
||||
while (i < tail) {
|
||||
if (!isspace(line[tail]))
|
||||
break;
|
||||
tail--;
|
||||
}
|
||||
}
|
||||
if ((i < tail && line[tail + 1] != '\n')) {
|
||||
/* This has whitespace between tail+1..len */
|
||||
@@ -565,7 +579,7 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons
|
||||
emit_line(set, reset, line, len);
|
||||
else
|
||||
emit_line_with_ws(ecbdata->nparents, set, reset, ws,
|
||||
line, len);
|
||||
line, len, ecbdata->ws_rule);
|
||||
}
|
||||
|
||||
static void fn_out_consume(void *priv, char *line, unsigned long len)
|
||||
@@ -720,7 +734,9 @@ struct diffstat_t {
|
||||
int nr;
|
||||
int alloc;
|
||||
struct diffstat_file {
|
||||
char *from_name;
|
||||
char *name;
|
||||
char *print_name;
|
||||
unsigned is_unmerged:1;
|
||||
unsigned is_binary:1;
|
||||
unsigned is_renamed:1;
|
||||
@@ -741,11 +757,14 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
|
||||
}
|
||||
diffstat->files[diffstat->nr++] = x;
|
||||
if (name_b) {
|
||||
x->name = pprint_rename(name_a, name_b);
|
||||
x->from_name = xstrdup(name_a);
|
||||
x->name = xstrdup(name_b);
|
||||
x->is_renamed = 1;
|
||||
}
|
||||
else
|
||||
else {
|
||||
x->from_name = NULL;
|
||||
x->name = xstrdup(name_a);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -789,6 +808,28 @@ static void show_graph(char ch, int cnt, const char *set, const char *reset)
|
||||
printf("%s", reset);
|
||||
}
|
||||
|
||||
static void fill_print_name(struct diffstat_file *file)
|
||||
{
|
||||
char *pname;
|
||||
|
||||
if (file->print_name)
|
||||
return;
|
||||
|
||||
if (!file->is_renamed) {
|
||||
struct strbuf buf;
|
||||
strbuf_init(&buf, 0);
|
||||
if (quote_c_style(file->name, &buf, NULL, 0)) {
|
||||
pname = strbuf_detach(&buf, NULL);
|
||||
} else {
|
||||
pname = file->name;
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
} else {
|
||||
pname = pprint_rename(file->from_name, file->name);
|
||||
}
|
||||
file->print_name = pname;
|
||||
}
|
||||
|
||||
static void show_stats(struct diffstat_t* data, struct diff_options *options)
|
||||
{
|
||||
int i, len, add, del, total, adds = 0, dels = 0;
|
||||
@@ -822,19 +863,8 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
|
||||
for (i = 0; i < data->nr; i++) {
|
||||
struct diffstat_file *file = data->files[i];
|
||||
int change = file->added + file->deleted;
|
||||
|
||||
if (!file->is_renamed) { /* renames are already quoted by pprint_rename */
|
||||
struct strbuf buf;
|
||||
strbuf_init(&buf, 0);
|
||||
if (quote_c_style(file->name, &buf, NULL, 0)) {
|
||||
free(file->name);
|
||||
file->name = strbuf_detach(&buf, NULL);
|
||||
} else {
|
||||
strbuf_release(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
len = strlen(file->name);
|
||||
fill_print_name(file);
|
||||
len = strlen(file->print_name);
|
||||
if (max_len < len)
|
||||
max_len = len;
|
||||
|
||||
@@ -859,7 +889,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
|
||||
|
||||
for (i = 0; i < data->nr; i++) {
|
||||
const char *prefix = "";
|
||||
char *name = data->files[i]->name;
|
||||
char *name = data->files[i]->print_name;
|
||||
int added = data->files[i]->added;
|
||||
int deleted = data->files[i]->deleted;
|
||||
int name_len;
|
||||
@@ -887,17 +917,17 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
|
||||
printf("%s%d%s", add_c, added, reset);
|
||||
printf(" bytes");
|
||||
printf("\n");
|
||||
goto free_diffstat_file;
|
||||
continue;
|
||||
}
|
||||
else if (data->files[i]->is_unmerged) {
|
||||
show_name(prefix, name, len, reset, set);
|
||||
printf(" Unmerged\n");
|
||||
goto free_diffstat_file;
|
||||
continue;
|
||||
}
|
||||
else if (!data->files[i]->is_renamed &&
|
||||
(added + deleted == 0)) {
|
||||
total_files--;
|
||||
goto free_diffstat_file;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -919,11 +949,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
|
||||
show_graph('+', add, add_c, reset);
|
||||
show_graph('-', del, del_c, reset);
|
||||
putchar('\n');
|
||||
free_diffstat_file:
|
||||
free(data->files[i]->name);
|
||||
free(data->files[i]);
|
||||
}
|
||||
free(data->files);
|
||||
printf("%s %d files changed, %d insertions(+), %d deletions(-)%s\n",
|
||||
set, total_files, adds, dels, reset);
|
||||
}
|
||||
@@ -948,11 +974,7 @@ static void show_shortstats(struct diffstat_t* data)
|
||||
dels += deleted;
|
||||
}
|
||||
}
|
||||
free(data->files[i]->name);
|
||||
free(data->files[i]);
|
||||
}
|
||||
free(data->files);
|
||||
|
||||
printf(" %d files changed, %d insertions(+), %d deletions(-)\n",
|
||||
total_files, adds, dels);
|
||||
}
|
||||
@@ -961,6 +983,9 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (data->nr == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < data->nr; i++) {
|
||||
struct diffstat_file *file = data->files[i];
|
||||
|
||||
@@ -968,19 +993,44 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
|
||||
printf("-\t-\t");
|
||||
else
|
||||
printf("%d\t%d\t", file->added, file->deleted);
|
||||
if (!file->is_renamed) {
|
||||
write_name_quoted(file->name, stdout, options->line_termination);
|
||||
if (options->line_termination) {
|
||||
fill_print_name(file);
|
||||
if (!file->is_renamed)
|
||||
write_name_quoted(file->name, stdout,
|
||||
options->line_termination);
|
||||
else {
|
||||
fputs(file->print_name, stdout);
|
||||
putchar(options->line_termination);
|
||||
}
|
||||
} else {
|
||||
fputs(file->name, stdout);
|
||||
putchar(options->line_termination);
|
||||
if (file->is_renamed) {
|
||||
putchar('\0');
|
||||
write_name_quoted(file->from_name, stdout, '\0');
|
||||
}
|
||||
write_name_quoted(file->name, stdout, '\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_diffstat_info(struct diffstat_t *diffstat)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < diffstat->nr; i++) {
|
||||
struct diffstat_file *f = diffstat->files[i];
|
||||
if (f->name != f->print_name)
|
||||
free(f->print_name);
|
||||
free(f->name);
|
||||
free(f->from_name);
|
||||
free(f);
|
||||
}
|
||||
free(diffstat->files);
|
||||
}
|
||||
|
||||
struct checkdiff_t {
|
||||
struct xdiff_emit_state xm;
|
||||
const char *filename;
|
||||
int lineno, color_diff;
|
||||
unsigned ws_rule;
|
||||
};
|
||||
|
||||
static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
@@ -994,13 +1044,20 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
|
||||
|
||||
/* check space before tab */
|
||||
for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
|
||||
for (i = 1; i < len; i++) {
|
||||
if (line[i] == ' ')
|
||||
spaces++;
|
||||
if (line[i - 1] == '\t' && spaces)
|
||||
space_before_tab = 1;
|
||||
else if (line[i] == '\t') {
|
||||
if (spaces) {
|
||||
space_before_tab = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* check white space at line end */
|
||||
/* check whitespace at line end */
|
||||
if (line[len - 1] == '\n')
|
||||
len--;
|
||||
if (isspace(line[len - 1]))
|
||||
@@ -1014,9 +1071,10 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
|
||||
putchar(',');
|
||||
}
|
||||
if (white_space_at_end)
|
||||
printf("white space at end");
|
||||
printf("whitespace at end");
|
||||
printf(":%s ", reset);
|
||||
emit_line_with_ws(1, set, reset, ws, line, len);
|
||||
emit_line_with_ws(1, set, reset, ws, line, len,
|
||||
data->ws_rule);
|
||||
}
|
||||
|
||||
data->lineno++;
|
||||
@@ -1317,6 +1375,7 @@ static void builtin_diff(const char *name_a,
|
||||
ecbdata.label_path = lbl;
|
||||
ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
|
||||
ecbdata.found_changesp = &o->found_changes;
|
||||
ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
|
||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||
xecfg.ctxlen = o->context;
|
||||
xecfg.flags = XDL_EMIT_FUNCNAMES;
|
||||
@@ -1410,6 +1469,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
||||
data.filename = name_b ? name_b : name_a;
|
||||
data.lineno = 0;
|
||||
data.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
|
||||
data.ws_rule = whitespace_rule(data.filename);
|
||||
|
||||
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
|
||||
die("unable to read files to diff");
|
||||
@@ -2925,8 +2985,9 @@ void diff_flush(struct diff_options *options)
|
||||
show_numstat(&diffstat, options);
|
||||
if (output_format & DIFF_FORMAT_DIFFSTAT)
|
||||
show_stats(&diffstat, options);
|
||||
else if (output_format & DIFF_FORMAT_SHORTSTAT)
|
||||
if (output_format & DIFF_FORMAT_SHORTSTAT)
|
||||
show_shortstats(&diffstat);
|
||||
free_diffstat_info(&diffstat);
|
||||
separator++;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
|
||||
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
|
||||
size_t delta_base_cache_limit = 16 * 1024 * 1024;
|
||||
char *pager_program;
|
||||
int pager_in_use;
|
||||
int pager_use_color = 1;
|
||||
char *editor_program;
|
||||
char *excludes_file;
|
||||
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
|
||||
|
||||
/* This is set by setup_git_dir_gently() and/or git_default_config() */
|
||||
char *git_work_tree_cfg;
|
||||
|
||||
@@ -525,42 +525,23 @@ sub add_untracked_cmd {
|
||||
sub parse_diff {
|
||||
my ($path) = @_;
|
||||
my @diff = run_cmd_pipe(qw(git diff-files -p --), $path);
|
||||
my (@hunk) = { TEXT => [] };
|
||||
my @colored = ();
|
||||
if ($diff_use_color) {
|
||||
@colored = run_cmd_pipe(qw(git diff-files -p --color --), $path);
|
||||
}
|
||||
my (@hunk) = { TEXT => [], DISPLAY => [] };
|
||||
|
||||
for (@diff) {
|
||||
if (/^@@ /) {
|
||||
push @hunk, { TEXT => [] };
|
||||
for (my $i = 0; $i < @diff; $i++) {
|
||||
if ($diff[$i] =~ /^@@ /) {
|
||||
push @hunk, { TEXT => [], DISPLAY => [] };
|
||||
}
|
||||
push @{$hunk[-1]{TEXT}}, $_;
|
||||
push @{$hunk[-1]{TEXT}}, $diff[$i];
|
||||
push @{$hunk[-1]{DISPLAY}},
|
||||
($diff_use_color ? $colored[$i] : $diff[$i]);
|
||||
}
|
||||
return @hunk;
|
||||
}
|
||||
|
||||
sub colored_diff_hunk {
|
||||
my ($text) = @_;
|
||||
# return the text, so that it can be passed to print()
|
||||
my @ret;
|
||||
for (@$text) {
|
||||
if (!$diff_use_color) {
|
||||
push @ret, $_;
|
||||
next;
|
||||
}
|
||||
|
||||
if (/^\+/) {
|
||||
push @ret, colored($new_color, $_);
|
||||
} elsif (/^\-/) {
|
||||
push @ret, colored($old_color, $_);
|
||||
} elsif (/^\@/) {
|
||||
push @ret, colored($fraginfo_color, $_);
|
||||
} elsif (/^ /) {
|
||||
push @ret, colored($normal_color, $_);
|
||||
} else {
|
||||
push @ret, colored($metainfo_color, $_);
|
||||
}
|
||||
}
|
||||
return @ret;
|
||||
}
|
||||
|
||||
sub hunk_splittable {
|
||||
my ($text) = @_;
|
||||
|
||||
@@ -578,9 +559,11 @@ sub parse_hunk_header {
|
||||
}
|
||||
|
||||
sub split_hunk {
|
||||
my ($text) = @_;
|
||||
my ($text, $display) = @_;
|
||||
my @split = ();
|
||||
|
||||
if (!defined $display) {
|
||||
$display = $text;
|
||||
}
|
||||
# If there are context lines in the middle of a hunk,
|
||||
# it can be split, but we would need to take care of
|
||||
# overlaps later.
|
||||
@@ -594,16 +577,19 @@ sub split_hunk {
|
||||
my $i = $hunk_start - 1;
|
||||
my $this = +{
|
||||
TEXT => [],
|
||||
DISPLAY => [],
|
||||
OLD => $o_ofs,
|
||||
NEW => $n_ofs,
|
||||
OCNT => 0,
|
||||
NCNT => 0,
|
||||
ADDDEL => 0,
|
||||
POSTCTX => 0,
|
||||
USE => undef,
|
||||
};
|
||||
|
||||
while (++$i < @$text) {
|
||||
my $line = $text->[$i];
|
||||
my $display = $display->[$i];
|
||||
if ($line =~ /^ /) {
|
||||
if ($this->{ADDDEL} &&
|
||||
!defined $next_hunk_start) {
|
||||
@@ -615,6 +601,7 @@ sub split_hunk {
|
||||
$next_hunk_start = $i;
|
||||
}
|
||||
push @{$this->{TEXT}}, $line;
|
||||
push @{$this->{DISPLAY}}, $display;
|
||||
$this->{OCNT}++;
|
||||
$this->{NCNT}++;
|
||||
if (defined $next_hunk_start) {
|
||||
@@ -637,6 +624,7 @@ sub split_hunk {
|
||||
redo OUTER;
|
||||
}
|
||||
push @{$this->{TEXT}}, $line;
|
||||
push @{$this->{DISPLAY}}, $display;
|
||||
$this->{ADDDEL}++;
|
||||
if ($line =~ /^-/) {
|
||||
$this->{OCNT}++;
|
||||
@@ -661,9 +649,14 @@ sub split_hunk {
|
||||
" +$n_ofs" .
|
||||
(($n_cnt != 1) ? ",$n_cnt" : '') .
|
||||
" @@\n");
|
||||
my $display_head = $head;
|
||||
unshift @{$hunk->{TEXT}}, $head;
|
||||
if ($diff_use_color) {
|
||||
$display_head = colored($fraginfo_color, $head);
|
||||
}
|
||||
unshift @{$hunk->{DISPLAY}}, $display_head;
|
||||
}
|
||||
return map { $_->{TEXT} } @split;
|
||||
return @split;
|
||||
}
|
||||
|
||||
sub find_last_o_ctx {
|
||||
@@ -794,7 +787,9 @@ sub patch_update_file {
|
||||
my ($ix, $num);
|
||||
my $path = shift;
|
||||
my ($head, @hunk) = parse_diff($path);
|
||||
print colored_diff_hunk($head->{TEXT});
|
||||
for (@{$head->{DISPLAY}}) {
|
||||
print;
|
||||
}
|
||||
$num = scalar @hunk;
|
||||
$ix = 0;
|
||||
|
||||
@@ -836,7 +831,9 @@ sub patch_update_file {
|
||||
if (hunk_splittable($hunk[$ix]{TEXT})) {
|
||||
$other .= '/s';
|
||||
}
|
||||
print colored_diff_hunk($hunk[$ix]{TEXT});
|
||||
for (@{$hunk[$ix]{DISPLAY}}) {
|
||||
print;
|
||||
}
|
||||
print colored $prompt_color, "Stage this hunk [y/n/a/d$other/?]? ";
|
||||
my $line = <STDIN>;
|
||||
if ($line) {
|
||||
@@ -889,14 +886,12 @@ sub patch_update_file {
|
||||
next;
|
||||
}
|
||||
elsif ($other =~ /s/ && $line =~ /^s/) {
|
||||
my @split = split_hunk($hunk[$ix]{TEXT});
|
||||
my @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});
|
||||
if (1 < @split) {
|
||||
print colored $header_color, "Split into ",
|
||||
scalar(@split), " hunks.\n";
|
||||
}
|
||||
splice(@hunk, $ix, 1,
|
||||
map { +{ TEXT => $_, USE => undef } }
|
||||
@split);
|
||||
splice (@hunk, $ix, 1, @split);
|
||||
$num = scalar @hunk;
|
||||
next;
|
||||
}
|
||||
|
||||
@@ -324,8 +324,23 @@ bisect_next() {
|
||||
|
||||
bisect_visualize() {
|
||||
bisect_next_check fail
|
||||
|
||||
if test $# = 0
|
||||
then
|
||||
case "${DISPLAY+set}" in
|
||||
'') set git log ;;
|
||||
set) set gitk ;;
|
||||
esac
|
||||
else
|
||||
case "$1" in
|
||||
git*|tig) ;;
|
||||
-*) set git log "$@" ;;
|
||||
*) set git "$@" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
not=$(git for-each-ref --format='%(refname)' "refs/bisect/good-*")
|
||||
eval gitk refs/bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
|
||||
eval '"$@"' refs/bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
|
||||
}
|
||||
|
||||
bisect_reset() {
|
||||
@@ -449,7 +464,7 @@ case "$#" in
|
||||
next)
|
||||
# Not sure we want "next" at the UI level anymore.
|
||||
bisect_next "$@" ;;
|
||||
visualize)
|
||||
visualize|view)
|
||||
bisect_visualize "$@" ;;
|
||||
reset)
|
||||
bisect_reset "$@" ;;
|
||||
|
||||
149
git-browse-help.sh
Executable file
149
git-browse-help.sh
Executable file
@@ -0,0 +1,149 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This program launch a web browser on the html page
|
||||
# describing a git command.
|
||||
#
|
||||
# Copyright (c) 2007 Christian Couder
|
||||
# Copyright (c) 2006 Theodore Y. Ts'o
|
||||
#
|
||||
# This file is heavily stolen from git-mergetool.sh, by
|
||||
# Theodore Y. Ts'o (thanks) that is:
|
||||
#
|
||||
# Copyright (c) 2006 Theodore Y. Ts'o
|
||||
#
|
||||
# This file is licensed under the GPL v2, or a later version
|
||||
# at the discretion of Junio C Hamano or any other official
|
||||
# git maintainer.
|
||||
#
|
||||
|
||||
USAGE='[--browser=browser|--tool=browser] [cmd to display] ...'
|
||||
|
||||
# This must be capable of running outside of git directory, so
|
||||
# the vanilla git-sh-setup should not be used.
|
||||
NONGIT_OK=Yes
|
||||
. git-sh-setup
|
||||
|
||||
# Install data.
|
||||
html_dir="@@HTMLDIR@@"
|
||||
|
||||
test -f "$html_dir/git.html" || die "No documentation directory found."
|
||||
|
||||
valid_tool() {
|
||||
case "$1" in
|
||||
firefox | iceweasel | konqueror | w3m | links | lynx | dillo)
|
||||
;; # happy
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
init_browser_path() {
|
||||
test -z "$GIT_DIR" || browser_path=`git config browser.$1.path`
|
||||
test -z "$browser_path" && browser_path=$1
|
||||
}
|
||||
|
||||
while test $# != 0
|
||||
do
|
||||
case "$1" in
|
||||
-b|--browser*|-t|--tool*)
|
||||
case "$#,$1" in
|
||||
*,*=*)
|
||||
browser=`expr "z$1" : 'z-[^=]*=\(.*\)'`
|
||||
;;
|
||||
1,*)
|
||||
usage ;;
|
||||
*)
|
||||
browser="$2"
|
||||
shift ;;
|
||||
esac
|
||||
;;
|
||||
--)
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$browser" && test -n "$GIT_DIR"
|
||||
then
|
||||
for opt in "help.browser" "web.browser"
|
||||
do
|
||||
browser="`git config $opt`"
|
||||
test -z "$browser" || break
|
||||
done
|
||||
if test -n "$browser" && ! valid_tool "$browser"; then
|
||||
echo >&2 "git config option $opt set to unknown browser: $browser"
|
||||
echo >&2 "Resetting to default..."
|
||||
unset browser
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$browser" ; then
|
||||
if test -n "$DISPLAY"; then
|
||||
browser_candidates="firefox iceweasel konqueror w3m links lynx dillo"
|
||||
if test "$KDE_FULL_SESSION" = "true"; then
|
||||
browser_candidates="konqueror $browser_candidates"
|
||||
fi
|
||||
else
|
||||
browser_candidates="w3m links lynx"
|
||||
fi
|
||||
|
||||
for i in $browser_candidates; do
|
||||
init_browser_path $i
|
||||
if type "$browser_path" > /dev/null 2>&1; then
|
||||
browser=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
test -z "$browser" && die "No known browser available."
|
||||
else
|
||||
valid_tool "$browser" || die "Unknown browser '$browser'."
|
||||
|
||||
init_browser_path "$browser"
|
||||
|
||||
if ! type "$browser_path" > /dev/null 2>&1; then
|
||||
die "The browser $browser is not available as '$browser_path'."
|
||||
fi
|
||||
fi
|
||||
|
||||
pages=$(for p in "$@"; do echo "$html_dir/$p.html" ; done)
|
||||
test -z "$pages" && pages="$html_dir/git.html"
|
||||
|
||||
case "$browser" in
|
||||
firefox|iceweasel)
|
||||
# Check version because firefox < 2.0 does not support "-new-tab".
|
||||
vers=$(expr "$($browser_path -version)" : '.* \([0-9][0-9]*\)\..*')
|
||||
NEWTAB='-new-tab'
|
||||
test "$vers" -lt 2 && NEWTAB=''
|
||||
nohup "$browser_path" $NEWTAB $pages &
|
||||
;;
|
||||
konqueror)
|
||||
case "$(basename "$browser_path")" in
|
||||
konqueror)
|
||||
# It's simpler to use kfmclient to open a new tab in konqueror.
|
||||
browser_path="$(echo "$browser_path" | sed -e 's/konqueror$/kfmclient/')"
|
||||
type "$browser_path" > /dev/null 2>&1 || die "No '$browser_path' found."
|
||||
eval "$browser_path" newTab $pages
|
||||
;;
|
||||
kfmclient)
|
||||
eval "$browser_path" newTab $pages
|
||||
;;
|
||||
*)
|
||||
nohup "$browser_path" $pages &
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
w3m|links|lynx)
|
||||
eval "$browser_path" $pages
|
||||
;;
|
||||
dillo)
|
||||
nohup "$browser_path" $pages &
|
||||
;;
|
||||
esac
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
OPTIONS_KEEPDASHDASH=t
|
||||
OPTIONS_SPEC="\
|
||||
git-branch [options] [<branch>] [<paths>...]
|
||||
git-checkout [options] [<branch>] [<paths>...]
|
||||
--
|
||||
b= create a new branch started at <branch>
|
||||
l create the new branchs reflog
|
||||
track tells if the new branch should track the remote branch
|
||||
l create the new branch's reflog
|
||||
track arrange that the new branch tracks the remote branch
|
||||
f proceed even if the index or working tree is not HEAD
|
||||
m performa three-way merge on local modifications if needed
|
||||
m merge local modifications into the new branch
|
||||
q,quiet be quiet
|
||||
"
|
||||
SUBDIRECTORY_OK=Sometimes
|
||||
|
||||
@@ -244,7 +244,10 @@ fi
|
||||
# it is local
|
||||
if base=$(get_repo_base "$repo"); then
|
||||
repo="$base"
|
||||
local=yes
|
||||
if test -z "$depth"
|
||||
then
|
||||
local=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
dir="$2"
|
||||
@@ -336,7 +339,8 @@ yes)
|
||||
find objects -type f -print | sed -e 1q)
|
||||
# objects directory should not be empty because
|
||||
# we are cloning!
|
||||
test -f "$repo/$sample_file" || exit
|
||||
test -f "$repo/$sample_file" ||
|
||||
die "fatal: cannot clone empty repository"
|
||||
if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
|
||||
then
|
||||
rm -f "$GIT_DIR/objects/sample"
|
||||
|
||||
@@ -24,6 +24,7 @@ fqgitdir="$GIT_DIR"
|
||||
local="`git config --bool --get instaweb.local`"
|
||||
httpd="`git config --get instaweb.httpd`"
|
||||
browser="`git config --get instaweb.browser`"
|
||||
test -z "$browser" && browser="`git config --get web.browser`"
|
||||
port=`git config --get instaweb.port`
|
||||
module_path="`git config --get instaweb.modulepath`"
|
||||
|
||||
|
||||
@@ -80,6 +80,10 @@ case "${1:-.}${2:-.}${3:-.}" in
|
||||
echo "ERROR: $4: Not merging symbolic link changes."
|
||||
exit 1
|
||||
;;
|
||||
*,160000,*)
|
||||
echo "ERROR: $4: Not merging conflicting submodule changes."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
src2=`git-unpack-file $3`
|
||||
|
||||
@@ -152,10 +152,11 @@ merge_file () {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP="$path.BACKUP.$$"
|
||||
LOCAL="$path.LOCAL.$$"
|
||||
REMOTE="$path.REMOTE.$$"
|
||||
BASE="$path.BASE.$$"
|
||||
ext="$$$(expr "$path" : '.*\(\.[^/]*\)$')"
|
||||
BACKUP="$path.BACKUP.$ext"
|
||||
LOCAL="$path.LOCAL.$ext"
|
||||
REMOTE="$path.REMOTE.$ext"
|
||||
BASE="$path.BASE.$ext"
|
||||
|
||||
mv -- "$path" "$BACKUP"
|
||||
cp -- "$BACKUP" "$path"
|
||||
|
||||
@@ -367,8 +367,10 @@ if ($thread && !defined $initial_reply_to && $prompting) {
|
||||
} while (!defined $_);
|
||||
|
||||
$initial_reply_to = $_;
|
||||
$initial_reply_to =~ s/^\s+<?/</;
|
||||
$initial_reply_to =~ s/>?\s+$/>/;
|
||||
}
|
||||
if (defined $initial_reply_to && $_ ne "") {
|
||||
$initial_reply_to =~ s/^\s*<?/</;
|
||||
$initial_reply_to =~ s/>?\s*$/>/;
|
||||
}
|
||||
|
||||
if (!defined $smtp_server) {
|
||||
|
||||
@@ -122,30 +122,37 @@ get_author_ident_from_commit () {
|
||||
LANG=C LC_ALL=C sed -ne "$pick_author_script"
|
||||
}
|
||||
|
||||
# Make sure we are in a valid repository of a vintage we understand.
|
||||
if [ -z "$SUBDIRECTORY_OK" ]
|
||||
# Make sure we are in a valid repository of a vintage we understand,
|
||||
# if we require to be in a git repository.
|
||||
if test -n "$NONGIT_OK"
|
||||
then
|
||||
: ${GIT_DIR=.git}
|
||||
test -z "$(git rev-parse --show-cdup)" || {
|
||||
exit=$?
|
||||
echo >&2 "You need to run this command from the toplevel of the working tree."
|
||||
exit $exit
|
||||
}
|
||||
if git rev-parse --git-dir >/dev/null 2>&1
|
||||
then
|
||||
: ${GIT_DIR=.git}
|
||||
fi
|
||||
else
|
||||
GIT_DIR=$(git rev-parse --git-dir) || {
|
||||
exit=$?
|
||||
echo >&2 "Failed to find a valid git directory."
|
||||
exit $exit
|
||||
if [ -z "$SUBDIRECTORY_OK" ]
|
||||
then
|
||||
: ${GIT_DIR=.git}
|
||||
test -z "$(git rev-parse --show-cdup)" || {
|
||||
exit=$?
|
||||
echo >&2 "You need to run this command from the toplevel of the working tree."
|
||||
exit $exit
|
||||
}
|
||||
else
|
||||
GIT_DIR=$(git rev-parse --git-dir) || {
|
||||
exit=$?
|
||||
echo >&2 "Failed to find a valid git directory."
|
||||
exit $exit
|
||||
}
|
||||
fi
|
||||
test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
|
||||
echo >&2 "Unable to determine absolute path of git directory"
|
||||
exit 1
|
||||
}
|
||||
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
|
||||
fi
|
||||
|
||||
test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
|
||||
echo >&2 "Unable to determine absolute path of git directory"
|
||||
exit 1
|
||||
}
|
||||
|
||||
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
|
||||
|
||||
# Fix some commands on Windows
|
||||
case $(uname -s) in
|
||||
*MINGW*)
|
||||
|
||||
358
git-svn.perl
358
git-svn.perl
@@ -529,7 +529,7 @@ sub cmd_find_rev {
|
||||
"$head history\n";
|
||||
}
|
||||
my $desired_revision = substr($revision_or_hash, 1);
|
||||
$result = $gs->rev_db_get($desired_revision);
|
||||
$result = $gs->rev_map_get($desired_revision);
|
||||
} else {
|
||||
my (undef, $rev, undef) = cmt_metadata($revision_or_hash);
|
||||
$result = $rev;
|
||||
@@ -1128,12 +1128,12 @@ sub working_head_info {
|
||||
if (defined $url && defined $rev) {
|
||||
next if $max{$url} and $max{$url} < $rev;
|
||||
if (my $gs = Git::SVN->find_by_url($url)) {
|
||||
my $c = $gs->rev_db_get($rev);
|
||||
my $c = $gs->rev_map_get($rev);
|
||||
if ($c && $c eq $hash) {
|
||||
close $fh; # break the pipe
|
||||
return ($url, $rev, $uuid, $gs);
|
||||
} else {
|
||||
$max{$url} ||= $gs->rev_db_max;
|
||||
$max{$url} ||= $gs->rev_map_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1234,6 +1234,8 @@ sub md5sum {
|
||||
package Git::SVN;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Fcntl qw/:DEFAULT :seek/;
|
||||
use constant rev_map_fmt => 'NH40';
|
||||
use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
|
||||
$_repack $_repack_flags $_use_svm_props $_head
|
||||
$_use_svnsync_props $no_reuse_existing $_minimize_url
|
||||
@@ -1362,7 +1364,7 @@ sub fetch_all {
|
||||
if ($fetch) {
|
||||
foreach my $p (sort keys %$fetch) {
|
||||
my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p);
|
||||
my $lr = $gs->rev_db_max;
|
||||
my $lr = $gs->rev_map_max;
|
||||
if (defined $lr) {
|
||||
$base = $lr if ($lr < $base);
|
||||
}
|
||||
@@ -1897,38 +1899,20 @@ sub last_rev_commit {
|
||||
return ($rev, $c);
|
||||
}
|
||||
}
|
||||
my $db_path = $self->db_path;
|
||||
unless (-e $db_path) {
|
||||
my $map_path = $self->map_path;
|
||||
unless (-e $map_path) {
|
||||
($self->{last_rev}, $self->{last_commit}) = (undef, undef);
|
||||
return (undef, undef);
|
||||
}
|
||||
my $offset = -41; # from tail
|
||||
my $rl;
|
||||
open my $fh, '<', $db_path or croak "$db_path not readable: $!\n";
|
||||
sysseek($fh, $offset, 2); # don't care for errors
|
||||
sysread($fh, $rl, 41) == 41 or return (undef, undef);
|
||||
chomp $rl;
|
||||
while (('0' x40) eq $rl && sysseek($fh, 0, 1) != 0) {
|
||||
$offset -= 41;
|
||||
sysseek($fh, $offset, 2); # don't care for errors
|
||||
sysread($fh, $rl, 41) == 41 or return (undef, undef);
|
||||
chomp $rl;
|
||||
}
|
||||
if ($c && $c ne $rl) {
|
||||
die "$db_path and ", $self->refname,
|
||||
" inconsistent!:\n$c != $rl\n";
|
||||
}
|
||||
my $rev = sysseek($fh, 0, 1) or croak $!;
|
||||
$rev = ($rev - 41) / 41;
|
||||
close $fh or croak $!;
|
||||
($self->{last_rev}, $self->{last_commit}) = ($rev, $c);
|
||||
return ($rev, $c);
|
||||
my ($rev, $commit) = $self->rev_map_max(1);
|
||||
($self->{last_rev}, $self->{last_commit}) = ($rev, $commit);
|
||||
return ($rev, $commit);
|
||||
}
|
||||
|
||||
sub get_fetch_range {
|
||||
my ($self, $min, $max) = @_;
|
||||
$max ||= $self->ra->get_latest_revnum;
|
||||
$min ||= $self->rev_db_max;
|
||||
$min ||= $self->rev_map_max;
|
||||
(++$min, $max);
|
||||
}
|
||||
|
||||
@@ -2073,7 +2057,7 @@ sub do_git_commit {
|
||||
" was r$lr, but we are about to fetch: ",
|
||||
"r$log_entry->{revision}!\n";
|
||||
}
|
||||
if (my $c = $self->rev_db_get($log_entry->{revision})) {
|
||||
if (my $c = $self->rev_map_get($log_entry->{revision})) {
|
||||
croak "$log_entry->{revision} = $c already exists! ",
|
||||
"Why are we refetching it?\n";
|
||||
}
|
||||
@@ -2116,14 +2100,14 @@ sub do_git_commit {
|
||||
die "Failed to commit, invalid sha1: $commit\n";
|
||||
}
|
||||
|
||||
$self->rev_db_set($log_entry->{revision}, $commit, 1);
|
||||
$self->rev_map_set($log_entry->{revision}, $commit, 1);
|
||||
|
||||
$self->{last_rev} = $log_entry->{revision};
|
||||
$self->{last_commit} = $commit;
|
||||
print "r$log_entry->{revision}";
|
||||
if (defined $log_entry->{svm_revision}) {
|
||||
print " (\@$log_entry->{svm_revision})";
|
||||
$self->rev_db_set($log_entry->{svm_revision}, $commit,
|
||||
$self->rev_map_set($log_entry->{svm_revision}, $commit,
|
||||
0, $self->svm_uuid);
|
||||
}
|
||||
print " = $commit ($self->{ref_id})\n";
|
||||
@@ -2465,25 +2449,44 @@ sub set_tree {
|
||||
}
|
||||
}
|
||||
|
||||
sub rebuild_from_rev_db {
|
||||
my ($self, $path) = @_;
|
||||
my $r = -1;
|
||||
open my $fh, '<', $path or croak "open: $!";
|
||||
while (<$fh>) {
|
||||
length($_) == 41 or croak "inconsistent size in ($_) != 41";
|
||||
chomp($_);
|
||||
++$r;
|
||||
next if $_ eq ('0' x 40);
|
||||
$self->rev_map_set($r, $_);
|
||||
print "r$r = $_\n";
|
||||
}
|
||||
close $fh or croak "close: $!";
|
||||
unlink $path or croak "unlink: $!";
|
||||
}
|
||||
|
||||
sub rebuild {
|
||||
my ($self) = @_;
|
||||
my $db_path = $self->db_path;
|
||||
return if (-e $db_path && ! -z $db_path);
|
||||
my $map_path = $self->map_path;
|
||||
return if (-e $map_path && ! -z $map_path);
|
||||
return unless ::verify_ref($self->refname.'^0');
|
||||
if (-f $self->{db_root}) {
|
||||
rename $self->{db_root}, $db_path or die
|
||||
"rename $self->{db_root} => $db_path failed: $!\n";
|
||||
my ($dir, $base) = ($db_path =~ m#^(.*?)/?([^/]+)$#);
|
||||
symlink $base, $self->{db_root} or die
|
||||
"symlink $base => $self->{db_root} failed: $!\n";
|
||||
if ($self->use_svm_props || $self->no_metadata) {
|
||||
my $rev_db = $self->rev_db_path;
|
||||
$self->rebuild_from_rev_db($rev_db);
|
||||
if ($self->use_svm_props) {
|
||||
my $svm_rev_db = $self->rev_db_path($self->svm_uuid);
|
||||
$self->rebuild_from_rev_db($svm_rev_db);
|
||||
}
|
||||
$self->unlink_rev_db_symlink;
|
||||
return;
|
||||
}
|
||||
print "Rebuilding $db_path ...\n";
|
||||
my ($log, $ctx) = command_output_pipe("log", '--no-color', $self->refname);
|
||||
my $latest;
|
||||
print "Rebuilding $map_path ...\n";
|
||||
my ($log, $ctx) =
|
||||
command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/,
|
||||
$self->refname, '--');
|
||||
my $full_url = $self->full_url;
|
||||
remove_username($full_url);
|
||||
my $svn_uuid;
|
||||
my $svn_uuid = $self->ra_uuid;
|
||||
my $c;
|
||||
while (<$log>) {
|
||||
if ( m{^commit ($::sha1)$} ) {
|
||||
@@ -2499,46 +2502,85 @@ sub rebuild {
|
||||
|
||||
# if we merged or otherwise started elsewhere, this is
|
||||
# how we break out of it
|
||||
if ((defined $svn_uuid && ($uuid ne $svn_uuid)) ||
|
||||
if (($uuid ne $svn_uuid) ||
|
||||
($full_url && $url && ($url ne $full_url))) {
|
||||
next;
|
||||
}
|
||||
$latest ||= $rev;
|
||||
$svn_uuid ||= $uuid;
|
||||
|
||||
$self->rev_db_set($rev, $c);
|
||||
$self->rev_map_set($rev, $c);
|
||||
print "r$rev = $c\n";
|
||||
}
|
||||
command_close_pipe($log, $ctx);
|
||||
print "Done rebuilding $db_path\n";
|
||||
print "Done rebuilding $map_path\n";
|
||||
my $rev_db_path = $self->rev_db_path;
|
||||
if (-f $self->rev_db_path) {
|
||||
unlink $self->rev_db_path or croak "unlink: $!";
|
||||
}
|
||||
$self->unlink_rev_db_symlink;
|
||||
}
|
||||
|
||||
# rev_db:
|
||||
# rev_map:
|
||||
# Tie::File seems to be prone to offset errors if revisions get sparse,
|
||||
# it's not that fast, either. Tie::File is also not in Perl 5.6. So
|
||||
# one of my favorite modules is out :< Next up would be one of the DBM
|
||||
# modules, but I'm not sure which is most portable... So I'll just
|
||||
# go with something that's plain-text, but still capable of
|
||||
# being randomly accessed. So here's my ultra-simple fixed-width
|
||||
# database. All records are 40 characters + "\n", so it's easy to seek
|
||||
# to a revision: (41 * rev) is the byte offset.
|
||||
# A record of 40 0s denotes an empty revision.
|
||||
# And yes, it's still pretty fast (faster than Tie::File).
|
||||
# modules, but I'm not sure which is most portable...
|
||||
#
|
||||
# This is the replacement for the rev_db format, which was too big
|
||||
# and inefficient for large repositories with a lot of sparse history
|
||||
# (mainly tags)
|
||||
#
|
||||
# The format is this:
|
||||
# - 24 bytes for every record,
|
||||
# * 4 bytes for the integer representing an SVN revision number
|
||||
# * 20 bytes representing the sha1 of a git commit
|
||||
# - No empty padding records like the old format
|
||||
# (except the last record, which can be overwritten)
|
||||
# - new records are written append-only since SVN revision numbers
|
||||
# increase monotonically
|
||||
# - lookups on SVN revision number are done via a binary search
|
||||
# - Piping the file to xxd -c24 is a good way of dumping it for
|
||||
# viewing or editing (piped back through xxd -r), should the need
|
||||
# ever arise.
|
||||
# - The last record can be padding revision with an all-zero sha1
|
||||
# This is used to optimize fetch performance when using multiple
|
||||
# "fetch" directives in .git/config
|
||||
#
|
||||
# These files are disposable unless noMetadata or useSvmProps is set
|
||||
|
||||
sub _rev_db_set {
|
||||
sub _rev_map_set {
|
||||
my ($fh, $rev, $commit) = @_;
|
||||
my $offset = $rev * 41;
|
||||
# assume that append is the common case:
|
||||
seek $fh, 0, 2 or croak $!;
|
||||
my $pos = tell $fh;
|
||||
if ($pos < $offset) {
|
||||
for (1 .. (($offset - $pos) / 41)) {
|
||||
print $fh (('0' x 40),"\n") or croak $!;
|
||||
|
||||
my $size = (stat($fh))[7];
|
||||
($size % 24) == 0 or croak "inconsistent size: $size";
|
||||
|
||||
my $wr_offset = 0;
|
||||
if ($size > 0) {
|
||||
sysseek($fh, -24, SEEK_END) or croak "seek: $!";
|
||||
my $read = sysread($fh, my $buf, 24) or croak "read: $!";
|
||||
$read == 24 or croak "read only $read bytes (!= 24)";
|
||||
my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
|
||||
if ($last_commit eq ('0' x40)) {
|
||||
if ($size >= 48) {
|
||||
sysseek($fh, -48, SEEK_END) or croak "seek: $!";
|
||||
$read = sysread($fh, $buf, 24) or
|
||||
croak "read: $!";
|
||||
$read == 24 or
|
||||
croak "read only $read bytes (!= 24)";
|
||||
($last_rev, $last_commit) =
|
||||
unpack(rev_map_fmt, $buf);
|
||||
if ($last_commit eq ('0' x40)) {
|
||||
croak "inconsistent .rev_map\n";
|
||||
}
|
||||
}
|
||||
if ($last_rev >= $rev) {
|
||||
croak "last_rev is higher!: $last_rev >= $rev";
|
||||
}
|
||||
$wr_offset = -24;
|
||||
}
|
||||
}
|
||||
seek $fh, $offset, 0 or croak $!;
|
||||
print $fh $commit,"\n" or croak $!;
|
||||
sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
|
||||
syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
|
||||
croak "write: $!";
|
||||
}
|
||||
|
||||
sub mkfile {
|
||||
@@ -2551,10 +2593,10 @@ sub mkfile {
|
||||
}
|
||||
}
|
||||
|
||||
sub rev_db_set {
|
||||
sub rev_map_set {
|
||||
my ($self, $rev, $commit, $update_ref, $uuid) = @_;
|
||||
length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
|
||||
my $db = $self->db_path($uuid);
|
||||
my $db = $self->map_path($uuid);
|
||||
my $db_lock = "$db.lock";
|
||||
my $sig;
|
||||
if ($update_ref) {
|
||||
@@ -2569,16 +2611,18 @@ sub rev_db_set {
|
||||
# and we can't afford to lose it because rebuild() won't work
|
||||
if ($self->use_svm_props || $self->no_metadata) {
|
||||
$sync = 1;
|
||||
copy($db, $db_lock) or die "rev_db_set(@_): ",
|
||||
copy($db, $db_lock) or die "rev_map_set(@_): ",
|
||||
"Failed to copy: ",
|
||||
"$db => $db_lock ($!)\n";
|
||||
} else {
|
||||
rename $db, $db_lock or die "rev_db_set(@_): ",
|
||||
rename $db, $db_lock or die "rev_map_set(@_): ",
|
||||
"Failed to rename: ",
|
||||
"$db => $db_lock ($!)\n";
|
||||
}
|
||||
open my $fh, '+<', $db_lock or die "Couldn't open $db_lock: $!\n";
|
||||
_rev_db_set($fh, $rev, $commit);
|
||||
|
||||
sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
|
||||
or croak "Couldn't open $db_lock: $!\n";
|
||||
_rev_map_set($fh, $rev, $commit);
|
||||
if ($sync) {
|
||||
$fh->flush or die "Couldn't flush $db_lock: $!\n";
|
||||
$fh->sync or die "Couldn't sync $db_lock: $!\n";
|
||||
@@ -2589,7 +2633,7 @@ sub rev_db_set {
|
||||
command_noisy('update-ref', '-m', "r$rev",
|
||||
$self->refname, $commit);
|
||||
}
|
||||
rename $db_lock, $db or die "rev_db_set(@_): ", "Failed to rename: ",
|
||||
rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
|
||||
"$db_lock => $db ($!)\n";
|
||||
delete $LOCKFILES{$db_lock};
|
||||
if ($update_ref) {
|
||||
@@ -2599,29 +2643,76 @@ sub rev_db_set {
|
||||
}
|
||||
}
|
||||
|
||||
sub rev_db_max {
|
||||
my ($self) = @_;
|
||||
# If want_commit, this will return an array of (rev, commit) where
|
||||
# commit _must_ be a valid commit in the archive.
|
||||
# Otherwise, it'll return the max revision (whether or not the
|
||||
# commit is valid or just a 0x40 placeholder).
|
||||
sub rev_map_max {
|
||||
my ($self, $want_commit) = @_;
|
||||
$self->rebuild;
|
||||
my $db_path = $self->db_path;
|
||||
my @stat = stat $db_path or return 0;
|
||||
($stat[7] % 41) == 0 or die "$db_path inconsistent size: $stat[7]\n";
|
||||
my $max = $stat[7] / 41;
|
||||
(($max > 0) ? $max - 1 : 0);
|
||||
my $map_path = $self->map_path;
|
||||
stat $map_path or return $want_commit ? (0, undef) : 0;
|
||||
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
|
||||
my $size = (stat($fh))[7];
|
||||
($size % 24) == 0 or croak "inconsistent size: $size";
|
||||
|
||||
if ($size == 0) {
|
||||
close $fh or croak "close: $!";
|
||||
return $want_commit ? (0, undef) : 0;
|
||||
}
|
||||
|
||||
sysseek($fh, -24, SEEK_END) or croak "seek: $!";
|
||||
sysread($fh, my $buf, 24) == 24 or croak "read: $!";
|
||||
my ($r, $c) = unpack(rev_map_fmt, $buf);
|
||||
if ($want_commit && $c eq ('0' x40)) {
|
||||
if ($size < 48) {
|
||||
return $want_commit ? (0, undef) : 0;
|
||||
}
|
||||
sysseek($fh, -48, SEEK_END) or croak "seek: $!";
|
||||
sysread($fh, $buf, 24) == 24 or croak "read: $!";
|
||||
($r, $c) = unpack(rev_map_fmt, $buf);
|
||||
if ($c eq ('0'x40)) {
|
||||
croak "Penultimate record is all-zeroes in $map_path";
|
||||
}
|
||||
}
|
||||
close $fh or croak "close: $!";
|
||||
$want_commit ? ($r, $c) : $r;
|
||||
}
|
||||
|
||||
sub rev_db_get {
|
||||
sub rev_map_get {
|
||||
my ($self, $rev, $uuid) = @_;
|
||||
my $ret;
|
||||
my $offset = $rev * 41;
|
||||
my $db_path = $self->db_path($uuid);
|
||||
return undef unless -e $db_path;
|
||||
open my $fh, '<', $db_path or croak $!;
|
||||
if (sysseek($fh, $offset, 0) == $offset) {
|
||||
my $read = sysread($fh, $ret, 40);
|
||||
$ret = undef if ($read != 40 || $ret eq ('0'x40));
|
||||
my $map_path = $self->map_path($uuid);
|
||||
return undef unless -e $map_path;
|
||||
|
||||
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
|
||||
my $size = (stat($fh))[7];
|
||||
($size % 24) == 0 or croak "inconsistent size: $size";
|
||||
|
||||
if ($size == 0) {
|
||||
close $fh or croak "close: $fh";
|
||||
return undef;
|
||||
}
|
||||
close $fh or croak $!;
|
||||
$ret;
|
||||
|
||||
my ($l, $u) = (0, $size - 24);
|
||||
my ($r, $c, $buf);
|
||||
|
||||
while ($l <= $u) {
|
||||
my $i = int(($l/24 + $u/24) / 2) * 24;
|
||||
sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
|
||||
sysread($fh, my $buf, 24) == 24 or croak "read: $!";
|
||||
my ($r, $c) = unpack('NH40', $buf);
|
||||
|
||||
if ($r < $rev) {
|
||||
$l = $i + 24;
|
||||
} elsif ($r > $rev) {
|
||||
$u = $i - 24;
|
||||
} else { # $r == $rev
|
||||
close($fh) or croak "close: $!";
|
||||
return $c eq ('0' x 40) ? undef : $c;
|
||||
}
|
||||
}
|
||||
close($fh) or croak "close: $!";
|
||||
undef;
|
||||
}
|
||||
|
||||
# Finds the first svn revision that exists on (if $eq_ok is true) or
|
||||
@@ -2633,7 +2724,7 @@ sub find_rev_before {
|
||||
--$rev unless $eq_ok;
|
||||
$min_rev ||= 1;
|
||||
while ($rev >= $min_rev) {
|
||||
if (my $c = $self->rev_db_get($rev)) {
|
||||
if (my $c = $self->rev_map_get($rev)) {
|
||||
return ($rev, $c);
|
||||
}
|
||||
--$rev;
|
||||
@@ -2648,9 +2739,9 @@ sub find_rev_before {
|
||||
sub find_rev_after {
|
||||
my ($self, $rev, $eq_ok, $max_rev) = @_;
|
||||
++$rev unless $eq_ok;
|
||||
$max_rev ||= $self->rev_db_max();
|
||||
$max_rev ||= $self->rev_map_max;
|
||||
while ($rev <= $max_rev) {
|
||||
if (my $c = $self->rev_db_get($rev)) {
|
||||
if (my $c = $self->rev_map_get($rev)) {
|
||||
return ($rev, $c);
|
||||
}
|
||||
++$rev;
|
||||
@@ -2673,13 +2764,32 @@ sub _new {
|
||||
bless {
|
||||
ref_id => $ref_id, dir => $dir, index => "$dir/index",
|
||||
path => $path, config => "$ENV{GIT_DIR}/svn/config",
|
||||
db_root => "$dir/.rev_db", repo_id => $repo_id }, $class;
|
||||
map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
|
||||
}
|
||||
|
||||
sub db_path {
|
||||
# for read-only access of old .rev_db formats
|
||||
sub unlink_rev_db_symlink {
|
||||
my ($self) = @_;
|
||||
my $link = $self->rev_db_path;
|
||||
$link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link";
|
||||
if (-l $link) {
|
||||
unlink $link or croak "unlink: $link failed!";
|
||||
}
|
||||
}
|
||||
|
||||
sub rev_db_path {
|
||||
my ($self, $uuid) = @_;
|
||||
my $db_path = $self->map_path($uuid);
|
||||
$db_path =~ s{/\.rev_map\.}{/\.rev_db\.}
|
||||
or croak "map_path: $db_path does not contain '/.rev_map.' !";
|
||||
$db_path;
|
||||
}
|
||||
|
||||
# the new replacement for .rev_db
|
||||
sub map_path {
|
||||
my ($self, $uuid) = @_;
|
||||
$uuid ||= $self->ra_uuid;
|
||||
"$self->{db_root}.$uuid";
|
||||
"$self->{map_root}.$uuid";
|
||||
}
|
||||
|
||||
sub uri_encode {
|
||||
@@ -3763,7 +3873,7 @@ sub gs_fetch_loop_common {
|
||||
|
||||
foreach my $gs ($self->match_globs(\%exists, $paths,
|
||||
$globs, $r)) {
|
||||
if ($gs->rev_db_max >= $r) {
|
||||
if ($gs->rev_map_max >= $r) {
|
||||
next;
|
||||
}
|
||||
next unless $gs->match_paths($paths, $r);
|
||||
@@ -3792,8 +3902,9 @@ sub gs_fetch_loop_common {
|
||||
# pre-fill the .rev_db since it'll eventually get filled in
|
||||
# with '0' x40 if something new gets committed
|
||||
foreach my $gs (@$gsv) {
|
||||
next if defined $gs->rev_db_get($max);
|
||||
$gs->rev_db_set($max, 0 x40);
|
||||
next if $gs->rev_map_max >= $max;
|
||||
next if defined $gs->rev_map_get($max);
|
||||
$gs->rev_map_set($max, 0 x40);
|
||||
}
|
||||
foreach my $g (@$globs) {
|
||||
my $k = "svn-remote.$g->{remote}.$g->{t}-maxRev";
|
||||
@@ -3969,39 +4080,7 @@ sub cmt_showable {
|
||||
}
|
||||
|
||||
sub log_use_color {
|
||||
return 1 if $color;
|
||||
my ($dc, $dcvar);
|
||||
$dcvar = 'color.diff';
|
||||
$dc = `git-config --get $dcvar`;
|
||||
if ($dc eq '') {
|
||||
# nothing at all; fallback to "diff.color"
|
||||
$dcvar = 'diff.color';
|
||||
$dc = `git-config --get $dcvar`;
|
||||
}
|
||||
chomp($dc);
|
||||
if ($dc eq 'auto') {
|
||||
my $pc;
|
||||
$pc = `git-config --get color.pager`;
|
||||
if ($pc eq '') {
|
||||
# does not have it -- fallback to pager.color
|
||||
$pc = `git-config --bool --get pager.color`;
|
||||
}
|
||||
else {
|
||||
$pc = `git-config --bool --get color.pager`;
|
||||
if ($?) {
|
||||
$pc = 'false';
|
||||
}
|
||||
}
|
||||
chomp($pc);
|
||||
if (-t *STDOUT || (defined $pager && $pc eq 'true')) {
|
||||
return ($ENV{TERM} && $ENV{TERM} ne 'dumb');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0 if $dc eq 'never';
|
||||
return 1 if $dc eq 'always';
|
||||
chomp($dc = `git-config --bool --get $dcvar`);
|
||||
return ($dc eq 'true');
|
||||
return $color || Git->repository->get_colorbool('color.diff');
|
||||
}
|
||||
|
||||
sub git_svn_log_cmd {
|
||||
@@ -4030,7 +4109,7 @@ sub git_svn_log_cmd {
|
||||
push @cmd, @log_opts;
|
||||
if (defined $r_max && $r_max == $r_min) {
|
||||
push @cmd, '--max-count=1';
|
||||
if (my $c = $gs->rev_db_get($r_max)) {
|
||||
if (my $c = $gs->rev_map_get($r_max)) {
|
||||
push @cmd, $c;
|
||||
}
|
||||
} elsif (defined $r_max) {
|
||||
@@ -4060,6 +4139,7 @@ sub config_pager {
|
||||
} elsif (length $pager == 0 || $pager eq 'cat') {
|
||||
$pager = undef;
|
||||
}
|
||||
$ENV{GIT_PAGER_IN_USE} = defined($pager);
|
||||
}
|
||||
|
||||
sub run_pager {
|
||||
@@ -4311,6 +4391,16 @@ package Git::SVN::Migration;
|
||||
# --use-separate-remotes option in git-clone (now default)
|
||||
# - we do not automatically migrate to this (following
|
||||
# the example set by core git)
|
||||
#
|
||||
# v5 layout: .rev_db.$UUID => .rev_map.$UUID
|
||||
# - newer, more-efficient format that uses 24-bytes per record
|
||||
# with no filler space.
|
||||
# - use xxd -c24 < .rev_map.$UUID to view and debug
|
||||
# - This is a one-way migration, repositories updated to the
|
||||
# new format will not be able to use old git-svn without
|
||||
# rebuilding the .rev_db. Rebuilding the rev_db is not
|
||||
# possible if noMetadata or useSvmProps are set; but should
|
||||
# be no problem for users that use the (sensible) defaults.
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp qw/croak/;
|
||||
|
||||
15
git.spec.in
15
git.spec.in
@@ -1,7 +1,5 @@
|
||||
# Pass --without docs to rpmbuild if you don't want the documentation
|
||||
|
||||
%define python_path /usr/bin/python
|
||||
|
||||
Name: git
|
||||
Version: @@VERSION@@
|
||||
Release: 1%{?dist}
|
||||
@@ -85,20 +83,20 @@ BuildRequires: perl(Error)
|
||||
%description -n perl-Git
|
||||
Perl interface to Git
|
||||
|
||||
%define path_settings ETC_GITCONFIG=/etc/gitconfig prefix=%{_prefix} mandir=%{_mandir} htmldir=%{_docdir}/%{name}-core-%{version}
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" \
|
||||
ETC_GITCONFIG=/etc/gitconfig \
|
||||
prefix=%{_prefix} all %{!?_without_docs: doc}
|
||||
%{path_settings} \
|
||||
all %{!?_without_docs: doc}
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" DESTDIR=$RPM_BUILD_ROOT \
|
||||
prefix=%{_prefix} mandir=%{_mandir} \
|
||||
ETC_GITCONFIG=/etc/gitconfig \
|
||||
PYTHON_PATH=%{python_path} \
|
||||
%{path_settings} \
|
||||
INSTALLDIRS=vendor install %{!?_without_docs: install-doc}
|
||||
find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';'
|
||||
find $RPM_BUILD_ROOT -type f -name '*.bs' -empty -exec rm -f {} ';'
|
||||
@@ -174,6 +172,9 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{!?_without_docs: %doc Documentation/technical}
|
||||
|
||||
%changelog
|
||||
* Wed Dec 12 2007 Junio C Hamano <gitster@pobox.com>
|
||||
- Adjust htmldir to point at /usr/share/doc/git-core-$version/
|
||||
|
||||
* Sun Jul 15 2007 Sean Estabrooks <seanlkml@sympatico.ca>
|
||||
- Removed p4import.
|
||||
|
||||
|
||||
86
help.c
86
help.c
@@ -240,7 +240,58 @@ void list_common_cmds_help(void)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *cmd_to_page(const char *git_cmd)
|
||||
{
|
||||
if (!git_cmd)
|
||||
return "git";
|
||||
else if (!prefixcmp(git_cmd, "git"))
|
||||
return git_cmd;
|
||||
else {
|
||||
int page_len = strlen(git_cmd) + 4;
|
||||
char *p = xmalloc(page_len + 1);
|
||||
strcpy(p, "git-");
|
||||
strcpy(p + 4, git_cmd);
|
||||
p[page_len] = 0;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_man_path(void)
|
||||
{
|
||||
struct strbuf new_path;
|
||||
const char *old_path = getenv("MANPATH");
|
||||
|
||||
strbuf_init(&new_path, 0);
|
||||
|
||||
/* We should always put ':' after our path. If there is no
|
||||
* old_path, the ':' at the end will let 'man' to try
|
||||
* system-wide paths after ours to find the manual page. If
|
||||
* there is old_path, we need ':' as delimiter. */
|
||||
strbuf_addstr(&new_path, GIT_MAN_PATH);
|
||||
strbuf_addch(&new_path, ':');
|
||||
if (old_path)
|
||||
strbuf_addstr(&new_path, old_path);
|
||||
|
||||
setenv("MANPATH", new_path.buf, 1);
|
||||
|
||||
strbuf_release(&new_path);
|
||||
}
|
||||
|
||||
static void show_man_page(const char *git_cmd)
|
||||
{
|
||||
const char *page = cmd_to_page(git_cmd);
|
||||
setup_man_path();
|
||||
execlp("man", "man", page, NULL);
|
||||
}
|
||||
|
||||
static void show_info_page(const char *git_cmd)
|
||||
{
|
||||
const char *page = cmd_to_page(git_cmd);
|
||||
setenv("INFOPATH", GIT_INFO_PATH, 1);
|
||||
execlp("info", "info", "gitman", page, NULL);
|
||||
}
|
||||
|
||||
static void show_html_page(const char *git_cmd)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
{
|
||||
@@ -266,20 +317,8 @@ static void show_man_page(const char *git_cmd)
|
||||
ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
|
||||
}
|
||||
#else
|
||||
const char *page;
|
||||
|
||||
if (!prefixcmp(git_cmd, "git"))
|
||||
page = git_cmd;
|
||||
else {
|
||||
int page_len = strlen(git_cmd) + 4;
|
||||
char *p = xmalloc(page_len + 1);
|
||||
strcpy(p, "git-");
|
||||
strcpy(p + 4, git_cmd);
|
||||
p[page_len] = 0;
|
||||
page = p;
|
||||
}
|
||||
|
||||
execlp("man", "man", page, NULL);
|
||||
const char *page = cmd_to_page(git_cmd);
|
||||
execl_git_cmd("browse-help", page, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -297,22 +336,33 @@ int cmd_version(int argc, const char **argv, const char *prefix)
|
||||
|
||||
int cmd_help(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *help_cmd = argc > 1 ? argv[1] : NULL;
|
||||
const char *help_cmd = argv[1];
|
||||
|
||||
if (!help_cmd) {
|
||||
if (argc < 2) {
|
||||
printf("usage: %s\n\n", git_usage_string);
|
||||
list_common_cmds_help();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) {
|
||||
if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) {
|
||||
printf("usage: %s\n\n", git_usage_string);
|
||||
list_commands();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
else if (!strcmp(help_cmd, "--web") || !strcmp(help_cmd, "-w")) {
|
||||
show_html_page(argc > 2 ? argv[2] : NULL);
|
||||
}
|
||||
|
||||
else if (!strcmp(help_cmd, "--info") || !strcmp(help_cmd, "-i")) {
|
||||
show_info_page(argc > 2 ? argv[2] : NULL);
|
||||
}
|
||||
|
||||
else
|
||||
#ifdef __MINGW32__
|
||||
show_html_page(help_cmd);
|
||||
#else
|
||||
show_man_page(help_cmd);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
15
http-push.c
15
http-push.c
@@ -1275,8 +1275,6 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
|
||||
char *ep;
|
||||
char timeout_header[25];
|
||||
struct remote_lock *lock = NULL;
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
enum XML_Status result;
|
||||
struct curl_slist *dav_headers = NULL;
|
||||
struct xml_ctx ctx;
|
||||
|
||||
@@ -1345,6 +1343,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
|
||||
if (start_active_slot(slot)) {
|
||||
run_active_slot(slot);
|
||||
if (results.curl_result == CURLE_OK) {
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
enum XML_Status result;
|
||||
ctx.name = xcalloc(10, 1);
|
||||
ctx.len = 0;
|
||||
ctx.cdata = NULL;
|
||||
@@ -1363,6 +1363,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
|
||||
XML_GetErrorCode(parser)));
|
||||
lock->timeout = -1;
|
||||
}
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unable to start LOCK request\n");
|
||||
@@ -1525,8 +1526,6 @@ static void remote_ls(const char *path, int flags,
|
||||
struct buffer out_buffer;
|
||||
char *in_data;
|
||||
char *out_data;
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
enum XML_Status result;
|
||||
struct curl_slist *dav_headers = NULL;
|
||||
struct xml_ctx ctx;
|
||||
struct remote_ls_ctx ls;
|
||||
@@ -1569,6 +1568,8 @@ static void remote_ls(const char *path, int flags,
|
||||
if (start_active_slot(slot)) {
|
||||
run_active_slot(slot);
|
||||
if (results.curl_result == CURLE_OK) {
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
enum XML_Status result;
|
||||
ctx.name = xcalloc(10, 1);
|
||||
ctx.len = 0;
|
||||
ctx.cdata = NULL;
|
||||
@@ -1587,6 +1588,7 @@ static void remote_ls(const char *path, int flags,
|
||||
XML_ErrorString(
|
||||
XML_GetErrorCode(parser)));
|
||||
}
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unable to start PROPFIND request\n");
|
||||
@@ -1620,8 +1622,6 @@ static int locking_available(void)
|
||||
struct buffer out_buffer;
|
||||
char *in_data;
|
||||
char *out_data;
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
enum XML_Status result;
|
||||
struct curl_slist *dav_headers = NULL;
|
||||
struct xml_ctx ctx;
|
||||
int lock_flags = 0;
|
||||
@@ -1658,6 +1658,8 @@ static int locking_available(void)
|
||||
if (start_active_slot(slot)) {
|
||||
run_active_slot(slot);
|
||||
if (results.curl_result == CURLE_OK) {
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
enum XML_Status result;
|
||||
ctx.name = xcalloc(10, 1);
|
||||
ctx.len = 0;
|
||||
ctx.cdata = NULL;
|
||||
@@ -1676,6 +1678,7 @@ static int locking_available(void)
|
||||
XML_GetErrorCode(parser)));
|
||||
lock_flags = 0;
|
||||
}
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unable to start PROPFIND request\n");
|
||||
|
||||
28
http.c
28
http.c
@@ -4,31 +4,31 @@ int data_received;
|
||||
int active_requests = 0;
|
||||
|
||||
#ifdef USE_CURL_MULTI
|
||||
int max_requests = -1;
|
||||
CURLM *curlm;
|
||||
static int max_requests = -1;
|
||||
static CURLM *curlm;
|
||||
#endif
|
||||
#ifndef NO_CURL_EASY_DUPHANDLE
|
||||
CURL *curl_default;
|
||||
static CURL *curl_default;
|
||||
#endif
|
||||
char curl_errorstr[CURL_ERROR_SIZE];
|
||||
|
||||
int curl_ssl_verify = -1;
|
||||
char *ssl_cert = NULL;
|
||||
static int curl_ssl_verify = -1;
|
||||
static char *ssl_cert = NULL;
|
||||
#if LIBCURL_VERSION_NUM >= 0x070902
|
||||
char *ssl_key = NULL;
|
||||
static char *ssl_key = NULL;
|
||||
#endif
|
||||
#if LIBCURL_VERSION_NUM >= 0x070908
|
||||
char *ssl_capath = NULL;
|
||||
static char *ssl_capath = NULL;
|
||||
#endif
|
||||
char *ssl_cainfo = NULL;
|
||||
long curl_low_speed_limit = -1;
|
||||
long curl_low_speed_time = -1;
|
||||
int curl_ftp_no_epsv = 0;
|
||||
char *curl_http_proxy = NULL;
|
||||
static char *ssl_cainfo = NULL;
|
||||
static long curl_low_speed_limit = -1;
|
||||
static long curl_low_speed_time = -1;
|
||||
static int curl_ftp_no_epsv = 0;
|
||||
static char *curl_http_proxy = NULL;
|
||||
|
||||
struct curl_slist *pragma_header;
|
||||
static struct curl_slist *pragma_header;
|
||||
|
||||
struct active_request_slot *active_queue_head = NULL;
|
||||
static struct active_request_slot *active_queue_head = NULL;
|
||||
|
||||
size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb,
|
||||
struct buffer *buffer)
|
||||
|
||||
18
http.h
18
http.h
@@ -80,24 +80,6 @@ extern void http_cleanup(void);
|
||||
extern int data_received;
|
||||
extern int active_requests;
|
||||
|
||||
#ifndef NO_CURL_EASY_DUPHANDLE
|
||||
extern CURL *curl_default;
|
||||
#endif
|
||||
extern char curl_errorstr[CURL_ERROR_SIZE];
|
||||
|
||||
extern int curl_ssl_verify;
|
||||
extern char *ssl_cert;
|
||||
#if LIBCURL_VERSION_NUM >= 0x070902
|
||||
extern char *ssl_key;
|
||||
#endif
|
||||
#if LIBCURL_VERSION_NUM >= 0x070908
|
||||
extern char *ssl_capath;
|
||||
#endif
|
||||
extern char *ssl_cainfo;
|
||||
extern long curl_low_speed_limit;
|
||||
extern long curl_low_speed_time;
|
||||
|
||||
extern struct curl_slist *pragma_header;
|
||||
extern struct curl_slist *no_range_header;
|
||||
|
||||
#endif /* HTTP_H */
|
||||
|
||||
30
ident.c
30
ident.c
@@ -182,14 +182,15 @@ static const char *env_hint =
|
||||
"Omit --global to set the identity only in this repository.\n"
|
||||
"\n";
|
||||
|
||||
static const char *fmt_ident_1(const char *name, const char *email,
|
||||
const char *date_str, int flag)
|
||||
const char *fmt_ident(const char *name, const char *email,
|
||||
const char *date_str, int flag)
|
||||
{
|
||||
static char buffer[1000];
|
||||
char date[50];
|
||||
int i;
|
||||
int error_on_no_name = !!(flag & 01);
|
||||
int name_addr_only = !!(flag & 02);
|
||||
int error_on_no_name = (flag & IDENT_ERROR_ON_NO_NAME);
|
||||
int warn_on_no_name = (flag & IDENT_WARN_ON_NO_NAME);
|
||||
int name_addr_only = (flag & IDENT_NO_DATE);
|
||||
|
||||
setup_ident();
|
||||
if (!name)
|
||||
@@ -200,12 +201,12 @@ static const char *fmt_ident_1(const char *name, const char *email,
|
||||
if (!*name) {
|
||||
struct passwd *pw;
|
||||
|
||||
if (0 <= error_on_no_name &&
|
||||
if ((warn_on_no_name || error_on_no_name) &&
|
||||
name == git_default_name && env_hint) {
|
||||
fprintf(stderr, env_hint, au_env, co_env);
|
||||
env_hint = NULL; /* warn only once, for "git-var -l" */
|
||||
}
|
||||
if (0 < error_on_no_name)
|
||||
if (error_on_no_name)
|
||||
die("empty ident %s <%s> not allowed", name, email);
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw)
|
||||
@@ -234,30 +235,23 @@ static const char *fmt_ident_1(const char *name, const char *email,
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char *fmt_ident(const char *name, const char *email,
|
||||
const char *date_str, int error_on_no_name)
|
||||
{
|
||||
int flag = (error_on_no_name ? 01 : 0);
|
||||
return fmt_ident_1(name, email, date_str, flag);
|
||||
}
|
||||
|
||||
const char *fmt_name(const char *name, const char *email)
|
||||
{
|
||||
return fmt_ident_1(name, email, NULL, 03);
|
||||
return fmt_ident(name, email, NULL, IDENT_ERROR_ON_NO_NAME | IDENT_NO_DATE);
|
||||
}
|
||||
|
||||
const char *git_author_info(int error_on_no_name)
|
||||
const char *git_author_info(int flag)
|
||||
{
|
||||
return fmt_ident(getenv("GIT_AUTHOR_NAME"),
|
||||
getenv("GIT_AUTHOR_EMAIL"),
|
||||
getenv("GIT_AUTHOR_DATE"),
|
||||
error_on_no_name);
|
||||
flag);
|
||||
}
|
||||
|
||||
const char *git_committer_info(int error_on_no_name)
|
||||
const char *git_committer_info(int flag)
|
||||
{
|
||||
return fmt_ident(getenv("GIT_COMMITTER_NAME"),
|
||||
getenv("GIT_COMMITTER_EMAIL"),
|
||||
getenv("GIT_COMMITTER_DATE"),
|
||||
error_on_no_name);
|
||||
flag);
|
||||
}
|
||||
|
||||
@@ -42,9 +42,10 @@ int read_mailmap(struct path_list *map, const char *filename, char **repo_abbrev
|
||||
continue;
|
||||
if (right_bracket == left_bracket + 1)
|
||||
continue;
|
||||
for (end_of_name = left_bracket; end_of_name != buffer
|
||||
&& isspace(end_of_name[-1]); end_of_name--)
|
||||
/* keep on looking */
|
||||
for (end_of_name = left_bracket;
|
||||
end_of_name != buffer && isspace(end_of_name[-1]);
|
||||
end_of_name--)
|
||||
; /* keep on looking */
|
||||
if (end_of_name == buffer)
|
||||
continue;
|
||||
name = xmalloc(end_of_name - buffer + 1);
|
||||
|
||||
@@ -1046,14 +1046,16 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
|
||||
|
||||
free(result_buf.ptr);
|
||||
result.clean = (merge_status == 0);
|
||||
} else {
|
||||
if (!(S_ISLNK(a->mode) || S_ISLNK(b->mode)))
|
||||
die("cannot merge modes?");
|
||||
|
||||
} else if (S_ISGITLINK(a->mode)) {
|
||||
result.clean = 0;
|
||||
hashcpy(result.sha, a->sha1);
|
||||
} else if (S_ISLNK(a->mode)) {
|
||||
hashcpy(result.sha, a->sha1);
|
||||
|
||||
if (!sha_eq(a->sha1, b->sha1))
|
||||
result.clean = 0;
|
||||
} else {
|
||||
die("unsupported object type in the tree");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
25
pager.c
25
pager.c
@@ -1,10 +1,12 @@
|
||||
#include "cache.h"
|
||||
|
||||
/*
|
||||
* This is split up from the rest of git so that we might do
|
||||
* something different on Windows, for example.
|
||||
* This is split up from the rest of git so that we can do
|
||||
* something different on Windows.
|
||||
*/
|
||||
|
||||
static int spawned_pager;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
static void run_pager(const char *pager)
|
||||
{
|
||||
@@ -24,12 +26,12 @@ static void run_pager(const char *pager)
|
||||
#else
|
||||
#include "run-command.h"
|
||||
|
||||
const char *pager_argv[] = { "sh", "-c", NULL, NULL };
|
||||
static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
|
||||
static struct child_process pager_process = {
|
||||
.argv = pager_argv,
|
||||
.in = -1
|
||||
};
|
||||
static void collect_pager(void)
|
||||
static void wait_for_pager(void)
|
||||
{
|
||||
fflush(stdout);
|
||||
close(1); /* signals EOF to pager */
|
||||
@@ -59,7 +61,7 @@ void setup_pager(void)
|
||||
else if (!*pager || !strcmp(pager, "cat"))
|
||||
return;
|
||||
|
||||
pager_in_use = 1; /* means we are emitting to terminal */
|
||||
spawned_pager = 1; /* means we are emitting to terminal */
|
||||
|
||||
#ifndef __MINGW32__
|
||||
if (pipe(fd) < 0)
|
||||
@@ -99,6 +101,17 @@ void setup_pager(void)
|
||||
close(pager_process.in);
|
||||
|
||||
/* this makes sure that the parent terminates after the pager */
|
||||
atexit(collect_pager);
|
||||
atexit(wait_for_pager);
|
||||
#endif
|
||||
}
|
||||
|
||||
int pager_in_use(void)
|
||||
{
|
||||
const char *env;
|
||||
|
||||
if (spawned_pager)
|
||||
return 1;
|
||||
|
||||
env = getenv("GIT_PAGER_IN_USE");
|
||||
return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
|
||||
}
|
||||
|
||||
2
path.c
2
path.c
@@ -75,11 +75,13 @@ int git_mkstemp(char *path, size_t len, const char *template)
|
||||
size_t n;
|
||||
|
||||
tmp = getenv("TMPDIR");
|
||||
#ifdef __MINGW32__
|
||||
/* on Windows it is TMP and TEMP */
|
||||
if (!tmp)
|
||||
tmp = getenv("TMP");
|
||||
if (!tmp)
|
||||
tmp = getenv("TEMP");
|
||||
#endif
|
||||
if (!tmp)
|
||||
tmp = "/tmp";
|
||||
n = snprintf(path, len, "%s/%s", tmp, template);
|
||||
|
||||
@@ -17,9 +17,6 @@ if ($@ || $Error::VERSION < 0.15009) {
|
||||
$pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm';
|
||||
}
|
||||
|
||||
my %extra;
|
||||
$extra{DESTDIR} = $ENV{DESTDIR} if $ENV{DESTDIR};
|
||||
|
||||
# redirect stdout, otherwise the message "Writing perl.mak for Git"
|
||||
# disrupts the output for the target 'instlibdir'
|
||||
open STDOUT, ">&STDERR";
|
||||
@@ -29,6 +26,5 @@ WriteMakefile(
|
||||
VERSION_FROM => 'Git.pm',
|
||||
PM => \%pm,
|
||||
MAKEFILE => 'perl.mak',
|
||||
INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3',
|
||||
%extra
|
||||
INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3'
|
||||
);
|
||||
|
||||
2
refs.c
2
refs.c
@@ -1094,7 +1094,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
|
||||
adjust_shared_perm(log_file);
|
||||
|
||||
msglen = msg ? strlen(msg) : 0;
|
||||
committer = git_committer_info(-1);
|
||||
committer = git_committer_info(0);
|
||||
maxlen = strlen(committer) + msglen + 100;
|
||||
logrec = xmalloc(maxlen);
|
||||
len = sprintf(logrec, "%s %s %s\n",
|
||||
|
||||
12
revision.c
12
revision.c
@@ -139,6 +139,18 @@ void add_pending_object(struct rev_info *revs, struct object *obj, const char *n
|
||||
add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
|
||||
}
|
||||
|
||||
void add_head_to_pending(struct rev_info *revs)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
struct object *obj;
|
||||
if (get_sha1("HEAD", sha1))
|
||||
return;
|
||||
obj = parse_object(sha1);
|
||||
if (!obj)
|
||||
return;
|
||||
add_pending_object(revs, obj, "HEAD");
|
||||
}
|
||||
|
||||
static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
|
||||
{
|
||||
struct object *object;
|
||||
|
||||
@@ -130,6 +130,8 @@ extern void add_object(struct object *obj,
|
||||
|
||||
extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
|
||||
|
||||
extern void add_head_to_pending(struct rev_info *);
|
||||
|
||||
enum commit_action {
|
||||
commit_ignore,
|
||||
commit_show,
|
||||
|
||||
11
setup.c
11
setup.c
@@ -82,21 +82,23 @@ const char *prefix_path(const char *prefix, int len, const char *path)
|
||||
const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
|
||||
{
|
||||
static char path[PATH_MAX];
|
||||
char *p;
|
||||
#ifndef __MINGW32__
|
||||
if (!pfx || !*pfx || is_absolute_path(arg))
|
||||
return arg;
|
||||
memcpy(path, pfx, pfx_len);
|
||||
strcpy(path + pfx_len, arg);
|
||||
#else
|
||||
/* don't add prefix to absolute paths */
|
||||
char *p;
|
||||
/* don't add prefix to absolute paths, but still replace '\' by '/' */
|
||||
if (is_absolute_path(arg))
|
||||
pfx_len = 0;
|
||||
else
|
||||
#endif
|
||||
memcpy(path, pfx, pfx_len);
|
||||
memcpy(path, pfx, pfx_len);
|
||||
strcpy(path + pfx_len, arg);
|
||||
for (p = path + pfx_len; *p; p++)
|
||||
if (*p == '\\')
|
||||
*p = '/';
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -427,7 +429,6 @@ int check_repository_format(void)
|
||||
const char *setup_git_directory(void)
|
||||
{
|
||||
const char *retval = setup_git_directory_gently(NULL);
|
||||
check_repository_format();
|
||||
|
||||
/* If the work tree is not the default one, recompute prefix */
|
||||
if (inside_work_tree < 0) {
|
||||
|
||||
@@ -83,20 +83,18 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns the number of chars to skip to first component */
|
||||
static inline int is_path_absolute(const char *path)
|
||||
static inline int offset_1st_component(const char *path)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
if (isalpha(path[0]) && path[1] == ':')
|
||||
return 2 + (path[2] == '/');
|
||||
/* TODO: C:dir/file 'relative' paths are not catered for */
|
||||
#endif
|
||||
return *path == '/';
|
||||
}
|
||||
|
||||
int safe_create_leading_directories(char *path)
|
||||
{
|
||||
char *pos = path + is_path_absolute(path);
|
||||
char *pos = path + offset_1st_component(path);
|
||||
struct stat st;
|
||||
|
||||
while (pos) {
|
||||
|
||||
@@ -82,3 +82,29 @@ stop_httpd () {
|
||||
test -z "$SVN_HTTPD_PORT" && return
|
||||
"$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k stop
|
||||
}
|
||||
|
||||
convert_to_rev_db () {
|
||||
perl -w -- - "$@" <<\EOF
|
||||
use strict;
|
||||
@ARGV == 2 or die "Usage: convert_to_rev_db <input> <output>";
|
||||
open my $wr, '+>', $ARGV[1] or die "$!: couldn't open: $ARGV[1]";
|
||||
open my $rd, '<', $ARGV[0] or die "$!: couldn't open: $ARGV[0]";
|
||||
my $size = (stat($rd))[7];
|
||||
($size % 24) == 0 or die "Inconsistent size: $size";
|
||||
while (sysread($rd, my $buf, 24) == 24) {
|
||||
my ($r, $c) = unpack('NH40', $buf);
|
||||
my $offset = $r * 41;
|
||||
seek $wr, 0, 2 or die $!;
|
||||
my $pos = tell $wr;
|
||||
if ($pos < $offset) {
|
||||
for (1 .. (($offset - $pos) / 41)) {
|
||||
print $wr (('0' x 40),"\n") or die $!;
|
||||
}
|
||||
}
|
||||
seek $wr, $offset, 0 or die $!;
|
||||
print $wr $c,"\n" or die $!;
|
||||
}
|
||||
close $wr or die $!;
|
||||
close $rd or die $!;
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -117,4 +117,13 @@ EOF
|
||||
git diff -b > out
|
||||
test_expect_success 'another test, with -b' 'git diff expect out'
|
||||
|
||||
|
||||
test_expect_success 'check mixed spaces and tabs in indent' '
|
||||
|
||||
# This is indented with SP HT SP.
|
||||
echo " foo();" > x &&
|
||||
git diff --check | grep "space before tab"
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
123
t/t4019-diff-wserror.sh
Executable file
123
t/t4019-diff-wserror.sh
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='diff whitespace error detection'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
git config diff.color.whitespace "blue reverse" &&
|
||||
>F &&
|
||||
git add F &&
|
||||
echo " Eight SP indent" >>F &&
|
||||
echo " HT and SP indent" >>F &&
|
||||
echo "With trailing SP " >>F &&
|
||||
echo "No problem" >>F
|
||||
|
||||
'
|
||||
|
||||
blue_grep='7;34m' ;# ESC [ 7 ; 3 4 m
|
||||
|
||||
test_expect_success default '
|
||||
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
grep With error >/dev/null &&
|
||||
grep No normal >/dev/null
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'without -trail' '
|
||||
|
||||
git config core.whitespace -trail
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
grep With normal >/dev/null &&
|
||||
grep No normal >/dev/null
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'without -trail (attribute)' '
|
||||
|
||||
git config --unset core.whitespace
|
||||
echo "F whitespace=-trail" >.gitattributes
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT error >/dev/null &&
|
||||
grep With normal >/dev/null &&
|
||||
grep No normal >/dev/null
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'without -space' '
|
||||
|
||||
rm -f .gitattributes
|
||||
git config core.whitespace -space
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
grep With error >/dev/null &&
|
||||
grep No normal >/dev/null
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'without -space (attribute)' '
|
||||
|
||||
git config --unset core.whitespace
|
||||
echo "F whitespace=-space" >.gitattributes
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
|
||||
grep Eight normal >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
grep With error >/dev/null &&
|
||||
grep No normal >/dev/null
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'with indent-non-tab only' '
|
||||
|
||||
rm -f .gitattributes
|
||||
git config core.whitespace indent,-trailing,-space
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
|
||||
grep Eight error >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
grep With normal >/dev/null &&
|
||||
grep No normal >/dev/null
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'with indent-non-tab only (attribute)' '
|
||||
|
||||
git config --unset core.whitespace
|
||||
echo "F whitespace=indent,-trailing,-space" >.gitattributes
|
||||
git diff --color >output
|
||||
grep "$blue_grep" output >error
|
||||
grep -v "$blue_grep" output >normal
|
||||
|
||||
grep Eight error >/dev/null &&
|
||||
grep HT normal >/dev/null &&
|
||||
grep With normal >/dev/null &&
|
||||
grep No normal >/dev/null
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
151
t/t4124-apply-ws-rule.sh
Executable file
151
t/t4124-apply-ws-rule.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='core.whitespace rules and git-apply'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
prepare_test_file () {
|
||||
|
||||
# A line that has character X is touched iff RULE is in effect:
|
||||
# X RULE
|
||||
# ! trailing-space
|
||||
# @ space-before-tab
|
||||
# # indent-with-non-tab
|
||||
sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF
|
||||
An_SP in an ordinary line>and a HT.
|
||||
>A HT.
|
||||
_>A SP and a HT (@).
|
||||
_>_A SP, a HT and a SP (@).
|
||||
_______Seven SP.
|
||||
________Eight SP (#).
|
||||
_______>Seven SP and a HT (@).
|
||||
________>Eight SP and a HT (@#).
|
||||
_______>_Seven SP, a HT and a SP (@).
|
||||
________>_Eight SP, a HT and a SP (@#).
|
||||
_______________Fifteen SP (#).
|
||||
_______________>Fifteen SP and a HT (@#).
|
||||
________________Sixteen SP (#).
|
||||
________________>Sixteen SP and a HT (@#).
|
||||
_____a__Five SP, a non WS, two SP.
|
||||
A line with a (!) trailing SP_
|
||||
A line with a (!) trailing HT>
|
||||
EOF
|
||||
}
|
||||
|
||||
apply_patch () {
|
||||
>target &&
|
||||
sed -e "s|\([ab]\)/file|\1/target|" <patch |
|
||||
git apply "$@"
|
||||
}
|
||||
|
||||
test_fix () {
|
||||
|
||||
# fix should not barf
|
||||
apply_patch --whitespace=fix || return 1
|
||||
|
||||
# find touched lines
|
||||
diff file target | sed -n -e "s/^> //p" >fixed
|
||||
|
||||
# the changed lines are all expeced to change
|
||||
fixed_cnt=$(wc -l <fixed)
|
||||
case "$1" in
|
||||
'') expect_cnt=$fixed_cnt ;;
|
||||
?*) expect_cnt=$(grep "[$1]" <fixed | wc -l) ;;
|
||||
esac
|
||||
test $fixed_cnt -eq $expect_cnt || return 1
|
||||
|
||||
# and we are not missing anything
|
||||
case "$1" in
|
||||
'') expect_cnt=0 ;;
|
||||
?*) expect_cnt=$(grep "[$1]" <file | wc -l) ;;
|
||||
esac
|
||||
test $fixed_cnt -eq $expect_cnt || return 1
|
||||
|
||||
# Get the patch actually applied
|
||||
git diff-files -p target >fixed-patch
|
||||
test -s fixed-patch && return 0
|
||||
|
||||
# Make sure it is complaint-free
|
||||
>target
|
||||
git apply --whitespace=error-all <fixed-patch
|
||||
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
>file &&
|
||||
git add file &&
|
||||
prepare_test_file >file &&
|
||||
git diff-files -p >patch &&
|
||||
>target &&
|
||||
git add target
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=nowarn, default rule' '
|
||||
|
||||
apply_patch --whitespace=nowarn &&
|
||||
diff file target
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=warn, default rule' '
|
||||
|
||||
apply_patch --whitespace=warn &&
|
||||
diff file target
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=error-all, default rule' '
|
||||
|
||||
apply_patch --whitespace=error-all && return 1
|
||||
test -s target && return 1
|
||||
: happy
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=error-all, no rule' '
|
||||
|
||||
git config core.whitespace -trailing,-space-before,-indent &&
|
||||
apply_patch --whitespace=error-all &&
|
||||
diff file target
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=error-all, no rule (attribute)' '
|
||||
|
||||
git config --unset core.whitespace &&
|
||||
echo "target -whitespace" >.gitattributes &&
|
||||
apply_patch --whitespace=error-all &&
|
||||
diff file target
|
||||
|
||||
'
|
||||
|
||||
for t in - ''
|
||||
do
|
||||
case "$t" in '') tt='!' ;; *) tt= ;; esac
|
||||
for s in - ''
|
||||
do
|
||||
case "$s" in '') ts='@' ;; *) ts= ;; esac
|
||||
for i in - ''
|
||||
do
|
||||
case "$i" in '') ti='#' ;; *) ti= ;; esac
|
||||
rule=${t}trailing,${s}space,${i}indent
|
||||
|
||||
rm -f .gitattributes
|
||||
test_expect_success "rule=$rule" '
|
||||
git config core.whitespace "$rule" &&
|
||||
test_fix "$tt$ts$ti"
|
||||
'
|
||||
|
||||
test_expect_success "rule=$rule (attributes)" '
|
||||
git config --unset core.whitespace &&
|
||||
echo "target whitespace=$rule" >.gitattributes &&
|
||||
test_fix "$tt$ts$ti"
|
||||
'
|
||||
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
test_done
|
||||
@@ -641,6 +641,46 @@ test_expect_success 'creating a signed tag with -m message should succeed' '
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
get_tag_header u-signed-tag $commit commit $time >expect
|
||||
echo 'Another message' >>expect
|
||||
echo '-----BEGIN PGP SIGNATURE-----' >>expect
|
||||
test_expect_success 'sign with a given key id' '
|
||||
|
||||
git tag -u committer@example.com -m "Another message" u-signed-tag &&
|
||||
get_tag_msg u-signed-tag >actual &&
|
||||
git diff expect actual
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'sign with an unknown id (1)' '
|
||||
|
||||
! git tag -u author@example.com -m "Another message" o-signed-tag
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'sign with an unknown id (2)' '
|
||||
|
||||
! git tag -u DEADBEEF -m "Another message" o-signed-tag
|
||||
|
||||
'
|
||||
|
||||
cat >fakeeditor <<'EOF'
|
||||
#!/bin/sh
|
||||
test -n "$1" && exec >"$1"
|
||||
echo A signed tag message
|
||||
echo from a fake editor.
|
||||
EOF
|
||||
chmod +x fakeeditor
|
||||
|
||||
get_tag_header implied-sign $commit commit $time >expect
|
||||
./fakeeditor >>expect
|
||||
echo '-----BEGIN PGP SIGNATURE-----' >>expect
|
||||
test_expect_success '-u implies signed tag' '
|
||||
GIT_EDITOR=./fakeeditor git-tag -u CDDE430D implied-sign &&
|
||||
get_tag_msg implied-sign >actual &&
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
cat >sigmsgfile <<EOF
|
||||
Another signed tag
|
||||
message in a file.
|
||||
@@ -668,13 +708,6 @@ test_expect_success 'creating a signed tag with -F - should succeed' '
|
||||
git diff expect actual
|
||||
'
|
||||
|
||||
cat >fakeeditor <<'EOF'
|
||||
#!/bin/sh
|
||||
test -n "$1" && exec >"$1"
|
||||
echo A signed tag message
|
||||
echo from a fake editor.
|
||||
EOF
|
||||
chmod +x fakeeditor
|
||||
get_tag_header implied-annotate $commit commit $time >expect
|
||||
./fakeeditor >>expect
|
||||
echo '-----BEGIN PGP SIGNATURE-----' >>expect
|
||||
|
||||
@@ -20,6 +20,8 @@ Test switching across them.
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_tick
|
||||
|
||||
fill () {
|
||||
for i
|
||||
do
|
||||
@@ -30,9 +32,10 @@ fill () {
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
fill x y z > same &&
|
||||
fill 1 2 3 4 5 6 7 8 >one &&
|
||||
fill a b c d e >two &&
|
||||
git add one two &&
|
||||
git add same one two &&
|
||||
git commit -m "Initial A one, A two" &&
|
||||
|
||||
git checkout -b renamer &&
|
||||
@@ -74,16 +77,44 @@ test_expect_success "checkout with dirty tree without -m" '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success "checkout with unrelated dirty tree without -m" '
|
||||
|
||||
git checkout -f master &&
|
||||
fill 0 1 2 3 4 5 6 7 8 >same &&
|
||||
cp same kept
|
||||
git checkout side >messages &&
|
||||
git diff same kept
|
||||
(cat > messages.expect <<EOF
|
||||
M same
|
||||
EOF
|
||||
) &&
|
||||
touch messages.expect &&
|
||||
git diff messages.expect messages
|
||||
'
|
||||
|
||||
test_expect_success "checkout -m with dirty tree" '
|
||||
|
||||
git checkout -f master &&
|
||||
git clean -f &&
|
||||
|
||||
fill 0 1 2 3 4 5 6 7 8 >one &&
|
||||
git checkout -m side &&
|
||||
git checkout -m side > messages &&
|
||||
|
||||
test "$(git symbolic-ref HEAD)" = "refs/heads/side" &&
|
||||
|
||||
(cat >expect.messages <<EOF
|
||||
Merging side with local
|
||||
Merging:
|
||||
ab76817 Side M one, D two, A three
|
||||
virtual local
|
||||
found 1 common ancestor(s):
|
||||
7329388 Initial A one, A two
|
||||
Auto-merged one
|
||||
M one
|
||||
EOF
|
||||
) &&
|
||||
git diff expect.messages messages &&
|
||||
|
||||
fill "M one" "A three" "D two" >expect.master &&
|
||||
git diff --name-status master >current.master &&
|
||||
diff expect.master current.master &&
|
||||
@@ -145,7 +176,16 @@ test_expect_success 'checkout -m with merge conflict' '
|
||||
test_expect_success 'checkout to detach HEAD' '
|
||||
|
||||
git checkout -f renamer && git clean -f &&
|
||||
git checkout renamer^ &&
|
||||
git checkout renamer^ 2>messages &&
|
||||
(cat >messages.expect <<EOF
|
||||
Note: moving to "renamer^" which isn'"'"'t a local branch
|
||||
If you want to create a new branch from this checkout, you may do so
|
||||
(now or later) by using -b with the checkout command again. Example:
|
||||
git checkout -b <new_branch_name>
|
||||
HEAD is now at 7329388... Initial A one, A two
|
||||
EOF
|
||||
) &&
|
||||
git diff -w messages.expect messages &&
|
||||
H=$(git rev-parse --verify HEAD) &&
|
||||
M=$(git show-ref -s --verify refs/heads/master) &&
|
||||
test "z$H" = "z$M" &&
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
|
||||
# FIXME: Test the various index usages, -i and -o, test reflog,
|
||||
# signoff, hooks
|
||||
# signoff
|
||||
|
||||
test_description='git-commit'
|
||||
. ./test-lib.sh
|
||||
|
||||
@@ -88,4 +88,35 @@ test_expect_success 'status with relative paths' '
|
||||
|
||||
'
|
||||
|
||||
cat > expect << \EOF
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
#
|
||||
# new file: dir2/added
|
||||
#
|
||||
# Changed but not updated:
|
||||
# (use "git add <file>..." to update what will be committed)
|
||||
#
|
||||
# modified: dir1/modified
|
||||
#
|
||||
# Untracked files:
|
||||
# (use "git add <file>..." to include in what will be committed)
|
||||
#
|
||||
# dir1/untracked
|
||||
# dir2/modified
|
||||
# dir2/untracked
|
||||
# expect
|
||||
# output
|
||||
# untracked
|
||||
EOF
|
||||
|
||||
test_expect_success 'status without relative paths' '
|
||||
|
||||
git config status.relativePaths false
|
||||
(cd dir1 && git status) > output &&
|
||||
git diff expect output
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
94
t/t7503-pre-commit-hook.sh
Executable file
94
t/t7503-pre-commit-hook.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='pre-commit hook'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'with no hook' '
|
||||
|
||||
echo "foo" > file &&
|
||||
git add file &&
|
||||
git commit -m "first"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with no hook' '
|
||||
|
||||
echo "bar" > file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "bar"
|
||||
|
||||
'
|
||||
|
||||
# now install hook that always succeeds
|
||||
HOOKDIR="$(git rev-parse --git-dir)/hooks"
|
||||
HOOK="$HOOKDIR/pre-commit"
|
||||
mkdir -p "$HOOKDIR"
|
||||
cat > "$HOOK" <<EOF
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$HOOK"
|
||||
|
||||
test_expect_success 'with succeeding hook' '
|
||||
|
||||
echo "more" >> file &&
|
||||
git add file &&
|
||||
git commit -m "more"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with succeeding hook' '
|
||||
|
||||
echo "even more" >> file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "even more"
|
||||
|
||||
'
|
||||
|
||||
# now a hook that fails
|
||||
cat > "$HOOK" <<EOF
|
||||
#!/bin/sh
|
||||
exit 1
|
||||
EOF
|
||||
|
||||
test_expect_failure 'with failing hook' '
|
||||
|
||||
echo "another" >> file &&
|
||||
git add file &&
|
||||
git commit -m "another"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with failing hook' '
|
||||
|
||||
echo "stuff" >> file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "stuff"
|
||||
|
||||
'
|
||||
|
||||
chmod -x "$HOOK"
|
||||
if test "$(git config --bool core.filemode)" = false; then
|
||||
say "executable bit not honored - skipping tests of non-executable hook"
|
||||
else
|
||||
|
||||
test_expect_success 'with non-executable hook' '
|
||||
|
||||
echo "content" >> file &&
|
||||
git add file &&
|
||||
git commit -m "content"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with non-executable hook' '
|
||||
|
||||
echo "more content" >> file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "more content"
|
||||
|
||||
'
|
||||
|
||||
fi # non-executable hooks
|
||||
|
||||
test_done
|
||||
226
t/t7504-commit-msg-hook.sh
Executable file
226
t/t7504-commit-msg-hook.sh
Executable file
@@ -0,0 +1,226 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='commit-msg hook'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'with no hook' '
|
||||
|
||||
echo "foo" > file &&
|
||||
git add file &&
|
||||
git commit -m "first"
|
||||
|
||||
'
|
||||
|
||||
# set up fake editor for interactive editing
|
||||
cat > fake-editor <<'EOF'
|
||||
#!/bin/sh
|
||||
cp FAKE_MSG "$1"
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x fake-editor
|
||||
FAKE_EDITOR="$(pwd)/fake-editor"
|
||||
export FAKE_EDITOR
|
||||
|
||||
test_expect_success 'with no hook (editor)' '
|
||||
|
||||
echo "more foo" >> file &&
|
||||
git add file &&
|
||||
echo "more foo" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with no hook' '
|
||||
|
||||
echo "bar" > file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "bar"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with no hook (editor)' '
|
||||
|
||||
echo "more bar" > file &&
|
||||
git add file &&
|
||||
echo "more bar" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
|
||||
|
||||
'
|
||||
|
||||
# now install hook that always succeeds
|
||||
HOOKDIR="$(git rev-parse --git-dir)/hooks"
|
||||
HOOK="$HOOKDIR/commit-msg"
|
||||
mkdir -p "$HOOKDIR"
|
||||
cat > "$HOOK" <<EOF
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$HOOK"
|
||||
|
||||
test_expect_success 'with succeeding hook' '
|
||||
|
||||
echo "more" >> file &&
|
||||
git add file &&
|
||||
git commit -m "more"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'with succeeding hook (editor)' '
|
||||
|
||||
echo "more more" >> file &&
|
||||
git add file &&
|
||||
echo "more more" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with succeeding hook' '
|
||||
|
||||
echo "even more" >> file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "even more"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with succeeding hook (editor)' '
|
||||
|
||||
echo "even more more" >> file &&
|
||||
git add file &&
|
||||
echo "even more more" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
|
||||
|
||||
'
|
||||
|
||||
# now a hook that fails
|
||||
cat > "$HOOK" <<EOF
|
||||
#!/bin/sh
|
||||
exit 1
|
||||
EOF
|
||||
|
||||
test_expect_failure 'with failing hook' '
|
||||
|
||||
echo "another" >> file &&
|
||||
git add file &&
|
||||
git commit -m "another"
|
||||
|
||||
'
|
||||
|
||||
test_expect_failure 'with failing hook (editor)' '
|
||||
|
||||
echo "more another" >> file &&
|
||||
git add file &&
|
||||
echo "more another" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with failing hook' '
|
||||
|
||||
echo "stuff" >> file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "stuff"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with failing hook (editor)' '
|
||||
|
||||
echo "more stuff" >> file &&
|
||||
git add file &&
|
||||
echo "more stuff" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
|
||||
|
||||
'
|
||||
|
||||
chmod -x "$HOOK"
|
||||
if test "$(git config --bool core.filemode)" = false; then
|
||||
say "executable bit not honored - skipping tests of non-executable hook"
|
||||
else
|
||||
|
||||
test_expect_success 'with non-executable hook' '
|
||||
|
||||
echo "content" >> file &&
|
||||
git add file &&
|
||||
git commit -m "content"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'with non-executable hook (editor)' '
|
||||
|
||||
echo "content again" >> file &&
|
||||
git add file &&
|
||||
echo "content again" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit -m "content again"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with non-executable hook' '
|
||||
|
||||
echo "more content" >> file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "more content"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--no-verify with non-executable hook (editor)' '
|
||||
|
||||
echo "even more content" >> file &&
|
||||
git add file &&
|
||||
echo "even more content" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
|
||||
|
||||
'
|
||||
|
||||
fi # non-executable hooks
|
||||
|
||||
# now a hook that edits the commit message
|
||||
cat > "$HOOK" <<'EOF'
|
||||
#!/bin/sh
|
||||
echo "new message" > "$1"
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$HOOK"
|
||||
|
||||
commit_msg_is () {
|
||||
test "`git log --pretty=format:%s%b -1`" = "$1"
|
||||
}
|
||||
|
||||
test_expect_success 'hook edits commit message' '
|
||||
|
||||
echo "additional" >> file &&
|
||||
git add file &&
|
||||
git commit -m "additional" &&
|
||||
commit_msg_is "new message"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'hook edits commit message (editor)' '
|
||||
|
||||
echo "additional content" >> file &&
|
||||
git add file &&
|
||||
echo "additional content" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit &&
|
||||
commit_msg_is "new message"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success "hook doesn't edit commit message" '
|
||||
|
||||
echo "plus" >> file &&
|
||||
git add file &&
|
||||
git commit --no-verify -m "plus" &&
|
||||
commit_msg_is "plus"
|
||||
|
||||
'
|
||||
|
||||
test_expect_success "hook doesn't edit commit message (editor)" '
|
||||
|
||||
echo "more plus" >> file &&
|
||||
git add file &&
|
||||
echo "more plus" > FAKE_MSG &&
|
||||
GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify &&
|
||||
commit_msg_is "more plus"
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -97,15 +97,19 @@ test_expect_success 'migrate --minimize on old inited layout' "
|
||||
grep '^:refs/remotes/git-svn' fetch.out
|
||||
"
|
||||
|
||||
test_expect_success ".rev_db auto-converted to .rev_db.UUID" "
|
||||
test_expect_success ".rev_db auto-converted to .rev_map.UUID" "
|
||||
git-svn fetch -i trunk &&
|
||||
expect=$GIT_DIR/svn/trunk/.rev_db.* &&
|
||||
test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
|
||||
expect=\"\$(ls $GIT_DIR/svn/trunk/.rev_map.*)\" &&
|
||||
test -n \"\$expect\" &&
|
||||
mv \$expect $GIT_DIR/svn/trunk/.rev_db &&
|
||||
rev_db=\$(echo \$expect | sed -e 's,_map,_db,') &&
|
||||
convert_to_rev_db \$expect \$rev_db &&
|
||||
rm -f \$expect &&
|
||||
test -f \$rev_db &&
|
||||
git-svn fetch -i trunk &&
|
||||
test -L $GIT_DIR/svn/trunk/.rev_db &&
|
||||
test -f \$expect &&
|
||||
cmp \$expect $GIT_DIR/svn/trunk/.rev_db
|
||||
test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
|
||||
test ! -e $GIT_DIR/svn/trunk/.rev_db &&
|
||||
test -f \$expect
|
||||
"
|
||||
|
||||
test_done
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
test_description='git-svn info'
|
||||
|
||||
. ./lib-git-svn.sh
|
||||
say 'skipping svn-info test (has a race undiagnosed yet)'
|
||||
test_done
|
||||
|
||||
ptouch() {
|
||||
perl -w -e '
|
||||
|
||||
@@ -326,6 +326,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
|
||||
die("unable to set up diff options to follow renames");
|
||||
diff_tree(t1, t2, base, &diff_opts);
|
||||
diffcore_std(&diff_opts);
|
||||
diff_tree_release_paths(&diff_opts);
|
||||
|
||||
/* Go through the new set of filepairing, and see if we find a more interesting one */
|
||||
for (i = 0; i < q->nr; i++) {
|
||||
@@ -342,6 +343,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
|
||||
choice = p;
|
||||
|
||||
/* Update the path we use from now on.. */
|
||||
diff_tree_release_paths(opt);
|
||||
opt->paths[0] = xstrdup(p->one->path);
|
||||
diff_tree_setup_paths(opt->paths, opt);
|
||||
break;
|
||||
|
||||
4
var.c
4
var.c
@@ -21,7 +21,7 @@ static void list_vars(void)
|
||||
{
|
||||
struct git_var *ptr;
|
||||
for(ptr = git_vars; ptr->read; ptr++) {
|
||||
printf("%s=%s\n", ptr->name, ptr->read(0));
|
||||
printf("%s=%s\n", ptr->name, ptr->read(IDENT_WARN_ON_NO_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ static const char *read_var(const char *var)
|
||||
val = NULL;
|
||||
for(ptr = git_vars; ptr->read; ptr++) {
|
||||
if (strcmp(var, ptr->name) == 0) {
|
||||
val = ptr->read(1);
|
||||
val = ptr->read(IDENT_ERROR_ON_NO_NAME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,16 +34,12 @@ void maybe_flush_or_die(FILE *f, const char *desc)
|
||||
return;
|
||||
}
|
||||
if (fflush(f)) {
|
||||
#ifndef __MINGW32__
|
||||
if (errno == EPIPE)
|
||||
#else
|
||||
/*
|
||||
* On Windows, EPIPE is returned only by the first write()
|
||||
* after the reading end has closed its handle; subsequent
|
||||
* write()s return EINVAL.
|
||||
*/
|
||||
if (errno == EPIPE || errno == EINVAL)
|
||||
#endif
|
||||
exit(0);
|
||||
die("write failure on %s: %s", desc, strerror(errno));
|
||||
}
|
||||
|
||||
96
ws.c
Normal file
96
ws.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Whitespace rules
|
||||
*
|
||||
* Copyright (c) 2007 Junio C Hamano
|
||||
*/
|
||||
|
||||
#include "cache.h"
|
||||
#include "attr.h"
|
||||
|
||||
static struct whitespace_rule {
|
||||
const char *rule_name;
|
||||
unsigned rule_bits;
|
||||
} whitespace_rule_names[] = {
|
||||
{ "trailing-space", WS_TRAILING_SPACE },
|
||||
{ "space-before-tab", WS_SPACE_BEFORE_TAB },
|
||||
{ "indent-with-non-tab", WS_INDENT_WITH_NON_TAB },
|
||||
};
|
||||
|
||||
unsigned parse_whitespace_rule(const char *string)
|
||||
{
|
||||
unsigned rule = WS_DEFAULT_RULE;
|
||||
|
||||
while (string) {
|
||||
int i;
|
||||
size_t len;
|
||||
const char *ep;
|
||||
int negated = 0;
|
||||
|
||||
string = string + strspn(string, ", \t\n\r");
|
||||
ep = strchr(string, ',');
|
||||
if (!ep)
|
||||
len = strlen(string);
|
||||
else
|
||||
len = ep - string;
|
||||
|
||||
if (*string == '-') {
|
||||
negated = 1;
|
||||
string++;
|
||||
len--;
|
||||
}
|
||||
if (!len)
|
||||
break;
|
||||
for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) {
|
||||
if (strncmp(whitespace_rule_names[i].rule_name,
|
||||
string, len))
|
||||
continue;
|
||||
if (negated)
|
||||
rule &= ~whitespace_rule_names[i].rule_bits;
|
||||
else
|
||||
rule |= whitespace_rule_names[i].rule_bits;
|
||||
break;
|
||||
}
|
||||
string = ep;
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
static void setup_whitespace_attr_check(struct git_attr_check *check)
|
||||
{
|
||||
static struct git_attr *attr_whitespace;
|
||||
|
||||
if (!attr_whitespace)
|
||||
attr_whitespace = git_attr("whitespace", 10);
|
||||
check[0].attr = attr_whitespace;
|
||||
}
|
||||
|
||||
unsigned whitespace_rule(const char *pathname)
|
||||
{
|
||||
struct git_attr_check attr_whitespace_rule;
|
||||
|
||||
setup_whitespace_attr_check(&attr_whitespace_rule);
|
||||
if (!git_checkattr(pathname, 1, &attr_whitespace_rule)) {
|
||||
const char *value;
|
||||
|
||||
value = attr_whitespace_rule.value;
|
||||
if (ATTR_TRUE(value)) {
|
||||
/* true (whitespace) */
|
||||
unsigned all_rule = 0;
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
|
||||
all_rule |= whitespace_rule_names[i].rule_bits;
|
||||
return all_rule;
|
||||
} else if (ATTR_FALSE(value)) {
|
||||
/* false (-whitespace) */
|
||||
return 0;
|
||||
} else if (ATTR_UNSET(value)) {
|
||||
/* reset to default (!whitespace) */
|
||||
return whitespace_rule_cfg;
|
||||
} else {
|
||||
/* string */
|
||||
return parse_whitespace_rule(value);
|
||||
}
|
||||
} else {
|
||||
return whitespace_rule_cfg;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "revision.h"
|
||||
#include "diffcore.h"
|
||||
|
||||
int wt_status_relative_paths = 1;
|
||||
int wt_status_use_color = 0;
|
||||
static char wt_status_colors[][COLOR_MAXLEN] = {
|
||||
"", /* WT_STATUS_HEADER: normal */
|
||||
@@ -121,6 +122,9 @@ static char *quote_path(const char *in, int len,
|
||||
}
|
||||
}
|
||||
|
||||
if (!out->len)
|
||||
strbuf_addstr(out, "./");
|
||||
|
||||
return out->buf;
|
||||
}
|
||||
|
||||
@@ -397,6 +401,11 @@ int git_status_config(const char *k, const char *v)
|
||||
if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
|
||||
int slot = parse_status_slot(k, 13);
|
||||
color_parse(v, k, wt_status_colors[slot]);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "status.relativepaths")) {
|
||||
wt_status_relative_paths = git_config_bool(k, v);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(k, v);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ struct wt_status {
|
||||
|
||||
int git_status_config(const char *var, const char *value);
|
||||
int wt_status_use_color;
|
||||
int wt_status_relative_paths;
|
||||
void wt_status_prepare(struct wt_status *s);
|
||||
void wt_status_print(struct wt_status *s);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user