Merge commit 'j6t/master' into devel

Conflicts:
	Makefile
	compat/mingw.c
	compat/win32mmap.c
	t/t1301-shared-repo.sh
	t/t4020-diff-external.sh
	t/t4129-apply-samemode.sh
	t/t7005-editor.sh
	t/test-lib.sh

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2009-04-07 17:39:50 +02:00
231 changed files with 5490 additions and 3066 deletions

View File

@@ -129,3 +129,6 @@ For C programs:
used in the git core command set (unless your command is clearly used in the git core command set (unless your command is clearly
separate from it, such as an importer to convert random-scm-X separate from it, such as an importer to convert random-scm-X
repositories to git). repositories to git).
- When we pass <string, length> pair to functions, we should try to
pass them in that order.

View File

@@ -41,7 +41,8 @@ man7dir=$(mandir)/man7
ASCIIDOC=asciidoc ASCIIDOC=asciidoc
ASCIIDOC_EXTRA = ASCIIDOC_EXTRA =
MANPAGE_XSL = callouts.xsl MANPAGE_XSL = manpage-normal.xsl
XMLTO_EXTRA =
INSTALL?=install INSTALL?=install
RM ?= rm -f RM ?= rm -f
DOC_REF = origin/man DOC_REF = origin/man
@@ -59,12 +60,47 @@ endif
-include ../config.mak.autogen -include ../config.mak.autogen
-include ../config.mak -include ../config.mak
#
# For asciidoc ...
# -7.1.2, no extra settings are needed.
# 8.0-, set ASCIIDOC8.
#
#
# For docbook-xsl ...
# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0)
# 1.69.0, no extra settings are needed?
# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP?
# 1.71.1, no extra settings are needed?
# 1.72.0, set DOCBOOK_XSL_172.
# 1.73.0-, set ASCIIDOC_NO_ROFF
#
#
# If you had been using DOCBOOK_XSL_172 in an attempt to get rid
# of 'the ".ft C" problem' in your generated manpages, and you
# instead ended up with weird characters around callouts, try
# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8).
#
ifdef ASCIIDOC8 ifdef ASCIIDOC8
ASCIIDOC_EXTRA += -a asciidoc7compatible ASCIIDOC_EXTRA += -a asciidoc7compatible
endif endif
ifdef DOCBOOK_XSL_172 ifdef DOCBOOK_XSL_172
ASCIIDOC_EXTRA += -a docbook-xsl-172 ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
MANPAGE_XSL = manpage-1.72.xsl MANPAGE_XSL = manpage-1.72.xsl
else
ifdef ASCIIDOC_NO_ROFF
# docbook-xsl after 1.72 needs the regular XSL, but will not
# pass-thru raw roff codes from asciidoc.conf, so turn them off.
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
endif
endif
ifdef MAN_BOLD_LITERAL
XMLTO_EXTRA += -m manpage-bold-literal.xsl
endif
ifdef DOCBOOK_SUPPRESS_SP
XMLTO_EXTRA += -m manpage-suppress-sp.xsl
endif endif
# #
@@ -76,6 +112,32 @@ endif
# yourself - yes, all 6 characters of it! # yourself - yes, all 6 characters of it!
# #
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
ifneq ($(findstring $(MAKEFLAGS),w),w)
PRINT_DIR = --no-print-directory
else # "make -w"
NO_SUBDIR = :
endif
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifndef V
QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
QUIET_XMLTO = @echo ' ' XMLTO $@;
QUIET_DB2TEXI = @echo ' ' DB2TEXI $@;
QUIET_MAKEINFO = @echo ' ' MAKEINFO $@;
QUIET_DBLATEX = @echo ' ' DBLATEX $@;
QUIET_XSLTPROC = @echo ' ' XSLTPROC $@;
QUIET_GEN = @echo ' ' GEN $@;
QUIET_STDERR = 2> /dev/null
QUIET_SUBDIR0 = +@subdir=
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
$(MAKE) $(PRINT_DIR) -C $$subdir
export V
endif
endif
all: html man all: html man
html: $(DOC_HTML) html: $(DOC_HTML)
@@ -119,7 +181,7 @@ install-html: html
sh ./install-webdoc.sh $(DESTDIR)$(htmldir) sh ./install-webdoc.sh $(DESTDIR)$(htmldir)
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE ../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
$(MAKE) -C ../ GIT-VERSION-FILE $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
-include ../GIT-VERSION-FILE -include ../GIT-VERSION-FILE
@@ -127,8 +189,8 @@ install-html: html
# Determine "include::" file references in asciidoc files. # Determine "include::" file references in asciidoc files.
# #
doc.dep : $(wildcard *.txt) build-docdep.perl doc.dep : $(wildcard *.txt) build-docdep.perl
$(RM) $@+ $@ $(QUIET_GEN)$(RM) $@+ $@ && \
$(PERL_PATH) ./build-docdep.perl >$@+ $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
mv $@+ $@ mv $@+ $@
-include doc.dep -include doc.dep
@@ -146,91 +208,94 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
$(cmds_txt): cmd-list.made $(cmds_txt): cmd-list.made
cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
$(RM) $@ $(QUIET_GEN)$(RM) $@ && \
$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
date >$@ date >$@
clean: clean:
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
$(RM) *.texi *.texi+ git.info gitman.info $(RM) *.texi *.texi+ *.texi++ git.info gitman.info
$(RM) howto-index.txt howto/*.html doc.dep $(RM) howto-index.txt howto/*.html doc.dep
$(RM) technical/api-*.html technical/api-index.txt $(RM) technical/api-*.html technical/api-index.txt
$(RM) $(cmds_txt) *.made $(RM) $(cmds_txt) *.made
$(MAN_HTML): %.html : %.txt $(MAN_HTML): %.html : %.txt
$(RM) $@+ $@ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \ $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
mv $@+ $@ mv $@+ $@
%.1 %.5 %.7 : %.xml %.1 %.5 %.7 : %.xml
$(RM) $@ $(QUIET_XMLTO)$(RM) $@ && \
xmlto -m $(MANPAGE_XSL) man $< xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
%.xml : %.txt %.xml : %.txt
$(RM) $@+ $@ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
mv $@+ $@ mv $@+ $@
user-manual.xml: user-manual.txt user-manual.conf user-manual.xml: user-manual.txt user-manual.conf
$(ASCIIDOC) -b docbook -d book $< $(QUIET_ASCIIDOC)$(ASCIIDOC) -b docbook -d book $<
technical/api-index.txt: technical/api-index-skel.txt \ technical/api-index.txt: technical/api-index-skel.txt \
technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS)) technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
cd technical && sh ./api-index.sh $(QUIET_GEN)cd technical && sh ./api-index.sh
$(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt $(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt
$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \ $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt
XSLT = docbook.xsl XSLT = docbook.xsl
XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
user-manual.html: user-manual.xml user-manual.html: user-manual.xml
xsltproc $(XSLTOPTS) -o $@ $(XSLT) $< $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
git.info: user-manual.texi git.info: user-manual.texi
$(MAKEINFO) --no-split -o $@ user-manual.texi $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
user-manual.texi: user-manual.xml user-manual.texi: user-manual.xml
$(RM) $@+ $@ $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
$(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout | \ $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
$(PERL_PATH) fix-texi.perl >$@+ $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
rm $@++ && \
mv $@+ $@ mv $@+ $@
user-manual.pdf: user-manual.xml user-manual.pdf: user-manual.xml
$(RM) $@+ $@ $(QUIET_DBLATEX)$(RM) $@+ $@ && \
$(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
mv $@+ $@ mv $@+ $@
gitman.texi: $(MAN_XML) cat-texi.perl gitman.texi: $(MAN_XML) cat-texi.perl
$(RM) $@+ $@ $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \ ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
--to-stdout $(xml);)) | $(PERL_PATH) cat-texi.perl $@ >$@+ --to-stdout $(xml) &&) true) > $@++ && \
$(PERL_PATH) cat-texi.perl $@ <$@++ >$@+ && \
rm $@++ && \
mv $@+ $@ mv $@+ $@
gitman.info: gitman.texi gitman.info: gitman.texi
$(MAKEINFO) --no-split --no-validate $*.texi $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
$(RM) $@+ $@ $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ $(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ && \
mv $@+ $@ mv $@+ $@
howto-index.txt: howto-index.sh $(wildcard howto/*.txt) howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
$(RM) $@+ $@ $(QUIET_GEN)$(RM) $@+ $@ && \
sh ./howto-index.sh $(wildcard howto/*.txt) >$@+ sh ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \
mv $@+ $@ mv $@+ $@
$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
$(ASCIIDOC) -b xhtml11 $*.txt $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt
WEBDOC_DEST = /pub/software/scm/git/docs WEBDOC_DEST = /pub/software/scm/git/docs
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
$(RM) $@+ $@ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
mv $@+ $@ mv $@+ $@
install-webdoc : html install-webdoc : html

View File

@@ -0,0 +1,45 @@
GIT v1.6.2.2 Release Notes
==========================
Fixes since v1.6.2.1
--------------------
* A longstanding confusing description of what --pickaxe option of
git-diff does has been clarified in the documentation.
* "git-blame -S" did not quite work near the commits that were given
on the command line correctly.
* "git diff --pickaxe-regexp" did not count overlapping matches
correctly.
* "git diff" did not feed files in work-tree representation to external
diff and textconv.
* "git-fetch" in a repository that was not cloned from anywhere said
it cannot find 'origin', which was hard to understand for new people.
* "git-format-patch --numbered-files --stdout" did not have to die of
incompatible options; it now simply ignores --numbered-files as no files
are produced anyway.
* "git-ls-files --deleted" did not work well with GIT_DIR&GIT_WORK_TREE.
* "git-read-tree A B C..." without -m option has been broken for a long
time.
* git-send-email ignored --in-reply-to when --no-thread was given.
* 'git-submodule add' did not tolerate extra slashes and ./ in the path it
accepted from the command line; it now is more lenient.
* git-svn misbehaved when the project contained a path that began with
two dashes.
* import-zips script (in contrib) did not compute the common directory
prefix correctly.
* miscompilation of negated enum constants by old gcc (2.9) affected the
codepaths to spawn subprocesses.
Many small documentation updates are included as well.

View File

@@ -22,6 +22,13 @@ branch pointed at by its HEAD, gets a large warning. You can choose what
should happen upon such a push by setting the configuration variable should happen upon such a push by setting the configuration variable
receive.denyDeleteCurrent in the receiving repository. receive.denyDeleteCurrent in the receiving repository.
When the user does not tell "git push" what to push, it has always
pushed matching refs. For some people it is unexpected, and a new
configuration variable push.default has been introduced to allow
changing a different default behaviour. To advertise the new feature,
a big warning is issued if this is not configured and a git push without
arguments is attempted.
Updates since v1.6.2 Updates since v1.6.2
-------------------- --------------------
@@ -30,8 +37,21 @@ Updates since v1.6.2
(performance) (performance)
* many uses of lstat(2) in the codepath for "git checkout" have been
optimized out.
(usability, bells and whistles) (usability, bells and whistles)
* rsync:/path/to/repo can be used to run git over rsync for local
repositories. It may not be useful in practice; meant primarily for
testing.
* http transport learned to prompt and use password when fetching from or
pushing to http://user@host.xz/ URL.
* (msysgit) progress output that is sent over the sideband protocol can
be handled appropriately in Windows console.
* "--pretty=<style>" option to the log family of commands can now be * "--pretty=<style>" option to the log family of commands can now be
spelled as "--format=<style>". In addition, --format=%formatstring spelled as "--format=<style>". In addition, --format=%formatstring
is a short-hand for --pretty=tformat:%formatstring. is a short-hand for --pretty=tformat:%formatstring.
@@ -42,6 +62,10 @@ Updates since v1.6.2
with the 'edit' action in git-add -i/-p, you can abort the editor to with the 'edit' action in git-add -i/-p, you can abort the editor to
tell git not to apply it. tell git not to apply it.
* The number of commits shown in "you are ahead/behind your upstream"
messages given by "git checkout" and "git status" used to count merge
commits; now it doesn't.
* git-archive learned --output=<file> option. * git-archive learned --output=<file> option.
* git-bisect shows not just the number of remaining commits whose goodness * git-bisect shows not just the number of remaining commits whose goodness
@@ -57,11 +81,19 @@ Updates since v1.6.2
* git-clone runs post-checkout hook when run without --no-checkout. * git-clone runs post-checkout hook when run without --no-checkout.
* git-fast-export choked when seeing a tag that does not point at commit.
* git-format-patch can be told to use attachment with a new configuration, * git-format-patch can be told to use attachment with a new configuration,
format.attach. format.attach.
* git-format-patch can be told to produce deep or shallow message threads. * git-format-patch can be told to produce deep or shallow message threads.
* git-format-patch learned format.headers configuration to add extra
header fields to the output. This behaviour is similar to the existing
--add-header=<header> option of the command.
* git-grep learned to highlight the found substrings in color.
* git-imap-send learned to work around Thunderbird's inability to easily * git-imap-send learned to work around Thunderbird's inability to easily
disable format=flowed with a new configuration, imap.preformattedHTML. disable format=flowed with a new configuration, imap.preformattedHTML.
@@ -71,6 +103,13 @@ Updates since v1.6.2
* git-rebase can be told to report diffstat with the --stat option. * git-rebase can be told to report diffstat with the --stat option.
* Output from git-remote command has been vastly improved.
* git-repack (invoked from git-gc) did not work as nicely as it should in
a repository that borrows objects from neighbours via alternates
mechanism especially when some packs are marked with the ".keep" flag
to prevent them from being repacked.
* git-send-email learned --confirm option to review the Cc: list before * git-send-email learned --confirm option to review the Cc: list before
sending the messages out. sending the messages out.
@@ -78,9 +117,18 @@ Updates since v1.6.2
* Test scripts can be run under valgrind. * Test scripts can be run under valgrind.
* Test scripts can be run with installed git.
* Makefile learned 'coverage' option to run the test suites with * Makefile learned 'coverage' option to run the test suites with
coverage tracking enabled. coverage tracking enabled.
* Building the manpages with docbook-xsl between 1.69.1 and 1.71.1 now
requires setting DOCBOOK_SUPPRESS_SP to work around a docbook-xsl bug.
This workaround used to be enabled by default, but causes problems
with newer versions of docbook-xsl. In addition, there are a few more
knobs you can tweak to work around issues with various versions of the
docbook-xsl package. See comments in Documentation/Makefile for details.
Fixes since v1.6.2 Fixes since v1.6.2
------------------ ------------------
@@ -90,15 +138,14 @@ release, unless otherwise noted.
Here are fixes that this release has, but have not been backported to Here are fixes that this release has, but have not been backported to
v1.6.2.X series. v1.6.2.X series.
* 'git-submodule add' did not tolerate extra slashes and ./ in the * The initial checkout did not read the attributes from the .gitattribute
path it accepted from the command line; it now is more lenient file that is being checked out.
(if needed, backport by merging db75ada).
* git-gc spent excessive amount of time to decide if an object appears * git-gc spent excessive amount of time to decide if an object appears
in a locally existing pack (if needed, backport by merging 69e020a). in a locally existing pack (if needed, backport by merging 69e020a).
--- ---
exec >/var/tmp/1 exec >/var/tmp/1
O=v1.6.2.1-135-g7d65c21 O=v1.6.2.2-403-g8130949
echo O=$(git describe master) echo O=$(git describe master)
git shortlog --no-merges $O..master ^maint git shortlog --no-merges $O..master ^maint

View File

@@ -27,7 +27,7 @@ ifdef::backend-docbook[]
endif::backend-docbook[] endif::backend-docbook[]
ifdef::backend-docbook[] ifdef::backend-docbook[]
ifndef::docbook-xsl-172[] ifndef::git-asciidoc-no-roff[]
# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this. # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
# v1.72 breaks with this because it replaces dots not in roff requests. # v1.72 breaks with this because it replaces dots not in roff requests.
[listingblock] [listingblock]
@@ -42,16 +42,16 @@ ifdef::doctype-manpage[]
endif::doctype-manpage[] endif::doctype-manpage[]
</literallayout> </literallayout>
{title#}</example> {title#}</example>
endif::docbook-xsl-172[] endif::git-asciidoc-no-roff[]
ifdef::docbook-xsl-172[] ifdef::git-asciidoc-no-roff[]
ifdef::doctype-manpage[] ifdef::doctype-manpage[]
# The following two small workarounds insert a simple paragraph after screen # The following two small workarounds insert a simple paragraph after screen
[listingblock] [listingblock]
<example><title>{title}</title> <example><title>{title}</title>
<screen> <literallayout>
| |
</screen><simpara></simpara> </literallayout><simpara></simpara>
{title#}</example> {title#}</example>
[verseblock] [verseblock]
@@ -59,10 +59,11 @@ ifdef::doctype-manpage[]
{title%}<literallayout{id? id="{id}"}> {title%}<literallayout{id? id="{id}"}>
{title#}<literallayout> {title#}<literallayout>
| |
</literallayout><simpara></simpara> </literallayout>
{title#}</para></formalpara> {title#}</para></formalpara>
{title%}<simpara></simpara>
endif::doctype-manpage[] endif::doctype-manpage[]
endif::docbook-xsl-172[] endif::git-asciidoc-no-roff[]
endif::backend-docbook[] endif::backend-docbook[]
ifdef::doctype-manpage[] ifdef::doctype-manpage[]

View File

@@ -39,7 +39,7 @@ of lines before or after the line given by <start>.
Show raw timestamp (Default: off). Show raw timestamp (Default: off).
-S <revs-file>:: -S <revs-file>::
Use revs from revs-file instead of calling linkgit:git-rev-list[1]. Use revisions from revs-file instead of calling linkgit:git-rev-list[1].
--reverse:: --reverse::
Walk history forward instead of backward. Instead of showing Walk history forward instead of backward. Instead of showing

View File

@@ -1,30 +0,0 @@
<!-- callout.xsl: converts asciidoc callouts to man page format -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="co">
<xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/>
</xsl:template>
<xsl:template match="calloutlist">
<xsl:text>.sp&#10;</xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;</xsl:text>
</xsl:template>
<xsl:template match="callout">
<xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/>
<xsl:apply-templates/>
<xsl:text>.br&#10;</xsl:text>
</xsl:template>
<!-- sorry, this is not about callouts, but attempts to work around
spurious .sp at the tail of the line docbook stylesheets seem to add -->
<xsl:template match="simpara">
<xsl:variable name="content">
<xsl:apply-templates/>
</xsl:variable>
<xsl:value-of select="normalize-space($content)"/>
<xsl:if test="not(ancestor::authorblurb) and
not(ancestor::personblurb)">
<xsl:text>&#10;&#10;</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View File

@@ -25,7 +25,7 @@ blank lines are ignored.
The file consists of sections and variables. A section begins with The file consists of sections and variables. A section begins with
the name of the section in square brackets and continues until the next the name of the section in square brackets and continues until the next
section begins. Section names are not case sensitive. Only alphanumeric section begins. Section names are not case sensitive. Only alphanumeric
characters, '`-`' and '`.`' are allowed in section names. Each variable characters, `-` and `.` are allowed in section names. Each variable
must belong to some section, which means that there must be section must belong to some section, which means that there must be section
header before first setting of a variable. header before first setting of a variable.
@@ -39,7 +39,7 @@ in the section header, like in example below:
-------- --------
Subsection names can contain any characters except newline (doublequote Subsection names can contain any characters except newline (doublequote
'`"`' and backslash have to be escaped as '`\"`' and '`\\`', `"` and backslash have to be escaped as `\"` and `\\`,
respectively) and are case sensitive. Section header cannot span multiple respectively) and are case sensitive. Section header cannot span multiple
lines. Variables may belong directly to a section or to a given subsection. lines. Variables may belong directly to a section or to a given subsection.
You can have `[section]` if you have `[section "subsection"]`, but you You can have `[section]` if you have `[section "subsection"]`, but you
@@ -53,7 +53,7 @@ All the other lines are recognized as setting variables, in the form
'name = value'. If there is no equal sign on the line, the entire line 'name = value'. If there is no equal sign on the line, the entire line
is taken as 'name' and the variable is recognized as boolean "true". is taken as 'name' and the variable is recognized as boolean "true".
The variable names are case-insensitive and only alphanumeric The variable names are case-insensitive and only alphanumeric
characters and '`-`' are allowed. There can be more than one value characters and `-` are allowed. There can be more than one value
for a given variable; we say then that variable is multivalued. for a given variable; we say then that variable is multivalued.
Leading and trailing whitespace in a variable value is discarded. Leading and trailing whitespace in a variable value is discarded.
@@ -69,15 +69,15 @@ String values may be entirely or partially enclosed in double quotes.
You need to enclose variable value in double quotes if you want to You need to enclose variable value in double quotes if you want to
preserve leading or trailing whitespace, or if variable value contains preserve leading or trailing whitespace, or if variable value contains
beginning of comment characters (if it contains '#' or ';'). beginning of comment characters (if it contains '#' or ';').
Double quote '`"`' and backslash '`\`' characters in variable value must Double quote `"` and backslash `\` characters in variable value must
be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'. be escaped: use `\"` for `"` and `\\` for `\`.
The following escape sequences (beside '`\"`' and '`\\`') are recognized: The following escape sequences (beside `\"` and `\\`) are recognized:
'`\n`' for newline character (NL), '`\t`' for horizontal tabulation (HT, TAB) `\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
and '`\b`' for backspace (BS). No other char escape sequence, nor octal and `\b` for backspace (BS). No other char escape sequence, nor octal
char sequences are valid. char sequences are valid.
Variable value ending in a '`\`' is continued on the next line in the Variable value ending in a `\` is continued on the next line in the
customary UNIX fashion. customary UNIX fashion.
Some variables may require special value format. Some variables may require special value format.
@@ -221,6 +221,11 @@ core.gitProxy::
Can be overridden by the 'GIT_PROXY_COMMAND' environment variable Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
(which always applies universally, without the special "for" (which always applies universally, without the special "for"
handling). handling).
+
The special string `none` can be used as the proxy command to
specify that no proxy be used for a given domain pattern.
This is useful for excluding servers inside a firewall from
proxy use, while defaulting to a common proxy for external domains.
core.ignoreStat:: core.ignoreStat::
If true, commands which modify both the working tree and the index If true, commands which modify both the working tree and the index
@@ -382,9 +387,9 @@ core.pager::
to override git's default settings this way, you need to override git's default settings this way, you need
to be explicit. For example, to disable the S option to be explicit. For example, to disable the S option
in a backward compatible manner, set `core.pager` in a backward compatible manner, set `core.pager`
to "`less -+$LESS -FRX`". This will be passed to the to `less -+$LESS -FRX`. This will be passed to the
shell by git, which will translate the final command to shell by git, which will translate the final command to
"`LESS=FRSX less -+FRSX -FRX`". `LESS=FRSX less -+FRSX -FRX`.
core.whitespace:: core.whitespace::
A comma separated list of common whitespace problems to A comma separated list of common whitespace problems to
@@ -468,10 +473,14 @@ branch.autosetuprebase::
This option defaults to never. This option defaults to never.
branch.<name>.remote:: branch.<name>.remote::
When in branch <name>, it tells 'git-fetch' which remote to fetch. When in branch <name>, it tells 'git-fetch' and 'git-push' which
If this option is not given, 'git-fetch' defaults to remote "origin". remote to fetch from/push to. It defaults to `origin` if no remote is
configured. `origin` is also used if you are not on any branch.
branch.<name>.merge:: branch.<name>.merge::
Defines, together with branch.<name>.remote, the upstream branch
for the given branch. It tells 'git-fetch'/'git-pull' which
branch to merge from.
When in branch <name>, it tells 'git-fetch' the default When in branch <name>, it tells 'git-fetch' the default
refspec to be marked for merging in FETCH_HEAD. The value is refspec to be marked for merging in FETCH_HEAD. The value is
handled like the remote part of a refspec, and must match a handled like the remote part of a refspec, and must match a
@@ -548,6 +557,25 @@ color.diff.<slot>::
whitespace errors). The values of these variables may be specified as whitespace errors). The values of these variables may be specified as
in color.branch.<slot>. in color.branch.<slot>.
color.grep::
When set to `always`, always highlight matches. When `false` (or
`never`), never. When set to `true` or `auto`, use color only
when the output is written to the terminal. Defaults to `false`.
color.grep.external::
The string value of this variable is passed to an external 'grep'
command as a command line option if match highlighting is turned
on. If set to an empty string, no option is passed at all,
turning off coloring for external 'grep' calls; this is the default.
For GNU grep, set it to `--color=always` to highlight matches even
when a pager is used.
color.grep.match::
Use customized color for matches. The value of this variable
may be specified as in color.branch.<slot>. It is passed using
the environment variables 'GREP_COLOR' and 'GREP_COLORS' when
calling an external 'grep'.
color.interactive:: color.interactive::
When set to `always`, always use colors for interactive prompts When set to `always`, always use colors for interactive prompts
and displays (such as those used by "git-add --interactive"). and displays (such as those used by "git-add --interactive").
@@ -1161,7 +1189,7 @@ pager.<cmd>::
particular git subcommand when writing to a tty. If particular git subcommand when writing to a tty. If
`\--paginate` or `\--no-pager` is specified on the command line, `\--paginate` or `\--no-pager` is specified on the command line,
it takes precedence over this option. To disable pagination for it takes precedence over this option. To disable pagination for
all commands, set `core.pager` or 'GIT_PAGER' to "`cat`". all commands, set `core.pager` or `GIT_PAGER` to `cat`.
pull.octopus:: pull.octopus::
The default merge strategy to use when pulling multiple branches The default merge strategy to use when pulling multiple branches
@@ -1170,6 +1198,19 @@ pull.octopus::
pull.twohead:: pull.twohead::
The default merge strategy to use when pulling a single branch. The default merge strategy to use when pulling a single branch.
push.default::
Defines the action git push should take if no refspec is given
on the command line, no refspec is configured in the remote, and
no refspec is implied by any of the options given on the command
line. Possible values are:
+
* `nothing` do not push anything.
* `matching` push all matching branches.
All branches having the same name in both ends are considered to be
matching. This is the default.
* `tracking` push the current branch to the branch it is tracking.
* `current` push the current branch to a branch of the same name.
rebase.stat:: rebase.stat::
Whether to show a diffstat of what changed upstream since the last Whether to show a diffstat of what changed upstream since the last
rebase. False by default. rebase. False by default.

View File

@@ -176,7 +176,10 @@ override configuration settings.
number. number.
-S<string>:: -S<string>::
Look for differences that contain the change in <string>. Look for differences that introduce or remove an instance of
<string>. Note that this is different than the string simply
appearing in diff output; see the 'pickaxe' entry in
linkgit:gitdiffcore[7] for more details.
--pickaxe-all:: --pickaxe-all::
When -S finds a change, show all the changes in that When -S finds a change, show all the changes in that

View File

@@ -98,7 +98,7 @@ Use a tarball as a starting point for a new repository.::
------------ ------------
$ tar zxf frotz.tar.gz $ tar zxf frotz.tar.gz
$ cd frotz $ cd frotz
$ git-init $ git init
$ git add . <1> $ git add . <1>
$ git commit -m "import of frotz source tree." $ git commit -m "import of frotz source tree."
$ git tag v2.43 <2> $ git tag v2.43 <2>

View File

@@ -23,7 +23,7 @@ prepended to the filenames in the archive.
'git-archive' behaves differently when given a tree ID versus when 'git-archive' behaves differently when given a tree ID versus when
given a commit ID or tag ID. In the first case the current time is given a commit ID or tag ID. In the first case the current time is
used as modification time of each file in the archive. In the latter used as the modification time of each file in the archive. In the latter
case the commit time as recorded in the referenced commit object is case the commit time as recorded in the referenced commit object is
used instead. Additionally the commit ID is stored in a global used instead. Additionally the commit ID is stored in a global
extended pax header if the tar format is used; it can be extracted extended pax header if the tar format is used; it can be extracted
@@ -52,11 +52,11 @@ OPTIONS
Write the archive to <file> instead of stdout. Write the archive to <file> instead of stdout.
<extra>:: <extra>::
This can be any options that the archiver backend understand. This can be any options that the archiver backend understands.
See next section. See next section.
--remote=<repo>:: --remote=<repo>::
Instead of making a tar archive from local repository, Instead of making a tar archive from the local repository,
retrieve a tar archive from a remote repository. retrieve a tar archive from a remote repository.
--exec=<git-upload-archive>:: --exec=<git-upload-archive>::
@@ -109,7 +109,7 @@ EXAMPLES
git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -):: git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)::
Create a tar archive that contains the contents of the Create a tar archive that contains the contents of the
latest commit on the current branch, and extracts it in latest commit on the current branch, and extract it in the
`/var/tmp/junk` directory. `/var/tmp/junk` directory.
git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz:: git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz::

View File

@@ -3,7 +3,7 @@ git-bisect(1)
NAME NAME
---- ----
git-bisect - Find the change that introduced a bug by binary search git-bisect - Find by binary search the change that introduced a bug
SYNOPSIS SYNOPSIS
@@ -39,7 +39,8 @@ help" or "git bisect -h" to get a long usage description.
Basic bisect commands: start, bad, good Basic bisect commands: start, bad, good
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The way you use it is: Using the Linux kernel tree as an example, basic use of the bisect
command is as follows:
------------------------------------------------ ------------------------------------------------
$ git bisect start $ git bisect start
@@ -48,61 +49,63 @@ $ git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
# tested that was good # tested that was good
------------------------------------------------ ------------------------------------------------
When you give at least one bad and one good versions, it will bisect When you have specified at least one bad and one good version, the
the revision tree and say something like: command bisects the revision tree and outputs something similar to
the following:
------------------------------------------------ ------------------------------------------------
Bisecting: 675 revisions left to test after this Bisecting: 675 revisions left to test after this
------------------------------------------------ ------------------------------------------------
and check out the state in the middle. Now, compile that kernel, and The state in the middle of the set of revisions is then checked out.
boot it. Now, let's say that this booted kernel works fine, then just You would now compile that kernel and boot it. If the booted kernel
do works correctly, you would then issue the following command:
------------------------------------------------ ------------------------------------------------
$ git bisect good # this one is good $ git bisect good # this one is good
------------------------------------------------ ------------------------------------------------
which will now say The output of this command would be something similar to the following:
------------------------------------------------ ------------------------------------------------
Bisecting: 337 revisions left to test after this Bisecting: 337 revisions left to test after this
------------------------------------------------ ------------------------------------------------
and you continue along, compiling that one, testing it, and depending You keep repeating this process, compiling the tree, testing it, and
on whether it is good or bad, you say "git bisect good" or "git bisect depending on whether it is good or bad issuing the command "git bisect good"
bad", and ask for the next bisection. or "git bisect bad" to ask for the next bisection.
Until you have no more left, and you'll have been left with the first Eventually there will be no more revisions left to bisect, and you
bad kernel rev in "refs/bisect/bad". will have been left with the first bad kernel revision in "refs/bisect/bad".
Bisect reset Bisect reset
~~~~~~~~~~~~ ~~~~~~~~~~~~
Oh, and then after you want to reset to the original head, do a To return to the original head after a bisect session, issue the
following command:
------------------------------------------------ ------------------------------------------------
$ git bisect reset $ git bisect reset
------------------------------------------------ ------------------------------------------------
to get back to the original branch, instead of being on the bisection This resets the tree to the original branch instead of being on the
commit ("git bisect start" will do that for you too, actually: it will bisection commit ("git bisect start" will also do that, as it resets
reset the bisection state). the bisection state).
Bisect visualize Bisect visualize
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
During the bisection process, you can say To see the currently remaining suspects in 'gitk', issue the following
command during the bisection process:
------------ ------------
$ git bisect visualize $ git bisect visualize
------------ ------------
to see the currently remaining suspects in 'gitk'. `visualize` is a bit `view` may also be used as a synonym for `visualize`.
too long to type and `view` is provided as a synonym.
If 'DISPLAY' environment variable is not set, 'git log' is used If the 'DISPLAY' environment variable is not set, 'git log' is used
instead. You can even give command line options such as `-p` and instead. You can also give command line options such as `-p` and
`--stat`. `--stat`.
------------ ------------
@@ -112,57 +115,58 @@ $ git bisect view --stat
Bisect log and bisect replay Bisect log and bisect replay
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The good/bad input is logged, and After having marked revisions as good or bad, issue the following
command to show what has been done so far:
------------ ------------
$ git bisect log $ git bisect log
------------ ------------
shows what you have done so far. You can truncate its output somewhere If you discover that you made a mistake in specifying the status of a
and save it in a file, and run revision, you can save the output of this command to a file, edit it to
remove the incorrect entries, and then issue the following commands to
return to a corrected state:
------------ ------------
$ git bisect reset
$ git bisect replay that-file $ git bisect replay that-file
------------ ------------
if you find later you made a mistake telling good/bad about a Avoiding testing a commit
revision.
Avoiding to test a commit
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
If in a middle of bisect session, you know what the bisect suggested If, in the middle of a bisect session, you know that the next suggested
to try next is not a good one to test (e.g. the change the commit revision is not a good one to test (e.g. the change the commit
introduces is known not to work in your environment and you know it introduces is known not to work in your environment and you know it
does not have anything to do with the bug you are chasing), you may does not have anything to do with the bug you are chasing), you may
want to find a near-by commit and try that instead. want to find a nearby commit and try that instead.
It goes something like this: For example:
------------ ------------
$ git bisect good/bad # previous round was good/bad. $ git bisect good/bad # previous round was good or bad.
Bisecting: 337 revisions left to test after this Bisecting: 337 revisions left to test after this
$ git bisect visualize # oops, that is uninteresting. $ git bisect visualize # oops, that is uninteresting.
$ git reset --hard HEAD~3 # try 3 revs before what $ git reset --hard HEAD~3 # try 3 revisions before what
# was suggested # was suggested
------------ ------------
Then compile and test the one you chose to try. After that, tell Then compile and test the chosen revision, and afterwards mark
bisect what the result was as usual. the revision as good or bad in the usual manner.
Bisect skip Bisect skip
~~~~~~~~~~~~ ~~~~~~~~~~~~
Instead of choosing by yourself a nearby commit, you may just want git Instead of choosing by yourself a nearby commit, you can ask git
to do it for you using: to do it for you by issuing the command:
------------ ------------
$ git bisect skip # Current version cannot be tested $ git bisect skip # Current version cannot be tested
------------ ------------
But computing the commit to test may be slower afterwards and git may But computing the commit to test may be slower afterwards and git may
eventually not be able to tell the first bad among a bad and one or eventually not be able to tell the first bad commit among a bad commit
more "skip"ped commits. and one or more skipped commits.
You can even skip a range of commits, instead of just one commit, You can even skip a range of commits, instead of just one commit,
using the "'<commit1>'..'<commit2>'" notation. For example: using the "'<commit1>'..'<commit2>'" notation. For example:
@@ -171,33 +175,34 @@ using the "'<commit1>'..'<commit2>'" notation. For example:
$ git bisect skip v2.5..v2.6 $ git bisect skip v2.5..v2.6
------------ ------------
would mean that no commit between `v2.5` excluded and `v2.6` included This tells the bisect process that no commit after `v2.5`, up to and
can be tested. including `v2.6`, should be tested.
Note that if you want to also skip the first commit of a range you can Note that if you also want to skip the first commit of the range you
use something like: would issue the command:
------------ ------------
$ git bisect skip v2.5 v2.5..v2.6 $ git bisect skip v2.5 v2.5..v2.6
------------ ------------
and the commit pointed to by `v2.5` will be skipped too. This tells the bisect process that the commits between `v2.5` included
and `v2.6` included should be skipped.
Cutting down bisection by giving more parameters to bisect start Cutting down bisection by giving more parameters to bisect start
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can further cut down the number of trials if you know what part of You can further cut down the number of trials, if you know what part of
the tree is involved in the problem you are tracking down, by giving the tree is involved in the problem you are tracking down, by specifying
paths parameters when you say `bisect start`, like this: path parameters when issuing the `bisect start` command:
------------ ------------
$ git bisect start -- arch/i386 include/asm-i386 $ git bisect start -- arch/i386 include/asm-i386
------------ ------------
If you know beforehand more than one good commits, you can narrow the If you know beforehand more than one good commit, you can narrow the
bisect space down without doing the whole tree checkout every time you bisect space down by specifying all of the good commits immediately after
give good commits. You give the bad revision immediately after `start` the bad commit when issuing the `bisect start` command:
and then you give all the good revisions you have:
------------ ------------
$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 -- $ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
@@ -209,38 +214,38 @@ Bisect run
~~~~~~~~~~ ~~~~~~~~~~
If you have a script that can tell if the current source code is good If you have a script that can tell if the current source code is good
or bad, you can automatically bisect using: or bad, you can bisect by issuing the command:
------------ ------------
$ git bisect run my_script arguments $ git bisect run my_script arguments
------------ ------------
Note that the "run" script (`my_script` in the above example) should Note that the script (`my_script` in the above example) should
exit with code 0 in case the current source code is good. Exit with a exit with code 0 if the current source code is good, and exit with a
code between 1 and 127 (inclusive), except 125, if the current code between 1 and 127 (inclusive), except 125, if the current
source code is bad. source code is bad.
Any other exit code will abort the automatic bisect process. (A Any other exit code will abort the bisect process. It should be noted
program that does "exit(-1)" leaves $? = 255, see exit(3) manual page, that a program that terminates via "exit(-1)" leaves $? = 255, (see the
the value is chopped with "& 0377".) exit(3) manual page), as the value is chopped with "& 0377".
The special exit code 125 should be used when the current source code The special exit code 125 should be used when the current source code
cannot be tested. If the "run" script exits with this code, the current cannot be tested. If the script exits with this code, the current
revision will be skipped, see `git bisect skip` above. revision will be skipped (see `git bisect skip` above).
You may often find that during bisect you want to have near-constant You may often find that during a bisect session you want to have
tweaks (e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or temporary modifications (e.g. s/#define DEBUG 0/#define DEBUG 1/ in a
"revision that does not have this commit needs this patch applied to header file, or "revision that does not have this commit needs this
work around other problem this bisection is not interested in") patch applied to work around another problem this bisection is not
applied to the revision being tested. interested in") applied to the revision being tested.
To cope with such a situation, after the inner 'git bisect' finds the To cope with such a situation, after the inner 'git bisect' finds the
next revision to test, with the "run" script, you can apply that tweak next revision to test, the script can apply the patch
before compiling, run the real test, and after the test decides if the before compiling, run the real test, and afterwards decide if the
revision (possibly with the needed tweaks) passed the test, rewind the revision (possibly with the needed patch) passed the test and then
tree to the pristine state. Finally the "run" script can exit with rewind the tree to the pristine state. Finally the script should exit
the status of the real test to let the "git bisect run" command loop to with the status of the real test to let the "git bisect run" command loop
determine the outcome. determine the eventual outcome of the bisect session.
EXAMPLES EXAMPLES
-------- --------
@@ -264,39 +269,39 @@ $ git bisect run make test # "make test" builds and tests
------------ ------------
$ cat ~/test.sh $ cat ~/test.sh
#!/bin/sh #!/bin/sh
make || exit 125 # this "skip"s broken builds make || exit 125 # this skips broken builds
make test # "make test" runs the test suite make test # "make test" runs the test suite
$ git bisect start v1.3 v1.1 -- # v1.3 is bad, v1.1 is good $ git bisect start v1.3 v1.1 -- # v1.3 is bad, v1.1 is good
$ git bisect run ~/test.sh $ git bisect run ~/test.sh
------------ ------------
+ +
Here we use a "test.sh" custom script. In this script, if "make" Here we use a "test.sh" custom script. In this script, if "make"
fails, we "skip" the current commit. fails, we skip the current commit.
+ +
It's safer to use a custom script outside the repo to prevent It is safer to use a custom script outside the repository to prevent
interactions between the bisect, make and test processes and the interactions between the bisect, make and test processes and the
script. script.
+ +
And "make test" should "exit 0", if the test suite passes, and "make test" should "exit 0", if the test suite passes, and
"exit 1" (for example) otherwise. "exit 1" otherwise.
* Automatically bisect a broken test case: * Automatically bisect a broken test case:
+ +
------------ ------------
$ cat ~/test.sh $ cat ~/test.sh
#!/bin/sh #!/bin/sh
make || exit 125 # this "skip"s broken builds make || exit 125 # this skips broken builds
~/check_test_case.sh # does the test case passes ? ~/check_test_case.sh # does the test case passes ?
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10 $ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run ~/test.sh $ git bisect run ~/test.sh
------------ ------------
+ +
Here "check_test_case.sh" should "exit 0", if the test case passes, Here "check_test_case.sh" should "exit 0" if the test case passes,
and "exit 1" (for example) otherwise. and "exit 1" otherwise.
+ +
It's safer if both "test.sh" and "check_test_case.sh" scripts are It is safer if both "test.sh" and "check_test_case.sh" scripts are
outside the repo to prevent interactions between the bisect, make and outside the repository to prevent interactions between the bisect,
test processes and the scripts. make and test processes and the scripts.
* Automatically bisect a broken test suite: * Automatically bisect a broken test suite:
+ +

View File

@@ -18,9 +18,9 @@ DESCRIPTION
Annotates each line in the given file with information from the revision which Annotates each line in the given file with information from the revision which
last modified the line. Optionally, start annotating from the given revision. last modified the line. Optionally, start annotating from the given revision.
Also it can limit the range of lines annotated. The command can also limit the range of lines annotated.
This report doesn't tell you anything about lines which have been deleted or The report does not tell you anything about lines which have been deleted or
replaced; you need to use a tool such as 'git-diff' or the "pickaxe" replaced; you need to use a tool such as 'git-diff' or the "pickaxe"
interface briefly mentioned in the following paragraph. interface briefly mentioned in the following paragraph.
@@ -48,26 +48,26 @@ include::blame-options.txt[]
lines between files (see `-C`) and lines moved within a lines between files (see `-C`) and lines moved within a
file (see `-M`). The first number listed is the score. file (see `-M`). The first number listed is the score.
This is the number of alphanumeric characters detected This is the number of alphanumeric characters detected
to be moved between or within files. This must be above as having been moved between or within files. This must be above
a certain threshold for 'git-blame' to consider those lines a certain threshold for 'git-blame' to consider those lines
of code to have been moved. of code to have been moved.
-f:: -f::
--show-name:: --show-name::
Show filename in the original commit. By default Show the filename in the original commit. By default
filename is shown if there is any line that came from a the filename is shown if there is any line that came from a
file with different name, due to rename detection. file with a different name, due to rename detection.
-n:: -n::
--show-number:: --show-number::
Show line number in the original commit (Default: off). Show the line number in the original commit (Default: off).
-s:: -s::
Suppress author name and timestamp from the output. Suppress the author name and timestamp from the output.
-w:: -w::
Ignore whitespace when comparing parent's version and Ignore whitespace when comparing the parent's version and
child's to find where the lines came from. the child's to find where the lines came from.
THE PORCELAIN FORMAT THE PORCELAIN FORMAT
@@ -79,17 +79,17 @@ header at the minimum has the first line which has:
- 40-byte SHA-1 of the commit the line is attributed to; - 40-byte SHA-1 of the commit the line is attributed to;
- the line number of the line in the original file; - the line number of the line in the original file;
- the line number of the line in the final file; - the line number of the line in the final file;
- on a line that starts a group of line from a different - on a line that starts a group of lines from a different
commit than the previous one, the number of lines in this commit than the previous one, the number of lines in this
group. On subsequent lines this field is absent. group. On subsequent lines this field is absent.
This header line is followed by the following information This header line is followed by the following information
at least once for each commit: at least once for each commit:
- author name ("author"), email ("author-mail"), time - the author name ("author"), email ("author-mail"), time
("author-time"), and timezone ("author-tz"); similarly ("author-time"), and timezone ("author-tz"); similarly
for committer. for committer.
- filename in the commit the line is attributed to. - the filename in the commit that the line is attributed to.
- the first line of the commit log message ("summary"). - the first line of the commit log message ("summary").
The contents of the actual line is output after the above The contents of the actual line is output after the above
@@ -100,23 +100,23 @@ header elements later.
SPECIFYING RANGES SPECIFYING RANGES
----------------- -----------------
Unlike 'git-blame' and 'git-annotate' in older git, the extent Unlike 'git-blame' and 'git-annotate' in older versions of git, the extent
of annotation can be limited to both line ranges and revision of the annotation can be limited to both line ranges and revision
ranges. When you are interested in finding the origin for ranges. When you are interested in finding the origin for
ll. 40-60 for file `foo`, you can use `-L` option like these lines 40-60 for file `foo`, you can use the `-L` option like so
(they mean the same thing -- both ask for 21 lines starting at (they mean the same thing -- both ask for 21 lines starting at
line 40): line 40):
git blame -L 40,60 foo git blame -L 40,60 foo
git blame -L 40,+21 foo git blame -L 40,+21 foo
Also you can use regular expression to specify the line range. Also you can use a regular expression to specify the line range:
git blame -L '/^sub hello {/,/^}$/' foo git blame -L '/^sub hello {/,/^}$/' foo
would limit the annotation to the body of `hello` subroutine. which limits the annotation to the body of the `hello` subroutine.
When you are not interested in changes older than the version When you are not interested in changes older than version
v2.6.18, or changes older than 3 weeks, you can use revision v2.6.18, or changes older than 3 weeks, you can use revision
range specifiers similar to 'git-rev-list': range specifiers similar to 'git-rev-list':
@@ -129,7 +129,7 @@ commit v2.6.18 or the most recent commit that is more than 3
weeks old in the above example) are blamed for that range weeks old in the above example) are blamed for that range
boundary commit. boundary commit.
A particularly useful way is to see if an added file have lines A particularly useful way is to see if an added file has lines
created by copy-and-paste from existing files. Sometimes this created by copy-and-paste from existing files. Sometimes this
indicates that the developer was being sloppy and did not indicates that the developer was being sloppy and did not
refactor the code properly. You can first find the commit that refactor the code properly. You can first find the commit that
@@ -162,26 +162,26 @@ annotated.
+ +
Line numbers count from 1. Line numbers count from 1.
. The first time that commit shows up in the stream, it has various . The first time that a commit shows up in the stream, it has various
other information about it printed out with a one-word tag at the other information about it printed out with a one-word tag at the
beginning of each line about that "extended commit info" (author, beginning of each line describing the extra commit information (author,
email, committer, dates, summary etc). email, committer, dates, summary, etc.).
. Unlike Porcelain format, the filename information is always . Unlike the Porcelain format, the filename information is always
given and terminates the entry: given and terminates the entry:
"filename" <whitespace-quoted-filename-goes-here> "filename" <whitespace-quoted-filename-goes-here>
+ +
and thus it's really quite easy to parse for some line- and word-oriented and thus it is really quite easy to parse for some line- and word-oriented
parser (which should be quite natural for most scripting languages). parser (which should be quite natural for most scripting languages).
+ +
[NOTE] [NOTE]
For people who do parsing: to make it more robust, just ignore any For people who do parsing: to make it more robust, just ignore any
lines in between the first and last one ("<sha1>" and "filename" lines) lines between the first and last one ("<sha1>" and "filename" lines)
where you don't recognize the tag-words (or care about that particular where you do not recognize the tag words (or care about that particular
one) at the beginning of the "extended information" lines. That way, if one) at the beginning of the "extended information" lines. That way, if
there is ever added information (like the commit encoding or extended there is ever added information (like the commit encoding or extended
commit commentary), a blame viewer won't ever care. commit commentary), a blame viewer will not care.
MAPPING AUTHORS MAPPING AUTHORS

View File

@@ -18,19 +18,19 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
With no arguments, existing branches are listed, the current branch will With no arguments, existing branches are listed and the current branch will
be highlighted with an asterisk. Option `-r` causes the remote-tracking be highlighted with an asterisk. Option `-r` causes the remote-tracking
branches to be listed, and option `-a` shows both. branches to be listed, and option `-a` shows both.
With `--contains`, shows only the branches that contains the named commit With `--contains`, shows only the branches that contain the named commit
(in other words, the branches whose tip commits are descendant of the (in other words, the branches whose tip commits are descendants of the
named commit). With `--merged`, only branches merged into the named named commit). With `--merged`, only branches merged into the named
commit (i.e. the branches whose tip commits are reachable from the named commit (i.e. the branches whose tip commits are reachable from the named
commit) will be listed. With `--no-merged` only branches not merged into commit) will be listed. With `--no-merged` only branches not merged into
the named commit will be listed. Missing <commit> argument defaults to the named commit will be listed. If the <commit> argument is missing it
'HEAD' (i.e. the tip of the current branch). defaults to 'HEAD' (i.e. the tip of the current branch).
In its second form, a new branch named <branchname> will be created. In the command's second form, a new branch named <branchname> will be created.
It will start out with a head equal to the one given as <start-point>. It will start out with a head equal to the one given as <start-point>.
If no <start-point> is given, the branch will be created with a head If no <start-point> is given, the branch will be created with a head
equal to that of the currently checked out branch. equal to that of the currently checked out branch.
@@ -57,9 +57,9 @@ has a reflog then the reflog will also be deleted.
Use -r together with -d to delete remote-tracking branches. Note, that it Use -r together with -d to delete remote-tracking branches. Note, that it
only makes sense to delete remote-tracking branches if they no longer exist only makes sense to delete remote-tracking branches if they no longer exist
in remote repository or if 'git-fetch' was configured not to fetch in the remote repository or if 'git-fetch' was configured not to fetch
them again. See also 'prune' subcommand of linkgit:git-remote[1] for way to them again. See also the 'prune' subcommand of linkgit:git-remote[1] for a
clean up all obsolete remote-tracking branches. way to clean up all obsolete remote-tracking branches.
OPTIONS OPTIONS
@@ -76,14 +76,14 @@ OPTIONS
based sha1 expressions such as "<branchname>@\{yesterday}". based sha1 expressions such as "<branchname>@\{yesterday}".
-f:: -f::
Force the creation of a new branch even if it means deleting Reset <branchname> to <startpoint> if <branchname> exists
a branch that already exists with the same name. already. Without `-f` 'git-branch' refuses to change an existing branch.
-m:: -m::
Move/rename a branch and the corresponding reflog. Move/rename a branch and the corresponding reflog.
-M:: -M::
Move/rename a branch even if the new branchname already exists. Move/rename a branch even if the new branch name already exists.
--color:: --color::
Color branches to highlight current, local, and remote branches. Color branches to highlight current, local, and remote branches.
@@ -103,17 +103,17 @@ OPTIONS
Show sha1 and commit subject line for each head. Show sha1 and commit subject line for each head.
--abbrev=<length>:: --abbrev=<length>::
Alter minimum display length for sha1 in output listing, Alter the sha1's minimum display length in the output listing.
default value is 7. The default value is 7.
--no-abbrev:: --no-abbrev::
Display the full sha1s in output listing rather than abbreviating them. Display the full sha1s in the output listing rather than abbreviating them.
--track:: --track::
When creating a new branch, set up configuration so that 'git-pull' When creating a new branch, set up the configuration so that 'git-pull'
will automatically retrieve data from the start point, which must be will automatically retrieve data from the start point, which must be
a branch. Use this if you always pull from the same upstream branch a branch. Use this if you always pull from the same upstream branch
into the new branch, and if you don't want to use "git pull into the new branch, and if you do not want to use "git pull
<repository> <refspec>" explicitly. This behavior is the default <repository> <refspec>" explicitly. This behavior is the default
when the start point is a remote branch. Set the when the start point is a remote branch. Set the
branch.autosetupmerge configuration variable to `false` if you want branch.autosetupmerge configuration variable to `false` if you want
@@ -149,13 +149,13 @@ OPTIONS
<newbranch>:: <newbranch>::
The new name for an existing branch. The same restrictions as for The new name for an existing branch. The same restrictions as for
<branchname> applies. <branchname> apply.
Examples Examples
-------- --------
Start development off of a known tag:: Start development from a known tag::
+ +
------------ ------------
$ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6 $ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6
@@ -167,7 +167,7 @@ $ git checkout my2.6.14
<1> This step and the next one could be combined into a single step with <1> This step and the next one could be combined into a single step with
"checkout -b my2.6.14 v2.6.14". "checkout -b my2.6.14 v2.6.14".
Delete unneeded branch:: Delete an unneeded branch::
+ +
------------ ------------
$ git clone git://git.kernel.org/.../git.git my.git $ git clone git://git.kernel.org/.../git.git my.git
@@ -176,21 +176,21 @@ $ git branch -d -r origin/todo origin/html origin/man <1>
$ git branch -D test <2> $ git branch -D test <2>
------------ ------------
+ +
<1> Delete remote-tracking branches "todo", "html", "man". Next 'fetch' or <1> Delete the remote-tracking branches "todo", "html" and "man". The next
'pull' will create them again unless you configure them not to. See 'fetch' or 'pull' will create them again unless you configure them not to.
linkgit:git-fetch[1]. See linkgit:git-fetch[1].
<2> Delete "test" branch even if the "master" branch (or whichever branch is <2> Delete the "test" branch even if the "master" branch (or whichever branch
currently checked out) does not have all commits from test branch. is currently checked out) does not have all commits from the test branch.
Notes Notes
----- -----
If you are creating a branch that you want to immediately checkout, it's If you are creating a branch that you want to checkout immediately, it is
easier to use the git checkout command with its `-b` option to create easier to use the git checkout command with its `-b` option to create
a branch and check it out with a single command. a branch and check it out with a single command.
The options `--contains`, `--merged` and `--no-merged` serves three related The options `--contains`, `--merged` and `--no-merged` serve three related
but different purposes: but different purposes:
- `--contains <commit>` is used to find all branches which will need - `--contains <commit>` is used to find all branches which will need

View File

@@ -19,13 +19,13 @@ DESCRIPTION
Some workflows require that one or more branches of development on one Some workflows require that one or more branches of development on one
machine be replicated on another machine, but the two machines cannot machine be replicated on another machine, but the two machines cannot
be directly connected so the interactive git protocols (git, ssh, be directly connected, and therefore the interactive git protocols (git,
rsync, http) cannot be used. This command provides support for ssh, rsync, http) cannot be used. This command provides support for
'git-fetch' and 'git-pull' to operate by packaging objects and references 'git-fetch' and 'git-pull' to operate by packaging objects and references
in an archive at the originating machine, then importing those into in an archive at the originating machine, then importing those into
another repository using 'git-fetch' and 'git-pull' another repository using 'git-fetch' and 'git-pull'
after moving the archive by some means (i.e., by sneakernet). As no after moving the archive by some means (i.e., by sneakernet). As no
direct connection between repositories exists, the user must specify a direct connection between the repositories exists, the user must specify a
basis for the bundle that is held by the destination repository: the basis for the bundle that is held by the destination repository: the
bundle assumes that all objects in the basis are already in the bundle assumes that all objects in the basis are already in the
destination repository. destination repository.
@@ -43,7 +43,7 @@ verify <file>::
bundle format itself as well as checking that the prerequisite bundle format itself as well as checking that the prerequisite
commits exist and are fully linked in the current repository. commits exist and are fully linked in the current repository.
'git-bundle' prints a list of missing commits, if any, and exits 'git-bundle' prints a list of missing commits, if any, and exits
with non-zero status. with a non-zero status.
list-heads <file>:: list-heads <file>::
Lists the references defined in the bundle. If followed by a Lists the references defined in the bundle. If followed by a
@@ -53,14 +53,14 @@ list-heads <file>::
unbundle <file>:: unbundle <file>::
Passes the objects in the bundle to 'git-index-pack' Passes the objects in the bundle to 'git-index-pack'
for storage in the repository, then prints the names of all for storage in the repository, then prints the names of all
defined references. If a reflist is given, only references defined references. If a list of references is given, only
matching those in the given list are printed. This command is references matching those in the list are printed. This command is
really plumbing, intended to be called only by 'git-fetch'. really plumbing, intended to be called only by 'git-fetch'.
[git-rev-list-args...]:: [git-rev-list-args...]::
A list of arguments, acceptable to 'git-rev-parse' and A list of arguments, acceptable to 'git-rev-parse' and
'git-rev-list', that specify the specific objects and references 'git-rev-list', that specifies the specific objects and references
to transport. For example, "master~10..master" causes the to transport. For example, `master\~10..master` causes the
current master reference to be packaged along with all objects current master reference to be packaged along with all objects
added since its 10th ancestor commit. There is no explicit added since its 10th ancestor commit. There is no explicit
limit to the number of references and objects that may be limit to the number of references and objects that may be
@@ -71,24 +71,24 @@ unbundle <file>::
A list of references used to limit the references reported as A list of references used to limit the references reported as
available. This is principally of use to 'git-fetch', which available. This is principally of use to 'git-fetch', which
expects to receive only those references asked for and not expects to receive only those references asked for and not
necessarily everything in the pack (in this case, 'git-bundle' is necessarily everything in the pack (in this case, 'git-bundle' acts
acting like 'git-fetch-pack'). like 'git-fetch-pack').
SPECIFYING REFERENCES SPECIFYING REFERENCES
--------------------- ---------------------
'git-bundle' will only package references that are shown by 'git-bundle' will only package references that are shown by
'git-show-ref': this includes heads, tags, and remote heads. References 'git-show-ref': this includes heads, tags, and remote heads. References
such as master~1 cannot be packaged, but are perfectly suitable for such as `master\~1` cannot be packaged, but are perfectly suitable for
defining the basis. More than one reference may be packaged, and more defining the basis. More than one reference may be packaged, and more
than one basis can be specified. The objects packaged are those not than one basis can be specified. The objects packaged are those not
contained in the union of the given bases. Each basis can be contained in the union of the given bases. Each basis can be
specified explicitly (e.g., ^master~10), or implicitly (e.g., specified explicitly (e.g. `^master\~10`), or implicitly (e.g.
master~10..master, --since=10.days.ago master). `master\~10..master`, `--since=10.days.ago master`).
It is very important that the basis used be held by the destination. It is very important that the basis used be held by the destination.
It is okay to err on the side of conservatism, causing the bundle file It is okay to err on the side of caution, causing the bundle file
to contain objects already in the destination as these are ignored to contain objects already in the destination, as these are ignored
when unpacking at the destination. when unpacking at the destination.
EXAMPLE EXAMPLE
@@ -97,13 +97,13 @@ EXAMPLE
Assume you want to transfer the history from a repository R1 on machine A Assume you want to transfer the history from a repository R1 on machine A
to another repository R2 on machine B. to another repository R2 on machine B.
For whatever reason, direct connection between A and B is not allowed, For whatever reason, direct connection between A and B is not allowed,
but we can move data from A to B via some mechanism (CD, email, etc). but we can move data from A to B via some mechanism (CD, email, etc.).
We want to update R2 with developments made on branch master in R1. We want to update R2 with development made on the branch master in R1.
To bootstrap the process, you can first create a bundle that doesn't have To bootstrap the process, you can first create a bundle that does not have
any basis. You can use a tag to remember up to what commit you sent out any basis. You can use a tag to remember up to what commit you last
in order to make it easy to later update the other repository with processed, in order to make it easy to later update the other repository
incremental bundle, with an incremental bundle:
---------------- ----------------
machineA$ cd R1 machineA$ cd R1
@@ -111,17 +111,17 @@ machineA$ git bundle create file.bundle master
machineA$ git tag -f lastR2bundle master machineA$ git tag -f lastR2bundle master
---------------- ----------------
Then you sneakernet file.bundle to the target machine B. Because you don't Then you transfer file.bundle to the target machine B. If you are creating
have to have any object to extract objects from such a bundle, not only the repository on machine B, then you can clone from the bundle as if it
you can fetch/pull from a bundle, you can clone from it as if it was a were a remote repository instead of creating an empty repository and then
remote repository. pulling or fetching objects from the bundle:
---------------- ----------------
machineB$ git clone /home/me/tmp/file.bundle R2 machineB$ git clone /home/me/tmp/file.bundle R2
---------------- ----------------
This will define a remote called "origin" in the resulting repository that This will define a remote called "origin" in the resulting repository that
lets you fetch and pull from the bundle. $GIT_DIR/config file in R2 may lets you fetch and pull from the bundle. The $GIT_DIR/config file in R2 will
have an entry like this: have an entry like this:
------------------------ ------------------------
@@ -130,12 +130,12 @@ have an entry like this:
fetch = refs/heads/*:refs/remotes/origin/* fetch = refs/heads/*:refs/remotes/origin/*
------------------------ ------------------------
You can fetch/pull to update the resulting mine.git repository after To update the resulting mine.git repository, you can fetch or pull after
replacing the bundle you store at /home/me/tmp/file.bundle with incremental replacing the bundle stored at /home/me/tmp/file.bundle with incremental
updates from here on. updates.
After working more in the original repository, you can create an After working some more in the original repository, you can create an
incremental bundle to update the other: incremental bundle to update the other repository:
---------------- ----------------
machineA$ cd R1 machineA$ cd R1
@@ -143,8 +143,8 @@ machineA$ git bundle create file.bundle lastR2bundle..master
machineA$ git tag -f lastR2bundle master machineA$ git tag -f lastR2bundle master
---------------- ----------------
and sneakernet it to the other machine to replace /home/me/tmp/file.bundle, You then transfer the bundle to the other machine to replace
and pull from it. /home/me/tmp/file.bundle, and pull from it.
---------------- ----------------
machineB$ cd R2 machineB$ cd R2
@@ -152,49 +152,49 @@ machineB$ git pull
---------------- ----------------
If you know up to what commit the intended recipient repository should If you know up to what commit the intended recipient repository should
have the necessary objects for, you can use that knowledge to specify the have the necessary objects, you can use that knowledge to specify the
basis, giving a cut-off point to limit the revisions and objects that go basis, giving a cut-off point to limit the revisions and objects that go
in the resulting bundle. The previous example used lastR2bundle tag in the resulting bundle. The previous example used lastR2bundle tag
for this purpose, but you can use other options you would give to for this purpose, but you can use any other options that you would give to
the linkgit:git-log[1] command. Here are more examples: the linkgit:git-log[1] command. Here are more examples:
You can use a tag that is present in both. You can use a tag that is present in both:
---------------- ----------------
$ git bundle create mybundle v1.0.0..master $ git bundle create mybundle v1.0.0..master
---------------- ----------------
You can use a basis based on time. You can use a basis based on time:
---------------- ----------------
$ git bundle create mybundle --since=10.days master $ git bundle create mybundle --since=10.days master
---------------- ----------------
Or you can use the number of commits. You can use the number of commits:
---------------- ----------------
$ git bundle create mybundle -10 master $ git bundle create mybundle -10 master
---------------- ----------------
You can run `git-bundle verify` to see if you can extract from a bundle You can run `git-bundle verify` to see if you can extract from a bundle
that was created with a basis. that was created with a basis:
---------------- ----------------
$ git bundle verify mybundle $ git bundle verify mybundle
---------------- ----------------
This will list what commits you must have in order to extract from the This will list what commits you must have in order to extract from the
bundle and will error out if you don't have them. bundle and will error out if you do not have them.
A bundle from a recipient repository's point of view is just like a A bundle from a recipient repository's point of view is just like a
regular repository it fetches/pulls from. You can for example map regular repository which it fetches or pulls from. You can, for example, map
refs, like this example, when fetching: references when fetching:
---------------- ----------------
$ git fetch mybundle master:localRef $ git fetch mybundle master:localRef
---------------- ----------------
Or see what refs it offers. You can also see what references it offers.
---------------- ----------------
$ git ls-remote mybundle $ git ls-remote mybundle

View File

@@ -3,7 +3,7 @@ git-cat-file(1)
NAME NAME
---- ----
git-cat-file - Provide content or type/size information for repository objects git-cat-file - Provide content or type and size information for repository objects
SYNOPSIS SYNOPSIS
@@ -14,19 +14,19 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
In the first form, provides content or type of objects in the repository. The In its first form, the command provides the content or the type of an object in
type is required unless '-t' or '-p' is used to find the object type, or '-s' the repository. The type is required unless '-t' or '-p' is used to find the
is used to find the object size. object type, or '-s' is used to find the object size.
In the second form, a list of object (separated by LFs) is provided on stdin, In the second form, a list of objects (separated by linefeeds) is provided on
and the SHA1, type, and size of each object is printed on stdout. stdin, and the SHA1, type, and size of each object is printed on stdout.
OPTIONS OPTIONS
------- -------
<object>:: <object>::
The name of the object to show. The name of the object to show.
For a more complete list of ways to spell object names, see For a more complete list of ways to spell object names, see
"SPECIFYING REVISIONS" section in linkgit:git-rev-parse[1]. the "SPECIFYING REVISIONS" section in linkgit:git-rev-parse[1].
-t:: -t::
Instead of the content, show the object type identified by Instead of the content, show the object type identified by
@@ -56,8 +56,8 @@ OPTIONS
stdin. May not be combined with any other options or arguments. stdin. May not be combined with any other options or arguments.
--batch-check:: --batch-check::
Print the SHA1, type, and size of each object provided on stdin. May not be Print the SHA1, type, and size of each object provided on stdin. May not
combined with any other options or arguments. be combined with any other options or arguments.
OUTPUT OUTPUT
------ ------

View File

@@ -14,7 +14,7 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
For every pathname, this command will list if each attr is 'unspecified', For every pathname, this command will list if each attribute is 'unspecified',
'set', or 'unset' as a gitattribute on that pathname. 'set', or 'unset' as a gitattribute on that pathname.
OPTIONS OPTIONS
@@ -23,11 +23,11 @@ OPTIONS
Read file names from stdin instead of from the command-line. Read file names from stdin instead of from the command-line.
-z:: -z::
Only meaningful with `--stdin`; paths are separated with Only meaningful with `--stdin`; paths are separated with a
NUL character instead of LF. NUL character instead of a linefeed character.
\--:: \--::
Interpret all preceding arguments as attributes, and all following Interpret all preceding arguments as attributes and all following
arguments as path names. If not supplied, only the first argument will arguments as path names. If not supplied, only the first argument will
be treated as an attribute. be treated as an attribute.
@@ -37,12 +37,12 @@ OUTPUT
The output is of the form: The output is of the form:
<path> COLON SP <attribute> COLON SP <info> LF <path> COLON SP <attribute> COLON SP <info> LF
Where <path> is the path of a file being queried, <attribute> is an attribute <path> is the path of a file being queried, <attribute> is an attribute
being queried and <info> can be either: being queried and <info> can be either:
'unspecified';; when the attribute is not defined for the path. 'unspecified';; when the attribute is not defined for the path.
'unset';; when the attribute is defined to false. 'unset';; when the attribute is defined as false.
'set';; when the attribute is defined to true. 'set';; when the attribute is defined as true.
<value>;; when a value has been assigned to the attribute. <value>;; when a value has been assigned to the attribute.
EXAMPLES EXAMPLES
@@ -69,7 +69,7 @@ org/example/MyClass.java: diff: java
org/example/MyClass.java: myAttr: set org/example/MyClass.java: myAttr: set
--------------- ---------------
* Listing attribute for multiple files: * Listing an attribute for multiple files:
--------------- ---------------
$ git check-attr myAttr -- org/example/MyClass.java org/example/NoMyAttr.java $ git check-attr myAttr -- org/example/MyClass.java org/example/NoMyAttr.java
org/example/MyClass.java: myAttr: set org/example/MyClass.java: myAttr: set

View File

@@ -3,7 +3,7 @@ git-check-ref-format(1)
NAME NAME
---- ----
git-check-ref-format - Make sure ref name is well formed git-check-ref-format - Ensures that a reference name is well formed
SYNOPSIS SYNOPSIS
-------- --------
@@ -11,40 +11,40 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
Checks if a given 'refname' is acceptable, and exits non-zero if Checks if a given 'refname' is acceptable, and exits with a non-zero
it is not. status if it is not.
A reference is used in git to specify branches and tags. A A reference is used in git to specify branches and tags. A
branch head is stored under `$GIT_DIR/refs/heads` directory, and branch head is stored under the `$GIT_DIR/refs/heads` directory, and
a tag is stored under `$GIT_DIR/refs/tags` directory. git a tag is stored under the `$GIT_DIR/refs/tags` directory. git
imposes the following rules on how refs are named: imposes the following rules on how references are named:
. It can include slash `/` for hierarchical (directory) . They can include slash `/` for hierarchical (directory)
grouping, but no slash-separated component can begin with a grouping, but no slash-separated component can begin with a
dot `.`; dot `.`.
. It cannot have two consecutive dots `..` anywhere; . They cannot have two consecutive dots `..` anywhere.
. It cannot have ASCII control character (i.e. bytes whose . They cannot have ASCII control characters (i.e. bytes whose
values are lower than \040, or \177 `DEL`), space, tilde `~`, values are lower than \040, or \177 `DEL`), space, tilde `~`,
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`, caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
or open bracket `[` anywhere; or open bracket `[` anywhere.
. It cannot end with a slash `/`. . They cannot end with a slash `/`.
These rules makes it easy for shell script based tools to parse These rules make it easy for shell script based tools to parse
refnames, pathname expansion by the shell when a refname is used reference names, pathname expansion by the shell when a reference name is used
unquoted (by mistake), and also avoids ambiguities in certain unquoted (by mistake), and also avoids ambiguities in certain
refname expressions (see linkgit:git-rev-parse[1]). Namely: reference name expressions (see linkgit:git-rev-parse[1]):
. double-dot `..` are often used as in `ref1..ref2`, and in some . A double-dot `..` is often used as in `ref1..ref2`, and in some
context this notation means `{caret}ref1 ref2` (i.e. not in contexts this notation means `{caret}ref1 ref2` (i.e. not in
ref1 and in ref2). `ref1` and in `ref2`).
. tilde `~` and caret `{caret}` are used to introduce postfix . A tilde `~` and caret `{caret}` are used to introduce the postfix
'nth parent' and 'peel onion' operation. 'nth parent' and 'peel onion' operation.
. colon `:` is used as in `srcref:dstref` to mean "use srcref\'s . A colon `:` is used as in `srcref:dstref` to mean "use srcref\'s
value and store it in dstref" in fetch and push operations. value and store it in dstref" in fetch and push operations.
It may also be used to select a specific object such as with It may also be used to select a specific object such as with
'git-cat-file': "git cat-file blob v1.3.3:refs.c". 'git-cat-file': "git cat-file blob v1.3.3:refs.c".

View File

@@ -133,9 +133,9 @@ the conflicted merge in the specified paths.
When this parameter names a non-branch (but still a valid commit object), When this parameter names a non-branch (but still a valid commit object),
your HEAD becomes 'detached'. your HEAD becomes 'detached'.
+ +
As a special case, the "`@\{-N\}`" syntax for the N-th last branch As a special case, the `"@\{-N\}"` syntax for the N-th last branch
checks out the branch (instead of detaching). You may also specify checks out the branch (instead of detaching). You may also specify
"`-`" which is synonymous with "`@\{-1\}`". `-` which is synonymous with `"@\{-1\}"`.
Detached HEAD Detached HEAD

View File

@@ -117,7 +117,7 @@ then the cloned repository will become corrupt.
--origin <name>:: --origin <name>::
-o <name>:: -o <name>::
Instead of using the remote name 'origin' to keep track Instead of using the remote name 'origin' to keep track
of the upstream repository, use <name> instead. of the upstream repository, use <name>.
--upload-pack <upload-pack>:: --upload-pack <upload-pack>::
-u <upload-pack>:: -u <upload-pack>::

View File

@@ -11,7 +11,7 @@ SYNOPSIS
[verse] [verse]
'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]] 'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]]
'git config' [<file-option>] [type] --add name value 'git config' [<file-option>] [type] --add name value
'git config' [<file-option>] [type] --replace-all name [value [value_regex]] 'git config' [<file-option>] [type] --replace-all name value [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get name [value_regex] 'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex] 'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex] 'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]

View File

@@ -24,6 +24,9 @@ repository, or incrementally import into an existing one.
Splitting the CVS log into patch sets is done by 'cvsps'. Splitting the CVS log into patch sets is done by 'cvsps'.
At least version 2.1 is required. At least version 2.1 is required.
*WARNING:* for certain situations the import leads to incorrect results.
Please see the section <<issues,ISSUES>> for further reference.
You should *never* do any work of your own on the branches that are You should *never* do any work of your own on the branches that are
created by 'git-cvsimport'. By default initial import will create and populate a created by 'git-cvsimport'. By default initial import will create and populate a
"master" branch from the CVS repository's main branch which you're free "master" branch from the CVS repository's main branch which you're free
@@ -62,7 +65,7 @@ OPTIONS
-r <remote>:: -r <remote>::
The git remote to import this CVS repository into. The git remote to import this CVS repository into.
Moves all CVS branches into remotes/<remote>/<branch> Moves all CVS branches into remotes/<remote>/<branch>
akin to the 'git-clone' "--use-separate-remote" option. akin to the way 'git-clone' uses 'origin' by default.
-o <branch-for-HEAD>:: -o <branch-for-HEAD>::
When no remote is specified (via -r) the 'HEAD' branch When no remote is specified (via -r) the 'HEAD' branch
@@ -164,6 +167,39 @@ If '-v' is specified, the script reports what it is doing.
Otherwise, success is indicated the Unix way, i.e. by simply exiting with Otherwise, success is indicated the Unix way, i.e. by simply exiting with
a zero exit status. a zero exit status.
[[issues]]
ISSUES
------
Problems related to timestamps:
* If timestamps of commits in the cvs repository are not stable enough
to be used for ordering commits changes may show up in the wrong
order.
* If any files were ever "cvs import"ed more than once (e.g., import of
more than one vendor release) the HEAD contains the wrong content.
* If the timestamp order of different files cross the revision order
within the commit matching time window the order of commits may be
wrong.
Problems related to branches:
* Branches on which no commits have been made are not imported.
* All files from the branching point are added to a branch even if
never added in cvs.
* This applies to files added to the source branch *after* a daughter
branch was created: if previously no commit was made on the daughter
branch they will erroneously be added to the daughter branch in git.
Problems related to tags:
* Multiple tags on the same revision are not imported.
If you suspect that any of these issues may apply to the repository you
want to import consider using these alternative tools which proved to be
more stable in practise:
* cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
* parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
Author Author
------ ------

View File

@@ -40,15 +40,11 @@ There are two ways to specify which commits to operate on.
REVISIONS" section in linkgit:git-rev-parse[1]) means the REVISIONS" section in linkgit:git-rev-parse[1]) means the
commits in the specified range. commits in the specified range.
A single commit, when interpreted as a <revision range> The first rule takes precedence in the case of a single <commit>. To
expression, means "everything that leads to that commit", but apply the second rule, i.e., format everything since the beginning of
if you write 'git format-patch <commit>', the previous rule history up until <commit>, use the '\--root' option: "git format-patch
applies to that command line and you do not get "everything \--root <commit>". If you want to format only <commit> itself, you
since the beginning of the time". If you want to format can do this with "git format-patch -1 <commit>".
everything since project inception to one commit, say "git
format-patch \--root <commit>" to make it clear that it is the
latter case. If you want to format a single commit, you can do
this with "git format-patch -1 <commit>".
By default, each output file is numbered sequentially from 1, and uses the By default, each output file is numbered sequentially from 1, and uses the
first line of the commit message (massaged for pathname safety) as first line of the commit message (massaged for pathname safety) as
@@ -97,7 +93,6 @@ include::diff-options.txt[]
--numbered-files:: --numbered-files::
Output file names will be a simple number sequence Output file names will be a simple number sequence
without the default first line of the commit appended. without the default first line of the commit appended.
Mutually exclusive with the --stdout option.
-k:: -k::
--keep-subject:: --keep-subject::
@@ -162,6 +157,11 @@ if that is not set.
Add a "Cc:" header to the email headers. This is in addition Add a "Cc:" header to the email headers. This is in addition
to any configured headers, and may be used multiple times. to any configured headers, and may be used multiple times.
--add-header=<header>::
Add an arbitrary header to the email headers. This is in addition
to any configured headers, and may be used multiple times.
For example, --add-header="Organization: git-foo"
--cover-letter:: --cover-letter::
In addition to the patches, generate a cover letter file In addition to the patches, generate a cover letter file
containing the shortlog and the overall diffstat. You can containing the shortlog and the overall diffstat. You can
@@ -183,6 +183,13 @@ not add any suffix.
applied. By default the contents of changes in those files are applied. By default the contents of changes in those files are
encoded in the patch. encoded in the patch.
--root::
Treat the revision argument as a <revision range>, even if it
is just a single commit (that would normally be treated as a
<since>). Note that root commits included in the specified
range are always formatted as creation patches, independently
of this flag.
CONFIGURATION CONFIGURATION
------------- -------------
You can specify extra mail header lines to be added to each message You can specify extra mail header lines to be added to each message

View File

@@ -17,6 +17,7 @@ SYNOPSIS
[-l | --files-with-matches] [-L | --files-without-match] [-l | --files-with-matches] [-L | --files-without-match]
[-z | --null] [-z | --null]
[-c | --count] [--all-match] [-c | --count] [--all-match]
[--color | --no-color]
[-A <post-context>] [-B <pre-context>] [-C <context>] [-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e] <pattern> [-f <file>] [-e] <pattern>
[--and|--or|--not|(|)|-e <pattern>...] [<tree>...] [--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
@@ -105,6 +106,13 @@ OPTIONS
Instead of showing every matched line, show the number of Instead of showing every matched line, show the number of
lines that match. lines that match.
--color::
Show colored matches.
--no-color::
Turn off match highlighting, even when the configuration file
gives the default to color output.
-[ABC] <context>:: -[ABC] <context>::
Show `context` trailing (`A` -- after), or leading (`B` Show `context` trailing (`A` -- after), or leading (`B`
-- before), or both (`C` -- context) lines, and place a -- before), or both (`C` -- context) lines, and place a

View File

@@ -40,8 +40,8 @@ include::merge-options.txt[]
include::merge-strategies.txt[] include::merge-strategies.txt[]
If you tried a merge which resulted in a complex conflicts and If you tried a merge which resulted in complex conflicts and
would want to start over, you can recover with 'git-reset'. want to start over, you can recover with 'git-reset'.
CONFIGURATION CONFIGURATION
------------- -------------
@@ -146,7 +146,7 @@ And here is another line that is cleanly resolved or unmodified.
------------ ------------
The area where a pair of conflicting changes happened is marked with markers The area where a pair of conflicting changes happened is marked with markers
"`<<<<<<<`", "`=======`", and "`>>>>>>>`". The part before the "`=======`" `<<<<<<<`, `=======`, and `>>>>>>>`. The part before the `=======`
is typically your side, and the part afterwards is typically their side. is typically your side, and the part afterwards is typically their side.
The default format does not show what the original said in the conflicting The default format does not show what the original said in the conflicting
@@ -173,8 +173,8 @@ Git makes conflict resolution easy.
And here is another line that is cleanly resolved or unmodified. And here is another line that is cleanly resolved or unmodified.
------------ ------------
In addition to the "`<<<<<<<`", "`=======`", and "`>>>>>>>`" markers, it uses In addition to the `<<<<<<<`, `=======`, and `>>>>>>>` markers, it uses
another "`|||||||`" marker that is followed by the original text. You can another `|||||||` marker that is followed by the original text. You can
tell that the original just stated a fact, and your side simply gave in to tell that the original just stated a fact, and your side simply gave in to
that statement and gave up, while the other side tried to have a more that statement and gave up, while the other side tried to have a more
positive attitude. You can sometimes come up with a better resolution by positive attitude. You can sometimes come up with a better resolution by

View File

@@ -20,7 +20,7 @@ IOW, you can use this thing to look for likely duplicate commits.
When dealing with 'git-diff-tree' output, it takes advantage of When dealing with 'git-diff-tree' output, it takes advantage of
the fact that the patch is prefixed with the object name of the the fact that the patch is prefixed with the object name of the
commit, and outputs two 40-byte hexadecimal string. The first commit, and outputs two 40-byte hexadecimal strings. The first
string is the patch ID, and the second string is the commit ID. string is the patch ID, and the second string is the commit ID.
This can be used to make a mapping from patch ID to commit ID. This can be used to make a mapping from patch ID to commit ID.

View File

@@ -24,8 +24,8 @@ every time you push into it, by setting up 'hooks' there. See
documentation for linkgit:git-receive-pack[1]. documentation for linkgit:git-receive-pack[1].
OPTIONS OPTIONS[[OPTIONS]]
------- ------------------
<repository>:: <repository>::
The "remote" repository that is destination of a push The "remote" repository that is destination of a push
operation. This parameter can be either a URL operation. This parameter can be either a URL
@@ -187,6 +187,28 @@ reason::
Examples Examples
-------- --------
git push::
Works like `git push <remote>`, where <remote> is the
current branch's remote (or `origin`, if no remote is
configured for the current branch).
git push origin::
Without additional configuration, works like
`git push origin :`.
+
The default behavior of this command when no <refspec> is given can be
configured by setting the `push` option of the remote.
+
For example, to default to pushing only the current branch to `origin`
use `git config remote.origin.push HEAD`. Any valid <refspec> (like
the ones in the examples below) can be configured as the default for
`git push origin`.
git push origin :::
Push "matching" branches to `origin`. See
<refspec> in the <<OPTIONS,OPTIONS>> section above for a
description of "matching" branches.
git push origin master:: git push origin master::
Find a ref that matches `master` in the source repository Find a ref that matches `master` in the source repository
(most likely, it would find `refs/heads/master`), and update (most likely, it would find `refs/heads/master`), and update

View File

@@ -258,11 +258,23 @@ OPTIONS
context exist they all must match. By default no context is context exist they all must match. By default no context is
ever ignored. ever ignored.
-f::
--force-rebase::
Force the rebase even if the current branch is a descendant
of the commit you are rebasing onto. Normally the command will
exit with the message "Current branch is up to date" in such a
situation.
--whitespace=<option>:: --whitespace=<option>::
This flag is passed to the 'git-apply' program This flag is passed to the 'git-apply' program
(see linkgit:git-apply[1]) that applies the patch. (see linkgit:git-apply[1]) that applies the patch.
Incompatible with the --interactive option. Incompatible with the --interactive option.
--committer-date-is-author-date::
--ignore-date::
These flags are passed to 'git-am' to easily change the dates
of the rebased commits (see linkgit:git-am[1]).
-i:: -i::
--interactive:: --interactive::
Make a list of the commits which are about to be rebased. Let the Make a list of the commits which are about to be rebased. Let the

View File

@@ -13,6 +13,7 @@ SYNOPSIS
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url> 'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
'git remote rename' <old> <new> 'git remote rename' <old> <new>
'git remote rm' <name> 'git remote rm' <name>
'git remote set-head' <name> [-a | -d | <branch>]
'git remote show' [-n] <name> 'git remote show' [-n] <name>
'git remote prune' [-n | --dry-run] <name> 'git remote prune' [-n | --dry-run] <name>
'git remote update' [group] 'git remote update' [group]
@@ -53,8 +54,7 @@ is created. You can give more than one `-t <branch>` to track
multiple branches without grabbing all branches. multiple branches without grabbing all branches.
+ +
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
up to point at remote's `<master>` branch instead of whatever up to point at remote's `<master>` branch. See also the set-head command.
branch the `HEAD` at the remote repository actually points at.
+ +
In mirror mode, enabled with `\--mirror`, the refs will not be stored In mirror mode, enabled with `\--mirror`, the refs will not be stored
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
@@ -76,6 +76,30 @@ the configuration file format.
Remove the remote named <name>. All remote tracking branches and Remove the remote named <name>. All remote tracking branches and
configuration settings for the remote are removed. configuration settings for the remote are removed.
'set-head'::
Sets or deletes the default branch (`$GIT_DIR/remotes/<name>/HEAD`) for
the named remote. Having a default branch for a remote is not required,
but allows the name of the remote to be specified in lieu of a specific
branch. For example, if the default branch for `origin` is set to
`master`, then `origin` may be specified wherever you would normally
specify `origin/master`.
+
With `-d`, `$GIT_DIR/remotes/<name>/HEAD` is deleted.
+
With `-a`, the remote is queried to determine its `HEAD`, then
`$GIT_DIR/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
`$GIT_DIR/refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
only work if `refs/remotes/origin/next` already exists; if not it must be
fetched first.
+
Use `<branch>` to set `$GIT_DIR/remotes/<name>/HEAD` explicitly. e.g., "git
remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
`refs/remotes/origin/master`. This will only work if
`refs/remotes/origin/master` already exists; if not it must be fetched first.
+
'show':: 'show'::
Gives some information about the remote <name>. Gives some information about the remote <name>.

View File

@@ -299,18 +299,18 @@ previous section means the set of commits reachable from that
commit, following the commit ancestry chain. commit, following the commit ancestry chain.
To exclude commits reachable from a commit, a prefix `{caret}` To exclude commits reachable from a commit, a prefix `{caret}`
notation is used. E.g. "`{caret}r1 r2`" means commits reachable notation is used. E.g. `{caret}r1 r2` means commits reachable
from `r2` but exclude the ones reachable from `r1`. from `r2` but exclude the ones reachable from `r1`.
This set operation appears so often that there is a shorthand This set operation appears so often that there is a shorthand
for it. When you have two commits `r1` and `r2` (named according for it. When you have two commits `r1` and `r2` (named according
to the syntax explained in SPECIFYING REVISIONS above), you can ask to the syntax explained in SPECIFYING REVISIONS above), you can ask
for commits that are reachable from r2 excluding those that are reachable for commits that are reachable from r2 excluding those that are reachable
from r1 by "`{caret}r1 r2`" and it can be written as "`r1..r2`". from r1 by `{caret}r1 r2` and it can be written as `r1..r2`.
A similar notation "`r1\...r2`" is called symmetric difference A similar notation `r1\...r2` is called symmetric difference
of `r1` and `r2` and is defined as of `r1` and `r2` and is defined as
"`r1 r2 --not $(git merge-base --all r1 r2)`". `r1 r2 --not $(git merge-base --all r1 r2)`.
It is the set of commits that are reachable from either one of It is the set of commits that are reachable from either one of
`r1` or `r2` but not from both. `r1` or `r2` but not from both.

View File

@@ -60,14 +60,13 @@ The --cc option must be repeated for each user you want on the cc list.
Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an
introductory message for the patch series. introductory message for the patch series.
+ +
When '--compose' is used, git send-email gets less interactive will use the When '--compose' is used, git send-email will use the From, Subject, and
values of the headers you set there. If the body of the email (what you type In-Reply-To headers specified in the message. If the body of the message
after the headers and a blank line) only contains blank (or GIT: prefixed) (what you type after the headers and a blank line) only contains blank
lines, the summary won't be sent, but git-send-email will still use the (or GIT: prefixed) lines the summary won't be sent, but From, Subject,
Headers values if you don't removed them. and In-Reply-To headers will be used unless they are removed.
+ +
If it wasn't able to see a header in the summary it will ask you about it Missing From or In-Reply-To headers will be prompted for.
interactively after quitting your editor.
--from:: --from::
Specify the sender of the emails. This will default to Specify the sender of the emails. This will default to

View File

@@ -385,7 +385,8 @@ config key: svn.authorsfile
-q:: -q::
--quiet:: --quiet::
Make 'git-svn' less verbose. Make 'git-svn' less verbose. Specify a second time to make it
even less verbose.
--repack[=<n>]:: --repack[=<n>]::
--repack-flags=<flags>:: --repack-flags=<flags>::
@@ -672,9 +673,9 @@ listed below are allowed:
------------------------------------------------------------------------ ------------------------------------------------------------------------
[svn-remote "project-a"] [svn-remote "project-a"]
url = http://server.org/svn url = http://server.org/svn
fetch = trunk/project-a:refs/remotes/project-a/trunk
branches = branches/*/project-a:refs/remotes/project-a/branches/* branches = branches/*/project-a:refs/remotes/project-a/branches/*
tags = tags/*/project-a:refs/remotes/project-a/tags/* tags = tags/*/project-a:refs/remotes/project-a/tags/*
trunk = trunk/project-a:refs/remotes/project-a/trunk
------------------------------------------------------------------------ ------------------------------------------------------------------------
Keep in mind that the '*' (asterisk) wildcard of the local ref Keep in mind that the '*' (asterisk) wildcard of the local ref

View File

@@ -63,6 +63,7 @@ OPTIONS
are printed when using -l. are printed when using -l.
The default is not to print any annotation lines. The default is not to print any annotation lines.
If no number is given to `-n`, only the first line is printed. If no number is given to `-n`, only the first line is printed.
If the tag is not annotated, the commit message is displayed instead.
-l <pattern>:: -l <pattern>::
List tags with names that match the given pattern (or all if no pattern is given). List tags with names that match the given pattern (or all if no pattern is given).

View File

@@ -46,20 +46,20 @@ Here are the rules regarding the "flags" that you should follow when you are
scripting git: scripting git:
* it's preferred to use the non dashed form of git commands, which means that * it's preferred to use the non dashed form of git commands, which means that
you should prefer `"git foo"` to `"git-foo"`. you should prefer `git foo` to `git-foo`.
* splitting short options to separate words (prefer `"git foo -a -b"` * splitting short options to separate words (prefer `git foo -a -b`
to `"git foo -ab"`, the latter may not even work). to `git foo -ab`, the latter may not even work).
* when a command line option takes an argument, use the 'sticked' form. In * when a command line option takes an argument, use the 'sticked' form. In
other words, write `"git foo -oArg"` instead of `"git foo -o Arg"` for short other words, write `git foo -oArg` instead of `git foo -o Arg` for short
options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"` options, and `git foo --long-opt=Arg` instead of `git foo --long-opt Arg`
for long options. An option that takes optional option-argument must be for long options. An option that takes optional option-argument must be
written in the 'sticked' form. written in the 'sticked' form.
* when you give a revision parameter to a command, make sure the parameter is * when you give a revision parameter to a command, make sure the parameter is
not ambiguous with a name of a file in the work tree. E.g. do not write not ambiguous with a name of a file in the work tree. E.g. do not write
`"git log -1 HEAD"` but write `"git log -1 HEAD --"`; the former will not work `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
if you happen to have a file called `HEAD` in the work tree. if you happen to have a file called `HEAD` in the work tree.
@@ -99,17 +99,17 @@ usage: git-describe [options] <committish>*
Negating options Negating options
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
Options with long option names can be negated by prefixing `"--no-"`. For Options with long option names can be negated by prefixing `--no-`. For
example, `"git branch"` has the option `"--track"` which is 'on' by default. You example, `git branch` has the option `--track` which is 'on' by default. You
can use `"--no-track"` to override that behaviour. The same goes for `"--color"` can use `--no-track` to override that behaviour. The same goes for `--color`
and `"--no-color"`. and `--no-color`.
Aggregating short options Aggregating short options
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
Commands that support the enhanced option parser allow you to aggregate short Commands that support the enhanced option parser allow you to aggregate short
options. This means that you can for example use `"git rm -rf"` or options. This means that you can for example use `git rm -rf` or
`"git clean -fdx"`. `git clean -fdx`.
Separating argument from the option Separating argument from the option

View File

@@ -151,6 +151,10 @@ indicating whether the checkout was a branch checkout (changing branches,
flag=1) or a file checkout (retrieving a file from the index, flag=0). flag=1) or a file checkout (retrieving a file from the index, flag=0).
This hook cannot affect the outcome of 'git-checkout'. This hook cannot affect the outcome of 'git-checkout'.
It is also run after 'git-clone', unless the --no-checkout (-n) option is
used. The first parameter given to the hook is the null-ref, the second the
ref of the new HEAD and the flag is always 1.
This hook can be used to perform repository validity checks, auto-display This hook can be used to perform repository validity checks, auto-display
differences from the previous HEAD if different, or set working dir metadata differences from the previous HEAD if different, or set working dir metadata
properties. properties.

View File

@@ -262,7 +262,7 @@ This commit is referred to as a "merge commit", or sometimes just a
'origin' is used for that purpose. New upstream updates 'origin' is used for that purpose. New upstream updates
will be fetched into remote <<def_tracking_branch,tracking branches>> named will be fetched into remote <<def_tracking_branch,tracking branches>> named
origin/name-of-upstream-branch, which you can see using origin/name-of-upstream-branch, which you can see using
"`git branch -r`". `git branch -r`.
[[def_pack]]pack:: [[def_pack]]pack::
A set of objects which have been compressed into one file (to save space A set of objects which have been compressed into one file (to save space

View File

@@ -5,22 +5,21 @@ canonical real names and email addresses.
In the simple form, each line in the file consists of the canonical In the simple form, each line in the file consists of the canonical
real name of an author, whitespace, and an email address used in the real name of an author, whitespace, and an email address used in the
commit (enclosed by '<' and '>') to map to the name. Thus, looks like commit (enclosed by '<' and '>') to map to the name. For example:
this
-- --
Proper Name <commit@email.xx> Proper Name <commit@email.xx>
-- --
The more complex forms are The more complex forms are:
-- --
<proper@email.xx> <commit@email.xx> <proper@email.xx> <commit@email.xx>
-- --
which allows mailmap to replace only the email part of a commit, and which allows mailmap to replace only the email part of a commit, and:
-- --
Proper Name <proper@email.xx> <commit@email.xx> Proper Name <proper@email.xx> <commit@email.xx>
-- --
which allows mailmap to replace both the name and the email of a which allows mailmap to replace both the name and the email of a
commit matching the specified commit email address, and commit matching the specified commit email address, and:
-- --
Proper Name <proper@email.xx> Commit Name <commit@email.xx> Proper Name <proper@email.xx> Commit Name <commit@email.xx>
-- --
@@ -47,8 +46,8 @@ Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com> Joe R. Developer <joe@example.com>
------------ ------------
Note how we don't need an entry for <jane@laptop.(none)>, because the Note how there is no need for an entry for <jane@laptop.(none)>, because the
real name of that author is correct already. real name of that author is already correct.
Example 2: Your repository contains commits from the following Example 2: Your repository contains commits from the following
authors: authors:
@@ -62,7 +61,7 @@ claus <me@company.xx>
CTO <cto@coompany.xx> CTO <cto@coompany.xx>
------------ ------------
Then, you might want a `.mailmap` file looking like: Then you might want a `.mailmap` file that looks like:
------------ ------------
<cto@company.xx> <cto@coompany.xx> <cto@company.xx> <cto@coompany.xx>
Some Dude <some@dude.xx> nick1 <bugs@company.xx> Some Dude <some@dude.xx> nick1 <bugs@company.xx>
@@ -72,4 +71,4 @@ Santa Claus <santa.claus@northpole.xx> <me@company.xx>
------------ ------------
Use hash '#' for comments that are either on their own line, or after Use hash '#' for comments that are either on their own line, or after
the email address. the email address.

View File

@@ -1,21 +1,14 @@
<!-- Based on callouts.xsl. Fixes man page callouts for DocBook 1.72 XSL --> <!-- manpage-1.72.xsl:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> special settings for manpages rendered from asciidoc+docbook
handles peculiarities in docbook-xsl 1.72.0 -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:param name="man.output.quietly" select="1"/> <xsl:import href="manpage-base.xsl"/>
<xsl:param name="refentry.meta.get.quietly" select="1"/>
<xsl:template match="co"> <!-- these are the special values for the roff control characters
<xsl:value-of select="concat('&#x2593;fB(',substring-after(@id,'-'),')&#x2593;fR')"/> needed for docbook-xsl 1.72.0 -->
</xsl:template> <xsl:param name="git.docbook.backslash">&#x2593;</xsl:param>
<xsl:template match="calloutlist"> <xsl:param name="git.docbook.dot" >&#x2302;</xsl:param>
<xsl:text>&#x2302;sp&#10;</xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;</xsl:text>
</xsl:template>
<xsl:template match="callout">
<xsl:value-of select="concat('&#x2593;fB',substring-after(@arearefs,'-'),'. &#x2593;fR')"/>
<xsl:apply-templates/>
<xsl:text>&#x2302;br&#10;</xsl:text>
</xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@@ -0,0 +1,35 @@
<!-- manpage-base.xsl:
special formatting for manpages rendered from asciidoc+docbook -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- these params silence some output from xmlto -->
<xsl:param name="man.output.quietly" select="1"/>
<xsl:param name="refentry.meta.get.quietly" select="1"/>
<!-- convert asciidoc callouts to man page format;
git.docbook.backslash and git.docbook.dot params
must be supplied by another XSL file or other means -->
<xsl:template match="co">
<xsl:value-of select="concat(
$git.docbook.backslash,'fB(',
substring-after(@id,'-'),')',
$git.docbook.backslash,'fR')"/>
</xsl:template>
<xsl:template match="calloutlist">
<xsl:value-of select="$git.docbook.dot"/>
<xsl:text>sp&#10;</xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;</xsl:text>
</xsl:template>
<xsl:template match="callout">
<xsl:value-of select="concat(
$git.docbook.backslash,'fB',
substring-after(@arearefs,'-'),
'. ',$git.docbook.backslash,'fR')"/>
<xsl:apply-templates/>
<xsl:value-of select="$git.docbook.dot"/>
<xsl:text>br&#10;</xsl:text>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,17 @@
<!-- manpage-bold-literal.xsl:
special formatting for manpages rendered from asciidoc+docbook -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- render literal text as bold (instead of plain or monospace);
this makes literal text easier to distinguish in manpages
viewed on a tty -->
<xsl:template match="literal">
<xsl:value-of select="$git.docbook.backslash"/>
<xsl:text>fB</xsl:text>
<xsl:apply-templates/>
<xsl:value-of select="$git.docbook.backslash"/>
<xsl:text>fR</xsl:text>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,13 @@
<!-- manpage-normal.xsl:
special settings for manpages rendered from asciidoc+docbook
handles anything we want to keep away from docbook-xsl 1.72.0 -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:import href="manpage-base.xsl"/>
<!-- these are the normal values for the roff control characters -->
<xsl:param name="git.docbook.backslash">\</xsl:param>
<xsl:param name="git.docbook.dot" >.</xsl:param>
</xsl:stylesheet>

View File

@@ -0,0 +1,21 @@
<!-- manpage-suppress-sp.xsl:
special settings for manpages rendered from asciidoc+docbook
handles erroneous, inline .sp in manpage output of some
versions of docbook-xsl -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- attempt to work around spurious .sp at the tail of the line
that some versions of docbook stylesheets seem to add -->
<xsl:template match="simpara">
<xsl:variable name="content">
<xsl:apply-templates/>
</xsl:variable>
<xsl:value-of select="normalize-space($content)"/>
<xsl:if test="not(ancestor::authorblurb) and
not(ancestor::personblurb)">
<xsl:text>&#10;&#10;</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View File

@@ -3,15 +3,15 @@ MERGE STRATEGIES
resolve:: resolve::
This can only resolve two heads (i.e. the current branch This can only resolve two heads (i.e. the current branch
and another branch you pulled from) using 3-way merge and another branch you pulled from) using a 3-way merge
algorithm. It tries to carefully detect criss-cross algorithm. It tries to carefully detect criss-cross
merge ambiguities and is considered generally safe and merge ambiguities and is considered generally safe and
fast. fast.
recursive:: recursive::
This can only resolve two heads using 3-way merge This can only resolve two heads using a 3-way merge
algorithm. When there are more than one common algorithm. When there is more than one common
ancestors that can be used for 3-way merge, it creates a ancestor that can be used for 3-way merge, it creates a
merged tree of the common ancestors and uses that as merged tree of the common ancestors and uses that as
the reference tree for the 3-way merge. This has been the reference tree for the 3-way merge. This has been
reported to result in fewer merge conflicts without reported to result in fewer merge conflicts without
@@ -22,11 +22,11 @@ recursive::
pulling or merging one branch. pulling or merging one branch.
octopus:: octopus::
This resolves more than two-head case, but refuses to do This resolves cases with more than two heads, but refuses to do
complex merge that needs manual resolution. It is a complex merge that needs manual resolution. It is
primarily meant to be used for bundling topic branch primarily meant to be used for bundling topic branch
heads together. This is the default merge strategy when heads together. This is the default merge strategy when
pulling or merging more than one branches. pulling or merging more than one branch.
ours:: ours::
This resolves any number of heads, but the result of the This resolves any number of heads, but the result of the

View File

@@ -148,22 +148,22 @@ outputting that information, if desired.
------------ ------------
* *
* *
M *
|\ |\
* | * |
| | * | | *
| \ \ | \ \
| \ \ | \ \
M-. \ \ *-. \ \
|\ \ \ \ |\ \ \ \
| | * | | | | * | |
| | | | | * | | | | | *
| | | | | * | | | | | *
| | | | | M | | | | | *
| | | | | |\ | | | | | |\
| | | | | | * | | | | | | *
| * | | | | | | * | | | | |
| | | | | M \ | | | | | * \
| | | | | |\ | | | | | | |\ |
| | | | * | | | | | | | * | | |
| | | | * | | | | | | | * | | |

View File

@@ -1136,10 +1136,10 @@ Ignoring files
A project will often generate files that you do 'not' want to track with git. A project will often generate files that you do 'not' want to track with git.
This typically includes files generated by a build process or temporary This typically includes files generated by a build process or temporary
backup files made by your editor. Of course, 'not' tracking files with git backup files made by your editor. Of course, 'not' tracking files with git
is just a matter of 'not' calling "`git-add`" on them. But it quickly becomes is just a matter of 'not' calling `git-add` on them. But it quickly becomes
annoying to have these untracked files lying around; e.g. they make annoying to have these untracked files lying around; e.g. they make
"`git add .`" practically useless, and they keep showing up in the output of `git add .` practically useless, and they keep showing up in the output of
"`git status`". `git status`.
You can tell git to ignore certain files by creating a file called .gitignore You can tell git to ignore certain files by creating a file called .gitignore
in the top level of your working directory, with contents such as: in the top level of your working directory, with contents such as:

View File

@@ -126,6 +126,12 @@ all::
# randomly break unless your underlying filesystem supports those sub-second # randomly break unless your underlying filesystem supports those sub-second
# times (my ext3 doesn't). # times (my ext3 doesn't).
# #
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
# "st_ctim"
#
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
# available. This automatically turns USE_NSEC off.
#
# Define USE_STDEV below if you want git to care about the underlying device # Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective. # change being considered an inode change from the update-index perspective.
# #
@@ -258,6 +264,18 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
BASIC_CFLAGS = BASIC_CFLAGS =
BASIC_LDFLAGS = BASIC_LDFLAGS =
# Guard against environment variables
BUILTIN_OBJS =
BUILT_INS =
COMPAT_CFLAGS =
COMPAT_OBJS =
LIB_H =
LIB_OBJS =
PROGRAMS =
SCRIPT_PERL =
SCRIPT_SH =
TEST_PROGRAMS =
SCRIPT_SH += git-am.sh SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-filter-branch.sh SCRIPT_SH += git-filter-branch.sh
@@ -658,6 +676,7 @@ ifeq ($(uname_S),Darwin)
endif endif
NO_MEMMEM = YesPlease NO_MEMMEM = YesPlease
THREADED_DELTA_SEARCH = YesPlease THREADED_DELTA_SEARCH = YesPlease
USE_ST_TIMESPEC = YesPlease
endif endif
ifeq ($(uname_S),SunOS) ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease NEEDS_SOCKET = YesPlease
@@ -707,6 +726,7 @@ ifeq ($(uname_S),FreeBSD)
BASIC_CFLAGS += -I/usr/local/include BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib BASIC_LDFLAGS += -L/usr/local/lib
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
USE_ST_TIMESPEC = YesPlease
THREADED_DELTA_SEARCH = YesPlease THREADED_DELTA_SEARCH = YesPlease
ifeq ($(shell expr "$(uname_R)" : '4\.'),2) ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
PTHREAD_LIBS = -pthread PTHREAD_LIBS = -pthread
@@ -735,6 +755,7 @@ ifeq ($(uname_S),AIX)
NO_MEMMEM = YesPlease NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease NO_MKDTEMP = YesPlease
NO_STRLCPY = YesPlease NO_STRLCPY = YesPlease
NO_NSEC = YesPlease
FREAD_READS_DIRECTORIES = UnfortunatelyYes FREAD_READS_DIRECTORIES = UnfortunatelyYes
INTERNAL_QSORT = UnfortunatelyYes INTERNAL_QSORT = UnfortunatelyYes
NEEDS_LIBICONV=YesPlease NEEDS_LIBICONV=YesPlease
@@ -804,6 +825,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
RUNTIME_PREFIX = YesPlease RUNTIME_PREFIX = YesPlease
NO_POSIX_ONLY_PROGRAMS = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease USE_WIN32_MMAP = YesPlease
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@ -926,6 +948,15 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
endif endif
ifdef USE_NSEC
BASIC_CFLAGS += -DUSE_NSEC
endif
ifdef USE_ST_TIMESPEC
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
endif
ifdef NO_NSEC
BASIC_CFLAGS += -DNO_NSEC
endif
ifdef NO_C99_FORMAT ifdef NO_C99_FORMAT
BASIC_CFLAGS += -DNO_C99_FORMAT BASIC_CFLAGS += -DNO_C99_FORMAT
endif endif
@@ -973,6 +1004,11 @@ endif
ifdef NO_MMAP ifdef NO_MMAP
COMPAT_CFLAGS += -DNO_MMAP COMPAT_CFLAGS += -DNO_MMAP
COMPAT_OBJS += compat/mmap.o COMPAT_OBJS += compat/mmap.o
else
ifdef USE_WIN32_MMAP
COMPAT_CFLAGS += -DUSE_WIN32_MMAP
COMPAT_OBJS += compat/win32mmap.o
endif
endif endif
ifdef USE_WIN32_MMAP ifdef USE_WIN32_MMAP
COMPAT_CFLAGS += -DUSE_WIN32_MMAP COMPAT_CFLAGS += -DUSE_WIN32_MMAP
@@ -1373,6 +1409,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
@echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
### Detect Tck/Tk interpreter path changes ### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK ifndef NO_TCLTK

73
attr.c
View File

@@ -1,3 +1,4 @@
#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h" #include "cache.h"
#include "attr.h" #include "attr.h"
@@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list)
return res; return res;
} }
static enum git_attr_direction direction;
static struct index_state *use_index;
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
{ {
FILE *fp = fopen(path, "r"); FILE *fp = fopen(path, "r");
@@ -340,9 +344,10 @@ static void *read_index_data(const char *path)
unsigned long sz; unsigned long sz;
enum object_type type; enum object_type type;
void *data; void *data;
struct index_state *istate = use_index ? use_index : &the_index;
len = strlen(path); len = strlen(path);
pos = cache_name_pos(path, len); pos = index_name_pos(istate, path, len);
if (pos < 0) { if (pos < 0) {
/* /*
* We might be in the middle of a merge, in which * We might be in the middle of a merge, in which
@@ -350,15 +355,15 @@ static void *read_index_data(const char *path)
*/ */
int i; int i;
for (i = -pos - 1; for (i = -pos - 1;
(pos < 0 && i < active_nr && (pos < 0 && i < istate->cache_nr &&
!strcmp(active_cache[i]->name, path)); !strcmp(istate->cache[i]->name, path));
i++) i++)
if (ce_stage(active_cache[i]) == 2) if (ce_stage(istate->cache[i]) == 2)
pos = i; pos = i;
} }
if (pos < 0) if (pos < 0)
return NULL; return NULL;
data = read_sha1_file(active_cache[pos]->sha1, &type, &sz); data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
if (!data || type != OBJ_BLOB) { if (!data || type != OBJ_BLOB) {
free(data); free(data);
return NULL; return NULL;
@@ -366,27 +371,17 @@ static void *read_index_data(const char *path)
return data; return data;
} }
static struct attr_stack *read_attr(const char *path, int macro_ok) static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)
{ {
struct attr_stack *res; struct attr_stack *res;
char *buf, *sp; char *buf, *sp;
int lineno = 0; int lineno = 0;
res = read_attr_from_file(path, macro_ok);
if (res)
return res;
res = xcalloc(1, sizeof(*res));
/*
* There is no checked out .gitattributes file there, but
* we might have it in the index. We allow operation in a
* sparsely checked out work tree, so read from it.
*/
buf = read_index_data(path); buf = read_index_data(path);
if (!buf) if (!buf)
return res; return NULL;
res = xcalloc(1, sizeof(*res));
for (sp = buf; *sp; ) { for (sp = buf; *sp; ) {
char *ep; char *ep;
int more; int more;
@@ -401,6 +396,30 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
return res; return res;
} }
static struct attr_stack *read_attr(const char *path, int macro_ok)
{
struct attr_stack *res;
if (direction == GIT_ATTR_CHECKOUT) {
res = read_attr_from_index(path, macro_ok);
if (!res)
res = read_attr_from_file(path, macro_ok);
}
else {
res = read_attr_from_file(path, macro_ok);
if (!res)
/*
* There is no checked out .gitattributes file there, but
* we might have it in the index. We allow operation in a
* sparsely checked out work tree, so read from it.
*/
res = read_attr_from_index(path, macro_ok);
}
if (!res)
res = xcalloc(1, sizeof(*res));
return res;
}
#if DEBUG_ATTR #if DEBUG_ATTR
static void debug_info(const char *what, struct attr_stack *elem) static void debug_info(const char *what, struct attr_stack *elem)
{ {
@@ -428,6 +447,15 @@ static void debug_set(const char *what, const char *match, struct git_attr *attr
#define debug_set(a,b,c,d) do { ; } while (0) #define debug_set(a,b,c,d) do { ; } while (0)
#endif #endif
static void drop_attr_stack(void)
{
while (attr_stack) {
struct attr_stack *elem = attr_stack;
attr_stack = elem->prev;
free_attr_elem(elem);
}
}
static void bootstrap_attr_stack(void) static void bootstrap_attr_stack(void)
{ {
if (!attr_stack) { if (!attr_stack) {
@@ -642,3 +670,12 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
return 0; return 0;
} }
void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
{
enum git_attr_direction old = direction;
direction = new;
if (new != old)
drop_attr_stack();
use_index = istate;
}

6
attr.h
View File

@@ -31,4 +31,10 @@ struct git_attr_check {
int git_checkattr(const char *path, int, struct git_attr_check *); int git_checkattr(const char *path, int, struct git_attr_check *);
enum git_attr_direction {
GIT_ATTR_CHECKIN,
GIT_ATTR_CHECKOUT
};
void git_attr_set_direction(enum git_attr_direction, struct index_state *);
#endif /* ATTR_H */ #endif /* ATTR_H */

View File

@@ -32,21 +32,59 @@ static int find_tracked_branch(struct remote *remote, void *priv)
return 0; return 0;
} }
static int should_setup_rebase(const struct tracking *tracking) static int should_setup_rebase(const char *origin)
{ {
switch (autorebase) { switch (autorebase) {
case AUTOREBASE_NEVER: case AUTOREBASE_NEVER:
return 0; return 0;
case AUTOREBASE_LOCAL: case AUTOREBASE_LOCAL:
return tracking->remote == NULL; return origin == NULL;
case AUTOREBASE_REMOTE: case AUTOREBASE_REMOTE:
return tracking->remote != NULL; return origin != NULL;
case AUTOREBASE_ALWAYS: case AUTOREBASE_ALWAYS:
return 1; return 1;
} }
return 0; return 0;
} }
void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
{
struct strbuf key = STRBUF_INIT;
int rebasing = should_setup_rebase(origin);
strbuf_addf(&key, "branch.%s.remote", local);
git_config_set(key.buf, origin ? origin : ".");
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.merge", local);
git_config_set(key.buf, remote);
if (rebasing) {
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.rebase", local);
git_config_set(key.buf, "true");
}
if (flag & BRANCH_CONFIG_VERBOSE) {
strbuf_reset(&key);
strbuf_addstr(&key, origin ? "remote" : "local");
/* Are we tracking a proper "branch"? */
if (!prefixcmp(remote, "refs/heads/")) {
strbuf_addf(&key, " branch %s", remote + 11);
if (origin)
strbuf_addf(&key, " from %s", origin);
}
else
strbuf_addf(&key, " ref %s", remote);
printf("Branch %s set up to track %s%s.\n",
local, key.buf,
rebasing ? " by rebasing" : "");
}
strbuf_release(&key);
}
/* /*
* This is called when new_ref is branched off of orig_ref, and tries * This is called when new_ref is branched off of orig_ref, and tries
* to infer the settings for branch.<new_ref>.{remote,merge} from the * to infer the settings for branch.<new_ref>.{remote,merge} from the
@@ -55,7 +93,6 @@ static int should_setup_rebase(const struct tracking *tracking)
static int setup_tracking(const char *new_ref, const char *orig_ref, static int setup_tracking(const char *new_ref, const char *orig_ref,
enum branch_track track) enum branch_track track)
{ {
char key[1024];
struct tracking tracking; struct tracking tracking;
if (strlen(new_ref) > 1024 - 7 - 7 - 1) if (strlen(new_ref) > 1024 - 7 - 7 - 1)
@@ -80,19 +117,10 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
return error("Not tracking: ambiguous information for ref %s", return error("Not tracking: ambiguous information for ref %s",
orig_ref); orig_ref);
sprintf(key, "branch.%s.remote", new_ref); install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote,
git_config_set(key, tracking.remote ? tracking.remote : "."); tracking.src ? tracking.src : orig_ref);
sprintf(key, "branch.%s.merge", new_ref);
git_config_set(key, tracking.src ? tracking.src : orig_ref);
printf("Branch %s set up to track %s branch %s.\n", new_ref,
tracking.remote ? "remote" : "local", orig_ref);
if (should_setup_rebase(&tracking)) {
sprintf(key, "branch.%s.rebase", new_ref);
git_config_set(key, "true");
printf("This branch will rebase on pull.\n");
}
free(tracking.src);
free(tracking.src);
return 0; return 0;
} }

View File

@@ -21,4 +21,11 @@ void create_branch(const char *head, const char *name, const char *start_name,
*/ */
void remove_branch_state(void); void remove_branch_state(void);
/*
* Configure local branch "local" to merge remote branch "remote"
* taken from origin "origin".
*/
#define BRANCH_CONFIG_VERBOSE 01
extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote);
#endif #endif

View File

@@ -104,7 +104,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
/* Set up the default git porcelain excludes */ /* Set up the default git porcelain excludes */
memset(dir, 0, sizeof(*dir)); memset(dir, 0, sizeof(*dir));
if (!ignored_too) { if (!ignored_too) {
dir->collect_ignored = 1; dir->flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(dir); setup_standard_excludes(dir);
} }
@@ -148,7 +148,7 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p
if (pathspec) { if (pathspec) {
const char **p; const char **p;
for (p = pathspec; *p; p++) { for (p = pathspec; *p; p++) {
if (has_symlink_leading_path(strlen(*p), *p)) { if (has_symlink_leading_path(*p, strlen(*p))) {
int len = prefix ? strlen(prefix) : 0; int len = prefix ? strlen(prefix) : 0;
die("'%s' is beyond a symbolic link", *p + len); die("'%s' is beyond a symbolic link", *p + len);
} }

View File

@@ -2360,7 +2360,7 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists)
* In such a case, path "new_name" does not exist as * In such a case, path "new_name" does not exist as
* far as git is concerned. * far as git is concerned.
*/ */
if (has_symlink_leading_path(strlen(new_name), new_name)) if (has_symlink_leading_path(new_name, strlen(new_name)))
return 0; return 0;
return error("%s: already exists in working directory", new_name); return error("%s: already exists in working directory", new_name);
@@ -2451,7 +2451,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
if ((st_mode ^ patch->old_mode) & S_IFMT) if ((st_mode ^ patch->old_mode) & S_IFMT)
return error("%s: wrong type", old_name); return error("%s: wrong type", old_name);
if (st_mode != patch->old_mode) if (st_mode != patch->old_mode)
fprintf(stderr, "warning: %s has type %o, expected %o\n", warning("%s has type %o, expected %o",
old_name, st_mode, patch->old_mode); old_name, st_mode, patch->old_mode);
if (!patch->new_mode && !patch->is_delete) if (!patch->new_mode && !patch->is_delete)
patch->new_mode = st_mode; patch->new_mode = st_mode;
@@ -2932,8 +2932,7 @@ static int write_out_one_reject(struct patch *patch)
cnt = strlen(patch->new_name); cnt = strlen(patch->new_name);
if (ARRAY_SIZE(namebuf) <= cnt + 5) { if (ARRAY_SIZE(namebuf) <= cnt + 5) {
cnt = ARRAY_SIZE(namebuf) - 5; cnt = ARRAY_SIZE(namebuf) - 5;
fprintf(stderr, warning("truncating .rej filename to %.*s.rej",
"warning: truncating .rej filename to %.*s.rej",
cnt - 1, patch->new_name); cnt - 1, patch->new_name);
} }
memcpy(namebuf, patch->new_name, cnt); memcpy(namebuf, patch->new_name, cnt);
@@ -3212,7 +3211,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
struct option builtin_apply_options[] = { struct option builtin_apply_options[] = {
{ OPTION_CALLBACK, 0, "exclude", NULL, "path", { OPTION_CALLBACK, 0, "exclude", NULL, "path",
"don´t apply changes matching the given path", "don't apply changes matching the given path",
0, option_parse_exclude }, 0, option_parse_exclude },
{ OPTION_CALLBACK, 0, "include", NULL, "path", { OPTION_CALLBACK, 0, "include", NULL, "path",
"apply changes matching the given path", "apply changes matching the given path",
@@ -3224,10 +3223,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
"ignore additions made by the patch"), "ignore additions made by the patch"),
OPT_BOOLEAN(0, "stat", &diffstat, OPT_BOOLEAN(0, "stat", &diffstat,
"instead of applying the patch, output diffstat for the input"), "instead of applying the patch, output diffstat for the input"),
OPT_BOOLEAN(0, "allow-binary-replacement", &binary, { OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
"now no-op"), NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
OPT_BOOLEAN(0, "binary", &binary, { OPTION_BOOLEAN, 0, "binary", &binary,
"now no-op"), NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
OPT_BOOLEAN(0, "numstat", &numstat, OPT_BOOLEAN(0, "numstat", &numstat,
"shows number of added and deleted lines in decimal notation"), "shows number of added and deleted lines in decimal notation"),
OPT_BOOLEAN(0, "summary", &summary, OPT_BOOLEAN(0, "summary", &summary,
@@ -3315,8 +3314,8 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
squelch_whitespace_errors < whitespace_error) { squelch_whitespace_errors < whitespace_error) {
int squelched = int squelched =
whitespace_error - squelch_whitespace_errors; whitespace_error - squelch_whitespace_errors;
fprintf(stderr, "warning: squelched %d " warning("squelched %d "
"whitespace error%s\n", "whitespace error%s",
squelched, squelched,
squelched == 1 ? "" : "s"); squelched == 1 ? "" : "s");
} }
@@ -3326,12 +3325,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
whitespace_error == 1 ? "" : "s", whitespace_error == 1 ? "" : "s",
whitespace_error == 1 ? "s" : ""); whitespace_error == 1 ? "s" : "");
if (applied_after_fixing_ws && apply) if (applied_after_fixing_ws && apply)
fprintf(stderr, "warning: %d line%s applied after" warning("%d line%s applied after"
" fixing whitespace errors.\n", " fixing whitespace errors.",
applied_after_fixing_ws, applied_after_fixing_ws,
applied_after_fixing_ws == 1 ? "" : "s"); applied_after_fixing_ws == 1 ? "" : "s");
else if (whitespace_error) else if (whitespace_error)
fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n", warning("%d line%s add%s whitespace errors.",
whitespace_error, whitespace_error,
whitespace_error == 1 ? "" : "s", whitespace_error == 1 ? "" : "s",
whitespace_error == 1 ? "s" : ""); whitespace_error == 1 ? "s" : "");

View File

@@ -2250,6 +2250,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_done: parse_done:
argc = parse_options_end(&ctx); argc = parse_options_end(&ctx);
if (revs_file && read_ancestry(revs_file))
die("reading graft file %s failed: %s",
revs_file, strerror(errno));
if (cmd_is_annotate) { if (cmd_is_annotate) {
output_option |= OUTPUT_ANNOTATE_COMPAT; output_option |= OUTPUT_ANNOTATE_COMPAT;
blame_date_mode = DATE_ISO8601; blame_date_mode = DATE_ISO8601;
@@ -2418,10 +2422,6 @@ parse_done:
sb.ent = ent; sb.ent = ent;
sb.path = path; sb.path = path;
if (revs_file && read_ancestry(revs_file))
die("reading graft file %s failed: %s",
revs_file, strerror(errno));
read_mailmap(&mailmap, NULL); read_mailmap(&mailmap, NULL);
if (!incremental) if (!incremental)

View File

@@ -171,7 +171,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
ret = 1; ret = 1;
} else { } else {
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
printf("Deleted %sbranch %s (%s).\n", remote, printf("Deleted %sbranch %s (was %s).\n", remote,
bname.buf, bname.buf,
find_unique_abbrev(sha1, DEFAULT_ABBREV)); find_unique_abbrev(sha1, DEFAULT_ABBREV));
strbuf_addf(&buf, "branch.%s", bname.buf); strbuf_addf(&buf, "branch.%s", bname.buf);

View File

@@ -407,7 +407,7 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.verbose_update = !opts->quiet; topts.verbose_update = !opts->quiet;
topts.fn = twoway_merge; topts.fn = twoway_merge;
topts.dir = xcalloc(1, sizeof(*topts.dir)); topts.dir = xcalloc(1, sizeof(*topts.dir));
topts.dir->show_ignored = 1; topts.dir->flags |= DIR_SHOW_IGNORED;
topts.dir->exclude_per_dir = ".gitignore"; topts.dir->exclude_per_dir = ".gitignore";
tree = parse_tree_indirect(old->commit->object.sha1); tree = parse_tree_indirect(old->commit->object.sha1);
init_tree_desc(&trees[0], tree->buffer, tree->size); init_tree_desc(&trees[0], tree->buffer, tree->size);
@@ -558,8 +558,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
if (!old.commit && !opts->force) { if (!old.commit && !opts->force) {
if (!opts->quiet) { if (!opts->quiet) {
fprintf(stderr, "warning: You appear to be on a branch yet to be born.\n"); warning("You appear to be on a branch yet to be born.");
fprintf(stderr, "warning: Forcing checkout of %s.\n", new->name); warning("Forcing checkout of %s.", new->name);
} }
opts->force = 1; opts->force = 1;
} }

View File

@@ -60,7 +60,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
memset(&dir, 0, sizeof(dir)); memset(&dir, 0, sizeof(dir));
if (ignored_only) if (ignored_only)
dir.show_ignored = 1; dir.flags |= DIR_SHOW_IGNORED;
if (ignored && ignored_only) if (ignored && ignored_only)
die("-x and -X cannot be used together"); die("-x and -X cannot be used together");
@@ -69,7 +69,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
die("clean.requireForce%s set and -n or -f not given; " die("clean.requireForce%s set and -n or -f not given; "
"refusing to clean", config_set ? "" : " not"); "refusing to clean", config_set ? "" : " not");
dir.show_other_directories = 1; dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (!ignored) if (!ignored)
setup_standard_excludes(&dir); setup_standard_excludes(&dir);

View File

@@ -20,6 +20,8 @@
#include "dir.h" #include "dir.h"
#include "pack-refs.h" #include "pack-refs.h"
#include "sigchain.h" #include "sigchain.h"
#include "branch.h"
#include "remote.h"
#include "run-command.h" #include "run-command.h"
/* /*
@@ -268,7 +270,7 @@ static const struct ref *clone_local(const char *src_repo,
static const char *junk_work_tree; static const char *junk_work_tree;
static const char *junk_git_dir; static const char *junk_git_dir;
pid_t junk_pid; static pid_t junk_pid;
static void remove_junk(void) static void remove_junk(void)
{ {
@@ -294,43 +296,6 @@ static void remove_junk_on_signal(int signo)
raise(signo); raise(signo);
} }
static const struct ref *locate_head(const struct ref *refs,
const struct ref *mapped_refs,
const struct ref **remote_head_p)
{
const struct ref *remote_head = NULL;
const struct ref *remote_master = NULL;
const struct ref *r;
for (r = refs; r; r = r->next)
if (!strcmp(r->name, "HEAD"))
remote_head = r;
for (r = mapped_refs; r; r = r->next)
if (!strcmp(r->name, "refs/heads/master"))
remote_master = r;
if (remote_head_p)
*remote_head_p = remote_head;
/* If there's no HEAD value at all, never mind. */
if (!remote_head)
return NULL;
/* If refs/heads/master could be right, it is. */
if (remote_master && !hashcmp(remote_master->old_sha1,
remote_head->old_sha1))
return remote_master;
/* Look for another ref that points there */
for (r = mapped_refs; r; r = r->next)
if (r != remote_head &&
!hashcmp(r->old_sha1, remote_head->old_sha1))
return r;
/* Nothing is the same */
return NULL;
}
static struct ref *write_remote_refs(const struct ref *refs, static struct ref *write_remote_refs(const struct ref *refs,
struct refspec *refspec, const char *reflog) struct refspec *refspec, const char *reflog)
{ {
@@ -351,19 +316,6 @@ static struct ref *write_remote_refs(const struct ref *refs,
return local_refs; return local_refs;
} }
static void install_branch_config(const char *local,
const char *origin,
const char *remote)
{
struct strbuf key = STRBUF_INIT;
strbuf_addf(&key, "branch.%s.remote", local);
git_config_set(key.buf, origin);
strbuf_reset(&key);
strbuf_addf(&key, "branch.%s.merge", local);
git_config_set(key.buf, remote);
strbuf_release(&key);
}
int cmd_clone(int argc, const char **argv, const char *prefix) int cmd_clone(int argc, const char **argv, const char *prefix)
{ {
int is_bundle = 0; int is_bundle = 0;
@@ -378,7 +330,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
char *src_ref_prefix = "refs/heads/"; char *src_ref_prefix = "refs/heads/";
int err = 0; int err = 0;
struct refspec refspec; struct refspec *refspec;
const char *fetch_pattern;
junk_pid = getpid(); junk_pid = getpid();
@@ -453,7 +406,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
atexit(remove_junk); atexit(remove_junk);
sigchain_push_common(remove_junk_on_signal); sigchain_push_common(remove_junk_on_signal);
setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1); setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);
if (safe_create_leading_directories_const(git_dir) < 0) if (safe_create_leading_directories_const(git_dir) < 0)
die("could not create leading directories of '%s'", git_dir); die("could not create leading directories of '%s'", git_dir);
@@ -483,8 +436,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin); strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
} }
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
if (option_mirror || !option_bare) { if (option_mirror || !option_bare) {
/* Configure the remote */ /* Configure the remote */
strbuf_addf(&key, "remote.%s.fetch", option_origin);
git_config_set_multivar(key.buf, value.buf, "^$", 0);
strbuf_reset(&key);
if (option_mirror) { if (option_mirror) {
strbuf_addf(&key, "remote.%s.mirror", option_origin); strbuf_addf(&key, "remote.%s.mirror", option_origin);
git_config_set(key.buf, "true"); git_config_set(key.buf, "true");
@@ -493,19 +452,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_addf(&key, "remote.%s.url", option_origin); strbuf_addf(&key, "remote.%s.url", option_origin);
git_config_set(key.buf, repo); git_config_set(key.buf, repo);
strbuf_reset(&key);
strbuf_addf(&key, "remote.%s.fetch", option_origin);
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
git_config_set_multivar(key.buf, value.buf, "^$", 0);
strbuf_reset(&key); strbuf_reset(&key);
strbuf_reset(&value);
} }
refspec.force = 0; fetch_pattern = value.buf;
refspec.pattern = 1; refspec = parse_fetch_refspec(1, &fetch_pattern);
refspec.src = src_ref_prefix;
refspec.dst = branch_top.buf; strbuf_reset(&value);
if (path && !is_bundle) if (path && !is_bundle)
refs = clone_local(path, git_dir); refs = clone_local(path, git_dir);
@@ -539,9 +492,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (refs) { if (refs) {
clear_extra_refs(); clear_extra_refs();
mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf); mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
head_points_at = locate_head(refs, mapped_refs, &remote_head); remote_head = find_ref_by_name(refs, "HEAD");
head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
} }
else { else {
warning("You appear to have cloned an empty repository."); warning("You appear to have cloned an empty repository.");
@@ -549,7 +503,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head = NULL; remote_head = NULL;
option_no_checkout = 1; option_no_checkout = 1;
if (!option_bare) if (!option_bare)
install_branch_config("master", option_origin, install_branch_config(0, "master", option_origin,
"refs/heads/master"); "refs/heads/master");
} }
@@ -579,7 +533,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
head_points_at->peer_ref->name, head_points_at->peer_ref->name,
reflog_msg.buf); reflog_msg.buf);
install_branch_config(head, option_origin, install_branch_config(0, head, option_origin,
head_points_at->name); head_points_at->name);
} }
} else if (remote_head) { } else if (remote_head) {

View File

@@ -1,9 +1,12 @@
#include "builtin.h" #include "builtin.h"
#include "cache.h" #include "cache.h"
#include "color.h" #include "color.h"
#include "parse-options.h"
static const char git_config_set_usage[] = static const char *const builtin_config_usage[] = {
"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty] | --edit | -e ]"; "git config [options]",
NULL
};
static char *key; static char *key;
static regex_t *key_regexp; static regex_t *key_regexp;
@@ -16,7 +19,67 @@ static int seen;
static char delim = '='; static char delim = '=';
static char key_delim = ' '; static char key_delim = ' ';
static char term = '\n'; static char term = '\n';
static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW;
static int use_global_config, use_system_config;
static const char *given_config_file;
static int actions, types;
static const char *get_color_slot, *get_colorbool_slot;
static int end_null;
#define ACTION_GET (1<<0)
#define ACTION_GET_ALL (1<<1)
#define ACTION_GET_REGEXP (1<<2)
#define ACTION_REPLACE_ALL (1<<3)
#define ACTION_ADD (1<<4)
#define ACTION_UNSET (1<<5)
#define ACTION_UNSET_ALL (1<<6)
#define ACTION_RENAME_SECTION (1<<7)
#define ACTION_REMOVE_SECTION (1<<8)
#define ACTION_LIST (1<<9)
#define ACTION_EDIT (1<<10)
#define ACTION_SET (1<<11)
#define ACTION_SET_ALL (1<<12)
#define ACTION_GET_COLOR (1<<13)
#define ACTION_GET_COLORBOOL (1<<14)
#define TYPE_BOOL (1<<0)
#define TYPE_INT (1<<1)
#define TYPE_BOOL_OR_INT (1<<2)
static struct option builtin_config_options[] = {
OPT_GROUP("Config file location"),
OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"),
OPT_GROUP("Action"),
OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP),
OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL),
OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD),
OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET),
OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL),
OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION),
OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION),
OPT_BIT('l', "list", &actions, "list all", ACTION_LIST),
OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT),
OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"),
OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"),
OPT_GROUP("Type"),
OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL),
OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT),
OPT_GROUP("Other"),
OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
OPT_END(),
};
static void check_argc(int argc, int min, int max) {
if (argc >= min && argc <= max)
return;
error("wrong number of arguments");
usage_with_options(builtin_config_usage, builtin_config_options);
}
static int show_all_config(const char *key_, const char *value_, void *cb) static int show_all_config(const char *key_, const char *value_, void *cb)
{ {
@@ -49,11 +112,11 @@ static int show_config(const char *key_, const char *value_, void *cb)
} }
if (seen && !do_all) if (seen && !do_all)
dup_error = 1; dup_error = 1;
if (type == T_INT) if (types == TYPE_INT)
sprintf(value, "%d", git_config_int(key_, value_?value_:"")); sprintf(value, "%d", git_config_int(key_, value_?value_:""));
else if (type == T_BOOL) else if (types == TYPE_BOOL)
vptr = git_config_bool(key_, value_) ? "true" : "false"; vptr = git_config_bool(key_, value_) ? "true" : "false";
else if (type == T_BOOL_OR_INT) { else if (types == TYPE_BOOL_OR_INT) {
int is_bool, v; int is_bool, v;
v = git_config_bool_or_int(key_, value_, &is_bool); v = git_config_bool_or_int(key_, value_, &is_bool);
if (is_bool) if (is_bool)
@@ -152,18 +215,18 @@ static char *normalize_value(const char *key, const char *value)
if (!value) if (!value)
return NULL; return NULL;
if (type == T_RAW) if (types == 0)
normalized = xstrdup(value); normalized = xstrdup(value);
else { else {
normalized = xmalloc(64); normalized = xmalloc(64);
if (type == T_INT) { if (types == TYPE_INT) {
int v = git_config_int(key, value); int v = git_config_int(key, value);
sprintf(normalized, "%d", v); sprintf(normalized, "%d", v);
} }
else if (type == T_BOOL) else if (types == TYPE_BOOL)
sprintf(normalized, "%s", sprintf(normalized, "%s",
git_config_bool(key, value) ? "true" : "false"); git_config_bool(key, value) ? "true" : "false");
else if (type == T_BOOL_OR_INT) { else if (types == TYPE_BOOL_OR_INT) {
int is_bool, v; int is_bool, v;
v = git_config_bool_or_int(key, value, &is_bool); v = git_config_bool_or_int(key, value, &is_bool);
if (!is_bool) if (!is_bool)
@@ -178,6 +241,7 @@ static char *normalize_value(const char *key, const char *value)
static int get_color_found; static int get_color_found;
static const char *get_color_slot; static const char *get_color_slot;
static const char *get_colorbool_slot;
static char parsed_color[COLOR_MAXLEN]; static char parsed_color[COLOR_MAXLEN];
static int git_get_color_config(const char *var, const char *value, void *cb) static int git_get_color_config(const char *var, const char *value, void *cb)
@@ -191,29 +255,8 @@ static int git_get_color_config(const char *var, const char *value, void *cb)
return 0; return 0;
} }
static int get_color(int argc, const char **argv) static void get_color(const char *def_color)
{ {
/*
* grab the color setting for the given slot from the configuration,
* or parse the default value if missing, and return ANSI color
* escape sequence.
*
* e.g.
* git config --get-color color.diff.whitespace "blue reverse"
*/
const char *def_color = NULL;
switch (argc) {
default:
usage(git_config_set_usage);
case 2:
def_color = argv[1];
/* fallthru */
case 1:
get_color_slot = argv[0];
break;
}
get_color_found = 0; get_color_found = 0;
parsed_color[0] = '\0'; parsed_color[0] = '\0';
git_config(git_get_color_config, NULL); git_config(git_get_color_config, NULL);
@@ -222,7 +265,6 @@ static int get_color(int argc, const char **argv)
color_parse(def_color, "command line", parsed_color); color_parse(def_color, "command line", parsed_color);
fputs(parsed_color, stdout); fputs(parsed_color, stdout);
return 0;
} }
static int stdout_is_tty; static int stdout_is_tty;
@@ -231,7 +273,7 @@ static int get_diff_color_found;
static int git_get_colorbool_config(const char *var, const char *value, static int git_get_colorbool_config(const char *var, const char *value,
void *cb) void *cb)
{ {
if (!strcmp(var, get_color_slot)) { if (!strcmp(var, get_colorbool_slot)) {
get_colorbool_found = get_colorbool_found =
git_config_colorbool(var, value, stdout_is_tty); git_config_colorbool(var, value, stdout_is_tty);
} }
@@ -246,191 +288,188 @@ static int git_get_colorbool_config(const char *var, const char *value,
return 0; return 0;
} }
static int get_colorbool(int argc, const char **argv) static int get_colorbool(int print)
{ {
/*
* git config --get-colorbool <slot> [<stdout-is-tty>]
*
* returns "true" or "false" depending on how <slot>
* is configured.
*/
if (argc == 2)
stdout_is_tty = git_config_bool("command line", argv[1]);
else if (argc == 1)
stdout_is_tty = isatty(1);
else
usage(git_config_set_usage);
get_colorbool_found = -1; get_colorbool_found = -1;
get_diff_color_found = -1; get_diff_color_found = -1;
get_color_slot = argv[0];
git_config(git_get_colorbool_config, NULL); git_config(git_get_colorbool_config, NULL);
if (get_colorbool_found < 0) { if (get_colorbool_found < 0) {
if (!strcmp(get_color_slot, "color.diff")) if (!strcmp(get_colorbool_slot, "color.diff"))
get_colorbool_found = get_diff_color_found; get_colorbool_found = get_diff_color_found;
if (get_colorbool_found < 0) if (get_colorbool_found < 0)
get_colorbool_found = git_use_color_default; get_colorbool_found = git_use_color_default;
} }
if (argc == 1) { if (print) {
return get_colorbool_found ? 0 : 1;
} else {
printf("%s\n", get_colorbool_found ? "true" : "false"); printf("%s\n", get_colorbool_found ? "true" : "false");
return 0; return 0;
} } else
return get_colorbool_found ? 0 : 1;
} }
int cmd_config(int argc, const char **argv, const char *prefix) int cmd_config(int argc, const char **argv, const char *unused_prefix)
{ {
int nongit; int nongit;
char *value; char *value;
const char *file = setup_git_directory_gently(&nongit); const char *prefix = setup_git_directory_gently(&nongit);
config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
while (1 < argc) { argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage,
if (!strcmp(argv[1], "--int")) PARSE_OPT_STOP_AT_NON_OPTION);
type = T_INT;
else if (!strcmp(argv[1], "--bool")) if (use_global_config + use_system_config + !!given_config_file > 1) {
type = T_BOOL; error("only one config file at a time.");
else if (!strcmp(argv[1], "--bool-or-int")) usage_with_options(builtin_config_usage, builtin_config_options);
type = T_BOOL_OR_INT;
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
if (argc != 2)
usage(git_config_set_usage);
if (git_config(show_all_config, NULL) < 0 &&
file && errno)
die("unable to read config file %s: %s", file,
strerror(errno));
return 0;
}
else if (!strcmp(argv[1], "--global")) {
char *home = getenv("HOME");
if (home) {
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
config_exclusive_filename = user_config;
} else {
die("$HOME not set");
}
}
else if (!strcmp(argv[1], "--system"))
config_exclusive_filename = git_etc_gitconfig();
else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
if (argc < 3)
usage(git_config_set_usage);
if (!is_absolute_path(argv[2]) && file)
file = prefix_filename(file, strlen(file),
argv[2]);
else
file = argv[2];
config_exclusive_filename = file;
argc--;
argv++;
}
else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
term = '\0';
delim = '\n';
key_delim = '\n';
}
else if (!strcmp(argv[1], "--rename-section")) {
int ret;
if (argc != 4)
usage(git_config_set_usage);
ret = git_config_rename_section(argv[2], argv[3]);
if (ret < 0)
return ret;
if (ret == 0) {
fprintf(stderr, "No such section!\n");
return 1;
}
return 0;
}
else if (!strcmp(argv[1], "--remove-section")) {
int ret;
if (argc != 3)
usage(git_config_set_usage);
ret = git_config_rename_section(argv[2], NULL);
if (ret < 0)
return ret;
if (ret == 0) {
fprintf(stderr, "No such section!\n");
return 1;
}
return 0;
} else if (!strcmp(argv[1], "--get-color")) {
return get_color(argc-2, argv+2);
} else if (!strcmp(argv[1], "--get-colorbool")) {
return get_colorbool(argc-2, argv+2);
} else if (!strcmp(argv[1], "--edit") || !strcmp(argv[1], "-e")) {
if (argc != 2)
usage(git_config_set_usage);
git_config(git_default_config, NULL);
launch_editor(config_exclusive_filename ?
config_exclusive_filename : git_path("config"),
NULL, NULL);
return 0;
} else
break;
argc--;
argv++;
} }
switch (argc) { if (use_global_config) {
case 2: char *home = getenv("HOME");
return get_value(argv[1], NULL); if (home) {
case 3: char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
if (!strcmp(argv[1], "--unset")) config_exclusive_filename = user_config;
return git_config_set(argv[2], NULL);
else if (!strcmp(argv[1], "--unset-all"))
return git_config_set_multivar(argv[2], NULL, NULL, 1);
else if (!strcmp(argv[1], "--get"))
return get_value(argv[2], NULL);
else if (!strcmp(argv[1], "--get-all")) {
do_all = 1;
return get_value(argv[2], NULL);
} else if (!strcmp(argv[1], "--get-regexp")) {
show_keys = 1;
use_key_regexp = 1;
do_all = 1;
return get_value(argv[2], NULL);
} else { } else {
value = normalize_value(argv[1], argv[2]); die("$HOME not set");
return git_config_set(argv[1], value);
} }
case 4:
if (!strcmp(argv[1], "--unset"))
return git_config_set_multivar(argv[2], NULL, argv[3], 0);
else if (!strcmp(argv[1], "--unset-all"))
return git_config_set_multivar(argv[2], NULL, argv[3], 1);
else if (!strcmp(argv[1], "--get"))
return get_value(argv[2], argv[3]);
else if (!strcmp(argv[1], "--get-all")) {
do_all = 1;
return get_value(argv[2], argv[3]);
} else if (!strcmp(argv[1], "--get-regexp")) {
show_keys = 1;
use_key_regexp = 1;
do_all = 1;
return get_value(argv[2], argv[3]);
} else if (!strcmp(argv[1], "--add")) {
value = normalize_value(argv[2], argv[3]);
return git_config_set_multivar(argv[2], value, "^$", 0);
} else if (!strcmp(argv[1], "--replace-all")) {
value = normalize_value(argv[2], argv[3]);
return git_config_set_multivar(argv[2], value, NULL, 1);
} else {
value = normalize_value(argv[1], argv[2]);
return git_config_set_multivar(argv[1], value, argv[3], 0);
}
case 5:
if (!strcmp(argv[1], "--replace-all")) {
value = normalize_value(argv[2], argv[3]);
return git_config_set_multivar(argv[2], value, argv[4], 1);
}
case 1:
default:
usage(git_config_set_usage);
} }
else if (use_system_config)
config_exclusive_filename = git_etc_gitconfig();
else if (given_config_file) {
if (!is_absolute_path(given_config_file) && prefix)
config_exclusive_filename = prefix_filename(prefix,
strlen(prefix),
argv[2]);
else
config_exclusive_filename = given_config_file;
}
if (end_null) {
term = '\0';
delim = '\n';
key_delim = '\n';
}
if (HAS_MULTI_BITS(types)) {
error("only one type at a time.");
usage_with_options(builtin_config_usage, builtin_config_options);
}
if (get_color_slot)
actions |= ACTION_GET_COLOR;
if (get_colorbool_slot)
actions |= ACTION_GET_COLORBOOL;
if ((get_color_slot || get_colorbool_slot) && types) {
error("--get-color and variable type are incoherent");
usage_with_options(builtin_config_usage, builtin_config_options);
}
if (HAS_MULTI_BITS(actions)) {
error("only one action at a time.");
usage_with_options(builtin_config_usage, builtin_config_options);
}
if (actions == 0)
switch (argc) {
case 1: actions = ACTION_GET; break;
case 2: actions = ACTION_SET; break;
case 3: actions = ACTION_SET_ALL; break;
default:
usage_with_options(builtin_config_usage, builtin_config_options);
}
if (actions == ACTION_LIST) {
check_argc(argc, 0, 0);
if (git_config(show_all_config, NULL) < 0) {
if (config_exclusive_filename)
die("unable to read config file %s: %s",
config_exclusive_filename, strerror(errno));
else
die("error processing config file(s)");
}
}
else if (actions == ACTION_EDIT) {
check_argc(argc, 0, 0);
git_config(git_default_config, NULL);
launch_editor(config_exclusive_filename ?
config_exclusive_filename : git_path("config"),
NULL, NULL);
}
else if (actions == ACTION_SET) {
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
return git_config_set(argv[0], value);
}
else if (actions == ACTION_SET_ALL) {
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar(argv[0], value, argv[2], 0);
}
else if (actions == ACTION_ADD) {
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar(argv[0], value, "^$", 0);
}
else if (actions == ACTION_REPLACE_ALL) {
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
return git_config_set_multivar(argv[0], value, argv[2], 1);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
return get_value(argv[0], argv[1]);
}
else if (actions == ACTION_GET_ALL) {
do_all = 1;
check_argc(argc, 1, 2);
return get_value(argv[0], argv[1]);
}
else if (actions == ACTION_GET_REGEXP) {
show_keys = 1;
use_key_regexp = 1;
do_all = 1;
check_argc(argc, 1, 2);
return get_value(argv[0], argv[1]);
}
else if (actions == ACTION_UNSET) {
check_argc(argc, 1, 2);
if (argc == 2)
return git_config_set_multivar(argv[0], NULL, argv[1], 0);
else
return git_config_set(argv[0], NULL);
}
else if (actions == ACTION_UNSET_ALL) {
check_argc(argc, 1, 2);
return git_config_set_multivar(argv[0], NULL, argv[1], 1);
}
else if (actions == ACTION_RENAME_SECTION) {
int ret;
check_argc(argc, 2, 2);
ret = git_config_rename_section(argv[0], argv[1]);
if (ret < 0)
return ret;
if (ret == 0)
die("No such section!");
}
else if (actions == ACTION_REMOVE_SECTION) {
int ret;
check_argc(argc, 1, 1);
ret = git_config_rename_section(argv[0], NULL);
if (ret < 0)
return ret;
if (ret == 0)
die("No such section!");
}
else if (actions == ACTION_GET_COLOR) {
get_color(argv[0]);
}
else if (actions == ACTION_GET_COLORBOOL) {
if (argc == 1)
stdout_is_tty = git_config_bool("command line", argv[0]);
else if (argc == 0)
stdout_is_tty = isatty(1);
return get_colorbool(argc != 0);
}
return 0; return 0;
} }

View File

@@ -221,7 +221,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
if (message) if (message)
message += 2; message += 2;
if (commit->parents) { if (commit->parents &&
get_object_mark(&commit->parents->item->object) != 0) {
parse_commit(commit->parents->item); parse_commit(commit->parents->item);
diff_tree_sha1(commit->parents->item->tree->object.sha1, diff_tree_sha1(commit->parents->item->tree->object.sha1,
commit->tree->object.sha1, "", &rev->diffopt); commit->tree->object.sha1, "", &rev->diffopt);
@@ -362,7 +363,10 @@ static void get_tags_and_duplicates(struct object_array *pending,
break; break;
case OBJ_TAG: case OBJ_TAG:
tag = (struct tag *)e->item; tag = (struct tag *)e->item;
/* handle nested tags */
while (tag && tag->object.type == OBJ_TAG) { while (tag && tag->object.type == OBJ_TAG) {
parse_object(tag->object.sha1);
string_list_append(full_name, extra_refs)->util = tag; string_list_append(full_name, extra_refs)->util = tag;
tag = (struct tag *)tag->tagged; tag = (struct tag *)tag->tagged;
} }
@@ -375,11 +379,17 @@ static void get_tags_and_duplicates(struct object_array *pending,
case OBJ_BLOB: case OBJ_BLOB:
handle_object(tag->object.sha1); handle_object(tag->object.sha1);
continue; continue;
default: /* OBJ_TAG (nested tags) is already handled */
warning("Tag points to object of unexpected type %s, skipping.",
typename(tag->object.type));
continue;
} }
break; break;
default: default:
die ("Unexpected object of type %s", warning("%s: Unexpected object of type %s, skipping.",
typename(e->item->type)); e->name,
typename(e->item->type));
continue;
} }
if (commit->util) if (commit->util)
/* more than one name for the same object */ /* more than one name for the same object */

View File

@@ -605,7 +605,7 @@ static struct ref *do_fetch_pack(int fd[2],
/* When cloning, it is not unusual to have /* When cloning, it is not unusual to have
* no common commit. * no common commit.
*/ */
fprintf(stderr, "warning: no common commits\n"); warning("no common commits");
if (get_pack(fd, pack_lockfile)) if (get_pack(fd, pack_lockfile))
die("git fetch-pack: fetch failed."); die("git fetch-pack: fetch failed.");
@@ -800,15 +800,13 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
int fd; int fd;
mtime.sec = st.st_mtime; mtime.sec = st.st_mtime;
#ifdef USE_NSEC mtime.nsec = ST_MTIME_NSEC(st);
mtime.usec = st.st_mtim.usec;
#endif
if (stat(shallow, &st)) { if (stat(shallow, &st)) {
if (mtime.sec) if (mtime.sec)
die("shallow file was removed during fetch"); die("shallow file was removed during fetch");
} else if (st.st_mtime != mtime.sec } else if (st.st_mtime != mtime.sec
#ifdef USE_NSEC #ifdef USE_NSEC
|| st.st_mtim.usec != mtime.usec || ST_MTIME_NSEC(st) != mtime.nsec
#endif #endif
) )
die("shallow file was changed during fetch"); die("shallow file was changed during fetch");

View File

@@ -197,11 +197,7 @@ static int update_local_ref(struct ref *ref,
struct commit *current = NULL, *updated; struct commit *current = NULL, *updated;
enum object_type type; enum object_type type;
struct branch *current_branch = branch_get(NULL); struct branch *current_branch = branch_get(NULL);
const char *pretty_ref = ref->name + ( const char *pretty_ref = prettify_ref(ref);
!prefixcmp(ref->name, "refs/heads/") ? 11 :
!prefixcmp(ref->name, "refs/tags/") ? 10 :
!prefixcmp(ref->name, "refs/remotes/") ? 13 :
0);
*display = 0; *display = 0;
type = sha1_object_info(ref->new_sha1, NULL); type = sha1_object_info(ref->new_sha1, NULL);
@@ -544,7 +540,8 @@ static void check_not_current_branch(struct ref *ref_map)
for (; ref_map; ref_map = ref_map->next) for (; ref_map; ref_map = ref_map->next)
if (ref_map->peer_ref && !strcmp(current_branch->refname, if (ref_map->peer_ref && !strcmp(current_branch->refname,
ref_map->peer_ref->name)) ref_map->peer_ref->name))
die("Refusing to fetch into current branch"); die("Refusing to fetch into current branch %s "
"of non-bare repository", current_branch->refname);
} }
static int do_fetch(struct transport *transport, static int do_fetch(struct transport *transport,
@@ -636,6 +633,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
else else
remote = remote_get(argv[0]); remote = remote_get(argv[0]);
if (!remote)
die("Where do you want to fetch from today?");
transport = transport_get(remote, remote->url[0]); transport = transport_get(remote, remote->url[0]);
if (verbosity >= 2) if (verbosity >= 2)
transport->verbose = 1; transport->verbose = 1;
@@ -648,9 +648,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (depth) if (depth)
set_option(TRANS_OPT_DEPTH, depth); set_option(TRANS_OPT_DEPTH, depth);
if (!transport->url)
die("Where do you want to fetch from today?");
if (argc > 1) { if (argc > 1) {
int j = 0; int j = 0;
refs = xcalloc(argc + 1, sizeof(const char *)); refs = xcalloc(argc + 1, sizeof(const char *));

View File

@@ -23,7 +23,7 @@ static const char * const builtin_gc_usage[] = {
}; };
static int pack_refs = 1; static int pack_refs = 1;
static int aggressive_window = -1; static int aggressive_window = 250;
static int gc_auto_threshold = 6700; static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 50; static int gc_auto_pack_limit = 50;
static const char *prune_expire = "2.weeks.ago"; static const char *prune_expire = "2.weeks.ago";
@@ -200,6 +200,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (aggressive) { if (aggressive) {
append_option(argv_repack, "-f", MAX_ADD); append_option(argv_repack, "-f", MAX_ADD);
append_option(argv_repack, "--depth=250", MAX_ADD);
if (aggressive_window > 0) { if (aggressive_window > 0) {
sprintf(buf, "--window=%d", aggressive_window); sprintf(buf, "--window=%d", aggressive_window);
append_option(argv_repack, buf, MAX_ADD); append_option(argv_repack, buf, MAX_ADD);

View File

@@ -22,6 +22,28 @@
static int builtin_grep; static int builtin_grep;
static int grep_config(const char *var, const char *value, void *cb)
{
struct grep_opt *opt = cb;
if (!strcmp(var, "grep.color") || !strcmp(var, "color.grep")) {
opt->color = git_config_colorbool(var, value, -1);
return 0;
}
if (!strcmp(var, "grep.color.external") ||
!strcmp(var, "color.grep.external")) {
return git_config_string(&(opt->color_external), var, value);
}
if (!strcmp(var, "grep.color.match") ||
!strcmp(var, "color.grep.match")) {
if (!value)
return config_error_nonbool(var);
color_parse(value, var, opt->color_match);
return 0;
}
return git_color_default_config(var, value, cb);
}
/* /*
* git grep pathspecs are somewhat different from diff-tree pathspecs; * git grep pathspecs are somewhat different from diff-tree pathspecs;
* pathname wildcards are allowed. * pathname wildcards are allowed.
@@ -269,6 +291,21 @@ static int flush_grep(struct grep_opt *opt,
return status; return status;
} }
static void grep_add_color(struct strbuf *sb, const char *escape_seq)
{
size_t orig_len = sb->len;
while (*escape_seq) {
if (*escape_seq == 'm')
strbuf_addch(sb, ';');
else if (*escape_seq != '\033' && *escape_seq != '[')
strbuf_addch(sb, *escape_seq);
escape_seq++;
}
if (sb->len > orig_len && sb->buf[sb->len - 1] == ';')
strbuf_setlen(sb, sb->len - 1);
}
static int external_grep(struct grep_opt *opt, const char **paths, int cached) static int external_grep(struct grep_opt *opt, const char **paths, int cached)
{ {
int i, nr, argc, hit, len, status; int i, nr, argc, hit, len, status;
@@ -339,6 +376,23 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
push_arg("-e"); push_arg("-e");
push_arg(p->pattern); push_arg(p->pattern);
} }
if (opt->color) {
struct strbuf sb = STRBUF_INIT;
grep_add_color(&sb, opt->color_match);
setenv("GREP_COLOR", sb.buf, 1);
strbuf_reset(&sb);
strbuf_addstr(&sb, "mt=");
grep_add_color(&sb, opt->color_match);
strbuf_addstr(&sb, ":sl=:cx=:fn=:ln=:bn=:se=");
setenv("GREP_COLORS", sb.buf, 1);
strbuf_release(&sb);
if (opt->color_external && strlen(opt->color_external) > 0)
push_arg(opt->color_external);
}
hit = 0; hit = 0;
argc = nr; argc = nr;
@@ -536,6 +590,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.pattern_tail = &opt.pattern_list; opt.pattern_tail = &opt.pattern_list;
opt.regflags = REG_NEWLINE; opt.regflags = REG_NEWLINE;
strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD);
opt.color = -1;
git_config(grep_config, &opt);
if (opt.color == -1)
opt.color = git_use_color_default;
/* /*
* If there is no -- then the paths must exist in the working * If there is no -- then the paths must exist in the working
* tree. If there is no explicit pattern specified with -e or * tree. If there is no explicit pattern specified with -e or
@@ -732,6 +792,14 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.relative = 0; opt.relative = 0;
continue; continue;
} }
if (!strcmp("--color", arg)) {
opt.color = 1;
continue;
}
if (!strcmp("--no-color", arg)) {
opt.color = 0;
continue;
}
if (!strcmp("--", arg)) { if (!strcmp("--", arg)) {
/* later processing wants to have this at argv[1] */ /* later processing wants to have this at argv[1] */
argv--; argv--;
@@ -757,6 +825,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
} }
} }
if (opt.color && !opt.color_external)
builtin_grep = 1;
if (!opt.pattern_list) if (!opt.pattern_list)
die("no pattern given."); die("no pattern given.");
if ((opt.regflags != REG_NEWLINE) && opt.fixed) if ((opt.regflags != REG_NEWLINE) && opt.fixed)

View File

@@ -130,8 +130,7 @@ static void copy_templates(const char *template_dir)
} }
dir = opendir(template_path); dir = opendir(template_path);
if (!dir) { if (!dir) {
fprintf(stderr, "warning: templates not found %s\n", warning("templates not found %s", template_dir);
template_dir);
return; return;
} }
@@ -144,8 +143,8 @@ static void copy_templates(const char *template_dir)
if (repository_format_version && if (repository_format_version &&
repository_format_version != GIT_REPO_VERSION) { repository_format_version != GIT_REPO_VERSION) {
fprintf(stderr, "warning: not copying templates of " warning("not copying templates of "
"a wrong format version %d from '%s'\n", "a wrong format version %d from '%s'",
repository_format_version, repository_format_version,
template_dir); template_dir);
closedir(dir); closedir(dir);

View File

@@ -573,7 +573,7 @@ static FILE *realstdout = NULL;
static const char *output_directory = NULL; static const char *output_directory = NULL;
static int outdir_offset; static int outdir_offset;
static int reopen_stdout(const char *oneline, int nr, int total) static int reopen_stdout(const char *oneline, int nr, struct rev_info *rev)
{ {
char filename[PATH_MAX]; char filename[PATH_MAX];
int len = 0; int len = 0;
@@ -598,7 +598,9 @@ static int reopen_stdout(const char *oneline, int nr, int total)
strcpy(filename + len, fmt_patch_suffix); strcpy(filename + len, fmt_patch_suffix);
} }
fprintf(realstdout, "%s\n", filename + outdir_offset); if (!DIFF_OPT_TST(&rev->diffopt, QUIET))
fprintf(realstdout, "%s\n", filename + outdir_offset);
if (freopen(filename, "w", stdout) == NULL) if (freopen(filename, "w", stdout) == NULL)
return error("Cannot open patch file %s",filename); return error("Cannot open patch file %s",filename);
@@ -687,7 +689,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
die("Cover letter needs email format"); die("Cover letter needs email format");
if (!use_stdout && reopen_stdout(numbered_files ? if (!use_stdout && reopen_stdout(numbered_files ?
NULL : "cover-letter", 0, rev->total)) NULL : "cover-letter", 0, rev))
return; return;
head_sha1 = sha1_to_hex(head->object.sha1); head_sha1 = sha1_to_hex(head->object.sha1);
@@ -916,6 +918,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
cover_letter = 1; cover_letter = 1;
else if (!strcmp(argv[i], "--no-binary")) else if (!strcmp(argv[i], "--no-binary"))
no_binary_diff = 1; no_binary_diff = 1;
else if (!prefixcmp(argv[i], "--add-header="))
add_header(argv[i] + 13);
else else
argv[j++] = argv[i]; argv[j++] = argv[i];
} }
@@ -956,8 +960,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
die ("-n and -k are mutually exclusive."); die ("-n and -k are mutually exclusive.");
if (keep_subject && subject_prefix) if (keep_subject && subject_prefix)
die ("--subject-prefix and -k are mutually exclusive."); die ("--subject-prefix and -k are mutually exclusive.");
if (numbered_files && use_stdout)
die ("--numbered-files and --stdout are mutually exclusive.");
argc = setup_revisions(argc, argv, &rev, "HEAD"); argc = setup_revisions(argc, argv, &rev, "HEAD");
if (argc > 1) if (argc > 1)
@@ -1106,7 +1108,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
} }
if (!use_stdout && reopen_stdout(numbered_files ? NULL : if (!use_stdout && reopen_stdout(numbered_files ? NULL :
get_oneline_for_filename(commit, keep_subject), get_oneline_for_filename(commit, keep_subject),
rev.nr, rev.total)) rev.nr, &rev))
die("Failed to create output files"); die("Failed to create output files");
shown = log_tree_commit(&rev, commit); shown = log_tree_commit(&rev, commit);
free(commit->buffer); free(commit->buffer);

