Mark t1301 permission test to depend on POSIXPERM

This prepares the topic for inclusion to master.
This commit is contained in:
Junio C Hamano 2009-04-12 17:55:18 -07:00
commit 7d5a1806e8
346 changed files with 10262 additions and 4387 deletions

View File

@ -129,3 +129,6 @@ For C programs:
used in the git core command set (unless your command is clearly
separate from it, such as an importer to convert random-scm-X
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_EXTRA =
MANPAGE_XSL = callouts.xsl
MANPAGE_XSL = manpage-normal.xsl
XMLTO_EXTRA =
INSTALL?=install
RM ?= rm -f
DOC_REF = origin/man
@ -59,13 +60,52 @@ endif
-include ../config.mak.autogen
-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
ASCIIDOC_EXTRA += -a asciidoc7compatible
endif
ifdef DOCBOOK_XSL_172
ASCIIDOC_EXTRA += -a docbook-xsl-172
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
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
SHELL_PATH ?= $(SHELL)
# Shell quote;
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
#
# Please note that there is a minor bug in asciidoc.
@ -76,6 +116,32 @@ endif
# 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
html: $(DOC_HTML)
@ -116,10 +182,10 @@ install-pdf: pdf
$(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
install-html: html
sh ./install-webdoc.sh $(DESTDIR)$(htmldir)
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
$(MAKE) -C ../ GIT-VERSION-FILE
$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
-include ../GIT-VERSION-FILE
@ -127,8 +193,8 @@ install-html: html
# Determine "include::" file references in asciidoc files.
#
doc.dep : $(wildcard *.txt) build-docdep.perl
$(RM) $@+ $@
$(PERL_PATH) ./build-docdep.perl >$@+
$(QUIET_GEN)$(RM) $@+ $@ && \
$(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
mv $@+ $@
-include doc.dep
@ -146,102 +212,105 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
$(cmds_txt): cmd-list.made
cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
$(RM) $@
$(PERL_PATH) ./cmd-list.perl ../command-list.txt
$(QUIET_GEN)$(RM) $@ && \
$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
date >$@
clean:
$(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) technical/api-*.html technical/api-index.txt
$(RM) $(cmds_txt) *.made
$(MAN_HTML): %.html : %.txt
$(RM) $@+ $@
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $<
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
mv $@+ $@
%.1 %.5 %.7 : %.xml
$(RM) $@
xmlto -m $(MANPAGE_XSL) man $<
$(QUIET_XMLTO)$(RM) $@ && \
xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
%.xml : %.txt
$(RM) $@+ $@
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $<
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
mv $@+ $@
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.sh $(patsubst %,%.txt,$(API_DOCS))
cd technical && sh ./api-index.sh
$(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh
$(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
XSLT = docbook.xsl
XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
user-manual.html: user-manual.xml
xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
$(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
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
$(RM) $@+ $@
$(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout | \
$(PERL_PATH) fix-texi.perl >$@+
$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
$(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
$(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
rm $@++ && \
mv $@+ $@
user-manual.pdf: user-manual.xml
$(RM) $@+ $@
$(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $<
$(QUIET_DBLATEX)$(RM) $@+ $@ && \
$(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
mv $@+ $@
gitman.texi: $(MAN_XML) cat-texi.perl
$(RM) $@+ $@
$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
($(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 $@+ $@
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
$(RM) $@+ $@
$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+
$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ && \
mv $@+ $@
howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
$(RM) $@+ $@
sh ./howto-index.sh $(wildcard howto/*.txt) >$@+
$(QUIET_GEN)$(RM) $@+ $@ && \
'$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \
mv $@+ $@
$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
$(ASCIIDOC) -b xhtml11 $*.txt
$(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt
WEBDOC_DEST = /pub/software/scm/git/docs
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
$(RM) $@+ $@
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
mv $@+ $@
install-webdoc : html
sh ./install-webdoc.sh $(WEBDOC_DEST)
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
quick-install: quick-install-man
quick-install-man:
sh ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
'$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
quick-install-html:
sh ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
'$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
.PHONY: .FORCE-GIT-VERSION-FILE

View File

@ -7,9 +7,15 @@ 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.
@ -27,9 +33,13 @@ Fixes since v1.6.2.1
* '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.
---
exec >/var/tmp/1
O=v1.6.2.1-23-g67c176f
echo O=$(git describe maint)
git shortlog --no-merges $O..maint
* 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

@ -0,0 +1,22 @@
GIT v1.6.2.3 Release Notes
==========================
Fixes since v1.6.2.2
--------------------
* Setting an octal mode value to core.sharedrepository configuration to
restrict access to the repository to group members did not work as
advertised.
* A fairly large and trivial memory leak while rev-list shows list of
reachable objects has been identified and plugged.
* "git-commit --interactive" did not abort when underlying "git-add -i"
signaled a failure.
* 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.
Many small documentation updates are included as well.

View File

@ -0,0 +1,181 @@
GIT v1.6.3 Release Notes
========================
With the next major release, "git push" into a branch that is
currently checked out will be refused by default. You can choose
what should happen upon such a push by setting the configuration
variable receive.denyCurrentBranch in the receiving repository.
To ease the transition plan, the receiving repository of such a
push running this release will issue a big warning when the
configuration variable is missing. Please refer to:
http://git.or.cz/gitwiki/GitFaq#non-bare
http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
for more details on the reason why this change is needed and the
transition plan.
For a similar reason, "git push $there :$killed" to delete the branch
$killed in a remote repository $there, if $killed branch is the current
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
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
--------------------
(subsystems)
* various git-svn updates.
(performance)
* many uses of lstat(2) in the codepath for "git checkout" have been
optimized out.
* pruning reflog entries that are unreachable from the tip of the ref
during "git reflog prune" (hence "git gc") was very inefficient.
(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
spelled as "--format=<style>". In addition, --format=%formatstring
is a short-hand for --pretty=tformat:%formatstring.
* "--oneline" is a synonym for "--pretty=oneline --abbrev-commit".
* If you realize that you botched the patch when you are editing hunks
with the 'edit' action in git-add -i/-p, you can abort the editor to
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.
* @{-1} is a new way to refer to the last branch you were on introduced in
1.6.2, but the initial implementation did not teach this to a few
commands. Now the syntax works with "branch -m @{-1} newname".
* git-archive learned --output=<file> option.
* git-bisect shows not just the number of remaining commits whose goodness
is unknown, but also shows the estimated number of remaining rounds.
* You can give --date=<format> option to git-blame.
* "git-branch -r" shows HEAD symref that points at a remote branch in
interest of each tracked remote repository.
* "git-branch -v -v" is a new way to get list of names for branches and the
"upstream" branch for them.
* git-config learned -e option to open an editor to edit the config file
directly.
* 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-for-each-ref learned a new "upstream" token.
* git-format-patch can be told to use attachment with a new configuration,
format.attach.
* git-format-patch can be told to produce deep or shallow message threads.
* git-format-patch can be told to always add sign-off with a configuration
variable.
* 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-format-patch gives human readable names to the attached files, when
told to send patches as attachments.
* git-grep learned to highlight the found substrings in color.
* git-imap-send learned to work around Thunderbird's inability to easily
disable format=flowed with a new configuration, imap.preformattedHTML.
* git-rebase can be told to rebase the series even if your branch is a
descendant of the commit you are rebasing onto with --force-rebase
option.
* git-rebase can be told to report diffstat with the --stat option.
* Output from git-remote command has been vastly improved.
* "git remote update --prune $remote" updates from the named remote and
then prunes stale tracking branches.
* git-send-email learned --confirm option to review the Cc: list before
sending the messages out.
(developers)
* 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
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
------------------
All of the fixes in v1.6.2.X maintenance series are included in this
release, unless otherwise noted.
Here are fixes that this release has, but have not been backported to
v1.6.2.X series.
* The initial checkout did not read the attributes from the .gitattribute
file that is being checked out.
* "git-checkout <tree-ish> <submodule>" did not update the index entry at
the named path; it now does.
* git-gc spent excessive amount of time to decide if an object appears
in a locally existing pack (if needed, backport by merging 69e020a).
* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
deciding to descend into a subdirectory but they did not match the
individual paths correctly. This caused pathspecs "abc/d ab" to match
"abc/0" ("abc/d" made them decide to descend into the directory "abc/",
and then "ab" incorrectly matched "abc/0" when it shouldn't).
* "git-merge-recursive" was broken when a submodule entry was involved in
a criss-cross merge situation.
---
exec >/var/tmp/1
O=v1.6.2.3-497-g54a4749
echo O=$(git describe master)
git shortlog --no-merges $O..master ^maint

View File

@ -491,6 +491,12 @@ message, complete the addressing and subject fields, and press send.
Gmail
-----
GMail does not appear to have any way to turn off line wrapping in the web
interface, so this will mangle any emails that you send. You can however
use any IMAP email client to connect to the google imap server, and forward
the emails through that. Just make sure to disable line wrapping in that
email client. Alternatively, use "git send-email" instead.
Submitting properly formatted patches via Gmail is simple now that
IMAP support is available. First, edit your ~/.gitconfig to specify your
account settings:
@ -503,6 +509,9 @@ account settings:
port = 993
sslverify = false
You might need to instead use: folder = "[Google Mail]/Drafts" if you get an error
that the "Folder doesn't exist".
Next, ensure that your Gmail settings are correct. In "Settings" the
"Use Unicode (UTF-8) encoding for outgoing messages" should be checked.
@ -513,3 +522,4 @@ command to send the patch emails to your Gmail Drafts folder.
Go to your Gmail account, open the Drafts folder, find the patch email, fill
in the To: and CC: fields and send away!

View File

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

View File

@ -39,7 +39,7 @@ of lines before or after the line given by <start>.
Show raw timestamp (Default: off).
-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::
Walk history forward instead of backward. Instead of showing
@ -70,6 +70,14 @@ of lines before or after the line given by <start>.
tree copy has the contents of the named file (specify
`-` to make the command read from the standard input).
--date <format>::
The value is one of the following alternatives:
{relative,local,default,iso,rfc,short}. If --date is not
provided, the value of the blame.date config variable is
used. If the blame.date config variable is also not set, the
iso format is used. For more information, See the discussion
of the --date option at linkgit:git-log[1].
-M|<num>|::
Detect moving lines in the file as well. When a commit
moves a block of lines in a file (e.g. the original file

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 name of the section in square brackets and continues until the next
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
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
'`"`' 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
lines. Variables may belong directly to a section or to a given subsection.
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
is taken as 'name' and the variable is recognized as boolean "true".
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.
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
preserve leading or trailing whitespace, or if variable value contains
beginning of comment characters (if it contains '#' or ';').
Double quote '`"`' and backslash '`\`' characters in variable value must
be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'.
Double quote `"` and backslash `\` characters in variable value must
be escaped: use `\"` for `"` and `\\` for `\`.
The following escape sequences (beside '`\"`' and '`\\`') are recognized:
'`\n`' for newline character (NL), '`\t`' for horizontal tabulation (HT, TAB)
and '`\b`' for backspace (BS). No other char escape sequence, nor octal
The following escape sequences (beside `\"` and `\\`) are recognized:
`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
and `\b` for backspace (BS). No other char escape sequence, nor octal
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.
Some variables may require special value format.
@ -221,6 +221,11 @@ core.gitProxy::
Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
(which always applies universally, without the special "for"
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::
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 be explicit. For example, to disable the S option
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
"`LESS=FRSX less -+FRSX -FRX`".
`LESS=FRSX less -+FRSX -FRX`.
core.whitespace::
A comma separated list of common whitespace problems to
@ -468,10 +473,14 @@ branch.autosetuprebase::
This option defaults to never.
branch.<name>.remote::
When in branch <name>, it tells 'git-fetch' which remote to fetch.
If this option is not given, 'git-fetch' defaults to remote "origin".
When in branch <name>, it tells 'git-fetch' and 'git-push' which
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::
Defines, together with branch.<name>.remote, the upstream branch
for the given branch. It tells 'git-fetch'/'git-pull' which
branch to merge and can also affect 'git-push' (see push.default).
When in branch <name>, it tells 'git-fetch' the default
refspec to be marked for merging in FETCH_HEAD. The value is
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
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::
When set to `always`, always use colors for interactive prompts
and displays (such as those used by "git-add --interactive").
@ -677,6 +705,23 @@ format.pretty::
See linkgit:git-log[1], linkgit:git-show[1],
linkgit:git-whatchanged[1].
format.thread::
The default threading style for 'git-format-patch'. Can be
either a boolean value, `shallow` or `deep`. 'Shallow'
threading makes every mail a reply to the head of the series,
where the head is chosen from the cover letter, the
`\--in-reply-to`, and the first patch mail, in this order.
'Deep' threading makes every mail a reply to the previous one.
A true boolean value is the same as `shallow`, and a false
value disables threading.
format.signoff::
A boolean value which lets you enable the `-s/--signoff` option of
format-patch by default. *Note:* Adding the Signed-off-by: line to a
patch should be a conscious act and means that you certify you have
the rights to submit this work under the same open source license.
Please see the 'SubmittingPatches' document for further discussion.
gc.aggressiveWindow::
The window size parameter used in the delta compression
algorithm used by 'git-gc --aggressive'. This defaults
@ -1151,7 +1196,7 @@ pager.<cmd>::
particular git subcommand when writing to a tty. If
`\--paginate` or `\--no-pager` is specified on the command line,
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::
The default merge strategy to use when pulling multiple branches
@ -1160,6 +1205,23 @@ pull.octopus::
pull.twohead::
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 its upstream branch.
* `current` push the current branch to a branch of the same name.
rebase.stat::
Whether to show a diffstat of what changed upstream since the last
rebase. False by default.
receive.fsckObjects::
If it is set to true, git-receive-pack will check all received
objects. It will abort in the case of a malformed object or a

View File

@ -16,6 +16,7 @@ body blockquote {
html body {
margin: 1em 5% 1em 5%;
line-height: 1.2;
font-family: sans-serif;
}
body div {
@ -128,6 +129,15 @@ body pre {
tt.literal, code.literal {
color: navy;
font-family: sans-serif;
}
code.literal:before { content: "'"; }
code.literal:after { content: "'"; }
em {
font-style: italic;
color: #064;
}
div.literallayout p {
@ -137,7 +147,6 @@ div.literallayout p {
div.literallayout {
font-family: monospace;
# margin: 0.5em 10% 0.5em 1em;
margin: 0em;
color: navy;
border: 1px solid silver;
@ -187,7 +196,8 @@ dt {
}
dt span.term {
font-style: italic;
font-style: normal;
color: navy;
}
div.variablelist dd p {

View File

@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
[--output=<file>]
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
[path...]
@ -22,7 +23,7 @@ prepended to the filenames in the archive.
'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
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
used instead. Additionally the commit ID is stored in a global
extended pax header if the tar format is used; it can be extracted
@ -47,12 +48,15 @@ OPTIONS
--prefix=<prefix>/::
Prepend <prefix>/ to each filename in the archive.
--output=<file>::
Write the archive to <file> instead of stdout.
<extra>::
This can be any options that the archiver backend understand.
This can be any options that the archiver backend understands.
See next section.
--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.
--exec=<git-upload-archive>::
@ -105,7 +109,7 @@ EXAMPLES
git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)::
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.
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
----
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
@ -39,7 +39,8 @@ help" or "git bisect -h" to get a long usage description.
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
@ -48,61 +49,63 @@ $ git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
# tested that was good
------------------------------------------------
When you give at least one bad and one good versions, it will bisect
the revision tree and say something like:
When you have specified at least one bad and one good version, the
command bisects the revision tree and outputs something similar to
the following:
------------------------------------------------
Bisecting: 675 revisions left to test after this
------------------------------------------------
and check out the state in the middle. Now, compile that kernel, and
boot it. Now, let's say that this booted kernel works fine, then just
do
The state in the middle of the set of revisions is then checked out.
You would now compile that kernel and boot it. If the booted kernel
works correctly, you would then issue the following command:
------------------------------------------------
$ 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
------------------------------------------------
and you continue along, compiling that one, testing it, and depending
on whether it is good or bad, you say "git bisect good" or "git bisect
bad", and ask for the next bisection.
You keep repeating this process, compiling the tree, testing it, and
depending on whether it is good or bad issuing the command "git bisect good"
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
bad kernel rev in "refs/bisect/bad".
Eventually there will be no more revisions left to bisect, and you
will have been left with the first bad kernel revision in "refs/bisect/bad".
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
------------------------------------------------
to get back to the original branch, instead of being on the bisection
commit ("git bisect start" will do that for you too, actually: it will
reset the bisection state).
This resets the tree to the original branch instead of being on the
bisection commit ("git bisect start" will also do that, as it resets
the bisection state).
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
------------
to see the currently remaining suspects in 'gitk'. `visualize` is a bit
too long to type and `view` is provided as a synonym.
`view` may also be used as a synonym for `visualize`.
If 'DISPLAY' environment variable is not set, 'git log' is used
instead. You can even give command line options such as `-p` and
If the 'DISPLAY' environment variable is not set, 'git log' is used
instead. You can also give command line options such as `-p` and
`--stat`.
------------
@ -112,57 +115,58 @@ $ git bisect view --stat
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
------------
shows what you have done so far. You can truncate its output somewhere
and save it in a file, and run
If you discover that you made a mistake in specifying the status of a
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
------------
if you find later you made a mistake telling good/bad about a
revision.
Avoiding to test a commit
Avoiding testing a commit
~~~~~~~~~~~~~~~~~~~~~~~~~
If in a middle of bisect session, you know what the bisect suggested
to try next is not a good one to test (e.g. the change the commit
If, in the middle of a bisect session, you know that the next suggested
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
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
$ 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
------------
Then compile and test the one you chose to try. After that, tell
bisect what the result was as usual.
Then compile and test the chosen revision, and afterwards mark
the revision as good or bad in the usual manner.
Bisect skip
~~~~~~~~~~~~
Instead of choosing by yourself a nearby commit, you may just want git
to do it for you using:
Instead of choosing by yourself a nearby commit, you can ask git
to do it for you by issuing the command:
------------
$ git bisect skip # Current version cannot be tested
------------
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
more "skip"ped commits.
eventually not be able to tell the first bad commit among a bad commit
and one or more skipped commits.
You can even skip a range of commits, instead of just one commit,
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
------------
would mean that no commit between `v2.5` excluded and `v2.6` included
can be tested.
This tells the bisect process that no commit after `v2.5`, up to and
including `v2.6`, should be tested.
Note that if you want to also skip the first commit of a range you can
use something like:
Note that if you also want to skip the first commit of the range you
would issue the command:
------------
$ 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
paths parameters when you say `bisect start`, like this:
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 specifying
path parameters when issuing the `bisect start` command:
------------
$ git bisect start -- arch/i386 include/asm-i386
------------
If you know beforehand more than one good commits, you can narrow the
bisect space down without doing the whole tree checkout every time you
give good commits. You give the bad revision immediately after `start`
and then you give all the good revisions you have:
If you know beforehand more than one good commit, you can narrow the
bisect space down by specifying all of the good commits immediately after
the bad commit when issuing the `bisect start` command:
------------
$ 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
or bad, you can automatically bisect using:
or bad, you can bisect by issuing the command:
------------
$ git bisect run my_script
$ git bisect run my_script arguments
------------
Note that the "run" script (`my_script` in the above example) should
exit with code 0 in case the current source code is good. Exit with a
Note that the script (`my_script` in the above example) should
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
source code is bad.
Any other exit code will abort the automatic bisect process. (A
program that does "exit(-1)" leaves $? = 255, see exit(3) manual page,
the value is chopped with "& 0377".)
Any other exit code will abort the bisect process. It should be noted
that a program that terminates via "exit(-1)" leaves $? = 255, (see the
exit(3) manual page), as the value is chopped with "& 0377".
The special exit code 125 should be used when the current source code
cannot be tested. If the "run" script exits with this code, the current
revision will be skipped, see `git bisect skip` above.
cannot be tested. If the script exits with this code, the current
revision will be skipped (see `git bisect skip` above).
You may often find that during bisect you want to have near-constant
tweaks (e.g., s/#define DEBUG 0/#define DEBUG 1/ in a header file, or
"revision that does not have this commit needs this patch applied to
work around other problem this bisection is not interested in")
applied to the revision being tested.
You may often find that during a bisect session you want to have
temporary modifications (e.g. s/#define DEBUG 0/#define DEBUG 1/ in a
header file, or "revision that does not have this commit needs this
patch applied to work around another problem this bisection is not
interested in") applied to the revision being tested.
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
before compiling, run the real test, and after the test decides if the
revision (possibly with the needed tweaks) passed the test, rewind the
tree to the pristine state. Finally the "run" script can exit with
the status of the real test to let the "git bisect run" command loop to
determine the outcome.
next revision to test, the script can apply the patch
before compiling, run the real test, and afterwards decide if the
revision (possibly with the needed patch) passed the test and then
rewind the tree to the pristine state. Finally the script should exit
with the status of the real test to let the "git bisect run" command loop
determine the eventual outcome of the bisect session.
EXAMPLES
--------
@ -252,44 +257,60 @@ $ git bisect start HEAD v1.2 -- # HEAD is bad, v1.2 is good
$ git bisect run make # "make" builds the app
------------
* Automatically bisect a test failure between origin and HEAD:
+
------------
$ git bisect start HEAD origin -- # HEAD is bad, origin is good
$ git bisect run make test # "make test" builds and tests
------------
* Automatically bisect a broken test suite:
+
------------
$ cat ~/test.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
$ git bisect start v1.3 v1.1 -- # v1.3 is bad, v1.1 is good
$ git bisect run ~/test.sh
------------
+
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
script.
+
And "make test" should "exit 0", if the test suite passes, and
"exit 1" (for example) otherwise.
"make test" should "exit 0", if the test suite passes, and
"exit 1" otherwise.
* Automatically bisect a broken test case:
+
------------
$ cat ~/test.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 ?
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run ~/test.sh
------------
+
Here "check_test_case.sh" should "exit 0", if the test case passes,
and "exit 1" (for example) otherwise.
Here "check_test_case.sh" should "exit 0" if the test case passes,
and "exit 1" otherwise.
+
It's safer if both "test.sh" and "check_test_case.sh" scripts are
outside the repo to prevent interactions between the bisect, make and
test processes and the scripts.
It is safer if both "test.sh" and "check_test_case.sh" scripts are
outside the repository to prevent interactions between the bisect,
make and test processes and the scripts.
* Automatically bisect a broken test suite:
+
------------
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
------------
+
Does the same as the previous example, but on a single line.
Author
------

View File

@ -18,9 +18,9 @@ DESCRIPTION
Annotates each line in the given file with information from the revision which
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"
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
file (see `-M`). The first number listed is the score.
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
of code to have been moved.
-f::
--show-name::
Show filename in the original commit. By default
filename is shown if there is any line that came from a
file with different name, due to rename detection.
Show the filename in the original commit. By default
the filename is shown if there is any line that came from a
file with a different name, due to rename detection.
-n::
--show-number::
Show line number in the original commit (Default: off).
Show the line number in the original commit (Default: off).
-s::
Suppress author name and timestamp from the output.
Suppress the author name and timestamp from the output.
-w::
Ignore whitespace when comparing parent's version and
child's to find where the lines came from.
Ignore whitespace when comparing the parent's version and
the child's to find where the lines came from.
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;
- the line number of the line in the original 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
group. On subsequent lines this field is absent.
This header line is followed by the following information
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
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 contents of the actual line is output after the above
@ -100,23 +100,23 @@ header elements later.
SPECIFYING RANGES
-----------------
Unlike 'git-blame' and 'git-annotate' in older git, the extent
of annotation can be limited to both line ranges and revision
Unlike 'git-blame' and 'git-annotate' in older versions of git, the extent
of the annotation can be limited to both line ranges and revision
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
line 40):
git blame -L 40,60 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
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
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
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
indicates that the developer was being sloppy and did not
refactor the code properly. You can first find the commit that
@ -162,26 +162,26 @@ annotated.
+
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
beginning of each line about that "extended commit info" (author,
email, committer, dates, summary etc).
beginning of each line describing the extra commit information (author,
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:
"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).
+
[NOTE]
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)
where you don't recognize the tag-words (or care about that particular
lines between the first and last one ("<sha1>" and "filename" lines)
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
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

View File

@ -18,19 +18,19 @@ SYNOPSIS
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
branches to be listed, and option `-a` shows both.
With `--contains`, shows only the branches that contains the named commit
(in other words, the branches whose tip commits are descendant of the
With `--contains`, shows only the branches that contain the named commit
(in other words, the branches whose tip commits are descendants of the
named commit). With `--merged`, only branches merged into 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
the named commit will be listed. Missing <commit> argument defaults to
'HEAD' (i.e. the tip of the current branch).
the named commit will be listed. If the <commit> argument is missing it
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>.
If no <start-point> is given, the branch will be created with a head
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
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
them again. See also 'prune' subcommand of linkgit:git-remote[1] for way to
clean up all obsolete remote-tracking branches.
in the remote repository or if 'git-fetch' was configured not to fetch
them again. See also the 'prune' subcommand of linkgit:git-remote[1] for a
way to clean up all obsolete remote-tracking branches.
OPTIONS
@ -76,14 +76,14 @@ OPTIONS
based sha1 expressions such as "<branchname>@\{yesterday}".
-f::
Force the creation of a new branch even if it means deleting
a branch that already exists with the same name.
Reset <branchname> to <startpoint> if <branchname> exists
already. Without `-f` 'git-branch' refuses to change an existing branch.
-m::
Move/rename a branch and the corresponding reflog.
-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 branches to highlight current, local, and remote branches.
@ -100,20 +100,22 @@ OPTIONS
-v::
--verbose::
Show sha1 and commit subject line for each head.
Show sha1 and commit subject line for each head, along with
relationship to upstream branch (if any). If given twice, print
the name of the upstream branch, as well.
--abbrev=<length>::
Alter minimum display length for sha1 in output listing,
default value is 7.
Alter the sha1's minimum display length in the output listing.
The default value is 7.
--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::
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
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
when the start point is a remote branch. Set the
branch.autosetupmerge configuration variable to `false` if you want
@ -149,13 +151,13 @@ OPTIONS
<newbranch>::
The new name for an existing branch. The same restrictions as for
<branchname> applies.
<branchname> apply.
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
@ -167,7 +169,7 @@ $ git checkout my2.6.14
<1> This step and the next one could be combined into a single step with
"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
@ -176,21 +178,21 @@ $ git branch -d -r origin/todo origin/html origin/man <1>
$ git branch -D test <2>
------------
+
<1> Delete remote-tracking branches "todo", "html", "man". Next 'fetch' or
'pull' will create them again unless you configure them not to. See
linkgit:git-fetch[1].
<2> Delete "test" branch even if the "master" branch (or whichever branch is
currently checked out) does not have all commits from test branch.
<1> Delete the remote-tracking branches "todo", "html" and "man". The next
'fetch' or 'pull' will create them again unless you configure them not to.
See linkgit:git-fetch[1].
<2> Delete the "test" branch even if the "master" branch (or whichever branch
is currently checked out) does not have all commits from the test branch.
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
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:
- `--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
machine be replicated on another machine, but the two machines cannot
be directly connected so the interactive git protocols (git, ssh,
rsync, http) cannot be used. This command provides support for
be directly connected, and therefore the interactive git protocols (git,
ssh, rsync, http) cannot be used. This command provides support for
'git-fetch' and 'git-pull' to operate by packaging objects and references
in an archive at the originating machine, then importing those into
another repository using 'git-fetch' and 'git-pull'
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
bundle assumes that all objects in the basis are already in the
destination repository.
@ -43,7 +43,7 @@ verify <file>::
bundle format itself as well as checking that the prerequisite
commits exist and are fully linked in the current repository.
'git-bundle' prints a list of missing commits, if any, and exits
with non-zero status.
with a non-zero status.
list-heads <file>::
Lists the references defined in the bundle. If followed by a
@ -53,14 +53,14 @@ list-heads <file>::
unbundle <file>::
Passes the objects in the bundle to 'git-index-pack'
for storage in the repository, then prints the names of all
defined references. If a reflist is given, only references
matching those in the given list are printed. This command is
defined references. If a list of references is given, only
references matching those in the list are printed. This command is
really plumbing, intended to be called only by 'git-fetch'.
[git-rev-list-args...]::
A list of arguments, acceptable to 'git-rev-parse' and
'git-rev-list', that specify the specific objects and references
to transport. For example, "master~10..master" causes the
'git-rev-list', that specifies the specific objects and references
to transport. For example, `master\~10..master` causes the
current master reference to be packaged along with all objects
added since its 10th ancestor commit. There is no explicit
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
available. This is principally of use to 'git-fetch', which
expects to receive only those references asked for and not
necessarily everything in the pack (in this case, 'git-bundle' is
acting like 'git-fetch-pack').
necessarily everything in the pack (in this case, 'git-bundle' acts
like 'git-fetch-pack').
SPECIFYING REFERENCES
---------------------
'git-bundle' will only package references that are shown by
'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
than one basis can be specified. The objects packaged are those not
contained in the union of the given bases. Each basis can be
specified explicitly (e.g., ^master~10), or implicitly (e.g.,
master~10..master, --since=10.days.ago master).
specified explicitly (e.g. `^master\~10`), or implicitly (e.g.
`master\~10..master`, `--since=10.days.ago master`).
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
to contain objects already in the destination as these are ignored
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
when unpacking at the destination.
EXAMPLE
@ -97,13 +97,13 @@ EXAMPLE
Assume you want to transfer the history from a repository R1 on machine A
to another repository R2 on machine B.
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).
We want to update R2 with developments made on branch master in R1.
but we can move data from A to B via some mechanism (CD, email, etc.).
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
any basis. You can use a tag to remember up to what commit you sent out
in order to make it easy to later update the other repository with
incremental bundle,
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 last
processed, in order to make it easy to later update the other repository
with an incremental bundle:
----------------
machineA$ cd R1
@ -111,17 +111,17 @@ machineA$ git bundle create file.bundle master
machineA$ git tag -f lastR2bundle master
----------------
Then you sneakernet file.bundle to the target machine B. Because you don't
have to have any object to extract objects from such a bundle, not only
you can fetch/pull from a bundle, you can clone from it as if it was a
remote repository.
Then you transfer file.bundle to the target machine B. If you are creating
the repository on machine B, then you can clone from the bundle as if it
were a remote repository instead of creating an empty repository and then
pulling or fetching objects from the bundle:
----------------
machineB$ git clone /home/me/tmp/file.bundle R2
----------------
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:
------------------------
@ -130,12 +130,12 @@ have an entry like this:
fetch = refs/heads/*:refs/remotes/origin/*
------------------------
You can fetch/pull to update the resulting mine.git repository after
replacing the bundle you store at /home/me/tmp/file.bundle with incremental
updates from here on.
To update the resulting mine.git repository, you can fetch or pull after
replacing the bundle stored at /home/me/tmp/file.bundle with incremental
updates.
After working more in the original repository, you can create an
incremental bundle to update the other:
After working some more in the original repository, you can create an
incremental bundle to update the other repository:
----------------
machineA$ cd R1
@ -143,8 +143,8 @@ machineA$ git bundle create file.bundle lastR2bundle..master
machineA$ git tag -f lastR2bundle master
----------------
and sneakernet it to the other machine to replace /home/me/tmp/file.bundle,
and pull from it.
You then transfer the bundle to the other machine to replace
/home/me/tmp/file.bundle, and pull from it.
----------------
machineB$ cd R2
@ -152,49 +152,49 @@ machineB$ git pull
----------------
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
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:
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
----------------
You can use a basis based on time.
You can use a basis based on time:
----------------
$ 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
----------------
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
----------------
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
regular repository it fetches/pulls from. You can for example map
refs, like this example, when fetching:
regular repository which it fetches or pulls from. You can, for example, map
references when fetching:
----------------
$ git fetch mybundle master:localRef
----------------
Or see what refs it offers.
You can also see what references it offers.
----------------
$ git ls-remote mybundle

View File

@ -3,7 +3,7 @@ git-cat-file(1)
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
@ -14,19 +14,19 @@ SYNOPSIS
DESCRIPTION
-----------
In the first form, provides content or type of objects in the repository. The
type is required unless '-t' or '-p' is used to find the object type, or '-s'
is used to find the object size.
In its first form, the command provides the content or the type of an object in
the repository. The type is required unless '-t' or '-p' is used to find the
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,
and the SHA1, type, and size of each object is printed on stdout.
In the second form, a list of objects (separated by linefeeds) is provided on
stdin, and the SHA1, type, and size of each object is printed on stdout.
OPTIONS
-------
<object>::
The name of the object to show.
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::
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.
--batch-check::
Print the SHA1, type, and size of each object provided on stdin. May not be
combined with any other options or arguments.
Print the SHA1, type, and size of each object provided on stdin. May not
be combined with any other options or arguments.
OUTPUT
------

View File

@ -14,7 +14,7 @@ SYNOPSIS
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.
OPTIONS
@ -23,11 +23,11 @@ OPTIONS
Read file names from stdin instead of from the command-line.
-z::
Only meaningful with `--stdin`; paths are separated with
NUL character instead of LF.
Only meaningful with `--stdin`; paths are separated with a
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
be treated as an attribute.
@ -37,12 +37,12 @@ OUTPUT
The output is of the form:
<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:
'unspecified';; when the attribute is not defined for the path.
'unset';; when the attribute is defined to false.
'set';; when the attribute is defined to true.
'unset';; when the attribute is defined as false.
'set';; when the attribute is defined as true.
<value>;; when a value has been assigned to the attribute.
EXAMPLES
@ -69,7 +69,7 @@ org/example/MyClass.java: diff: java
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
org/example/MyClass.java: myAttr: set

View File

@ -3,52 +3,70 @@ git-check-ref-format(1)
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
--------
[verse]
'git check-ref-format' <refname>
'git check-ref-format' [--branch] <branchname-shorthand>
DESCRIPTION
-----------
Checks if a given 'refname' is acceptable, and exits non-zero if
it is not.
Checks if a given 'refname' is acceptable, and exits with a non-zero
status if it is not.
A reference is used in git to specify branches and tags. A
branch head is stored under `$GIT_DIR/refs/heads` directory, and
a tag is stored under `$GIT_DIR/refs/tags` directory. git
imposes the following rules on how refs are named:
branch head is stored under the `$GIT_DIR/refs/heads` directory, and
a tag is stored under the `$GIT_DIR/refs/tags` directory. git
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
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 `~`,
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 `/` nor a dot `.`.
These rules makes it easy for shell script based tools to parse
refnames, pathname expansion by the shell when a refname is used
. They cannot end with the sequence `.lock`.
. They cannot contain a sequence `@{`.
These rules make it easy for shell script based tools to parse
reference names, pathname expansion by the shell when a reference name is used
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
context this notation means `{caret}ref1 ref2` (i.e. not in
ref1 and in ref2).
. A double-dot `..` is often used as in `ref1..ref2`, and in some
contexts this notation means `{caret}ref1 ref2` (i.e. not in
`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.
. 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.
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".
. at-open-brace `@{` is used as a notation to access a reflog entry.
With the `--branch` option, it expands a branch name shorthand and
prints the name of the branch the shorthand refers to.
EXAMPLE
-------
git check-ref-format --branch @{-1}::
Print the name of the previous branch.
GIT
---

View File

@ -8,7 +8,7 @@ git-checkout - Checkout a branch or paths to the working tree
SYNOPSIS
--------
[verse]
'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]
'git checkout' [-q] [-f] [-t | --track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>]
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
DESCRIPTION
@ -21,15 +21,15 @@ specified, <new_branch>. Using -b will cause <new_branch> to
be created; in this case you can use the --track or --no-track
options, which will be passed to `git branch`.
As a convenience, --track will default to create a branch whose
As a convenience, --track will default to creating a branch whose
name is constructed from the specified branch name by stripping
the first namespace level.
When <paths> are given, this command does *not* switch
branches. It updates the named paths in the working tree from
the index file, or from a named <tree-ish> (most often a commit). In
this case, the `-b` options is meaningless and giving
either of them results in an error. <tree-ish> argument can be
this case, the `-b` and `--track` options are meaningless and giving
either of them results in an error. The <tree-ish> argument can be
used to specify a specific tree-ish (i.e. commit, tag or tree)
to update the index for the given paths before updating the
working tree.
@ -75,14 +75,13 @@ entries; instead, unmerged entries are ignored.
<repository> <refspec>" explicitly. This behavior is the default
when the start point is a remote branch. Set the
branch.autosetupmerge configuration variable to `false` if you want
'git-checkout' and 'git-branch' to always behave as if '--no-track' were
'git checkout' and 'git branch' to always behave as if '--no-track' were
given. Set it to `always` if you want this behavior when the
start-point is either a local or remote branch.
start point is either a local or remote branch.
+
If no '-b' option was given, the name of the new branch will be
derived from the remote branch, by attempting to guess the name
of the branch on remote system. If "remotes/" or "refs/remotes/"
are prefixed, it is stripped away, and then the part up to the
If no '-b' option is given, the name of the new branch will be
derived from the remote branch. If "remotes/" or "refs/remotes/"
is prefixed it is stripped away, and then the part up to the
next slash (which would be the nickname of the remote) is removed.
This would tell us to use "hack" as the local branch when branching
off of "origin/hack" (or "remotes/origin/hack", or even
@ -127,16 +126,20 @@ the conflicted merge in the specified paths.
<new_branch>::
Name for the new branch.
<tree-ish>::
Tree to checkout from (when paths are given). If not specified,
the index will be used.
<branch>::
Branch to checkout; may be any object ID that resolves to a
commit. Defaults to HEAD.
Branch to checkout (when no paths are given); may be any object
ID that resolves to a commit. Defaults to HEAD.
+
When this parameter names a non-branch (but still a valid commit object),
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
"`-`" which is synonymous with "`@\{-1\}`".
`-` which is synonymous with `"@\{-1\}"`.
Detached HEAD
@ -152,12 +155,12 @@ $ git checkout v2.6.18
------------
Earlier versions of git did not allow this and asked you to
create a temporary branch using `-b` option, but starting from
create a temporary branch using the `-b` option, but starting from
version 1.5.0, the above command 'detaches' your HEAD from the
current branch and directly point at the commit named by the tag
(`v2.6.18` in the above example).
current branch and directly points at the commit named by the tag
(`v2.6.18` in the example above).
You can use usual git commands while in this state. You can use
You can use all git commands while in this state. You can use
`git reset --hard $othercommit` to further move around, for
example. You can make changes and create a new commit on top of
a detached HEAD. You can even create a merge by using `git
@ -191,8 +194,8 @@ $ git checkout hello.c <3>
------------
+
<1> switch branch
<2> take out a file out of other commit
<3> restore hello.c from HEAD of current branch
<2> take a file out of another commit
<3> restore hello.c from the index
+
If you have an unfortunate branch that is named `hello.c`, this
step would be confused as an instruction to switch to that branch.
@ -202,7 +205,7 @@ You should instead write:
$ git checkout -- hello.c
------------
. After working in a wrong branch, switching to the correct
. After working in the wrong branch, switching to the correct
branch would be done using:
+
------------
@ -210,7 +213,7 @@ $ git checkout mytopic
------------
+
However, your "wrong" branch and correct "mytopic" branch may
differ in files that you have locally modified, in which case,
differ in files that you have modified locally, in which case
the above checkout would fail like this:
+
------------

View File

@ -117,7 +117,7 @@ then the cloned repository will become corrupt.
--origin <name>::
-o <name>::
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>::
-u <upload-pack>::

View File

@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]]
'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-all name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
@ -22,6 +22,7 @@ SYNOPSIS
'git config' [<file-option>] [-z|--null] -l | --list
'git config' [<file-option>] --get-color name [default]
'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
'git config' [<file-option>] -e | --edit
DESCRIPTION
-----------
@ -161,6 +162,11 @@ See also <<FILES>>.
output. The optional `default` parameter is used instead, if
there is no color configured for `name`.
-e::
--edit::
Opens an editor to modify the specified config file; either
'--system', '--global', or repository (default).
[[FILES]]
FILES
-----

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'.
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
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
@ -62,7 +65,7 @@ OPTIONS
-r <remote>::
The git remote to import this CVS repository into.
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>::
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
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
------

View File

@ -31,6 +31,9 @@ changes, which would normally have no effect. Nevertheless, this may be
useful in the future for compensating for some git bugs or such,
therefore such a usage is permitted.
*NOTE*: This command honors `.git/info/grafts`. If you have any grafts
defined, running this command will make them permanent.
*WARNING*! The rewritten history will have different object names for all
the objects and will not converge with the original branch. You will not
be able to easily push and distribute the rewritten branch on top of the
@ -91,7 +94,9 @@ OPTIONS
--index-filter <command>::
This is the filter for rewriting the index. It is similar to the
tree filter but does not check out the tree, which makes it much
faster. For hairy cases, see linkgit:git-update-index[1].
faster. Frequently used with `git rm \--cached
\--ignore-unmatch ...`, see EXAMPLES below. For hairy
cases, see linkgit:git-update-index[1].
--parent-filter <command>::
This is the filter for rewriting the commit's parent list.
@ -204,19 +209,18 @@ However, if the file is absent from the tree of some commit,
a simple `rm filename` will fail for that tree and commit.
Thus you may instead want to use `rm -f filename` as the script.
A significantly faster version:
Using `\--index-filter` with 'git-rm' yields a significantly faster
version. Like with using `rm filename`, `git rm --cached filename`
will fail if the file is absent from the tree of a commit. If you
want to "completely forget" a file, it does not matter when it entered
history, so we also add `\--ignore-unmatch`:
--------------------------------------------------------------------------
git filter-branch --index-filter 'git rm --cached filename' HEAD
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
--------------------------------------------------------------------------
Now, you will get the rewritten history saved in HEAD.
As with using `rm filename`, `git rm --cached filename` will fail
if the file is absent from the tree of a commit. If it is not important
whether the file is already absent from the tree, you can use
`git rm --cached --ignore-unmatch filename` instead.
To rewrite the repository to look as if `foodir/` had been its project
root, and discard all other history:

View File

@ -85,6 +85,11 @@ objectsize::
objectname::
The object name (aka SHA-1).
upstream::
The name of a local ref which can be considered ``upstream''
from the displayed ref. Respects `:short` in the same way as
`refname` above.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
be used to specify the value in the header field.

View File

@ -10,7 +10,8 @@ SYNOPSIS
--------
[verse]
'git format-patch' [-k] [-o <dir> | --stdout] [--thread]
[--attach[=<boundary>] | --inline[=<boundary>]]
[--attach[=<boundary>] | --inline[=<boundary>] |
[--no-attach]]
[-s | --signoff] [<common diff options>]
[-n | --numbered | -N | --no-numbered]
[--start-number <n>] [--numbered-files]
@ -39,15 +40,11 @@ There are two ways to specify which commits to operate on.
REVISIONS" section in linkgit:git-rev-parse[1]) means the
commits in the specified range.
A single commit, when interpreted as a <revision range>
expression, means "everything that leads to that commit", but
if you write 'git format-patch <commit>', the previous rule
applies to that command line and you do not get "everything
since the beginning of the time". If you want to format
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>".
The first rule takes precedence in the case of a single <commit>. To
apply the second rule, i.e., format everything since the beginning of
history up until <commit>, use the '\--root' option: "git format-patch
\--root <commit>". If you want to format only <commit> itself, you
can do this with "git format-patch -1 <commit>".
By default, each output file is numbered sequentially from 1, and uses the
first line of the commit message (massaged for pathname safety) as
@ -116,15 +113,27 @@ include::diff-options.txt[]
which is the commit message and the patch itself in the
second part, with "Content-Disposition: attachment".
--no-attach::
Disable the creation of an attachment, overriding the
configuration setting.
--inline[=<boundary>]::
Create multipart/mixed attachment, the first part of
which is the commit message and the patch itself in the
second part, with "Content-Disposition: inline".
--thread::
--thread[=<style>]::
Add In-Reply-To and References headers to make the second and
subsequent mails appear as replies to the first. Also generates
the Message-Id header to reference.
+
The optional <style> argument can be either `shallow` or `deep`.
'Shallow' threading makes every mail a reply to the head of the
series, where the head is chosen from the cover letter, the
`\--in-reply-to`, and the first patch mail, in this order. 'Deep'
threading makes every mail a reply to the previous one. If not
specified, defaults to the 'format.thread' configuration, or `shallow`
if that is not set.
--in-reply-to=Message-Id::
Make the first mail (or all the mails with --no-thread) appear as a
@ -148,6 +157,11 @@ include::diff-options.txt[]
Add a "Cc:" header to the email headers. This is in addition
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::
In addition to the patches, generate a cover letter file
containing the shortlog and the overall diffstat. You can
@ -169,11 +183,19 @@ not add any suffix.
applied. By default the contents of changes in those files are
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
-------------
You can specify extra mail header lines to be added to each message
in the repository configuration, new defaults for the subject prefix
and file suffix, and number patches when outputting more than one.
and file suffix, control attachements, and number patches when outputting
more than one.
------------
[format]
@ -182,6 +204,8 @@ and file suffix, and number patches when outputting more than one.
suffix = .txt
numbered = auto
cc = <email>
attach [ = mime-boundary-string ]
signoff = true
------------

View File

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

View File

@ -64,6 +64,13 @@ imap.sslverify::
used by the SSL/TLS connection. Default is `true`. Ignored when
imap.tunnel is set.
imap.preformattedHTML::
A boolean to enable/disable the use of html encoding when sending
a patch. An html encoded patch will be bracketed with <pre>
and have a content type of text/html. Ironically, enabling this
option causes Thunderbird to send the patch as a plain/text,
format=fixed email. Default is `false`.
Examples
~~~~~~~~

View File

@ -40,8 +40,8 @@ include::merge-options.txt[]
include::merge-strategies.txt[]
If you tried a merge which resulted in a complex conflicts and
would want to start over, you can recover with 'git-reset'.
If you tried a merge which resulted in complex conflicts and
want to start over, you can recover with 'git-reset'.
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
"`<<<<<<<`", "`=======`", and "`>>>>>>>`". The part before the "`=======`"
`<<<<<<<`, `=======`, and `>>>>>>>`. The part before the `=======`
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
@ -173,8 +173,8 @@ Git makes conflict resolution easy.
And here is another line that is cleanly resolved or unmodified.
------------
In addition to the "`<<<<<<<`", "`=======`", and "`>>>>>>>`" markers, it uses
another "`|||||||`" marker that is followed by the original text. You can
In addition to the `<<<<<<<`, `=======`, and `>>>>>>>` markers, it uses
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
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

View File

@ -26,7 +26,7 @@ problem by stashing the refs in a single file,
traditional `$GIT_DIR/refs` hierarchy, it is looked up in this
file and used if found.
Subsequent updates to branches always creates new file under
Subsequent updates to branches always create new files under
`$GIT_DIR/refs` hierarchy.
A recommended practice to deal with a repository with too many
@ -35,7 +35,7 @@ occasionally run `git pack-refs \--prune`. Tags are by
definition stationary and are not expected to change. Branch
heads will be packed with the initial `pack-refs --all`, but
only the currently active branch heads will become unpacked,
and next `pack-refs` (without `--all`) will leave them
and the next `pack-refs` (without `--all`) will leave them
unpacked.

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
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.
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].
OPTIONS
-------
OPTIONS[[OPTIONS]]
------------------
<repository>::
The "remote" repository that is destination of a push
operation. This parameter can be either a URL
@ -187,6 +187,28 @@ reason::
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::
Find a ref that matches `master` in the source repository
(most likely, it would find `refs/heads/master`), and update

View File

@ -192,6 +192,13 @@ Alternatively, you can undo the 'git-rebase' with
git rebase --abort
CONFIGURATION
-------------
rebase.stat::
Whether to show a diffstat of what changed upstream since the last
rebase. False by default.
OPTIONS
-------
<newbase>::
@ -232,7 +239,15 @@ OPTIONS
-v::
--verbose::
Display a diffstat of what changed upstream since the last rebase.
Be verbose. Implies --stat.
--stat::
Show a diffstat of what changed upstream since the last rebase. The
diffstat is also controlled by the configuration option rebase.stat.
-n::
--no-stat::
Do not show a diffstat as part of the rebase process.
--no-verify::
This option bypasses the pre-rebase hook. See also linkgit:githooks[5].
@ -243,11 +258,23 @@ OPTIONS
context exist they all must match. By default no context is
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>::
This flag is passed to the 'git-apply' program
(see linkgit:git-apply[1]) that applies the patch.
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::
--interactive::
Make a list of the commits which are about to be rebased. Let the

View File

@ -13,9 +13,10 @@ SYNOPSIS
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
'git remote rename' <old> <new>
'git remote rm' <name>
'git remote set-head' <name> [-a | -d | <branch>]
'git remote show' [-n] <name>
'git remote prune' [-n | --dry-run] <name>
'git remote update' [group]
'git remote update' [-p | --prune] [group | remote]...
DESCRIPTION
-----------
@ -53,8 +54,7 @@ is created. You can give more than one `-t <branch>` to track
multiple branches without grabbing all branches.
+
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
up to point at remote's `<master>` branch instead of whatever
branch the `HEAD` at the remote repository actually points at.
up to point at remote's `<master>` branch. See also the set-head command.
+
In mirror mode, enabled with `\--mirror`, the refs will not be stored
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
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'::
Gives some information about the remote <name>.
@ -101,6 +125,8 @@ the configuration parameter remotes.default will get used; if
remotes.default is not defined, all remotes which do not have the
configuration parameter remote.<name>.skipDefaultUpdate set to true will
be updated. (See linkgit:git-config[1]).
+
With `--prune` option, prune all the remotes that are updated.
DISCUSSION

View File

@ -299,18 +299,18 @@ previous section means the set of commits reachable from that
commit, following the commit ancestry chain.
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`.
This set operation appears so often that there is a shorthand
for it. When you have two commits `r1` and `r2` (named according
to the syntax explained in SPECIFYING REVISIONS above), you can ask
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
"`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
`r1` or `r2` but not from both.

View File

@ -39,13 +39,13 @@ OPTIONS
Composing
~~~~~~~~~
--bcc::
--bcc=<address>::
Specify a "Bcc:" value for each email. Default is the value of
'sendemail.bcc'.
+
The --bcc option must be repeated for each user you want on the bcc list.
--cc::
--cc=<address>::
Specify a starting "Cc:" value for each email.
Default is the value of 'sendemail.cc'.
+
@ -60,33 +60,32 @@ 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
introductory message for the patch series.
+
When '--compose' is used, git send-email gets less interactive will use the
values of the headers you set there. If the body of the email (what you type
after the headers and a blank line) only contains blank (or GIT: prefixed)
lines, the summary won't be sent, but git-send-email will still use the
Headers values if you don't removed them.
When '--compose' is used, git send-email will use the From, Subject, and
In-Reply-To headers specified in the message. If the body of the message
(what you type after the headers and a blank line) only contains blank
(or GIT: prefixed) lines the summary won't be sent, but From, Subject,
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
interactively after quitting your editor.
Missing From or In-Reply-To headers will be prompted for.
--from::
--from=<address>::
Specify the sender of the emails. This will default to
the value GIT_COMMITTER_IDENT, as returned by "git var -l".
The user will still be prompted to confirm this entry.
--in-reply-to::
--in-reply-to=<identifier>::
Specify the contents of the first In-Reply-To header.
Subsequent emails will refer to the previous email
instead of this if --chain-reply-to is set (the default)
Only necessary if --compose is also set. If --compose
is not set, this will be prompted for.
--subject::
--subject=<string>::
Specify the initial subject of the email thread.
Only necessary if --compose is also set. If --compose
is not set, this will be prompted for.
--to::
--to=<address>::
Specify the primary recipient of the emails generated. Generally, this
will be the upstream maintainer of the project involved. Default is the
value of the 'sendemail.to' configuration value; if that is unspecified,
@ -98,7 +97,7 @@ The --to option must be repeated for each user you want on the to list.
Sending
~~~~~~~
--envelope-sender::
--envelope-sender=<address>::
Specify the envelope sender used to send the emails.
This is useful if your default address is not the address that is
subscribed to a list. If you use the sendmail binary, you must have
@ -106,12 +105,12 @@ Sending
the 'sendemail.envelopesender' configuration variable; if that is
unspecified, choosing the envelope sender is left to your MTA.
--smtp-encryption::
--smtp-encryption=<encryption>::
Specify the encryption to use, either 'ssl' or 'tls'. Any other
value reverts to plain SMTP. Default is the value of
'sendemail.smtpencryption'.
--smtp-pass::
--smtp-pass[=<password>]::
Password for SMTP-AUTH. The argument is optional: If no
argument is specified, then the empty string is used as
the password. Default is the value of 'sendemail.smtppass',
@ -123,7 +122,7 @@ or on the command line. If a username has been specified (with
specified (with '--smtp-pass' or 'sendemail.smtppass'), then the
user is prompted for a password while the input is masked for privacy.
--smtp-server::
--smtp-server=<host>::
If set, specifies the outgoing SMTP server to use (e.g.
`smtp.example.com` or a raw IP address). Alternatively it can
specify a full pathname of a sendmail-like program instead;
@ -133,7 +132,7 @@ user is prompted for a password while the input is masked for privacy.
`/usr/lib/sendmail` if such program is available, or
`localhost` otherwise.
--smtp-server-port::
--smtp-server-port=<port>::
Specifies a port different from the default port (SMTP
servers typically listen to smtp port 25 and ssmtp port
465). This can be set with 'sendemail.smtpserverport'.
@ -141,7 +140,7 @@ user is prompted for a password while the input is masked for privacy.
--smtp-ssl::
Legacy alias for '--smtp-encryption ssl'.
--smtp-user::
--smtp-user=<user>::
Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
then authentication is not attempted.
@ -150,13 +149,13 @@ user is prompted for a password while the input is masked for privacy.
Automating
~~~~~~~~~~
--cc-cmd::
--cc-cmd=<command>::
Specify a command to execute once per patch file which
should generate patch file specific "Cc:" entries.
Output of this command must be single email address per line.
Default is the value of 'sendemail.cccmd' configuration value.
--[no-]chain-reply-to::
--[no-]chain-reply-to=<identifier>::
If this is set, each email will be sent as a reply to the previous
email sent. If disabled with "--no-chain-reply-to", all emails after
the first will be sent as replies to the first email sent. When using
@ -164,7 +163,7 @@ Automating
entire patch series. Default is the value of the 'sendemail.chainreplyto'
configuration value; if that is unspecified, default to --chain-reply-to.
--identity::
--identity=<identity>::
A configuration identity. When given, causes values in the
'sendemail.<identity>' subsection to take precedence over
values in the 'sendemail' section. The default identity is
@ -175,7 +174,7 @@ Automating
cc list. Default is the value of 'sendemail.signedoffbycc' configuration
value; if that is unspecified, default to --signed-off-by-cc.
--suppress-cc::
--suppress-cc=<category>::
Specify an additional category of recipients to suppress the
auto-cc of:
+
@ -212,6 +211,22 @@ specified, as well as 'body' if --no-signed-off-cc is specified.
Administering
~~~~~~~~~~~~~
--confirm=<mode>::
Confirm just before sending:
+
--
- 'always' will always confirm before sending
- 'never' will never confirm before sending
- 'cc' will confirm before sending when send-email has automatically
added addresses from the patch to the Cc list
- 'compose' will confirm before sending the first message when using --compose.
- 'auto' is equivalent to 'cc' + 'compose'
--
+
Default is the value of 'sendemail.confirm' configuration value; if that
is unspecified, default to 'auto' unless any of the suppress options
have been specified, in which case default to 'compose'.
--dry-run::
Do everything except actually send the emails.
@ -255,6 +270,11 @@ sendemail.multiedit::
summary when '--compose' is used). If false, files will be edited one
after the other, spawning a new editor each time.
sendemail.confirm::
Sets the default for whether to confirm before sending. Must be
one of 'always', 'never', 'cc', 'compose', or 'auto'. See '--confirm'
in the previous section for the meaning of these values.
Author
------

View File

@ -85,6 +85,10 @@ COMMANDS
specified, the prefix must include a trailing slash.
Setting a prefix is useful if you wish to track multiple
projects that share a common repository.
--ignore-paths=<regex>;;
When passed to 'init' or 'clone' this regular expression will
be preserved as a config key. See 'fetch' for a description
of '--ignore-paths'.
'fetch'::
Fetch unfetched revisions from the Subversion remote we are
@ -97,6 +101,9 @@ COMMANDS
makes 'git-log' (even without --date=local) show the same times
that `svn log` would in the local timezone.
--parent;;
Fetch only from the SVN parent of the current HEAD.
This doesn't interfere with interoperating with the Subversion
repository you cloned from, but if you wish for your local Git
repository to be able to interoperate with someone else's local Git
@ -104,17 +111,25 @@ repository, either don't use this option or you should both use it in
the same local timezone.
--ignore-paths=<regex>;;
This allows one to specify Perl regular expression that will
This allows one to specify a Perl regular expression that will
cause skipping of all matching paths from checkout from SVN.
Examples:
The '--ignore-paths' option should match for every 'fetch'
(including automatic fetches due to 'clone', 'dcommit',
'rebase', etc) on a given repository.
--ignore-paths="^doc" - skip "doc*" directory for every fetch.
config key: svn-remote.<name>.ignore-paths
--ignore-paths="^[^/]+/(?:branches|tags)" - skip "branches"
and "tags" of first level directories.
If the ignore-paths config key is set and the command
line option is also given, both regular expressions
will be used.
Regular expression is not persistent, you should specify
it every time when fetching.
Examples:
--ignore-paths="^doc" - skip "doc*" directory for every
fetch.
--ignore-paths="^[^/]+/(?:branches|tags)" - skip
"branches" and "tags" of first level directories.
'clone'::
Runs 'init' and 'fetch'. It will automatically create a
@ -385,7 +400,8 @@ config key: svn.authorsfile
-q::
--quiet::
Make 'git-svn' less verbose.
Make 'git-svn' less verbose. Specify a second time to make it
even less verbose.
--repack[=<n>]::
--repack-flags=<flags>::
@ -672,9 +688,9 @@ listed below are allowed:
------------------------------------------------------------------------
[svn-remote "project-a"]
url = http://server.org/svn
fetch = trunk/project-a:refs/remotes/project-a/trunk
branches = branches/*/project-a:refs/remotes/project-a/branches/*
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

View File

@ -63,6 +63,7 @@ OPTIONS
are printed when using -l.
The default is not to print any annotation lines.
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>::
List tags with names that match the given pattern (or all if no pattern is given).

View File

@ -9,7 +9,7 @@ git - the stupid content tracker
SYNOPSIS
--------
[verse]
'git' [--version] [--exec-path[=GIT_EXEC_PATH]]
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
[-p|--paginate|--no-pager]
[--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
[--help] COMMAND [ARGS]
@ -43,9 +43,12 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
* link:v1.6.2/git.html[documentation for release 1.6.2]
* link:v1.6.2.3/git.html[documentation for release 1.6.2.3]
* release notes for
link:RelNotes-1.6.2.3.txt[1.6.2.3],
link:RelNotes-1.6.2.2.txt[1.6.2.2],
link:RelNotes-1.6.2.1.txt[1.6.2.1],
link:RelNotes-1.6.2.txt[1.6.2].
* link:v1.6.1.3/git.html[documentation for release 1.6.1.3]
@ -177,6 +180,10 @@ help ...`.
environment variable. If no path is given, 'git' will print
the current setting and then exit.
--html-path::
Print the path to wherever your git HTML documentation is installed
and exit.
-p::
--paginate::
Pipe all output into 'less' (or if set, $PAGER).

View File

@ -60,9 +60,9 @@ same as in `.gitignore` files; see linkgit:gitignore[5].
When deciding what attributes are assigned to a path, git
consults `$GIT_DIR/info/attributes` file (which has the highest
precedence), `.gitattributes` file in the same directory as the
path in question, and its parent directories (the further the
directory that contains `.gitattributes` is from the path in
question, the lower its precedence).
path in question, and its parent directories up to the toplevel of the
work tree (the further the directory that contains `.gitattributes`
is from the path in question, the lower its precedence).
If you wish to affect only a single repository (i.e., to assign
attributes to files that are particular to one user's workflow), then

View File

@ -46,20 +46,20 @@ Here are the rules regarding the "flags" that you should follow when you are
scripting git:
* 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"`
to `"git foo -ab"`, the latter may not even work).
* splitting short options to separate words (prefer `git foo -a -b`
to `git foo -ab`, the latter may not even work).
* 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
options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"`
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`
for long options. An option that takes optional option-argument must be
written in the 'sticked' form.
* 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
`"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.
@ -99,17 +99,17 @@ usage: git-describe [options] <committish>*
Negating options
~~~~~~~~~~~~~~~~
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
can use `"--no-track"` to override that behaviour. The same goes for `"--color"`
and `"--no-color"`.
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
can use `--no-track` to override that behaviour. The same goes for `--color`
and `--no-color`.
Aggregating short options
~~~~~~~~~~~~~~~~~~~~~~~~~
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
`"git clean -fdx"`.
options. This means that you can for example use `git rm -rf` or
`git clean -fdx`.
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).
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
differences from the previous HEAD if different, or set working dir metadata
properties.

View File

@ -31,8 +31,8 @@ precedence, the last matching pattern decides the outcome):
* Patterns read from a `.gitignore` file in the same directory
as the path, or in any parent directory, with patterns in the
higher level files (up to the root) being overridden by those in
lower level files down to the directory containing the file.
higher level files (up to the toplevel of the work tree) being overridden
by those in lower level files down to the directory containing the file.
These patterns match relative to the location of the
`.gitignore` file. A project normally includes such
`.gitignore` files in its repository, containing patterns for

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
will be fetched into remote <<def_tracking_branch,tracking branches>> named
origin/name-of-upstream-branch, which you can see using
"`git branch -r`".
`git branch -r`.
[[def_pack]]pack::
A set of objects which have been compressed into one file (to save space
@ -449,6 +449,12 @@ This commit is referred to as a "merge commit", or sometimes just a
An <<def_object,object>> which is not <<def_reachable,reachable>> from a
<<def_branch,branch>>, <<def_tag,tag>>, or any other reference.
[[def_upstream_branch]]upstream branch::
The default <<def_branch,branch>> that is merged into the branch in
question (or the branch in question is rebased onto). It is configured
via branch.<name>.remote and branch.<name>.merge. If the upstream branch
of 'A' is 'origin/B' sometimes we say "'A' is tracking 'origin/B'".
[[def_working_tree]]working tree::
The tree of actual checked out files. The working tree is
normally equal to the <<def_HEAD,HEAD>> plus any local changes

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
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
this
commit (enclosed by '<' and '>') to map to the name. For example:
--
Proper Name <commit@email.xx>
--
The more complex forms are
The more complex forms are:
--
<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>
--
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>
--
@ -47,8 +46,8 @@ Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com>
------------
Note how we don't need an entry for <jane@laptop.(none)>, because the
real name of that author is correct already.
Note how there is no need for an entry for <jane@laptop.(none)>, because the
real name of that author is already correct.
Example 2: Your repository contains commits from the following
authors:
@ -62,7 +61,7 @@ claus <me@company.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>
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
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 -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- manpage-1.72.xsl:
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:param name="refentry.meta.get.quietly" select="1"/>
<xsl:import href="manpage-base.xsl"/>
<xsl:template match="co">
<xsl:value-of select="concat('&#x2593;fB(',substring-after(@id,'-'),')&#x2593;fR')"/>
</xsl:template>
<xsl:template match="calloutlist">
<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>
<!-- these are the special values for the roff control characters
needed for docbook-xsl 1.72.0 -->
<xsl:param name="git.docbook.backslash">&#x2593;</xsl:param>
<xsl:param name="git.docbook.dot" >&#x2302;</xsl:param>
</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::
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
merge ambiguities and is considered generally safe and
fast.
recursive::
This can only resolve two heads using 3-way merge
algorithm. When there are more than one common
ancestors that can be used for 3-way merge, it creates a
This can only resolve two heads using a 3-way merge
algorithm. When there is more than one common
ancestor that can be used for 3-way merge, it creates a
merged tree of the common ancestors and uses that as
the reference tree for the 3-way merge. This has been
reported to result in fewer merge conflicts without
@ -22,11 +22,11 @@ recursive::
pulling or merging one branch.
octopus::
This resolves more than two-head case, but refuses to do
complex merge that needs manual resolution. It is
This resolves cases with more than two heads, but refuses to do
a complex merge that needs manual resolution. It is
primarily meant to be used for bundling topic branch
heads together. This is the default merge strategy when
pulling or merging more than one branches.
pulling or merging more than one branch.
ours::
This resolves any number of heads, but the result of the

View File

@ -121,6 +121,7 @@ The placeholders are:
- '%d': ref names, like the --decorate option of linkgit:git-log[1]
- '%e': encoding
- '%s': subject
- '%f': sanitized subject line, suitable for a filename
- '%b': body
- '%Cred': switch color to red
- '%Cgreen': switch color to green
@ -152,3 +153,12 @@ $ git log -2 --pretty=tformat:%h 4da45bef \
4da45be
7134973
---------------------
+
In addition, any unrecognized string that has a `%` in it is interpreted
as if it has `tformat:` in front of it. For example, these two are
equivalent:
+
---------------------
$ git log -2 --pretty=tformat:%h 4da45bef
$ git log -2 --pretty=%h 4da45bef
---------------------

View File

@ -1,4 +1,5 @@
--pretty[='<format>']::
--format[='<format>']::
Pretty-print the contents of the commit logs in a given format,
where '<format>' can be one of 'oneline', 'short', 'medium',
@ -17,6 +18,10 @@ configuration (see linkgit:git-config[1]).
This should make "--pretty=oneline" a whole lot more readable for
people using 80-column terminals.
--oneline::
This is a shorthand for "--pretty=oneline --abbrev-commit"
used together.
--encoding[=<encoding>]::
The commit objects record the encoding used for the log message
in their encoding header; this option can be used to tell the

View File

@ -140,38 +140,38 @@ limiting may be applied.
--
-n 'number'::
--max-count='number'::
--max-count=<number>::
Limit the number of commits output.
--skip='number'::
--skip=<number>::
Skip 'number' commits before starting to show the commit output.
--since='date'::
--after='date'::
--since=<date>::
--after=<date>::
Show commits more recent than a specific date.
--until='date'::
--before='date'::
--until=<date>::
--before=<date>::
Show commits older than a specific date.
ifdef::git-rev-list[]
--max-age='timestamp'::
--min-age='timestamp'::
--max-age=<timestamp>::
--min-age=<timestamp>::
Limit the commits output to specified time range.
endif::git-rev-list[]
--author='pattern'::
--committer='pattern'::
--author=<pattern>::
--committer=<pattern>::
Limit the commits output to ones with author/committer
header lines that match the specified pattern (regular expression).
--grep='pattern'::
--grep=<pattern>::
Limit the commits output to ones with log message that
matches the specified pattern (regular expression).

View File

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

View File

@ -66,6 +66,12 @@ Steps to parse options
non-option arguments in `argv[]`.
`argc` is updated appropriately because of the assignment.
+
You can also pass NULL instead of a usage array as fourth parameter of
parse_options(), to avoid displaying a help screen with usage info and
option list. This should only be done if necessary, e.g. to implement
a limited parser for only a subset of the options that needs to be run
before the full parser, which in turn shows the full help message.
+
Flags are the bitwise-or of:
`PARSE_OPT_KEEP_DASHDASH`::
@ -77,6 +83,28 @@ Flags are the bitwise-or of:
Using this flag, processing is stopped at the first non-option
argument.
`PARSE_OPT_KEEP_ARGV0`::
Keep the first argument, which contains the program name. It's
removed from argv[] by default.
`PARSE_OPT_KEEP_UNKNOWN`::
Keep unknown arguments instead of erroring out. This doesn't
work for all combinations of arguments as users might expect
it to do. E.g. if the first argument in `--unknown --known`
takes a value (which we can't know), the second one is
mistakenly interpreted as a known option. Similarly, if
`PARSE_OPT_STOP_AT_NON_OPTION` is set, the second argument in
`--unknown value` will be mistakenly interpreted as a
non-option, not as a value belonging to the unknown option,
the parser early. That's why parse_options() errors out if
both options are set.
`PARSE_OPT_NO_INTERNAL_HELP`::
By default, parse_options() handles `-h`, `--help` and
`--help-all` internally, by showing a help screen. This option
turns it off and allows one to add custom handlers for these
options, or to just leave them unknown.
Data Structure
--------------

View File

@ -188,7 +188,7 @@ As you can see, a commit shows who made the latest change, what they
did, and why.
Every commit has a 40-hexdigit id, sometimes called the "object name" or the
"SHA1 id", shown on the first line of the "git-show" output. You can usually
"SHA-1 id", shown on the first line of the "git show" output. You can usually
refer to a commit by a shorter name, such as a tag or a branch name, but this
longer name can also be useful. Most importantly, it is a globally unique
name for this commit: so if you tell somebody else the object name (for
@ -307,7 +307,7 @@ ref: refs/heads/master
Examining an old version without creating a new branch
------------------------------------------------------
The git-checkout command normally expects a branch head, but will also
The `git checkout` command normally expects a branch head, but will also
accept an arbitrary commit; for example, you can check out the commit
referenced by a tag:
@ -320,7 +320,7 @@ If you want to create a new branch from this checkout, you may do so
HEAD is now at 427abfa... Linux v2.6.17
------------------------------------------------
The HEAD then refers to the SHA1 of the commit instead of to a branch,
The HEAD then refers to the SHA-1 of the commit instead of to a branch,
and git branch shows that you are no longer on a branch:
------------------------------------------------
@ -400,7 +400,7 @@ references with the same shorthand name, see the "SPECIFYING
REVISIONS" section of linkgit:git-rev-parse[1].
[[Updating-a-repository-With-git-fetch]]
Updating a repository with git-fetch
Updating a repository with git fetch
------------------------------------
Eventually the developer cloned from will do additional work in her
@ -427,7 +427,7 @@ $ git fetch linux-nfs
-------------------------------------------------
New remote-tracking branches will be stored under the shorthand name
that you gave "git-remote add", in this case linux-nfs:
that you gave "git remote add", in this case linux-nfs:
-------------------------------------------------
$ git branch -r
@ -516,7 +516,7 @@ $ git bisect reset
to return you to the branch you were on before.
Note that the version which git-bisect checks out for you at each
Note that the version which `git bisect` checks out for you at each
point is just a suggestion, and you're free to try a different
version if you think it would be a good idea. For example,
occasionally you may land on a commit that broke something unrelated;
@ -592,11 +592,11 @@ In addition to HEAD, there are several other special names for
commits:
Merges (to be discussed later), as well as operations such as
git-reset, which change the currently checked-out commit, generally
`git reset`, which change the currently checked-out commit, generally
set ORIG_HEAD to the value HEAD had before the current operation.
The git-fetch operation always stores the head of the last fetched
branch in FETCH_HEAD. For example, if you run git fetch without
The `git fetch` operation always stores the head of the last fetched
branch in FETCH_HEAD. For example, if you run `git fetch` without
specifying a local branch as the target of the operation
-------------------------------------------------
@ -739,7 +739,7 @@ $ git log --pretty=oneline origin..mybranch | wc -l
-------------------------------------------------
Alternatively, you may often see this sort of thing done with the
lower-level command linkgit:git-rev-list[1], which just lists the SHA1's
lower-level command linkgit:git-rev-list[1], which just lists the SHA-1's
of all the given commits:
-------------------------------------------------
@ -1073,9 +1073,9 @@ $ git diff
shows the difference between the working tree and the index file.
Note that "git-add" always adds just the current contents of a file
Note that "git add" always adds just the current contents of a file
to the index; further changes to the same file will be ignored unless
you run git-add on the file again.
you run `git add` on the file again.
When you're ready, just run
@ -1136,10 +1136,10 @@ Ignoring files
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
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
"`git add .`" practically useless, and they keep showing up in the output of
"`git status`".
`git add .` practically useless, and they keep showing up in the output of
`git status`.
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:
@ -1349,7 +1349,7 @@ $ git add file.txt
-------------------------------------------------
the different stages of that file will be "collapsed", after which
git-diff will (by default) no longer show diffs for that file.
`git diff` will (by default) no longer show diffs for that file.
[[undoing-a-merge]]
Undoing a merge
@ -1446,7 +1446,7 @@ Fixing a mistake by rewriting history
If the problematic commit is the most recent commit, and you have not
yet made that commit public, then you may just
<<undoing-a-merge,destroy it using git-reset>>.
<<undoing-a-merge,destroy it using `git reset`>>.
Alternatively, you
can edit the working directory and update the index to fix your
@ -1474,7 +1474,7 @@ Checking out an old version of a file
In the process of undoing a previous bad change, you may find it
useful to check out an older version of a particular file using
linkgit:git-checkout[1]. We've used git-checkout before to switch
linkgit:git-checkout[1]. We've used `git checkout` before to switch
branches, but it has quite different behavior if it is given a path
name: the command
@ -1542,7 +1542,7 @@ $ git gc
-------------------------------------------------
to recompress the archive. This can be very time-consuming, so
you may prefer to run git-gc when you are not doing other work.
you may prefer to run `git gc` when you are not doing other work.
[[ensuring-reliability]]
@ -1634,7 +1634,7 @@ In some situations the reflog may not be able to save you. For example,
suppose you delete a branch, then realize you need the history it
contained. The reflog is also deleted; however, if you have not yet
pruned the repository, then you may still be able to find the lost
commits in the dangling objects that git-fsck reports. See
commits in the dangling objects that `git fsck` reports. See
<<dangling-objects>> for the details.
-------------------------------------------------
@ -1676,7 +1676,7 @@ Sharing development with others
===============================
[[getting-updates-With-git-pull]]
Getting updates with git-pull
Getting updates with git pull
-----------------------------
After you clone a repository and make a few changes of your own, you
@ -1722,7 +1722,7 @@ repository that you pulled from.
<<fast-forwards,fast forward>>; instead, your branch will just be
updated to point to the latest commit from the upstream branch.)
The git-pull command can also be given "." as the "remote" repository,
The `git pull` command can also be given "." as the "remote" repository,
in which case it just merges in a branch from the current repository; so
the commands
@ -1795,7 +1795,7 @@ Public git repositories
Another way to submit changes to a project is to tell the maintainer
of that project to pull the changes from your repository using
linkgit:git-pull[1]. In the section "<<getting-updates-With-git-pull,
Getting updates with git-pull>>" we described this as a way to get
Getting updates with `git pull`>>" we described this as a way to get
updates from the "main" repository, but it works just as well in the
other direction.
@ -1847,7 +1847,7 @@ Setting up a public repository
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assume your personal repository is in the directory ~/proj. We
first create a new clone of the repository and tell git-daemon that it
first create a new clone of the repository and tell `git daemon` that it
is meant to be public:
-------------------------------------------------
@ -1878,10 +1878,10 @@ repository>>", below.
Otherwise, all you need to do is start linkgit:git-daemon[1]; it will
listen on port 9418. By default, it will allow access to any directory
that looks like a git directory and contains the magic file
git-daemon-export-ok. Passing some directory paths as git-daemon
git-daemon-export-ok. Passing some directory paths as `git daemon`
arguments will further restrict the exports to those paths.
You can also run git-daemon as an inetd service; see the
You can also run `git daemon` as an inetd service; see the
linkgit:git-daemon[1] man page for details. (See especially the
examples section.)
@ -1942,7 +1942,7 @@ or just
$ git push ssh://yourserver.com/~you/proj.git master
-------------------------------------------------
As with git-fetch, git-push will complain if this does not result in a
As with `git fetch`, `git push` will complain if this does not result in a
<<fast-forwards,fast forward>>; see the following section for details on
handling this case.
@ -1952,7 +1952,7 @@ repository that has a checked-out working tree, but the working tree
will not be updated by the push. This may lead to unexpected results if
the branch you push to is the currently checked-out branch!
As with git-fetch, you may also set up configuration options to
As with `git fetch`, you may also set up configuration options to
save typing; so, for example, after
-------------------------------------------------
@ -1988,13 +1988,13 @@ error: failed to push to 'ssh://yourserver.com/~you/proj.git'
This can happen, for example, if you:
- use `git-reset --hard` to remove already-published commits, or
- use `git-commit --amend` to replace already-published commits
- use `git reset --hard` to remove already-published commits, or
- use `git commit --amend` to replace already-published commits
(as in <<fixing-a-mistake-by-rewriting-history>>), or
- use `git-rebase` to rebase any already-published commits (as
- use `git rebase` to rebase any already-published commits (as
in <<using-git-rebase>>).
You may force git-push to perform the update anyway by preceding the
You may force `git push` to perform the update anyway by preceding the
branch name with a plus sign:
-------------------------------------------------
@ -2036,7 +2036,7 @@ advantages over the central shared repository:
- Git's ability to quickly import and merge patches allows a
single maintainer to process incoming changes even at very
high rates. And when that becomes too much, git-pull provides
high rates. And when that becomes too much, `git pull` provides
an easy way for that maintainer to delegate this job to other
maintainers while still allowing optional review of incoming
changes.
@ -2404,7 +2404,7 @@ use them, and then explain some of the problems that can arise because
you are rewriting history.
[[using-git-rebase]]
Keeping a patch series up to date using git-rebase
Keeping a patch series up to date using git rebase
--------------------------------------------------
Suppose that you create a branch "mywork" on a remote-tracking branch
@ -2468,9 +2468,9 @@ patches to the new mywork. The result will look like:
................................................
In the process, it may discover conflicts. In that case it will stop
and allow you to fix the conflicts; after fixing conflicts, use "git-add"
and allow you to fix the conflicts; after fixing conflicts, use `git add`
to update the index with those contents, and then, instead of
running git-commit, just run
running `git commit`, just run
-------------------------------------------------
$ git rebase --continue
@ -2508,7 +2508,7 @@ with
$ git tag bad mywork~5
-------------------------------------------------
(Either gitk or git-log may be useful for finding the commit.)
(Either gitk or `git log` may be useful for finding the commit.)
Then check out that commit, edit it, and rebase the rest of the series
on top of it (note that we could check out the commit on a temporary
@ -2549,12 +2549,12 @@ $ gitk origin..mywork &
and browse through the list of patches in the mywork branch using gitk,
applying them (possibly in a different order) to mywork-new using
cherry-pick, and possibly modifying them as you go using `commit --amend`.
cherry-pick, and possibly modifying them as you go using `git commit --amend`.
The linkgit:git-gui[1] command may also help as it allows you to
individually select diff hunks for inclusion in the index (by
right-clicking on the diff hunk and choosing "Stage Hunk for Commit").
Another technique is to use git-format-patch to create a series of
Another technique is to use `git format-patch` to create a series of
patches, then reset the state to before the patches:
-------------------------------------------------
@ -2662,7 +2662,7 @@ you know is that D is bad, that Z is good, and that
linkgit:git-bisect[1] identifies C as the culprit, how will you
figure out that the problem is due to this change in semantics?
When the result of a git-bisect is a non-merge commit, you should
When the result of a `git bisect` is a non-merge commit, you should
normally be able to discover the problem by examining just that commit.
Developers can make this easy by breaking their changes into small
self-contained commits. That won't help in the case above, however,
@ -2725,7 +2725,7 @@ master branch. In more detail:
git fetch and fast-forwards
---------------------------
In the previous example, when updating an existing branch, "git-fetch"
In the previous example, when updating an existing branch, "git fetch"
checks to make sure that the most recent commit on the remote
branch is a descendant of the most recent commit on your copy of the
branch before updating your copy of the branch to point at the new
@ -2751,7 +2751,7 @@ resulting in a situation like:
o--o--o <-- new head of the branch
................................................
In this case, "git-fetch" will fail, and print out a warning.
In this case, "git fetch" will fail, and print out a warning.
In that case, you can still force git to update to the new head, as
described in the following section. However, note that in the
@ -2760,7 +2760,7 @@ unless you've already created a reference of your own pointing to
them.
[[forcing-fetch]]
Forcing git-fetch to do non-fast-forward updates
Forcing git fetch to do non-fast-forward updates
------------------------------------------------
If git fetch fails because the new head of a branch is not a
@ -2865,8 +2865,8 @@ The Object Database
We already saw in <<understanding-commits>> that all commits are stored
under a 40-digit "object name". In fact, all the information needed to
represent the history of a project is stored in objects with such names.
In each case the name is calculated by taking the SHA1 hash of the
contents of the object. The SHA1 hash is a cryptographic hash function.
In each case the name is calculated by taking the SHA-1 hash of the
contents of the object. The SHA-1 hash is a cryptographic hash function.
What that means to us is that it is impossible to find two different
objects with the same name. This has a number of advantages; among
others:
@ -2877,10 +2877,10 @@ others:
same content stored in two repositories will always be stored under
the same name.
- Git can detect errors when it reads an object, by checking that the
object's name is still the SHA1 hash of its contents.
object's name is still the SHA-1 hash of its contents.
(See <<object-details>> for the details of the object formatting and
SHA1 calculation.)
SHA-1 calculation.)
There are four different types of objects: "blob", "tree", "commit", and
"tag".
@ -2926,9 +2926,9 @@ committer Junio C Hamano <gitster@pobox.com> 1187591163 -0700
As you can see, a commit is defined by:
- a tree: The SHA1 name of a tree object (as defined below), representing
- a tree: The SHA-1 name of a tree object (as defined below), representing
the contents of a directory at a certain point in time.
- parent(s): The SHA1 name of some number of commits which represent the
- parent(s): The SHA-1 name of some number of commits which represent the
immediately previous step(s) in the history of the project. The
example above has one parent; merge commits may have more than
one. A commit with no parents is called a "root" commit, and
@ -2977,13 +2977,13 @@ $ git ls-tree fb3a8bdd0ce
------------------------------------------------
As you can see, a tree object contains a list of entries, each with a
mode, object type, SHA1 name, and name, sorted by name. It represents
mode, object type, SHA-1 name, and name, sorted by name. It represents
the contents of a single directory tree.
The object type may be a blob, representing the contents of a file, or
another tree, representing the contents of a subdirectory. Since trees
and blobs, like all other objects, are named by the SHA1 hash of their
contents, two trees have the same SHA1 name if and only if their
and blobs, like all other objects, are named by the SHA-1 hash of their
contents, two trees have the same SHA-1 name if and only if their
contents (including, recursively, the contents of all subdirectories)
are identical. This allows git to quickly determine the differences
between two related tree objects, since it can ignore any entries with
@ -3029,15 +3029,15 @@ currently checked out.
Trust
~~~~~
If you receive the SHA1 name of a blob from one source, and its contents
If you receive the SHA-1 name of a blob from one source, and its contents
from another (possibly untrusted) source, you can still trust that those
contents are correct as long as the SHA1 name agrees. This is because
the SHA1 is designed so that it is infeasible to find different contents
contents are correct as long as the SHA-1 name agrees. This is because
the SHA-1 is designed so that it is infeasible to find different contents
that produce the same hash.
Similarly, you need only trust the SHA1 name of a top-level tree object
Similarly, you need only trust the SHA-1 name of a top-level tree object
to trust the contents of the entire directory that it refers to, and if
you receive the SHA1 name of a commit from a trusted source, then you
you receive the SHA-1 name of a commit from a trusted source, then you
can easily verify the entire history of commits reachable through
parents of that commit, and all of those contents of the trees referred
to by those commits.
@ -3049,7 +3049,7 @@ that you trust that commit, and the immutability of the history of
commits tells others that they can trust the whole history.
In other words, you can easily validate a whole archive by just
sending out a single email that tells the people the name (SHA1 hash)
sending out a single email that tells the people the name (SHA-1 hash)
of the top commit, and digitally sign that email using something
like GPG/PGP.
@ -3090,7 +3090,7 @@ How git stores objects efficiently: pack files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Newly created objects are initially created in a file named after the
object's SHA1 hash (stored in .git/objects).
object's SHA-1 hash (stored in .git/objects).
Unfortunately this system becomes inefficient once a project has a
lot of objects. Try this on an old project:
@ -3131,7 +3131,7 @@ $ git prune
to remove any of the "loose" objects that are now contained in the
pack. This will also remove any unreferenced objects (which may be
created when, for example, you use "git-reset" to remove a commit).
created when, for example, you use "git reset" to remove a commit).
You can verify that the loose objects are gone by looking at the
.git/objects directory or by running
@ -3160,7 +3160,7 @@ branch still exists, as does everything it pointed to. The branch
pointer itself just doesn't, since you replaced it with another one.
There are also other situations that cause dangling objects. For
example, a "dangling blob" may arise because you did a "git-add" of a
example, a "dangling blob" may arise because you did a "git add" of a
file, but then, before you actually committed it and made it part of the
bigger picture, you changed something else in that file and committed
that *updated* thing--the old state that you added originally ends up
@ -3210,7 +3210,7 @@ Usually, dangling blobs and trees aren't very interesting. They're
almost always the result of either being a half-way mergebase (the blob
will often even have the conflict markers from a merge in it, if you
have had conflicting merges that you fixed up by hand), or simply
because you interrupted a "git-fetch" with ^C or something like that,
because you interrupted a "git fetch" with ^C or something like that,
leaving _some_ of the new objects in the object database, but just
dangling and useless.
@ -3225,9 +3225,9 @@ and they'll be gone. But you should only run "git prune" on a quiescent
repository--it's kind of like doing a filesystem fsck recovery: you
don't want to do that while the filesystem is mounted.
(The same is true of "git-fsck" itself, btw, but since
git-fsck never actually *changes* the repository, it just reports
on what it found, git-fsck itself is never "dangerous" to run.
(The same is true of "git fsck" itself, btw, but since
`git fsck` never actually *changes* the repository, it just reports
on what it found, `git fsck` itself is never 'dangerous' to run.
Running it while somebody is actually changing the repository can cause
confusing and scary messages, but it won't actually do anything bad. In
contrast, running "git prune" while somebody is actively changing the
@ -3297,7 +3297,7 @@ $ git hash-object -w somedirectory/myfile
------------------------------------------------
which will create and store a blob object with the contents of
somedirectory/myfile, and output the sha1 of that object. if you're
somedirectory/myfile, and output the SHA-1 of that object. if you're
extremely lucky it might be 4b9458b3786228369c63936db65827de3cc06200, in
which case you've guessed right, and the corruption is fixed!
@ -3359,7 +3359,7 @@ The index
-----------
The index is a binary file (generally kept in .git/index) containing a
sorted list of path names, each with permissions and the SHA1 of a blob
sorted list of path names, each with permissions and the SHA-1 of a blob
object; linkgit:git-ls-files[1] can show you the contents of the index:
-------------------------------------------------
@ -3489,14 +3489,14 @@ done
NOTE: Do not use local URLs here if you plan to publish your superproject!
See what files `git-submodule` created:
See what files `git submodule` created:
-------------------------------------------------
$ ls -a
. .. .git .gitmodules a b c d
-------------------------------------------------
The `git-submodule add <repo> <path>` command does a couple of things:
The `git submodule add <repo> <path>` command does a couple of things:
- It clones the submodule from <repo> to the given <path> under the
current directory and by default checks out the master branch.
@ -3542,7 +3542,7 @@ init` to add the submodule repository URLs to `.git/config`:
$ git submodule init
-------------------------------------------------
Now use `git-submodule update` to clone the repositories and check out the
Now use `git submodule update` to clone the repositories and check out the
commits specified in the superproject:
-------------------------------------------------
@ -3552,8 +3552,8 @@ $ ls -a
. .. .git a.txt
-------------------------------------------------
One major difference between `git-submodule update` and `git-submodule add` is
that `git-submodule update` checks out a specific commit, rather than the tip
One major difference between `git submodule update` and `git submodule add` is
that `git submodule update` checks out a specific commit, rather than the tip
of a branch. It's like checking out a tag: the head is detached, so you're not
working on a branch.
@ -3754,7 +3754,7 @@ unsaved state that you might want to restore later!) your current
index. Normal operation is just
-------------------------------------------------
$ git read-tree <sha1 of tree>
$ git read-tree <SHA-1 of tree>
-------------------------------------------------
and your index file will now be equivalent to the tree that you saved
@ -3769,7 +3769,7 @@ You update your working directory from the index by "checking out"
files. This is not a very common operation, since normally you'd just
keep your files updated, and rather than write to your working
directory, you'd tell the index files about the changes in your
working directory (i.e. `git-update-index`).
working directory (i.e. `git update-index`).
However, if you decide to jump to a new version, or check out somebody
else's version, or just restore a previous tree, you'd populate your
@ -3782,7 +3782,7 @@ $ git checkout-index filename
or, if you want to check out all of the index, use `-a`.
NOTE! git-checkout-index normally refuses to overwrite old files, so
NOTE! `git checkout-index` normally refuses to overwrite old files, so
if you have an old version of the tree already checked out, you will
need to use the "-f" flag ('before' the "-a" flag or the filename) to
'force' the checkout.
@ -3820,7 +3820,7 @@ $ git commit-tree <tree> -p <parent> [-p <parent2> ..]
and then giving the reason for the commit on stdin (either through
redirection from a pipe or file, or by just typing it at the tty).
git-commit-tree will return the name of the object that represents
`git commit-tree` will return the name of the object that represents
that commit, and you should save it away for later use. Normally,
you'd commit a new `HEAD` state, and while git doesn't care where you
save the note about that state, in practice we tend to just write the
@ -3889,7 +3889,7 @@ $ git cat-file blob|tree|commit|tag <objectname>
to show its contents. NOTE! Trees have binary content, and as a result
there is a special helper for showing that content, called
`git-ls-tree`, which turns the binary content into a more easily
`git ls-tree`, which turns the binary content into a more easily
readable form.
It's especially instructive to look at "commit" objects, since those
@ -3978,13 +3978,13 @@ $ git ls-files --unmerged
------------------------------------------------
Each line of the `git ls-files --unmerged` output begins with
the blob mode bits, blob SHA1, 'stage number', and the
the blob mode bits, blob SHA-1, 'stage number', and the
filename. The 'stage number' is git's way to say which tree it
came from: stage 1 corresponds to `$orig` tree, stage 2 `HEAD`
tree, and stage3 `$target` tree.
Earlier we said that trivial merges are done inside
`git-read-tree -m`. For example, if the file did not change
`git read-tree -m`. For example, if the file did not change
from `$orig` to `HEAD` nor `$target`, or if the file changed
from `$orig` to `HEAD` and `$orig` to `$target` the same way,
obviously the final outcome is what is in `HEAD`. What the
@ -4011,20 +4011,20 @@ $ mv -f hello.c~2 hello.c
$ git update-index hello.c
-------------------------------------------------
When a path is in the "unmerged" state, running `git-update-index` for
When a path is in the "unmerged" state, running `git update-index` for
that path tells git to mark the path resolved.
The above is the description of a git merge at the lowest level,
to help you understand what conceptually happens under the hood.
In practice, nobody, not even git itself, runs `git-cat-file` three times
for this. There is a `git-merge-index` program that extracts the
In practice, nobody, not even git itself, runs `git cat-file` three times
for this. There is a `git merge-index` program that extracts the
stages to temporary files and calls a "merge" script on it:
-------------------------------------------------
$ git merge-index git-merge-one-file hello.c
-------------------------------------------------
and that is what higher level `git-merge -s resolve` is implemented with.
and that is what higher level `git merge -s resolve` is implemented with.
[[hacking-git]]
Hacking git
@ -4045,12 +4045,12 @@ objects). There are currently four different object types: "blob",
Regardless of object type, all objects share the following
characteristics: they are all deflated with zlib, and have a header
that not only specifies their type, but also provides size information
about the data in the object. It's worth noting that the SHA1 hash
about the data in the object. It's worth noting that the SHA-1 hash
that is used to name the object is the hash of the original data
plus this header, so `sha1sum` 'file' does not match the object name
for 'file'.
(Historical note: in the dawn of the age of git the hash
was the sha1 of the 'compressed' object.)
was the SHA-1 of the 'compressed' object.)
As a result, the general consistency of an object can always be tested
independently of the contents or the type of the object: all objects can
@ -4061,7 +4061,7 @@ size> {plus} <byte\0> {plus} <binary object data>.
The structured objects can further have their structure and
connectivity to other objects verified. This is generally done with
the `git-fsck` program, which generates a full dependency graph
the `git fsck` program, which generates a full dependency graph
of all objects, and verifies their internal consistency (in addition
to just verifying their superficial consistency through the hash).
@ -4120,7 +4120,7 @@ functions like `get_sha1_basic()` or the likes.
This is just to get you into the groove for the most libified part of Git:
the revision walker.
Basically, the initial version of `git-log` was a shell script:
Basically, the initial version of `git log` was a shell script:
----------------------------------------------------------------
$ git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | \
@ -4129,20 +4129,20 @@ $ git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | \
What does this mean?
`git-rev-list` is the original version of the revision walker, which
`git rev-list` is the original version of the revision walker, which
_always_ printed a list of revisions to stdout. It is still functional,
and needs to, since most new Git programs start out as scripts using
`git-rev-list`.
`git rev-list`.
`git-rev-parse` is not as important any more; it was only used to filter out
`git rev-parse` is not as important any more; it was only used to filter out
options that were relevant for the different plumbing commands that were
called by the script.
Most of what `git-rev-list` did is contained in `revision.c` and
Most of what `git rev-list` did is contained in `revision.c` and
`revision.h`. It wraps the options in a struct named `rev_info`, which
controls how and what revisions are walked, and more.
The original job of `git-rev-parse` is now taken by the function
The original job of `git rev-parse` is now taken by the function
`setup_revisions()`, which parses the revisions and the common command line
options for the revision walker. This information is stored in the struct
`rev_info` for later consumption. You can do your own command line option
@ -4155,7 +4155,7 @@ just have a look at the first implementation of `cmd_log()`; call
`git show v1.3.0{tilde}155^2{tilde}4` and scroll down to that function (note that you
no longer need to call `setup_pager()` directly).
Nowadays, `git-log` is a builtin, which means that it is _contained_ in the
Nowadays, `git log` is a builtin, which means that it is _contained_ in the
command `git`. The source side of a builtin is
- a function called `cmd_<bla>`, typically defined in `builtin-<bla>.c`,
@ -4171,7 +4171,7 @@ since they share quite a bit of code. In that case, the commands which are
_not_ named like the `.c` file in which they live have to be listed in
`BUILT_INS` in the `Makefile`.
`git-log` looks more complicated in C than it does in the original script,
`git log` looks more complicated in C than it does in the original script,
but that allows for a much greater flexibility and performance.
Here again it is a good point to take a pause.
@ -4182,9 +4182,9 @@ the organization of Git (after you know the basic concepts).
So, think about something which you are interested in, say, "how can I
access a blob just knowing the object name of it?". The first step is to
find a Git command with which you can do it. In this example, it is either
`git-show` or `git-cat-file`.
`git show` or `git cat-file`.
For the sake of clarity, let's stay with `git-cat-file`, because it
For the sake of clarity, let's stay with `git cat-file`, because it
- is plumbing, and
@ -4198,7 +4198,7 @@ it does.
------------------------------------------------------------------
git_config(git_default_config);
if (argc != 3)
usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>");
usage("git cat-file [-t|-s|-e|-p|<type>] <sha1>");
if (get_sha1(argv[2], sha1))
die("Not a valid object name %s", argv[2]);
------------------------------------------------------------------
@ -4243,10 +4243,10 @@ To find out how the result can be used, just read on in `cmd_cat_file()`:
-----------------------------------
Sometimes, you do not know where to look for a feature. In many such cases,
it helps to search through the output of `git log`, and then `git-show` the
it helps to search through the output of `git log`, and then `git show` the
corresponding commit.
Example: If you know that there was some test case for `git-bundle`, but
Example: If you know that there was some test case for `git bundle`, but
do not remember where it was (yes, you _could_ `git grep bundle t/`, but that
does not illustrate the point!):
@ -4530,7 +4530,7 @@ The basic requirements:
- Whenever possible, section headings should clearly describe the task
they explain how to do, in language that requires no more knowledge
than necessary: for example, "importing patches into a project" rather
than "the git-am command"
than "the `git am` command"
Think about how to create a clear chapter dependency graph that will
allow people to get to important topics without necessarily reading

View File

@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v1.6.2.1
DEF_VER=v1.6.2.GIT
LF='
'

View File

@ -126,6 +126,12 @@ all::
# randomly break unless your underlying filesystem supports those sub-second
# 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
# change being considered an inode change from the update-index perspective.
#
@ -139,6 +145,8 @@ all::
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
# MakeMaker (e.g. using ActiveState under Cygwin).
#
# Define NO_PERL if you do not want Perl scripts or libraries at all.
#
# Define NO_TCLTK if you do not want Tcl/Tk GUI.
#
# The TCL_PATH variable governs the location of the Tcl interpreter
@ -257,6 +265,18 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
BASIC_CFLAGS =
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-bisect.sh
SCRIPT_SH += git-filter-branch.sh
@ -335,7 +355,10 @@ BUILT_INS += git-whatchanged$X
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X gitweb/gitweb.cgi
OTHER_PROGRAMS = git$X
ifndef NO_PERL
OTHER_PROGRAMS += gitweb/gitweb.cgi
endif
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
@ -414,6 +437,7 @@ LIB_OBJS += archive-tar.o
LIB_OBJS += archive-zip.o
LIB_OBJS += attr.o
LIB_OBJS += base85.o
LIB_OBJS += bisect.o
LIB_OBJS += blob.o
LIB_OBJS += branch.o
LIB_OBJS += bundle.o
@ -514,6 +538,7 @@ BUILTIN_OBJS += builtin-add.o
BUILTIN_OBJS += builtin-annotate.o
BUILTIN_OBJS += builtin-apply.o
BUILTIN_OBJS += builtin-archive.o
BUILTIN_OBJS += builtin-bisect--helper.o
BUILTIN_OBJS += builtin-blame.o
BUILTIN_OBJS += builtin-branch.o
BUILTIN_OBJS += builtin-bundle.o
@ -657,6 +682,7 @@ ifeq ($(uname_S),Darwin)
endif
NO_MEMMEM = YesPlease
THREADED_DELTA_SEARCH = YesPlease
USE_ST_TIMESPEC = YesPlease
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@ -706,6 +732,7 @@ ifeq ($(uname_S),FreeBSD)
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
USE_ST_TIMESPEC = YesPlease
THREADED_DELTA_SEARCH = YesPlease
ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
PTHREAD_LIBS = -pthread
@ -734,6 +761,7 @@ ifeq ($(uname_S),AIX)
NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease
NO_STRLCPY = YesPlease
NO_NSEC = YesPlease
FREAD_READS_DIRECTORIES = UnfortunatelyYes
INTERNAL_QSORT = UnfortunatelyYes
NEEDS_LIBICONV=YesPlease
@ -776,7 +804,6 @@ ifneq (,$(findstring CYGWIN,$(uname_S)))
COMPAT_OBJS += compat/cygwin.o
endif
ifneq (,$(findstring MINGW,$(uname_S)))
NO_MMAP = YesPlease
NO_PREAD = YesPlease
NO_OPENSSL = YesPlease
NO_CURL = YesPlease
@ -799,6 +826,8 @@ ifneq (,$(findstring MINGW,$(uname_S)))
RUNTIME_PREFIX = YesPlease
NO_POSIX_ONLY_PROGRAMS = YesPlease
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
NO_NSEC = YesPlease
USE_WIN32_MMAP = YesPlease
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@ -920,6 +949,15 @@ endif
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
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
BASIC_CFLAGS += -DNO_C99_FORMAT
endif
@ -967,6 +1005,11 @@ endif
ifdef NO_MMAP
COMPAT_CFLAGS += -DNO_MMAP
COMPAT_OBJS += compat/mmap.o
else
ifdef USE_WIN32_MMAP
COMPAT_CFLAGS += -DUSE_WIN32_MMAP
COMPAT_OBJS += compat/win32mmap.o
endif
endif
ifdef NO_PREAD
COMPAT_CFLAGS += -DNO_PREAD
@ -1068,6 +1111,10 @@ ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
endif
ifeq ($(PERL_PATH),)
NO_PERL=NoThanks
endif
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
@ -1142,7 +1189,9 @@ ifndef NO_TCLTK
$(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all
$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
endif
ifndef NO_PERL
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
endif
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
please_set_SHELL_PATH_to_a_more_modern_shell:
@ -1155,6 +1204,7 @@ strip: $(PROGRAMS) git$X
git.o: git.c common-cmds.h GIT-CFLAGS
$(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
$(ALL_CFLAGS) -c $(filter %.c,$^)
git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
@ -1189,6 +1239,7 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
chmod +x $@+ && \
mv $@+ $@
ifndef NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
@ -1248,6 +1299,15 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
$@.sh > $@+ && \
chmod +x $@+ && \
mv $@+ $@
else # NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@@REASON@@|NO_PERL=$(NO_PERL)|g' \
unimplemented.sh >$@+ && \
chmod +x $@+ && \
mv $@+ $@
endif # NO_PERL
configure: configure.ac
$(QUIET_GEN)$(RM) $@ $<+ && \
@ -1363,6 +1423,8 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
@echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
### Detect Tck/Tk interpreter path changes
ifndef NO_TCLTK
@ -1565,9 +1627,11 @@ clean:
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
$(RM) gitweb/gitweb.cgi
$(MAKE) -C Documentation/ clean
ifndef NO_PERL
$(RM) gitweb/gitweb.cgi
$(MAKE) -C perl clean
endif
$(MAKE) -C templates/ clean
$(MAKE) -C t/ clean
ifndef NO_TCLTK
@ -1640,3 +1704,27 @@ check-docs::
check-builtins::
./check-builtins.sh
### Test suite coverage testing
#
.PHONY: coverage coverage-clean coverage-build coverage-report
coverage:
$(MAKE) coverage-build
$(MAKE) coverage-report
coverage-clean:
rm -f *.gcda *.gcno
COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov
coverage-build: coverage-clean
$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
-j1 test
coverage-report:
gcov -b *.c
grep '^function.*called 0 ' *.c.gcov \
| sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
| tee coverage-untested-functions

View File

@ -1 +1 @@
Documentation/RelNotes-1.6.2.2.txt
Documentation/RelNotes-1.6.3.txt

View File

@ -253,6 +253,7 @@ static int parse_archive_args(int argc, const char **argv,
const char *base = NULL;
const char *remote = NULL;
const char *exec = NULL;
const char *output = NULL;
int compression_level = -1;
int verbose = 0;
int i;
@ -262,6 +263,8 @@ static int parse_archive_args(int argc, const char **argv,
OPT_STRING(0, "format", &format, "fmt", "archive format"),
OPT_STRING(0, "prefix", &base, "prefix",
"prepend prefix to each pathname in the archive"),
OPT_STRING(0, "output", &output, "file",
"write the archive to this file"),
OPT__VERBOSE(&verbose),
OPT__COMPR('0', &compression_level, "store only", 0),
OPT__COMPR('1', &compression_level, "compress faster", 1),
@ -290,6 +293,8 @@ static int parse_archive_args(int argc, const char **argv,
die("Unexpected option --remote");
if (exec)
die("Option --exec can only be used together with --remote");
if (output)
die("Unexpected option --output");
if (!base)
base = "";

73
attr.c
View File

@ -1,3 +1,4 @@
#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "attr.h"
@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list)
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)
{
FILE *fp = fopen(path, "r");
@ -340,9 +344,10 @@ static void *read_index_data(const char *path)
unsigned long sz;
enum object_type type;
void *data;
struct index_state *istate = use_index ? use_index : &the_index;
len = strlen(path);
pos = cache_name_pos(path, len);
pos = index_name_pos(istate, path, len);
if (pos < 0) {
/*
* 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;
for (i = -pos - 1;
(pos < 0 && i < active_nr &&
!strcmp(active_cache[i]->name, path));
(pos < 0 && i < istate->cache_nr &&
!strcmp(istate->cache[i]->name, path));
i++)
if (ce_stage(active_cache[i]) == 2)
if (ce_stage(istate->cache[i]) == 2)
pos = i;
}
if (pos < 0)
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) {
free(data);
return NULL;
@ -366,27 +371,17 @@ static void *read_index_data(const char *path)
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;
char *buf, *sp;
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);
if (!buf)
return res;
return NULL;
res = xcalloc(1, sizeof(*res));
for (sp = buf; *sp; ) {
char *ep;
int more;
@ -401,6 +396,30 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
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
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)
#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)
{
if (!attr_stack) {
@ -642,3 +670,12 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
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 *);
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 */

556
bisect.c Normal file
View File

@ -0,0 +1,556 @@
#include "cache.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
#include "refs.h"
#include "list-objects.h"
#include "quote.h"
#include "sha1-lookup.h"
#include "bisect.h"
static unsigned char (*skipped_sha1)[20];
static int skipped_sha1_nr;
static int skipped_sha1_alloc;
static const char **rev_argv;
static int rev_argv_nr;
static int rev_argv_alloc;
/* bits #0-15 in revision.h */
#define COUNTED (1u<<16)
/*
* This is a truly stupid algorithm, but it's only
* used for bisection, and we just don't care enough.
*
* We care just barely enough to avoid recursing for
* non-merge entries.
*/
static int count_distance(struct commit_list *entry)
{
int nr = 0;
while (entry) {
struct commit *commit = entry->item;
struct commit_list *p;
if (commit->object.flags & (UNINTERESTING | COUNTED))
break;
if (!(commit->object.flags & TREESAME))
nr++;
commit->object.flags |= COUNTED;
p = commit->parents;
entry = p;
if (p) {
p = p->next;
while (p) {
nr += count_distance(p);
p = p->next;
}
}
}
return nr;
}
static void clear_distance(struct commit_list *list)
{
while (list) {
struct commit *commit = list->item;
commit->object.flags &= ~COUNTED;
list = list->next;
}
}
#define DEBUG_BISECT 0
static inline int weight(struct commit_list *elem)
{
return *((int*)(elem->item->util));
}
static inline void weight_set(struct commit_list *elem, int weight)
{
*((int*)(elem->item->util)) = weight;
}
static int count_interesting_parents(struct commit *commit)
{
struct commit_list *p;
int count;
for (count = 0, p = commit->parents; p; p = p->next) {
if (p->item->object.flags & UNINTERESTING)
continue;
count++;
}
return count;
}
static inline int halfway(struct commit_list *p, int nr)
{
/*
* Don't short-cut something we are not going to return!
*/
if (p->item->object.flags & TREESAME)
return 0;
if (DEBUG_BISECT)
return 0;
/*
* 2 and 3 are halfway of 5.
* 3 is halfway of 6 but 2 and 4 are not.
*/
switch (2 * weight(p) - nr) {
case -1: case 0: case 1:
return 1;
default:
return 0;
}
}
#if !DEBUG_BISECT
#define show_list(a,b,c,d) do { ; } while (0)
#else
static void show_list(const char *debug, int counted, int nr,
struct commit_list *list)
{
struct commit_list *p;
fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr);
for (p = list; p; p = p->next) {
struct commit_list *pp;
struct commit *commit = p->item;
unsigned flags = commit->object.flags;
enum object_type type;
unsigned long size;
char *buf = read_sha1_file(commit->object.sha1, &type, &size);
char *ep, *sp;
fprintf(stderr, "%c%c%c ",
(flags & TREESAME) ? ' ' : 'T',
(flags & UNINTERESTING) ? 'U' : ' ',
(flags & COUNTED) ? 'C' : ' ');
if (commit->util)
fprintf(stderr, "%3d", weight(p));
else
fprintf(stderr, "---");
fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1));
for (pp = commit->parents; pp; pp = pp->next)
fprintf(stderr, " %.*s", 8,
sha1_to_hex(pp->item->object.sha1));
sp = strstr(buf, "\n\n");
if (sp) {
sp += 2;
for (ep = sp; *ep && *ep != '\n'; ep++)
;
fprintf(stderr, " %.*s", (int)(ep - sp), sp);
}
fprintf(stderr, "\n");
}
}
#endif /* DEBUG_BISECT */
static struct commit_list *best_bisection(struct commit_list *list, int nr)
{
struct commit_list *p, *best;
int best_distance = -1;
best = list;
for (p = list; p; p = p->next) {
int distance;
unsigned flags = p->item->object.flags;
if (flags & TREESAME)
continue;
distance = weight(p);
if (nr - distance < distance)
distance = nr - distance;
if (distance > best_distance) {
best = p;
best_distance = distance;
}
}
return best;
}
struct commit_dist {
struct commit *commit;
int distance;
};
static int compare_commit_dist(const void *a_, const void *b_)
{
struct commit_dist *a, *b;
a = (struct commit_dist *)a_;
b = (struct commit_dist *)b_;
if (a->distance != b->distance)
return b->distance - a->distance; /* desc sort */
return hashcmp(a->commit->object.sha1, b->commit->object.sha1);
}
static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr)
{
struct commit_list *p;
struct commit_dist *array = xcalloc(nr, sizeof(*array));
int cnt, i;
for (p = list, cnt = 0; p; p = p->next) {
int distance;
unsigned flags = p->item->object.flags;
if (flags & TREESAME)
continue;
distance = weight(p);
if (nr - distance < distance)
distance = nr - distance;
array[cnt].commit = p->item;
array[cnt].distance = distance;
cnt++;
}
qsort(array, cnt, sizeof(*array), compare_commit_dist);
for (p = list, i = 0; i < cnt; i++) {
struct name_decoration *r = xmalloc(sizeof(*r) + 100);
struct object *obj = &(array[i].commit->object);
sprintf(r->name, "dist=%d", array[i].distance);
r->next = add_decoration(&name_decoration, obj, r);
p->item = array[i].commit;
p = p->next;
}
if (p)
p->next = NULL;
free(array);
return list;
}
/*
* zero or positive weight is the number of interesting commits it can
* reach, including itself. Especially, weight = 0 means it does not
* reach any tree-changing commits (e.g. just above uninteresting one
* but traversal is with pathspec).
*
* weight = -1 means it has one parent and its distance is yet to
* be computed.
*
* weight = -2 means it has more than one parent and its distance is
* unknown. After running count_distance() first, they will get zero
* or positive distance.
*/
static struct commit_list *do_find_bisection(struct commit_list *list,
int nr, int *weights,
int find_all)
{
int n, counted;
struct commit_list *p;
counted = 0;
for (n = 0, p = list; p; p = p->next) {
struct commit *commit = p->item;
unsigned flags = commit->object.flags;
p->item->util = &weights[n++];
switch (count_interesting_parents(commit)) {
case 0:
if (!(flags & TREESAME)) {
weight_set(p, 1);
counted++;
show_list("bisection 2 count one",
counted, nr, list);
}
/*
* otherwise, it is known not to reach any
* tree-changing commit and gets weight 0.
*/
break;
case 1:
weight_set(p, -1);
break;
default:
weight_set(p, -2);
break;
}
}
show_list("bisection 2 initialize", counted, nr, list);
/*
* If you have only one parent in the resulting set
* then you can reach one commit more than that parent
* can reach. So we do not have to run the expensive
* count_distance() for single strand of pearls.
*
* However, if you have more than one parents, you cannot
* just add their distance and one for yourself, since
* they usually reach the same ancestor and you would
* end up counting them twice that way.
*
* So we will first count distance of merges the usual
* way, and then fill the blanks using cheaper algorithm.
*/
for (p = list; p; p = p->next) {
if (p->item->object.flags & UNINTERESTING)
continue;
if (weight(p) != -2)
continue;
weight_set(p, count_distance(p));
clear_distance(list);
/* Does it happen to be at exactly half-way? */
if (!find_all && halfway(p, nr))
return p;
counted++;
}
show_list("bisection 2 count_distance", counted, nr, list);
while (counted < nr) {
for (p = list; p; p = p->next) {
struct commit_list *q;
unsigned flags = p->item->object.flags;
if (0 <= weight(p))
continue;
for (q = p->item->parents; q; q = q->next) {
if (q->item->object.flags & UNINTERESTING)
continue;
if (0 <= weight(q))
break;
}
if (!q)
continue;
/*
* weight for p is unknown but q is known.
* add one for p itself if p is to be counted,
* otherwise inherit it from q directly.
*/
if (!(flags & TREESAME)) {
weight_set(p, weight(q)+1);
counted++;
show_list("bisection 2 count one",
counted, nr, list);
}
else
weight_set(p, weight(q));
/* Does it happen to be at exactly half-way? */
if (!find_all && halfway(p, nr))
return p;
}
}
show_list("bisection 2 counted all", counted, nr, list);
if (!find_all)
return best_bisection(list, nr);
else
return best_bisection_sorted(list, nr);
}
struct commit_list *find_bisection(struct commit_list *list,
int *reaches, int *all,
int find_all)
{
int nr, on_list;
struct commit_list *p, *best, *next, *last;
int *weights;
show_list("bisection 2 entry", 0, 0, list);
/*
* Count the number of total and tree-changing items on the
* list, while reversing the list.
*/
for (nr = on_list = 0, last = NULL, p = list;
p;
p = next) {
unsigned flags = p->item->object.flags;
next = p->next;
if (flags & UNINTERESTING)
continue;
p->next = last;
last = p;
if (!(flags & TREESAME))
nr++;
on_list++;
}
list = last;
show_list("bisection 2 sorted", 0, nr, list);
*all = nr;
weights = xcalloc(on_list, sizeof(*weights));
/* Do the real work of finding bisection commit. */
best = do_find_bisection(list, nr, weights, find_all);
if (best) {
if (!find_all)
best->next = NULL;
*reaches = weight(best);
}
free(weights);
return best;
}
static int register_ref(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
if (!strcmp(refname, "bad")) {
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = xstrdup(sha1_to_hex(sha1));
} else if (!prefixcmp(refname, "good-")) {
const char *hex = sha1_to_hex(sha1);
char *good = xmalloc(strlen(hex) + 2);
*good = '^';
memcpy(good + 1, hex, strlen(hex) + 1);
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = good;
} else if (!prefixcmp(refname, "skip-")) {
ALLOC_GROW(skipped_sha1, skipped_sha1_nr + 1,
skipped_sha1_alloc);
hashcpy(skipped_sha1[skipped_sha1_nr++], sha1);
}
return 0;
}
static int read_bisect_refs(void)
{
return for_each_ref_in("refs/bisect/", register_ref, NULL);
}
void read_bisect_paths(void)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path("BISECT_NAMES");
FILE *fp = fopen(filename, "r");
if (!fp)
die("Could not open file '%s': %s", filename, strerror(errno));
while (strbuf_getline(&str, fp, '\n') != EOF) {
char *quoted;
int res;
strbuf_trim(&str);
quoted = strbuf_detach(&str, NULL);
res = sq_dequote_to_argv(quoted, &rev_argv,
&rev_argv_nr, &rev_argv_alloc);
if (res)
die("Badly quoted content in file '%s': %s",
filename, quoted);
}
strbuf_release(&str);
fclose(fp);
}
static int skipcmp(const void *a, const void *b)
{
return hashcmp(a, b);
}
static void prepare_skipped(void)
{
qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp);
}
static const unsigned char *skipped_sha1_access(size_t index, void *table)
{
unsigned char (*skipped)[20] = table;
return skipped[index];
}
static int lookup_skipped(unsigned char *sha1)
{
return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr,
skipped_sha1_access);
}
struct commit_list *filter_skipped(struct commit_list *list,
struct commit_list **tried,
int show_all)
{
struct commit_list *filtered = NULL, **f = &filtered;
*tried = NULL;
if (!skipped_sha1_nr)
return list;
prepare_skipped();
while (list) {
struct commit_list *next = list->next;
list->next = NULL;
if (0 <= lookup_skipped(list->item->object.sha1)) {
/* Move current to tried list */
*tried = list;
tried = &list->next;
} else {
if (!show_all)
return list;
/* Move current to filtered list */
*f = list;
f = &list->next;
}
list = next;
}
return filtered;
}
static void bisect_rev_setup(struct rev_info *revs, const char *prefix)
{
init_revisions(revs, prefix);
revs->abbrev = 0;
revs->commit_format = CMIT_FMT_UNSPECIFIED;
/* argv[0] will be ignored by setup_revisions */
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = xstrdup("bisect_rev_setup");
if (read_bisect_refs())
die("reading bisect refs failed");
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = xstrdup("--");
read_bisect_paths();
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = NULL;
setup_revisions(rev_argv_nr, rev_argv, revs, NULL);
revs->limited = 1;
}
int bisect_next_vars(const char *prefix)
{
struct rev_info revs;
struct rev_list_info info;
int reaches = 0, all = 0;
memset(&info, 0, sizeof(info));
info.revs = &revs;
info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED;
bisect_rev_setup(&revs, prefix);
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
if (revs.tree_objects)
mark_edges_uninteresting(revs.commits, &revs, NULL);
revs.commits = find_bisection(revs.commits, &reaches, &all,
!!skipped_sha1_nr);
return show_bisect_vars(&info, reaches, all);
}

29
bisect.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef BISECT_H
#define BISECT_H
extern struct commit_list *find_bisection(struct commit_list *list,
int *reaches, int *all,
int find_all);
extern struct commit_list *filter_skipped(struct commit_list *list,
struct commit_list **tried,
int show_all);
/* bisect_show_flags flags in struct rev_list_info */
#define BISECT_SHOW_ALL (1<<0)
#define BISECT_SHOW_TRIED (1<<1)
#define BISECT_SHOW_STRINGED (1<<2)
struct rev_list_info {
struct rev_info *revs;
int bisect_show_flags;
int show_timestamp;
int hdr_termination;
const char *header_prefix;
};
extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all);
extern int bisect_next_vars(const char *prefix);
#endif

View File

@ -32,21 +32,59 @@ static int find_tracked_branch(struct remote *remote, void *priv)
return 0;
}
static int should_setup_rebase(const struct tracking *tracking)
static int should_setup_rebase(const char *origin)
{
switch (autorebase) {
case AUTOREBASE_NEVER:
return 0;
case AUTOREBASE_LOCAL:
return tracking->remote == NULL;
return origin == NULL;
case AUTOREBASE_REMOTE:
return tracking->remote != NULL;
return origin != NULL;
case AUTOREBASE_ALWAYS:
return 1;
}
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
* 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,
enum branch_track track)
{
char key[1024];
struct tracking tracking;
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",
orig_ref);
sprintf(key, "branch.%s.remote", new_ref);
git_config_set(key, tracking.remote ? tracking.remote : ".");
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);
install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote,
tracking.src ? tracking.src : orig_ref);
free(tracking.src);
return 0;
}
@ -106,16 +134,8 @@ void create_branch(const char *head,
char *real_ref, msg[PATH_MAX + 20];
struct strbuf ref = STRBUF_INIT;
int forcing = 0;
int len;
len = strlen(name);
if (interpret_nth_last_branch(name, &ref) != len) {
strbuf_reset(&ref);
strbuf_add(&ref, name, len);
}
strbuf_splice(&ref, 0, 0, "refs/heads/", 11);
if (check_ref_format(ref.buf))
if (strbuf_check_branch_ref(&ref, name))
die("'%s' is not a valid branch name.", name);
if (resolve_ref(ref.buf, sha1, 1, NULL)) {

View File

@ -21,4 +21,11 @@ void create_branch(const char *head, const char *name, const char *start_name,
*/
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

View File

@ -104,7 +104,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
/* Set up the default git porcelain excludes */
memset(dir, 0, sizeof(*dir));
if (!ignored_too) {
dir->collect_ignored = 1;
dir->flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(dir);
}
@ -148,7 +148,7 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p
if (pathspec) {
const char **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;
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
* 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 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)
return error("%s: wrong type", old_name);
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);
if (!patch->new_mode && !patch->is_delete)
patch->new_mode = st_mode;
@ -2932,8 +2932,7 @@ static int write_out_one_reject(struct patch *patch)
cnt = strlen(patch->new_name);
if (ARRAY_SIZE(namebuf) <= cnt + 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);
}
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[] = {
{ 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 },
{ OPTION_CALLBACK, 0, "include", NULL, "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"),
OPT_BOOLEAN(0, "stat", &diffstat,
"instead of applying the patch, output diffstat for the input"),
OPT_BOOLEAN(0, "allow-binary-replacement", &binary,
"now no-op"),
OPT_BOOLEAN(0, "binary", &binary,
"now no-op"),
{ OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
{ OPTION_BOOLEAN, 0, "binary", &binary,
NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
OPT_BOOLEAN(0, "numstat", &numstat,
"shows number of added and deleted lines in decimal notation"),
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) {
int squelched =
whitespace_error - squelch_whitespace_errors;
fprintf(stderr, "warning: squelched %d "
"whitespace error%s\n",
warning("squelched %d "
"whitespace error%s",
squelched,
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" : "");
if (applied_after_fixing_ws && apply)
fprintf(stderr, "warning: %d line%s applied after"
" fixing whitespace errors.\n",
warning("%d line%s applied after"
" fixing whitespace errors.",
applied_after_fixing_ws,
applied_after_fixing_ws == 1 ? "" : "s");
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 == 1 ? "" : "s",
whitespace_error == 1 ? "s" : "");

View File

@ -5,44 +5,35 @@
#include "cache.h"
#include "builtin.h"
#include "archive.h"
#include "parse-options.h"
#include "pkt-line.h"
#include "sideband.h"
static int run_remote_archiver(const char *remote, int argc,
const char **argv)
static void create_output_file(const char *output_file)
{
int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
if (output_fd < 0)
die("could not create archive file: %s ", output_file);
if (output_fd != 1) {
if (dup2(output_fd, 1) < 0)
die("could not redirect output");
else
close(output_fd);
}
}
static int run_remote_archiver(int argc, const char **argv,
const char *remote, const char *exec)
{
char *url, buf[LARGE_PACKET_MAX];
int fd[2], i, len, rv;
struct child_process *conn;
const char *exec = "git-upload-archive";
int exec_at = 0, exec_value_at = 0;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!prefixcmp(arg, "--exec=")) {
if (exec_at)
die("multiple --exec specified");
exec = arg + 7;
exec_at = i;
} else if (!strcmp(arg, "--exec")) {
if (exec_at)
die("multiple --exec specified");
if (i + 1 >= argc)
die("option --exec requires a value");
exec = argv[i + 1];
exec_at = i;
exec_value_at = ++i;
}
}
url = xstrdup(remote);
conn = git_connect(fd, url, exec, 0);
for (i = 1; i < argc; i++) {
if (i == exec_at || i == exec_value_at)
continue;
for (i = 1; i < argc; i++)
packet_write(fd[1], "argument %s\n", argv[i]);
}
packet_flush(fd[1]);
len = packet_read_line(fd[0], buf, sizeof(buf));
@ -61,7 +52,7 @@ static int run_remote_archiver(const char *remote, int argc,
die("git archive: expected a flush");
/* Now, start reading from fd[0] and spit it out to stdout */
rv = recv_sideband("archive", fd[0], 1, 2);
rv = recv_sideband("archive", fd[0], 1);
close(fd[0]);
close(fd[1]);
rv |= finish_connect(conn);
@ -69,51 +60,33 @@ static int run_remote_archiver(const char *remote, int argc,
return !!rv;
}
static const char *extract_remote_arg(int *ac, const char **av)
{
int ix, iy, cnt = *ac;
int no_more_options = 0;
const char *remote = NULL;
for (ix = iy = 1; ix < cnt; ix++) {
const char *arg = av[ix];
if (!strcmp(arg, "--"))
no_more_options = 1;
if (!no_more_options) {
if (!prefixcmp(arg, "--remote=")) {
if (remote)
die("Multiple --remote specified");
remote = arg + 9;
continue;
} else if (!strcmp(arg, "--remote")) {
if (remote)
die("Multiple --remote specified");
if (++ix >= cnt)
die("option --remote requires a value");
remote = av[ix];
continue;
}
if (arg[0] != '-')
no_more_options = 1;
}
if (ix != iy)
av[iy] = arg;
iy++;
}
if (remote) {
av[--cnt] = NULL;
*ac = cnt;
}
return remote;
}
#define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | \
PARSE_OPT_KEEP_ARGV0 | \
PARSE_OPT_KEEP_UNKNOWN | \
PARSE_OPT_NO_INTERNAL_HELP )
int cmd_archive(int argc, const char **argv, const char *prefix)
{
const char *exec = "git-upload-archive";
const char *output = NULL;
const char *remote = NULL;
struct option local_opts[] = {
OPT_STRING(0, "output", &output, "file",
"write the archive to this file"),
OPT_STRING(0, "remote", &remote, "repo",
"retrieve the archive from remote repository <repo>"),
OPT_STRING(0, "exec", &exec, "cmd",
"path to the remote git-upload-archive command"),
OPT_END()
};
argc = parse_options(argc, argv, local_opts, NULL, PARSE_OPT_KEEP_ALL);
if (output)
create_output_file(output);
remote = extract_remote_arg(&argc, argv);
if (remote)
return run_remote_archiver(remote, argc, argv);
return run_remote_archiver(argc, argv, remote, exec);
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);

27
builtin-bisect--helper.c Normal file
View File

@ -0,0 +1,27 @@
#include "builtin.h"
#include "cache.h"
#include "parse-options.h"
#include "bisect.h"
static const char * const git_bisect_helper_usage[] = {
"git bisect--helper --next-vars",
NULL
};
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
int next_vars = 0;
struct option options[] = {
OPT_BOOLEAN(0, "next-vars", &next_vars,
"output next bisect step variables"),
OPT_END()
};
argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0);
if (!next_vars)
usage_with_options(git_bisect_helper_usage, options);
/* next-vars */
return bisect_next_vars(prefix);
}

View File

@ -1,5 +1,5 @@
/*
* Pickaxe
* Blame
*
* Copyright (c) 2006, Junio C Hamano
*/
@ -40,6 +40,10 @@ static int reverse;
static int blank_boundary;
static int incremental;
static int xdl_opts = XDF_NEED_MINIMAL;
static enum date_mode blame_date_mode = DATE_ISO8601;
static size_t blame_date_width;
static struct string_list mailmap;
#ifndef DEBUG
@ -74,6 +78,7 @@ static unsigned blame_copy_score;
*/
struct origin {
int refcnt;
struct origin *previous;
struct commit *commit;
mmfile_t file;
unsigned char blob_sha1[20];
@ -115,6 +120,8 @@ static inline struct origin *origin_incref(struct origin *o)
static void origin_decref(struct origin *o)
{
if (o && --o->refcnt <= 0) {
if (o->previous)
origin_decref(o->previous);
free(o->file.ptr);
free(o);
}
@ -1198,6 +1205,10 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
struct origin *porigin = sg_origin[i];
if (!porigin)
continue;
if (!origin->previous) {
origin_incref(porigin);
origin->previous = porigin;
}
if (pass_blame_to_parent(sb, origin, porigin))
goto finish;
}
@ -1414,6 +1425,39 @@ static void write_filename_info(const char *path)
write_name_quoted(path, stdout, '\n');
}
/*
* Porcelain/Incremental format wants to show a lot of details per
* commit. Instead of repeating this every line, emit it only once,
* the first time each commit appears in the output.
*/
static int emit_one_suspect_detail(struct origin *suspect)
{
struct commit_info ci;
if (suspect->commit->object.flags & METAINFO_SHOWN)
return 0;
suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1);
printf("author %s\n", ci.author);
printf("author-mail %s\n", ci.author_mail);
printf("author-time %lu\n", ci.author_time);
printf("author-tz %s\n", ci.author_tz);
printf("committer %s\n", ci.committer);
printf("committer-mail %s\n", ci.committer_mail);
printf("committer-time %lu\n", ci.committer_time);
printf("committer-tz %s\n", ci.committer_tz);
printf("summary %s\n", ci.summary);
if (suspect->commit->object.flags & UNINTERESTING)
printf("boundary\n");
if (suspect->previous) {
struct origin *prev = suspect->previous;
printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
write_name_quoted(prev->path, stdout, '\n');
}
return 1;
}
/*
* The blame_entry is found to be guilty for the range. Mark it
* as such, and show it in incremental output.
@ -1429,22 +1473,7 @@ static void found_guilty_entry(struct blame_entry *ent)
printf("%s %d %d %d\n",
sha1_to_hex(suspect->commit->object.sha1),
ent->s_lno + 1, ent->lno + 1, ent->num_lines);
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
struct commit_info ci;
suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1);
printf("author %s\n", ci.author);
printf("author-mail %s\n", ci.author_mail);
printf("author-time %lu\n", ci.author_time);
printf("author-tz %s\n", ci.author_tz);
printf("committer %s\n", ci.committer);
printf("committer-mail %s\n", ci.committer_mail);
printf("committer-time %lu\n", ci.committer_time);
printf("committer-tz %s\n", ci.committer_tz);
printf("summary %s\n", ci.summary);
if (suspect->commit->object.flags & UNINTERESTING)
printf("boundary\n");
}
emit_one_suspect_detail(suspect);
write_filename_info(suspect->path);
maybe_flush_or_die(stdout, "stdout");
}
@ -1507,24 +1536,20 @@ static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
time_t t = time;
int minutes, tz;
struct tm *tm;
const char *time_str;
int time_len;
int tz;
if (show_raw_time) {
sprintf(time_buf, "%lu %s", time, tz_str);
return time_buf;
}
tz = atoi(tz_str);
minutes = tz < 0 ? -tz : tz;
minutes = (minutes / 100)*60 + (minutes % 100);
minutes = tz < 0 ? -minutes : minutes;
t = time + minutes * 60;
tm = gmtime(&t);
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
strcat(time_buf, tz_str);
else {
tz = atoi(tz_str);
time_str = show_date(time, tz, blame_date_mode);
time_len = strlen(time_str);
memcpy(time_buf, time_str, time_len);
memset(time_buf + time_len, ' ', blame_date_width - time_len);
}
return time_buf;
}
@ -1551,24 +1576,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
ent->s_lno + 1,
ent->lno + 1,
ent->num_lines);
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
struct commit_info ci;
suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1);
printf("author %s\n", ci.author);
printf("author-mail %s\n", ci.author_mail);
printf("author-time %lu\n", ci.author_time);
printf("author-tz %s\n", ci.author_tz);
printf("committer %s\n", ci.committer);
printf("committer-mail %s\n", ci.committer_mail);
printf("committer-time %lu\n", ci.committer_time);
printf("committer-tz %s\n", ci.committer_tz);
write_filename_info(suspect->path);
printf("summary %s\n", ci.summary);
if (suspect->commit->object.flags & UNINTERESTING)
printf("boundary\n");
}
else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
if (emit_one_suspect_detail(suspect) ||
(suspect->commit->object.flags & MORE_THAN_ONE_PATH))
write_filename_info(suspect->path);
cp = nth_line(sb, ent->lno);
@ -1806,36 +1815,6 @@ static void sanity_check_refcnt(struct scoreboard *sb)
baa = 1;
}
}
for (ent = sb->ent; ent; ent = ent->next) {
/* Mark the ones that haven't been checked */
if (0 < ent->suspect->refcnt)
ent->suspect->refcnt = -ent->suspect->refcnt;
}
for (ent = sb->ent; ent; ent = ent->next) {
/*
* ... then pick each and see if they have the the
* correct refcnt.
*/
int found;
struct blame_entry *e;
struct origin *suspect = ent->suspect;
if (0 < suspect->refcnt)
continue;
suspect->refcnt = -suspect->refcnt; /* Unmark */
for (found = 0, e = sb->ent; e; e = e->next) {
if (e->suspect != suspect)
continue;
found++;
}
if (suspect->refcnt != found) {
fprintf(stderr, "%s in %s has refcnt %d, not %d\n",
ent->suspect->path,
sha1_to_hex(ent->suspect->commit->object.sha1),
ent->suspect->refcnt, found);
baa = 2;
}
}
if (baa) {
int opt = 0160;
find_alignment(sb, &opt);
@ -1975,6 +1954,12 @@ static int git_blame_config(const char *var, const char *value, void *cb)
blank_boundary = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "blame.date")) {
if (!value)
return config_error_nonbool(var);
blame_date_mode = parse_date_format(value);
return 0;
}
return git_default_config(var, value, cb);
}
@ -2239,6 +2224,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
git_config(git_blame_config, NULL);
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
save_commit_buffer = 0;
dashdash_pos = 0;
@ -2263,8 +2250,39 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
parse_done:
argc = parse_options_end(&ctx);
if (cmd_is_annotate)
if (revs_file && read_ancestry(revs_file))
die("reading graft file %s failed: %s",
revs_file, strerror(errno));
if (cmd_is_annotate) {
output_option |= OUTPUT_ANNOTATE_COMPAT;
blame_date_mode = DATE_ISO8601;
} else {
blame_date_mode = revs.date_mode;
}
/* The maximum width used to show the dates */
switch (blame_date_mode) {
case DATE_RFC2822:
blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
break;
case DATE_ISO8601:
blame_date_width = sizeof("2006-10-19 16:00:04 -0700");
break;
case DATE_RAW:
blame_date_width = sizeof("1161298804 -0700");
break;
case DATE_SHORT:
blame_date_width = sizeof("2006-10-19");
break;
case DATE_RELATIVE:
/* "normal" is used as the fallback for "relative" */
case DATE_LOCAL:
case DATE_NORMAL:
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
break;
}
blame_date_width -= 1; /* strip the null */
if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER))
opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
@ -2404,10 +2422,6 @@ parse_done:
sb.ent = ent;
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);
if (!incremental)

