Merge branch 'master' into sb/opt-filename

* master: (654 commits)
  http-push.c::remove_locks(): fix use after free
  t/t3400-rebase.sh: add more tests to help migrating git-rebase.sh to C
  post-receive-email: hooks.showrev: show how to include both web link and patch
  MinGW: Fix compiler warning in merge-recursive
  MinGW: Add a simple getpass()
  MinGW: use POSIX signature of waitpid()
  MinGW: the path separator to split GITPERLLIB is ';' on Win32
  MinGW: Scan for \r in addition to \n when reading shbang lines
  gitweb: Sanitize title attribute in format_subject_html
  Terminate argv with NULL before calling setup_revisions()
  doc/git-rebase.txt: remove mention of multiple strategies
  git-send-email: Handle quotes when parsing .mailrc files
  git-svn: add --authors-prog option
  git-svn: Set svn.authorsfile if it is passed to git svn clone
  git-svn: Correctly report max revision when following deleted paths
  git-svn: Fix for svn paths removed > log-window-size revisions ago
  git-svn testsuite: use standard configuration for Subversion tools
  grep: fix word-regexp colouring
  completion: use git rev-parse to detect bare repos
  Cope better with a _lot_ of packs
  ...
This commit is contained in:
Junio C Hamano 2009-05-25 00:59:07 -07:00
Родитель 4c8d4c14c6 9619ff1415
Коммит ee969693c5
448 изменённых файлов: 16245 добавлений и 6362 удалений

4
.gitignore поставляемый
Просмотреть файл

@ -11,6 +11,7 @@ git-apply
git-archimport
git-archive
git-bisect
git-bisect--helper
git-blame
git-branch
git-bundle
@ -35,6 +36,8 @@ git-diff
git-diff-files
git-diff-index
git-diff-tree
git-difftool
git-difftool--helper
git-describe
git-fast-export
git-fast-import
@ -78,6 +81,7 @@ git-merge-recursive
git-merge-resolve
git-merge-subtree
git-mergetool
git-mergetool--lib
git-mktag
git-mktree
git-name-rev

Просмотреть файл

@ -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.

Просмотреть файл

@ -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) $(ASCIIDOC_EXTRA) -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) $(ASCIIDOC_EXTRA) -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) $(ASCIIDOC_EXTRA) -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

Просмотреть файл

@ -0,0 +1,10 @@
GIT v1.6.3.1 Release Notes
==========================
Fixes since v1.6.3
------------------
* "git checkout -b new-branch" with a staged change in the index
incorrectly primed the in-index cache-tree, resulting a wrong tree
object to be written out of the index. This is a grave regression
since the last 1.6.2.X maintenance release.

Просмотреть файл

@ -0,0 +1,182 @@
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.
* git-gui updates, including an update to Russian translation, and a
fix to an infinite loop when showing an empty diff.
* gitk updates, including an update to Russian translation and improved Windows
support.
(performance)
* many uses of lstat(2) in the codepath for "git checkout" have been
optimized out.
(usability, bells and whistles)
* Boolean configuration variable yes/no can be written as on/off.
* 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".
* "--graph" to the "git log" family can draw the commit ancestry graph
in colors.
* 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.
* @{-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-archive takes attributes from the tree being archived; strictly
speaking, this is an incompatible behaviour change, but is a good one.
Use --worktree-attributes option to allow it to read attributes from
the work tree as before (deprecated git-tar tree command always reads
attributes from the work tree).
* 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-difftool is now part of the officially supported command, primarily
maintained by David Aguilar.
* 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.
* Support for building and testing a subset of git on a system without a
working perl has been improved.
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.
* "git-apply" rejected a patch that swaps two files (i.e. renames A to B
and B to A at the same time). May need to be backported by cherry
picking d8c81df and then 7fac0ee).
* The initial checkout did not read the attributes from the .gitattribute
file that is being checked out.
* git-gc spent excessive amount of time to decide if an object appears
in a locally existing pack (if needed, backport by merging 69e020a).

Просмотреть файл

@ -0,0 +1,59 @@
GIT v1.6.4 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.3
--------------------
(subsystems)
(performance)
(usability, bells and whistles)
(developers)
Fixes since v1.6.3
------------------
All of the fixes in v1.6.3.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.3.X series.
---
exec >/var/tmp/1
echo O=$(git describe master)
O=v1.6.3
git shortlog --no-merges $O..master ^maint

Просмотреть файл