View File

@@ -10,6 +10,7 @@
#include "dir.h" #include "dir.h"
#include "builtin.h" #include "builtin.h"
#include "tree.h" #include "tree.h"
#include "parse-options.h"
static int abbrev; static int abbrev;
static int show_deleted; static int show_deleted;
@@ -28,6 +29,7 @@ static const char **pathspec;
static int error_unmatch; static int error_unmatch;
static char *ps_matched; static char *ps_matched;
static const char *with_tree; static const char *with_tree;
static int exc_given;
static const char *tag_cached = ""; static const char *tag_cached = "";
static const char *tag_unmerged = ""; static const char *tag_unmerged = "";
@@ -174,7 +176,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
for (i = 0; i < active_nr; i++) { for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i]; struct cache_entry *ce = active_cache[i];
int dtype = ce_to_dtype(ce); int dtype = ce_to_dtype(ce);
if (excluded(dir, ce->name, &dtype) != dir->show_ignored) if (excluded(dir, ce->name, &dtype) !=
!!(dir->flags & DIR_SHOW_IGNORED))
continue; continue;
if (show_unmerged && !ce_stage(ce)) if (show_unmerged && !ce_stage(ce))
continue; continue;
@@ -189,7 +192,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
struct stat st; struct stat st;
int err; int err;
int dtype = ce_to_dtype(ce); int dtype = ce_to_dtype(ce);
if (excluded(dir, ce->name, &dtype) != dir->show_ignored) if (excluded(dir, ce->name, &dtype) !=
!!(dir->flags & DIR_SHOW_IGNORED))
continue; continue;
if (ce->ce_flags & CE_UPDATE) if (ce->ce_flags & CE_UPDATE)
continue; continue;
@@ -374,156 +378,139 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
return errors; return errors;
} }
static const char ls_files_usage[] = static const char * const ls_files_usage[] = {
"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* " "git ls-files [options] [<file>]*",
"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] " NULL
"[ --exclude-per-directory=<filename> ] [--exclude-standard] " };
"[--full-name] [--abbrev] [--] [<file>]*";
static int option_parse_z(const struct option *opt,
const char *arg, int unset)
{
line_terminator = unset ? '\n' : '\0';
return 0;
}
static int option_parse_exclude(const struct option *opt,
const char *arg, int unset)
{
struct exclude_list *list = opt->value;
exc_given = 1;
add_exclude(arg, "", 0, list);
return 0;
}
static int option_parse_exclude_from(const struct option *opt,
const char *arg, int unset)
{
struct dir_struct *dir = opt->value;
exc_given = 1;
add_excludes_from_file(dir, arg);
return 0;
}
static int option_parse_exclude_standard(const struct option *opt,
const char *arg, int unset)
{
struct dir_struct *dir = opt->value;
exc_given = 1;
setup_standard_excludes(dir);
return 0;
}
int cmd_ls_files(int argc, const char **argv, const char *prefix) int cmd_ls_files(int argc, const char **argv, const char *prefix)
{ {
int i; int require_work_tree = 0, show_tag = 0;
int exc_given = 0, require_work_tree = 0;
struct dir_struct dir; struct dir_struct dir;
struct option builtin_ls_files_options[] = {
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
"paths are separated with NUL character",
PARSE_OPT_NOARG, option_parse_z },
OPT_BOOLEAN('t', NULL, &show_tag,
"identify the file status with tags"),
OPT_BOOLEAN('v', NULL, &show_valid_bit,
"use lowercase letters for 'assume unchanged' files"),
OPT_BOOLEAN('c', "cached", &show_cached,
"show cached files in the output (default)"),
OPT_BOOLEAN('d', "deleted", &show_deleted,
"show deleted files in the output"),
OPT_BOOLEAN('m', "modified", &show_modified,
"show modified files in the output"),
OPT_BOOLEAN('o', "others", &show_others,
"show other files in the output"),
OPT_BIT('i', "ignored", &dir.flags,
"show ignored files in the output",
DIR_SHOW_IGNORED),
OPT_BOOLEAN('s', "stage", &show_stage,
"show staged contents' object name in the output"),
OPT_BOOLEAN('k', "killed", &show_killed,
"show files on the filesystem that need to be removed"),
OPT_BIT(0, "directory", &dir.flags,
"show 'other' directories' name only",
DIR_SHOW_OTHER_DIRECTORIES),
OPT_BIT(0, "no-empty-directory", &dir.flags,
"don't show empty directories",
DIR_HIDE_EMPTY_DIRECTORIES),
OPT_BOOLEAN('u', "unmerged", &show_unmerged,
"show unmerged files in the output"),
{ OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern",
"skip files matching pattern",
0, option_parse_exclude },
{ OPTION_CALLBACK, 'X', "exclude-from", &dir, "file",
"exclude patterns are read from <file>",
0, option_parse_exclude_from },
OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file",
"read additional per-directory exclude patterns in <file>"),
{ OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
"add the standard git exclusions",
PARSE_OPT_NOARG, option_parse_exclude_standard },
{ OPTION_SET_INT, 0, "full-name", &prefix_offset, NULL,
"make the output relative to the project top directory",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
"if any <file> is not in the index, treat this as an error"),
OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
"pretend that paths removed since <tree-ish> are still present"),
OPT__ABBREV(&abbrev),
OPT_END()
};
memset(&dir, 0, sizeof(dir)); memset(&dir, 0, sizeof(dir));
if (prefix) if (prefix)
prefix_offset = strlen(prefix); prefix_offset = strlen(prefix);
git_config(git_default_config, NULL); git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) { argc = parse_options(argc, argv, builtin_ls_files_options,
const char *arg = argv[i]; ls_files_usage, 0);
if (show_tag || show_valid_bit) {
if (!strcmp(arg, "--")) { tag_cached = "H ";
i++; tag_unmerged = "M ";
break; tag_removed = "R ";
} tag_modified = "C ";
if (!strcmp(arg, "-z")) { tag_other = "? ";
line_terminator = 0; tag_killed = "K ";
continue;
}
if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) {
tag_cached = "H ";
tag_unmerged = "M ";
tag_removed = "R ";
tag_modified = "C ";
tag_other = "? ";
tag_killed = "K ";
if (arg[1] == 'v')
show_valid_bit = 1;
continue;
}
if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
show_cached = 1;
continue;
}
if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
show_deleted = 1;
continue;
}
if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
show_modified = 1;
require_work_tree = 1;
continue;
}
if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
show_others = 1;
require_work_tree = 1;
continue;
}
if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
dir.show_ignored = 1;
require_work_tree = 1;
continue;
}
if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
show_stage = 1;
continue;
}
if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
show_killed = 1;
require_work_tree = 1;
continue;
}
if (!strcmp(arg, "--directory")) {
dir.show_other_directories = 1;
continue;
}
if (!strcmp(arg, "--no-empty-directory")) {
dir.hide_empty_directories = 1;
continue;
}
if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
/* There's no point in showing unmerged unless
* you also show the stage information.
*/
show_stage = 1;
show_unmerged = 1;
continue;
}
if (!strcmp(arg, "-x") && i+1 < argc) {
exc_given = 1;
add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
continue;
}
if (!prefixcmp(arg, "--exclude=")) {
exc_given = 1;
add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
continue;
}
if (!strcmp(arg, "-X") && i+1 < argc) {
exc_given = 1;
add_excludes_from_file(&dir, argv[++i]);
continue;
}
if (!prefixcmp(arg, "--exclude-from=")) {
exc_given = 1;
add_excludes_from_file(&dir, arg+15);
continue;
}
if (!prefixcmp(arg, "--exclude-per-directory=")) {
exc_given = 1;
dir.exclude_per_dir = arg + 24;
continue;
}
if (!strcmp(arg, "--exclude-standard")) {
exc_given = 1;
setup_standard_excludes(&dir);
continue;
}
if (!strcmp(arg, "--full-name")) {
prefix_offset = 0;
continue;
}
if (!strcmp(arg, "--error-unmatch")) {
error_unmatch = 1;
continue;
}
if (!prefixcmp(arg, "--with-tree=")) {
with_tree = arg + 12;
continue;
}
if (!prefixcmp(arg, "--abbrev=")) {
abbrev = strtoul(arg+9, NULL, 10);
if (abbrev && abbrev < MINIMUM_ABBREV)
abbrev = MINIMUM_ABBREV;
else if (abbrev > 40)
abbrev = 40;
continue;
}
if (!strcmp(arg, "--abbrev")) {
abbrev = DEFAULT_ABBREV;
continue;
}
if (*arg == '-')
usage(ls_files_usage);
break;
} }
if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
require_work_tree = 1;
if (show_unmerged)
/*
* There's no point in showing unmerged unless
* you also show the stage information.
*/
show_stage = 1;
if (dir.exclude_per_dir)
exc_given = 1;
if (require_work_tree && !is_inside_work_tree()) if (require_work_tree && !is_inside_work_tree())
setup_work_tree(); setup_work_tree();
pathspec = get_pathspec(prefix, argv + i); pathspec = get_pathspec(prefix, argv);
/* be nice with submodule patsh ending in a slash */ /* be nice with submodule patsh ending in a slash */
read_cache(); read_cache();
@@ -542,7 +529,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
ps_matched = xcalloc(1, num); ps_matched = xcalloc(1, num);
} }
if (dir.show_ignored && !exc_given) { if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) {
fprintf(stderr, "%s: --ignored needs some exclude pattern\n", fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
argv[0]); argv[0]);
exit(1); exit(1);