View File

@ -32,18 +32,18 @@ static unsigned char head_sha1[20];
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
"\033[m", /* reset */
"", /* PLAIN (normal) */
"\033[31m", /* REMOTE (red) */
"", /* LOCAL (normal) */
"\033[32m", /* CURRENT (green) */
GIT_COLOR_RESET,
GIT_COLOR_NORMAL, /* PLAIN */
GIT_COLOR_RED, /* REMOTE */
GIT_COLOR_NORMAL, /* LOCAL */
GIT_COLOR_GREEN, /* CURRENT */
};
enum color_branch {
COLOR_BRANCH_RESET = 0,
COLOR_BRANCH_PLAIN = 1,
COLOR_BRANCH_REMOTE = 2,
COLOR_BRANCH_LOCAL = 3,
COLOR_BRANCH_CURRENT = 4,
BRANCH_COLOR_RESET = 0,
BRANCH_COLOR_PLAIN = 1,
BRANCH_COLOR_REMOTE = 2,
BRANCH_COLOR_LOCAL = 3,
BRANCH_COLOR_CURRENT = 4,
};
static enum merge_filter {
@ -56,15 +56,15 @@ static unsigned char merge_filter_ref[20];
static int parse_branch_color_slot(const char *var, int ofs)
{
if (!strcasecmp(var+ofs, "plain"))
return COLOR_BRANCH_PLAIN;
return BRANCH_COLOR_PLAIN;
if (!strcasecmp(var+ofs, "reset"))
return COLOR_BRANCH_RESET;
return BRANCH_COLOR_RESET;
if (!strcasecmp(var+ofs, "remote"))
return COLOR_BRANCH_REMOTE;
return BRANCH_COLOR_REMOTE;
if (!strcasecmp(var+ofs, "local"))
return COLOR_BRANCH_LOCAL;
return BRANCH_COLOR_LOCAL;
if (!strcasecmp(var+ofs, "current"))
return COLOR_BRANCH_CURRENT;
return BRANCH_COLOR_CURRENT;
die("bad config variable '%s'", var);
}
@ -121,11 +121,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
die("Couldn't look up commit object for HEAD");
}
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
int len = strlen(argv[i]);
if (interpret_nth_last_branch(argv[i], &bname) != len)
strbuf_add(&bname, argv[i], len);
strbuf_branchname(&bname, argv[i]);
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
error("Cannot delete the branch '%s' "
"which you are currently on.", bname.buf);
@ -171,7 +167,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
ret = 1;
} else {
struct strbuf buf = STRBUF_INIT;
printf("Deleted %sbranch %s (%s).\n", remote,
printf("Deleted %sbranch %s (was %s).\n", remote,
bname.buf,
find_unique_abbrev(sha1, DEFAULT_ABBREV));
strbuf_addf(&buf, "branch.%s", bname.buf);
@ -188,7 +184,8 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
struct ref_item {
char *name;
unsigned int kind;
char *dest;
unsigned int kind, len;
struct commit *commit;
};
@ -200,22 +197,47 @@ struct ref_list {
int kinds;
};
static char *resolve_symref(const char *src, const char *prefix)
{
unsigned char sha1[20];
int flag;
const char *dst, *cp;
dst = resolve_ref(src, sha1, 0, &flag);
if (!(dst && (flag & REF_ISSYMREF)))
return NULL;
if (prefix && (cp = skip_prefix(dst, prefix)))
dst = cp;
return xstrdup(dst);
}
static int append_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
{
struct ref_list *ref_list = (struct ref_list*)(cb_data);
struct ref_item *newitem;
struct commit *commit;
int kind;
int len;
int kind, i;
const char *prefix, *orig_refname = refname;
static struct {
int kind;
const char *prefix;
int pfxlen;
} ref_kind[] = {
{ REF_LOCAL_BRANCH, "refs/heads/", 11 },
{ REF_REMOTE_BRANCH, "refs/remotes/", 13 },
};
/* Detect kind */
if (!prefixcmp(refname, "refs/heads/")) {
kind = REF_LOCAL_BRANCH;
refname += 11;
} else if (!prefixcmp(refname, "refs/remotes/")) {
kind = REF_REMOTE_BRANCH;
refname += 13;
} else
for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
prefix = ref_kind[i].prefix;
if (strncmp(refname, prefix, ref_kind[i].pfxlen))
continue;
kind = ref_kind[i].kind;
refname += ref_kind[i].pfxlen;
break;
}
if (ARRAY_SIZE(ref_kind) <= i)
return 0;
commit = lookup_commit_reference_gently(sha1, 1);
@ -246,9 +268,14 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
newitem->name = xstrdup(refname);
newitem->kind = kind;
newitem->commit = commit;
len = strlen(newitem->name);
if (len > ref_list->maxwidth)
ref_list->maxwidth = len;
newitem->len = strlen(refname);
newitem->dest = resolve_symref(orig_refname, prefix);
/* adjust for "remotes/" */
if (newitem->kind == REF_REMOTE_BRANCH &&
ref_list->kinds != REF_REMOTE_BRANCH)
newitem->len += 8;
if (newitem->len > ref_list->maxwidth)
ref_list->maxwidth = newitem->len;
return 0;
}
@ -257,8 +284,10 @@ static void free_ref_list(struct ref_list *ref_list)
{
int i;
for (i = 0; i < ref_list->index; i++)
for (i = 0; i < ref_list->index; i++) {
free(ref_list->list[i].name);
free(ref_list->list[i].dest);
}
free(ref_list->list);
}
@ -272,19 +301,30 @@ static int ref_cmp(const void *r1, const void *r2)
return strcmp(c1->name, c2->name);
}
static void fill_tracking_info(struct strbuf *stat, const char *branch_name)
static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
int show_upstream_ref)
{
int ours, theirs;
struct branch *branch = branch_get(branch_name);
if (!stat_tracking_info(branch, &ours, &theirs) || (!ours && !theirs))
if (!stat_tracking_info(branch, &ours, &theirs)) {
if (branch && branch->merge && branch->merge[0]->dst &&
show_upstream_ref)
strbuf_addf(stat, "[%s] ",
shorten_unambiguous_ref(branch->merge[0]->dst));
return;
}
strbuf_addch(stat, '[');
if (show_upstream_ref)
strbuf_addf(stat, "%s: ",
shorten_unambiguous_ref(branch->merge[0]->dst));
if (!ours)
strbuf_addf(stat, "[behind %d] ", theirs);
strbuf_addf(stat, "behind %d] ", theirs);
else if (!theirs)
strbuf_addf(stat, "[ahead %d] ", ours);
strbuf_addf(stat, "ahead %d] ", ours);
else
strbuf_addf(stat, "[ahead %d, behind %d] ", ours, theirs);
strbuf_addf(stat, "ahead %d, behind %d] ", ours, theirs);
}
static int matches_merge_filter(struct commit *commit)
@ -299,34 +339,46 @@ static int matches_merge_filter(struct commit *commit)
}
static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
int abbrev, int current)
int abbrev, int current, char *prefix)
{
char c;
int color;
struct commit *commit = item->commit;
struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
if (!matches_merge_filter(commit))
return;
switch (item->kind) {
case REF_LOCAL_BRANCH:
color = COLOR_BRANCH_LOCAL;
color = BRANCH_COLOR_LOCAL;
break;
case REF_REMOTE_BRANCH:
color = COLOR_BRANCH_REMOTE;
color = BRANCH_COLOR_REMOTE;
break;
default:
color = COLOR_BRANCH_PLAIN;
color = BRANCH_COLOR_PLAIN;
break;
}
c = ' ';
if (current) {
c = '*';
color = COLOR_BRANCH_CURRENT;
color = BRANCH_COLOR_CURRENT;
}
if (verbose) {
strbuf_addf(&name, "%s%s", prefix, item->name);
if (verbose)
strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
maxwidth, name.buf,
branch_get_color(BRANCH_COLOR_RESET));
else
strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
name.buf, branch_get_color(BRANCH_COLOR_RESET));
if (item->dest)
strbuf_addf(&out, " -> %s", item->dest);
else if (verbose) {
struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
const char *sub = " **** invalid ref ****";
@ -338,30 +390,27 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
}
if (item->kind == REF_LOCAL_BRANCH)
fill_tracking_info(&stat, item->name);
fill_tracking_info(&stat, item->name, verbose > 1);
printf("%c %s%-*s%s %s %s%s\n", c, branch_get_color(color),
maxwidth, item->name,
branch_get_color(COLOR_BRANCH_RESET),
find_unique_abbrev(item->commit->object.sha1, abbrev),
stat.buf, sub);
strbuf_addf(&out, " %s %s%s",
find_unique_abbrev(item->commit->object.sha1, abbrev),
stat.buf, sub);
strbuf_release(&stat);
strbuf_release(&subject);
} else {
printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
branch_get_color(COLOR_BRANCH_RESET));
}
printf("%s\n", out.buf);
strbuf_release(&name);
strbuf_release(&out);
}
static int calc_maxwidth(struct ref_list *refs)
{
int i, l, w = 0;
int i, w = 0;
for (i = 0; i < refs->index; i++) {
if (!matches_merge_filter(refs->list[i].commit))
continue;
l = strlen(refs->list[i].name);
if (l > w)
w = l;
if (refs->list[i].len > w)
w = refs->list[i].len;
}
return w;
}
@ -397,11 +446,13 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
is_descendant_of(head_commit, with_commit)) {
struct ref_item item;
item.name = xstrdup("(no branch)");
item.len = strlen(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
item.commit = head_commit;
if (strlen(item.name) > ref_list.maxwidth)
ref_list.maxwidth = strlen(item.name);
print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1);
if (item.len > ref_list.maxwidth)
ref_list.maxwidth = item.len;
print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, "");
free(item.name);
}
@ -409,8 +460,11 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
int current = !detached &&
(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
!strcmp(ref_list.list[i].name, head);
char *prefix = (kinds != REF_REMOTE_BRANCH &&
ref_list.list[i].kind == REF_REMOTE_BRANCH)
? "remotes/" : "";
print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,
abbrev, current);
abbrev, current, prefix);
}
free_ref_list(&ref_list);
@ -421,22 +475,27 @@ static void rename_branch(const char *oldname, const char *newname, int force)
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
unsigned char sha1[20];
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
int recovery = 0;
if (!oldname)
die("cannot rename the current branch while not on any.");
strbuf_addf(&oldref, "refs/heads/%s", oldname);
if (strbuf_check_branch_ref(&oldref, oldname)) {
/*
* Bad name --- this could be an attempt to rename a
* ref that we used to allow to be created by accident.
*/
if (resolve_ref(oldref.buf, sha1, 1, NULL))
recovery = 1;
else
die("Invalid branch name: '%s'", oldname);
}
if (check_ref_format(oldref.buf))
die("Invalid branch name: %s", oldref.buf);
strbuf_addf(&newref, "refs/heads/%s", newname);
if (check_ref_format(newref.buf))
die("Invalid branch name: %s", newref.buf);
if (strbuf_check_branch_ref(&newref, newname))
die("Invalid branch name: '%s'", newname);
if (resolve_ref(newref.buf, sha1, 1, NULL) && !force)
die("A branch named '%s' already exists.", newname);
die("A branch named '%s' already exists.", newref.buf + 11);
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
oldref.buf, newref.buf);
@ -445,6 +504,9 @@ static void rename_branch(const char *oldname, const char *newname, int force)
die("Branch rename failed");
strbuf_release(&logmsg);
if (recovery)
warning("Renamed a misnamed branch '%s' away", oldref.buf + 11);
/* no need to pass logmsg here as HEAD didn't really move */
if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL))
die("Branch renamed to %s, but HEAD is not updated!", newname);