@ -6,9 +6,13 @@ Checklist (and a short version for the impatient):
- check for unnecessary whitespace with "git diff --check"
before committing
- do not check in commented out code or unneeded files
- provide a meaningful commit message
- the first line of the commit message should be a short
description and should skip the full stop
- the body should provide a meaningful commit message, which:
- uses the imperative, present tense: "change",
not "changed" or "changes".
- includes motivation for the change, and contrasts
its implementation with previous behaviour
- if you want your work included in git.git, add a
"Signed-off-by: Your Name <you@example.com>" line to the
commit message (or just use the option "-s" when
@ -62,6 +66,14 @@ Describe the technical detail of the change(s).
If your description starts to get too long, that's a sign that you
probably need to split up your commit to finer grained pieces.
That being said, patches which plainly describe the things that
help reviewers check the patch, and future maintainers understand
the code, are the most beautiful patches. Descriptions that summarise
the point in the subject well, and describe the motivation for the
change, the approach taken by the change, and if relevant how this
differs substantially from the prior version, can be found on Usenet
archives back into the late 80's. Consider it like good Netiquette,
but for code.
Oh, another thing. I am picky about whitespaces. Make sure your
changes do not trigger errors with the sample pre-commit hook shipped
@ -491,6 +503,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 +521,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 +534,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!

Просмотреть файл

@ -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[]

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -2,15 +2,15 @@ CONFIGURATION FILE
------------------
The git configuration file contains a number of variables that affect
the git command's behavior. `.git/config` file for each repository
is used to store the information for that repository, and
`$HOME/.gitconfig` is used to store per user information to give
fallback values for `.git/config` file. The file `/etc/gitconfig`
can be used to store system-wide defaults.
the git command's behavior. The `.git/config` file in each repository
is used to store the configuration for that repository, and
`$HOME/.gitconfig` is used to store a per-user configuration as
fallback values for the `.git/config` file. The file `/etc/gitconfig`
can be used to store a system-wide default configuration.
They can be used by both the git plumbing
and the porcelains. The variables are divided into sections, where
in the fully qualified variable name the variable itself is the last
The configuration variables are used by both the git plumbing
and the porcelains. The variables are divided into sections, wherein
the fully qualified variable name of the variable itself is the last
dot-separated segment and the section name is everything before the last
dot. The variable names are case-insensitive and only alphanumeric
characters are allowed. Some variables may appear multiple times.
@ -25,35 +25,35 @@ 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
must belong to some section, which means that there must be section
header before first setting of a variable.
characters, `-` and `.` are allowed in section names. Each variable
must belong to some section, which means that there must be a section
header before the first setting of a variable.
Sections can be further divided into subsections. To begin a subsection
put its name in double quotes, separated by space from the section name,
in the section header, like in example below:
in the section header, like in the example below:
--------
[section "subsection"]
--------
Subsection names can contain any characters except newline (doublequote
'`"`' and backslash have to be escaped as '`\"`' and '`\\`',
respectively) and are case sensitive. Section header cannot span multiple
Subsection names are case sensitive and can contain any characters except
newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`,
respectively). Section headers 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
don't need to.
There is also (case insensitive) alternative `[section.subsection]` syntax.
In this syntax subsection names follow the same restrictions as for section
name.
There is also a case insensitive alternative `[section.subsection]` syntax.
In this syntax, subsection names follow the same restrictions as for section
names.
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.
@ -61,26 +61,26 @@ Internal whitespace within a variable value is retained verbatim.
The values following the equals sign in variable assign are all either
a string, an integer, or a boolean. Boolean values may be given as yes/no,
0/1 or true/false. Case is not significant in boolean values, when
0/1, true/false or on/off. Case is not significant in boolean values, when
converting value to the canonical form using '--bool' type specifier;
'git-config' will ensure that the output is "true" or "false".
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 '`\`'.
You need to enclose variable values in double quotes if you want to
preserve leading or trailing whitespace, or if the variable value contains
comment characters (i.e. it contains '#' or ';').
Double quote `"` and backslash `\` characters in variable values 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 values ending in a `\` are continued on the next line in the
customary UNIX fashion.
Some variables may require special value format.
Some variables may require a special value format.
Example
~~~~~~~
@ -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
@ -384,9 +389,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
@ -424,6 +429,15 @@ relatively high IO latencies. With this set to 'true', git will do the
index comparison to the filesystem data in parallel, allowing
overlapping IO's.
core.createObject::
You can set this to 'link', in which case a hardlink followed by
a delete of the source are used to make sure that object creation
will not overwrite existing objects.
+
On some file system/operating system combinations, this is unreliable.
Set this config setting to 'rename' there; However, This will remove the
check that makes sure that existing object files will not get overwritten.
alias.*::
Command aliases for the linkgit:git[1] command wrapper - e.g.
after defining "alias.last = cat-file commit HEAD", the invocation
@ -470,10 +484,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
@ -550,6 +568,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").
@ -567,6 +604,12 @@ color.pager::
A boolean to enable/disable colored output when the pager is in
use (default is true).
color.showbranch::
A boolean to enable/disable color in the output of
linkgit:git-show-branch[1]. May be set to `always`,
`false` (or `never`) or `auto` (or `true`), in which case colors are used
only when the output is to a terminal. Defaults to false.
color.status::
A boolean to enable/disable color in the output of
linkgit:git-status[1]. May be set to `always`,
@ -641,6 +684,27 @@ diff.suppressBlankEmpty::
A boolean to inhibit the standard behavior of printing a space
before each empty output line. Defaults to false.
diff.tool::
Controls which diff tool is used. `diff.tool` overrides
`merge.tool` when used by linkgit:git-difftool[1] and has
the same valid values as `merge.tool` minus "tortoisemerge"
and plus "kompare".
difftool.<tool>.path::
Override the path for the given tool. This is useful in case
your tool is not in the PATH.
difftool.<tool>.cmd::
Specify the command to invoke the specified diff tool.
The specified command is evaluated in shell with the following
variables available: 'LOCAL' is set to the name of the temporary
file containing the contents of the diff pre-image and 'REMOTE'
is set to the name of the temporary file containing the contents
of the diff post-image.
difftool.prompt::
Prompt before each invocation of the diff tool.
diff.wordRegex::
A POSIX Extended Regular Expression used to determine what is a "word"
when performing word-by-word difference calculations. Character
@ -658,6 +722,13 @@ fetch.unpackLimit::
especially on slow filesystems. If not set, the value of
`transfer.unpackLimit` is used instead.
format.attach::
Enable multipart/mixed attachments as the default for
'format-patch'. The value can also be a double quoted string
which will enable attachments as the default and set the
value as the boundary. See the --attach option in
linkgit:git-format-patch[1].
format.numbered::
A boolean which can enable or disable sequence numbers in patch
subjects. It defaults to "auto" which enables it only if there
@ -669,6 +740,14 @@ format.headers::
Additional email headers to include in a patch to be submitted
by mail. See linkgit:git-format-patch[1].
format.cc::
Additional "Cc:" headers to include in a patch to be submitted
by mail. See the --cc option in linkgit:git-format-patch[1].
format.subjectprefix::
The default for format-patch is to output files with the '[PATCH]'
subject prefix. Use this variable to change that prefix.
format.suffix::
The default for format-patch is to output files with the suffix
`.patch`. Use this variable to change that suffix (make sure to
@ -679,6 +758,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
@ -1153,7 +1249,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
@ -1162,6 +1258,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

Просмотреть файл

@ -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 {

Просмотреть файл

@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
[--all | [--update | -u]] [--intent-to-add | -N]
[--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
[--refresh] [--ignore-errors] [--] <filepattern>...
DESCRIPTION
@ -76,6 +76,15 @@ OPTIONS
bypassed and the 'patch' subcommand is invoked using each of
the specified filepatterns before exiting.
-e, \--edit::
Open the diff vs. the index in an editor and let the user
edit it. After the editor was closed, adjust the hunk headers
and apply the patch to the index.
+
*NOTE*: Obviously, if you change anything else than the first character
on lines beginning with a space or a minus, the patch will no longer
apply.
-u::
--update::
Update only files that git already knows about, staging modified

Просмотреть файл

@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
[--output=<file>] [--worktree-attributes]
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
[path...]
@ -47,6 +48,12 @@ OPTIONS
--prefix=<prefix>/::
Prepend <prefix>/ to each filename in the archive.
--output=<file>::
Write the archive to <file> instead of stdout.
--worktree-attributes::
Look for attributes in .gitattributes in working directory too.
<extra>::
This can be any options that the archiver backend understands.
See next section.

Просмотреть файл

@ -217,7 +217,7 @@ If you have a script that can tell if the current source code is good
or bad, you can bisect by issuing the command:
------------
$ git bisect run my_script
$ git bisect run my_script arguments
------------
Note that the script (`my_script` in the above example) should
@ -257,6 +257,13 @@ $ 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:
+
------------
@ -296,6 +303,15 @@ 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
------
Written by Linus Torvalds <torvalds@osdl.org>

Просмотреть файл

@ -76,8 +76,8 @@ 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.
@ -100,7 +100,9 @@ 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 the sha1's minimum display length in the output listing.
@ -109,20 +111,24 @@ OPTIONS
--no-abbrev::
Display the full sha1s in the output listing rather than abbreviating them.
-t::
--track::
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 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
'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.
When creating a new branch, set up configuration to mark the
start-point branch as "upstream" from the new branch. This
configuration will tell git to show the relationship between the
two branches in `git status` and `git branch -v`. Furthermore,
it directs `git pull` without arguments to pull from the
upstream when the new branch is checked out.
+
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 given. Set it to `always` if you want this behavior when the
start-point is either a local or remote branch.
--no-track::
Ignore the branch.autosetupmerge configuration variable.
Do not set up "upstream" configuration, even if the
branch.autosetupmerge configuration variable is true.
--contains <commit>::
Only list branches which contain the specified commit.

Просмотреть файл

@ -7,7 +7,9 @@ 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
-----------
@ -23,6 +25,10 @@ imposes the following rules on how references are named:
grouping, but no slash-separated component can begin with a
dot `.`.
. They must contain at least one `/`. This enforces the presence of a
category like `heads/`, `tags/` etc. but the actual names are not
restricted.
. They cannot have two consecutive dots `..` anywhere.
. They cannot have ASCII control characters (i.e. bytes whose
@ -30,7 +36,13 @@ imposes the following rules on how references are named:
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
or open bracket `[` anywhere.
. They cannot end with a slash `/`.
. They cannot end with a slash `/` nor a dot `.`.
. They cannot end with the sequence `.lock`.
. They cannot contain a sequence `@{`.
- They cannot contain a `\\`.
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
@ -49,6 +61,18 @@ reference name expressions (see linkgit:git-rev-parse[1]):
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
---

Просмотреть файл

@ -8,28 +8,28 @@ 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] [-m] [<branch>]
'git checkout' [-q] [-f] [-m] [-b <new_branch>] [<start_point>]
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
DESCRIPTION
-----------
When <paths> are not given, this command switches branches by
updating the index and working tree to reflect the specified
branch, <branch>, and updating HEAD to be <branch> or, if
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`.
updating the index, working tree, and HEAD to reflect the specified
branch.
As a convenience, --track will default to create a branch whose
name is constructed from the specified branch name by stripping
the first namespace level.
If `-b` is given, a new branch is created and checked out, as if
linkgit:git-branch[1] were called; in this case you can
use the --track or --no-track options, which will be passed to `git
branch`. As a convenience, --track without `-b` implies branch
creation; see the description of --track below.
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.
@ -62,27 +62,16 @@ entries; instead, unmerged entries are ignored.
-b::
Create a new branch named <new_branch> and start it at
<branch>. The new branch name must pass all checks defined
by linkgit:git-check-ref-format[1]. Some of these checks
may restrict the characters allowed in a branch name.
<start_point>; see linkgit:git-branch[1] for details.
-t::
--track::
When creating a new branch, set up 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
<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
given. Set it to `always` if you want this behavior when the
start-point is either a local or remote branch.
When creating a new branch, set up "upstream" configuration. See
"--track" in linkgit:git-branch[1] for details.
+
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
@ -91,12 +80,12 @@ guessing results in an empty name, the guessing is aborted. You can
explicitly give a name with '-b' in such a case.
--no-track::
Ignore the branch.autosetupmerge configuration variable.
Do not set up "upstream" configuration, even if the
branch.autosetupmerge configuration variable is true.
-l::
Create the new branch's reflog. This activates recording of
all changes made to the branch ref, enabling use of date
based sha1 expressions such as "<branchname>@\{yesterday}".
Create the new branch's reflog; see linkgit:git-branch[1] for
details.
-m::
--merge::
@ -124,23 +113,28 @@ the conflicted merge in the specified paths.
"merge" (default) and "diff3" (in addition to what is shown by
"merge" style, shows the original contents).
<branch>::
Branch to checkout; if it refers to a branch (i.e., a name that,
when prepended with "refs/heads/", is a valid ref), then that
branch is checked out. Otherwise, if it refers to a valid
commit, your HEAD becomes "detached" and you are no longer on
any branch (see below for details).
+
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\}"`.
<new_branch>::
Name for the new branch.
<start_point>::
The name of a commit at which to start the new branch; see
linkgit:git-branch[1] for details. Defaults to HEAD.
<tree-ish>::
Tree to checkout from (when paths are given). If not specified,
the index will be used.
<branch>::
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
checks out the branch (instead of detaching). You may also specify
"`-`" which is synonymous with "`@\{-1\}`".
Detached HEAD
@ -156,12 +150,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
@ -206,7 +200,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:
+
------------
@ -214,7 +208,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:
+
------------

Просмотреть файл

@ -12,14 +12,17 @@ SYNOPSIS
DESCRIPTION
-----------
Removes files unknown to git. This allows to clean the working tree
from files that are not under version control. If the '-x' option is
specified, ignored files are also removed, allowing to remove all
build products.
Cleans the working tree by recursively removing files that are not
under version control, starting from the current directory.
Normally, only files unknown to git are removed, but if the '-x'
option is specified, ignored files are also removed. This can, for
example, be useful to remove all build products.
If any optional `<path>...` arguments are given, only those paths
are affected.
OPTIONS
-------
-d::

Просмотреть файл

@ -149,7 +149,7 @@ then the cloned repository will become corrupt.
part of the source repository is used if no directory is
explicitly given ("repo" for "/path/to/repo.git" and "foo"
for "host.xz:foo/.git"). Cloning into an existing directory
is not allowed.
is only allowed if the directory is empty.
:git-clone: 1
include::urls.txt[]

Просмотреть файл

@ -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
-----------
@ -68,7 +69,8 @@ OPTIONS
--add::
Adds a new line to the option without altering any existing
values. This is the same as providing '^$' as the value_regex.
values. This is the same as providing '^$' as the value_regex
in `--replace-all`.
--get::
Get the value for a given key (optionally filtered by a regex
@ -154,13 +156,18 @@ See also <<FILES>>.
When the color setting for `name` is undefined, the command uses
`color.ui` as fallback.
--get-color name default::
--get-color name [default]::
Find the color configured for `name` (e.g. `color.diff.new`) and
output it as the ANSI color escape sequence to the standard
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
-----

Просмотреть файл

@ -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
@ -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 practice:
* cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
* parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
Author
------

Просмотреть файл

@ -3,52 +3,54 @@ git-difftool(1)
NAME
----
git-difftool - compare changes using common merge tools
git-difftool - Show changes using common diff tools
SYNOPSIS
--------
'git difftool' [--tool=<tool>] [--no-prompt] ['git diff' options]
'git difftool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<'git diff' options>]
DESCRIPTION
-----------
'git-difftool' is a git command that allows you to compare and edit files
between revisions using common merge tools. At its most basic level,
'git-difftool' does what 'git-mergetool' does but its use is for non-merge
situations such as when preparing commits or comparing changes against
the index.
'git difftool' is a frontend to 'git diff' and accepts the same
arguments and options.
See linkgit:git-diff[1] for the full list of supported options.
between revisions using common diff tools. 'git difftool' is a frontend
to 'git-diff' and accepts the same options and arguments.
OPTIONS
-------
-y::
--no-prompt::
Do not prompt before launching a diff tool.
--prompt::
Prompt before each invocation of the diff tool.
This is the default behaviour; the option is provided to
override any configuration settings.
-t <tool>::
--tool=<tool>::
Use the merge resolution program specified by <tool>.
Use the diff tool specified by <tool>.
Valid merge tools are:
kdiff3, kompare, tkdiff, meld, xxdiff, emerge,
vimdiff, gvimdiff, ecmerge, and opendiff
kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
ecmerge, diffuse and opendiff
+
If a merge resolution program is not specified, 'git-difftool'
will use the configuration variable `merge.tool`. If the
configuration variable `merge.tool` is not set, 'git difftool'
If a diff tool is not specified, 'git-difftool'
will use the configuration variable `diff.tool`. If the
configuration variable `diff.tool` is not set, 'git-difftool'
will pick a suitable default.
+
You can explicitly provide a full path to the tool by setting the
configuration variable `mergetool.<tool>.path`. For example, you
configuration variable `difftool.<tool>.path`. For example, you
can configure the absolute path to kdiff3 by setting
`mergetool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
`difftool.kdiff3.path`. Otherwise, 'git-difftool' assumes the
tool is available in PATH.
+
Instead of running one of the known merge tool programs,
Instead of running one of the known diff tools,
'git-difftool' can be customized to run an alternative program
by specifying the command line to invoke in a configuration
variable `mergetool.<tool>.cmd`.
variable `difftool.<tool>.cmd`.
+
When 'git-difftool' is invoked with this tool (either through the
`-t` or `--tool` option or the `merge.tool` configuration variable)
`-t` or `--tool` option or the `diff.tool` configuration variable)
the configured command line will be invoked with the following
variables available: `$LOCAL` is set to the name of the temporary
file containing the contents of the diff pre-image and `$REMOTE`
@ -56,29 +58,27 @@ is set to the name of the temporary file containing the contents
of the diff post-image. `$BASE` is provided for compatibility
with custom merge tool commands and has the same value as `$LOCAL`.
--no-prompt::
Do not prompt before launching a diff tool.
See linkgit:git-diff[1] for the full list of supported options.
CONFIG VARIABLES
----------------
merge.tool::
The default merge tool to use.
+
See the `--tool=<tool>` option above for more details.
'git-difftool' falls back to 'git-mergetool' config variables when the
difftool equivalents have not been defined.
merge.keepBackup::
The original, unedited file content can be saved to a file with
a `.orig` extension. Defaults to `true` (i.e. keep the backup files).
diff.tool::
The default diff tool to use.
mergetool.<tool>.path::
difftool.<tool>.path::
Override the path for the given tool. This is useful in case
your tool is not in the PATH.
mergetool.<tool>.cmd::
Specify the command to invoke the specified merge tool.
difftool.<tool>.cmd::
Specify the command to invoke the specified diff tool.
+
See the `--tool=<tool>` option above for more details.
difftool.prompt::
Prompt before each invocation of the diff tool.
SEE ALSO
--------

Просмотреть файл

@ -94,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.
@ -207,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:

Просмотреть файл

@ -75,6 +75,8 @@ For all objects, the following names can be used:
refname::
The name of the ref (the part after $GIT_DIR/).
For a non-ambiguous short name of the ref append `:short`.
The option core.warnAmbiguousRefs is used to select the strict
abbreviation mode.
objecttype::
The type of the object (`blob`, `tree`, `commit`, `tag`).
@ -85,6 +87,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.

Просмотреть файл

@ -9,9 +9,10 @@ git-format-patch - Prepare patches for e-mail submission
SYNOPSIS
--------
[verse]
'git format-patch' [-k] [-o <dir> | --stdout] [--thread]
[--attach[=<boundary>] | --inline[=<boundary>]]
[-s | --signoff] [<common diff options>]
'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout]
[--thread[=<style>]]
[(--attach|--inline)[=<boundary>] | --no-attach]
[-s | --signoff]
[-n | --numbered | -N | --no-numbered]
[--start-number <n>] [--numbered-files]
[--in-reply-to=Message-Id] [--suffix=.<sfx>]
@ -19,6 +20,7 @@ SYNOPSIS
[--subject-prefix=Subject-Prefix]
[--cc=<email>]
[--cover-letter]
[<common diff options>]
[ <since> | <revision range> ]
DESCRIPTION
@ -112,15 +114,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
@ -144,6 +158,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
@ -152,18 +171,17 @@ include::diff-options.txt[]
--suffix=.<sfx>::
Instead of using `.patch` as the suffix for generated
filenames, use specified suffix. A common alternative is
`--suffix=.txt`.
`--suffix=.txt`. Leaving this empty will remove the `.patch`
suffix.
+
Note that you would need to include the leading dot `.` if you
want a filename like `0001-description-of-my-change.patch`, and
the first letter does not have to be a dot. Leaving it empty would
not add any suffix.
Note that the leading character does not have to be a dot; for example,
you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
--no-binary::
Don't output contents of changes in binary files, just take note
that they differ. Note that this disable the patch to be properly
applied. By default the contents of changes in those files are
encoded in the patch.
Do not output contents of changes in binary files, instead
display a notice that those files changed. Patches generated
using this option cannot be applied properly, but they are
still useful for code review.
--root::
Treat the revision argument as a <revision range>, even if it
@ -174,9 +192,10 @@ not add any suffix.
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.
You can specify extra mail header lines to be added to each message,
defaults for the subject prefix and file suffix, number patches when
outputting more than one patch, add "Cc:" headers, configure attachments,
and sign off patches with configuration variables.
------------
[format]
@ -185,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
------------
@ -222,8 +243,8 @@ $ git format-patch -M -B origin
+
Additionally, it detects and handles renames and complete rewrites
intelligently to produce a renaming patch. A renaming patch reduces
the amount of text output, and generally makes it easier to review it.
Note that the "patch" program does not understand renaming patches, so
the amount of text output, and generally makes it easier to review.
Note that non-git "patch" programs won't understand renaming patches, so
use it only when you know the recipient uses git to apply your patch.
* Extract three topmost commits from the current branch and format them

Просмотреть файл

@ -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

Просмотреть файл

@ -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
~~~~~~~~

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,54 @@
git-mergetool--lib(1)
=====================
NAME
----
git-mergetool--lib - Common git merge tool shell scriptlets
SYNOPSIS
--------
'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool--lib"'
DESCRIPTION
-----------
This is not a command the end user would want to run. Ever.
This documentation is meant for people who are studying the
Porcelain-ish scripts and/or are writing new ones.
The 'git-mergetool--lib' scriptlet is designed to be sourced (using
`.`) by other shell scripts to set up functions for working
with git merge tools.
Before sourcing 'git-mergetool--lib', your script must set `TOOL_MODE`
to define the operation mode for the functions listed below.
'diff' and 'merge' are valid values.
FUNCTIONS
---------
get_merge_tool::
returns a merge tool.
get_merge_tool_cmd::
returns the custom command for a merge tool.
get_merge_tool_path::
returns the custom path for a merge tool.
run_merge_tool::
launches a merge tool given the tool name and a true/false
flag to indicate whether a merge base is present.
'$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
for use by the merge tool.
Author
------
Written by David Aguilar <davvid@gmail.com>
Documentation
--------------
Documentation by David Aguilar and the git-list <git@vger.kernel.org>.
GIT
---
Part of the linkgit:git[1] suite

Просмотреть файл

@ -26,7 +26,8 @@ OPTIONS
--tool=<tool>::
Use the merge resolution program specified by <tool>.
Valid merge tools are:
kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, and opendiff
kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge,
diffuse, tortoisemerge and opendiff
+
If a merge resolution program is not specified, 'git-mergetool'
will use the configuration variable `merge.tool`. If the

Просмотреть файл

@ -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.

Просмотреть файл

@ -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

Просмотреть файл

@ -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>::
@ -224,15 +231,22 @@ OPTIONS
-s <strategy>::
--strategy=<strategy>::
Use the given merge strategy; can be supplied more than
once to specify them in the order they should be tried.
Use the given merge strategy.
If there is no `-s` option, a built-in list of strategies
is used instead ('git-merge-recursive' when merging a single
head, 'git-merge-octopus' otherwise). This implies --merge.
-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 +257,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

Просмотреть файл

@ -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

Просмотреть файл

@ -26,10 +26,15 @@ OPTIONS
--parseopt::
Use 'git-rev-parse' in option parsing mode (see PARSEOPT section below).
--keep-dash-dash::
--keep-dashdash::
Only meaningful in `--parseopt` mode. Tells the option parser to echo
out the first `--` met instead of skipping it.
--sq-quote::
Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE
section below). In contrast to the `--sq` option below, this
mode does only quoting. Nothing else is done to command input.
--revs-only::
Do not output flags and parameters not meant for
'git-rev-list' command.
@ -64,7 +69,8 @@ OPTIONS
properly quoted for consumption by shell. Useful when
you expect your parameter to contain whitespaces and
newlines (e.g. when using pickaxe `-S` with
'git-diff-\*').
'git-diff-\*'). In contrast to the `--sq-quote` option,
the command input is still interpreted as usual.
--not::
When showing object names, prefix them with '{caret}' and
@ -84,6 +90,11 @@ OPTIONS
unfortunately named tag "master"), and show them as full
refnames (e.g. "refs/heads/master").
--abbrev-ref[={strict|loose}]::
A non-ambiguous short name of the objects name.
The option core.warnAmbiguousRefs is used to select the strict
abbreviation mode.
--all::
Show all refs found in `$GIT_DIR/refs`.
@ -299,18 +310,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.
@ -401,6 +412,33 @@ C? option C with an optional argument"
eval `echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?`
------------
SQ-QUOTE
--------
In `--sq-quote` mode, 'git-rev-parse' echoes on the standard output a
single line suitable for `sh(1)` `eval`. This line is made by
normalizing the arguments following `--sq-quote`. Nothing other than
quoting the arguments is done.
If you want command input to still be interpreted as usual by
'git-rev-parse' before the output is shell quoted, see the `--sq`
option.
Example
~~~~~~~
------------
$ cat >your-git-script.sh <<\EOF
#!/bin/sh
args=$(git rev-parse --sq-quote "$@") # quote user-supplied arguments
command="git frotz -n24 $args" # and use it inside a handcrafted
# command line
eval "$command"
EOF
$ sh your-git-script.sh "a b'c"
------------
EXAMPLES
--------

Просмотреть файл

@ -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,35 @@ 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::
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.
--from=<address>::
Specify the sender of the emails. If not specified on the command line,
the value of the 'sendemail.from' configuration option is used. If
neither the command line option nor 'sendemail.from' are set, then the
user will be prompted for the value. The default for the prompt will be
the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not
set, as returned by "git var -l".
--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 +100,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 +108,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 +125,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 +135,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 +143,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 +152,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 +166,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 +177,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 +214,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.
@ -247,7 +265,7 @@ sendemail.aliasesfile::
sendemail.aliasfiletype::
Format of the file(s) specified in sendemail.aliasesfile. Must be
one of 'mutt', 'mailrc', 'pine', or 'gnus'.
one of 'mutt', 'mailrc', 'pine', 'elm', or 'gnus'.
sendemail.multiedit::
If true (default), a single editor instance will be spawned to edit
@ -255,6 +273,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
------

Просмотреть файл

@ -18,9 +18,9 @@ of server-side GIT commands implementing the pull/push functionality.
The commands can be executed only by the '-c' option; the shell is not
interactive.
Currently, only three commands are permitted to be called, 'git-receive-pack'
'git-upload-pack' with a single required argument or 'cvs server' (to invoke
'git-cvsserver').
Currently, only four commands are permitted to be called, 'git-receive-pack'
'git-upload-pack' and 'git-upload-archive' with a single required argument, or
'cvs server' (to invoke 'git-cvsserver').
Author
------

Просмотреть файл

@ -10,6 +10,7 @@ SYNOPSIS
[verse]
'git show-branch' [--all] [--remotes] [--topo-order] [--current]
[--more=<n> | --list | --independent | --merge-base]
[--color | --no-color]
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
@ -107,6 +108,14 @@ OPTIONS
When no explicit <ref> parameter is given, it defaults to the
current branch (or `HEAD` if it is detached).
--color::
Color the status sign (one of these: `*` `!` `+` `-`) of each commit
corresponding to the branch it's in.
--no-color::
Turn off colored output, even when the configuration file gives the
default to color output.
Note that --more, --list, --independent and --merge-base options
are mutually exclusive.
@ -148,9 +157,10 @@ $ git show-branch master fixes mhf
------------------------------------------------
These three branches all forked from a common commit, [master],
whose commit message is "Add 'git show-branch'. "fixes" branch
adds one commit 'Introduce "reset type"'. "mhf" branch has many
other commits. The current branch is "master".
whose commit message is "Add \'git show-branch\'". The "fixes"
branch adds one commit "Introduce "reset type" flag to "git reset"".
The "mhf" branch adds many other commits. The current branch
is "master".
EXAMPLE

Просмотреть файл

@ -9,10 +9,12 @@ git-submodule - Initialize, update or inspect submodules
SYNOPSIS
--------
[verse]
'git submodule' [--quiet] add [-b branch] [--] <repository> <path>
'git submodule' [--quiet] add [-b branch]
[--reference <repository>] [--] <repository> <path>
'git submodule' [--quiet] status [--cached] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch]
[--reference <repository>] [--] [<path>...]
'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
'git submodule' [--quiet] foreach <command>
'git submodule' [--quiet] sync [--] [<path>...]
@ -177,6 +179,14 @@ OPTIONS
This option is only valid for the update command.
Don't fetch new objects from the remote site.
--reference <repository>::
This option is only valid for add and update commands. These
commands sometimes need to clone a remote repository. In this case,
this option will be passed to the linkgit:git-clone[1] command.
+
*NOTE*: Do *not* use this option unless you have read the note
for linkgit:git-clone[1]'s --reference and --shared options carefully.
<path>...::
Paths to submodule(s). When specified this will restrict the command
to only operate on the submodules found at the specified paths.

Просмотреть файл

@ -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
@ -383,9 +398,18 @@ after the authors-file is modified should continue operation.
config key: svn.authorsfile
--authors-prog=<filename>::
If this option is specified, for each SVN committer name that does not
exist in the authors file, the given file is executed with the committer
name as the first argument. The program is expected to return a single
line of the form "Name <email>", which will be treated as if included in
the authors file.
-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,14 +696,14 @@ 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
Keep in mind that the '\*' (asterisk) wildcard of the local ref
(right of the ':') *must* be the farthest right path component;
however the remote wildcard may be anywhere as long as it's own
however the remote wildcard may be anywhere as long as it's an
independent path component (surrounded by '/' or EOL). This
type of configuration is not automatically created by 'init' and
should be manually entered with a text-editor or using 'git-config'.

Просмотреть файл

@ -39,12 +39,6 @@ what they are for:
* info/refs
BUGS
----
When you remove an existing ref, the command fails to update
info/refs file unless `--force` flag is given.
Author
------
Written by Junio C Hamano <gitster@pobox.com>

Просмотреть файл

@ -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,14 @@ 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.3/git.html[documentation for release 1.6.3]
* release notes for
link:RelNotes-1.6.2.5.txt[1.6.2.5],
link:RelNotes-1.6.2.4.txt[1.6.2.4],
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 +182,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).

Просмотреть файл

@ -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

Просмотреть файл

@ -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.

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -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>

Просмотреть файл

@ -22,7 +22,8 @@ merge.stat::
merge.tool::
Controls which merge resolution program is used by
linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3",
"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
"tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff",
"diffuse", "ecmerge", "tortoisemerge", and
"opendiff". Any other value is treated is custom merge tool
and there must be a corresponding mergetool.<tool>.cmd option.

Просмотреть файл

@ -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

Просмотреть файл

@ -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
---------------------

Просмотреть файл

@ -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

Просмотреть файл

@ -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).

Просмотреть файл

@ -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
--------------
@ -109,6 +137,10 @@ There are some macros to easily define options:
Introduce a boolean option.
If used, `int_var` is bitwise-ored with `mask`.
`OPT_NEGBIT(short, long, &int_var, description, mask)`::
Introduce a boolean option.
If used, `int_var` is bitwise-anded with the inverted `mask`.
`OPT_SET_INT(short, long, &int_var, description, integer)`::
Introduce a boolean option.
If used, set `int_var` to `integer`.
@ -138,6 +170,14 @@ There are some macros to easily define options:
`OPT_ARGUMENT(long, description)`::
Introduce a long-option argument that will be kept in `argv[]`.
`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
Recognize numerical options like -123 and feed the integer as
if it was an argument to the function given by `func_ptr`.
The result will be put into `var`. There can be only one such
option definition. It cannot be negated and it takes no
arguments. Short options that happen to be digits take
precedence over it.
The last element of the array must be `OPT_END()`.
@ -170,7 +210,7 @@ The function must be defined in this form:
The callback mechanism is as follows:
* Inside `funct`, the only interesting member of the structure
* Inside `func`, the only interesting member of the structure
given by `opt` is the void pointer `opt->value`.
`\*opt->value` will be the value that is saved into `var`, if you
use `OPT_CALLBACK()`.

Просмотреть файл

@ -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

Просмотреть файл

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

129
Makefile
Просмотреть файл

@ -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
@ -159,6 +167,17 @@ all::
# Define NO_EXTERNAL_GREP if you don't want "git grep" to ever call
# your external grep (e.g., if your system lacks grep, if its grep is
# broken, or spawning external process is slower than built-in grep git has).
#
# Define UNRELIABLE_FSTAT if your system's fstat does not return the same
# information on a not yet closed file that lstat would return for the same
# file after it was closed.
#
# Define OBJECT_CREATION_USES_RENAMES if your operating systems has problems
# when hardlinking a file to another name and unlinking the original file right
# away (some NTFS drivers seem to zero the contents in that scenario).
#
# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
# programs as a tar, where bin/ and libexec/ might be on different file systems.
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@ -209,6 +228,7 @@ ETC_GITCONFIG = etc/gitconfig
endif
lib = lib
# DESTDIR=
pathsep = :
# default configuration for gitweb
GITWEB_CONFIG = gitweb_config.perl
@ -257,14 +277,28 @@ 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-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
SCRIPT_SH += git-lost-found.sh
SCRIPT_SH += git-merge-octopus.sh
SCRIPT_SH += git-merge-one-file.sh
SCRIPT_SH += git-merge-resolve.sh
SCRIPT_SH += git-mergetool.sh
SCRIPT_SH += git-mergetool--lib.sh
SCRIPT_SH += git-parse-remote.sh
SCRIPT_SH += git-pull.sh
SCRIPT_SH += git-quiltimport.sh
@ -278,6 +312,7 @@ SCRIPT_SH += git-submodule.sh
SCRIPT_SH += git-web--browse.sh
SCRIPT_PERL += git-add--interactive.perl
SCRIPT_PERL += git-difftool.perl
SCRIPT_PERL += git-archimport.perl
SCRIPT_PERL += git-cvsexportcommit.perl
SCRIPT_PERL += git-cvsimport.perl
@ -333,7 +368,7 @@ 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
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
@ -412,6 +447,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
@ -512,6 +548,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
@ -655,6 +692,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
@ -704,6 +742,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
@ -714,6 +753,7 @@ endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
NEEDS_LIBICONV = YesPlease
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
@ -726,12 +766,14 @@ ifeq ($(uname_S),NetBSD)
BASIC_CFLAGS += -I/usr/pkg/include
BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
THREADED_DELTA_SEARCH = YesPlease
USE_ST_TIMESPEC = YesPlease
endif
ifeq ($(uname_S),AIX)
NO_STRCASESTR=YesPlease
NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease
NO_STRLCPY = YesPlease
NO_NSEC = YesPlease
FREAD_READS_DIRECTORIES = UnfortunatelyYes
INTERNAL_QSORT = UnfortunatelyYes
NEEDS_LIBICONV=YesPlease
@ -772,9 +814,10 @@ ifeq ($(uname_S),HP-UX)
endif
ifneq (,$(findstring CYGWIN,$(uname_S)))
COMPAT_OBJS += compat/cygwin.o
UNRELIABLE_FSTAT = UnfortunatelyYes
endif
ifneq (,$(findstring MINGW,$(uname_S)))
NO_MMAP = YesPlease
pathsep = ;
NO_PREAD = YesPlease
NO_OPENSSL = YesPlease
NO_CURL = YesPlease
@ -797,6 +840,10 @@ 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
UNRELIABLE_FSTAT = UnfortunatelyYes
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@ -918,6 +965,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
@ -965,6 +1021,14 @@ 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 OBJECT_CREATION_USES_RENAMES
COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1
endif
ifdef NO_PREAD
COMPAT_CFLAGS += -DNO_PREAD
@ -1061,11 +1125,18 @@ endif
ifdef NO_EXTERNAL_GREP
BASIC_CFLAGS += -DNO_EXTERNAL_GREP
endif
ifdef UNRELIABLE_FSTAT
BASIC_CFLAGS += -DUNRELIABLE_FSTAT
endif
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 =
@ -1140,7 +1211,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:
@ -1153,6 +1226,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)
@ -1180,13 +1254,13 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
$@.sh >$@+ && \
chmod +x $@+ && \
mv $@+ $@
ifndef NO_PERL
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
@ -1198,7 +1272,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
sed -e '1{' \
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
-e ' h' \
-e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
-e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
-e ' H' \
-e ' x' \
-e '}' \
@ -1208,6 +1282,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
chmod +x $@+ && \
mv $@+ $@
OTHER_PROGRAMS += gitweb/gitweb.cgi
gitweb/gitweb.cgi: gitweb/gitweb.perl
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
@ -1246,6 +1321,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) $@ $<+ && \
@ -1361,6 +1445,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
@ -1455,17 +1541,20 @@ install: all
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
$(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)'
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
ifndef NO_PERL
$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
endif
ifndef NO_TCLTK
$(MAKE) -C gitk-git install
$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
endif
ifneq (,$X)
$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
{ $(RM) "$$execdir/git-add$X" && \
test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
{ for p in $(filter-out git-add$X,$(BUILT_INS)); do \
@ -1473,7 +1562,7 @@ endif
ln "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git-add$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \
done } && \
done; } && \
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
install-doc:
@ -1563,9 +1652,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
@ -1638,3 +1729,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

Просмотреть файл

@ -1 +1 @@
Documentation/RelNotes-1.6.2.5.txt
Documentation/RelNotes-1.6.4.txt

10
alias.c
Просмотреть файл

@ -27,7 +27,7 @@ int split_cmdline(char *cmdline, const char ***argv)
int src, dst, count = 0, size = 16;
char quoted = 0;
*argv = xmalloc(sizeof(char*) * size);
*argv = xmalloc(sizeof(char *) * size);
/* split alias_string */
(*argv)[count++] = cmdline;
@ -38,10 +38,7 @@ int split_cmdline(char *cmdline, const char ***argv)
while (cmdline[++src]
&& isspace(cmdline[src]))
; /* skip */
if (count >= size) {
size += 16;
*argv = xrealloc(*argv, sizeof(char*) * size);
}
ALLOC_GROW(*argv, count+1, size);
(*argv)[count++] = cmdline + dst;
} else if (!quoted && (c == '\'' || c == '"')) {
quoted = c;
@ -72,6 +69,9 @@ int split_cmdline(char *cmdline, const char ***argv)
return error("unclosed quote");
}
ALLOC_GROW(*argv, count+1, size);
(*argv)[count] = NULL;
return count;
}

Просмотреть файл

@ -57,7 +57,7 @@ DEFINE_ALLOCATOR(object, union any_object)
#define SZ_FMT "%zu"
#endif
static void report(const char* name, unsigned int count, size_t size)
static void report(const char *name, unsigned int count, size_t size)
{
fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size);
}

Просмотреть файл

@ -180,7 +180,7 @@ static int write_tar_entry(struct archiver_args *args,
sprintf(header.mode, "%07o", mode & 07777);
sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
sprintf(header.mtime, "%011lo", args->time);
sprintf(header.mtime, "%011lo", (unsigned long) args->time);
sprintf(header.uid, "%07o", 0);
sprintf(header.gid, "%07o", 0);

Просмотреть файл

@ -4,6 +4,7 @@
#include "attr.h"
#include "archive.h"
#include "parse-options.h"
#include "unpack-trees.h"
static char const * const archive_usage[] = {
"git archive [options] <tree-ish> [path...]",
@ -150,6 +151,8 @@ int write_archive_entries(struct archiver_args *args,
write_archive_entry_fn_t write_entry)
{
struct archiver_context context;
struct unpack_trees_options opts;
struct tree_desc t;
int err;
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
@ -168,6 +171,22 @@ int write_archive_entries(struct archiver_args *args,
context.args = args;
context.write_entry = write_entry;
/*
* Setup index and instruct attr to read index only
*/
if (!args->worktree_attributes) {
memset(&opts, 0, sizeof(opts));
opts.index_only = 1;
opts.head_idx = -1;
opts.src_index = &the_index;
opts.dst_index = &the_index;
opts.fn = oneway_merge;
init_tree_desc(&t, args->tree->buffer, args->tree->size);
if (unpack_trees(1, &t, &opts))
return -1;
git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
}
err = read_tree_recursive(args->tree, args->base, args->baselen, 0,
args->pathspec, write_archive_entry, &context);
if (err == READ_TREE_RECURSIVE)
@ -253,15 +272,21 @@ 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;
int list = 0;
int worktree_attributes = 0;
struct option opts[] = {
OPT_GROUP(""),
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_BOOLEAN(0, "worktree-attributes", &worktree_attributes,
"read .gitattributes in working directory"),
OPT__VERBOSE(&verbose),
OPT__COMPR('0', &compression_level, "store only", 0),
OPT__COMPR('1', &compression_level, "compress faster", 1),
@ -290,6 +315,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 = "";
@ -319,6 +346,7 @@ static int parse_archive_args(int argc, const char **argv,
args->verbose = verbose;
args->base = base;
args->baselen = strlen(base);
args->worktree_attributes = worktree_attributes;
return argc;
}

Просмотреть файл

@ -10,6 +10,7 @@ struct archiver_args {
time_t time;
const char **pathspec;
unsigned int verbose : 1;
unsigned int worktree_attributes : 1;
int compression_level;
};

87
attr.c
Просмотреть файл

@ -1,3 +1,4 @@
#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "attr.h"
@ -223,7 +224,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
if (is_macro)
res->u.attr = git_attr(name, namelen);
else {
res->u.pattern = (char*)&(res->state[num_attr]);
res->u.pattern = (char *)&(res->state[num_attr]);
memcpy(res->u.pattern, name, namelen);
res->u.pattern[namelen] = 0;
}
@ -274,7 +275,7 @@ static void free_attr_elem(struct attr_stack *e)
setto == ATTR__UNKNOWN)
;
else
free((char*) setto);
free((char *) setto);
}
free(a);
}
@ -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,32 @@ 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 if (direction == GIT_ATTR_CHECKIN) {
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);
}
else
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 +449,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) {
@ -438,7 +468,7 @@ static void bootstrap_attr_stack(void)
elem->prev = attr_stack;
attr_stack = elem;
if (!is_bare_repository()) {
if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
elem = read_attr(GITATTRIBUTES_FILE, 1);
elem->origin = strdup("");
elem->prev = attr_stack;
@ -505,7 +535,7 @@ static void prepare_attr_stack(const char *path, int dirlen)
/*
* Read from parent directories and push them down
*/
if (!is_bare_repository()) {
if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
while (1) {
char *cp;
@ -642,3 +672,16 @@ 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;
if (is_bare_repository() && new != GIT_ATTR_INDEX)
die("BUG: non-INDEX attr direction in a bare repo");
direction = new;
if (new != old)
drop_attr_stack();
use_index = istate;
}

7
attr.h
Просмотреть файл

@ -31,4 +31,11 @@ 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,
GIT_ATTR_INDEX,
};
void git_attr_set_direction(enum git_attr_direction, struct index_state *);
#endif /* ATTR_H */

882
bisect.c Normal file
Просмотреть файл

@ -0,0 +1,882 @@
#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 "run-command.h"
#include "bisect.h"
struct sha1_array {
unsigned char (*sha1)[20];
int sha1_nr;
int sha1_alloc;
int sorted;
};
static struct sha1_array good_revs;
static struct sha1_array skipped_revs;
static const unsigned char *current_bad_sha1;
struct argv_array {
const char **argv;
int argv_nr;
int argv_alloc;
};
static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL};
static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
/* 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 void argv_array_push(struct argv_array *array, const char *string)
{
ALLOC_GROW(array->argv, array->argv_nr + 1, array->argv_alloc);
array->argv[array->argv_nr++] = string;
}
static void argv_array_push_sha1(struct argv_array *array,
const unsigned char *sha1,
const char *format)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, format, sha1_to_hex(sha1));
argv_array_push(array, strbuf_detach(&buf, NULL));
}
static void sha1_array_push(struct sha1_array *array,
const unsigned char *sha1)
{
ALLOC_GROW(array->sha1, array->sha1_nr + 1, array->sha1_alloc);
hashcpy(array->sha1[array->sha1_nr++], sha1);
}
static int register_ref(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
if (!strcmp(refname, "bad")) {
current_bad_sha1 = sha1;
} else if (!prefixcmp(refname, "good-")) {
sha1_array_push(&good_revs, sha1);
} else if (!prefixcmp(refname, "skip-")) {
sha1_array_push(&skipped_revs, sha1);
}
return 0;
}
static int read_bisect_refs(void)
{
return for_each_ref_in("refs/bisect/", register_ref, NULL);
}
void read_bisect_paths(struct argv_array *array)
{
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, &array->argv,
&array->argv_nr, &array->argv_alloc);
if (res)
die("Badly quoted content in file '%s': %s",
filename, quoted);
}
strbuf_release(&str);
fclose(fp);
}
static int array_cmp(const void *a, const void *b)
{
return hashcmp(a, b);
}
static void sort_sha1_array(struct sha1_array *array)
{
qsort(array->sha1, array->sha1_nr, sizeof(*array->sha1), array_cmp);
array->sorted = 1;
}
static const unsigned char *sha1_access(size_t index, void *table)
{
unsigned char (*array)[20] = table;
return array[index];
}
static int lookup_sha1_array(struct sha1_array *array,
const unsigned char *sha1)
{
if (!array->sorted)
sort_sha1_array(array);
return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access);
}
static char *join_sha1_array_hex(struct sha1_array *array, char delim)
{
struct strbuf joined_hexs = STRBUF_INIT;
int i;
for (i = 0; i < array->sha1_nr; i++) {
strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i]));
if (i + 1 < array->sha1_nr)
strbuf_addch(&joined_hexs, delim);
}
return strbuf_detach(&joined_hexs, NULL);
}
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_revs.sha1_nr)
return list;
while (list) {
struct commit_list *next = list->next;
list->next = NULL;
if (0 <= lookup_sha1_array(&skipped_revs,
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)
{
struct argv_array rev_argv = { NULL, 0, 0 };
int i;
init_revisions(revs, prefix);
revs->abbrev = 0;
revs->commit_format = CMIT_FMT_UNSPECIFIED;
/* rev_argv.argv[0] will be ignored by setup_revisions */
argv_array_push(&rev_argv, xstrdup("bisect_rev_setup"));
argv_array_push_sha1(&rev_argv, current_bad_sha1, "%s");
for (i = 0; i < good_revs.sha1_nr; i++)
argv_array_push_sha1(&rev_argv, good_revs.sha1[i], "^%s");
argv_array_push(&rev_argv, xstrdup("--"));
read_bisect_paths(&rev_argv);
argv_array_push(&rev_argv, NULL);
setup_revisions(rev_argv.argv_nr, rev_argv.argv, revs, NULL);
revs->limited = 1;
}
static void bisect_common(struct rev_info *revs, int *reaches, int *all)
{
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_revs.sha1_nr);
}
static void exit_if_skipped_commits(struct commit_list *tried,
const unsigned char *bad)
{
if (!tried)
return;
printf("There are only 'skip'ped commits left to test.\n"
"The first bad commit could be any of:\n");
print_commit_list(tried, "%s\n", "%s\n");
if (bad)
printf("%s\n", sha1_to_hex(bad));
printf("We cannot bisect more!\n");
exit(2);
}
static int is_expected_rev(const unsigned char *sha1)
{
const char *filename = git_path("BISECT_EXPECTED_REV");
struct stat st;
struct strbuf str = STRBUF_INIT;
FILE *fp;
int res = 0;
if (stat(filename, &st) || !S_ISREG(st.st_mode))
return 0;
fp = fopen(filename, "r");
if (!fp)
return 0;
if (strbuf_getline(&str, fp, '\n') != EOF)
res = !strcmp(str.buf, sha1_to_hex(sha1));
strbuf_release(&str);
fclose(fp);
return res;
}
static void mark_expected_rev(char *bisect_rev_hex)
{
int len = strlen(bisect_rev_hex);
const char *filename = git_path("BISECT_EXPECTED_REV");
int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
die("could not create file '%s': %s",
filename, strerror(errno));
bisect_rev_hex[len] = '\n';
write_or_die(fd, bisect_rev_hex, len + 1);
bisect_rev_hex[len] = '\0';
if (close(fd) < 0)
die("closing file %s: %s", filename, strerror(errno));
}
static int bisect_checkout(char *bisect_rev_hex)
{
int res;
mark_expected_rev(bisect_rev_hex);
argv_checkout[2] = bisect_rev_hex;
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
if (res)
exit(res);
argv_show_branch[1] = bisect_rev_hex;
return run_command_v_opt(argv_show_branch, RUN_GIT_CMD);
}
static struct commit *get_commit_reference(const unsigned char *sha1)
{
struct commit *r = lookup_commit_reference(sha1);
if (!r)
die("Not a valid commit name %s", sha1_to_hex(sha1));
return r;
}
static struct commit **get_bad_and_good_commits(int *rev_nr)
{
int len = 1 + good_revs.sha1_nr;
struct commit **rev = xmalloc(len * sizeof(*rev));
int i, n = 0;
rev[n++] = get_commit_reference(current_bad_sha1);
for (i = 0; i < good_revs.sha1_nr; i++)
rev[n++] = get_commit_reference(good_revs.sha1[i]);
*rev_nr = n;
return rev;
}
static void handle_bad_merge_base(void)
{
if (is_expected_rev(current_bad_sha1)) {
char *bad_hex = sha1_to_hex(current_bad_sha1);
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
fprintf(stderr, "The merge base %s is bad.\n"
"This means the bug has been fixed "
"between %s and [%s].\n",
bad_hex, bad_hex, good_hex);
exit(3);
}
fprintf(stderr, "Some good revs are not ancestor of the bad rev.\n"
"git bisect cannot work properly in this case.\n"
"Maybe you mistake good and bad revs?\n");
exit(1);
}
void handle_skipped_merge_base(const unsigned char *mb)
{
char *mb_hex = sha1_to_hex(mb);
char *bad_hex = sha1_to_hex(current_bad_sha1);
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
fprintf(stderr, "Warning: the merge base between %s and [%s] "
"must be skipped.\n"
"So we cannot be sure the first bad commit is "
"between %s and %s.\n"
"We continue anyway.\n",
bad_hex, good_hex, mb_hex, bad_hex);
free(good_hex);
}
/*
* "check_merge_bases" checks that merge bases are not "bad".
*
* - If one is "bad", it means the user assumed something wrong
* and we must exit with a non 0 error code.
* - If one is "good", that's good, we have nothing to do.
* - If one is "skipped", we can't know but we should warn.
* - If we don't know, we should check it out and ask the user to test.
*/
static void check_merge_bases(void)
{
struct commit_list *result;
int rev_nr;
struct commit **rev = get_bad_and_good_commits(&rev_nr);
result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
for (; result; result = result->next) {
const unsigned char *mb = result->item->object.sha1;
if (!hashcmp(mb, current_bad_sha1)) {
handle_bad_merge_base();
} else if (0 <= lookup_sha1_array(&good_revs, mb)) {
continue;
} else if (0 <= lookup_sha1_array(&skipped_revs, mb)) {
handle_skipped_merge_base(mb);
} else {
printf("Bisecting: a merge base must be tested\n");
exit(bisect_checkout(sha1_to_hex(mb)));
}
}
free(rev);
free_commit_list(result);
}
/*
* This function runs the command "git rev-list $_good ^$_bad"
* and returns 1 if it produces some output, 0 otherwise.
*/
static int check_ancestors(void)
{
struct argv_array rev_argv = { NULL, 0, 0 };
struct strbuf str = STRBUF_INIT;
int i, result = 0;
struct child_process rls;
FILE *rls_fout;
argv_array_push(&rev_argv, xstrdup("rev-list"));
argv_array_push_sha1(&rev_argv, current_bad_sha1, "^%s");
for (i = 0; i < good_revs.sha1_nr; i++)
argv_array_push_sha1(&rev_argv, good_revs.sha1[i], "%s");
argv_array_push(&rev_argv, NULL);
memset(&rls, 0, sizeof(rls));
rls.argv = rev_argv.argv;
rls.out = -1;
rls.git_cmd = 1;
if (start_command(&rls))
die("Could not launch 'git rev-list' command.");
rls_fout = fdopen(rls.out, "r");
while (strbuf_getline(&str, rls_fout, '\n') != EOF) {
strbuf_trim(&str);
if (*str.buf) {
result = 1;
break;
}
}
fclose(rls_fout);
finish_command(&rls);
return result;
}
/*
* "check_good_are_ancestors_of_bad" checks that all "good" revs are
* ancestor of the "bad" rev.
*
* If that's not the case, we need to check the merge bases.
* If a merge base must be tested by the user, its source code will be
* checked out to be tested by the user and we will exit.
*/
static void check_good_are_ancestors_of_bad(const char *prefix)
{
const char *filename = git_path("BISECT_ANCESTORS_OK");
struct stat st;
int fd;
if (!current_bad_sha1)
die("a bad revision is needed");
/* Check if file BISECT_ANCESTORS_OK exists. */
if (!stat(filename, &st) && S_ISREG(st.st_mode))
return;
/* Bisecting with no good rev is ok. */
if (good_revs.sha1_nr == 0)
return;
if (check_ancestors())
check_merge_bases();
/* Create file BISECT_ANCESTORS_OK. */
fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
warning("could not create file '%s': %s",
filename, strerror(errno));
else
close(fd);
}
/*
* We use the convention that exiting with an exit code 10 means that
* the bisection process finished successfully.
* In this case the calling shell script should exit 0.
*/
int bisect_next_all(const char *prefix)
{
struct rev_info revs;
struct commit_list *tried;
int reaches = 0, all = 0, nr;
const unsigned char *bisect_rev;
char bisect_rev_hex[41];
if (read_bisect_refs())
die("reading bisect refs failed");
check_good_are_ancestors_of_bad(prefix);
bisect_rev_setup(&revs, prefix);
bisect_common(&revs, &reaches, &all);
revs.commits = filter_skipped(revs.commits, &tried, 0);
if (!revs.commits) {
/*
* We should exit here only if the "bad"
* commit is also a "skip" commit.
*/
exit_if_skipped_commits(tried, NULL);
printf("%s was both good and bad\n",
sha1_to_hex(current_bad_sha1));
exit(1);
}
bisect_rev = revs.commits->item->object.sha1;
memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), 41);
if (!hashcmp(bisect_rev, current_bad_sha1)) {
exit_if_skipped_commits(tried, current_bad_sha1);
printf("%s is first bad commit\n", bisect_rev_hex);
argv_diff_tree[2] = bisect_rev_hex;
run_command_v_opt(argv_diff_tree, RUN_GIT_CMD);
/* This means the bisection process succeeded. */
exit(10);
}
nr = all - reaches - 1;
printf("Bisecting: %d revisions left to test after this "
"(roughly %d steps)\n", nr, estimate_bisect_steps(all));
return bisect_checkout(bisect_rev_hex);
}