View File

@@ -60,7 +60,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
{ {
int retval = 0; int retval = 0;
const char *type = blob_type; const char *type = blob_type;
unsigned long size;
if (S_ISGITLINK(mode)) { if (S_ISGITLINK(mode)) {
/* /*
@@ -90,17 +89,20 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
if (!(ls_options & LS_NAME_ONLY)) { if (!(ls_options & LS_NAME_ONLY)) {
if (ls_options & LS_SHOW_SIZE) { if (ls_options & LS_SHOW_SIZE) {
char size_text[24];
if (!strcmp(type, blob_type)) { if (!strcmp(type, blob_type)) {
sha1_object_info(sha1, &size); unsigned long size;
printf("%06o %s %s %7lu\t", mode, type, if (sha1_object_info(sha1, &size) == OBJ_BAD)
abbrev ? find_unique_abbrev(sha1, abbrev) strcpy(size_text, "BAD");
: sha1_to_hex(sha1), else
size); snprintf(size_text, sizeof(size_text),
"%lu", size);
} else } else
printf("%06o %s %s %7c\t", mode, type, strcpy(size_text, "-");
abbrev ? find_unique_abbrev(sha1, abbrev) printf("%06o %s %s %7s\t", mode, type,
: sha1_to_hex(sha1), abbrev ? find_unique_abbrev(sha1, abbrev)
'-'); : sha1_to_hex(sha1),
size_text);
} else } else
printf("%06o %s %s\t", mode, type, printf("%06o %s %s\t", mode, type,
abbrev ? find_unique_abbrev(sha1, abbrev) abbrev ? find_unique_abbrev(sha1, abbrev)

View File

@@ -636,7 +636,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
memset(&dir, 0, sizeof(dir)); memset(&dir, 0, sizeof(dir));
dir.show_ignored = 1; dir.flags |= DIR_SHOW_IGNORED;
dir.exclude_per_dir = ".gitignore"; dir.exclude_per_dir = ".gitignore";
opts.dir = &dir; opts.dir = &dir;

View File

@@ -1293,7 +1293,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
max_size = trg_entry->delta_size; max_size = trg_entry->delta_size;
ref_depth = trg->depth; ref_depth = trg->depth;
} }
max_size = max_size * (max_depth - src->depth) / max_size = (uint64_t)max_size * (max_depth - src->depth) /
(max_depth - ref_depth + 1); (max_depth - ref_depth + 1);
if (max_size == 0) if (max_size == 0)
return 0; return 0;
@@ -1966,7 +1966,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
const unsigned char *sha1; const unsigned char *sha1;
struct object *o; struct object *o;
if (p->pack_keep) if (!p->pack_local || p->pack_keep)
continue; continue;
if (open_pack_index(p)) if (open_pack_index(p))
die("cannot open pack index"); die("cannot open pack index");
@@ -1995,6 +1995,29 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
free(in_pack.array); free(in_pack.array);
} }
static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
{
static struct packed_git *last_found = (void *)1;
struct packed_git *p;
p = (last_found != (void *)1) ? last_found : packed_git;
while (p) {
if ((!p->pack_local || p->pack_keep) &&
find_pack_entry_one(sha1, p)) {
last_found = p;
return 1;
}
if (p == last_found)
p = packed_git;
else
p = p->next;
if (p == last_found)
p = p->next;
}
return 0;
}
static void loosen_unused_packed_objects(struct rev_info *revs) static void loosen_unused_packed_objects(struct rev_info *revs)
{ {
struct packed_git *p; struct packed_git *p;
@@ -2002,7 +2025,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
const unsigned char *sha1; const unsigned char *sha1;
for (p = packed_git; p; p = p->next) { for (p = packed_git; p; p = p->next) {
if (p->pack_keep) if (!p->pack_local || p->pack_keep)
continue; continue;
if (open_pack_index(p)) if (open_pack_index(p))
@@ -2010,7 +2033,8 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
for (i = 0; i < p->num_objects; i++) { for (i = 0; i < p->num_objects; i++) {
sha1 = nth_packed_object_sha1(p, i); sha1 = nth_packed_object_sha1(p, i);
if (!locate_object_entry(sha1)) if (!locate_object_entry(sha1) &&
!has_sha1_pack_kept_or_nonlocal(sha1))
if (force_object_loose(sha1, p->mtime)) if (force_object_loose(sha1, p->mtime))
die("unable to force loose object"); die("unable to force loose object");
} }
@@ -2200,7 +2224,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
continue; continue;
} }
if (!strcmp("--unpacked", arg) || if (!strcmp("--unpacked", arg) ||
!strcmp("--kept-pack-only", arg) ||
!strcmp("--reflog", arg) || !strcmp("--reflog", arg) ||
!strcmp("--all", arg)) { !strcmp("--all", arg)) {
use_internal_rev_list = 1; use_internal_rev_list = 1;

View File

@@ -48,13 +48,81 @@ static void set_refspecs(const char **refs, int nr)
} }
} }
static void setup_push_tracking(void)
{
struct strbuf refspec = STRBUF_INIT;
struct branch *branch = branch_get(NULL);
if (!branch)
die("You are not currently on a branch.");
if (!branch->merge_nr)
die("The current branch %s is not tracking anything.",
branch->name);
if (branch->merge_nr != 1)
die("The current branch %s is tracking multiple branches, "
"refusing to push.", branch->name);
strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
add_refspec(refspec.buf);
}
static const char *warn_unconfigured_push_msg[] = {
"You did not specify any refspecs to push, and the current remote",
"has not configured any push refspecs. The default action in this",
"case is to push all matching refspecs, that is, all branches",
"that exist both locally and remotely will be updated. This may",
"not necessarily be what you want to happen.",
"",
"You can specify what action you want to take in this case, and",
"avoid seeing this message again, by configuring 'push.default' to:",
" 'nothing' : Do not push anything",
" 'matching' : Push all matching branches (default)",
" 'tracking' : Push the current branch to whatever it is tracking",
" 'current' : Push the current branch"
};
static void warn_unconfigured_push(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++)
warning("%s", warn_unconfigured_push_msg[i]);
}
static void setup_default_push_refspecs(void)
{
git_config(git_default_config, NULL);
switch (push_default) {
case PUSH_DEFAULT_UNSPECIFIED:
warn_unconfigured_push();
/* fallthrough */
case PUSH_DEFAULT_MATCHING:
add_refspec(":");
break;
case PUSH_DEFAULT_TRACKING:
setup_push_tracking();
break;
case PUSH_DEFAULT_CURRENT:
add_refspec("HEAD");
break;
case PUSH_DEFAULT_NOTHING:
die("You didn't specify any refspecs to push, and "
"push.default is \"nothing\".");
break;
}
}
static int do_push(const char *repo, int flags) static int do_push(const char *repo, int flags)
{ {
int i, errs; int i, errs;
struct remote *remote = remote_get(repo); struct remote *remote = remote_get(repo);
if (!remote) if (!remote) {
die("bad repository '%s'", repo); if (repo)
die("bad repository '%s'", repo);
die("No destination configured to push to.");
}
if (remote->mirror) if (remote->mirror)
flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE); flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
@@ -76,11 +144,12 @@ static int do_push(const char *repo, int flags)
return error("--all and --mirror are incompatible"); return error("--all and --mirror are incompatible");
} }
if (!refspec if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
&& !(flags & TRANSPORT_PUSH_ALL) if (remote->push_refspec_nr) {
&& remote->push_refspec_nr) { refspec = remote->push_refspec;
refspec = remote->push_refspec; refspec_nr = remote->push_refspec_nr;
refspec_nr = remote->push_refspec_nr; } else if (!(flags & TRANSPORT_PUSH_MIRROR))
setup_default_push_refspecs();
} }
errs = 0; errs = 0;
for (i = 0; i < remote->url_nr; i++) { for (i = 0; i < remote->url_nr; i++) {

View File

@@ -170,7 +170,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
die("more than one --exclude-per-directory are given."); die("more than one --exclude-per-directory are given.");
dir = xcalloc(1, sizeof(*opts.dir)); dir = xcalloc(1, sizeof(*opts.dir));
dir->show_ignored = 1; dir->flags |= DIR_SHOW_IGNORED;
dir->exclude_per_dir = arg + 24; dir->exclude_per_dir = arg + 24;
opts.dir = dir; opts.dir = dir;
/* We do not need to nor want to do read-directory /* We do not need to nor want to do read-directory

View File

@@ -12,12 +12,17 @@ static const char * const builtin_remote_usage[] = {
"git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>", "git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
"git remote rename <old> <new>", "git remote rename <old> <new>",
"git remote rm <name>", "git remote rm <name>",
"git remote set-head <name> [-a | -d | <branch>]",
"git remote show [-n] <name>", "git remote show [-n] <name>",
"git remote prune [-n | --dry-run] <name>", "git remote prune [-n | --dry-run] <name>",
"git remote [-v | --verbose] update [group]", "git remote [-v | --verbose] update [group]",
NULL NULL
}; };
#define GET_REF_STATES (1<<0)
#define GET_HEAD_NAMES (1<<1)
#define GET_PUSH_REF_STATES (1<<2)
static int verbose; static int verbose;
static int show_all(void); static int show_all(void);
@@ -143,8 +148,9 @@ static int add(int argc, const char **argv)
} }
struct branch_info { struct branch_info {
char *remote; char *remote_name;
struct string_list merge; struct string_list merge;
int rebase;
}; };
static struct string_list branch_list; static struct string_list branch_list;
@@ -161,10 +167,11 @@ static const char *abbrev_ref(const char *name, const char *prefix)
static int config_read_branches(const char *key, const char *value, void *cb) static int config_read_branches(const char *key, const char *value, void *cb)
{ {
if (!prefixcmp(key, "branch.")) { if (!prefixcmp(key, "branch.")) {
const char *orig_key = key;
char *name; char *name;
struct string_list_item *item; struct string_list_item *item;
struct branch_info *info; struct branch_info *info;
enum { REMOTE, MERGE } type; enum { REMOTE, MERGE, REBASE } type;
key += 7; key += 7;
if (!postfixcmp(key, ".remote")) { if (!postfixcmp(key, ".remote")) {
@@ -173,6 +180,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)
} else if (!postfixcmp(key, ".merge")) { } else if (!postfixcmp(key, ".merge")) {
name = xstrndup(key, strlen(key) - 6); name = xstrndup(key, strlen(key) - 6);
type = MERGE; type = MERGE;
} else if (!postfixcmp(key, ".rebase")) {
name = xstrndup(key, strlen(key) - 7);
type = REBASE;
} else } else
return 0; return 0;
@@ -182,10 +192,10 @@ static int config_read_branches(const char *key, const char *value, void *cb)
item->util = xcalloc(sizeof(struct branch_info), 1); item->util = xcalloc(sizeof(struct branch_info), 1);
info = item->util; info = item->util;
if (type == REMOTE) { if (type == REMOTE) {
if (info->remote) if (info->remote_name)
warning("more than one branch.%s", key); warning("more than one %s", orig_key);
info->remote = xstrdup(value); info->remote_name = xstrdup(value);
} else { } else if (type == MERGE) {
char *space = strchr(value, ' '); char *space = strchr(value, ' ');
value = abbrev_branch(value); value = abbrev_branch(value);
while (space) { while (space) {
@@ -196,7 +206,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
space = strchr(value, ' '); space = strchr(value, ' ');
} }
string_list_append(xstrdup(value), &info->merge); string_list_append(xstrdup(value), &info->merge);
} } else
info->rebase = git_config_bool(orig_key, value);
} }
return 0; return 0;
} }
@@ -206,12 +217,12 @@ static void read_branches(void)
if (branch_list.nr) if (branch_list.nr)
return; return;
git_config(config_read_branches, NULL); git_config(config_read_branches, NULL);
sort_string_list(&branch_list);
} }
struct ref_states { struct ref_states {
struct remote *remote; struct remote *remote;
struct string_list new, stale, tracked; struct string_list new, stale, tracked, heads, push;
int queried;
}; };
static int handle_one_branch(const char *refname, static int handle_one_branch(const char *refname,
@@ -227,10 +238,8 @@ static int handle_one_branch(const char *refname,
const char *name = abbrev_branch(refspec.src); const char *name = abbrev_branch(refspec.src);
/* symbolic refs pointing nowhere were handled already */ /* symbolic refs pointing nowhere were handled already */
if ((flags & REF_ISSYMREF) || if ((flags & REF_ISSYMREF) ||
unsorted_string_list_has_string(&states->tracked, string_list_has_string(&states->tracked, name) ||
name) || string_list_has_string(&states->new, name))
unsorted_string_list_has_string(&states->new,
name))
return 0; return 0;
item = string_list_append(name, &states->stale); item = string_list_append(name, &states->stale);
item->util = xstrdup(refname); item->util = xstrdup(refname);
@@ -238,39 +247,154 @@ static int handle_one_branch(const char *refname,
return 0; return 0;
} }
static int get_ref_states(const struct ref *ref, struct ref_states *states) static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
{ {
struct ref *fetch_map = NULL, **tail = &fetch_map; struct ref *fetch_map = NULL, **tail = &fetch_map;
struct ref *ref;
int i; int i;
for (i = 0; i < states->remote->fetch_refspec_nr; i++) for (i = 0; i < states->remote->fetch_refspec_nr; i++)
if (get_fetch_map(ref, states->remote->fetch + i, &tail, 1)) if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1))
die("Could not get fetch map for refspec %s", die("Could not get fetch map for refspec %s",
states->remote->fetch_refspec[i]); states->remote->fetch_refspec[i]);
states->new.strdup_strings = states->tracked.strdup_strings = 1; states->new.strdup_strings = states->tracked.strdup_strings = 1;
for (ref = fetch_map; ref; ref = ref->next) { for (ref = fetch_map; ref; ref = ref->next) {
struct string_list *target = &states->tracked;
unsigned char sha1[20]; unsigned char sha1[20];
void *util = NULL;
if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1)) if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))
target = &states->new; string_list_append(abbrev_branch(ref->name), &states->new);
else { else
target = &states->tracked; string_list_append(abbrev_branch(ref->name), &states->tracked);
if (hashcmp(sha1, ref->new_sha1))
util = &states;
}
string_list_append(abbrev_branch(ref->name), target)->util = util;
} }
free_refs(fetch_map); free_refs(fetch_map);
sort_string_list(&states->new);
sort_string_list(&states->tracked);
for_each_ref(handle_one_branch, states); for_each_ref(handle_one_branch, states);
sort_string_list(&states->stale); sort_string_list(&states->stale);
return 0; return 0;
} }
struct push_info {
char *dest;
int forced;
enum {
PUSH_STATUS_CREATE = 0,
PUSH_STATUS_DELETE,
PUSH_STATUS_UPTODATE,
PUSH_STATUS_FASTFORWARD,
PUSH_STATUS_OUTOFDATE,
PUSH_STATUS_NOTQUERIED,
} status;
};
static int get_push_ref_states(const struct ref *remote_refs,
struct ref_states *states)
{
struct remote *remote = states->remote;
struct ref *ref, *local_refs, *push_map, **push_tail;
if (remote->mirror)
return 0;
local_refs = get_local_heads();
ref = push_map = copy_ref_list(remote_refs);
while (ref->next)
ref = ref->next;
push_tail = &ref->next;
match_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr,
remote->push_refspec, MATCH_REFS_NONE);
states->push.strdup_strings = 1;
for (ref = push_map; ref; ref = ref->next) {
struct string_list_item *item;
struct push_info *info;
if (!ref->peer_ref)
continue;
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
item = string_list_append(abbrev_branch(ref->peer_ref->name),
&states->push);
item->util = xcalloc(sizeof(struct push_info), 1);
info = item->util;
info->forced = ref->force;
info->dest = xstrdup(abbrev_branch(ref->name));
if (is_null_sha1(ref->new_sha1)) {
info->status = PUSH_STATUS_DELETE;
} else if (!hashcmp(ref->old_sha1, ref->new_sha1))
info->status = PUSH_STATUS_UPTODATE;
else if (is_null_sha1(ref->old_sha1))
info->status = PUSH_STATUS_CREATE;
else if (has_sha1_file(ref->old_sha1) &&
ref_newer(ref->new_sha1, ref->old_sha1))
info->status = PUSH_STATUS_FASTFORWARD;
else
info->status = PUSH_STATUS_OUTOFDATE;
}
free_refs(local_refs);
free_refs(push_map);
return 0;
}
static int get_push_ref_states_noquery(struct ref_states *states)
{
int i;
struct remote *remote = states->remote;
struct string_list_item *item;
struct push_info *info;
if (remote->mirror)
return 0;
states->push.strdup_strings = 1;
if (!remote->push_refspec_nr) {
item = string_list_append("(matching)", &states->push);
info = item->util = xcalloc(sizeof(struct push_info), 1);
info->status = PUSH_STATUS_NOTQUERIED;
info->dest = xstrdup(item->string);
}
for (i = 0; i < remote->push_refspec_nr; i++) {
struct refspec *spec = remote->push + i;
if (spec->matching)
item = string_list_append("(matching)", &states->push);
else if (strlen(spec->src))
item = string_list_append(spec->src, &states->push);
else
item = string_list_append("(delete)", &states->push);
info = item->util = xcalloc(sizeof(struct push_info), 1);
info->forced = spec->force;
info->status = PUSH_STATUS_NOTQUERIED;
info->dest = xstrdup(spec->dst ? spec->dst : item->string);
}
return 0;
}
static int get_head_names(const struct ref *remote_refs, struct ref_states *states)
{
struct ref *ref, *matches;
struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
struct refspec refspec;
refspec.force = 0;
refspec.pattern = 1;
refspec.src = refspec.dst = "refs/heads/*";
states->heads.strdup_strings = 1;
get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
fetch_map, 1);
for(ref = matches; ref; ref = ref->next)
string_list_append(abbrev_branch(ref->name), &states->heads);
free_refs(fetch_map);
free_refs(matches);
return 0;
}
struct known_remote { struct known_remote {
struct known_remote *next; struct known_remote *next;
struct remote *remote; struct remote *remote;
@@ -466,7 +590,7 @@ static int mv(int argc, const char **argv)
for (i = 0; i < branch_list.nr; i++) { for (i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i; struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util; struct branch_info *info = item->util;
if (info->remote && !strcmp(info->remote, rename.old)) { if (info->remote_name && !strcmp(info->remote_name, rename.old)) {
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.remote", item->string); strbuf_addf(&buf, "branch.%s.remote", item->string);
if (git_config_set(buf.buf, rename.new)) { if (git_config_set(buf.buf, rename.new)) {
@@ -575,7 +699,7 @@ static int rm(int argc, const char **argv)
for (i = 0; i < branch_list.nr; i++) { for (i = 0; i < branch_list.nr; i++) {
struct string_list_item *item = branch_list.items + i; struct string_list_item *item = branch_list.items + i;
struct branch_info *info = item->util; struct branch_info *info = item->util;
if (info->remote && !strcmp(info->remote, remote->name)) { if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
const char *keys[] = { "remote", "merge", NULL }, **k; const char *keys[] = { "remote", "merge", NULL }, **k;
for (k = keys; *k; k++) { for (k = keys; *k; k++) {
strbuf_reset(&buf); strbuf_reset(&buf);
@@ -617,18 +741,37 @@ static int rm(int argc, const char **argv)
return result; return result;
} }
static void show_list(const char *title, struct string_list *list, void clear_push_info(void *util, const char *string)
const char *extra_arg)
{ {
int i; struct push_info *info = util;
free(info->dest);
free(info);
}
if (!list->nr) static void free_remote_ref_states(struct ref_states *states)
return; {
string_list_clear(&states->new, 0);
string_list_clear(&states->stale, 0);
string_list_clear(&states->tracked, 0);
string_list_clear(&states->heads, 0);
string_list_clear_func(&states->push, clear_push_info);
}
printf(title, list->nr > 1 ? "es" : "", extra_arg); static int append_ref_to_tracked_list(const char *refname,
printf("\n"); const unsigned char *sha1, int flags, void *cb_data)
for (i = 0; i < list->nr; i++) {
printf(" %s\n", list->items[i].string); struct ref_states *states = cb_data;
struct refspec refspec;
if (flags & REF_ISSYMREF)
return 0;
memset(&refspec, 0, sizeof(refspec));
refspec.dst = (char *)refname;
if (!remote_find_tracking(states->remote, &refspec))
string_list_append(abbrev_branch(refspec.src), &states->tracked);
return 0;
} }
static int get_remote_ref_states(const char *name, static int get_remote_ref_states(const char *name,
@@ -636,7 +779,7 @@ static int get_remote_ref_states(const char *name,
int query) int query)
{ {
struct transport *transport; struct transport *transport;
const struct ref *ref; const struct ref *remote_refs;
states->remote = remote_get(name); states->remote = remote_get(name);
if (!states->remote) if (!states->remote)
@@ -647,105 +790,336 @@ static int get_remote_ref_states(const char *name,
if (query) { if (query) {
transport = transport_get(NULL, states->remote->url_nr > 0 ? transport = transport_get(NULL, states->remote->url_nr > 0 ?
states->remote->url[0] : NULL); states->remote->url[0] : NULL);
ref = transport_get_remote_refs(transport); remote_refs = transport_get_remote_refs(transport);
transport_disconnect(transport); transport_disconnect(transport);
get_ref_states(ref, states); states->queried = 1;
if (query & GET_REF_STATES)
get_ref_states(remote_refs, states);
if (query & GET_HEAD_NAMES)
get_head_names(remote_refs, states);
if (query & GET_PUSH_REF_STATES)
get_push_ref_states(remote_refs, states);
} else {
for_each_ref(append_ref_to_tracked_list, states);
sort_string_list(&states->tracked);
get_push_ref_states_noquery(states);
} }
return 0; return 0;
} }
static int append_ref_to_tracked_list(const char *refname, struct show_info {
const unsigned char *sha1, int flags, void *cb_data) struct string_list *list;
struct ref_states *states;
int width, width2;
int any_rebase;
};
int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
{ {
struct ref_states *states = cb_data; struct show_info *info = cb_data;
struct refspec refspec; int n = strlen(item->string);
if (n > info->width)
info->width = n;
string_list_insert(item->string, info->list);
return 0;
}
memset(&refspec, 0, sizeof(refspec)); int show_remote_info_item(struct string_list_item *item, void *cb_data)
refspec.dst = (char *)refname; {
if (!remote_find_tracking(states->remote, &refspec)) struct show_info *info = cb_data;
string_list_append(abbrev_branch(refspec.src), &states->tracked); struct ref_states *states = info->states;
const char *name = item->string;
if (states->queried) {
const char *fmt = "%s";
const char *arg = "";
if (string_list_has_string(&states->new, name)) {
fmt = " new (next fetch will store in remotes/%s)";
arg = states->remote->name;
} else if (string_list_has_string(&states->tracked, name))
arg = " tracked";
else if (string_list_has_string(&states->stale, name))
arg = " stale (use 'git remote prune' to remove)";
else
arg = " ???";
printf(" %-*s", info->width, name);
printf(fmt, arg);
printf("\n");
} else
printf(" %s\n", name);
return 0;
}
int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct ref_states *states = show_info->states;
struct branch_info *branch_info = branch_item->util;
struct string_list_item *item;
int n;
if (!branch_info->merge.nr || !branch_info->remote_name ||
strcmp(states->remote->name, branch_info->remote_name))
return 0;
if ((n = strlen(branch_item->string)) > show_info->width)
show_info->width = n;
if (branch_info->rebase)
show_info->any_rebase = 1;
item = string_list_insert(branch_item->string, show_info->list);
item->util = branch_info;
return 0;
}
int show_local_info_item(struct string_list_item *item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct branch_info *branch_info = item->util;
struct string_list *merge = &branch_info->merge;
const char *also;
int i;
if (branch_info->rebase && branch_info->merge.nr > 1) {
error("invalid branch.%s.merge; cannot rebase onto > 1 branch",
item->string);
return 0;
}
printf(" %-*s ", show_info->width, item->string);
if (branch_info->rebase) {
printf("rebases onto remote %s\n", merge->items[0].string);
return 0;
} else if (show_info->any_rebase) {
printf(" merges with remote %s\n", merge->items[0].string);
also = " and with remote";
} else {
printf("merges with remote %s\n", merge->items[0].string);
also = " and with remote";
}
for (i = 1; i < merge->nr; i++)
printf(" %-*s %s %s\n", show_info->width, "", also,
merge->items[i].string);
return 0;
}
int add_push_to_show_info(struct string_list_item *push_item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct push_info *push_info = push_item->util;
struct string_list_item *item;
int n;
if ((n = strlen(push_item->string)) > show_info->width)
show_info->width = n;
if ((n = strlen(push_info->dest)) > show_info->width2)
show_info->width2 = n;
item = string_list_append(push_item->string, show_info->list);
item->util = push_item->util;
return 0;
}
/*
* Sorting comparison for a string list that has push_info
* structs in its util field
*/
static int cmp_string_with_push(const void *va, const void *vb)
{
const struct string_list_item *a = va;
const struct string_list_item *b = vb;
const struct push_info *a_push = a->util;
const struct push_info *b_push = b->util;
int cmp = strcmp(a->string, b->string);
return cmp ? cmp : strcmp(a_push->dest, b_push->dest);
}
int show_push_info_item(struct string_list_item *item, void *cb_data)
{
struct show_info *show_info = cb_data;
struct push_info *push_info = item->util;
char *src = item->string, *status = NULL;
switch (push_info->status) {
case PUSH_STATUS_CREATE:
status = "create";
break;
case PUSH_STATUS_DELETE:
status = "delete";
src = "(none)";
break;
case PUSH_STATUS_UPTODATE:
status = "up to date";
break;
case PUSH_STATUS_FASTFORWARD:
status = "fast forwardable";
break;
case PUSH_STATUS_OUTOFDATE:
status = "local out of date";
break;
case PUSH_STATUS_NOTQUERIED:
break;
}
if (status)
printf(" %-*s %s to %-*s (%s)\n", show_info->width, src,
push_info->forced ? "forces" : "pushes",
show_info->width2, push_info->dest, status);
else
printf(" %-*s %s to %s\n", show_info->width, src,
push_info->forced ? "forces" : "pushes",
push_info->dest);
return 0; return 0;
} }
static int show(int argc, const char **argv) static int show(int argc, const char **argv)
{ {
int no_query = 0, result = 0; int no_query = 0, result = 0, query_flag = 0;
struct option options[] = { struct option options[] = {
OPT_GROUP("show specific options"), OPT_GROUP("show specific options"),
OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"), OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
OPT_END() OPT_END()
}; };
struct ref_states states; struct ref_states states;
struct string_list info_list = { NULL, 0, 0, 0 };
struct show_info info;
argc = parse_options(argc, argv, options, builtin_remote_usage, 0); argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
if (argc < 1) if (argc < 1)
return show_all(); return show_all();
if (!no_query)
query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);
memset(&states, 0, sizeof(states)); memset(&states, 0, sizeof(states));
memset(&info, 0, sizeof(info));
info.states = &states;
info.list = &info_list;
for (; argc; argc--, argv++) { for (; argc; argc--, argv++) {
int i; int i;
get_remote_ref_states(*argv, &states, !no_query); get_remote_ref_states(*argv, &states, query_flag);
printf("* remote %s\n URL: %s\n", *argv, printf("* remote %s\n URL: %s\n", *argv,
states.remote->url_nr > 0 ? states.remote->url_nr > 0 ?
states.remote->url[0] : "(no URL)"); states.remote->url[0] : "(no URL)");
for (i = 0; i < branch_list.nr; i++) {
struct string_list_item *branch = branch_list.items + i;
struct branch_info *info = branch->util;
int j;
if (!info->merge.nr || strcmp(*argv, info->remote))
continue;
printf(" Remote branch%s merged with 'git pull' "
"while on branch %s\n ",
info->merge.nr > 1 ? "es" : "",
branch->string);
for (j = 0; j < info->merge.nr; j++)
printf(" %s", info->merge.items[j].string);
printf("\n");
}
if (!no_query) {
show_list(" New remote branch%s (next fetch "
"will store in remotes/%s)",
&states.new, states.remote->name);
show_list(" Stale tracking branch%s (use 'git remote "
"prune')", &states.stale, "");
}
if (no_query) if (no_query)
for_each_ref(append_ref_to_tracked_list, &states); printf(" HEAD branch: (not queried)\n");
show_list(" Tracked remote branch%s", &states.tracked, ""); else if (!states.heads.nr)
printf(" HEAD branch: (unknown)\n");
if (states.remote->push_refspec_nr) { else if (states.heads.nr == 1)
printf(" Local branch%s pushed with 'git push'\n", printf(" HEAD branch: %s\n", states.heads.items[0].string);
states.remote->push_refspec_nr > 1 ? else {
"es" : ""); printf(" HEAD branch (remote HEAD is ambiguous,"
for (i = 0; i < states.remote->push_refspec_nr; i++) { " may be one of the following):\n");
struct refspec *spec = states.remote->push + i; for (i = 0; i < states.heads.nr; i++)
printf(" %s%s%s%s\n", printf(" %s\n", states.heads.items[i].string);
spec->force ? "+" : "",
abbrev_branch(spec->src),
spec->dst ? ":" : "",
spec->dst ? abbrev_branch(spec->dst) : "");
}
} }
/* NEEDSWORK: free remote */ /* remote branch info */
string_list_clear(&states.new, 0); info.width = 0;
string_list_clear(&states.stale, 0); for_each_string_list(add_remote_to_show_info, &states.new, &info);
string_list_clear(&states.tracked, 0); for_each_string_list(add_remote_to_show_info, &states.tracked, &info);
for_each_string_list(add_remote_to_show_info, &states.stale, &info);
if (info.list->nr)
printf(" Remote branch%s:%s\n",
info.list->nr > 1 ? "es" : "",
no_query ? " (status not queried)" : "");
for_each_string_list(show_remote_info_item, info.list, &info);
string_list_clear(info.list, 0);
/* git pull info */
info.width = 0;
info.any_rebase = 0;
for_each_string_list(add_local_to_show_info, &branch_list, &info);
if (info.list->nr)
printf(" Local branch%s configured for 'git pull':\n",
info.list->nr > 1 ? "es" : "");
for_each_string_list(show_local_info_item, info.list, &info);
string_list_clear(info.list, 0);
/* git push info */
if (states.remote->mirror)
printf(" Local refs will be mirrored by 'git push'\n");
info.width = info.width2 = 0;
for_each_string_list(add_push_to_show_info, &states.push, &info);
qsort(info.list->items, info.list->nr,
sizeof(*info.list->items), cmp_string_with_push);
if (info.list->nr)
printf(" Local ref%s configured for 'git push'%s:\n",
info.list->nr > 1 ? "s" : "",
no_query ? " (status not queried)" : "");
for_each_string_list(show_push_info_item, info.list, &info);
string_list_clear(info.list, 0);
free_remote_ref_states(&states);
} }
return result; return result;
} }
static int set_head(int argc, const char **argv)
{
int i, opt_a = 0, opt_d = 0, result = 0;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
char *head_name = NULL;
struct option options[] = {
OPT_GROUP("set-head specific options"),
OPT_BOOLEAN('a', "auto", &opt_a,
"set refs/remotes/<name>/HEAD according to remote"),
OPT_BOOLEAN('d', "delete", &opt_d,
"delete refs/remotes/<name>/HEAD"),
OPT_END()
};
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
if (argc)
strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
if (!opt_a && !opt_d && argc == 2) {
head_name = xstrdup(argv[1]);
} else if (opt_a && !opt_d && argc == 1) {
struct ref_states states;
memset(&states, 0, sizeof(states));
get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
if (!states.heads.nr)
result |= error("Cannot determine remote HEAD");
else if (states.heads.nr > 1) {
result |= error("Multiple remote HEAD branches. "
"Please choose one explicitly with:");
for (i = 0; i < states.heads.nr; i++)
fprintf(stderr, " git remote set-head %s %s\n",
argv[0], states.heads.items[i].string);
} else
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
if (delete_ref(buf.buf, NULL, REF_NODEREF))
result |= error("Could not delete %s", buf.buf);
} else
usage_with_options(builtin_remote_usage, options);
if (head_name) {
unsigned char sha1[20];
strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name);
/* make sure it's valid */
if (!resolve_ref(buf2.buf, sha1, 1, NULL))
result |= error("Not a valid ref: %s", buf2.buf);
else if (create_symref(buf.buf, buf2.buf, "remote set-head"))
result |= error("Could not setup %s", buf.buf);
if (opt_a)
printf("%s/HEAD set to %s\n", argv[0], head_name);
free(head_name);
}
strbuf_release(&buf);
strbuf_release(&buf2);
return result;
}
static int prune(int argc, const char **argv) static int prune(int argc, const char **argv)
{ {
int dry_run = 0, result = 0; int dry_run = 0, result = 0;
@@ -770,7 +1144,7 @@ static int prune(int argc, const char **argv)
for (; argc; argc--, argv++) { for (; argc; argc--, argv++) {
int i; int i;
get_remote_ref_states(*argv, &states, 1); get_remote_ref_states(*argv, &states, GET_REF_STATES);
if (states.stale.nr) { if (states.stale.nr) {
printf("Pruning %s\n", *argv); printf("Pruning %s\n", *argv);
@@ -791,10 +1165,7 @@ static int prune(int argc, const char **argv)
warn_dangling_symref(dangling_msg, refname); warn_dangling_symref(dangling_msg, refname);
} }
/* NEEDSWORK: free remote */ free_remote_ref_states(&states);
string_list_clear(&states.new, 0);
string_list_clear(&states.stale, 0);
string_list_clear(&states.tracked, 0);
} }
return result; return result;
@@ -919,6 +1290,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
result = mv(argc, argv); result = mv(argc, argv);
else if (!strcmp(argv[0], "rm")) else if (!strcmp(argv[0], "rm"))
result = rm(argc, argv); result = rm(argc, argv);
else if (!strcmp(argv[0], "set-head"))
result = set_head(argc, argv);
else if (!strcmp(argv[0], "show")) else if (!strcmp(argv[0], "show"))
result = show(argc, argv); result = show(argc, argv);
else if (!strcmp(argv[0], "prune")) else if (!strcmp(argv[0], "prune"))

View File

@@ -59,8 +59,7 @@ static int check_local_mod(unsigned char *head, int index_only)
if (lstat(ce->name, &st) < 0) { if (lstat(ce->name, &st) < 0) {
if (errno != ENOENT) if (errno != ENOENT)
fprintf(stderr, "warning: '%s': %s", warning("'%s': %s", ce->name, strerror(errno));
ce->name, strerror(errno));
/* It already vanished from the working tree */ /* It already vanished from the working tree */
continue; continue;
} }

View File

@@ -1,6 +1,5 @@
#include "cache.h" #include "cache.h"
#include "commit.h" #include "commit.h"
#include "tag.h"
#include "refs.h" #include "refs.h"
#include "pkt-line.h" #include "pkt-line.h"
#include "run-command.h" #include "run-command.h"
@@ -11,9 +10,7 @@ static const char send_pack_usage[] =
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
" --all and explicit <ref> specification are mutually exclusive."; " --all and explicit <ref> specification are mutually exclusive.";
static struct send_pack_args args = { static struct send_pack_args args;
/* .receivepack = */ "git-receive-pack",
};
static int feed_object(const unsigned char *sha1, int fd, int negative) static int feed_object(const unsigned char *sha1, int fd, int negative)
{ {
@@ -32,7 +29,7 @@ static int feed_object(const unsigned char *sha1, int fd, int negative)
/* /*
* Make a pack stream and spit it out into file descriptor fd * Make a pack stream and spit it out into file descriptor fd
*/ */
static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra) static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
{ {
/* /*
* The child becomes pack-objects --revs; we feed * The child becomes pack-objects --revs; we feed
@@ -50,7 +47,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
struct child_process po; struct child_process po;
int i; int i;
if (args.use_thin_pack) if (args->use_thin_pack)
argv[4] = "--thin"; argv[4] = "--thin";
memset(&po, 0, sizeof(po)); memset(&po, 0, sizeof(po));
po.argv = argv; po.argv = argv;
@@ -84,82 +81,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
return 0; return 0;
} }
static void unmark_and_free(struct commit_list *list, unsigned int mark)
{
while (list) {
struct commit_list *temp = list;
temp->item->object.flags &= ~mark;
list = temp->next;
free(temp);
}
}
static int ref_newer(const unsigned char *new_sha1,
const unsigned char *old_sha1)
{
struct object *o;
struct commit *old, *new;
struct commit_list *list, *used;
int found = 0;
/* Both new and old must be commit-ish and new is descendant of
* old. Otherwise we require --force.
*/
o = deref_tag(parse_object(old_sha1), NULL, 0);
if (!o || o->type != OBJ_COMMIT)
return 0;
old = (struct commit *) o;
o = deref_tag(parse_object(new_sha1), NULL, 0);
if (!o || o->type != OBJ_COMMIT)
return 0;
new = (struct commit *) o;
if (parse_commit(new) < 0)
return 0;
used = list = NULL;
commit_list_insert(new, &list);
while (list) {
new = pop_most_recent_commit(&list, 1);
commit_list_insert(new, &used);
if (new == old) {
found = 1;
break;
}
}
unmark_and_free(list, 1);
unmark_and_free(used, 1);
return found;
}
static struct ref *local_refs, **local_tail;
static struct ref *remote_refs, **remote_tail;
static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
struct ref *ref;
int len;
/* we already know it starts with refs/ to get here */
if (check_ref_format(refname + 5))
return 0;
len = strlen(refname) + 1;
ref = xcalloc(1, sizeof(*ref) + len);
hashcpy(ref->new_sha1, sha1);
memcpy(ref->name, refname, len);
*local_tail = ref;
local_tail = &ref->next;
return 0;
}
static void get_local_heads(void)
{
local_tail = &local_refs;
for_each_ref(one_local_ref, NULL);
}
static int receive_status(int in, struct ref *refs) static int receive_status(int in, struct ref *refs)
{ {
struct ref *hint; struct ref *hint;
@@ -247,16 +168,6 @@ static void update_tracking_ref(struct remote *remote, struct ref *ref)
} }
} }
static const char *prettify_ref(const struct ref *ref)
{
const char *name = ref->name;
return name + (
!prefixcmp(name, "refs/heads/") ? 11 :
!prefixcmp(name, "refs/tags/") ? 10 :
!prefixcmp(name, "refs/remotes/") ? 13 :
0);
}
#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg) static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
@@ -385,27 +296,19 @@ static int refs_pushed(struct ref *ref)
return 0; return 0;
} }
static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec) int send_pack(struct send_pack_args *args,
int fd[], struct child_process *conn,
struct ref *remote_refs,
struct extra_have_objects *extra_have)
{ {
int in = fd[0];
int out = fd[1];
struct ref *ref; struct ref *ref;
int new_refs; int new_refs;
int ask_for_status_report = 0; int ask_for_status_report = 0;
int allow_deleting_refs = 0; int allow_deleting_refs = 0;
int expect_status_report = 0; int expect_status_report = 0;
int flags = MATCH_REFS_NONE;
int ret; int ret;
struct extra_have_objects extra_have;
memset(&extra_have, 0, sizeof(extra_have));
if (args.send_all)
flags |= MATCH_REFS_ALL;
if (args.send_mirror)
flags |= MATCH_REFS_MIRROR;
/* No funny business with the matcher */
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
&extra_have);
get_local_heads();
/* Does the other end support the reporting? */ /* Does the other end support the reporting? */
if (server_supports("report-status")) if (server_supports("report-status"))
@@ -413,19 +316,9 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (server_supports("delete-refs")) if (server_supports("delete-refs"))
allow_deleting_refs = 1; allow_deleting_refs = 1;
/* match them up */
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
nr_refspec, refspec, flags)) {
close(out);
return -1;
}
if (!remote_refs) { if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n" fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
"Perhaps you should specify a branch such as 'master'.\n"); "Perhaps you should specify a branch such as 'master'.\n");
close(out);
return 0; return 0;
} }
@@ -437,7 +330,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (ref->peer_ref) if (ref->peer_ref)
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
else if (!args.send_mirror) else if (!args->send_mirror)
continue; continue;
ref->deletion = is_null_sha1(ref->new_sha1); ref->deletion = is_null_sha1(ref->new_sha1);
@@ -476,7 +369,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
(!has_sha1_file(ref->old_sha1) (!has_sha1_file(ref->old_sha1)
|| !ref_newer(ref->new_sha1, ref->old_sha1)); || !ref_newer(ref->new_sha1, ref->old_sha1));
if (ref->nonfastforward && !ref->force && !args.force_update) { if (ref->nonfastforward && !ref->force && !args->force_update) {
ref->status = REF_STATUS_REJECT_NONFASTFORWARD; ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
continue; continue;
} }
@@ -484,7 +377,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
if (!ref->deletion) if (!ref->deletion)
new_refs++; new_refs++;
if (!args.dry_run) { if (!args->dry_run) {
char *old_hex = sha1_to_hex(ref->old_sha1); char *old_hex = sha1_to_hex(ref->old_sha1);
char *new_hex = sha1_to_hex(ref->new_sha1); char *new_hex = sha1_to_hex(ref->new_sha1);
@@ -505,27 +398,19 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
} }
packet_flush(out); packet_flush(out);
if (new_refs && !args.dry_run) { if (new_refs && !args->dry_run) {
if (pack_objects(out, remote_refs, &extra_have) < 0) if (pack_objects(out, remote_refs, extra_have, args) < 0) {
for (ref = remote_refs; ref; ref = ref->next)
ref->status = REF_STATUS_NONE;
return -1; return -1;
}
} }
else
close(out);
if (expect_status_report) if (expect_status_report)
ret = receive_status(in, remote_refs); ret = receive_status(in, remote_refs);
else else
ret = 0; ret = 0;
print_push_status(dest, remote_refs);
if (!args.dry_run && remote) {
for (ref = remote_refs; ref; ref = ref->next)
update_tracking_ref(remote, ref);
}
if (!refs_pushed(remote_refs))
fprintf(stderr, "Everything up-to-date\n");
if (ret < 0) if (ret < 0)
return ret; return ret;
for (ref = remote_refs; ref; ref = ref->next) { for (ref = remote_refs; ref; ref = ref->next) {
@@ -574,11 +459,19 @@ static void verify_remote_names(int nr_heads, const char **heads)
int cmd_send_pack(int argc, const char **argv, const char *prefix) int cmd_send_pack(int argc, const char **argv, const char *prefix)
{ {
int i, nr_heads = 0; int i, nr_refspecs = 0;
const char **heads = NULL; const char **refspecs = NULL;
const char *remote_name = NULL; const char *remote_name = NULL;
struct remote *remote = NULL; struct remote *remote = NULL;
const char *dest = NULL; const char *dest = NULL;
int fd[2];
struct child_process *conn;
struct extra_have_objects extra_have;
struct ref *remote_refs, **remote_tail, *local_refs;
int ret;
int send_all = 0;
const char *receivepack = "git-receive-pack";
int flags;
argv++; argv++;
for (i = 1; i < argc; i++, argv++) { for (i = 1; i < argc; i++, argv++) {
@@ -586,11 +479,11 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
if (*arg == '-') { if (*arg == '-') {
if (!prefixcmp(arg, "--receive-pack=")) { if (!prefixcmp(arg, "--receive-pack=")) {
args.receivepack = arg + 15; receivepack = arg + 15;
continue; continue;
} }
if (!prefixcmp(arg, "--exec=")) { if (!prefixcmp(arg, "--exec=")) {
args.receivepack = arg + 7; receivepack = arg + 7;
continue; continue;
} }
if (!prefixcmp(arg, "--remote=")) { if (!prefixcmp(arg, "--remote=")) {
@@ -598,7 +491,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
continue; continue;
} }
if (!strcmp(arg, "--all")) { if (!strcmp(arg, "--all")) {
args.send_all = 1; send_all = 1;
continue; continue;
} }
if (!strcmp(arg, "--dry-run")) { if (!strcmp(arg, "--dry-run")) {
@@ -627,8 +520,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
dest = arg; dest = arg;
continue; continue;
} }
heads = (const char **) argv; refspecs = (const char **) argv;
nr_heads = argc - i; nr_refspecs = argc - i;
break; break;
} }
if (!dest) if (!dest)
@@ -637,8 +530,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
* --all and --mirror are incompatible; neither makes sense * --all and --mirror are incompatible; neither makes sense
* with any refspecs. * with any refspecs.
*/ */
if ((heads && (args.send_all || args.send_mirror)) || if ((refspecs && (send_all || args.send_mirror)) ||
(args.send_all && args.send_mirror)) (send_all && args.send_mirror))
usage(send_pack_usage); usage(send_pack_usage);
if (remote_name) { if (remote_name) {
@@ -649,24 +542,50 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
} }
} }
return send_pack(&args, dest, remote, nr_heads, heads); conn = git_connect(fd, dest, receivepack, args.verbose ? CONNECT_VERBOSE : 0);
}
int send_pack(struct send_pack_args *my_args, memset(&extra_have, 0, sizeof(extra_have));
const char *dest, struct remote *remote,
int nr_heads, const char **heads)
{
int fd[2], ret;
struct child_process *conn;
memcpy(&args, my_args, sizeof(args)); get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
&extra_have);
verify_remote_names(nr_heads, heads); verify_remote_names(nr_refspecs, refspecs);
conn = git_connect(fd, dest, args.receivepack, args.verbose ? CONNECT_VERBOSE : 0); local_refs = get_local_heads();
ret = do_send_pack(fd[0], fd[1], remote, dest, nr_heads, heads);
flags = MATCH_REFS_NONE;
if (send_all)
flags |= MATCH_REFS_ALL;
if (args.send_mirror)
flags |= MATCH_REFS_MIRROR;
/* match them up */
remote_tail = &remote_refs;
while (*remote_tail)
remote_tail = &((*remote_tail)->next);
if (match_refs(local_refs, remote_refs, &remote_tail,
nr_refspecs, refspecs, flags)) {
return -1;
}
ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
close(fd[1]);
close(fd[0]); close(fd[0]);
/* do_send_pack always closes fd[1] */
ret |= finish_connect(conn); ret |= finish_connect(conn);
return !!ret;
print_push_status(dest, remote_refs);
if (!args.dry_run && remote) {
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next)
update_tracking_ref(remote, ref);
}
if (!ret && !refs_pushed(remote_refs))
fprintf(stderr, "Everything up-to-date\n");
return ret;
} }

View File

@@ -365,8 +365,7 @@ static int append_ref(const char *refname, const unsigned char *sha1,
return 0; return 0;
} }
if (MAX_REVS <= ref_name_cnt) { if (MAX_REVS <= ref_name_cnt) {
fprintf(stderr, "warning: ignoring %s; " warning("ignoring %s; cannot handle more than %d refs",
"cannot handle more than %d refs\n",
refname, MAX_REVS); refname, MAX_REVS);
return 0; return 0;
} }

View File

@@ -140,7 +140,7 @@ static int exclude_existing(const char *match)
continue; continue;
} }
if (check_ref_format(ref)) { if (check_ref_format(ref)) {
fprintf(stderr, "warning: ref '%s' ignored\n", ref); warning("ref '%s' ignored", ref);
continue; continue;
} }
if (!string_list_has_string(&existing_refs, ref)) { if (!string_list_has_string(&existing_refs, ref)) {

View File

@@ -195,7 +195,7 @@ static int process_path(const char *path)
struct stat st; struct stat st;
len = strlen(path); len = strlen(path);
if (has_symlink_leading_path(len, path)) if (has_symlink_leading_path(path, len))
return error("'%s' is beyond a symbolic link", path); return error("'%s' is beyond a symbolic link", path);
/* /*

31
cache.h
View File

@@ -140,8 +140,8 @@ struct ondisk_cache_entry_extended {
}; };
struct cache_entry { struct cache_entry {
unsigned int ce_ctime; struct cache_time ce_ctime;
unsigned int ce_mtime; struct cache_time ce_mtime;
unsigned int ce_dev; unsigned int ce_dev;
unsigned int ce_ino; unsigned int ce_ino;
unsigned int ce_mode; unsigned int ce_mode;
@@ -282,7 +282,7 @@ struct index_state {
struct cache_entry **cache; struct cache_entry **cache;
unsigned int cache_nr, cache_alloc, cache_changed; unsigned int cache_nr, cache_alloc, cache_changed;
struct cache_tree *cache_tree; struct cache_tree *cache_tree;
time_t timestamp; struct cache_time timestamp;
void *alloc; void *alloc;
unsigned name_hash_initialized : 1, unsigned name_hash_initialized : 1,
initialized : 1; initialized : 1;
@@ -428,7 +428,7 @@ extern int read_index_preload(struct index_state *, const char **pathspec);
extern int read_index_from(struct index_state *, const char *path); extern int read_index_from(struct index_state *, const char *path);
extern int is_index_unborn(struct index_state *); extern int is_index_unborn(struct index_state *);
extern int read_index_unmerged(struct index_state *); extern int read_index_unmerged(struct index_state *);
extern int write_index(const struct index_state *, int newfd); extern int write_index(struct index_state *, int newfd);
extern int discard_index(struct index_state *); extern int discard_index(struct index_state *);
extern int unmerged_index(const struct index_state *); extern int unmerged_index(const struct index_state *);
extern int verify_path(const char *path); extern int verify_path(const char *path);
@@ -443,6 +443,7 @@ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int opt
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name); extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
extern int remove_index_entry_at(struct index_state *, int pos); extern int remove_index_entry_at(struct index_state *, int pos);
extern void remove_marked_cache_entries(struct index_state *istate);
extern int remove_file_from_index(struct index_state *, const char *path); extern int remove_file_from_index(struct index_state *, const char *path);
#define ADD_CACHE_VERBOSE 1 #define ADD_CACHE_VERBOSE 1
#define ADD_CACHE_PRETEND 2 #define ADD_CACHE_PRETEND 2
@@ -541,8 +542,17 @@ enum rebase_setup_type {
AUTOREBASE_ALWAYS, AUTOREBASE_ALWAYS,
}; };
enum push_default_type {
PUSH_DEFAULT_UNSPECIFIED = -1,
PUSH_DEFAULT_NOTHING = 0,
PUSH_DEFAULT_MATCHING,
PUSH_DEFAULT_TRACKING,
PUSH_DEFAULT_CURRENT,
};
extern enum branch_track git_branch_track; extern enum branch_track git_branch_track;
extern enum rebase_setup_type autorebase; extern enum rebase_setup_type autorebase;
extern enum push_default_type push_default;
#define GIT_REPO_VERSION 0 #define GIT_REPO_VERSION 0
extern int repository_format_version; extern int repository_format_version;
@@ -645,7 +655,6 @@ extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned l
extern int move_temp_to_file(const char *tmpfile, const char *filename); extern int move_temp_to_file(const char *tmpfile, const char *filename);
extern int has_sha1_pack(const unsigned char *sha1); extern int has_sha1_pack(const unsigned char *sha1);
extern int has_sha1_kept_pack(const unsigned char *sha1);
extern int has_sha1_file(const unsigned char *sha1); extern int has_sha1_file(const unsigned char *sha1);
extern int has_loose_object_nonlocal(const unsigned char *sha1); extern int has_loose_object_nonlocal(const unsigned char *sha1);
@@ -725,11 +734,13 @@ struct checkout {
}; };
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath); extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
extern int has_symlink_leading_path(int len, const char *name); extern int has_symlink_leading_path(const char *name, int len);
extern int has_symlink_or_noent_leading_path(int len, const char *name); extern int has_symlink_or_noent_leading_path(const char *name, int len);
extern int has_dirs_only_path(int len, const char *name, int prefix_len); extern int has_dirs_only_path(const char *name, int len, int prefix_len);
extern void invalidate_lstat_cache(int len, const char *name); extern void invalidate_lstat_cache(const char *name, int len);
extern void clear_lstat_cache(void); extern void clear_lstat_cache(void);
extern void schedule_dir_for_removal(const char *name, int len);
extern void remove_scheduled_dirs(void);
extern struct alternate_object_database { extern struct alternate_object_database {
struct alternate_object_database *next; struct alternate_object_database *next;
@@ -802,7 +813,7 @@ struct ref {
#define REF_HEADS (1u << 1) #define REF_HEADS (1u << 1)
#define REF_TAGS (1u << 2) #define REF_TAGS (1u << 2)
extern struct ref *find_ref_by_name(struct ref *list, const char *name); extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
#define CONNECT_VERBOSE (1u << 0) #define CONNECT_VERBOSE (1u << 0)
extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags); extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);

View File

@@ -712,9 +712,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
result_size = buf.len; result_size = buf.len;
result = strbuf_detach(&buf, NULL); result = strbuf_detach(&buf, NULL);
elem->mode = canon_mode(st.st_mode); elem->mode = canon_mode(st.st_mode);
} } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
else if (0 <= (fd = open(elem->path, O_RDONLY)) &&
!fstat(fd, &st)) {
size_t len = xsize_t(st.st_size); size_t len = xsize_t(st.st_size);
ssize_t done; ssize_t done;
int is_file, i; int is_file, i;

View File

@@ -4,6 +4,119 @@
unsigned int _CRT_fmode = _O_BINARY; unsigned int _CRT_fmode = _O_BINARY;
static int err_win_to_posix(DWORD winerr)
{
int error = ENOSYS;
switch(winerr) {
case ERROR_ACCESS_DENIED: error = EACCES; break;
case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
case ERROR_ALREADY_EXISTS: error = EEXIST; break;
case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
case ERROR_BAD_COMMAND: error = EIO; break;
case ERROR_BAD_DEVICE: error = ENODEV; break;
case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
case ERROR_BAD_FORMAT: error = ENOEXEC; break;
case ERROR_BAD_LENGTH: error = EINVAL; break;
case ERROR_BAD_PATHNAME: error = ENOENT; break;
case ERROR_BAD_PIPE: error = EPIPE; break;
case ERROR_BAD_UNIT: error = ENODEV; break;
case ERROR_BAD_USERNAME: error = EINVAL; break;
case ERROR_BROKEN_PIPE: error = EPIPE; break;
case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
case ERROR_BUSY: error = EBUSY; break;
case ERROR_BUSY_DRIVE: error = EBUSY; break;
case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
case ERROR_CANNOT_MAKE: error = EACCES; break;
case ERROR_CANTOPEN: error = EIO; break;
case ERROR_CANTREAD: error = EIO; break;
case ERROR_CANTWRITE: error = EIO; break;
case ERROR_CRC: error = EIO; break;
case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
case ERROR_DEVICE_IN_USE: error = EBUSY; break;
case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
case ERROR_DIRECTORY: error = EINVAL; break;
case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
case ERROR_DISK_CHANGE: error = EIO; break;
case ERROR_DISK_FULL: error = ENOSPC; break;
case ERROR_DRIVE_LOCKED: error = EBUSY; break;
case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
case ERROR_FILE_EXISTS: error = EEXIST; break;
case ERROR_FILE_INVALID: error = ENODEV; break;
case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
case ERROR_GEN_FAILURE: error = EIO; break;
case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
case ERROR_INVALID_ACCESS: error = EACCES; break;
case ERROR_INVALID_ADDRESS: error = EFAULT; break;
case ERROR_INVALID_BLOCK: error = EFAULT; break;
case ERROR_INVALID_DATA: error = EINVAL; break;
case ERROR_INVALID_DRIVE: error = ENODEV; break;
case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
case ERROR_INVALID_FLAGS: error = EINVAL; break;
case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
case ERROR_INVALID_HANDLE: error = EBADF; break;
case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
case ERROR_INVALID_NAME: error = EINVAL; break;
case ERROR_INVALID_OWNER: error = EINVAL; break;
case ERROR_INVALID_PARAMETER: error = EINVAL; break;
case ERROR_INVALID_PASSWORD: error = EPERM; break;
case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
case ERROR_INVALID_WORKSTATION: error = EACCES; break;
case ERROR_IO_DEVICE: error = EIO; break;
case ERROR_IO_INCOMPLETE: error = EINTR; break;
case ERROR_LOCKED: error = EBUSY; break;
case ERROR_LOCK_VIOLATION: error = EACCES; break;
case ERROR_LOGON_FAILURE: error = EACCES; break;
case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
case ERROR_MORE_DATA: error = EPIPE; break;
case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
case ERROR_NOACCESS: error = EFAULT; break;
case ERROR_NONE_MAPPED: error = EINVAL; break;
case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
case ERROR_NOT_READY: error = EAGAIN; break;
case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
case ERROR_NO_DATA: error = EPIPE; break;
case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
case ERROR_OPEN_FAILED: error = EIO; break;
case ERROR_OPEN_FILES: error = EBUSY; break;
case ERROR_OPERATION_ABORTED: error = EINTR; break;
case ERROR_OUTOFMEMORY: error = ENOMEM; break;
case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
case ERROR_PATH_BUSY: error = EBUSY; break;
case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
case ERROR_PIPE_BUSY: error = EBUSY; break;
case ERROR_PIPE_CONNECTED: error = EPIPE; break;
case ERROR_PIPE_LISTENING: error = EPIPE; break;
case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
case ERROR_READ_FAULT: error = EIO; break;
case ERROR_SEEK: error = EIO; break;
case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
case ERROR_SHARING_VIOLATION: error = EACCES; break;
case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
case ERROR_SWAPERROR: error = ENOENT; break;
case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
case ERROR_WRITE_FAULT: error = EIO; break;
case ERROR_WRITE_PROTECT: error = EROFS; break;
}
return error;
}
#undef open #undef open
int mingw_open (const char *filename, int oflags, ...) int mingw_open (const char *filename, int oflags, ...)
{ {
@@ -344,7 +457,7 @@ static const char *quote_arg(const char *arg)
const char *p = arg; const char *p = arg;
if (!*p) force_quotes = 1; if (!*p) force_quotes = 1;
while (*p) { while (*p) {
if (isspace(*p) || *p == '*' || *p == '?' || *p == '{') if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
force_quotes = 1; force_quotes = 1;
else if (*p == '"') else if (*p == '"')
n++; n++;
@@ -821,7 +934,9 @@ int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
#undef rename #undef rename
int mingw_rename(const char *pold, const char *pnew) int mingw_rename(const char *pold, const char *pnew)
{ {
DWORD attrs; DWORD attrs, gle;
int tries = 0;
static const int delay[] = { 0, 1, 10, 20, 40 };
/* /*
* Try native rename() first to get errno right. * Try native rename() first to get errno right.
@@ -831,10 +946,12 @@ int mingw_rename(const char *pold, const char *pnew)
return 0; return 0;
if (errno != EEXIST) if (errno != EEXIST)
return -1; return -1;
repeat:
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
return 0; return 0;
/* TODO: translate more errors */ /* TODO: translate more errors */
if (GetLastError() == ERROR_ACCESS_DENIED && gle = GetLastError();
if (gle == ERROR_ACCESS_DENIED &&
(attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) { (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
if (attrs & FILE_ATTRIBUTE_DIRECTORY) { if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
errno = EISDIR; errno = EISDIR;
@@ -844,10 +961,24 @@ int mingw_rename(const char *pold, const char *pnew)
SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING)) if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
return 0; return 0;
gle = GetLastError();
/* revert file attributes on failure */ /* revert file attributes on failure */
SetFileAttributes(pnew, attrs); SetFileAttributes(pnew, attrs);
} }
} }
if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
/*
* We assume that some other process had the source or
* destination file open at the wrong moment and retry.
* In order to give the other process a higher chance to
* complete its operation, we give up our time slice now.
* If we have to retry again, we do sleep a bit.
*/
Sleep(delay[tries]);
tries++;
warning("rename retry #%d %s -> %s", tries, pold, pnew);
goto repeat;
}
errno = EACCES; errno = EACCES;
return -1; return -1;
} }
@@ -1006,123 +1137,9 @@ void mingw_open_html(const char *unixpath)
ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
} }
static int err_win_to_posix(DWORD winerr)
{
int error = ENOSYS;
switch(winerr) {
case ERROR_ACCESS_DENIED: error = EACCES; break;
case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
case ERROR_ALREADY_EXISTS: error = EEXIST; break;
case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
case ERROR_BAD_COMMAND: error = EIO; break;
case ERROR_BAD_DEVICE: error = ENODEV; break;
case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
case ERROR_BAD_FORMAT: error = ENOEXEC; break;
case ERROR_BAD_LENGTH: error = EINVAL; break;
case ERROR_BAD_PATHNAME: error = ENOENT; break;
case ERROR_BAD_PIPE: error = EPIPE; break;
case ERROR_BAD_UNIT: error = ENODEV; break;
case ERROR_BAD_USERNAME: error = EINVAL; break;
case ERROR_BROKEN_PIPE: error = EPIPE; break;
case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
case ERROR_BUSY: error = EBUSY; break;
case ERROR_BUSY_DRIVE: error = EBUSY; break;
case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
case ERROR_CANNOT_MAKE: error = EACCES; break;
case ERROR_CANTOPEN: error = EIO; break;
case ERROR_CANTREAD: error = EIO; break;
case ERROR_CANTWRITE: error = EIO; break;
case ERROR_CRC: error = EIO; break;
case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
case ERROR_DEVICE_IN_USE: error = EBUSY; break;
case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
case ERROR_DIRECTORY: error = EINVAL; break;
case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
case ERROR_DISK_CHANGE: error = EIO; break;
case ERROR_DISK_FULL: error = ENOSPC; break;
case ERROR_DRIVE_LOCKED: error = EBUSY; break;
case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
case ERROR_FILE_EXISTS: error = EEXIST; break;
case ERROR_FILE_INVALID: error = ENODEV; break;
case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
case ERROR_GEN_FAILURE: error = EIO; break;
case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
case ERROR_INVALID_ACCESS: error = EACCES; break;
case ERROR_INVALID_ADDRESS: error = EFAULT; break;
case ERROR_INVALID_BLOCK: error = EFAULT; break;
case ERROR_INVALID_DATA: error = EINVAL; break;
case ERROR_INVALID_DRIVE: error = ENODEV; break;
case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
case ERROR_INVALID_FLAGS: error = EINVAL; break;
case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
case ERROR_INVALID_HANDLE: error = EBADF; break;
case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
case ERROR_INVALID_NAME: error = EINVAL; break;
case ERROR_INVALID_OWNER: error = EINVAL; break;
case ERROR_INVALID_PARAMETER: error = EINVAL; break;
case ERROR_INVALID_PASSWORD: error = EPERM; break;
case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
case ERROR_INVALID_WORKSTATION: error = EACCES; break;
case ERROR_IO_DEVICE: error = EIO; break;
case ERROR_IO_INCOMPLETE: error = EINTR; break;
case ERROR_LOCKED: error = EBUSY; break;
case ERROR_LOCK_VIOLATION: error = EACCES; break;
case ERROR_LOGON_FAILURE: error = EACCES; break;
case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
case ERROR_MORE_DATA: error = EPIPE; break;
case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
case ERROR_NOACCESS: error = EFAULT; break;
case ERROR_NONE_MAPPED: error = EINVAL; break;
case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
case ERROR_NOT_READY: error = EAGAIN; break;
case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
case ERROR_NO_DATA: error = EPIPE; break;
case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
case ERROR_OPEN_FAILED: error = EIO; break;
case ERROR_OPEN_FILES: error = EBUSY; break;
case ERROR_OPERATION_ABORTED: error = EINTR; break;
case ERROR_OUTOFMEMORY: error = ENOMEM; break;
case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
case ERROR_PATH_BUSY: error = EBUSY; break;
case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
case ERROR_PIPE_BUSY: error = EBUSY; break;
case ERROR_PIPE_CONNECTED: error = EPIPE; break;
case ERROR_PIPE_LISTENING: error = EPIPE; break;
case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
case ERROR_READ_FAULT: error = EIO; break;
case ERROR_SEEK: error = EIO; break;
case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
case ERROR_SHARING_VIOLATION: error = EACCES; break;
case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
case ERROR_SWAPERROR: error = ENOENT; break;
case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
case ERROR_WRITE_FAULT: error = EIO; break;
case ERROR_WRITE_PROTECT: error = EROFS; break;
}
return error;
}
int link(const char *oldpath, const char *newpath) int link(const char *oldpath, const char *newpath)
{ {
typedef BOOL WINAPI (*T)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES); typedef BOOL WINAPI (*T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
static T create_hard_link = NULL; static T create_hard_link = NULL;
if (!create_hard_link) { if (!create_hard_link) {
create_hard_link = (T) GetProcAddress( create_hard_link = (T) GetProcAddress(

View File

@@ -1,6 +1,7 @@
#include "../git-compat-util.h" #include "../git-compat-util.h"
/* Note that this doesn't return the actual pagesize, but /*
* Note that this doesn't return the actual pagesize, but
* the allocation granularity. If future Windows specific git code * the allocation granularity. If future Windows specific git code
* needs the real getpagesize function, we need to find another solution. * needs the real getpagesize function, we need to find another solution.
*/ */
@@ -11,8 +12,7 @@ int mingw_getpagesize(void)
return si.dwAllocationGranularity; return si.dwAllocationGranularity;
} }
void *git_mmap void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
(void *start, size_t length, int prot, int flags, int fd, off_t offset)
{ {
HANDLE hmap; HANDLE hmap;
void *temp; void *temp;

View File

@@ -565,6 +565,31 @@ static int git_default_branch_config(const char *var, const char *value)
return 0; return 0;
} }
static int git_default_push_config(const char *var, const char *value)
{
if (!strcmp(var, "push.default")) {
if (!value)
return config_error_nonbool(var);
else if (!strcmp(value, "nothing"))
push_default = PUSH_DEFAULT_NOTHING;
else if (!strcmp(value, "matching"))
push_default = PUSH_DEFAULT_MATCHING;
else if (!strcmp(value, "tracking"))
push_default = PUSH_DEFAULT_TRACKING;
else if (!strcmp(value, "current"))
push_default = PUSH_DEFAULT_CURRENT;
else {
error("Malformed value for %s: %s", var, value);
return error("Must be one of nothing, matching, "
"tracking or current.");
}
return 0;
}
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
static int git_default_mailmap_config(const char *var, const char *value) static int git_default_mailmap_config(const char *var, const char *value)
{ {
if (!strcmp(var, "mailmap.file")) if (!strcmp(var, "mailmap.file"))
@@ -588,6 +613,9 @@ int git_default_config(const char *var, const char *value, void *dummy)
if (!prefixcmp(var, "branch.")) if (!prefixcmp(var, "branch."))
return git_default_branch_config(var, value); return git_default_branch_config(var, value);
if (!prefixcmp(var, "push."))
return git_default_push_config(var, value);
if (!prefixcmp(var, "mailmap.")) if (!prefixcmp(var, "mailmap."))
return git_default_mailmap_config(var, value); return git_default_mailmap_config(var, value);
@@ -644,28 +672,37 @@ int git_config_global(void)
int git_config(config_fn_t fn, void *data) int git_config(config_fn_t fn, void *data)
{ {
int ret = 0; int ret = 0, found = 0;
char *repo_config = NULL; char *repo_config = NULL;
const char *home = NULL; const char *home = NULL;
/* Setting $GIT_CONFIG makes git read _only_ the given config file. */ /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
if (config_exclusive_filename) if (config_exclusive_filename)
return git_config_from_file(fn, config_exclusive_filename, data); return git_config_from_file(fn, config_exclusive_filename, data);
if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
ret += git_config_from_file(fn, git_etc_gitconfig(), ret += git_config_from_file(fn, git_etc_gitconfig(),
data); data);
found += 1;
}
home = getenv("HOME"); home = getenv("HOME");
if (git_config_global() && home) { if (git_config_global() && home) {
char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
if (!access(user_config, R_OK)) if (!access(user_config, R_OK)) {
ret += git_config_from_file(fn, user_config, data); ret += git_config_from_file(fn, user_config, data);
found += 1;
}
free(user_config); free(user_config);
} }
repo_config = git_pathdup("config"); repo_config = git_pathdup("config");
ret += git_config_from_file(fn, repo_config, data); if (!access(repo_config, R_OK)) {
ret += git_config_from_file(fn, repo_config, data);
found += 1;
}
free(repo_config); free(repo_config);
if (found == 0)
return -1;
return ret; return ret;
} }

View File

@@ -42,6 +42,8 @@ else \
if test "$withval" = "yes"; then \ if test "$withval" = "yes"; then \
AC_MSG_WARN([You should provide path for --with-$1=PATH]); \ AC_MSG_WARN([You should provide path for --with-$1=PATH]); \
else \ else \
m4_toupper($1)_PATH=$withval; \
AC_MSG_NOTICE([Setting m4_toupper($1)_PATH to $withval]); \
GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval); \ GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval); \
fi; \ fi; \
fi; \ fi; \
@@ -61,6 +63,8 @@ elif test "$withval" = "yes"; then \
m4_toupper(NO_$1)=; \ m4_toupper(NO_$1)=; \
else \ else \
m4_toupper(NO_$1)=; \ m4_toupper(NO_$1)=; \
m4_toupper($1)DIR=$withval; \
AC_MSG_NOTICE([Setting m4_toupper($1)DIR to $withval]); \
GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval); \ GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval); \
fi \ fi \
])# GIT_PARSE_WITH ])# GIT_PARSE_WITH
@@ -76,6 +80,32 @@ AC_DEFUN([GIT_CHECK_FUNC],[AC_CHECK_FUNC([$1],[
AC_SEARCH_LIBS([$1],, AC_SEARCH_LIBS([$1],,
[$2],[$3]) [$2],[$3])
],[$3])]) ],[$3])])
dnl
dnl GIT_STASH_FLAGS(BASEPATH_VAR)
dnl -----------------------------
dnl Allow for easy stashing of LDFLAGS and CPPFLAGS before running
dnl tests that may want to take user settings into account.
AC_DEFUN([GIT_STASH_FLAGS],[
if test -n "$1"; then
old_CPPFLAGS="$CPPFLAGS"
old_LDFLAGS="$LDFLAGS"
CPPFLAGS="-I$1/include $CPPFLAGS"
LDFLAGS="-L$1/$lib $LDFLAGS"
fi
])
dnl
dnl GIT_UNSTASH_FLAGS(BASEPATH_VAR)
dnl -----------------------------
dnl Restore the stashed *FLAGS values.
AC_DEFUN([GIT_UNSTASH_FLAGS],[
if test -n "$1"; then
CPPFLAGS="$old_CPPFLAGS"
LDFLAGS="$old_LDFLAGS"
fi
])
## Site configuration related to programs (before tests) ## Site configuration related to programs (before tests)
## --with-PACKAGE[=ARG] and --without-PACKAGE ## --with-PACKAGE[=ARG] and --without-PACKAGE
# #
@@ -86,9 +116,124 @@ AC_ARG_WITH([lib],
[if test "$withval" = "no" || test "$withval" = "yes"; then \ [if test "$withval" = "no" || test "$withval" = "yes"; then \
AC_MSG_WARN([You should provide name for --with-lib=ARG]); \ AC_MSG_WARN([You should provide name for --with-lib=ARG]); \
else \ else \
lib=$withval; \
AC_MSG_NOTICE([Setting lib to '$lib']); \
GIT_CONF_APPEND_LINE(lib=$withval); \ GIT_CONF_APPEND_LINE(lib=$withval); \
fi; \ fi; \
],[]) ],[])
if test -z "$lib"; then
AC_MSG_NOTICE([Setting lib to 'lib' (the default)])
lib=lib
fi
AC_ARG_ENABLE([pthreads],
[AS_HELP_STRING([--enable-pthreads=FLAGS],
[FLAGS is the value to pass to the compiler to enable POSIX Threads.]
[The default if FLAGS is not specified is to try first -pthread]
[and then -lpthread.]
[--without-pthreads will disable threading.])],
[
if test "x$enableval" = "xyes"; then
AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads])
elif test "x$enableval" != "xno"; then
PTHREAD_CFLAGS=$enableval
AC_MSG_NOTICE([Setting '$PTHREAD_CFLAGS' as the FLAGS to enable POSIX Threads])
else
AC_MSG_NOTICE([POSIX Threads will be disabled.])
NO_PTHREADS=YesPlease
USER_NOPTHREAD=1
fi],
[
AC_MSG_NOTICE([Will try -pthread then -lpthread to enable POSIX Threads.])
])
## Site configuration (override autodetection)
## --with-PACKAGE[=ARG] and --without-PACKAGE
AC_MSG_NOTICE([CHECKS for site configuration])
#
# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
# tests. These tests take up a significant amount of the total test time
# but are not needed unless you plan to talk to SVN repos.
#
# Define MOZILLA_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
# choice) has very fast version optimized for i586.
#
# Define PPC_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine optimized for PowerPC.
#
# Define ARM_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine optimized for ARM.
#
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
# This also implies MOZILLA_SHA1.
#
# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(openssl,
AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)])
AS_HELP_STRING([], [ARG can be prefix for openssl library and headers]),\
GIT_PARSE_WITH(openssl))
#
# Define NO_CURL if you do not have curl installed. git-http-pull and
# git-http-push are not built, and you cannot use http:// and https://
# transports.
#
# Define CURLDIR=/foo/bar if your curl header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(curl,
AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)])
AS_HELP_STRING([], [ARG can be also prefix for curl library and headers]),
GIT_PARSE_WITH(curl))
#
# Define NO_EXPAT if you do not have expat installed. git-http-push is
# not built, and you cannot push using http:// and https:// transports.
#
# Define EXPATDIR=/foo/bar if your expat header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(expat,
AS_HELP_STRING([--with-expat],
[support git-push using http:// and https:// transports via WebDAV (default is YES)])
AS_HELP_STRING([], [ARG can be also prefix for expat library and headers]),
GIT_PARSE_WITH(expat))
#
# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
# installed in /sw, but don't want GIT to link against any libraries
# installed there. If defined you may specify your own (or Fink's)
# include directories and library directories by defining CFLAGS
# and LDFLAGS appropriately.
#
# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
# have DarwinPorts installed in /opt/local, but don't want GIT to
# link against any libraries installed there. If defined you may
# specify your own (or DarwinPort's) include directories and
# library directories by defining CFLAGS and LDFLAGS appropriately.
#
# Define NO_MMAP if you want to avoid mmap.
#
# Define NO_ICONV if your libc does not properly support iconv.
AC_ARG_WITH(iconv,
AS_HELP_STRING([--without-iconv],
[if your architecture doesn't properly support iconv])
AS_HELP_STRING([--with-iconv=PATH],
[PATH is prefix for libiconv library and headers])
AS_HELP_STRING([],
[used only if you need linking with libiconv]),
GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
# Define USE_NSEC below if you want git to care about sub-second file mtimes
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
# randomly break unless your underlying filesystem supports those sub-second
# times (my ext3 doesn't).
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
# #
# Define SHELL_PATH to provide path to shell. # Define SHELL_PATH to provide path to shell.
GIT_ARG_SET_PATH(shell) GIT_ARG_SET_PATH(shell)
@@ -167,7 +312,7 @@ fi
AC_CHECK_PROGS(ASCIIDOC, [asciidoc]) AC_CHECK_PROGS(ASCIIDOC, [asciidoc])
if test -n "$ASCIIDOC"; then if test -n "$ASCIIDOC"; then
AC_MSG_CHECKING([for asciidoc version]) AC_MSG_CHECKING([for asciidoc version])
asciidoc_version=`$ASCIIDOC --version 2>&1` asciidoc_version=`$ASCIIDOC --version 2>/dev/null`
case "${asciidoc_version}" in case "${asciidoc_version}" in
asciidoc' '8*) asciidoc' '8*)
ASCIIDOC8=YesPlease ASCIIDOC8=YesPlease
@@ -191,33 +336,57 @@ AC_MSG_NOTICE([CHECKS for libraries])
# #
# Define NO_OPENSSL environment variable if you do not have OpenSSL. # Define NO_OPENSSL environment variable if you do not have OpenSSL.
# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
GIT_STASH_FLAGS($OPENSSLDIR)
AC_CHECK_LIB([crypto], [SHA1_Init], AC_CHECK_LIB([crypto], [SHA1_Init],
[NEEDS_SSL_WITH_CRYPTO=], [NEEDS_SSL_WITH_CRYPTO=],
[AC_CHECK_LIB([ssl], [SHA1_Init], [AC_CHECK_LIB([ssl], [SHA1_Init],
[NEEDS_SSL_WITH_CRYPTO=YesPlease [NEEDS_SSL_WITH_CRYPTO=YesPlease
NEEDS_SSL_WITH_CRYPTO=], NEEDS_SSL_WITH_CRYPTO=],
[NO_OPENSSL=YesPlease])]) [NO_OPENSSL=YesPlease])])
GIT_UNSTASH_FLAGS($OPENSSLDIR)
AC_SUBST(NEEDS_SSL_WITH_CRYPTO) AC_SUBST(NEEDS_SSL_WITH_CRYPTO)
AC_SUBST(NO_OPENSSL) AC_SUBST(NO_OPENSSL)
# #
# Define NO_CURL if you do not have libcurl installed. git-http-pull and # Define NO_CURL if you do not have libcurl installed. git-http-pull and
# git-http-push are not built, and you cannot use http:// and https:// # git-http-push are not built, and you cannot use http:// and https://
# transports. # transports.
GIT_STASH_FLAGS($CURLDIR)
AC_CHECK_LIB([curl], [curl_global_init], AC_CHECK_LIB([curl], [curl_global_init],
[NO_CURL=], [NO_CURL=],
[NO_CURL=YesPlease]) [NO_CURL=YesPlease])
GIT_UNSTASH_FLAGS($CURLDIR)
AC_SUBST(NO_CURL) AC_SUBST(NO_CURL)
# #
# Define NO_EXPAT if you do not have expat installed. git-http-push is # Define NO_EXPAT if you do not have expat installed. git-http-push is
# not built, and you cannot push using http:// and https:// transports. # not built, and you cannot push using http:// and https:// transports.
GIT_STASH_FLAGS($EXPATDIR)
AC_CHECK_LIB([expat], [XML_ParserCreate], AC_CHECK_LIB([expat], [XML_ParserCreate],
[NO_EXPAT=], [NO_EXPAT=],
[NO_EXPAT=YesPlease]) [NO_EXPAT=YesPlease])
GIT_UNSTASH_FLAGS($EXPATDIR)
AC_SUBST(NO_EXPAT) AC_SUBST(NO_EXPAT)
# #
# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and
# some Solaris installations). # some Solaris installations).
# Define NO_ICONV if neither libc nor libiconv support iconv. # Define NO_ICONV if neither libc nor libiconv support iconv.
GIT_STASH_FLAGS($ICONVDIR)
AC_DEFUN([ICONVTEST_SRC], [ AC_DEFUN([ICONVTEST_SRC], [
#include <iconv.h> #include <iconv.h>
@@ -227,25 +396,46 @@ int main(void)
return 0; return 0;
} }
]) ])
AC_MSG_CHECKING([for iconv in -lc])
AC_LINK_IFELSE(ICONVTEST_SRC, if test -n "$ICONVDIR"; then
lib_order="-liconv -lc"
else
lib_order="-lc -liconv"
fi
NO_ICONV=YesPlease
for l in $lib_order; do
if test "$l" = "-liconv"; then
NEEDS_LIBICONV=YesPlease
else
NEEDS_LIBICONV=
fi
old_LIBS="$LIBS"
LIBS="$LIBS $l"
AC_MSG_CHECKING([for iconv in $l])
AC_LINK_IFELSE(ICONVTEST_SRC,
[AC_MSG_RESULT([yes]) [AC_MSG_RESULT([yes])
NEEDS_LIBICONV=], NO_ICONV=
[AC_MSG_RESULT([no]) break],
old_LIBS="$LIBS" [AC_MSG_RESULT([no])])
LIBS="$LIBS -liconv" LIBS="$old_LIBS"
AC_MSG_CHECKING([for iconv in -liconv]) done
AC_LINK_IFELSE(ICONVTEST_SRC,
[AC_MSG_RESULT([yes]) #in case of break
NEEDS_LIBICONV=YesPlease], LIBS="$old_LIBS"
[AC_MSG_RESULT([no])
NO_ICONV=YesPlease]) GIT_UNSTASH_FLAGS($ICONVDIR)
LIBS="$old_LIBS"])
AC_SUBST(NEEDS_LIBICONV) AC_SUBST(NEEDS_LIBICONV)
AC_SUBST(NO_ICONV) AC_SUBST(NO_ICONV)
test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv"
# #
# Define NO_DEFLATE_BOUND if deflateBound is missing from zlib. # Define NO_DEFLATE_BOUND if deflateBound is missing from zlib.
GIT_STASH_FLAGS($ZLIB_PATH)
AC_DEFUN([ZLIBTEST_SRC], [ AC_DEFUN([ZLIBTEST_SRC], [
#include <zlib.h> #include <zlib.h>
@@ -263,7 +453,11 @@ AC_LINK_IFELSE(ZLIBTEST_SRC,
[AC_MSG_RESULT([no]) [AC_MSG_RESULT([no])
NO_DEFLATE_BOUND=yes]) NO_DEFLATE_BOUND=yes])
LIBS="$old_LIBS" LIBS="$old_LIBS"
GIT_UNSTASH_FLAGS($ZLIB_PATH)
AC_SUBST(NO_DEFLATE_BOUND) AC_SUBST(NO_DEFLATE_BOUND)
# #
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS, # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
# Patrick Mauritz). # Patrick Mauritz).
@@ -297,13 +491,18 @@ int main(void)
return 0; return 0;
} }
]]) ]])
GIT_STASH_FLAGS($ICONVDIR)
AC_MSG_CHECKING([for old iconv()]) AC_MSG_CHECKING([for old iconv()])
AC_COMPILE_IFELSE(OLDICONVTEST_SRC, AC_COMPILE_IFELSE(OLDICONVTEST_SRC,
[AC_MSG_RESULT([no])], [AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes]) [AC_MSG_RESULT([yes])
OLD_ICONV=UnfortunatelyYes]) OLD_ICONV=UnfortunatelyYes])
AC_SUBST(OLD_ICONV)
GIT_UNSTASH_FLAGS($ICONVDIR)
AC_SUBST(OLD_ICONV)
## Checks for typedefs, structures, and compiler characteristics. ## Checks for typedefs, structures, and compiler characteristics.
AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics]) AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics])
@@ -494,114 +693,65 @@ AC_SUBST(NO_MKDTEMP)
# #
# Define PTHREAD_LIBS to the linker flag used for Pthread support and define # Define PTHREAD_LIBS to the linker flag used for Pthread support and define
# THREADED_DELTA_SEARCH if Pthreads are available. # THREADED_DELTA_SEARCH if Pthreads are available.
AC_LANG_CONFTEST([AC_LANG_PROGRAM( AC_DEFUN([PTHREADTEST_SRC], [
[[#include <pthread.h>]], #include <pthread.h>
[[pthread_mutex_t test_mutex;]]
)]) int main(void)
${CC} -pthread conftest.c -o conftest.o > /dev/null 2>&1 {
if test $? -eq 0;then pthread_mutex_t test_mutex;
PTHREAD_LIBS="-pthread" return (0);
THREADED_DELTA_SEARCH=YesPlease }
])
dnl AC_LANG_CONFTEST([AC_LANG_PROGRAM(
dnl [[#include <pthread.h>]],
dnl [[pthread_mutex_t test_mutex;]]
dnl )])
NO_PTHREADS=UnfortunatelyYes
THREADED_DELTA_SEARCH=
PTHREAD_LIBS=
if test -n "$USER_NOPTHREAD"; then
AC_MSG_NOTICE([Skipping POSIX Threads at user request.])
# handle these separately since PTHREAD_CFLAGS could be '-lpthreads
# -D_REENTRANT' or some such.
elif test -z "$PTHREAD_CFLAGS"; then
for opt in -pthread -lpthread; do
old_CFLAGS="$CFLAGS"
CFLAGS="$opt $CFLAGS"
AC_MSG_CHECKING([Checking for POSIX Threads with '$opt'])
AC_LINK_IFELSE(PTHREADTEST_SRC,
[AC_MSG_RESULT([yes])
NO_PTHREADS=
PTHREAD_LIBS="$opt"
THREADED_DELTA_SEARCH=YesPlease
break
],
[AC_MSG_RESULT([no])])
CFLAGS="$old_CFLAGS"
done
else else
${CC} -lpthread conftest.c -o conftest.o > /dev/null 2>&1 old_CFLAGS="$CFLAGS"
if test $? -eq 0;then CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
PTHREAD_LIBS="-lpthread" AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS'])
THREADED_DELTA_SEARCH=YesPlease AC_LINK_IFELSE(PTHREADTEST_SRC,
else [AC_MSG_RESULT([yes])
NO_PTHREADS=UnfortunatelyYes NO_PTHREADS=
fi PTHREAD_LIBS="$PTHREAD_CFLAGS"
THREADED_DELTA_SEARCH=YesPlease
],
[AC_MSG_RESULT([no])])
CFLAGS="$old_CFLAGS"
fi fi
CFLAGS="$old_CFLAGS"
AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_LIBS)
AC_SUBST(NO_PTHREADS) AC_SUBST(NO_PTHREADS)
AC_SUBST(THREADED_DELTA_SEARCH) AC_SUBST(THREADED_DELTA_SEARCH)
## Site configuration (override autodetection)
## --with-PACKAGE[=ARG] and --without-PACKAGE
AC_MSG_NOTICE([CHECKS for site configuration])
#
# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
# tests. These tests take up a significant amount of the total test time
# but are not needed unless you plan to talk to SVN repos.
#
# Define MOZILLA_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
# choice) has very fast version optimized for i586.
#
# Define PPC_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine optimized for PowerPC.
#
# Define ARM_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine optimized for ARM.
#
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
# This also implies MOZILLA_SHA1.
#
# Define OPENSSLDIR=/foo/bar if your openssl header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(openssl,
AS_HELP_STRING([--with-openssl],[use OpenSSL library (default is YES)])
AS_HELP_STRING([], [ARG can be prefix for openssl library and headers]),\
GIT_PARSE_WITH(openssl))
#
# Define NO_CURL if you do not have curl installed. git-http-pull and
# git-http-push are not built, and you cannot use http:// and https://
# transports.
#
# Define CURLDIR=/foo/bar if your curl header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(curl,
AS_HELP_STRING([--with-curl],[support http(s):// transports (default is YES)])
AS_HELP_STRING([], [ARG can be also prefix for curl library and headers]),
GIT_PARSE_WITH(curl))
#
# Define NO_EXPAT if you do not have expat installed. git-http-push is
# not built, and you cannot push using http:// and https:// transports.
#
# Define EXPATDIR=/foo/bar if your expat header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
AC_ARG_WITH(expat,
AS_HELP_STRING([--with-expat],
[support git-push using http:// and https:// transports via WebDAV (default is YES)])
AS_HELP_STRING([], [ARG can be also prefix for expat library and headers]),
GIT_PARSE_WITH(expat))
#
# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
# installed in /sw, but don't want GIT to link against any libraries
# installed there. If defined you may specify your own (or Fink's)
# include directories and library directories by defining CFLAGS
# and LDFLAGS appropriately.
#
# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
# have DarwinPorts installed in /opt/local, but don't want GIT to
# link against any libraries installed there. If defined you may
# specify your own (or DarwinPort's) include directories and
# library directories by defining CFLAGS and LDFLAGS appropriately.
#
# Define NO_MMAP if you want to avoid mmap.
#
# Define NO_ICONV if your libc does not properly support iconv.
AC_ARG_WITH(iconv,
AS_HELP_STRING([--without-iconv],
[if your architecture doesn't properly support iconv])
AS_HELP_STRING([--with-iconv=PATH],
[PATH is prefix for libiconv library and headers])
AS_HELP_STRING([],
[used only if you need linking with libiconv]),
GIT_PARSE_WITH(iconv))
## --enable-FEATURE[=ARG] and --disable-FEATURE
#
# Define USE_NSEC below if you want git to care about sub-second file mtimes
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
# randomly break unless your underlying filesystem supports those sub-second
# times (my ext3 doesn't).
#
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-index perspective.
## Output files ## Output files
AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"]) AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"])
AC_OUTPUT AC_OUTPUT

View File

@@ -899,7 +899,7 @@ _git_diff ()
local cur="${COMP_WORDS[COMP_CWORD]}" local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in case "$cur" in
--*) --*)
__gitcomp "--cached --pickaxe-all --pickaxe-regex __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
--base --ours --theirs --base --ours --theirs
$__git_diff_common_options $__git_diff_common_options
" "
@@ -930,15 +930,21 @@ _git_format_patch ()
{ {
local cur="${COMP_WORDS[COMP_CWORD]}" local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in case "$cur" in
--thread=*)
__gitcomp "
deep shallow
" "" "${cur##--thread=}"
return
;;
--*) --*)
__gitcomp " __gitcomp "
--stdout --attach --thread --stdout --attach --no-attach --thread --thread=
--output-directory --output-directory
--numbered --start-number --numbered --start-number
--numbered-files --numbered-files
--keep-subject --keep-subject
--signoff --signoff
--in-reply-to= --in-reply-to= --cc=
--full-index --binary --full-index --binary
--not --all --not --all
--cover-letter --cover-letter
@@ -952,6 +958,21 @@ _git_format_patch ()
__git_complete_revlist __git_complete_revlist
} }
_git_fsck ()
{
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--tags --root --unreachable --cache --no-reflogs --full
--strict --verbose --lost-found
"
return
;;
esac
COMPREPLY=()
}
_git_gc () _git_gc ()
{ {
local cur="${COMP_WORDS[COMP_CWORD]}" local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -1082,7 +1103,7 @@ _git_log ()
local cur="${COMP_WORDS[COMP_CWORD]}" local cur="${COMP_WORDS[COMP_CWORD]}"
local g="$(git rev-parse --git-dir 2>/dev/null)" local g="$(git rev-parse --git-dir 2>/dev/null)"
local merge="" local merge=""
if [ -f $g/MERGE_HEAD ]; then if [ -f "$g/MERGE_HEAD" ]; then
merge="--merge" merge="--merge"
fi fi
case "$cur" in case "$cur" in
@@ -1249,8 +1270,8 @@ _git_send_email ()
local cur="${COMP_WORDS[COMP_CWORD]}" local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in case "$cur" in
--*) --*)
__gitcomp "--bcc --cc --cc-cmd --chain-reply-to --compose __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to
--dry-run --envelope-sender --from --identity --compose --dry-run --envelope-sender --from --identity
--in-reply-to --no-chain-reply-to --no-signed-off-by-cc --in-reply-to --no-chain-reply-to --no-signed-off-by-cc
--no-suppress-from --no-thread --quiet --no-suppress-from --no-thread --quiet
--signed-off-by-cc --smtp-pass --smtp-server --signed-off-by-cc --smtp-pass --smtp-server
@@ -1516,7 +1537,7 @@ _git_config ()
_git_remote () _git_remote ()
{ {
local subcommands="add rename rm show prune update" local subcommands="add rename rm show prune update set-head"
local subcommand="$(__git_find_subcommand "$subcommands")" local subcommand="$(__git_find_subcommand "$subcommands")"
if [ -z "$subcommand" ]; then if [ -z "$subcommand" ]; then
__gitcomp "$subcommands" __gitcomp "$subcommands"
@@ -1880,6 +1901,7 @@ _git ()
diff) _git_diff ;; diff) _git_diff ;;
fetch) _git_fetch ;; fetch) _git_fetch ;;
format-patch) _git_format_patch ;; format-patch) _git_format_patch ;;
fsck) _git_fsck ;;
gc) _git_gc ;; gc) _git_gc ;;
grep) _git_grep ;; grep) _git_grep ;;
help) _git_help ;; help) _git_help ;;
@@ -1921,7 +1943,7 @@ _gitk ()
local cur="${COMP_WORDS[COMP_CWORD]}" local cur="${COMP_WORDS[COMP_CWORD]}"
local g="$(__gitdir)" local g="$(__gitdir)"
local merge="" local merge=""
if [ -f $g/MERGE_HEAD ]; then if [ -f "$g/MERGE_HEAD" ]; then
merge="--merge" merge="--merge"
fi fi
case "$cur" in case "$cur" in