View File

@ -5,9 +5,18 @@
#include "cache.h"
#include "refs.h"
#include "builtin.h"
#include "strbuf.h"
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
{
if (argc == 3 && !strcmp(argv[1], "--branch")) {
struct strbuf sb = STRBUF_INIT;
if (strbuf_check_branch_ref(&sb, argv[2]))
die("'%s' is not a valid branch name", argv[2]);
printf("%s\n", sb.buf + 11);
exit(0);
}
if (argc != 2)
usage("git check-ref-format refname");
return !!check_ref_format(argv[1]);

View File

@ -53,9 +53,6 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
int len;
struct cache_entry *ce;
if (S_ISGITLINK(mode))
return 0;
if (S_ISDIR(mode))
return READ_TREE_RECURSIVE;
@ -295,6 +292,8 @@ static void show_local_changes(struct object *head)
init_revisions(&rev, NULL);
rev.abbrev = 0;
rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
if (diff_setup_done(&rev.diffopt) < 0)
die("diff_setup_done failed");
add_pending_object(&rev, head, NULL);
run_diff_index(&rev, 0);
}
@ -351,16 +350,11 @@ struct branch_info {
static void setup_branch_path(struct branch_info *branch)
{
struct strbuf buf = STRBUF_INIT;
int ret;
if ((ret = interpret_nth_last_branch(branch->name, &buf))
&& ret == strlen(branch->name)) {
strbuf_branchname(&buf, branch->name);
if (strcmp(buf.buf, branch->name))
branch->name = xstrdup(buf.buf);
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
} else {
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, branch->name);
}
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
branch->path = strbuf_detach(&buf, NULL);
}
@ -405,7 +399,7 @@ static int merge_working_tree(struct checkout_opts *opts,
topts.verbose_update = !opts->quiet;
topts.fn = twoway_merge;
topts.dir = xcalloc(1, sizeof(*topts.dir));
topts.dir->show_ignored = 1;
topts.dir->flags |= DIR_SHOW_IGNORED;
topts.dir->exclude_per_dir = ".gitignore";
tree = parse_tree_indirect(old->commit->object.sha1);
init_tree_desc(&trees[0], tree->buffer, tree->size);
@ -501,10 +495,10 @@ static void update_refs_for_switch(struct checkout_opts *opts,
create_symref("HEAD", new->path, msg.buf);
if (!opts->quiet) {
if (old->path && !strcmp(new->path, old->path))
fprintf(stderr, "Already on \"%s\"\n",
fprintf(stderr, "Already on '%s'\n",
new->name);
else
fprintf(stderr, "Switched to%s branch \"%s\"\n",
fprintf(stderr, "Switched to%s branch '%s'\n",
opts->new_branch ? " a new" : "",
new->name);
}
@ -513,7 +507,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
REF_NODEREF, DIE_ON_ERR);
if (!opts->quiet) {
if (old->path)
fprintf(stderr, "Note: moving to \"%s\" which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n git checkout -b <new_branch_name>\n", new->name);
fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n git checkout -b <new_branch_name>\n", new->name);
describe_detached_head("HEAD is now at", new->commit);
}
}
@ -556,8 +550,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
if (!old.commit && !opts->force) {
if (!opts->quiet) {
fprintf(stderr, "warning: You appear to be on a branch yet to be born.\n");
fprintf(stderr, "warning: Forcing checkout of %s.\n", new->name);
warning("You appear to be on a branch yet to be born.");
warning("Forcing checkout of %s.", new->name);
}
opts->force = 1;
}
@ -736,12 +730,11 @@ no_reference:
if (opts.new_branch) {
struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, opts.new_branch);
if (strbuf_check_branch_ref(&buf, opts.new_branch))
die("git checkout: we do not like '%s' as a branch name.",
opts.new_branch);
if (!get_sha1(buf.buf, rev))
die("git checkout: branch %s already exists", opts.new_branch);
if (check_ref_format(buf.buf))
die("git checkout: we do not like '%s' as a branch name.", opts.new_branch);
strbuf_release(&buf);
}

View File

@ -60,7 +60,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
memset(&dir, 0, sizeof(dir));
if (ignored_only)
dir.show_ignored = 1;
dir.flags |= DIR_SHOW_IGNORED;
if (ignored && ignored_only)
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; "
"refusing to clean", config_set ? "" : " not");
dir.show_other_directories = 1;
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (!ignored)
setup_standard_excludes(&dir);