34
bisect.h Normal file
Просмотреть файл

@ -0,0 +1,34 @@
#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);
extern void print_commit_list(struct commit_list *list,
const char *format_cur,
const char *format_last);
/* bisect_show_flags flags in struct rev_list_info */
#define BISECT_SHOW_ALL (1<<0)
#define BISECT_SHOW_TRIED (1<<1)
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_all(const char *prefix);
extern int estimate_bisect_steps(int all);
#endif

Просмотреть файл

@ -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)) {

Просмотреть файл

@ -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

Просмотреть файл

@ -10,12 +10,14 @@
#include "cache-tree.h"
#include "run-command.h"
#include "parse-options.h"
#include "diff.h"
#include "revision.h"
static const char * const builtin_add_usage[] = {
"git add [options] [--] <filepattern>...",
NULL
};
static int patch_interactive, add_interactive;
static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
@ -61,7 +63,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
fill_pathspec_matches(pathspec, seen, specs);
for (i = 0; i < specs; i++) {
if (!seen[i] && !file_exists(pathspec[i]))
if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))
die("pathspec '%s' did not match any files",
pathspec[i]);
}
@ -104,7 +106,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 +150,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);
}
@ -187,6 +189,51 @@ int interactive_add(int argc, const char **argv, const char *prefix)
return status;
}
int edit_patch(int argc, const char **argv, const char *prefix)
{
char *file = xstrdup(git_path("ADD_EDIT.patch"));
const char *apply_argv[] = { "apply", "--recount", "--cached",
file, NULL };
struct child_process child;
struct rev_info rev;
int out;
struct stat st;
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
if (read_cache() < 0)
die ("Could not read the index");
init_revisions(&rev, prefix);
rev.diffopt.context = 7;
argc = setup_revisions(argc, argv, &rev, NULL);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
out = open(file, O_CREAT | O_WRONLY, 0644);
if (out < 0)
die ("Could not open '%s' for writing.", file);
rev.diffopt.file = fdopen(out, "w");
rev.diffopt.close_file = 1;
if (run_diff_files(&rev, 0))
die ("Could not write patch");
launch_editor(file, NULL, NULL);
if (stat(file, &st))
die("Could not stat '%s'", file);
if (!st.st_size)
die("Empty patch. Aborted.");
memset(&child, 0, sizeof(child));
child.git_cmd = 1;
child.argv = apply_argv;
if (run_command(&child))
die ("Could not apply '%s'", file);
unlink(file);
return 0;
}
static struct lock_file lock_file;
static const char ignore_error[] =
@ -201,6 +248,7 @@ static struct option builtin_add_options[] = {
OPT_GROUP(""),
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
@ -251,14 +299,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int require_pathspec;
argc = parse_options(argc, argv, builtin_add_options,
builtin_add_usage, 0);
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
add_interactive = 1;
if (add_interactive)
exit(interactive_add(argc, argv, prefix));
exit(interactive_add(argc - 1, argv + 1, prefix));
git_config(add_config, NULL);
if (edit_interactive)
return(edit_patch(argc, argv, prefix));
argc--;
argv++;
if (addremove && take_worktree_changes)
die("-A and -u are mutually incompatible");
if ((addremove || take_worktree_changes) && !argc) {

Просмотреть файл

@ -2394,7 +2394,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);
@ -2487,7 +2487,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;
@ -2781,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
if (rmdir(patch->old_name))
warning("unable to remove submodule %s",
patch->old_name);
} else if (!unlink(patch->old_name) && rmdir_empty) {
} else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
remove_path(patch->old_name);
}
}
@ -2891,7 +2891,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
if (!try_create_file(newpath, mode, buf, size)) {
if (!rename(newpath, path))
return;
unlink(newpath);
unlink_or_warn(newpath);
break;
}
if (errno != EEXIST)
@ -2971,8 +2971,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);
@ -3263,10 +3262,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,
@ -3358,8 +3357,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");
}
@ -3369,12 +3368,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" : "");