View File

@@ -14,13 +14,18 @@ die "usage: import-tars *.tar.{gz,bz2,Z}\n" unless @ARGV;
my $branch_name = 'import-tars'; my $branch_name = 'import-tars';
my $branch_ref = "refs/heads/$branch_name"; my $branch_ref = "refs/heads/$branch_name";
my $committer_name = 'T Ar Creator'; my $author_name = $ENV{'GIT_AUTHOR_NAME'} || 'T Ar Creator';
my $committer_email = 'tar@example.com'; my $author_email = $ENV{'GIT_AUTHOR_EMAIL'} || 'tar@example.com';
my $committer_name = $ENV{'GIT_COMMITTER_NAME'} || `git config --get user.name`;
my $committer_email = $ENV{'GIT_COMMITTER_EMAIL'} || `git config --get user.email`;
chomp($committer_name, $committer_email);
open(FI, '|-', 'git', 'fast-import', '--quiet') open(FI, '|-', 'git', 'fast-import', '--quiet')
or die "Unable to start git fast-import: $!\n"; or die "Unable to start git fast-import: $!\n";
foreach my $tar_file (@ARGV) foreach my $tar_file (@ARGV)
{ {
my $commit_time = time;
$tar_file =~ m,([^/]+)$,; $tar_file =~ m,([^/]+)$,;
my $tar_name = $1; my $tar_name = $1;
@@ -39,7 +44,7 @@ foreach my $tar_file (@ARGV)
die "Unrecognized compression format: $tar_file\n"; die "Unrecognized compression format: $tar_file\n";
} }
my $commit_time = 0; my $author_time = 0;
my $next_mark = 1; my $next_mark = 1;
my $have_top_dir = 1; my $have_top_dir = 1;
my ($top_dir, %files); my ($top_dir, %files);
@@ -92,7 +97,7 @@ foreach my $tar_file (@ARGV)
} }
$files{$path} = [$next_mark++, $mode]; $files{$path} = [$next_mark++, $mode];
$commit_time = $mtime if $mtime > $commit_time; $author_time = $mtime if $mtime > $author_time;
$path =~ m,^([^/]+)/,; $path =~ m,^([^/]+)/,;
$top_dir = $1 unless $top_dir; $top_dir = $1 unless $top_dir;
$have_top_dir = 0 if $top_dir ne $1; $have_top_dir = 0 if $top_dir ne $1;
@@ -100,6 +105,7 @@ foreach my $tar_file (@ARGV)
print FI <<EOF; print FI <<EOF;
commit $branch_ref commit $branch_ref
author $author_name <$author_email> $author_time +0000
committer $committer_name <$committer_email> $commit_time +0000 committer $committer_name <$committer_email> $commit_time +0000
data <<END_OF_COMMIT_MESSAGE data <<END_OF_COMMIT_MESSAGE
Imported from $tar_file. Imported from $tar_file.
@@ -119,7 +125,7 @@ EOF
print FI <<EOF; print FI <<EOF;
tag $tar_name tag $tar_name
from $branch_ref from $branch_ref
tagger $committer_name <$committer_email> $commit_time +0000 tagger $author_name <$author_email> $author_time +0000
data <<END_OF_TAG_MESSAGE data <<END_OF_TAG_MESSAGE
Package $tar_name Package $tar_name
END_OF_TAG_MESSAGE END_OF_TAG_MESSAGE