View File

@ -20,6 +20,9 @@
#include "dir.h"
#include "pack-refs.h"
#include "sigchain.h"
#include "branch.h"
#include "remote.h"
#include "run-command.h"
/*
* Overall FIXMEs:
@ -267,7 +270,7 @@ static const struct ref *clone_local(const char *src_repo,
static const char *junk_work_tree;
static const char *junk_git_dir;
pid_t junk_pid;
static pid_t junk_pid;
static void remove_junk(void)
{
@ -293,43 +296,6 @@ static void remove_junk_on_signal(int 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,
struct refspec *refspec, const char *reflog)
{
@ -350,23 +316,8 @@ static struct ref *write_remote_refs(const struct ref *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 use_local_hardlinks = 1;
int use_separate_remote = 1;
int is_bundle = 0;
struct stat buf;
const char *repo_name, *repo, *work_tree, *git_dir;
@ -377,8 +328,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
char *src_ref_prefix = "refs/heads/";
int err = 0;
struct refspec refspec;
struct refspec *refspec;
const char *fetch_pattern;
junk_pid = getpid();
@ -388,9 +341,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (argc == 0)
die("You must specify a repository to clone.");
if (option_no_hardlinks)
use_local_hardlinks = 0;
if (option_mirror)
option_bare = 1;
@ -399,7 +349,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die("--bare and --origin %s options are incompatible.",
option_origin);
option_no_checkout = 1;
use_separate_remote = 0;
}
if (!option_origin)
@ -457,7 +406,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
atexit(remove_junk);
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)
die("could not create leading directories of '%s'", git_dir);
@ -487,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(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
if (option_mirror || !option_bare) {
/* 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) {
strbuf_addf(&key, "remote.%s.mirror", option_origin);
git_config_set(key.buf, "true");
@ -497,19 +452,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_addf(&key, "remote.%s.url", option_origin);
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(&value);
}
refspec.force = 0;
refspec.pattern = 1;
refspec.src = src_ref_prefix;
refspec.dst = branch_top.buf;
fetch_pattern = value.buf;
refspec = parse_fetch_refspec(1, &fetch_pattern);
strbuf_reset(&value);
if (path && !is_bundle)
refs = clone_local(path, git_dir);
@ -543,9 +492,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (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 {
warning("You appear to have cloned an empty repository.");
@ -553,7 +503,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote_head = NULL;
option_no_checkout = 1;
if (!option_bare)
install_branch_config("master", option_origin,
install_branch_config(0, "master", option_origin,
"refs/heads/master");
}
@ -583,7 +533,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
head_points_at->peer_ref->name,
reflog_msg.buf);
install_branch_config(head, option_origin,
install_branch_config(0, head, option_origin,
head_points_at->name);
}
} else if (remote_head) {
@ -631,6 +581,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (write_cache(fd, active_cache, active_nr) ||
commit_locked_index(lock_file))
die("unable to write new index file");
err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
sha1_to_hex(remote_head->old_sha1), "1", NULL);
}
strbuf_release(&reflog_msg);
@ -638,5 +591,5 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_release(&key);
strbuf_release(&value);
junk_pid = 0;
return 0;
return err;
}

View File

@ -224,7 +224,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
const char **pathspec = NULL;
if (interactive) {
interactive_add(argc, argv, prefix);
if (interactive_add(argc, argv, prefix) != 0)
die("interactive add failed");
if (read_cache_preload(NULL) < 0)
die("index file corrupt");
commit_style = COMMIT_AS_IS;

View File

@ -1,9 +1,12 @@
#include "builtin.h"
#include "cache.h"
#include "color.h"
#include "parse-options.h"
static const char git_config_set_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]";
static const char *const builtin_config_usage[] = {
"git config [options]",
NULL
};
static char *key;
static regex_t *key_regexp;
@ -16,7 +19,67 @@ static int seen;
static char delim = '=';
static char key_delim = ' ';
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)
{
@ -27,7 +90,7 @@ static int show_all_config(const char *key_, const char *value_, void *cb)
return 0;
}
static int show_config(const char* key_, const char* value_, void *cb)
static int show_config(const char *key_, const char *value_, void *cb)
{
char value[256];
const char *vptr = value;
@ -49,11 +112,11 @@ static int show_config(const char* key_, const char* value_, void *cb)
}
if (seen && !do_all)
dup_error = 1;
if (type == T_INT)
if (types == TYPE_INT)
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";
else if (type == T_BOOL_OR_INT) {
else if (types == TYPE_BOOL_OR_INT) {
int is_bool, v;
v = git_config_bool_or_int(key_, value_, &is_bool);
if (is_bool)
@ -74,7 +137,7 @@ static int show_config(const char* key_, const char* value_, void *cb)
return 0;
}
static int get_value(const char* key_, const char* regex_)
static int get_value(const char *key_, const char *regex_)
{
int ret = -1;
char *tl;
@ -152,18 +215,18 @@ static char *normalize_value(const char *key, const char *value)
if (!value)
return NULL;
if (type == T_RAW)
if (types == 0)
normalized = xstrdup(value);
else {
normalized = xmalloc(64);
if (type == T_INT) {
if (types == TYPE_INT) {
int v = git_config_int(key, value);
sprintf(normalized, "%d", v);
}
else if (type == T_BOOL)
else if (types == TYPE_BOOL)
sprintf(normalized, "%s",
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;
v = git_config_bool_or_int(key, value, &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 const char *get_color_slot;
static const char *get_colorbool_slot;
static char parsed_color[COLOR_MAXLEN];
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;
}
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;
parsed_color[0] = '\0';
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);
fputs(parsed_color, stdout);
return 0;
}
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,
void *cb)
{
if (!strcmp(var, get_color_slot)) {
if (!strcmp(var, get_colorbool_slot)) {
get_colorbool_found =
git_config_colorbool(var, value, stdout_is_tty);
}
@ -246,183 +288,188 @@ static int git_get_colorbool_config(const char *var, const char *value,
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_diff_color_found = -1;
get_color_slot = argv[0];
git_config(git_get_colorbool_config, NULL);
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;
if (get_colorbool_found < 0)
get_colorbool_found = git_use_color_default;
}
if (argc == 1) {
return get_colorbool_found ? 0 : 1;
} else {
if (print) {
printf("%s\n", get_colorbool_found ? "true" : "false");
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;
char* value;
const char *file = setup_git_directory_gently(&nongit);
char *value;
const char *prefix = setup_git_directory_gently(&nongit);
config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
while (1 < argc) {
if (!strcmp(argv[1], "--int"))
type = T_INT;
else if (!strcmp(argv[1], "--bool"))
type = T_BOOL;
else if (!strcmp(argv[1], "--bool-or-int"))
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
break;
argc--;
argv++;
argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (use_global_config + use_system_config + !!given_config_file > 1) {
error("only one config file at a time.");
usage_with_options(builtin_config_usage, builtin_config_options);
}
switch (argc) {
case 2:
return get_value(argv[1], NULL);
case 3:
if (!strcmp(argv[1], "--unset"))
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);
if (use_global_config) {
char *home = getenv("HOME");
if (home) {
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
config_exclusive_filename = user_config;
} else {
value = normalize_value(argv[1], argv[2]);
return git_config_set(argv[1], value);
die("$HOME not set");
}
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;
}

View File

@ -60,7 +60,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
hex[40] = 0;
if (get_sha1_hex(hex, sha1))
die("internal error");
if (has_sha1_pack(sha1, NULL))
if (has_sha1_pack(sha1))
(*packed_loose)++;
}
}

View File

@ -102,7 +102,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
init_revisions(opt, prefix);
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
nr_sha1 = 0;
opt->abbrev = 0;
opt->diff = 1;
argc = setup_revisions(argc, argv, opt, NULL);

View File

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

View File

@ -216,9 +216,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
if (args.depth > 0) {
char line[1024];
unsigned char sha1[20];
int len;
while ((len = packet_read_line(fd[0], line, sizeof(line)))) {
while (packet_read_line(fd[0], line, sizeof(line))) {
if (!prefixcmp(line, "shallow ")) {
if (get_sha1_hex(line + 8, sha1))
die("invalid shallow line: %s", line);
@ -483,7 +482,7 @@ static int sideband_demux(int fd, void *data)
{
int *xd = data;
return recv_sideband("fetch-pack", xd[0], fd, 2);
return recv_sideband("fetch-pack", xd[0], fd);
}
static int get_pack(int xd[2], char **pack_lockfile)
@ -606,7 +605,7 @@ static struct ref *do_fetch_pack(int fd[2],
/* When cloning, it is not unusual to have
* no common commit.
*/
fprintf(stderr, "warning: no common commits\n");
warning("no common commits");
if (get_pack(fd, pack_lockfile))
die("git fetch-pack: fetch failed.");
@ -801,15 +800,13 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
int fd;
mtime.sec = st.st_mtime;
#ifdef USE_NSEC
mtime.usec = st.st_mtim.usec;
#endif
mtime.nsec = ST_MTIME_NSEC(st);
if (stat(shallow, &st)) {
if (mtime.sec)
die("shallow file was removed during fetch");
} else if (st.st_mtime != mtime.sec
#ifdef USE_NSEC
|| st.st_mtim.usec != mtime.usec
|| ST_MTIME_NSEC(st) != mtime.nsec
#endif
)
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;
enum object_type type;
struct branch *current_branch = branch_get(NULL);
const char *pretty_ref = ref->name + (
!prefixcmp(ref->name, "refs/heads/") ? 11 :
!prefixcmp(ref->name, "refs/tags/") ? 10 :
!prefixcmp(ref->name, "refs/remotes/") ? 13 :
0);
const char *pretty_ref = prettify_ref(ref);
*display = 0;
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)
if (ref_map->peer_ref && !strcmp(current_branch->refname,
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,

View File

@ -256,8 +256,7 @@ static void shortlog(const char *name, unsigned char *sha1,
int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
int limit = 20, i = 0, pos = 0;
char line[1024];
char *p = line, *sep = "";
char *sep = "";
unsigned char head_sha1[20];
const char *current_branch;
@ -271,9 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
/* get a line */
while (pos < in->len) {
int len;
char *newline;
char *newline, *p = in->buf + pos;
p = in->buf + pos;
newline = strchr(p, '\n');
len = newline ? newline - p : strlen(p);
pos += len + !!newline;

View File

@ -8,6 +8,7 @@
#include "blob.h"
#include "quote.h"
#include "parse-options.h"
#include "remote.h"
/* Quoting styles */
#define QUOTE_NONE 0
@ -66,6 +67,7 @@ static struct {
{ "subject" },
{ "body" },
{ "contents" },
{ "upstream" },
};
/*
@ -543,109 +545,6 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
}
}
/*
* generate a format suitable for scanf from a ref_rev_parse_rules
* rule, that is replace the "%.*s" spec with a "%s" spec
*/
static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
{
char *spec;
spec = strstr(rule, "%.*s");
if (!spec || strstr(spec + 4, "%.*s"))
die("invalid rule in ref_rev_parse_rules: %s", rule);
/* copy all until spec */
strncpy(scanf_fmt, rule, spec - rule);
scanf_fmt[spec - rule] = '\0';
/* copy new spec */
strcat(scanf_fmt, "%s");
/* copy remaining rule */
strcat(scanf_fmt, spec + 4);
return;
}
/*
* Shorten the refname to an non-ambiguous form
*/
static char *get_short_ref(struct refinfo *ref)
{
int i;
static char **scanf_fmts;
static int nr_rules;
char *short_name;
/* pre generate scanf formats from ref_rev_parse_rules[] */
if (!nr_rules) {
size_t total_len = 0;
/* the rule list is NULL terminated, count them first */
for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
/* no +1 because strlen("%s") < strlen("%.*s") */
total_len += strlen(ref_rev_parse_rules[nr_rules]);
scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
total_len = 0;
for (i = 0; i < nr_rules; i++) {
scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
+ total_len;
gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
total_len += strlen(ref_rev_parse_rules[i]);
}
}
/* bail out if there are no rules */
if (!nr_rules)
return ref->refname;
/* buffer for scanf result, at most ref->refname must fit */
short_name = xstrdup(ref->refname);
/* skip first rule, it will always match */
for (i = nr_rules - 1; i > 0 ; --i) {
int j;
int short_name_len;
if (1 != sscanf(ref->refname, scanf_fmts[i], short_name))
continue;
short_name_len = strlen(short_name);
/*
* check if the short name resolves to a valid ref,
* but use only rules prior to the matched one
*/
for (j = 0; j < i; j++) {
const char *rule = ref_rev_parse_rules[j];
unsigned char short_objectname[20];
char refname[PATH_MAX];
/*
* the short name is ambiguous, if it resolves
* (with this previous rule) to a valid ref
* read_ref() returns 0 on success
*/
mksnpath(refname, sizeof(refname),
rule, short_name_len, short_name);
if (!read_ref(refname, short_objectname))
break;
}
/*
* short name is non-ambiguous if all previous rules
* haven't resolved to a valid ref
*/
if (j == i)
return short_name;
}
free(short_name);
return ref->refname;
}
/*
* Parse the object referred by ref, and grab needed value.
*/
@ -672,32 +571,49 @@ static void populate_value(struct refinfo *ref)
const char *name = used_atom[i];
struct atom_value *v = &ref->value[i];
int deref = 0;
const char *refname;
const char *formatp;
if (*name == '*') {
deref = 1;
name++;
}
if (!prefixcmp(name, "refname")) {
const char *formatp = strchr(name, ':');
const char *refname = ref->refname;
/* look for "short" refname format */
if (formatp) {
formatp++;
if (!strcmp(formatp, "short"))
refname = get_short_ref(ref);
else
die("unknown refname format %s",
formatp);
}
if (!prefixcmp(name, "refname"))
refname = ref->refname;
else if(!prefixcmp(name, "upstream")) {
struct branch *branch;
/* only local branches may have an upstream */
if (prefixcmp(ref->refname, "refs/heads/"))
continue;
branch = branch_get(ref->refname + 11);
if (!deref)
v->s = refname;
else {
int len = strlen(refname);
char *s = xmalloc(len + 4);
sprintf(s, "%s^{}", refname);
v->s = s;
}
if (!branch || !branch->merge || !branch->merge[0] ||
!branch->merge[0]->dst)
continue;
refname = branch->merge[0]->dst;
}
else
continue;
formatp = strchr(name, ':');
/* look for "short" refname format */
if (formatp) {
formatp++;
if (!strcmp(formatp, "short"))
refname = shorten_unambiguous_ref(refname);
else
die("unknown %.*s format %s",
(int)(formatp - name), name, formatp);
}
if (!deref)
v->s = refname;
else {
int len = strlen(refname);
char *s = xmalloc(len + 4);
sprintf(s, "%s^{}", refname);
v->s = s;
}
}
@ -943,7 +859,6 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
return -1;
*sort_tail = s = xcalloc(1, sizeof(*s));
sort_tail = &s->next;
if (*arg == '-') {
s->reverse = 1;

View File

@ -160,7 +160,7 @@ static void check_reachable_object(struct object *obj)
* do a full fsck
*/
if (!obj->parsed) {
if (has_sha1_pack(obj->sha1, NULL))
if (has_sha1_pack(obj->sha1))
return; /* it is in pack - forget about it */
printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
errors_found |= ERROR_REACHABLE;

View File

@ -23,7 +23,7 @@ static const char * const builtin_gc_usage[] = {
};
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_pack_limit = 50;
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) {
append_option(argv_repack, "-f", MAX_ADD);
append_option(argv_repack, "--depth=250", MAX_ADD);
if (aggressive_window > 0) {
sprintf(buf, "--window=%d", aggressive_window);
append_option(argv_repack, buf, MAX_ADD);

View File

@ -22,6 +22,28 @@
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;
* pathname wildcards are allowed.
@ -269,6 +291,21 @@ static int flush_grep(struct grep_opt *opt,
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)
{
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(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;
argc = nr;
@ -536,6 +590,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.pattern_tail = &opt.pattern_list;
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
* 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;
continue;
}
if (!strcmp("--color", arg)) {
opt.color = 1;
continue;
}
if (!strcmp("--no-color", arg)) {
opt.color = 0;
continue;
}
if (!strcmp("--", arg)) {
/* later processing wants to have this at argv[1] */
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)
die("no pattern given.");
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);
if (!dir) {
fprintf(stderr, "warning: templates not found %s\n",
template_dir);
warning("templates not found %s", template_dir);
return;
}
@ -144,8 +143,8 @@ static void copy_templates(const char *template_dir)
if (repository_format_version &&
repository_format_version != GIT_REPO_VERSION) {
fprintf(stderr, "warning: not copying templates of "
"a wrong format version %d from '%s'\n",
warning("not copying templates of "
"a wrong format version %d from '%s'",
repository_format_version,
template_dir);
closedir(dir);

View File

@ -17,6 +17,7 @@
#include "run-command.h"
#include "shortlog.h"
#include "remote.h"
#include "string-list.h"
/* Set a default date-time format for git log ("log.date" config variable) */
static const char *default_date_mode = NULL;
@ -416,18 +417,13 @@ int cmd_log(int argc, const char **argv, const char *prefix)
}
/* format-patch */
#define FORMAT_PATCH_NAME_MAX 64
static int istitlechar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '.' || c == '_';
}
static const char *fmt_patch_suffix = ".patch";
static int numbered = 0;
static int auto_number = 1;
static char *default_attach = NULL;
static char **extra_hdr;
static int extra_hdr_nr;
static int extra_hdr_alloc;
@ -459,6 +455,11 @@ static void add_header(const char *value)
extra_hdr[extra_hdr_nr++] = xstrndup(value, len);
}
#define THREAD_SHALLOW 1
#define THREAD_DEEP 2
static int thread = 0;
static int do_signoff = 0;
static int git_format_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "format.headers")) {
@ -488,94 +489,60 @@ static int git_format_config(const char *var, const char *value, void *cb)
auto_number = auto_number && numbered;
return 0;
}
if (!strcmp(var, "format.attach")) {
if (value && *value)
default_attach = xstrdup(value);
else
default_attach = xstrdup(git_version_string);
return 0;
}
if (!strcmp(var, "format.thread")) {
if (value && !strcasecmp(value, "deep")) {
thread = THREAD_DEEP;
return 0;
}
if (value && !strcasecmp(value, "shallow")) {
thread = THREAD_SHALLOW;
return 0;
}
thread = git_config_bool(var, value) && THREAD_SHALLOW;
return 0;
}
if (!strcmp(var, "format.signoff")) {
do_signoff = git_config_bool(var, value);
return 0;
}
return git_log_config(var, value, cb);
}
static const char *get_oneline_for_filename(struct commit *commit,
int keep_subject)
{
static char filename[PATH_MAX];
char *sol;
int len = 0;
int suffix_len = strlen(fmt_patch_suffix) + 1;
sol = strstr(commit->buffer, "\n\n");
if (!sol)
filename[0] = '\0';
else {
int j, space = 0;
sol += 2;
/* strip [PATCH] or [PATCH blabla] */
if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
char *eos = strchr(sol + 6, ']');
if (eos) {
while (isspace(*eos))
eos++;
sol = eos;
}
}
for (j = 0;
j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
len < sizeof(filename) - suffix_len &&
sol[j] && sol[j] != '\n';
j++) {
if (istitlechar(sol[j])) {
if (space) {
filename[len++] = '-';
space = 0;
}
filename[len++] = sol[j];
if (sol[j] == '.')
while (sol[j + 1] == '.')
j++;
} else
space = 1;
}
while (filename[len - 1] == '.'
|| filename[len - 1] == '-')
len--;
filename[len] = '\0';
}
return filename;
}
static FILE *realstdout = NULL;
static const char *output_directory = NULL;
static int outdir_offset;
static int reopen_stdout(const char *oneline, int nr, int total)
static int reopen_stdout(struct commit *commit, struct rev_info *rev)
{
char filename[PATH_MAX];
int len = 0;
struct strbuf filename = STRBUF_INIT;
int suffix_len = strlen(fmt_patch_suffix) + 1;
if (output_directory) {
len = snprintf(filename, sizeof(filename), "%s",
output_directory);
if (len >=
sizeof(filename) - FORMAT_PATCH_NAME_MAX - suffix_len)
strbuf_addstr(&filename, output_directory);
if (filename.len >=
PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
return error("name of output directory is too long");
if (filename[len - 1] != '/')
filename[len++] = '/';
if (filename.buf[filename.len - 1] != '/')
strbuf_addch(&filename, '/');
}
if (!oneline)
len += sprintf(filename + len, "%d", nr);
else {
len += sprintf(filename + len, "%04d-", nr);
len += snprintf(filename + len, sizeof(filename) - len - 1
- suffix_len, "%s", oneline);
strcpy(filename + len, fmt_patch_suffix);
}
get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);
fprintf(realstdout, "%s\n", filename + outdir_offset);
if (freopen(filename, "w", stdout) == NULL)
return error("Cannot open patch file %s",filename);
if (!DIFF_OPT_TST(&rev->diffopt, QUIET))
fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
if (freopen(filename.buf, "w", stdout) == NULL)
return error("Cannot open patch file %s", filename.buf);
strbuf_release(&filename);
return 0;
}
@ -645,7 +612,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
int nr, struct commit **list, struct commit *head)
{
const char *committer;
char *head_sha1;
const char *subject_start = NULL;
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
const char *msg;
@ -656,21 +622,41 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
const char *encoding = "utf-8";
struct diff_options opts;
int need_8bit_cte = 0;
struct commit *commit = NULL;
if (rev->commit_format != CMIT_FMT_EMAIL)
die("Cover letter needs email format");
if (!use_stdout && reopen_stdout(numbered_files ?
NULL : "cover-letter", 0, rev->total))
committer = git_committer_info(0);
if (!numbered_files) {
/*
* We fake a commit for the cover letter so we get the filename
* desired.
*/
commit = xcalloc(1, sizeof(*commit));
commit->buffer = xmalloc(400);
snprintf(commit->buffer, 400,
"tree 0000000000000000000000000000000000000000\n"
"parent %s\n"
"author %s\n"
"committer %s\n\n"
"cover letter\n",
sha1_to_hex(head->object.sha1), committer, committer);
}
if (!use_stdout && reopen_stdout(commit, rev))
return;
head_sha1 = sha1_to_hex(head->object.sha1);
if (commit) {
log_write_email_headers(rev, head_sha1, &subject_start, &extra_headers,
free(commit->buffer);
free(commit);
}
log_write_email_headers(rev, head, &subject_start, &extra_headers,
&need_8bit_cte);
committer = git_committer_info(0);
msg = body;
pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,
encoding);
@ -766,7 +752,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int numbered_files = 0; /* _just_ numbers */
int subject_prefix = 0;
int ignore_if_in_upstream = 0;
int thread = 0;
int cover_letter = 0;
int boundary_count = 0;
int no_binary_diff = 0;
@ -787,6 +772,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.subject_prefix = fmt_patch_subject_prefix;
if (default_attach) {
rev.mime_boundary = default_attach;
rev.no_inline = 1;
}
/*
* Parse the arguments before setup_revisions(), or something
* like "git format-patch -o a123 HEAD^.." may fail; a123 is
@ -833,13 +823,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
else if (!strcmp(argv[i], "--signoff") ||
!strcmp(argv[i], "-s")) {
const char *committer;
const char *endpos;
committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
endpos = strchr(committer, '>');
if (!endpos)
die("bogus committer info %s", committer);
add_signoff = xmemdupz(committer, endpos - committer + 1);
do_signoff = 1;
}
else if (!strcmp(argv[i], "--attach")) {
rev.mime_boundary = git_version_string;
@ -849,6 +833,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.mime_boundary = argv[i] + 9;
rev.no_inline = 1;
}
else if (!strcmp(argv[i], "--no-attach")) {
rev.mime_boundary = NULL;
rev.no_inline = 0;
}
else if (!strcmp(argv[i], "--inline")) {
rev.mime_boundary = git_version_string;
rev.no_inline = 0;
@ -859,8 +847,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
ignore_if_in_upstream = 1;
else if (!strcmp(argv[i], "--thread"))
thread = 1;
else if (!strcmp(argv[i], "--thread")
|| !strcmp(argv[i], "--thread=shallow"))
thread = THREAD_SHALLOW;
else if (!strcmp(argv[i], "--thread=deep"))
thread = THREAD_DEEP;
else if (!strcmp(argv[i], "--no-thread"))
thread = 0;
else if (!prefixcmp(argv[i], "--in-reply-to="))
in_reply_to = argv[i] + 14;
else if (!strcmp(argv[i], "--in-reply-to")) {
@ -877,11 +870,23 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
cover_letter = 1;
else if (!strcmp(argv[i], "--no-binary"))
no_binary_diff = 1;
else if (!prefixcmp(argv[i], "--add-header="))
add_header(argv[i] + 13);
else
argv[j++] = argv[i];
}
argc = j;
if (do_signoff) {
const char *committer;
const char *endpos;
committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
endpos = strchr(committer, '>');
if (!endpos)
die("bogus committer info %s", committer);
add_signoff = xmemdupz(committer, endpos - committer + 1);
}
for (i = 0; i < extra_hdr_nr; i++) {
strbuf_addstr(&buf, extra_hdr[i]);
strbuf_addch(&buf, '\n');
@ -1009,8 +1014,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
numbered = 1;
if (numbered)
rev.total = total + start_number - 1;
if (in_reply_to)
rev.ref_message_id = clean_message_id(in_reply_to);
if (in_reply_to || thread || cover_letter)
rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
if (in_reply_to) {
const char *msgid = clean_message_id(in_reply_to);
string_list_append(msgid, rev.ref_message_ids);
}
rev.numbered_files = numbered_files;
rev.patch_suffix = fmt_patch_suffix;
if (cover_letter) {
if (thread)
gen_message_id(&rev, "cover");
@ -1029,21 +1040,39 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
/* Have we already had a message ID? */
if (rev.message_id) {
/*
* If we've got the ID to be a reply
* to, discard the current ID;
* otherwise, make everything a reply
* to that.
* For deep threading: make every mail
* a reply to the previous one, no
* matter what other options are set.
*
* For shallow threading:
*
* Without --cover-letter and
* --in-reply-to, make every mail a
* reply to the one before.
*
* With --in-reply-to but no
* --cover-letter, make every mail a
* reply to the <reply-to>.
*
* With --cover-letter, make every
* mail but the cover letter a reply
* to the cover letter. The cover
* letter is a reply to the
* --in-reply-to, if specified.
*/
if (rev.ref_message_id)
if (thread == THREAD_SHALLOW
&& rev.ref_message_ids->nr > 0
&& (!cover_letter || rev.nr > 1))
free(rev.message_id);
else
rev.ref_message_id = rev.message_id;
string_list_append(rev.message_id,
rev.ref_message_ids);
}
gen_message_id(&rev, sha1_to_hex(commit->object.sha1));
}
if (!use_stdout && reopen_stdout(numbered_files ? NULL :
get_oneline_for_filename(commit, keep_subject),
rev.nr, rev.total))
if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
&rev))
die("Failed to create output files");
shown = log_tree_commit(&rev, commit);
free(commit->buffer);