Просмотреть файл

@ -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
Просмотреть файл

@ -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-all",
NULL
};
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
int next_all = 0;
struct option options[] = {
OPT_BOOLEAN(0, "next-all", &next_all,
"perform 'git bisect next'"),
OPT_END()
};
argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0);
if (!next_all)
usage_with_options(git_bisect_helper_usage, options);
/* next-all */
return bisect_next_all(prefix);
}

Просмотреть файл

@ -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);
}
@ -866,7 +873,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
* Prepare mmfile that contains only the lines in ent.
*/
cp = nth_line(sb, ent->lno);
file_o.ptr = (char*) cp;
file_o.ptr = (char *) cp;
cnt = ent->num_lines;
while (cnt && cp < sb->final_buf + sb->final_buf_size) {
@ -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);
@ -1695,7 +1704,7 @@ static int prepare_lines(struct scoreboard *sb)
while (len--) {
if (bol) {
sb->lineno = xrealloc(sb->lineno,
sizeof(int* ) * (num + 1));
sizeof(int *) * (num + 1));
sb->lineno[num] = buf - sb->final_buf;
bol = 0;
}
@ -1705,7 +1714,7 @@ static int prepare_lines(struct scoreboard *sb)
}
}
sb->lineno = xrealloc(sb->lineno,
sizeof(int* ) * (num + incomplete + 1));
sizeof(int *) * (num + incomplete + 1));
sb->lineno[num + incomplete] = buf - sb->final_buf;
sb->num_lines = num + incomplete;
return sb->num_lines;
@ -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);
@ -1910,7 +1889,7 @@ static const char *parse_loc(const char *spec,
return spec;
/* it could be a regexp of form /.../ */
for (term = (char*) spec + 1; *term && *term != '/'; term++) {
for (term = (char *) spec + 1; *term && *term != '/'; term++) {
if (*term == '\\')
term++;
}
@ -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;
@ -2267,8 +2254,35 @@ parse_done:
die("reading graft file %s failed: %s",
revs_file, strerror(errno));
if (cmd_is_annotate)
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 |

Просмотреть файл

@ -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);
@ -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, 0));
return;
}
strbuf_addch(stat, '[');
if (show_upstream_ref)
strbuf_addf(stat, "%s: ",
shorten_unambiguous_ref(branch->merge[0]->dst, 0));
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);
@ -485,7 +547,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_GROUP("Generic options"),
OPT__VERBOSE(&verbose),
OPT_SET_INT( 0 , "track", &track, "set up tracking mode (see git-pull(1))",
OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))",
BRANCH_TRACK_EXPLICIT),
OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",