View File

@@ -44,7 +44,8 @@ for zipfile in argv[1:]:
common_prefix = name[:name.rfind('/') + 1] common_prefix = name[:name.rfind('/') + 1]
else: else:
while not name.startswith(common_prefix): while not name.startswith(common_prefix):
common_prefix = name[:name.rfind('/') + 1] last_slash = common_prefix[:-1].rfind('/') + 1
common_prefix = common_prefix[:last_slash]
mark[name] = ':' + str(next_mark) mark[name] = ':' + str(next_mark)
next_mark += 1 next_mark += 1

View File

@@ -31,7 +31,7 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
return -1; return -1;
return 1; return 1;
} }
if (has_symlink_leading_path(ce_namelen(ce), ce->name)) if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
return 1; return 1;
if (S_ISDIR(st->st_mode)) { if (S_ISDIR(st->st_mode)) {
unsigned char sub[20]; unsigned char sub[20];

View File

@@ -205,8 +205,6 @@ void diff_no_index(struct rev_info *revs,
no_index ? "--no-index" : "[--no-index]"); no_index ? "--no-index" : "[--no-index]");
diff_setup(&revs->diffopt); diff_setup(&revs->diffopt);
if (!revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
for (i = 1; i < argc - 2; ) { for (i = 1; i < argc - 2; ) {
int j; int j;
if (!strcmp(argv[i], "--no-index")) if (!strcmp(argv[i], "--no-index"))
@@ -252,6 +250,8 @@ void diff_no_index(struct rev_info *revs,
revs->diffopt.paths = argv + argc - 2; revs->diffopt.paths = argv + argc - 2;
revs->diffopt.nr_paths = 2; revs->diffopt.nr_paths = 2;
revs->diffopt.skip_stat_unmatch = 1; revs->diffopt.skip_stat_unmatch = 1;
if (!revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
DIFF_OPT_SET(&revs->diffopt, NO_INDEX); DIFF_OPT_SET(&revs->diffopt, NO_INDEX);

10
diff.c
View File

@@ -1757,7 +1757,8 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
struct stat st; struct stat st;
int pos, len; int pos, len;
/* We do not read the cache ourselves here, because the /*
* We do not read the cache ourselves here, because the
* benchmark with my previous version that always reads cache * benchmark with my previous version that always reads cache
* shows that it makes things worse for diff-tree comparing * shows that it makes things worse for diff-tree comparing
* two linux-2.6 kernel trees in an already checked out work * two linux-2.6 kernel trees in an already checked out work
@@ -1797,6 +1798,13 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode)) if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode))
return 0; return 0;
/*
* If ce is marked as "assume unchanged", there is no
* guarantee that work tree matches what we are looking for.
*/
if (ce->ce_flags & CE_VALID)
return 0;
/* /*
* If ce matches the file in the work tree, we can reuse it. * If ce matches the file in the work tree, we can reuse it.
*/ */

View File

@@ -25,10 +25,12 @@ static unsigned int contains(struct diff_filespec *one,
regmatch_t regmatch; regmatch_t regmatch;
int flags = 0; int flags = 0;
assert(data[sz] == '\0');
while (*data && !regexec(regexp, data, 1, &regmatch, flags)) { while (*data && !regexec(regexp, data, 1, &regmatch, flags)) {
flags |= REG_NOTBOL; flags |= REG_NOTBOL;
data += regmatch.rm_so; data += regmatch.rm_eo;
if (*data) data++; if (*data && regmatch.rm_so == regmatch.rm_eo)
data++;
cnt++; cnt++;
} }

19
dir.c
View File

@@ -487,14 +487,14 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
return recurse_into_directory; return recurse_into_directory;
case index_gitdir: case index_gitdir:
if (dir->show_other_directories) if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
return ignore_directory; return ignore_directory;
return show_directory; return show_directory;
case index_nonexistent: case index_nonexistent:
if (dir->show_other_directories) if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
break; break;
if (!dir->no_gitlinks) { if (!(dir->flags & DIR_NO_GITLINKS)) {
unsigned char sha1[20]; unsigned char sha1[20];
if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0) if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
return show_directory; return show_directory;
@@ -503,7 +503,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
} }
/* This is the "show_other_directories" case */ /* This is the "show_other_directories" case */
if (!dir->hide_empty_directories) if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
return show_directory; return show_directory;
if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify)) if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
return ignore_directory; return ignore_directory;
@@ -601,7 +601,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
dtype = DTYPE(de); dtype = DTYPE(de);
exclude = excluded(dir, fullname, &dtype); exclude = excluded(dir, fullname, &dtype);
if (exclude && dir->collect_ignored if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
&& in_pathspec(fullname, baselen + len, simplify)) && in_pathspec(fullname, baselen + len, simplify))
dir_add_ignored(dir, fullname, baselen + len); dir_add_ignored(dir, fullname, baselen + len);
@@ -609,7 +609,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
* Excluded? If we don't explicitly want to show * Excluded? If we don't explicitly want to show
* ignored files, ignore it * ignored files, ignore it
*/ */
if (exclude && !dir->show_ignored) if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
continue; continue;
if (dtype == DT_UNKNOWN) if (dtype == DT_UNKNOWN)
@@ -621,7 +621,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
* even if we don't ignore them, since the * even if we don't ignore them, since the
* directory may contain files that we do.. * directory may contain files that we do..
*/ */
if (!exclude && dir->show_ignored) { if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
if (dtype != DT_DIR) if (dtype != DT_DIR)
continue; continue;
} }
@@ -634,7 +634,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
len++; len++;
switch (treat_directory(dir, fullname, baselen + len, simplify)) { switch (treat_directory(dir, fullname, baselen + len, simplify)) {
case show_directory: case show_directory:
if (exclude != dir->show_ignored) if (exclude != !!(dir->flags
& DIR_SHOW_IGNORED))
continue; continue;
break; break;
case recurse_into_directory: case recurse_into_directory:
@@ -720,7 +721,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
{ {
struct path_simplify *simplify; struct path_simplify *simplify;
if (has_symlink_leading_path(strlen(path), path)) if (has_symlink_leading_path(path, strlen(path)))
return dir->nr; return dir->nr;
simplify = create_simplify(pathspec); simplify = create_simplify(pathspec);

12
dir.h
View File

@@ -34,11 +34,13 @@ struct exclude_stack {
struct dir_struct { struct dir_struct {
int nr, alloc; int nr, alloc;
int ignored_nr, ignored_alloc; int ignored_nr, ignored_alloc;
unsigned int show_ignored:1, enum {
show_other_directories:1, DIR_SHOW_IGNORED = 1<<0,
hide_empty_directories:1, DIR_SHOW_OTHER_DIRECTORIES = 1<<1,
no_gitlinks:1, DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
collect_ignored:1; DIR_NO_GITLINKS = 1<<3,
DIR_COLLECT_IGNORED = 1<<4
} flags;
struct dir_entry **entries; struct dir_entry **entries;
struct dir_entry **ignored; struct dir_entry **ignored;

106
entry.c
View File

@@ -2,15 +2,19 @@
#include "blob.h" #include "blob.h"
#include "dir.h" #include "dir.h"
static void create_directories(const char *path, const struct checkout *state) static void create_directories(const char *path, int path_len,
const struct checkout *state)
{ {
int len = strlen(path); char *buf = xmalloc(path_len + 1);
char *buf = xmalloc(len + 1); int len = 0;
const char *slash = path;
while ((slash = strchr(slash+1, '/')) != NULL) { while (len < path_len) {
len = slash - path; do {
memcpy(buf, path, len); buf[len] = path[len];
len++;
} while (len < path_len && path[len] != '/');
if (len >= path_len)
break;
buf[len] = 0; buf[len] = 0;
/* /*
@@ -20,7 +24,7 @@ static void create_directories(const char *path, const struct checkout *state)
* we test the path components of the prefix with the * we test the path components of the prefix with the
* stat() function instead of the lstat() function. * stat() function instead of the lstat() function.
*/ */
if (has_dirs_only_path(len, buf, state->base_dir_len)) if (has_dirs_only_path(buf, len, state->base_dir_len))
continue; /* ok, it is already a directory. */ continue; /* ok, it is already a directory. */
/* /*
@@ -74,7 +78,7 @@ static int create_file(const char *path, unsigned int mode)
return open(path, O_WRONLY | O_CREAT | O_EXCL, mode); return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
} }
static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned long *size) static void *read_blob_entry(struct cache_entry *ce, unsigned long *size)
{ {
enum object_type type; enum object_type type;
void *new = read_sha1_file(ce->sha1, &type, size); void *new = read_sha1_file(ce->sha1, &type, size);
@@ -89,36 +93,52 @@ static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned
static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile) static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
{ {
int fd; unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
long wrote; int fd, ret, fstat_done = 0;
char *new;
switch (ce->ce_mode & S_IFMT) { struct strbuf buf = STRBUF_INIT;
char *new; unsigned long size;
struct strbuf buf; size_t wrote, newsize = 0;
unsigned long size; struct stat st;
switch (ce_mode_s_ifmt) {
case S_IFREG: case S_IFREG:
new = read_blob_entry(ce, path, &size); case S_IFLNK:
new = read_blob_entry(ce, &size);
if (!new) if (!new)
return error("git checkout-index: unable to read sha1 file of %s (%s)", return error("git checkout-index: unable to read sha1 file of %s (%s)",
path, sha1_to_hex(ce->sha1)); path, sha1_to_hex(ce->sha1));
if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) {
ret = symlink(new, path);
free(new);
if (ret)
return error("git checkout-index: unable to create symlink %s (%s)",
path, strerror(errno));
break;
}
/* /*
* Convert from git internal format to working tree format * Convert from git internal format to working tree format
*/ */
strbuf_init(&buf, 0); if (ce_mode_s_ifmt == S_IFREG &&
if (convert_to_working_tree(ce->name, new, size, &buf)) { convert_to_working_tree(ce->name, new, size, &buf)) {
size_t newsize = 0;
free(new); free(new);
new = strbuf_detach(&buf, &newsize); new = strbuf_detach(&buf, &newsize);
size = newsize; size = newsize;
} }
if (to_tempfile) { if (to_tempfile) {
strcpy(path, ".merge_file_XXXXXX"); if (ce_mode_s_ifmt == S_IFREG)
strcpy(path, ".merge_file_XXXXXX");
else
strcpy(path, ".merge_link_XXXXXX");
fd = mkstemp(path); fd = mkstemp(path);
} else } else if (ce_mode_s_ifmt == S_IFREG) {
fd = create_file(path, ce->ce_mode); fd = create_file(path, ce->ce_mode);
} else {
fd = create_file(path, 0666);
}
if (fd < 0) { if (fd < 0) {
free(new); free(new);
return error("git checkout-index: unable to create file %s (%s)", return error("git checkout-index: unable to create file %s (%s)",
@@ -126,41 +146,16 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
} }
wrote = write_in_full(fd, new, size); wrote = write_in_full(fd, new, size);
/* use fstat() only when path == ce->name */
if (state->refresh_cache && !to_tempfile && !state->base_dir_len) {
fstat(fd, &st);
fstat_done = 1;
}
close(fd); close(fd);
free(new); free(new);
if (wrote != size) if (wrote != size)
return error("git checkout-index: unable to write file %s", path); return error("git checkout-index: unable to write file %s", path);
break; break;
case S_IFLNK:
new = read_blob_entry(ce, path, &size);
if (!new)
return error("git checkout-index: unable to read sha1 file of %s (%s)",
path, sha1_to_hex(ce->sha1));
if (to_tempfile || !has_symlinks) {
if (to_tempfile) {
strcpy(path, ".merge_link_XXXXXX");
fd = mkstemp(path);
} else
fd = create_file(path, 0666);
if (fd < 0) {
free(new);
return error("git checkout-index: unable to create "
"file %s (%s)", path, strerror(errno));
}
wrote = write_in_full(fd, new, size);
close(fd);
free(new);
if (wrote != size)
return error("git checkout-index: unable to write file %s",
path);
} else {
wrote = symlink(new, path);
free(new);
if (wrote)
return error("git checkout-index: unable to create "
"symlink %s (%s)", path, strerror(errno));
}
break;
case S_IFGITLINK: case S_IFGITLINK:
if (to_tempfile) if (to_tempfile)
return error("git checkout-index: cannot create temporary subproject %s", path); return error("git checkout-index: cannot create temporary subproject %s", path);
@@ -172,8 +167,8 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
} }
if (state->refresh_cache) { if (state->refresh_cache) {
struct stat st; if (!fstat_done)
lstat(ce->name, &st); lstat(ce->name, &st);
fill_stat_cache_info(ce, &st); fill_stat_cache_info(ce, &st);
} }
return 0; return 0;
@@ -190,6 +185,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
memcpy(path, state->base_dir, len); memcpy(path, state->base_dir, len);
strcpy(path + len, ce->name); strcpy(path + len, ce->name);
len += ce_namelen(ce);
if (!lstat(path, &st)) { if (!lstat(path, &st)) {
unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID); unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
@@ -218,6 +214,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
return error("unable to unlink old '%s' (%s)", path, strerror(errno)); return error("unable to unlink old '%s' (%s)", path, strerror(errno));
} else if (state->not_new) } else if (state->not_new)
return 0; return 0;
create_directories(path, state); create_directories(path, len, state);
return write_entry(ce, path, state, 0); return write_entry(ce, path, state, 0);
} }

View File

@@ -42,6 +42,7 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
unsigned whitespace_rule_cfg = WS_DEFAULT_RULE; unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
enum branch_track git_branch_track = BRANCH_TRACK_REMOTE; enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
enum rebase_setup_type autorebase = AUTOREBASE_NEVER; enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
/* Parallel index stat data preload? */ /* Parallel index stat data preload? */
int core_preload_index = 0; int core_preload_index = 0;

View File

@@ -28,9 +28,10 @@ const char *system_path(const char *path)
!(prefix = strip_path_suffix(argv0_path, BINDIR)) && !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
!(prefix = strip_path_suffix(argv0_path, "git"))) { !(prefix = strip_path_suffix(argv0_path, "git"))) {
prefix = PREFIX; prefix = PREFIX;
fprintf(stderr, "RUNTIME_PREFIX requested, " /*
"but prefix computation failed. " * RUNTIME_PREFIX requested, but prefix computation failed.
"Using static fallback '%s'.\n", prefix); * Using static fallback.
*/
} }
#endif #endif
@@ -61,6 +62,10 @@ const char *git_extract_argv0_path(const char *argv0)
void git_set_argv_exec_path(const char *exec_path) void git_set_argv_exec_path(const char *exec_path)
{ {
argv_exec_path = exec_path; argv_exec_path = exec_path;
/*
* Propagate this setting to external programs.
*/
setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
} }

View File

@@ -1,4 +1,5 @@
/* /*
(See Documentation/git-fast-import.txt for maintained documentation.)
Format of STDIN stream: Format of STDIN stream:
stream ::= cmd*; stream ::= cmd*;
@@ -18,8 +19,8 @@ Format of STDIN stream:
new_commit ::= 'commit' sp ref_str lf new_commit ::= 'commit' sp ref_str lf
mark? mark?
('author' sp name '<' email '>' when lf)? ('author' sp name sp '<' email '>' sp when lf)?
'committer' sp name '<' email '>' when lf 'committer' sp name sp '<' email '>' sp when lf
commit_msg commit_msg
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)? ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)* ('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
@@ -43,7 +44,7 @@ Format of STDIN stream:
new_tag ::= 'tag' sp tag_str lf new_tag ::= 'tag' sp tag_str lf
'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf 'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
('tagger' sp name '<' email '>' when lf)? ('tagger' sp name sp '<' email '>' sp when lf)?
tag_msg; tag_msg;
tag_msg ::= data; tag_msg ::= data;

View File

@@ -150,6 +150,7 @@
#endif #endif
/* General helper functions */ /* General helper functions */
extern void vreport(const char *prefix, const char *err, va_list params);
extern void usage(const char *err) NORETURN; extern void usage(const char *err) NORETURN;
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
@@ -394,4 +395,18 @@ void git_qsort(void *base, size_t nmemb, size_t size,
# define FORCE_DIR_SET_GID 0 # define FORCE_DIR_SET_GID 0
#endif #endif
#ifdef NO_NSEC
#undef USE_NSEC
#define ST_CTIME_NSEC(st) 0
#define ST_MTIME_NSEC(st) 0
#else
#ifdef USE_ST_TIMESPEC
#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
#else
#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
#endif
#endif
#endif #endif

View File

@@ -272,10 +272,10 @@ test $commits -eq 0 && die "Found nothing to rewrite"
# Rewrite the commits # Rewrite the commits
i=0 git_filter_branch__commit_count=0
while read commit parents; do while read commit parents; do
i=$(($i+1)) git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1))
printf "\rRewrite $commit ($i/$commits)" printf "\rRewrite $commit ($git_filter_branch__commit_count/$commits)"
case "$filter_subdir" in case "$filter_subdir" in
"") "")

View File

@@ -442,6 +442,30 @@ do_rest () {
done done
} }
# skip picking commits whose parents are unchanged
skip_unnecessary_picks () {
fd=3
while read command sha1 rest
do
# fd=3 means we skip the command
case "$fd,$command,$(git rev-parse --verify --quiet $sha1^)" in
3,pick,"$ONTO"*|3,p,"$ONTO"*)
# pick a commit whose parent is current $ONTO -> skip
ONTO=$sha1
;;
3,#*|3,,*)
# copy comments
;;
*)
fd=1
;;
esac
echo "$command${sha1:+ }$sha1${rest:+ }$rest" >&$fd
done <"$TODO" >"$TODO.new" 3>>"$DONE" &&
mv -f "$TODO".new "$TODO" ||
die "Could not skip unnecessary pick commands"
}
# check if no other options are set # check if no other options are set
is_standalone () { is_standalone () {
test $# -eq 2 -a "$2" = '--' && test $# -eq 2 -a "$2" = '--' &&
@@ -746,6 +770,8 @@ EOF
has_action "$TODO" || has_action "$TODO" ||
die_abort "Nothing to do" die_abort "Nothing to do"
test -d "$REWRITTEN" || skip_unnecessary_picks
git update-ref ORIG_HEAD $HEAD git update-ref ORIG_HEAD $HEAD
output git checkout $ONTO && do_rest output git checkout $ONTO && do_rest
;; ;;

View File

@@ -309,13 +309,17 @@ do
;; ;;
esac esac
;; ;;
--committer-date-is-author-date|--ignore-date)
git_am_opt="$git_am_opt $1"
force_rebase=t
;;
-C*) -C*)
git_am_opt="$git_am_opt $1" git_am_opt="$git_am_opt $1"
;; ;;
--root) --root)
rebase_root=t rebase_root=t
;; ;;
-f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force_rebas|--force-rebase) -f|--f|--fo|--for|--forc|force|--force-r|--force-re|--force-reb|--force-reba|--force-rebas|--force-rebase)
force_rebase=t force_rebase=t
;; ;;
-*) -*)

Some files were not shown because too many files have changed in this diff Show More