View File

@ -10,6 +10,7 @@
#include "dir.h"
#include "builtin.h"
#include "tree.h"
#include "parse-options.h"
static int abbrev;
static int show_deleted;
@ -28,6 +29,7 @@ static const char **pathspec;
static int error_unmatch;
static char *ps_matched;
static const char *with_tree;
static int exc_given;
static const char *tag_cached = "";
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++) {
struct cache_entry *ce = active_cache[i];
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;
if (show_unmerged && !ce_stage(ce))
continue;
@ -189,7 +192,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
struct stat st;
int err;
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;
if (ce->ce_flags & CE_UPDATE)
continue;
@ -374,157 +378,139 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
return errors;
}
static const char ls_files_usage[] =
"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
"[ --exclude-per-directory=<filename> ] [--exclude-standard] "
"[--full-name] [--abbrev] [--] [<file>]*";
static const char * const ls_files_usage[] = {
"git ls-files [options] [<file>]*",
NULL
};
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 i;
int exc_given = 0, require_work_tree = 0;
int require_work_tree = 0, show_tag = 0;
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));
if (prefix)
prefix_offset = strlen(prefix);
git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--")) {
i++;
break;
}
if (!strcmp(arg, "-z")) {
line_terminator = 0;
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;
require_work_tree = 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;
argc = parse_options(argc, argv, builtin_ls_files_options,
ls_files_usage, 0);
if (show_tag || show_valid_bit) {
tag_cached = "H ";
tag_unmerged = "M ";
tag_removed = "R ";
tag_modified = "C ";
tag_other = "? ";
tag_killed = "K ";
}
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())
setup_work_tree();
pathspec = get_pathspec(prefix, argv + i);
pathspec = get_pathspec(prefix, argv);
/* be nice with submodule patsh ending in a slash */
read_cache();
@ -543,7 +529,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
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",
argv[0]);
exit(1);