Просмотреть файл

@ -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]);

Просмотреть файл

@ -124,7 +124,7 @@ static int checkout_file(const char *name, int prefix_length)
static void checkout_all(const char *prefix, int prefix_length)
{
int i, errs = 0;
struct cache_entry* last_ce = NULL;
struct cache_entry *last_ce = NULL;
for (i = 0; i < active_nr ; i++) {
struct cache_entry *ce = active_cache[i];
@ -278,7 +278,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
p = prefix_path(prefix, prefix_length, arg);
checkout_file(p, prefix_length);
if (p < arg || p > arg + strlen(arg))
free((char*)p);
free((char *)p);
}
if (read_from_stdin) {

Просмотреть файл

@ -179,7 +179,7 @@ static int checkout_merged(int pos, struct checkout *state)
/*
* NEEDSWORK:
* There is absolutely no reason to write this as a blob object
* and create a phoney cache entry just to leak. This hack is
* and create a phony cache entry just to leak. This hack is
* primarily to get to the write_entry() machinery that massages
* the contents to work-tree format and writes out which only
* allows it for a cache entry. The code in write_entry() needs
@ -216,7 +216,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
if (read_cache() < 0)
if (read_cache_preload(pathspec) < 0)
return error("corrupt index file");
if (source_tree)
@ -293,6 +293,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);
}
@ -349,16 +351,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);
}
@ -369,7 +366,7 @@ static int merge_working_tree(struct checkout_opts *opts,
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
int newfd = hold_locked_index(lock_file, 1);
if (read_cache() < 0)
if (read_cache_preload(NULL) < 0)
return error("corrupt index file");
if (opts->force) {
@ -403,7 +400,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);
@ -544,18 +541,10 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
parse_commit(new->commit);
}
/*
* If we were on a detached HEAD, but we are now moving to
* a new commit, we want to mention the old commit once more
* to remind the user that it might be lost.
*/
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
describe_detached_head("Previous HEAD position was", old.commit);
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;
}
@ -564,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
if (ret)
return ret;
/*
* If we were on a detached HEAD, but have now moved to
* a new commit, we want to mention the old commit once more
* to remind the user that it might be lost.
*/
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
describe_detached_head("Previous HEAD position was", old.commit);
update_refs_for_switch(opts, &old, new);
ret = post_checkout_hook(old.commit, new->commit, 1);
@ -734,12 +731,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);
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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:
@ -101,11 +104,12 @@ static char *get_repo_path(const char *repo, int *is_bundle)
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
{
const char *end = repo + strlen(repo), *start;
char *dir;
/*
* Strip trailing slashes and /.git
* Strip trailing spaces, slashes and /.git
*/
while (repo < end && is_dir_sep(end[-1]))
while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
end--;
if (end - repo > 5 && is_dir_sep(end[-5]) &&
!strncmp(end - 4, ".git", 4)) {
@ -137,10 +141,33 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
if (is_bare) {
struct strbuf result = STRBUF_INIT;
strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
return strbuf_detach(&result, 0);
dir = strbuf_detach(&result, 0);
} else
dir = xstrndup(start, end - start);
/*
* Replace sequences of 'control' characters and whitespace
* with one ascii space, remove leading and trailing spaces.
*/
if (*dir) {
char *out = dir;
int prev_space = 1 /* strip leading whitespace */;
for (end = dir; *end; ++end) {
char ch = *end;
if ((unsigned char)ch < '\x20')
ch = '\x20';
if (isspace(ch)) {
if (prev_space)
continue;
prev_space = 1;
} else
prev_space = 0;
*out++ = ch;
}
*out = '\0';
if (out > dir && prev_space)
out[-1] = '\0';
}
return xstrndup(start, end - start);
return dir;
}
static void strip_trailing_slashes(char *dir)
@ -225,7 +252,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
}
if (unlink(dest->buf) && errno != ENOENT)
die("failed to unlink %s", dest->buf);
die("failed to unlink %s: %s",
dest->buf, strerror(errno));
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;
@ -267,7 +295,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 +321,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 +341,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 +353,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 +366,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 +374,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 +431,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 +461,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 +477,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 +517,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 +528,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 +558,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 +606,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 +616,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;
}

Просмотреть файл

@ -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,190 @@ 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);
if (!config_exclusive_filename && nongit)
die("not in a git directory");
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;
}

Просмотреть файл

@ -334,7 +334,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
die("--long is incompatible with --abbrev=0");
if (contains) {
const char **args = xmalloc((7 + argc) * sizeof(char*));
const char **args = xmalloc((7 + argc) * sizeof(char *));
int i = 0;
args[i++] = "name-rev";
args[i++] = "--name-only";
@ -349,7 +349,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
args[i++] = s;
}
}
memcpy(args + i, argv, argc * sizeof(char*));
memcpy(args + i, argv, argc * sizeof(char *));
args[i + argc] = NULL;
return cmd_name_rev(i + argc, args, prefix);
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -112,7 +112,7 @@ static void mark_common(struct commit *commit,
Get the next rev to send, ignoring the common.
*/
static const unsigned char* get_rev(void)
static const unsigned char *get_rev(void)
{
struct commit *commit = NULL;
@ -217,9 +217,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);
@ -484,7 +483,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)
@ -612,7 +611,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.");
@ -812,15 +811,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");
@ -828,7 +825,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
fd = hold_lock_file_for_update(&lock, shallow,
LOCK_DIE_ON_ERROR);
if (!write_shallow_commits(fd, 0)) {
unlink(shallow);
unlink_or_warn(shallow);
rollback_lock_file(&lock);
} else {
commit_lock_file(&lock);

Просмотреть файл

@ -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_refname(ref->name);
*display = 0;
type = sha1_object_info(ref->new_sha1, NULL);
@ -293,7 +289,7 @@ static int update_local_ref(struct ref *ref,
}
}
static int store_updated_refs(const char *url, const char *remote_name,
static int store_updated_refs(const char *raw_url, const char *remote_name,
struct ref *ref_map)
{
FILE *fp;
@ -302,11 +298,13 @@ static int store_updated_refs(const char *url, const char *remote_name,
char note[1024];
const char *what, *kind;
struct ref *rm;
char *filename = git_path("FETCH_HEAD");
char *url, *filename = git_path("FETCH_HEAD");
fp = fopen(filename, "a");
if (!fp)
return error("cannot open %s: %s\n", filename, strerror(errno));
url = transport_anonymize_url(raw_url);
for (rm = ref_map; rm; rm = rm->next) {
struct ref *ref = NULL;
@ -357,12 +355,18 @@ static int store_updated_refs(const char *url, const char *remote_name,
kind);
note_len += sprintf(note + note_len, "'%s' of ", what);
}
note_len += sprintf(note + note_len, "%.*s", url_len, url);
fprintf(fp, "%s\t%s\t%s\n",
note[note_len] = '\0';
fprintf(fp, "%s\t%s\t%s",
sha1_to_hex(commit ? commit->object.sha1 :
rm->old_sha1),
rm->merge ? "" : "not-for-merge",
note);
for (i = 0; i < url_len; ++i)
if ('\n' == url[i])
fputs("\\n", fp);
else
fputc(url[i], fp);
fputc('\n', fp);
if (ref)
rc |= update_local_ref(ref, what, note);
@ -380,6 +384,7 @@ static int store_updated_refs(const char *url, const char *remote_name,
fprintf(stderr, " %s\n", note);
}
}
free(url);
fclose(fp);
if (rc & 2)
error("some local refs could not be updated; try running\n"
@ -544,7 +549,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,

Просмотреть файл

@ -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;

Просмотреть файл

@ -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" },
};
/*
@ -337,8 +339,11 @@ static const char *copy_name(const char *buf)
static const char *copy_email(const char *buf)
{
const char *email = strchr(buf, '<');
const char *eoemail = strchr(email, '>');
if (!email || !eoemail)
const char *eoemail;
if (!email)
return "";
eoemail = strchr(email, '>');
if (!eoemail)
return "";
return xmemdupz(email, eoemail + 1 - email);
}
@ -543,109 +548,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 +574,50 @@ 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,
warn_ambiguous_refs);
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 +863,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;
@ -1002,6 +921,9 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
sort = default_sort();
sort_atom_limit = used_atom_cnt;
/* for warn_ambiguous_refs */
git_config(git_default_config, NULL);
memset(&cbdata, 0, sizeof(cbdata));
cbdata.grab_pattern = argv;
for_each_ref(grab_single_ref, &cbdata);

Просмотреть файл

@ -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);

Просмотреть файл

@ -10,6 +10,7 @@
#include "tag.h"
#include "tree-walk.h"
#include "builtin.h"
#include "parse-options.h"
#include "grep.h"
#ifndef NO_EXTERNAL_GREP
@ -20,7 +21,29 @@
#endif
#endif
static int builtin_grep;
static char const * const grep_usage[] = {
"git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
NULL
};
static int grep_config(const char *var, const char *value, void *cb)
{
struct grep_opt *opt = cb;
if (!strcmp(var, "color.grep")) {
opt->color = git_config_colorbool(var, value, -1);
return 0;
}
if (!strcmp(var, "color.grep.external"))
return git_config_string(&(opt->color_external), var, value);
if (!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;
@ -269,6 +292,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 +377,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;
@ -381,7 +436,8 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
}
#endif
static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
int external_grep_allowed)
{
int hit = 0;
int nr;
@ -393,7 +449,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
* we grep through the checked-out files. It tends to
* be a lot more optimized
*/
if (!cached && !builtin_grep) {
if (!cached && external_grep_allowed) {
hit = external_grep(opt, paths, cached);
if (hit >= 0)
return hit;
@ -509,25 +565,182 @@ static int grep_object(struct grep_opt *opt, const char **paths,
die("unable to grep from object of type %s", typename(obj->type));
}
static const char builtin_grep_usage[] =
"git grep <option>* [-e] <pattern> <rev>* [[--] <path>...]";
static int context_callback(const struct option *opt, const char *arg,
int unset)
{
struct grep_opt *grep_opt = opt->value;
int value;
const char *endp;
static const char emsg_invalid_context_len[] =
"%s: invalid context length argument";
static const char emsg_missing_context_len[] =
"missing context length argument";
static const char emsg_missing_argument[] =
"option requires an argument -%s";
if (unset) {
grep_opt->pre_context = grep_opt->post_context = 0;
return 0;
}
value = strtol(arg, (char **)&endp, 10);
if (*endp) {
return error("switch `%c' expects a numerical value",
opt->short_name);
}
grep_opt->pre_context = grep_opt->post_context = value;
return 0;
}
static int file_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
FILE *patterns;
int lno = 0;
struct strbuf sb;
patterns = fopen(arg, "r");
if (!patterns)
die("'%s': %s", arg, strerror(errno));
while (strbuf_getline(&sb, patterns, '\n') == 0) {
/* ignore empty line like grep does */
if (sb.len == 0)
continue;
append_grep_pattern(grep_opt, strbuf_detach(&sb, NULL), arg,
++lno, GREP_PATTERN);
}
fclose(patterns);
strbuf_release(&sb);
return 0;
}
static int not_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
return 0;
}
static int and_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
return 0;
}
static int open_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
return 0;
}
static int close_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
return 0;
}
static int pattern_callback(const struct option *opt, const char *arg,
int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
return 0;
}
static int help_callback(const struct option *opt, const char *arg, int unset)
{
return -1;
}
int cmd_grep(int argc, const char **argv, const char *prefix)
{
int hit = 0;
int cached = 0;
int external_grep_allowed = 1;
int seen_dashdash = 0;
struct grep_opt opt;
struct object_array list = { 0, 0, NULL };
const char **paths = NULL;
int i;
int dummy;
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
"search in index instead of in the work tree"),
OPT_GROUP(""),
OPT_BOOLEAN('v', "invert-match", &opt.invert,
"show non-matching lines"),
OPT_BIT('i', "ignore-case", &opt.regflags,
"case insensitive matching", REG_ICASE),
OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
"match patterns only at word boundaries"),
OPT_SET_INT('a', "text", &opt.binary,
"process binary files as text", GREP_BINARY_TEXT),
OPT_SET_INT('I', NULL, &opt.binary,
"don't match patterns in binary files",
GREP_BINARY_NOMATCH),
OPT_GROUP(""),
OPT_BIT('E', "extended-regexp", &opt.regflags,
"use extended POSIX regular expressions", REG_EXTENDED),
OPT_NEGBIT('G', "basic-regexp", &opt.regflags,
"use basic POSIX regular expressions (default)",
REG_EXTENDED),
OPT_BOOLEAN('F', "fixed-strings", &opt.fixed,
"interpret patterns as fixed strings"),
OPT_GROUP(""),
OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"),
OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
OPT_NEGBIT(0, "full-name", &opt.relative,
"show filenames relative to top directory", 1),
OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
"show only filenames instead of matching lines"),
OPT_BOOLEAN(0, "name-only", &opt.name_only,
"synonym for --files-with-matches"),
OPT_BOOLEAN('L', "files-without-match",
&opt.unmatch_name_only,
"show only the names of files without match"),
OPT_BOOLEAN('z', "null", &opt.null_following_name,
"print NUL after filenames"),
OPT_BOOLEAN('c', "count", &opt.count,
"show the number of matches instead of matching lines"),
OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1),
OPT_GROUP(""),
OPT_CALLBACK('C', NULL, &opt, "n",
"show <n> context lines before and after matches",
context_callback),
OPT_INTEGER('B', NULL, &opt.pre_context,
"show <n> context lines before matches"),
OPT_INTEGER('A', NULL, &opt.post_context,
"show <n> context lines after matches"),
OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
context_callback),
OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, "file",
"read patterns from file", file_callback),
{ OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
"match <pattern>", PARSE_OPT_NONEG, pattern_callback },
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
"combine patterns specified with -e",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
OPT_BOOLEAN(0, "or", &dummy, ""),
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
{ OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
open_callback },
{ OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
close_callback },
OPT_BOOLEAN(0, "all-match", &opt.all_match,
"show only matches from files that match all patterns"),
OPT_GROUP(""),
#if NO_EXTERNAL_GREP
OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
"allow calling of grep(1) (ignored by this build)"),
#else
OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
"allow calling of grep(1) (default)"),
#endif
{ OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
OPT_END()
};
memset(&opt, 0, sizeof(opt));
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
@ -536,6 +749,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
@ -546,217 +765,21 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
* unrecognized non option is the beginning of the refs list
* that continues up to the -- (if exists), and then paths.
*/
argc = parse_options(argc, argv, options, grep_usage,
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
while (1 < argc) {
const char *arg = argv[1];
argc--; argv++;
if (!strcmp("--cached", arg)) {
cached = 1;
continue;
}
if (!strcmp("--no-ext-grep", arg)) {
builtin_grep = 1;
continue;
}
if (!strcmp("-a", arg) ||
!strcmp("--text", arg)) {
opt.binary = GREP_BINARY_TEXT;
continue;
}
if (!strcmp("-i", arg) ||
!strcmp("--ignore-case", arg)) {
opt.regflags |= REG_ICASE;
continue;
}
if (!strcmp("-I", arg)) {
opt.binary = GREP_BINARY_NOMATCH;
continue;
}
if (!strcmp("-v", arg) ||
!strcmp("--invert-match", arg)) {
opt.invert = 1;
continue;
}
if (!strcmp("-E", arg) ||
!strcmp("--extended-regexp", arg)) {
opt.regflags |= REG_EXTENDED;
continue;
}
if (!strcmp("-F", arg) ||
!strcmp("--fixed-strings", arg)) {
opt.fixed = 1;
continue;
}
if (!strcmp("-G", arg) ||
!strcmp("--basic-regexp", arg)) {
opt.regflags &= ~REG_EXTENDED;
continue;
}
if (!strcmp("-n", arg)) {
opt.linenum = 1;
continue;
}
if (!strcmp("-h", arg)) {
opt.pathname = 0;
continue;
}
if (!strcmp("-H", arg)) {
opt.pathname = 1;
continue;
}
if (!strcmp("-l", arg) ||
!strcmp("--name-only", arg) ||
!strcmp("--files-with-matches", arg)) {
opt.name_only = 1;
continue;
}
if (!strcmp("-L", arg) ||
!strcmp("--files-without-match", arg)) {
opt.unmatch_name_only = 1;
continue;
}
if (!strcmp("-z", arg) ||
!strcmp("--null", arg)) {
opt.null_following_name = 1;
continue;
}
if (!strcmp("-c", arg) ||
!strcmp("--count", arg)) {
opt.count = 1;
continue;
}
if (!strcmp("-w", arg) ||
!strcmp("--word-regexp", arg)) {
opt.word_regexp = 1;
continue;
}
if (!prefixcmp(arg, "-A") ||
!prefixcmp(arg, "-B") ||
!prefixcmp(arg, "-C") ||
(arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
unsigned num;
const char *scan;
switch (arg[1]) {
case 'A': case 'B': case 'C':
if (!arg[2]) {
if (argc <= 1)
die(emsg_missing_context_len);
scan = *++argv;
argc--;
}
else
scan = arg + 2;
break;
default:
scan = arg + 1;
break;
}
if (strtoul_ui(scan, 10, &num))
die(emsg_invalid_context_len, scan);
switch (arg[1]) {
case 'A':
opt.post_context = num;
break;
default:
case 'C':
opt.post_context = num;
case 'B':
opt.pre_context = num;
break;
}
continue;
}
if (!strcmp("-f", arg)) {
FILE *patterns;
int lno = 0;
char buf[1024];
if (argc <= 1)
die(emsg_missing_argument, arg);
patterns = fopen(argv[1], "r");
if (!patterns)
die("'%s': %s", argv[1], strerror(errno));
while (fgets(buf, sizeof(buf), patterns)) {
int len = strlen(buf);
if (len && buf[len-1] == '\n')
buf[len-1] = 0;
/* ignore empty line like grep does */
if (!buf[0])
continue;
append_grep_pattern(&opt, xstrdup(buf),
argv[1], ++lno,
GREP_PATTERN);
}
fclose(patterns);
argv++;
argc--;
continue;
}
if (!strcmp("--not", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_NOT);
continue;
}
if (!strcmp("--and", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_AND);
continue;
}
if (!strcmp("--or", arg))
continue; /* no-op */
if (!strcmp("(", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_OPEN_PAREN);
continue;
}
if (!strcmp(")", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_CLOSE_PAREN);
continue;
}
if (!strcmp("--all-match", arg)) {
opt.all_match = 1;
continue;
}
if (!strcmp("-e", arg)) {
if (1 < argc) {
append_grep_pattern(&opt, argv[1],
"-e option", 0,
GREP_PATTERN);
argv++;
argc--;
continue;
}
die(emsg_missing_argument, arg);
}
if (!strcmp("--full-name", arg)) {
opt.relative = 0;
continue;
}
if (!strcmp("--", arg)) {
/* later processing wants to have this at argv[1] */
argv--;
argc++;
break;
}
if (*arg == '-')
usage(builtin_grep_usage);
/* First unrecognized non-option token */
if (!opt.pattern_list) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_PATTERN);
break;
}
else {
/* We are looking at the first path or rev;
* it is found at argv[1] after leaving the
* loop.
*/
argc++; argv--;
break;
}
/* First unrecognized non-option token */
if (argc > 0 && !opt.pattern_list) {
append_grep_pattern(&opt, argv[0], "command line", 0,
GREP_PATTERN);
argv++;
argc--;
}
if (opt.color && !opt.color_external)
external_grep_allowed = 0;
if (!opt.pattern_list)
die("no pattern given.");
if ((opt.regflags != REG_NEWLINE) && opt.fixed)
@ -764,7 +787,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
compile_grep_patterns(&opt);
/* Check revs and then paths */
for (i = 1; i < argc; i++) {
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
unsigned char sha1[20];
/* Is it a rev? */
@ -807,7 +830,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!list.nr) {
if (!cached)
setup_work_tree();
return !grep_cache(&opt, paths, cached);
return !grep_cache(&opt, paths, cached, external_grep_allowed);
}
if (cached)

Просмотреть файл

@ -114,7 +114,7 @@ static int check_emacsclient_version(void)
return 0;
}
static void exec_woman_emacs(const char* path, const char *page)
static void exec_woman_emacs(const char *path, const char *page)
{
if (!check_emacsclient_version()) {
/* This works only with emacsclient version >= 22. */
@ -128,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page)
}
}
static void exec_man_konqueror(const char* path, const char *page)
static void exec_man_konqueror(const char *path, const char *page)
{
const char *display = getenv("DISPLAY");
if (display && *display) {
@ -156,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page)
}
}
static void exec_man_man(const char* path, const char *page)
static void exec_man_man(const char *path, const char *page)
{
if (!path)
path = "man";
@ -236,7 +236,7 @@ static int add_man_viewer_info(const char *var, const char *value)
const char *subkey = strrchr(name, '.');
if (!subkey)
return error("Config with no key for man viewer: %s", name);
return 0;
if (!strcmp(subkey, ".path")) {
if (!value)
@ -249,7 +249,6 @@ static int add_man_viewer_info(const char *var, const char *value)
return add_man_viewer_cmd(name, subkey - name, value);
}
warning("'%s': unsupported man viewer sub key.", subkey);
return 0;
}