View File

@ -60,7 +60,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
{
int retval = 0;
const char *type = blob_type;
unsigned long size;
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_SHOW_SIZE) {
char size_text[24];
if (!strcmp(type, blob_type)) {
sha1_object_info(sha1, &size);
printf("%06o %s %s %7lu\t", mode, type,
abbrev ? find_unique_abbrev(sha1, abbrev)
: sha1_to_hex(sha1),
size);
unsigned long size;
if (sha1_object_info(sha1, &size) == OBJ_BAD)
strcpy(size_text, "BAD");
else
snprintf(size_text, sizeof(size_text),
"%lu", size);
} else
printf("%06o %s %s %7c\t", mode, type,
abbrev ? find_unique_abbrev(sha1, abbrev)
: sha1_to_hex(sha1),
'-');
strcpy(size_text, "-");
printf("%06o %s %s %7s\t", mode, type,
abbrev ? find_unique_abbrev(sha1, abbrev)
: sha1_to_hex(sha1),
size_text);
} else
printf("%06o %s %s\t", mode, type,
abbrev ? find_unique_abbrev(sha1, abbrev)

View File

@ -537,7 +537,6 @@ static int decode_header_bq(struct strbuf *it)
*/
strbuf_add(&outbuf, in, ep - in);
}
in = ep;
}
/* E.g.
* ep : "=?iso-2022-jp?B?GyR...?= foo"

View File

@ -360,9 +360,8 @@ static void merge_name(const char *remote, struct strbuf *msg)
const char *ptr;
int len, early;
len = strlen(remote);
if (interpret_nth_last_branch(remote, &bname) == len)
remote = bname.buf;
strbuf_branchname(&bname, remote);
remote = bname.buf;
memset(branch_head, 0, sizeof(branch_head));
remote_head = peel_to_type(remote, 0, NULL, OBJ_COMMIT);
@ -636,7 +635,7 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
memset(&opts, 0, sizeof(opts));
memset(&t, 0, sizeof(t));
memset(&dir, 0, sizeof(dir));
dir.show_ignored = 1;
dir.flags |= DIR_SHOW_IGNORED;
dir.exclude_per_dir = ".gitignore";
opts.dir = &dir;

View File

@ -1612,7 +1612,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
return;
}
if (progress > pack_to_stdout)
fprintf(stderr, "Delta compression using %d threads.\n",
fprintf(stderr, "Delta compression using up to %d threads.\n",
delta_search_threads);
/* Partition the work amongst work threads. */
@ -1901,17 +1901,19 @@ static void read_object_list_from_stdin(void)
#define OBJECT_ADDED (1u<<20)
static void show_commit(struct commit *commit)
static void show_commit(struct commit *commit, void *data)
{
add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
commit->object.flags |= OBJECT_ADDED;
}
static void show_object(struct object_array_entry *p)
static void show_object(struct object_array_entry *p, void *data)
{
add_preferred_base_object(p->name);
add_object_entry(p->item->sha1, p->item->type, p->name, 0);
p->item->flags |= OBJECT_ADDED;
free((char *)p->name);
p->name = NULL;
}
static void show_edge(struct commit *commit)
@ -1966,11 +1968,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
const unsigned char *sha1;
struct object *o;
for (i = 0; i < revs->num_ignore_packed; i++) {
if (matches_pack_name(p, revs->ignore_packed[i]))
break;
}
if (revs->num_ignore_packed <= i)
if (!p->pack_local || p->pack_keep)
continue;
if (open_pack_index(p))
die("cannot open pack index");
@ -1999,6 +1997,29 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
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)
{
struct packed_git *p;
@ -2006,11 +2027,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
const unsigned char *sha1;
for (p = packed_git; p; p = p->next) {
for (i = 0; i < revs->num_ignore_packed; i++) {
if (matches_pack_name(p, revs->ignore_packed[i]))
break;
}
if (revs->num_ignore_packed <= i)
if (!p->pack_local || p->pack_keep)
continue;
if (open_pack_index(p))
@ -2018,7 +2035,8 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
for (i = 0; i < p->num_objects; 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))
die("unable to force loose object");
}
@ -2055,7 +2073,7 @@ static void get_object_list(int ac, const char **av)
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
mark_edges_uninteresting(revs.commits, &revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object);
traverse_commit_list(&revs, show_commit, show_object, NULL);
if (keep_unreachable)
add_objects_in_unpacked_packs(&revs);
@ -2208,7 +2226,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp("--unpacked", arg) ||
!prefixcmp(arg, "--unpacked=") ||
!strcmp("--reflog", arg) ||
!strcmp("--all", arg)) {
use_internal_rev_list = 1;

View File

@ -23,7 +23,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
memcpy(hex+2, de->d_name, 38);
if (get_sha1_hex(hex, sha1))
continue;
if (!has_sha1_pack(sha1, NULL))
if (!has_sha1_pack(sha1))
continue;
memcpy(pathname + len, de->d_name, 38);
if (opts & DRY_RUN)

View File

@ -48,6 +48,71 @@ 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)
{
int i, errs;
@ -79,11 +144,12 @@ static int do_push(const char *repo, int flags)
return error("--all and --mirror are incompatible");
}
if (!refspec
&& !(flags & TRANSPORT_PUSH_ALL)
&& remote->push_refspec_nr) {
refspec = remote->push_refspec;
refspec_nr = remote->push_refspec_nr;
if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
if (remote->push_refspec_nr) {
refspec = remote->push_refspec;
refspec_nr = remote->push_refspec_nr;
} else if (!(flags & TRANSPORT_PUSH_MIRROR))
setup_default_push_refspecs();
}
errs = 0;
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.");
dir = xcalloc(1, sizeof(*opts.dir));
dir->show_ignored = 1;
dir->flags |= DIR_SHOW_IGNORED;
dir->exclude_per_dir = arg + 24;
opts.dir = dir;
/* We do not need to nor want to do read-directory

View File

@ -675,7 +675,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
setup_path();
if (!enter_repo(dir, 0))
die("'%s': unable to chdir or not a git archive", dir);
die("'%s' does not appear to be a git repository", dir);
if (is_repository_shallow())
die("attempt to push into a shallow repository");

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