Просмотреть файл

@ -132,8 +132,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;
}
@ -146,8 +145,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);

Просмотреть файл

@ -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,10 +752,10 @@ 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;
int numbered_cmdline_opt = 0;
struct commit *origin = NULL, *head = NULL;
const char *in_reply_to = NULL;
struct patch_ids ids;
@ -787,6 +773,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
@ -796,8 +787,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[i], "--stdout"))
use_stdout = 1;
else if (!strcmp(argv[i], "-n") ||
!strcmp(argv[i], "--numbered"))
!strcmp(argv[i], "--numbered")) {
numbered = 1;
numbered_cmdline_opt = 1;
}
else if (!strcmp(argv[i], "-N") ||
!strcmp(argv[i], "--no-numbered")) {
numbered = 0;
@ -833,13 +826,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 +836,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 +850,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 +873,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');
@ -913,6 +921,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (start_number < 0)
start_number = 1;
/*
* If numbered is set solely due to format.numbered in config,
* and it would conflict with --keep-subject (-k) from the
* command line, reset "numbered".
*/
if (numbered && keep_subject && !numbered_cmdline_opt)
numbered = 0;
if (numbered && keep_subject)
die ("-n and -k are mutually exclusive.");
if (keep_subject && subject_prefix)
@ -1009,8 +1026,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 +1052,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);

Просмотреть файл

@ -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,159 +378,141 @@ 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_NEGBIT(0, "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 */
/* be nice with submodule paths ending in a slash */
read_cache();
if (pathspec)
strip_trailing_slash_from_submodules();
@ -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);

Просмотреть файл

@ -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)

Просмотреть файл

@ -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"

Просмотреть файл

@ -45,8 +45,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
bases[bases_count++] = sha;
}
else
warning("Cannot handle more than %zu bases. "
"Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]);
warning("Cannot handle more than %d bases. "
"Ignoring %s.",
(int)ARRAY_SIZE(bases)-1, argv[i]);
}
if (argc - i != 3) /* "--" "<head>" "<remote>" */
die("Not handling anything other than two heads merge.");

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше